Skip to content

Commit 470e7e9

Browse files
perf: add only required schemas to the validator (#538)
* perf: add only required schemas to the validator * refactor: remove unused if/else check
1 parent 703c2a6 commit 470e7e9

File tree

2 files changed

+39
-19
lines changed

2 files changed

+39
-19
lines changed

index.js

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ function mergeLocation (location, key) {
4444
return {
4545
schema: location.schema[key],
4646
schemaId: location.schemaId,
47-
jsonPointer: location.jsonPointer + '/' + key
47+
jsonPointer: location.jsonPointer + '/' + key,
48+
isValidated: location.isValidated
4849
}
4950
}
5051

@@ -63,27 +64,29 @@ function resolveRef (location, ref) {
6364
throw new Error(`Cannot find reference "${ref}"`)
6465
}
6566

67+
if (location.isValidated) {
68+
validatorSchemasIds.add(schemaId)
69+
}
70+
6671
if (schema.$ref !== undefined) {
6772
return resolveRef({ schema, schemaId, jsonPointer }, schema.$ref)
6873
}
6974

70-
return { schema, schemaId, jsonPointer }
75+
return { schema, schemaId, jsonPointer, isValidated: location.isValidated }
7176
}
7277

7378
const contextFunctionsNamesBySchema = new Map()
7479

75-
let isValidatorUsed = null
7680
let rootSchemaId = null
7781
let refResolver = null
7882
let contextFunctions = null
79-
let mergeAllOfSchemas = null
83+
let validatorSchemasIds = null
8084

8185
function build (schema, options) {
8286
contextFunctionsNamesBySchema.clear()
8387

84-
isValidatorUsed = false
8588
contextFunctions = []
86-
mergeAllOfSchemas = {}
89+
validatorSchemasIds = new Set()
8790
options = options || {}
8891

8992
refResolver = new RefResolver()
@@ -122,7 +125,7 @@ function build (schema, options) {
122125
}
123126
}
124127

125-
const location = { schema, schemaId: rootSchemaId, jsonPointer: '#' }
128+
const location = { schema, schemaId: rootSchemaId, jsonPointer: '#', isValidated: false }
126129
const code = buildValue(location, 'input')
127130

128131
const contextFunctionCode = `
@@ -138,13 +141,9 @@ function build (schema, options) {
138141
const serializer = new Serializer(options)
139142
const validator = new Validator(options.ajv)
140143

141-
if (isValidatorUsed) {
142-
validator.addSchema(schema, rootSchemaId)
143-
const externalSchemas = options.schema || {}
144-
const validatorSchemas = { ...externalSchemas, ...mergeAllOfSchemas }
145-
for (const [schemaKey, schema] of Object.entries(validatorSchemas)) {
146-
validator.addSchema(schema, schemaKey)
147-
}
144+
for (const schemaId of validatorSchemasIds) {
145+
const schema = refResolver.getSchema(schemaId)
146+
validator.addSchema(schema, schemaId)
148147
}
149148

150149
const dependenciesName = ['validator', 'serializer', contextFunctionCode]
@@ -164,6 +163,7 @@ function build (schema, options) {
164163

165164
if (options.mode === 'standalone') {
166165
// lazy load
166+
const isValidatorUsed = validatorSchemasIds.size > 0
167167
const buildStandaloneCode = require('./lib/standalone')
168168
return buildStandaloneCode(options, validator, isValidatorUsed, contextFunctionCode)
169169
}
@@ -172,11 +172,10 @@ function build (schema, options) {
172172
const contextFunc = new Function('validator', 'serializer', contextFunctionCode)
173173
const stringifyFunc = contextFunc(validator, serializer)
174174

175-
isValidatorUsed = false
176175
refResolver = null
177176
rootSchemaId = null
178177
contextFunctions = null
179-
mergeAllOfSchemas = null
178+
validatorSchemasIds = null
180179
contextFunctionsNamesBySchema.clear()
181180

182181
return stringifyFunc
@@ -477,7 +476,6 @@ function mergeAllOfSchema (location, schema, mergedSchema) {
477476
delete mergedSchema.allOf
478477

479478
mergedSchema.$id = `merged_${randomUUID()}`
480-
mergeAllOfSchemas[mergedSchema.$id] = mergedSchema
481479
refResolver.addSchema(mergedSchema)
482480
location.schemaId = mergedSchema.$id
483481
location.jsonPointer = '#'
@@ -495,7 +493,8 @@ function buildInnerObject (location) {
495493
}
496494

497495
function addIfThenElse (location, input) {
498-
isValidatorUsed = true
496+
location.isValidated = true
497+
validatorSchemasIds.add(location.schemaId)
499498

500499
const schema = merge({}, location.schema)
501500
const thenSchema = schema.then
@@ -874,7 +873,8 @@ function buildValue (location, input) {
874873
let code = ''
875874

876875
if (type === undefined && (schema.anyOf || schema.oneOf)) {
877-
isValidatorUsed = true
876+
location.isValidated = true
877+
validatorSchemasIds.add(location.schemaId)
878878

879879
const type = schema.anyOf ? 'anyOf' : 'oneOf'
880880
const anyOfLocation = mergeLocation(location, type)

test/anyof.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,3 +596,23 @@ test('anyOf object with invalid field date of type string with format or null',
596596
const withOneOfStringify = build(withOneOfSchema)
597597
t.throws(() => withOneOfStringify({ prop: toStringify }))
598598
})
599+
600+
test('anyOf with a nested external schema', (t) => {
601+
t.plan(1)
602+
603+
const externalSchemas = {
604+
schema1: {
605+
definitions: {
606+
def1: {
607+
$id: 'external',
608+
type: 'string'
609+
}
610+
},
611+
type: 'number'
612+
}
613+
}
614+
const schema = { anyOf: [{ $ref: 'external' }] }
615+
616+
const stringify = build(schema, { schema: externalSchemas })
617+
t.equal(stringify('foo'), '"foo"')
618+
})

0 commit comments

Comments
 (0)