From cbe1892ca866f2fe4215327bc5ad129d4d80466c Mon Sep 17 00:00:00 2001 From: uzlopak Date: Tue, 24 Jan 2023 12:18:28 +0100 Subject: [PATCH] instead of global variables create context object and pass iit as parameter --- index.js | 155 ++++++++++++++++++++++++++----------------------------- 1 file changed, 72 insertions(+), 83 deletions(-) diff --git a/index.js b/index.js index 56efbf7e..ada7bd8d 100644 --- a/index.js +++ b/index.js @@ -43,7 +43,7 @@ function isValidSchema (schema, name) { } } -function resolveRef (location, ref) { +function resolveRef (context, location, ref) { let hashIndex = ref.indexOf('#') if (hashIndex === -1) { hashIndex = ref.length @@ -52,7 +52,7 @@ function resolveRef (location, ref) { const schemaId = ref.slice(0, hashIndex) || location.getOriginSchemaId() const jsonPointer = ref.slice(hashIndex) || '#' - const schema = refResolver.getSchema(schemaId, jsonPointer) + const schema = context.refResolver.getSchema(schemaId, jsonPointer) if (schema === undefined) { throw new Error(`Cannot find reference "${ref}"`) @@ -60,37 +60,32 @@ function resolveRef (location, ref) { const newLocation = new Location(schema, schemaId, jsonPointer) if (schema.$ref !== undefined) { - return resolveRef(newLocation, schema.$ref) + return resolveRef(context, newLocation, schema.$ref) } return newLocation } -const contextFunctionsNamesBySchema = new Map() - -let rootSchemaId = null -let refResolver = null -let contextFunctions = null -let validatorSchemasIds = null - function build (schema, options) { - contextFunctionsNamesBySchema.clear() + isValidSchema(schema) - contextFunctions = [] - validatorSchemasIds = new Set() options = options || {} - refResolver = new RefResolver() - - rootSchemaId = schema.$id || randomUUID() + const context = { + functions: [], + functionsNamesBySchema: new Map(), + options, + refResolver: new RefResolver(), + rootSchemaId: schema.$id || randomUUID(), + validatorSchemasIds: new Set() + } - isValidSchema(schema) - refResolver.addSchema(schema, rootSchemaId) + context.refResolver.addSchema(schema, context.rootSchemaId) if (options.schema) { for (const key of Object.keys(options.schema)) { isValidSchema(options.schema[key], key) - refResolver.addSchema(options.schema[key], key) + context.refResolver.addSchema(options.schema[key], key) } } @@ -120,8 +115,8 @@ function build (schema, options) { } } - const location = new Location(schema, rootSchemaId) - const code = buildValue(location, 'input') + const location = new Location(schema, context.rootSchemaId) + const code = buildValue(context, location, 'input') let contextFunctionCode @@ -132,7 +127,7 @@ function build (schema, options) { // 'main' if (code === 'json += anonymous0(input)') { contextFunctionCode = ` - ${contextFunctions.join('\n')} + ${context.functions.join('\n')} const main = anonymous0 return main ` @@ -143,7 +138,7 @@ function build (schema, options) { ${code} return json } - ${contextFunctions.join('\n')} + ${context.functions.join('\n')} return main ` } @@ -151,11 +146,11 @@ function build (schema, options) { const serializer = new Serializer(options) const validator = new Validator(options.ajv) - for (const schemaId of validatorSchemasIds) { - const schema = refResolver.getSchema(schemaId) + for (const schemaId of context.validatorSchemasIds) { + const schema = context.refResolver.getSchema(schemaId) validator.addSchema(schema, schemaId) - const dependencies = refResolver.getSchemaDependencies(schemaId) + const dependencies = context.refResolver.getSchemaDependencies(schemaId) for (const [schemaId, schema] of Object.entries(dependencies)) { validator.addSchema(schema, schemaId) } @@ -176,7 +171,7 @@ function build (schema, options) { if (options.mode === 'standalone') { // lazy load - const isValidatorUsed = validatorSchemasIds.size > 0 + const isValidatorUsed = context.validatorSchemasIds.size > 0 const buildStandaloneCode = require('./lib/standalone') return buildStandaloneCode(options, validator, isValidatorUsed, contextFunctionCode) } @@ -186,12 +181,6 @@ function build (schema, options) { const stringifyFunc = contextFunc(validator, serializer) genFuncNameCounter = 0 - refResolver = null - rootSchemaId = null - contextFunctions = null - validatorSchemasIds = null - contextFunctionsNamesBySchema.clear() - return stringifyFunc } @@ -252,7 +241,7 @@ function inferTypeByKeyword (schema) { return schema.type } -function buildExtraObjectPropertiesSerializer (location) { +function buildExtraObjectPropertiesSerializer (context, location) { const schema = location.schema const propertiesKeys = Object.keys(schema.properties || {}) @@ -278,7 +267,7 @@ function buildExtraObjectPropertiesSerializer (location) { if (/${propertyKey.replace(/\\*\//g, '\\/')}/.test(key)) { ${addComma} json += serializer.asString(key) + ':' - ${buildValue(propertyLocation, 'value')} + ${buildValue(context, propertyLocation, 'value')} continue } ` @@ -299,7 +288,7 @@ function buildExtraObjectPropertiesSerializer (location) { code += ` ${addComma} json += serializer.asString(key) + ':' - ${buildValue(propertyLocation, 'value')} + ${buildValue(context, propertyLocation, 'value')} ` } } @@ -310,7 +299,7 @@ function buildExtraObjectPropertiesSerializer (location) { return code } -function buildInnerObject (location) { +function buildInnerObject (context, location) { const schema = location.schema const required = schema.required || [] @@ -320,7 +309,7 @@ function buildInnerObject (location) { Object.keys(schema.properties || {}).forEach((key) => { let propertyLocation = propertiesLocation.getPropertyLocation(key) if (propertyLocation.schema.$ref) { - propertyLocation = resolveRef(location, propertyLocation.schema.$ref) + propertyLocation = resolveRef(context, location, propertyLocation.schema.$ref) } const sanitized = JSON.stringify(key) @@ -334,7 +323,7 @@ function buildInnerObject (location) { json += ${JSON.stringify(sanitized + ':')} ` - code += buildValue(propertyLocation, `obj[${sanitized}]`) + code += buildValue(context, propertyLocation, `obj[${sanitized}]`) const defaultValue = propertyLocation.schema.default if (defaultValue !== undefined) { @@ -361,13 +350,13 @@ function buildInnerObject (location) { } if (schema.patternProperties || schema.additionalProperties) { - code += buildExtraObjectPropertiesSerializer(location) + code += buildExtraObjectPropertiesSerializer(context, location) } return code } -function mergeAllOfSchema (location, schema, mergedSchema) { +function mergeAllOfSchema (context, location, schema, mergedSchema) { const allOfLocation = location.getPropertyLocation('allOf') for (let i = 0; i < schema.allOf.length; i++) { @@ -375,7 +364,7 @@ function mergeAllOfSchema (location, schema, mergedSchema) { if (allOfSchema.$ref) { const allOfSchemaLocation = allOfLocation.getPropertyLocation(i) - allOfSchema = resolveRef(allOfSchemaLocation, allOfSchema.$ref).schema + allOfSchema = resolveRef(context, allOfSchemaLocation, allOfSchema.$ref).schema } let allOfSchemaType = allOfSchema.type @@ -456,18 +445,18 @@ function mergeAllOfSchema (location, schema, mergedSchema) { } if (allOfSchema.allOf !== undefined) { - mergeAllOfSchema(location, allOfSchema, mergedSchema) + mergeAllOfSchema(context, location, allOfSchema, mergedSchema) } } delete mergedSchema.allOf mergedSchema.$id = `merged_${randomUUID()}` - refResolver.addSchema(mergedSchema) + context.refResolver.addSchema(mergedSchema) location.addMergedSchema(mergedSchema, mergedSchema.$id) } -function addIfThenElse (location, input) { - validatorSchemasIds.add(location.getSchemaId()) +function addIfThenElse (context, location, input) { + context.validatorSchemasIds.add(location.getSchemaId()) const schema = merge({}, location.schema) const thenSchema = schema.then @@ -488,9 +477,9 @@ function addIfThenElse (location, input) { return ` if (validator.validate("${ifSchemaRef}", ${input})) { - ${buildValue(thenLocation, input)} + ${buildValue(context, thenLocation, input)} } else { - ${buildValue(elseLocation, input)} + ${buildValue(context, elseLocation, input)} } ` } @@ -502,19 +491,19 @@ function toJSON (variableName) { ` } -function buildObject (location) { +function buildObject (context, location) { const schema = location.schema - if (contextFunctionsNamesBySchema.has(schema)) { - return contextFunctionsNamesBySchema.get(schema) + if (context.functionsNamesBySchema.has(schema)) { + return context.functionsNamesBySchema.get(schema) } const functionName = generateFuncName() - contextFunctionsNamesBySchema.set(schema, functionName) + context.functionsNamesBySchema.set(schema, functionName) let schemaRef = location.getSchemaRef() - if (schemaRef.startsWith(rootSchemaId)) { - schemaRef = schemaRef.replace(rootSchemaId, '') + if (schemaRef.startsWith(context.rootSchemaId)) { + schemaRef = schemaRef.replace(context.rootSchemaId, '') } let functionCode = ` @@ -528,38 +517,38 @@ function buildObject (location) { let addComma = false ` - functionCode += buildInnerObject(location) + functionCode += buildInnerObject(context, location) functionCode += ` return json + '}' } ` - contextFunctions.push(functionCode) + context.functions.push(functionCode) return functionName } -function buildArray (location) { +function buildArray (context, location) { const schema = location.schema let itemsLocation = location.getPropertyLocation('items') itemsLocation.schema = itemsLocation.schema || {} if (itemsLocation.schema.$ref) { - itemsLocation = resolveRef(itemsLocation, itemsLocation.schema.$ref) + itemsLocation = resolveRef(context, itemsLocation, itemsLocation.schema.$ref) } const itemsSchema = itemsLocation.schema - if (contextFunctionsNamesBySchema.has(schema)) { - return contextFunctionsNamesBySchema.get(schema) + if (context.functionsNamesBySchema.has(schema)) { + return context.functionsNamesBySchema.get(schema) } const functionName = generateFuncName() - contextFunctionsNamesBySchema.set(schema, functionName) + context.functionsNamesBySchema.set(schema, functionName) let schemaRef = location.getSchemaRef() - if (schemaRef.startsWith(rootSchemaId)) { - schemaRef = schemaRef.replace(rootSchemaId, '') + if (schemaRef.startsWith(context.rootSchemaId)) { + schemaRef = schemaRef.replace(context.rootSchemaId, '') } let functionCode = ` @@ -597,7 +586,7 @@ function buildArray (location) { if (Array.isArray(itemsSchema)) { for (let i = 0; i < itemsSchema.length; i++) { const item = itemsSchema[i] - const tmpRes = buildValue(itemsLocation.getPropertyLocation(i), `obj[${i}]`) + const tmpRes = buildValue(context, itemsLocation.getPropertyLocation(i), `obj[${i}]`) functionCode += ` if (${i} < arrayLength) { if (${buildArrayTypeCondition(item.type, `[${i}]`)}) { @@ -624,7 +613,7 @@ function buildArray (location) { }` } } else { - const code = buildValue(itemsLocation, 'obj[i]') + const code = buildValue(context, itemsLocation, 'obj[i]') functionCode += ` for (let i = 0; i < arrayLength; i++) { let json = '' @@ -640,7 +629,7 @@ function buildArray (location) { return \`[\${jsonOutput}]\` }` - contextFunctions.push(functionCode) + context.functions.push(functionCode) return functionName } @@ -686,7 +675,7 @@ function generateFuncName () { return 'anonymous' + genFuncNameCounter++ } -function buildMultiTypeSerializer (location, input) { +function buildMultiTypeSerializer (context, location, input) { const schema = location.schema const types = schema.type.sort(t1 => t1 === 'null' ? -1 : 1) @@ -694,7 +683,7 @@ function buildMultiTypeSerializer (location, input) { types.forEach((type, index) => { location.schema = { ...location.schema, type } - const nestedResult = buildSingleTypeSerializer(location, input) + const nestedResult = buildSingleTypeSerializer(context, location, input) const statement = index === 0 ? 'if' : 'else if' switch (type) { @@ -746,8 +735,8 @@ function buildMultiTypeSerializer (location, input) { } }) let schemaRef = location.getSchemaRef() - if (schemaRef.startsWith(rootSchemaId)) { - schemaRef = schemaRef.replace(rootSchemaId, '') + if (schemaRef.startsWith(context.rootSchemaId)) { + schemaRef = schemaRef.replace(context.rootSchemaId, '') } code += ` else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`) @@ -756,7 +745,7 @@ function buildMultiTypeSerializer (location, input) { return code } -function buildSingleTypeSerializer (location, input) { +function buildSingleTypeSerializer (context, location, input) { const schema = location.schema switch (schema.type) { @@ -780,11 +769,11 @@ function buildSingleTypeSerializer (location, input) { case 'boolean': return `json += serializer.asBoolean(${input})` case 'object': { - const funcName = buildObject(location) + const funcName = buildObject(context, location) return `json += ${funcName}(${input})` } case 'array': { - const funcName = buildArray(location) + const funcName = buildArray(context, location) return `json += ${funcName}(${input})` } case undefined: @@ -821,7 +810,7 @@ function buildConstSerializer (location, input) { return code } -function buildValue (location, input) { +function buildValue (context, location, input) { let schema = location.schema if (typeof schema === 'boolean') { @@ -829,7 +818,7 @@ function buildValue (location, input) { } if (schema.$ref) { - location = resolveRef(location, schema.$ref) + location = resolveRef(context, location, schema.$ref) schema = location.schema } @@ -841,11 +830,11 @@ function buildValue (location, input) { } if (schema.if && schema.then) { - return addIfThenElse(location, input) + return addIfThenElse(context, location, input) } if (schema.allOf) { - mergeAllOfSchema(location, schema, clone(schema)) + mergeAllOfSchema(context, location, schema, clone(schema)) schema = location.schema } @@ -854,7 +843,7 @@ function buildValue (location, input) { let code = '' if (type === undefined && (schema.anyOf || schema.oneOf)) { - validatorSchemasIds.add(location.getSchemaId()) + context.validatorSchemasIds.add(location.getSchemaId()) const type = schema.anyOf ? 'anyOf' : 'oneOf' const anyOfLocation = location.getPropertyLocation(type) @@ -862,7 +851,7 @@ function buildValue (location, input) { for (let index = 0; index < location.schema[type].length; index++) { const optionLocation = anyOfLocation.getPropertyLocation(index) const schemaRef = optionLocation.getSchemaRef() - const nestedResult = buildValue(optionLocation, input) + const nestedResult = buildValue(context, optionLocation, input) code += ` ${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input})) ${nestedResult} @@ -870,8 +859,8 @@ function buildValue (location, input) { } let schemaRef = location.getSchemaRef() - if (schemaRef.startsWith(rootSchemaId)) { - schemaRef = schemaRef.replace(rootSchemaId, '') + if (schemaRef.startsWith(context.rootSchemaId)) { + schemaRef = schemaRef.replace(context.rootSchemaId, '') } code += ` @@ -892,9 +881,9 @@ function buildValue (location, input) { if (schema.const !== undefined) { code += buildConstSerializer(location, input) } else if (Array.isArray(type)) { - code += buildMultiTypeSerializer(location, input) + code += buildMultiTypeSerializer(context, location, input) } else { - code += buildSingleTypeSerializer(location, input) + code += buildSingleTypeSerializer(context, location, input) } if (nullable) {