@@ -7,6 +7,7 @@ const ajvFormats = require('ajv-formats')
77const merge = require ( 'deepmerge' )
88const clone = require ( 'rfdc' ) ( { proto : true } )
99const fjsCloned = Symbol ( 'fast-json-stringify.cloned' )
10+ const { randomUUID } = require ( 'crypto' )
1011
1112const validate = require ( './schema-validator' )
1213let stringSimilarity = null
@@ -43,11 +44,17 @@ function mergeLocation (source, dest) {
4344
4445const arrayItemsReferenceSerializersMap = new Map ( )
4546const objectReferenceSerializersMap = new Map ( )
47+ let ajvInstance = null
4648
4749function build ( schema , options ) {
4850 arrayItemsReferenceSerializersMap . clear ( )
4951 objectReferenceSerializersMap . clear ( )
52+
5053 options = options || { }
54+
55+ ajvInstance = new Ajv ( { ...options . ajv , strictSchema : false } )
56+ ajvFormats ( ajvInstance )
57+
5158 isValidSchema ( schema )
5259 if ( options . schema ) {
5360 // eslint-disable-next-line
@@ -72,41 +79,6 @@ function build (schema, options) {
7279
7380 code += `
7481 ${ asFunctions }
75-
76-
77- /**
78- * Used by schemas that are dependant on calling 'ajv.validate' during runtime,
79- * it stores the value of the '$id' property of the schema (if it has it) inside
80- * a cache which is used to figure out if the schema was compiled into a validator
81- * by ajv on a previous call, if it was then the '$id' string will be used to
82- * invoke 'ajv.validate', this allows:
83- *
84- * 1. Schemas that depend on ajv.validate calls to leverage ajv caching system.
85- * 2. To avoid errors, since directly invoking 'ajv.validate' with the same
86- * schema (that contains an '$id' property) twice will throw an error.
87- */
88- const $validateWithAjv = (function() {
89- const cache = new Set()
90-
91- return function (schema, target) {
92- const id = schema.$id
93-
94- if (!id) {
95- return ajv.validate(schema, target)
96- }
97-
98- const cached = cache.has(id)
99-
100- if (cached) {
101- return ajv.validate(id, target)
102- } else {
103- cache.add(id)
104- return ajv.validate(schema, target)
105- }
106- }
107- })()
108-
109-
11082 function parseInteger(int) { return Math.${ intParseFunctionName } (int) }
11183 `
11284
@@ -163,18 +135,17 @@ function build (schema, options) {
163135 ;
164136 return ${ main }
165137 `
166-
167- const ajvInstance = new Ajv ( options . ajv )
168- ajvFormats ( ajvInstance )
169138 const dependencies = [ ajvInstance ]
170139 const dependenciesName = [ 'ajv' ]
140+ ajvInstance = null
141+
171142 dependenciesName . push ( code )
172143
173144 if ( options . debugMode ) {
174- dependenciesName . toString = function ( ) {
175- return dependenciesName . join ( '\n' )
145+ return {
146+ code : dependenciesName . join ( '\n' ) ,
147+ ajv : dependencies [ 0 ]
176148 }
177- return dependenciesName
178149 }
179150
180151 arrayItemsReferenceSerializersMap . clear ( )
@@ -874,8 +845,11 @@ function addIfThenElse (location, name) {
874845 let merged = merge ( copy , then )
875846 let mergedLocation = mergeLocation ( location , { schema : merged } )
876847
848+ const schemaKey = i . $id || randomUUID ( )
849+ ajvInstance . addSchema ( i , schemaKey )
850+
877851 code += `
878- valid = $validateWithAjv (${ JSON . stringify ( i ) } , obj)
852+ valid = ajv.validate (${ JSON . stringify ( schemaKey ) } , obj)
879853 if (valid) {
880854 `
881855 if ( merged . if && merged . then ) {
@@ -1224,8 +1198,12 @@ function nested (laterCode, name, key, location, subKey, isArray) {
12241198 // with the actual schema
12251199 // 2. `nested`, through `buildCode`, replaces any reference in object properties with the actual schema
12261200 // (see https://github.com/fastify/fast-json-stringify/blob/6da3b3e8ac24b1ca5578223adedb4083b7adf8db/index.js#L631)
1201+
1202+ const schemaKey = location . schema . $id || randomUUID ( )
1203+ ajvInstance . addSchema ( location . schema , schemaKey )
1204+
12271205 code += `
1228- ${ index === 0 ? 'if' : 'else if' } ($validateWithAjv (${ JSON . stringify ( location . schema ) } , ${ testValue } ))
1206+ ${ index === 0 ? 'if' : 'else if' } (ajv.validate (${ JSON . stringify ( schemaKey ) } , ${ testValue } ))
12291207 ${ nestedResult . code }
12301208 `
12311209 laterCode = nestedResult . laterCode
@@ -1241,8 +1219,12 @@ function nested (laterCode, name, key, location, subKey, isArray) {
12411219 const testSerializer = getTestSerializer ( location . schema . format )
12421220 const testValue = testSerializer !== undefined ? `${ testSerializer } (obj${ accessor } , true)` : `obj${ accessor } `
12431221 // see comment on anyOf about dereferencing the schema before calling ajv.validate
1222+
1223+ const schemaKey = location . schema . $id || randomUUID ( )
1224+ ajvInstance . addSchema ( location . schema , schemaKey )
1225+
12441226 code += `
1245- ${ index === 0 ? 'if' : 'else if' } ($validateWithAjv (${ JSON . stringify ( location . schema ) } , ${ testValue } ))
1227+ ${ index === 0 ? 'if' : 'else if' } (ajv.validate (${ JSON . stringify ( schemaKey ) } , ${ testValue } ))
12461228 ${ nestedResult . code }
12471229 `
12481230 laterCode = nestedResult . laterCode
@@ -1352,17 +1334,8 @@ function isEmpty (schema) {
13521334
13531335module . exports = build
13541336
1355- module . exports . restore = function ( debugModeStr , options = { } ) {
1356- const dependencies = [ debugModeStr ]
1357- const args = [ ]
1358- if ( debugModeStr . startsWith ( 'ajv' ) ) {
1359- dependencies . unshift ( 'ajv' )
1360- const ajvInstance = new Ajv ( options . ajv )
1361- ajvFormats ( ajvInstance )
1362- args . push ( ajvInstance )
1363- }
1364-
1337+ module . exports . restore = function ( { code, ajv } ) {
13651338 // eslint-disable-next-line
1366- return ( Function . apply ( null , [ 'ajv' , debugModeStr ] )
1367- . apply ( null , args ) )
1339+ return ( Function . apply ( null , [ 'ajv' , code ] )
1340+ . apply ( null , [ ajv ] ) )
13681341}
0 commit comments