Skip to content

Commit

Permalink
feat: export standalone dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-tymoshenko committed Apr 2, 2023
1 parent 895892c commit 363c7d5
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 44 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -689,8 +689,7 @@ console.log(stringify({ firstName: 'Foo', surname: 'bar' })) // '{"firstName":"F
### Standalone Mode

The standalone mode is used to compile the code that can be directly run by `node`
itself. You need to install `ajv`, `fast-uri` and `ajv-formats` for
the standalone code to work.
itself. You need to have `fast-json-stringify` installed for the standalone code to work.

```js
const fs = require('fs')
Expand Down
13 changes: 5 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,15 @@ function build (schema, options) {
}
}

/* eslint no-new-func: "off" */
const contextFunc = new Function('validator', 'serializer', contextFunctionCode)

if (options.mode === 'standalone') {
// lazy load
const isValidatorUsed = context.validatorSchemasIds.size > 0
const buildStandaloneCode = require('./lib/standalone')
return buildStandaloneCode(options, validator, isValidatorUsed, contextFunctionCode)
return buildStandaloneCode(contextFunc, context, serializer, validator)
}

/* eslint no-new-func: "off" */
const contextFunc = new Function('validator', 'serializer', contextFunctionCode)
const stringifyFunc = contextFunc(validator, serializer)

return stringifyFunc
return contextFunc(validator, serializer)
}

const objectKeywords = [
Expand Down
9 changes: 9 additions & 0 deletions lib/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = class Serializer {
this.parseInteger = Math.trunc
break
}
this._options = options
}

asInteger (i) {
Expand Down Expand Up @@ -156,4 +157,12 @@ module.exports = class Serializer {
}
return ((point < 32) || (surrogateFound === true)) ? JSON.stringify(str) : '"' + result + '"'
}

getState () {
return this._options
}

static restoreFromState (state) {
return new Serializer(state)
}
}
55 changes: 22 additions & 33 deletions lib/standalone.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,31 @@
const fs = require('fs')
const path = require('path')

function buildStandaloneCode (options, validator, isValidatorUsed, contextFunctionCode) {
const serializerCode = fs.readFileSync(path.join(__dirname, 'serializer.js')).toString()
let buildAjvCode = ''
let ajvSchemasCode = ''

if (isValidatorUsed) {
let defaultAjvSchema = ''
// we need to export the custom json schema
const defaultMeta = validator.ajv.defaultMeta()
if (typeof defaultMeta === 'string') {
defaultAjvSchema = defaultMeta
} else {
defaultAjvSchema = defaultMeta.$id || defaultMeta.id
}

ajvSchemasCode += `const validator = new Validator(${JSON.stringify(options.ajv || {})})\n`
for (const [id, schema] of Object.entries(validator.ajv.schemas)) {
// should skip ajv default schema
if (id === defaultAjvSchema) continue
ajvSchemasCode += `validator.ajv.addSchema(${JSON.stringify(schema.schema)}, "${id}")\n`
}
buildAjvCode = fs.readFileSync(path.join(__dirname, 'validator.js')).toString()
buildAjvCode = buildAjvCode.replace("'use strict'", '').replace('module.exports = SchemaValidator', '')
'use strict'

function buildStandaloneCode (contextFunc, context, serializer, validator) {
let ajvDependencyCode = ''
if (context.validatorSchemasIds.size > 0) {
ajvDependencyCode += `const validatorState = ${JSON.stringify(validator.getState())}\n`
ajvDependencyCode += 'const validator = Validator.restoreFromState(validatorState)\n'
} else {
ajvDependencyCode += 'const validator = null\n'
}

const serializerOptions = options && options.rounding ? JSON.stringify({ options: options.rounding }) : ''
return `
'use strict'
${serializerCode.replace("'use strict'", '').replace('module.exports = ', '')}
${buildAjvCode}
const serializer = new Serializer(${serializerOptions})
${ajvSchemasCode}
const { dependencies } = require('fast-json-stringify/lib/standalone')
const { Serializer, Validator } = dependencies
const serializerState = ${JSON.stringify(serializer.getState())}
const serializer = Serializer.restoreFromState(serializerState)
${contextFunctionCode.replace('return main', '')}
${ajvDependencyCode}
module.exports = main`
module.exports = ${contextFunc.toString()}(validator, serializer)`
}

module.exports = buildStandaloneCode

module.exports.dependencies = {
Serializer: require('./serializer'),
Validator: require('./validator')
}
19 changes: 19 additions & 0 deletions lib/validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class Validator {
return date instanceof Date
}
})

this._ajvSchemas = {}
this._ajvOptions = ajvOptions || {}
}

addSchema (schema, schemaName) {
Expand All @@ -40,6 +43,7 @@ class Validator {
const ajvSchema = clone(schema)
this.convertSchemaToAjvFormat(ajvSchema)
this.ajv.addSchema(ajvSchema, schemaKey)
this._ajvSchemas[schemaKey] = schema
}
}

Expand Down Expand Up @@ -70,6 +74,21 @@ class Validator {
}
}
}

getState () {
return {
ajvOptions: this._ajvOptions,
ajvSchemas: this._ajvSchemas
}
}

static restoreFromState (state) {
const validator = new Validator(state.ajvOptions)
for (const [id, ajvSchema] of Object.entries(state.ajvSchemas)) {
validator.ajv.addSchema(ajvSchema, id)
}
return validator
}
}

module.exports = Validator
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"standard": "^17.0.0",
"tap": "^16.0.1",
"tsd": "^0.28.0",
"webpack": "^5.40.0"
"webpack": "^5.40.0",
"fast-json-stringify": "."
},
"dependencies": {
"@fastify/deepmerge": "^1.0.0",
Expand Down

0 comments on commit 363c7d5

Please sign in to comment.