fast-json-stringify 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +3 -33
- package/README.md +6 -8
- package/benchmark/bench-cmp-branch.js +114 -0
- package/{bench.js → benchmark/bench-cmp-lib.js} +4 -4
- package/benchmark/bench-thread.js +21 -0
- package/benchmark/bench.js +251 -0
- package/example.js +0 -3
- package/index.js +476 -596
- package/package.json +10 -4
- package/test/additionalProperties.test.js +23 -19
- package/test/allof.test.js +56 -0
- package/test/anyof.test.js +88 -9
- package/test/array.test.js +81 -23
- package/test/basic.test.js +8 -8
- package/test/date.test.js +62 -35
- package/test/debug-mode.test.js +1 -1
- package/test/nestedObjects.test.js +31 -0
- package/test/nullable.test.js +328 -0
- package/test/oneof.test.js +9 -22
- package/test/patternProperties.test.js +17 -6
- package/test/required.test.js +1 -1
- package/test/sanitize3.test.js +9 -11
- package/test/typesArray.test.js +40 -3
package/index.js
CHANGED
|
@@ -56,6 +56,173 @@ const schemaReferenceMap = new Map()
|
|
|
56
56
|
|
|
57
57
|
let ajvInstance = null
|
|
58
58
|
|
|
59
|
+
class Serializer {
|
|
60
|
+
constructor (options = {}) {
|
|
61
|
+
switch (options.rounding) {
|
|
62
|
+
case 'floor':
|
|
63
|
+
this.parseInteger = Math.floor
|
|
64
|
+
break
|
|
65
|
+
case 'ceil':
|
|
66
|
+
this.parseInteger = Math.ceil
|
|
67
|
+
break
|
|
68
|
+
case 'round':
|
|
69
|
+
this.parseInteger = Math.round
|
|
70
|
+
break
|
|
71
|
+
default:
|
|
72
|
+
this.parseInteger = Math.trunc
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
asAny (i) {
|
|
78
|
+
return JSON.stringify(i)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
asNull () {
|
|
82
|
+
return 'null'
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
asInteger (i) {
|
|
86
|
+
if (typeof i === 'bigint') {
|
|
87
|
+
return i.toString()
|
|
88
|
+
} else if (Number.isInteger(i)) {
|
|
89
|
+
return '' + i
|
|
90
|
+
} else {
|
|
91
|
+
/* eslint no-undef: "off" */
|
|
92
|
+
const integer = this.parseInteger(i)
|
|
93
|
+
if (Number.isNaN(integer)) {
|
|
94
|
+
throw new Error(`The value "${i}" cannot be converted to an integer.`)
|
|
95
|
+
} else {
|
|
96
|
+
return '' + integer
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
asIntegerNullable (i) {
|
|
102
|
+
return i === null ? 'null' : this.asInteger(i)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
asNumber (i) {
|
|
106
|
+
const num = Number(i)
|
|
107
|
+
if (Number.isNaN(num)) {
|
|
108
|
+
throw new Error(`The value "${i}" cannot be converted to a number.`)
|
|
109
|
+
} else {
|
|
110
|
+
return '' + num
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
asNumberNullable (i) {
|
|
115
|
+
return i === null ? 'null' : this.asNumber(i)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
asBoolean (bool) {
|
|
119
|
+
return bool && 'true' || 'false' // eslint-disable-line
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
asBooleanNullable (bool) {
|
|
123
|
+
return bool === null ? 'null' : this.asBoolean(bool)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
asDatetime (date, skipQuotes) {
|
|
127
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
128
|
+
if (date instanceof Date) {
|
|
129
|
+
return quotes + date.toISOString() + quotes
|
|
130
|
+
}
|
|
131
|
+
return this.asString(date, skipQuotes)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
asDatetimeNullable (date, skipQuotes) {
|
|
135
|
+
return date === null ? 'null' : this.asDatetime(date, skipQuotes)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
asDate (date, skipQuotes) {
|
|
139
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
140
|
+
if (date instanceof Date) {
|
|
141
|
+
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + quotes
|
|
142
|
+
}
|
|
143
|
+
return this.asString(date, skipQuotes)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
asDateNullable (date, skipQuotes) {
|
|
147
|
+
return date === null ? 'null' : this.asDate(date, skipQuotes)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
asTime (date, skipQuotes) {
|
|
151
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
152
|
+
if (date instanceof Date) {
|
|
153
|
+
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + quotes
|
|
154
|
+
}
|
|
155
|
+
return this.asString(date, skipQuotes)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
asTimeNullable (date, skipQuotes) {
|
|
159
|
+
return date === null ? 'null' : this.asTime(date, skipQuotes)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
asString (str, skipQuotes) {
|
|
163
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
164
|
+
if (str instanceof Date) {
|
|
165
|
+
return quotes + str.toISOString() + quotes
|
|
166
|
+
} else if (str === null) {
|
|
167
|
+
return quotes + quotes
|
|
168
|
+
} else if (str instanceof RegExp) {
|
|
169
|
+
str = str.source
|
|
170
|
+
} else if (typeof str !== 'string') {
|
|
171
|
+
str = str.toString()
|
|
172
|
+
}
|
|
173
|
+
// If we skipQuotes it means that we are using it as test
|
|
174
|
+
// no need to test the string length for the render
|
|
175
|
+
if (skipQuotes) {
|
|
176
|
+
return str
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (str.length < 42) {
|
|
180
|
+
return this.asStringSmall(str)
|
|
181
|
+
} else {
|
|
182
|
+
return JSON.stringify(str)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
asStringNullable (str) {
|
|
187
|
+
return str === null ? 'null' : this.asString(str)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// magically escape strings for json
|
|
191
|
+
// relying on their charCodeAt
|
|
192
|
+
// everything below 32 needs JSON.stringify()
|
|
193
|
+
// every string that contain surrogate needs JSON.stringify()
|
|
194
|
+
// 34 and 92 happens all the time, so we
|
|
195
|
+
// have a fast case for them
|
|
196
|
+
asStringSmall (str) {
|
|
197
|
+
const l = str.length
|
|
198
|
+
let result = ''
|
|
199
|
+
let last = 0
|
|
200
|
+
let found = false
|
|
201
|
+
let surrogateFound = false
|
|
202
|
+
let point = 255
|
|
203
|
+
// eslint-disable-next-line
|
|
204
|
+
for (var i = 0; i < l && point >= 32; i++) {
|
|
205
|
+
point = str.charCodeAt(i)
|
|
206
|
+
if (point >= 0xD800 && point <= 0xDFFF) {
|
|
207
|
+
// The current character is a surrogate.
|
|
208
|
+
surrogateFound = true
|
|
209
|
+
}
|
|
210
|
+
if (point === 34 || point === 92) {
|
|
211
|
+
result += str.slice(last, i) + '\\'
|
|
212
|
+
last = i
|
|
213
|
+
found = true
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!found) {
|
|
218
|
+
result = str
|
|
219
|
+
} else {
|
|
220
|
+
result += str.slice(last)
|
|
221
|
+
}
|
|
222
|
+
return ((point < 32) || (surrogateFound === true)) ? JSON.stringify(str) : '"' + result + '"'
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
59
226
|
function build (schema, options) {
|
|
60
227
|
arrayItemsReferenceSerializersMap.clear()
|
|
61
228
|
objectReferenceSerializersMap.clear()
|
|
@@ -66,6 +233,29 @@ function build (schema, options) {
|
|
|
66
233
|
ajvInstance = new Ajv({ ...options.ajv, strictSchema: false, uriResolver: fastUri })
|
|
67
234
|
ajvFormats(ajvInstance)
|
|
68
235
|
|
|
236
|
+
const validateDateTimeFormat = ajvFormats.get('date-time').validate
|
|
237
|
+
const validateDateFormat = ajvFormats.get('date').validate
|
|
238
|
+
const validateTimeFormat = ajvFormats.get('time').validate
|
|
239
|
+
|
|
240
|
+
ajvInstance.addKeyword({
|
|
241
|
+
keyword: 'fjs_date_type',
|
|
242
|
+
validate: (schema, date) => {
|
|
243
|
+
if (date instanceof Date) {
|
|
244
|
+
return true
|
|
245
|
+
}
|
|
246
|
+
if (schema === 'date-time') {
|
|
247
|
+
return validateDateTimeFormat(date)
|
|
248
|
+
}
|
|
249
|
+
if (schema === 'date') {
|
|
250
|
+
return validateDateFormat(date)
|
|
251
|
+
}
|
|
252
|
+
if (schema === 'time') {
|
|
253
|
+
return validateTimeFormat(date)
|
|
254
|
+
}
|
|
255
|
+
return false
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
|
|
69
259
|
isValidSchema(schema)
|
|
70
260
|
if (options.schema) {
|
|
71
261
|
// eslint-disable-next-line
|
|
@@ -74,11 +264,8 @@ function build (schema, options) {
|
|
|
74
264
|
}
|
|
75
265
|
}
|
|
76
266
|
|
|
77
|
-
let intParseFunctionName = 'trunc'
|
|
78
267
|
if (options.rounding) {
|
|
79
|
-
if (['floor', 'ceil', 'round'].includes(options.rounding)) {
|
|
80
|
-
intParseFunctionName = options.rounding
|
|
81
|
-
} else {
|
|
268
|
+
if (!['floor', 'ceil', 'round'].includes(options.rounding)) {
|
|
82
269
|
throw new Error(`Unsupported integer rounding method ${options.rounding}`)
|
|
83
270
|
}
|
|
84
271
|
}
|
|
@@ -99,15 +286,7 @@ function build (schema, options) {
|
|
|
99
286
|
}
|
|
100
287
|
}
|
|
101
288
|
|
|
102
|
-
|
|
103
|
-
let code = `
|
|
104
|
-
'use strict'
|
|
105
|
-
`
|
|
106
|
-
|
|
107
|
-
code += `
|
|
108
|
-
${asFunctions}
|
|
109
|
-
function parseInteger(int) { return Math.${intParseFunctionName}(int) }
|
|
110
|
-
`
|
|
289
|
+
const serializer = new Serializer(options)
|
|
111
290
|
|
|
112
291
|
let location = {
|
|
113
292
|
schema,
|
|
@@ -124,62 +303,34 @@ function build (schema, options) {
|
|
|
124
303
|
schema.type = inferTypeByKeyword(schema)
|
|
125
304
|
}
|
|
126
305
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
code
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
main = schema.nullable ? '$asIntegerNullable' : '$asInteger'
|
|
139
|
-
break
|
|
140
|
-
case 'number':
|
|
141
|
-
main = schema.nullable ? '$asNumberNullable' : '$asNumber'
|
|
142
|
-
break
|
|
143
|
-
case 'boolean':
|
|
144
|
-
main = schema.nullable ? '$asBooleanNullable' : '$asBoolean'
|
|
145
|
-
break
|
|
146
|
-
case 'null':
|
|
147
|
-
main = '$asNull'
|
|
148
|
-
break
|
|
149
|
-
case 'array':
|
|
150
|
-
main = '$main'
|
|
151
|
-
code = buildArray(location, code, main)
|
|
152
|
-
schema = location.schema
|
|
153
|
-
break
|
|
154
|
-
case undefined:
|
|
155
|
-
main = '$asAny'
|
|
156
|
-
break
|
|
157
|
-
default:
|
|
158
|
-
throw new Error(`${schema.type} unsupported`)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
code += `
|
|
162
|
-
;
|
|
163
|
-
return ${main}
|
|
164
|
-
`
|
|
165
|
-
const dependencies = [ajvInstance]
|
|
166
|
-
const dependenciesName = ['ajv']
|
|
167
|
-
ajvInstance = null
|
|
306
|
+
const { code, laterCode } = buildValue('', 'main', 'input', location)
|
|
307
|
+
const contextFunctionCode = `
|
|
308
|
+
'use strict'
|
|
309
|
+
function main (input) {
|
|
310
|
+
let json = ''
|
|
311
|
+
${code}
|
|
312
|
+
return json
|
|
313
|
+
}
|
|
314
|
+
${laterCode}
|
|
315
|
+
return main
|
|
316
|
+
`
|
|
168
317
|
|
|
169
|
-
dependenciesName
|
|
318
|
+
const dependenciesName = ['ajv', 'serializer', contextFunctionCode]
|
|
170
319
|
|
|
171
320
|
if (options.debugMode) {
|
|
172
|
-
return {
|
|
173
|
-
code: dependenciesName.join('\n'),
|
|
174
|
-
ajv: dependencies[0]
|
|
175
|
-
}
|
|
321
|
+
return { code: dependenciesName.join('\n'), ajv: ajvInstance }
|
|
176
322
|
}
|
|
177
323
|
|
|
324
|
+
/* eslint no-new-func: "off" */
|
|
325
|
+
const contextFunc = new Function('ajv', 'serializer', contextFunctionCode)
|
|
326
|
+
const stringifyFunc = contextFunc(ajvInstance, serializer)
|
|
327
|
+
|
|
328
|
+
ajvInstance = null
|
|
178
329
|
arrayItemsReferenceSerializersMap.clear()
|
|
179
330
|
objectReferenceSerializersMap.clear()
|
|
180
331
|
schemaReferenceMap.clear()
|
|
181
332
|
|
|
182
|
-
return
|
|
333
|
+
return stringifyFunc
|
|
183
334
|
}
|
|
184
335
|
|
|
185
336
|
const objectKeywords = [
|
|
@@ -239,171 +390,15 @@ function inferTypeByKeyword (schema) {
|
|
|
239
390
|
return schema.type
|
|
240
391
|
}
|
|
241
392
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
function getStringSerializer (format) {
|
|
249
|
-
return stringSerializerMap[format] ||
|
|
250
|
-
'$asString'
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function getTestSerializer (format) {
|
|
254
|
-
return stringSerializerMap[format]
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const asFunctions = `
|
|
258
|
-
function $pad2Zeros (num) {
|
|
259
|
-
const s = '00' + num
|
|
260
|
-
return s[s.length - 2] + s[s.length - 1]
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function $asAny (i) {
|
|
264
|
-
return JSON.stringify(i)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function $asNull () {
|
|
268
|
-
return 'null'
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function $asInteger (i) {
|
|
272
|
-
if (typeof i === 'bigint') {
|
|
273
|
-
return i.toString()
|
|
274
|
-
} else if (Number.isInteger(i)) {
|
|
275
|
-
return $asNumber(i)
|
|
276
|
-
} else {
|
|
277
|
-
/* eslint no-undef: "off" */
|
|
278
|
-
return $asNumber(parseInteger(i))
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function $asIntegerNullable (i) {
|
|
283
|
-
return i === null ? null : $asInteger(i)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function $asNumber (i) {
|
|
287
|
-
const num = Number(i)
|
|
288
|
-
if (isNaN(num)) {
|
|
289
|
-
return 'null'
|
|
290
|
-
} else {
|
|
291
|
-
return '' + num
|
|
393
|
+
function getStringSerializer (format, nullable) {
|
|
394
|
+
switch (format) {
|
|
395
|
+
case 'date-time': return nullable ? 'serializer.asDatetimeNullable.bind(serializer)' : 'serializer.asDatetime.bind(serializer)'
|
|
396
|
+
case 'date': return nullable ? 'serializer.asDateNullable.bind(serializer)' : 'serializer.asDate.bind(serializer)'
|
|
397
|
+
case 'time': return nullable ? 'serializer.asTimeNullable.bind(serializer)' : 'serializer.asTime.bind(serializer)'
|
|
398
|
+
default: return nullable ? 'serializer.asStringNullable.bind(serializer)' : 'serializer.asString.bind(serializer)'
|
|
292
399
|
}
|
|
293
400
|
}
|
|
294
401
|
|
|
295
|
-
function $asNumberNullable (i) {
|
|
296
|
-
return i === null ? null : $asNumber(i)
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
function $asBoolean (bool) {
|
|
300
|
-
return bool && 'true' || 'false' // eslint-disable-line
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function $asBooleanNullable (bool) {
|
|
304
|
-
return bool === null ? null : $asBoolean(bool)
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
function $asDatetime (date, skipQuotes) {
|
|
308
|
-
const quotes = skipQuotes === true ? '' : '"'
|
|
309
|
-
if (date instanceof Date) {
|
|
310
|
-
return quotes + date.toISOString() + quotes
|
|
311
|
-
} else if (date && typeof date.toISOString === 'function') {
|
|
312
|
-
return quotes + date.toISOString() + quotes
|
|
313
|
-
} else {
|
|
314
|
-
return $asString(date, skipQuotes)
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
function $asDate (date, skipQuotes) {
|
|
319
|
-
const quotes = skipQuotes === true ? '' : '"'
|
|
320
|
-
if (date instanceof Date) {
|
|
321
|
-
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000 )).toISOString().slice(0, 10) + quotes
|
|
322
|
-
} else if (date && typeof date.format === 'function') {
|
|
323
|
-
return quotes + date.format('YYYY-MM-DD') + quotes
|
|
324
|
-
} else {
|
|
325
|
-
return $asString(date, skipQuotes)
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function $asTime (date, skipQuotes) {
|
|
330
|
-
const quotes = skipQuotes === true ? '' : '"'
|
|
331
|
-
if (date instanceof Date) {
|
|
332
|
-
const hour = new Intl.DateTimeFormat('en', { hour: 'numeric', hour12: false }).format(date)
|
|
333
|
-
const minute = new Intl.DateTimeFormat('en', { minute: 'numeric' }).format(date)
|
|
334
|
-
const second = new Intl.DateTimeFormat('en', { second: 'numeric' }).format(date)
|
|
335
|
-
return quotes + $pad2Zeros(hour) + ':' + $pad2Zeros(minute) + ':' + $pad2Zeros(second) + quotes
|
|
336
|
-
} else if (date && typeof date.format === 'function') {
|
|
337
|
-
return quotes + date.format('HH:mm:ss') + quotes
|
|
338
|
-
} else {
|
|
339
|
-
return $asString(date, skipQuotes)
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function $asString (str, skipQuotes) {
|
|
344
|
-
const quotes = skipQuotes === true ? '' : '"'
|
|
345
|
-
if (str instanceof Date) {
|
|
346
|
-
return quotes + str.toISOString() + quotes
|
|
347
|
-
} else if (str === null) {
|
|
348
|
-
return quotes + quotes
|
|
349
|
-
} else if (str instanceof RegExp) {
|
|
350
|
-
str = str.source
|
|
351
|
-
} else if (typeof str !== 'string') {
|
|
352
|
-
str = str.toString()
|
|
353
|
-
}
|
|
354
|
-
// If we skipQuotes it means that we are using it as test
|
|
355
|
-
// no need to test the string length for the render
|
|
356
|
-
if (skipQuotes) {
|
|
357
|
-
return str
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (str.length < 42) {
|
|
361
|
-
return $asStringSmall(str)
|
|
362
|
-
} else {
|
|
363
|
-
return JSON.stringify(str)
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
function $asStringNullable (str) {
|
|
368
|
-
return str === null ? null : $asString(str)
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// magically escape strings for json
|
|
372
|
-
// relying on their charCodeAt
|
|
373
|
-
// everything below 32 needs JSON.stringify()
|
|
374
|
-
// every string that contain surrogate needs JSON.stringify()
|
|
375
|
-
// 34 and 92 happens all the time, so we
|
|
376
|
-
// have a fast case for them
|
|
377
|
-
function $asStringSmall (str) {
|
|
378
|
-
const l = str.length
|
|
379
|
-
let result = ''
|
|
380
|
-
let last = 0
|
|
381
|
-
let found = false
|
|
382
|
-
let surrogateFound = false
|
|
383
|
-
let point = 255
|
|
384
|
-
// eslint-disable-next-line
|
|
385
|
-
for (var i = 0; i < l && point >= 32; i++) {
|
|
386
|
-
point = str.charCodeAt(i)
|
|
387
|
-
if (point >= 0xD800 && point <= 0xDFFF) {
|
|
388
|
-
// The current character is a surrogate.
|
|
389
|
-
surrogateFound = true
|
|
390
|
-
}
|
|
391
|
-
if (point === 34 || point === 92) {
|
|
392
|
-
result += str.slice(last, i) + '\\\\'
|
|
393
|
-
last = i
|
|
394
|
-
found = true
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (!found) {
|
|
399
|
-
result = str
|
|
400
|
-
} else {
|
|
401
|
-
result += str.slice(last)
|
|
402
|
-
}
|
|
403
|
-
return ((point < 32) || (surrogateFound === true)) ? JSON.stringify(str) : '"' + result + '"'
|
|
404
|
-
}
|
|
405
|
-
`
|
|
406
|
-
|
|
407
402
|
function addPatternProperties (location) {
|
|
408
403
|
const schema = location.schema
|
|
409
404
|
const pp = schema.patternProperties
|
|
@@ -413,103 +408,56 @@ function addPatternProperties (location) {
|
|
|
413
408
|
for (var i = 0; i < keys.length; i++) {
|
|
414
409
|
if (properties[keys[i]]) continue
|
|
415
410
|
`
|
|
411
|
+
let laterCode = ''
|
|
412
|
+
|
|
416
413
|
Object.keys(pp).forEach((regex, index) => {
|
|
417
414
|
let ppLocation = mergeLocation(location, { schema: pp[regex] })
|
|
418
415
|
if (pp[regex].$ref) {
|
|
419
416
|
ppLocation = refFinder(pp[regex].$ref, location)
|
|
420
417
|
pp[regex] = ppLocation.schema
|
|
421
418
|
}
|
|
422
|
-
|
|
423
|
-
const format = pp[regex].format
|
|
424
|
-
const stringSerializer = getStringSerializer(format)
|
|
419
|
+
|
|
425
420
|
try {
|
|
426
421
|
RegExp(regex)
|
|
427
422
|
} catch (err) {
|
|
428
423
|
throw new Error(`${err.message}. Found at ${regex} matching ${JSON.stringify(pp[regex])}`)
|
|
429
424
|
}
|
|
430
425
|
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
if (type === 'object') {
|
|
434
|
-
code += `${buildObject(ppLocation, '', 'buildObjectPP' + index)}
|
|
435
|
-
${ifPpKeyExists}
|
|
436
|
-
${addComma}
|
|
437
|
-
json += $asString(keys[i]) + ':' + buildObjectPP${index}(obj[keys[i]])
|
|
438
|
-
`
|
|
439
|
-
} else if (type === 'array') {
|
|
440
|
-
code += `${buildArray(ppLocation, '', 'buildArrayPP' + index)}
|
|
441
|
-
${ifPpKeyExists}
|
|
442
|
-
${addComma}
|
|
443
|
-
json += $asString(keys[i]) + ':' + buildArrayPP${index}(obj[keys[i]])
|
|
444
|
-
`
|
|
445
|
-
} else if (type === 'null') {
|
|
446
|
-
code += `
|
|
447
|
-
${ifPpKeyExists}
|
|
448
|
-
${addComma}
|
|
449
|
-
json += $asString(keys[i]) +':null'
|
|
450
|
-
`
|
|
451
|
-
} else if (type === 'string') {
|
|
452
|
-
code += `
|
|
453
|
-
${ifPpKeyExists}
|
|
454
|
-
${addComma}
|
|
455
|
-
json += $asString(keys[i]) + ':' + ${stringSerializer}(obj[keys[i]])
|
|
456
|
-
`
|
|
457
|
-
} else if (type === 'integer') {
|
|
458
|
-
code += `
|
|
459
|
-
${ifPpKeyExists}
|
|
460
|
-
${addComma}
|
|
461
|
-
json += $asString(keys[i]) + ':' + $asInteger(obj[keys[i]])
|
|
462
|
-
`
|
|
463
|
-
} else if (type === 'number') {
|
|
464
|
-
code += `
|
|
465
|
-
${ifPpKeyExists}
|
|
466
|
-
${addComma}
|
|
467
|
-
json += $asString(keys[i]) + ':' + $asNumber(obj[keys[i]])
|
|
468
|
-
`
|
|
469
|
-
} else if (type === 'boolean') {
|
|
470
|
-
code += `
|
|
471
|
-
${ifPpKeyExists}
|
|
472
|
-
${addComma}
|
|
473
|
-
json += $asString(keys[i]) + ':' + $asBoolean(obj[keys[i]])
|
|
474
|
-
`
|
|
475
|
-
} else if (type === undefined) {
|
|
476
|
-
code += `
|
|
477
|
-
${ifPpKeyExists}
|
|
478
|
-
${addComma}
|
|
479
|
-
json += $asString(keys[i]) + ':' + $asAny(obj[keys[i]])
|
|
480
|
-
`
|
|
481
|
-
} else {
|
|
482
|
-
code += `
|
|
483
|
-
${ifPpKeyExists}
|
|
484
|
-
throw new Error('Cannot coerce ' + obj[keys[i]] + ' to ' + ${JSON.stringify(type)})
|
|
485
|
-
`
|
|
486
|
-
}
|
|
487
|
-
|
|
426
|
+
const valueCode = buildValue('', '', 'obj[keys[i]]', ppLocation)
|
|
427
|
+
laterCode += valueCode.laterCode
|
|
488
428
|
code += `
|
|
489
|
-
|
|
490
|
-
}
|
|
429
|
+
if (/${regex.replace(/\\*\//g, '\\/')}/.test(keys[i])) {
|
|
430
|
+
${addComma}
|
|
431
|
+
json += serializer.asString(keys[i]) + ':'
|
|
432
|
+
${valueCode.code}
|
|
433
|
+
continue
|
|
434
|
+
}
|
|
491
435
|
`
|
|
492
436
|
})
|
|
493
437
|
if (schema.additionalProperties) {
|
|
494
|
-
|
|
438
|
+
const additionalPropertyCode = additionalProperty(location)
|
|
439
|
+
code += additionalPropertyCode.code
|
|
440
|
+
laterCode += additionalPropertyCode.laterCode
|
|
495
441
|
}
|
|
496
442
|
|
|
497
443
|
code += `
|
|
498
444
|
}
|
|
499
445
|
`
|
|
500
|
-
return code
|
|
446
|
+
return { code, laterCode }
|
|
501
447
|
}
|
|
502
448
|
|
|
503
449
|
function additionalProperty (location) {
|
|
504
450
|
let ap = location.schema.additionalProperties
|
|
505
451
|
let code = ''
|
|
506
452
|
if (ap === true) {
|
|
507
|
-
|
|
453
|
+
code += `
|
|
508
454
|
if (obj[keys[i]] !== undefined && typeof obj[keys[i]] !== 'function' && typeof obj[keys[i]] !== 'symbol') {
|
|
509
455
|
${addComma}
|
|
510
|
-
json +=
|
|
456
|
+
json += serializer.asString(keys[i]) + ':' + JSON.stringify(obj[keys[i]])
|
|
511
457
|
}
|
|
512
458
|
`
|
|
459
|
+
|
|
460
|
+
return { code, laterCode: '' }
|
|
513
461
|
}
|
|
514
462
|
let apLocation = mergeLocation(location, { schema: ap })
|
|
515
463
|
if (ap.$ref) {
|
|
@@ -517,72 +465,29 @@ function additionalProperty (location) {
|
|
|
517
465
|
ap = apLocation.schema
|
|
518
466
|
}
|
|
519
467
|
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
code += `${buildArray(apLocation, '', 'buildArrayAP')}
|
|
530
|
-
${addComma}
|
|
531
|
-
json += $asString(keys[i]) + ':' + buildArrayAP(obj[keys[i]])
|
|
532
|
-
`
|
|
533
|
-
} else if (type === 'null') {
|
|
534
|
-
code += `
|
|
535
|
-
${addComma}
|
|
536
|
-
json += $asString(keys[i]) +':null'
|
|
537
|
-
`
|
|
538
|
-
} else if (type === 'string') {
|
|
539
|
-
code += `
|
|
540
|
-
${addComma}
|
|
541
|
-
json += $asString(keys[i]) + ':' + ${stringSerializer}(obj[keys[i]])
|
|
542
|
-
`
|
|
543
|
-
} else if (type === 'integer') {
|
|
544
|
-
code += `
|
|
545
|
-
var t = Number(obj[keys[i]])
|
|
546
|
-
if (!isNaN(t)) {
|
|
547
|
-
${addComma}
|
|
548
|
-
json += $asString(keys[i]) + ':' + t
|
|
549
|
-
}
|
|
550
|
-
`
|
|
551
|
-
} else if (type === 'number') {
|
|
552
|
-
code += `
|
|
553
|
-
var t = Number(obj[keys[i]])
|
|
554
|
-
if (!isNaN(t)) {
|
|
555
|
-
${addComma}
|
|
556
|
-
json += $asString(keys[i]) + ':' + t
|
|
557
|
-
}
|
|
558
|
-
`
|
|
559
|
-
} else if (type === 'boolean') {
|
|
560
|
-
code += `
|
|
561
|
-
${addComma}
|
|
562
|
-
json += $asString(keys[i]) + ':' + $asBoolean(obj[keys[i]])
|
|
563
|
-
`
|
|
564
|
-
} else if (type === undefined) {
|
|
565
|
-
code += `
|
|
566
|
-
${addComma}
|
|
567
|
-
json += $asString(keys[i]) + ':' + $asAny(obj[keys[i]])
|
|
568
|
-
`
|
|
569
|
-
} else {
|
|
570
|
-
code += `
|
|
571
|
-
throw new Error('Cannot coerce ' + obj[keys[i]] + ' to ' + ${JSON.stringify(type)})
|
|
572
|
-
`
|
|
573
|
-
}
|
|
574
|
-
return code
|
|
468
|
+
const valueCode = buildValue('', '', 'obj[keys[i]]', apLocation)
|
|
469
|
+
|
|
470
|
+
code += `
|
|
471
|
+
${addComma}
|
|
472
|
+
json += serializer.asString(keys[i]) + ':'
|
|
473
|
+
${valueCode.code}
|
|
474
|
+
`
|
|
475
|
+
|
|
476
|
+
return { code, laterCode: valueCode.laterCode }
|
|
575
477
|
}
|
|
576
478
|
|
|
577
479
|
function addAdditionalProperties (location) {
|
|
578
|
-
|
|
480
|
+
const additionalPropertyCode = additionalProperty(location)
|
|
481
|
+
const code = `
|
|
579
482
|
var properties = ${JSON.stringify(location.schema.properties)} || {}
|
|
580
483
|
var keys = Object.keys(obj)
|
|
581
484
|
for (var i = 0; i < keys.length; i++) {
|
|
582
485
|
if (properties[keys[i]]) continue
|
|
583
|
-
${
|
|
486
|
+
${additionalPropertyCode.code}
|
|
584
487
|
}
|
|
585
488
|
`
|
|
489
|
+
|
|
490
|
+
return { code, laterCode: additionalPropertyCode.laterCode }
|
|
586
491
|
}
|
|
587
492
|
|
|
588
493
|
function idFinder (schema, searchedId) {
|
|
@@ -716,15 +621,15 @@ function refFinder (ref, location) {
|
|
|
716
621
|
}
|
|
717
622
|
}
|
|
718
623
|
|
|
719
|
-
function buildCode (location, code, laterCode,
|
|
624
|
+
function buildCode (location, code, laterCode, locationPath) {
|
|
720
625
|
if (location.schema.$ref) {
|
|
721
626
|
location = refFinder(location.schema.$ref, location)
|
|
722
627
|
}
|
|
723
628
|
|
|
724
629
|
const schema = location.schema
|
|
725
|
-
|
|
630
|
+
const required = schema.required || []
|
|
726
631
|
|
|
727
|
-
Object.keys(schema.properties || {}).forEach((key
|
|
632
|
+
Object.keys(schema.properties || {}).forEach((key) => {
|
|
728
633
|
let propertyLocation = mergeLocation(location, { schema: schema.properties[key] })
|
|
729
634
|
if (schema.properties[key].$ref) {
|
|
730
635
|
propertyLocation = refFinder(schema.properties[key].$ref, location)
|
|
@@ -734,61 +639,27 @@ function buildCode (location, code, laterCode, name) {
|
|
|
734
639
|
// Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
|
|
735
640
|
// see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
|
|
736
641
|
|
|
737
|
-
const type = schema.properties[key].type
|
|
738
|
-
const nullable = schema.properties[key].nullable
|
|
739
642
|
const sanitized = JSON.stringify(key)
|
|
740
643
|
const asString = JSON.stringify(sanitized)
|
|
741
644
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
json += ${asString} + ':null'
|
|
747
|
-
var rendered = true
|
|
748
|
-
} else {
|
|
749
|
-
`
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
if (type === 'number') {
|
|
753
|
-
code += `
|
|
754
|
-
var t = Number(obj[${sanitized}])
|
|
755
|
-
if (!isNaN(t)) {
|
|
756
|
-
${addComma}
|
|
757
|
-
json += ${asString} + ':' + t
|
|
758
|
-
`
|
|
759
|
-
} else if (type === 'integer') {
|
|
760
|
-
code += `
|
|
761
|
-
var rendered = false
|
|
762
|
-
var t = $asInteger(obj[${sanitized}])
|
|
763
|
-
if (!isNaN(t)) {
|
|
764
|
-
${addComma}
|
|
765
|
-
json += ${asString} + ':' + t
|
|
766
|
-
rendered = true
|
|
767
|
-
}
|
|
768
|
-
if (rendered) {
|
|
645
|
+
code += `
|
|
646
|
+
if (obj[${sanitized}] !== undefined) {
|
|
647
|
+
${addComma}
|
|
648
|
+
json += ${asString} + ':'
|
|
769
649
|
`
|
|
770
|
-
} else {
|
|
771
|
-
code += `
|
|
772
|
-
if (obj[${sanitized}] !== undefined) {
|
|
773
|
-
${addComma}
|
|
774
|
-
json += ${asString} + ':'
|
|
775
|
-
`
|
|
776
650
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
}
|
|
651
|
+
const result = buildValue(laterCode, locationPath + key, `obj[${JSON.stringify(key)}]`, mergeLocation(propertyLocation, { schema: schema.properties[key] }))
|
|
652
|
+
code += result.code
|
|
653
|
+
laterCode = result.laterCode
|
|
781
654
|
|
|
782
655
|
const defaultValue = schema.properties[key].default
|
|
783
656
|
if (defaultValue !== undefined) {
|
|
784
|
-
required = filterRequired(required, key)
|
|
785
657
|
code += `
|
|
786
658
|
} else {
|
|
787
659
|
${addComma}
|
|
788
660
|
json += ${asString} + ':' + ${JSON.stringify(JSON.stringify(defaultValue))}
|
|
789
661
|
`
|
|
790
|
-
} else if (required
|
|
791
|
-
required = filterRequired(required, key)
|
|
662
|
+
} else if (required.includes(key)) {
|
|
792
663
|
code += `
|
|
793
664
|
} else {
|
|
794
665
|
throw new Error('${sanitized} is required!')
|
|
@@ -798,75 +669,122 @@ function buildCode (location, code, laterCode, name) {
|
|
|
798
669
|
code += `
|
|
799
670
|
}
|
|
800
671
|
`
|
|
672
|
+
})
|
|
801
673
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
674
|
+
for (const requiredProperty of required) {
|
|
675
|
+
if (schema.properties && schema.properties[requiredProperty] !== undefined) continue
|
|
676
|
+
code += `if (obj['${requiredProperty}'] === undefined) throw new Error('"${requiredProperty}" is required!')\n`
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return { code, laterCode }
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function mergeAllOfSchema (location, schema, mergedSchema) {
|
|
683
|
+
for (let allOfSchema of schema.allOf) {
|
|
684
|
+
if (allOfSchema.$ref) {
|
|
685
|
+
allOfSchema = refFinder(allOfSchema.$ref, mergeLocation(location, { schema: allOfSchema })).schema
|
|
806
686
|
}
|
|
807
|
-
})
|
|
808
687
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
688
|
+
let allOfSchemaType = allOfSchema.type
|
|
689
|
+
if (allOfSchemaType === undefined) {
|
|
690
|
+
allOfSchemaType = inferTypeByKeyword(allOfSchema)
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (allOfSchemaType !== undefined) {
|
|
694
|
+
if (
|
|
695
|
+
mergedSchema.type !== undefined &&
|
|
696
|
+
mergedSchema.type !== allOfSchemaType
|
|
697
|
+
) {
|
|
698
|
+
throw new Error('allOf schemas have different type values')
|
|
815
699
|
}
|
|
816
|
-
|
|
700
|
+
mergedSchema.type = allOfSchemaType
|
|
817
701
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
702
|
+
|
|
703
|
+
if (allOfSchema.format !== undefined) {
|
|
704
|
+
if (
|
|
705
|
+
mergedSchema.format !== undefined &&
|
|
706
|
+
mergedSchema.format !== allOfSchema.format
|
|
707
|
+
) {
|
|
708
|
+
throw new Error('allOf schemas have different format values')
|
|
821
709
|
}
|
|
822
|
-
|
|
823
|
-
|
|
710
|
+
mergedSchema.format = allOfSchema.format
|
|
711
|
+
}
|
|
824
712
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
713
|
+
if (allOfSchema.nullable !== undefined) {
|
|
714
|
+
if (
|
|
715
|
+
mergedSchema.nullable !== undefined &&
|
|
716
|
+
mergedSchema.nullable !== allOfSchema.nullable
|
|
717
|
+
) {
|
|
718
|
+
throw new Error('allOf schemas have different nullable values')
|
|
719
|
+
}
|
|
720
|
+
mergedSchema.nullable = allOfSchema.nullable
|
|
721
|
+
}
|
|
830
722
|
|
|
831
|
-
|
|
832
|
-
|
|
723
|
+
if (allOfSchema.properties !== undefined) {
|
|
724
|
+
if (mergedSchema.properties === undefined) {
|
|
725
|
+
mergedSchema.properties = {}
|
|
726
|
+
}
|
|
727
|
+
Object.assign(mergedSchema.properties, allOfSchema.properties)
|
|
728
|
+
}
|
|
833
729
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
}
|
|
730
|
+
if (allOfSchema.additionalProperties !== undefined) {
|
|
731
|
+
if (mergedSchema.additionalProperties === undefined) {
|
|
732
|
+
mergedSchema.additionalProperties = {}
|
|
733
|
+
}
|
|
734
|
+
Object.assign(mergedSchema.additionalProperties, allOfSchema.additionalProperties)
|
|
735
|
+
}
|
|
840
736
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
})
|
|
848
|
-
} else {
|
|
849
|
-
const builtCode = buildCode(location, code, laterCode, name)
|
|
737
|
+
if (allOfSchema.patternProperties !== undefined) {
|
|
738
|
+
if (mergedSchema.patternProperties === undefined) {
|
|
739
|
+
mergedSchema.patternProperties = {}
|
|
740
|
+
}
|
|
741
|
+
Object.assign(mergedSchema.patternProperties, allOfSchema.patternProperties)
|
|
742
|
+
}
|
|
850
743
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
744
|
+
if (allOfSchema.required !== undefined) {
|
|
745
|
+
if (mergedSchema.required === undefined) {
|
|
746
|
+
mergedSchema.required = []
|
|
747
|
+
}
|
|
748
|
+
mergedSchema.required.push(...allOfSchema.required)
|
|
749
|
+
}
|
|
854
750
|
|
|
855
|
-
|
|
751
|
+
if (allOfSchema.oneOf !== undefined) {
|
|
752
|
+
if (mergedSchema.oneOf === undefined) {
|
|
753
|
+
mergedSchema.oneOf = []
|
|
754
|
+
}
|
|
755
|
+
mergedSchema.oneOf.push(...allOfSchema.oneOf)
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (allOfSchema.anyOf !== undefined) {
|
|
759
|
+
if (mergedSchema.anyOf === undefined) {
|
|
760
|
+
mergedSchema.anyOf = []
|
|
761
|
+
}
|
|
762
|
+
mergedSchema.anyOf.push(...allOfSchema.anyOf)
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (allOfSchema.allOf !== undefined) {
|
|
766
|
+
mergeAllOfSchema(location, allOfSchema, mergedSchema)
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
delete mergedSchema.allOf
|
|
856
770
|
}
|
|
857
771
|
|
|
858
|
-
function buildInnerObject (location,
|
|
772
|
+
function buildInnerObject (location, locationPath) {
|
|
859
773
|
const schema = location.schema
|
|
860
|
-
const result =
|
|
774
|
+
const result = buildCode(location, '', '', locationPath)
|
|
861
775
|
if (schema.patternProperties) {
|
|
862
|
-
|
|
776
|
+
const { code, laterCode } = addPatternProperties(location)
|
|
777
|
+
result.code += code
|
|
778
|
+
result.laterCode += laterCode
|
|
863
779
|
} else if (schema.additionalProperties && !schema.patternProperties) {
|
|
864
|
-
|
|
780
|
+
const { code, laterCode } = addAdditionalProperties(location)
|
|
781
|
+
result.code += code
|
|
782
|
+
result.laterCode += laterCode
|
|
865
783
|
}
|
|
866
784
|
return result
|
|
867
785
|
}
|
|
868
786
|
|
|
869
|
-
function addIfThenElse (location,
|
|
787
|
+
function addIfThenElse (location, locationPath) {
|
|
870
788
|
let code = ''
|
|
871
789
|
let r
|
|
872
790
|
let laterCode = ''
|
|
@@ -891,12 +809,12 @@ function addIfThenElse (location, name) {
|
|
|
891
809
|
if (valid) {
|
|
892
810
|
`
|
|
893
811
|
if (merged.if && merged.then) {
|
|
894
|
-
innerR = addIfThenElse(mergedLocation,
|
|
812
|
+
innerR = addIfThenElse(mergedLocation, locationPath + 'Then')
|
|
895
813
|
code += innerR.code
|
|
896
814
|
laterCode = innerR.laterCode
|
|
897
815
|
}
|
|
898
816
|
|
|
899
|
-
r = buildInnerObject(mergedLocation,
|
|
817
|
+
r = buildInnerObject(mergedLocation, locationPath + 'Then')
|
|
900
818
|
code += r.code
|
|
901
819
|
laterCode += r.laterCode
|
|
902
820
|
|
|
@@ -911,12 +829,12 @@ function addIfThenElse (location, name) {
|
|
|
911
829
|
`
|
|
912
830
|
|
|
913
831
|
if (merged.if && merged.then) {
|
|
914
|
-
innerR = addIfThenElse(mergedLocation,
|
|
832
|
+
innerR = addIfThenElse(mergedLocation, locationPath + 'Else')
|
|
915
833
|
code += innerR.code
|
|
916
834
|
laterCode += innerR.laterCode
|
|
917
835
|
}
|
|
918
836
|
|
|
919
|
-
r = buildInnerObject(mergedLocation,
|
|
837
|
+
r = buildInnerObject(mergedLocation, locationPath + 'Else')
|
|
920
838
|
code += r.code
|
|
921
839
|
laterCode += r.laterCode
|
|
922
840
|
|
|
@@ -933,13 +851,14 @@ function toJSON (variableName) {
|
|
|
933
851
|
`
|
|
934
852
|
}
|
|
935
853
|
|
|
936
|
-
function buildObject (location, code,
|
|
854
|
+
function buildObject (location, code, functionName, locationPath) {
|
|
937
855
|
const schema = location.schema
|
|
938
856
|
if (schema.$id !== undefined) {
|
|
939
857
|
schemaReferenceMap.set(schema.$id, schema)
|
|
940
858
|
}
|
|
941
859
|
code += `
|
|
942
|
-
function ${
|
|
860
|
+
function ${functionName} (input) {
|
|
861
|
+
// ${locationPath}
|
|
943
862
|
`
|
|
944
863
|
if (schema.nullable) {
|
|
945
864
|
code += `
|
|
@@ -949,14 +868,14 @@ function buildObject (location, code, name) {
|
|
|
949
868
|
`
|
|
950
869
|
}
|
|
951
870
|
|
|
952
|
-
if (objectReferenceSerializersMap.has(schema) && objectReferenceSerializersMap.get(schema) !==
|
|
871
|
+
if (objectReferenceSerializersMap.has(schema) && objectReferenceSerializersMap.get(schema) !== functionName) {
|
|
953
872
|
code += `
|
|
954
873
|
return ${objectReferenceSerializersMap.get(schema)}(input)
|
|
955
874
|
}
|
|
956
875
|
`
|
|
957
876
|
return code
|
|
958
877
|
}
|
|
959
|
-
objectReferenceSerializersMap.set(schema,
|
|
878
|
+
objectReferenceSerializersMap.set(schema, functionName)
|
|
960
879
|
|
|
961
880
|
code += `
|
|
962
881
|
var obj = ${toJSON('input')}
|
|
@@ -969,9 +888,9 @@ function buildObject (location, code, name) {
|
|
|
969
888
|
code += `
|
|
970
889
|
var valid
|
|
971
890
|
`
|
|
972
|
-
r = addIfThenElse(location,
|
|
891
|
+
r = addIfThenElse(location, locationPath)
|
|
973
892
|
} else {
|
|
974
|
-
r = buildInnerObject(location,
|
|
893
|
+
r = buildInnerObject(location, locationPath)
|
|
975
894
|
}
|
|
976
895
|
|
|
977
896
|
// Removes the comma if is the last element of the string (in case there are not properties)
|
|
@@ -985,13 +904,14 @@ function buildObject (location, code, name) {
|
|
|
985
904
|
return code
|
|
986
905
|
}
|
|
987
906
|
|
|
988
|
-
function buildArray (location, code,
|
|
907
|
+
function buildArray (location, code, functionName, locationPath) {
|
|
989
908
|
let schema = location.schema
|
|
990
909
|
if (schema.$id !== undefined) {
|
|
991
910
|
schemaReferenceMap.set(schema.$id, schema)
|
|
992
911
|
}
|
|
993
912
|
code += `
|
|
994
|
-
function ${
|
|
913
|
+
function ${functionName} (obj) {
|
|
914
|
+
// ${locationPath}
|
|
995
915
|
`
|
|
996
916
|
if (schema.nullable) {
|
|
997
917
|
code += `
|
|
@@ -1024,14 +944,14 @@ function buildArray (location, code, name, key = null) {
|
|
|
1024
944
|
`
|
|
1025
945
|
return code
|
|
1026
946
|
}
|
|
1027
|
-
arrayItemsReferenceSerializersMap.set(schema.items,
|
|
947
|
+
arrayItemsReferenceSerializersMap.set(schema.items, functionName)
|
|
1028
948
|
}
|
|
1029
949
|
|
|
1030
950
|
let result = { code: '', laterCode: '' }
|
|
1031
951
|
const accessor = '[i]'
|
|
1032
952
|
if (Array.isArray(schema.items)) {
|
|
1033
953
|
result = schema.items.reduce((res, item, i) => {
|
|
1034
|
-
const tmpRes =
|
|
954
|
+
const tmpRes = buildValue(laterCode, locationPath + accessor + i, 'obj[i]', mergeLocation(location, { schema: item }))
|
|
1035
955
|
const condition = `i === ${i} && ${buildArrayTypeCondition(item.type, accessor)}`
|
|
1036
956
|
return {
|
|
1037
957
|
code: `${res.code}
|
|
@@ -1044,7 +964,7 @@ function buildArray (location, code, name, key = null) {
|
|
|
1044
964
|
}, result)
|
|
1045
965
|
|
|
1046
966
|
if (schema.additionalItems) {
|
|
1047
|
-
const tmpRes =
|
|
967
|
+
const tmpRes = buildValue(laterCode, locationPath + accessor, 'obj[i]', mergeLocation(location, { schema: schema.items }))
|
|
1048
968
|
result.code += `
|
|
1049
969
|
else if (i >= ${schema.items.length}) {
|
|
1050
970
|
${tmpRes.code}
|
|
@@ -1058,54 +978,39 @@ function buildArray (location, code, name, key = null) {
|
|
|
1058
978
|
}
|
|
1059
979
|
`
|
|
1060
980
|
} else {
|
|
1061
|
-
result =
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
if (key) {
|
|
1065
|
-
code += `
|
|
1066
|
-
if(!Array.isArray(obj)) {
|
|
1067
|
-
throw new TypeError(\`Property '${key}' should be of type array, received '$\{obj}' instead.\`)
|
|
1068
|
-
}
|
|
1069
|
-
`
|
|
981
|
+
result = buildValue(laterCode, locationPath + accessor, 'obj[i]', mergeLocation(location, { schema: schema.items }))
|
|
1070
982
|
}
|
|
1071
983
|
|
|
1072
984
|
code += `
|
|
1073
|
-
|
|
1074
|
-
|
|
985
|
+
if (!Array.isArray(obj)) {
|
|
986
|
+
throw new TypeError(\`The value '$\{obj}' does not match schema definition.\`)
|
|
987
|
+
}
|
|
988
|
+
`
|
|
1075
989
|
|
|
1076
|
-
const
|
|
990
|
+
code += 'const arrayLength = obj.length\n'
|
|
991
|
+
if (largeArrayMechanism !== 'default') {
|
|
992
|
+
if (largeArrayMechanism === 'json-stringify') {
|
|
993
|
+
code += `if (arrayLength && arrayLength >= ${largeArraySize}) return JSON.stringify(obj)\n`
|
|
994
|
+
} else {
|
|
995
|
+
throw new Error(`Unsupported large array mechanism ${largeArrayMechanism}`)
|
|
1077
996
|
}
|
|
997
|
+
}
|
|
1078
998
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
999
|
+
code += `
|
|
1000
|
+
let jsonOutput= ''
|
|
1001
|
+
for (let i = 0; i < arrayLength; i++) {
|
|
1002
|
+
let json = ''
|
|
1082
1003
|
${result.code}
|
|
1083
1004
|
jsonOutput += json
|
|
1084
1005
|
|
|
1085
|
-
if (json.length > 0 && i <
|
|
1006
|
+
if (json.length > 0 && i < arrayLength - 1) {
|
|
1086
1007
|
jsonOutput += ','
|
|
1087
1008
|
}
|
|
1088
1009
|
}
|
|
1089
1010
|
return \`[\${jsonOutput}]\`
|
|
1090
1011
|
}`
|
|
1091
1012
|
|
|
1092
|
-
switch (largeArrayMechanism) {
|
|
1093
|
-
case 'default':
|
|
1094
|
-
code += `
|
|
1095
|
-
return \`[\${obj.map(${result.mapFnName}).join(',')}]\``
|
|
1096
|
-
break
|
|
1097
|
-
|
|
1098
|
-
case 'json-stringify':
|
|
1099
|
-
code += `
|
|
1100
|
-
return JSON.stringify(obj)`
|
|
1101
|
-
break
|
|
1102
|
-
|
|
1103
|
-
default:
|
|
1104
|
-
throw new Error(`Unsupported large array mechanism ${largeArrayMechanism}`)
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
1013
|
code += `
|
|
1108
|
-
${concatSnippet}
|
|
1109
1014
|
${result.laterCode}
|
|
1110
1015
|
`
|
|
1111
1016
|
|
|
@@ -1173,26 +1078,12 @@ function dereferenceOfRefs (location, type) {
|
|
|
1173
1078
|
return locations
|
|
1174
1079
|
}
|
|
1175
1080
|
|
|
1176
|
-
let
|
|
1177
|
-
function
|
|
1178
|
-
|
|
1179
|
-
let rep = str.replace(/[^a-zA-Z0-9$_]/g, '')
|
|
1180
|
-
|
|
1181
|
-
if (rep.length === 0) {
|
|
1182
|
-
return 'anan' + strNameCounter++
|
|
1183
|
-
} else if (rep !== str) {
|
|
1184
|
-
rep += strNameCounter++
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
return rep
|
|
1081
|
+
let genFuncNameCounter = 0
|
|
1082
|
+
function generateFuncName () {
|
|
1083
|
+
return 'anonymous' + genFuncNameCounter++
|
|
1188
1084
|
}
|
|
1189
1085
|
|
|
1190
|
-
function
|
|
1191
|
-
let code = ''
|
|
1192
|
-
let funcName
|
|
1193
|
-
|
|
1194
|
-
subKey = subKey || ''
|
|
1195
|
-
|
|
1086
|
+
function buildValue (laterCode, locationPath, input, location) {
|
|
1196
1087
|
let schema = location.schema
|
|
1197
1088
|
|
|
1198
1089
|
if (schema.$ref) {
|
|
@@ -1206,121 +1097,99 @@ function nested (laterCode, name, key, location, subKey, isArray) {
|
|
|
1206
1097
|
}
|
|
1207
1098
|
}
|
|
1208
1099
|
|
|
1100
|
+
if (schema.allOf) {
|
|
1101
|
+
const mergedSchema = clone(schema)
|
|
1102
|
+
mergeAllOfSchema(location, schema, mergedSchema)
|
|
1103
|
+
schema = mergedSchema
|
|
1104
|
+
location.schema = mergedSchema
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1209
1107
|
const type = schema.type
|
|
1210
1108
|
const nullable = schema.nullable === true
|
|
1211
1109
|
|
|
1212
|
-
|
|
1110
|
+
let code = ''
|
|
1111
|
+
let funcName
|
|
1213
1112
|
|
|
1214
1113
|
switch (type) {
|
|
1215
1114
|
case 'null':
|
|
1216
|
-
funcName = '$asNull'
|
|
1217
1115
|
code += `
|
|
1218
|
-
json +=
|
|
1116
|
+
json += serializer.asNull()
|
|
1219
1117
|
`
|
|
1220
1118
|
break
|
|
1221
1119
|
case 'string': {
|
|
1222
|
-
funcName =
|
|
1223
|
-
|
|
1224
|
-
code += nullable ? `json += obj${accessor} === null ? null : ${stringSerializer}(obj${accessor})` : `json += ${stringSerializer}(obj${accessor})`
|
|
1120
|
+
funcName = getStringSerializer(schema.format, nullable)
|
|
1121
|
+
code += `json += ${funcName}(${input})`
|
|
1225
1122
|
break
|
|
1226
1123
|
}
|
|
1227
1124
|
case 'integer':
|
|
1228
|
-
funcName = '
|
|
1229
|
-
code +=
|
|
1125
|
+
funcName = nullable ? 'serializer.asIntegerNullable.bind(serializer)' : 'serializer.asInteger.bind(serializer)'
|
|
1126
|
+
code += `json += ${funcName}(${input})`
|
|
1230
1127
|
break
|
|
1231
1128
|
case 'number':
|
|
1232
|
-
funcName = '
|
|
1233
|
-
code +=
|
|
1129
|
+
funcName = nullable ? 'serializer.asNumberNullable.bind(serializer)' : 'serializer.asNumber.bind(serializer)'
|
|
1130
|
+
code += `json += ${funcName}(${input})`
|
|
1234
1131
|
break
|
|
1235
1132
|
case 'boolean':
|
|
1236
|
-
funcName = '
|
|
1237
|
-
code +=
|
|
1133
|
+
funcName = nullable ? 'serializer.asBooleanNullable.bind(serializer)' : 'serializer.asBoolean.bind(serializer)'
|
|
1134
|
+
code += `json += ${funcName}(${input})`
|
|
1238
1135
|
break
|
|
1239
1136
|
case 'object':
|
|
1240
|
-
funcName =
|
|
1241
|
-
laterCode = buildObject(location, laterCode, funcName)
|
|
1242
|
-
code += `
|
|
1243
|
-
json += ${funcName}(obj${accessor})
|
|
1244
|
-
`
|
|
1137
|
+
funcName = generateFuncName()
|
|
1138
|
+
laterCode = buildObject(location, laterCode, funcName, locationPath)
|
|
1139
|
+
code += `json += ${funcName}(${input})`
|
|
1245
1140
|
break
|
|
1246
1141
|
case 'array':
|
|
1247
|
-
funcName =
|
|
1248
|
-
laterCode = buildArray(location, laterCode, funcName,
|
|
1249
|
-
code += `
|
|
1250
|
-
json += ${funcName}(obj${accessor})
|
|
1251
|
-
`
|
|
1142
|
+
funcName = generateFuncName()
|
|
1143
|
+
laterCode = buildArray(location, laterCode, funcName, locationPath)
|
|
1144
|
+
code += `json += ${funcName}(${input})`
|
|
1252
1145
|
break
|
|
1253
1146
|
case undefined:
|
|
1254
|
-
|
|
1255
|
-
if ('anyOf' in schema) {
|
|
1147
|
+
if (schema.anyOf || schema.oneOf) {
|
|
1256
1148
|
// beware: dereferenceOfRefs has side effects and changes schema.anyOf
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
const nestedResult =
|
|
1260
|
-
// We need a test serializer as the String serializer will not work with
|
|
1261
|
-
// date/time ajv validations
|
|
1262
|
-
// see: https://github.com/fastify/fast-json-stringify/issues/325
|
|
1263
|
-
const testSerializer = getTestSerializer(location.schema.format)
|
|
1264
|
-
const testValue = testSerializer !== undefined ? `${testSerializer}(obj${accessor}, true)` : `obj${accessor}`
|
|
1265
|
-
|
|
1149
|
+
const locations = dereferenceOfRefs(location, schema.anyOf ? 'anyOf' : 'oneOf')
|
|
1150
|
+
locations.forEach((location, index) => {
|
|
1151
|
+
const nestedResult = buildValue(laterCode, locationPath + 'i' + index, input, location)
|
|
1266
1152
|
// Since we are only passing the relevant schema to ajv.validate, it needs to be full dereferenced
|
|
1267
1153
|
// otherwise any $ref pointing to an external schema would result in an error.
|
|
1268
1154
|
// Full dereference of the schema happens as side effect of two functions:
|
|
1269
1155
|
// 1. `dereferenceOfRefs` loops through the `schema.anyOf`` array and replaces any top level reference
|
|
1270
1156
|
// with the actual schema
|
|
1271
|
-
// 2. `
|
|
1157
|
+
// 2. `buildValue`, through `buildCode`, replaces any reference in object properties with the actual schema
|
|
1272
1158
|
// (see https://github.com/fastify/fast-json-stringify/blob/6da3b3e8ac24b1ca5578223adedb4083b7adf8db/index.js#L631)
|
|
1273
1159
|
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
${nestedResult.code}
|
|
1280
|
-
`
|
|
1281
|
-
laterCode = nestedResult.laterCode
|
|
1282
|
-
})
|
|
1283
|
-
code += `
|
|
1284
|
-
else json+= null
|
|
1285
|
-
`
|
|
1286
|
-
} else if ('oneOf' in schema) {
|
|
1287
|
-
// beware: dereferenceOfRefs has side effects and changes schema.oneOf
|
|
1288
|
-
const oneOfLocations = dereferenceOfRefs(location, 'oneOf')
|
|
1289
|
-
oneOfLocations.forEach((location, index) => {
|
|
1290
|
-
const nestedResult = nested(laterCode, name, key, location, subKey !== '' ? subKey : 'i' + index, isArray)
|
|
1291
|
-
const testSerializer = getTestSerializer(location.schema.format)
|
|
1292
|
-
const testValue = testSerializer !== undefined ? `${testSerializer}(obj${accessor}, true)` : `obj${accessor}`
|
|
1293
|
-
// see comment on anyOf about dereferencing the schema before calling ajv.validate
|
|
1160
|
+
// Ajv does not support js date format. In order to properly validate objects containing a date,
|
|
1161
|
+
// it needs to replace all occurrences of the string date format with a custom keyword fjs_date_type.
|
|
1162
|
+
// (see https://github.com/fastify/fast-json-stringify/pull/441)
|
|
1163
|
+
const extendedSchema = clone(location.schema)
|
|
1164
|
+
extendDateTimeType(extendedSchema)
|
|
1294
1165
|
|
|
1295
1166
|
const schemaKey = location.schema.$id || randomUUID()
|
|
1296
|
-
ajvInstance.addSchema(
|
|
1167
|
+
ajvInstance.addSchema(extendedSchema, schemaKey)
|
|
1297
1168
|
|
|
1298
1169
|
code += `
|
|
1299
|
-
${index === 0 ? 'if' : 'else if'}(ajv.validate("${schemaKey}", ${
|
|
1170
|
+
${index === 0 ? 'if' : 'else if'}(ajv.validate("${schemaKey}", ${input}))
|
|
1300
1171
|
${nestedResult.code}
|
|
1301
1172
|
`
|
|
1302
1173
|
laterCode = nestedResult.laterCode
|
|
1303
1174
|
})
|
|
1304
1175
|
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
`
|
|
1309
|
-
}
|
|
1176
|
+
code += `
|
|
1177
|
+
else throw new Error(\`The value $\{JSON.stringify(${input})} does not match schema definition.\`)
|
|
1178
|
+
`
|
|
1310
1179
|
} else if (isEmpty(schema)) {
|
|
1311
1180
|
code += `
|
|
1312
|
-
json += JSON.stringify(
|
|
1181
|
+
json += JSON.stringify(${input})
|
|
1313
1182
|
`
|
|
1314
1183
|
} else if ('const' in schema) {
|
|
1315
1184
|
code += `
|
|
1316
|
-
if(ajv.validate(${JSON.stringify(schema)},
|
|
1185
|
+
if(ajv.validate(${JSON.stringify(schema)}, ${input}))
|
|
1317
1186
|
json += '${JSON.stringify(schema.const)}'
|
|
1318
1187
|
else
|
|
1319
|
-
throw new Error(\`Item $\{JSON.stringify(
|
|
1188
|
+
throw new Error(\`Item $\{JSON.stringify(${input})} does not match schema definition.\`)
|
|
1320
1189
|
`
|
|
1321
1190
|
} else if (schema.type === undefined) {
|
|
1322
1191
|
code += `
|
|
1323
|
-
json += JSON.stringify(
|
|
1192
|
+
json += JSON.stringify(${input})
|
|
1324
1193
|
`
|
|
1325
1194
|
} else {
|
|
1326
1195
|
throw new Error(`${schema.type} unsupported`)
|
|
@@ -1328,51 +1197,46 @@ function nested (laterCode, name, key, location, subKey, isArray) {
|
|
|
1328
1197
|
break
|
|
1329
1198
|
default:
|
|
1330
1199
|
if (Array.isArray(type)) {
|
|
1331
|
-
|
|
1332
|
-
const
|
|
1200
|
+
let sortedTypes = type
|
|
1201
|
+
const nullable = schema.nullable === true || type.includes('null')
|
|
1202
|
+
|
|
1203
|
+
if (nullable) {
|
|
1204
|
+
sortedTypes = sortedTypes.filter(type => type !== 'null')
|
|
1205
|
+
code += `
|
|
1206
|
+
if (${input} === null) {
|
|
1207
|
+
json += null
|
|
1208
|
+
} else {`
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1333
1211
|
sortedTypes.forEach((type, index) => {
|
|
1334
1212
|
const statement = index === 0 ? 'if' : 'else if'
|
|
1335
1213
|
const tempSchema = Object.assign({}, schema, { type })
|
|
1336
|
-
const nestedResult =
|
|
1214
|
+
const nestedResult = buildValue(laterCode, locationPath, input, mergeLocation(location, { schema: tempSchema }))
|
|
1337
1215
|
switch (type) {
|
|
1338
1216
|
case 'string': {
|
|
1339
1217
|
code += `
|
|
1340
|
-
${statement}(
|
|
1341
|
-
${nestedResult.code}
|
|
1342
|
-
`
|
|
1343
|
-
break
|
|
1344
|
-
}
|
|
1345
|
-
case 'null': {
|
|
1346
|
-
code += `
|
|
1347
|
-
${statement}(obj${accessor} == null)
|
|
1218
|
+
${statement}(${input} === null || typeof ${input} === "${type}" || ${input} instanceof Date || ${input} instanceof RegExp || (typeof ${input} === "object" && Object.hasOwnProperty.call(${input}, "toString")))
|
|
1348
1219
|
${nestedResult.code}
|
|
1349
1220
|
`
|
|
1350
1221
|
break
|
|
1351
1222
|
}
|
|
1352
1223
|
case 'array': {
|
|
1353
1224
|
code += `
|
|
1354
|
-
${statement}(Array.isArray(
|
|
1225
|
+
${statement}(Array.isArray(${input}))
|
|
1355
1226
|
${nestedResult.code}
|
|
1356
1227
|
`
|
|
1357
1228
|
break
|
|
1358
1229
|
}
|
|
1359
1230
|
case 'integer': {
|
|
1360
1231
|
code += `
|
|
1361
|
-
${statement}(Number.isInteger(
|
|
1362
|
-
${nestedResult.code}
|
|
1363
|
-
`
|
|
1364
|
-
break
|
|
1365
|
-
}
|
|
1366
|
-
case 'number': {
|
|
1367
|
-
code += `
|
|
1368
|
-
${statement}(isNaN(obj${accessor}) === false)
|
|
1232
|
+
${statement}(Number.isInteger(${input}) || ${input} === null)
|
|
1369
1233
|
${nestedResult.code}
|
|
1370
1234
|
`
|
|
1371
1235
|
break
|
|
1372
1236
|
}
|
|
1373
1237
|
default: {
|
|
1374
1238
|
code += `
|
|
1375
|
-
${statement}(typeof
|
|
1239
|
+
${statement}(typeof ${input} === "${type}" || ${input} === null)
|
|
1376
1240
|
${nestedResult.code}
|
|
1377
1241
|
`
|
|
1378
1242
|
break
|
|
@@ -1381,17 +1245,32 @@ function nested (laterCode, name, key, location, subKey, isArray) {
|
|
|
1381
1245
|
laterCode = nestedResult.laterCode
|
|
1382
1246
|
})
|
|
1383
1247
|
code += `
|
|
1384
|
-
else
|
|
1248
|
+
else throw new Error(\`The value $\{JSON.stringify(${input})} does not match schema definition.\`)
|
|
1385
1249
|
`
|
|
1250
|
+
|
|
1251
|
+
if (nullable) {
|
|
1252
|
+
code += `
|
|
1253
|
+
}
|
|
1254
|
+
`
|
|
1255
|
+
}
|
|
1386
1256
|
} else {
|
|
1387
1257
|
throw new Error(`${type} unsupported`)
|
|
1388
1258
|
}
|
|
1389
1259
|
}
|
|
1390
1260
|
|
|
1391
|
-
return {
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1261
|
+
return { code, laterCode }
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
function extendDateTimeType (schema) {
|
|
1265
|
+
if (schema.type === 'string' && ['date-time', 'date', 'time'].includes(schema.format)) {
|
|
1266
|
+
schema.fjs_date_type = schema.format
|
|
1267
|
+
delete schema.type
|
|
1268
|
+
delete schema.format
|
|
1269
|
+
}
|
|
1270
|
+
for (const property in schema) {
|
|
1271
|
+
if (typeof schema[property] === 'object') {
|
|
1272
|
+
extendDateTimeType(schema[property])
|
|
1273
|
+
}
|
|
1395
1274
|
}
|
|
1396
1275
|
}
|
|
1397
1276
|
|
|
@@ -1410,7 +1289,8 @@ module.exports = build
|
|
|
1410
1289
|
module.exports.validLargeArrayMechanisms = validLargeArrayMechanisms
|
|
1411
1290
|
|
|
1412
1291
|
module.exports.restore = function ({ code, ajv }) {
|
|
1292
|
+
const serializer = new Serializer()
|
|
1413
1293
|
// eslint-disable-next-line
|
|
1414
|
-
return (Function.apply(null, ['ajv', code])
|
|
1415
|
-
.apply(null, [ajv]))
|
|
1294
|
+
return (Function.apply(null, ['ajv', 'serializer', code])
|
|
1295
|
+
.apply(null, [ajv, serializer]))
|
|
1416
1296
|
}
|