2
2
3
3
/* eslint no-prototype-builtins: 0 */
4
4
5
- const Ajv = require ( 'ajv' )
5
+ const Ajv = require ( 'ajv' ) . default
6
6
const merge = require ( 'deepmerge' )
7
7
const clone = require ( 'rfdc' ) ( { proto : true } )
8
8
const fjsCloned = Symbol ( 'fast-json-stringify.cloned' )
@@ -87,6 +87,40 @@ function build (schema, options) {
87
87
${ $asBoolean . toString ( ) }
88
88
${ $asBooleanNullable . toString ( ) }
89
89
90
+
91
+ /**
92
+ * Used by schemas that are dependant on calling 'ajv.validate' during runtime,
93
+ * it stores the value of the '$id' property of the schema (if it has it) inside
94
+ * a cache which is used to figure out if the schema was compiled into a validator
95
+ * by ajv on a previous call, if it was then the '$id' string will be used to
96
+ * invoke 'ajv.validate', this allows:
97
+ *
98
+ * 1. Schemas that depend on ajv.validate calls to leverage ajv caching system.
99
+ * 2. To avoid errors, since directly invoking 'ajv.validate' with the same
100
+ * schema (that contains an '$id' property) twice will throw an error.
101
+ */
102
+ const $validateWithAjv = (function() {
103
+ const cache = new Set()
104
+
105
+ return function (schema, target) {
106
+ const id = schema.$id
107
+
108
+ if (!id) {
109
+ return ajv.validate(schema, target)
110
+ }
111
+
112
+ const cached = cache.has(id)
113
+
114
+ if (cached) {
115
+ return ajv.validate(id, target)
116
+ } else {
117
+ cache.add(id)
118
+ return ajv.validate(schema, target)
119
+ }
120
+ }
121
+ })()
122
+
123
+
90
124
var isLong = ${ isLong ? isLong . toString ( ) : false }
91
125
92
126
function parseInteger(int) { return Math.${ intParseFunctionName } (int) }
@@ -870,7 +904,7 @@ function addIfThenElse (location, name) {
870
904
let mergedLocation = mergeLocation ( location , { schema : merged } )
871
905
872
906
code += `
873
- valid = ajv.validate (${ JSON . stringify ( i ) } , obj)
907
+ valid = $validateWithAjv (${ JSON . stringify ( i ) } , obj)
874
908
if (valid) {
875
909
`
876
910
if ( merged . if && merged . then ) {
@@ -1189,7 +1223,7 @@ function nested (laterCode, name, key, location, subKey, isArray) {
1189
1223
// 2. `nested`, through `buildCode`, replaces any reference in object properties with the actual schema
1190
1224
// (see https://github.com/fastify/fast-json-stringify/blob/6da3b3e8ac24b1ca5578223adedb4083b7adf8db/index.js#L631)
1191
1225
code += `
1192
- ${ index === 0 ? 'if' : 'else if' } (ajv.validate (${ JSON . stringify ( location . schema ) } , obj${ accessor } ))
1226
+ ${ index === 0 ? 'if' : 'else if' } ($validateWithAjv (${ JSON . stringify ( location . schema ) } , obj${ accessor } ))
1193
1227
${ nestedResult . code }
1194
1228
`
1195
1229
laterCode = nestedResult . laterCode
@@ -1205,7 +1239,7 @@ function nested (laterCode, name, key, location, subKey, isArray) {
1205
1239
1206
1240
// see comment on anyOf about derefencing the schema before calling ajv.validate
1207
1241
code += `
1208
- ${ index === 0 ? 'if' : 'else if' } (ajv.validate (${ JSON . stringify ( location . schema ) } , obj${ accessor } ))
1242
+ ${ index === 0 ? 'if' : 'else if' } ($validateWithAjv (${ JSON . stringify ( location . schema ) } , obj${ accessor } ))
1209
1243
${ nestedResult . code }
1210
1244
`
1211
1245
laterCode = nestedResult . laterCode
0 commit comments