fast-json-stringify 5.11.0 → 5.11.1
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/index.js +237 -266
- package/lib/location.js +30 -1
- package/package.json +3 -3
- package/test/allof.test.js +17 -134
- package/test/anyof.test.js +0 -121
- package/test/if-then-else.test.js +9 -58
- package/test/required.test.js +3 -4
- package/lib/merge-schemas.js +0 -9
package/index.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
/* eslint no-prototype-builtins: 0 */
|
|
4
4
|
|
|
5
|
+
const merge = require('@fastify/deepmerge')()
|
|
6
|
+
const clone = require('rfdc')({ proto: true })
|
|
5
7
|
const { RefResolver } = require('json-schema-ref-resolver')
|
|
6
8
|
|
|
9
|
+
const validate = require('./lib/schema-validator')
|
|
7
10
|
const Serializer = require('./lib/serializer')
|
|
8
11
|
const Validator = require('./lib/validator')
|
|
9
12
|
const Location = require('./lib/location')
|
|
10
|
-
const validate = require('./lib/schema-validator')
|
|
11
|
-
const mergeSchemas = require('./lib/merge-schemas')
|
|
12
13
|
|
|
13
14
|
const SINGLE_TICK = /'/g
|
|
14
15
|
|
|
@@ -27,9 +28,9 @@ const validLargeArrayMechanisms = [
|
|
|
27
28
|
'json-stringify'
|
|
28
29
|
]
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
const addComma = '!addComma && (addComma = true) || (json += \',\')'
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
let schemaIdCounter = 0
|
|
33
34
|
|
|
34
35
|
function isValidSchema (schema, name) {
|
|
35
36
|
if (!validate(schema)) {
|
|
@@ -45,15 +46,13 @@ function isValidSchema (schema, name) {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
function resolveRef (context, location) {
|
|
49
|
-
const ref = location.schema.$ref
|
|
50
|
-
|
|
49
|
+
function resolveRef (context, location, ref) {
|
|
51
50
|
let hashIndex = ref.indexOf('#')
|
|
52
51
|
if (hashIndex === -1) {
|
|
53
52
|
hashIndex = ref.length
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
const schemaId = ref.slice(0, hashIndex) || location.
|
|
55
|
+
const schemaId = ref.slice(0, hashIndex) || location.getOriginSchemaId()
|
|
57
56
|
const jsonPointer = ref.slice(hashIndex) || '#'
|
|
58
57
|
|
|
59
58
|
const schema = context.refResolver.getSchema(schemaId, jsonPointer)
|
|
@@ -63,17 +62,12 @@ function resolveRef (context, location) {
|
|
|
63
62
|
|
|
64
63
|
const newLocation = new Location(schema, schemaId, jsonPointer)
|
|
65
64
|
if (schema.$ref !== undefined) {
|
|
66
|
-
return resolveRef(context, newLocation)
|
|
65
|
+
return resolveRef(context, newLocation, schema.$ref)
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
return newLocation
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
function getMergedLocation (context, mergedSchemaId) {
|
|
73
|
-
const mergedSchema = context.refResolver.getSchema(mergedSchemaId, '#')
|
|
74
|
-
return new Location(mergedSchema, mergedSchemaId, '#')
|
|
75
|
-
}
|
|
76
|
-
|
|
77
71
|
function getSchemaId (schema, rootSchemaId) {
|
|
78
72
|
if (schema.$id && schema.$id.charAt(0) !== '#') {
|
|
79
73
|
return schema.$id
|
|
@@ -91,6 +85,7 @@ function build (schema, options) {
|
|
|
91
85
|
functionsCounter: 0,
|
|
92
86
|
functionsNamesBySchema: new Map(),
|
|
93
87
|
options,
|
|
88
|
+
wrapObjects: true,
|
|
94
89
|
refResolver: new RefResolver(),
|
|
95
90
|
rootSchemaId: schema.$id || `__fjs_root_${schemaIdCounter++}`,
|
|
96
91
|
validatorSchemasIds: new Set()
|
|
@@ -260,7 +255,7 @@ function inferTypeByKeyword (schema) {
|
|
|
260
255
|
return schema.type
|
|
261
256
|
}
|
|
262
257
|
|
|
263
|
-
function buildExtraObjectPropertiesSerializer (context, location
|
|
258
|
+
function buildExtraObjectPropertiesSerializer (context, location) {
|
|
264
259
|
const schema = location.schema
|
|
265
260
|
const propertiesKeys = Object.keys(schema.properties || {})
|
|
266
261
|
|
|
@@ -319,137 +314,225 @@ function buildExtraObjectPropertiesSerializer (context, location, addComma) {
|
|
|
319
314
|
}
|
|
320
315
|
|
|
321
316
|
function buildInnerObject (context, location) {
|
|
317
|
+
let code = ''
|
|
322
318
|
const schema = location.schema
|
|
319
|
+
const required = schema.required || []
|
|
323
320
|
|
|
324
321
|
const propertiesLocation = location.getPropertyLocation('properties')
|
|
325
|
-
const requiredProperties = schema.required || []
|
|
326
322
|
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
323
|
+
const requiredWithDefault = []
|
|
324
|
+
const requiredWithoutDefault = []
|
|
325
|
+
if (schema.properties) {
|
|
326
|
+
for (const key of Object.keys(schema.properties)) {
|
|
327
|
+
if (required.indexOf(key) === -1) {
|
|
328
|
+
continue
|
|
329
|
+
}
|
|
330
|
+
let propertyLocation = propertiesLocation.getPropertyLocation(key)
|
|
331
|
+
if (propertyLocation.schema.$ref) {
|
|
332
|
+
propertyLocation = resolveRef(context, location, propertyLocation.schema.$ref)
|
|
333
|
+
}
|
|
336
334
|
|
|
337
|
-
|
|
335
|
+
const sanitizedKey = JSON.stringify(key)
|
|
338
336
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
337
|
+
// Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
|
|
338
|
+
// see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
|
|
339
|
+
const defaultValue = propertyLocation.schema.default
|
|
340
|
+
if (defaultValue === undefined) {
|
|
341
|
+
code += `if (obj[${sanitizedKey}] === undefined) throw new Error('${sanitizedKey} is required!')\n`
|
|
342
|
+
requiredWithoutDefault.push(key)
|
|
343
|
+
}
|
|
344
|
+
requiredWithDefault.push(key)
|
|
342
345
|
}
|
|
343
346
|
}
|
|
344
347
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
code += 'let addComma = false\n'
|
|
350
|
-
addComma = '!addComma && (addComma = true) || (json += \',\')'
|
|
348
|
+
// handle extraneous required fields
|
|
349
|
+
for (const requiredProperty of required) {
|
|
350
|
+
if (requiredWithDefault.indexOf(requiredProperty) !== -1) continue
|
|
351
|
+
code += `if (obj['${requiredProperty}'] === undefined) throw new Error('"${requiredProperty}" is required!')\n`
|
|
351
352
|
}
|
|
352
353
|
|
|
353
|
-
|
|
354
|
-
let
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
354
|
+
code += `
|
|
355
|
+
let addComma = false
|
|
356
|
+
let json = '${context.wrapObjects ? '{' : ''}'
|
|
357
|
+
`
|
|
358
|
+
const wrapObjects = context.wrapObjects
|
|
359
|
+
context.wrapObjects = true
|
|
360
|
+
|
|
361
|
+
if (schema.properties) {
|
|
362
|
+
for (const key of Object.keys(schema.properties)) {
|
|
363
|
+
let propertyLocation = propertiesLocation.getPropertyLocation(key)
|
|
364
|
+
if (propertyLocation.schema.$ref) {
|
|
365
|
+
propertyLocation = resolveRef(context, location, propertyLocation.schema.$ref)
|
|
366
|
+
}
|
|
358
367
|
|
|
359
|
-
|
|
360
|
-
const defaultValue = propertyLocation.schema.default
|
|
361
|
-
const isRequired = requiredProperties.includes(key)
|
|
368
|
+
const sanitizedKey = JSON.stringify(key)
|
|
362
369
|
|
|
363
|
-
|
|
364
|
-
|
|
370
|
+
if (requiredWithoutDefault.indexOf(key) !== -1) {
|
|
371
|
+
code += `
|
|
365
372
|
${addComma}
|
|
366
373
|
json += ${JSON.stringify(sanitizedKey + ':')}
|
|
367
374
|
${buildValue(context, propertyLocation, `obj[${sanitizedKey}]`)}
|
|
368
|
-
}`
|
|
369
|
-
|
|
370
|
-
if (defaultValue !== undefined) {
|
|
371
|
-
code += ` else {
|
|
372
|
-
${addComma}
|
|
373
|
-
json += ${JSON.stringify(sanitizedKey + ':' + JSON.stringify(defaultValue))}
|
|
374
|
-
}
|
|
375
375
|
`
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
376
|
+
} else {
|
|
377
|
+
// Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
|
|
378
|
+
// see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
|
|
379
|
+
code += `
|
|
380
|
+
if (obj[${sanitizedKey}] !== undefined) {
|
|
381
|
+
${addComma}
|
|
382
|
+
json += ${JSON.stringify(sanitizedKey + ':')}
|
|
383
|
+
${buildValue(context, propertyLocation, `obj[${sanitizedKey}]`)}
|
|
384
|
+
}
|
|
385
|
+
`
|
|
386
|
+
const defaultValue = propertyLocation.schema.default
|
|
387
|
+
if (defaultValue !== undefined) {
|
|
388
|
+
code += `
|
|
389
|
+
else {
|
|
390
|
+
${addComma}
|
|
391
|
+
json += ${JSON.stringify(sanitizedKey + ':' + JSON.stringify(defaultValue))}
|
|
392
|
+
}
|
|
393
|
+
`
|
|
394
|
+
}
|
|
379
395
|
}
|
|
380
|
-
`
|
|
381
|
-
} else {
|
|
382
|
-
code += '\n'
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (hasRequiredProperties) {
|
|
386
|
-
addComma = 'json += \',\''
|
|
387
396
|
}
|
|
388
397
|
}
|
|
389
398
|
|
|
390
399
|
if (schema.patternProperties || schema.additionalProperties) {
|
|
391
|
-
code += buildExtraObjectPropertiesSerializer(context, location
|
|
400
|
+
code += buildExtraObjectPropertiesSerializer(context, location)
|
|
392
401
|
}
|
|
393
402
|
|
|
403
|
+
context.wrapObjects = wrapObjects
|
|
394
404
|
code += `
|
|
395
|
-
|
|
405
|
+
return json${context.wrapObjects ? ' + \'}\'' : ''}
|
|
396
406
|
`
|
|
397
407
|
return code
|
|
398
408
|
}
|
|
399
409
|
|
|
400
|
-
function
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
410
|
+
function mergeAllOfSchema (context, location, schema, mergedSchema) {
|
|
411
|
+
const allOfLocation = location.getPropertyLocation('allOf')
|
|
412
|
+
|
|
413
|
+
for (let i = 0; i < schema.allOf.length; i++) {
|
|
414
|
+
let allOfSchema = schema.allOf[i]
|
|
415
|
+
|
|
416
|
+
if (allOfSchema.$ref) {
|
|
417
|
+
const allOfSchemaLocation = allOfLocation.getPropertyLocation(i)
|
|
418
|
+
allOfSchema = resolveRef(context, allOfSchemaLocation, allOfSchema.$ref).schema
|
|
406
419
|
}
|
|
407
|
-
}
|
|
408
420
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
421
|
+
let allOfSchemaType = allOfSchema.type
|
|
422
|
+
if (allOfSchemaType === undefined) {
|
|
423
|
+
allOfSchemaType = inferTypeByKeyword(allOfSchema)
|
|
424
|
+
}
|
|
413
425
|
|
|
414
|
-
|
|
415
|
-
|
|
426
|
+
if (allOfSchemaType !== undefined) {
|
|
427
|
+
if (
|
|
428
|
+
mergedSchema.type !== undefined &&
|
|
429
|
+
mergedSchema.type !== allOfSchemaType
|
|
430
|
+
) {
|
|
431
|
+
throw new Error('allOf schemas have different type values')
|
|
432
|
+
}
|
|
433
|
+
mergedSchema.type = allOfSchemaType
|
|
434
|
+
}
|
|
416
435
|
|
|
417
|
-
|
|
418
|
-
|
|
436
|
+
if (allOfSchema.format !== undefined) {
|
|
437
|
+
if (
|
|
438
|
+
mergedSchema.format !== undefined &&
|
|
439
|
+
mergedSchema.format !== allOfSchema.format
|
|
440
|
+
) {
|
|
441
|
+
throw new Error('allOf schemas have different format values')
|
|
442
|
+
}
|
|
443
|
+
mergedSchema.format = allOfSchema.format
|
|
444
|
+
}
|
|
419
445
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
446
|
+
if (allOfSchema.nullable !== undefined) {
|
|
447
|
+
if (
|
|
448
|
+
mergedSchema.nullable !== undefined &&
|
|
449
|
+
mergedSchema.nullable !== allOfSchema.nullable
|
|
450
|
+
) {
|
|
451
|
+
throw new Error('allOf schemas have different nullable values')
|
|
452
|
+
}
|
|
453
|
+
mergedSchema.nullable = allOfSchema.nullable
|
|
454
|
+
}
|
|
423
455
|
|
|
424
|
-
|
|
425
|
-
|
|
456
|
+
if (allOfSchema.properties !== undefined) {
|
|
457
|
+
if (mergedSchema.properties === undefined) {
|
|
458
|
+
mergedSchema.properties = {}
|
|
459
|
+
}
|
|
460
|
+
Object.assign(mergedSchema.properties, allOfSchema.properties)
|
|
461
|
+
}
|
|
426
462
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
463
|
+
if (allOfSchema.additionalProperties !== undefined) {
|
|
464
|
+
if (mergedSchema.additionalProperties === undefined) {
|
|
465
|
+
mergedSchema.additionalProperties = {}
|
|
466
|
+
}
|
|
467
|
+
Object.assign(mergedSchema.additionalProperties, allOfSchema.additionalProperties)
|
|
468
|
+
}
|
|
433
469
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
470
|
+
if (allOfSchema.patternProperties !== undefined) {
|
|
471
|
+
if (mergedSchema.patternProperties === undefined) {
|
|
472
|
+
mergedSchema.patternProperties = {}
|
|
473
|
+
}
|
|
474
|
+
Object.assign(mergedSchema.patternProperties, allOfSchema.patternProperties)
|
|
475
|
+
}
|
|
437
476
|
|
|
438
|
-
|
|
439
|
-
|
|
477
|
+
if (allOfSchema.required !== undefined) {
|
|
478
|
+
if (mergedSchema.required === undefined) {
|
|
479
|
+
mergedSchema.required = []
|
|
480
|
+
}
|
|
481
|
+
mergedSchema.required.push(...allOfSchema.required)
|
|
482
|
+
}
|
|
440
483
|
|
|
441
|
-
if (
|
|
442
|
-
|
|
484
|
+
if (allOfSchema.oneOf !== undefined) {
|
|
485
|
+
if (mergedSchema.oneOf === undefined) {
|
|
486
|
+
mergedSchema.oneOf = []
|
|
487
|
+
}
|
|
488
|
+
mergedSchema.oneOf.push(...allOfSchema.oneOf)
|
|
443
489
|
}
|
|
444
490
|
|
|
445
|
-
if (
|
|
446
|
-
|
|
491
|
+
if (allOfSchema.anyOf !== undefined) {
|
|
492
|
+
if (mergedSchema.anyOf === undefined) {
|
|
493
|
+
mergedSchema.anyOf = []
|
|
494
|
+
}
|
|
495
|
+
mergedSchema.anyOf.push(...allOfSchema.anyOf)
|
|
447
496
|
}
|
|
448
497
|
|
|
449
|
-
|
|
498
|
+
if (allOfSchema.allOf !== undefined) {
|
|
499
|
+
mergeAllOfSchema(context, location, allOfSchema, mergedSchema)
|
|
500
|
+
}
|
|
450
501
|
}
|
|
502
|
+
delete mergedSchema.allOf
|
|
451
503
|
|
|
452
|
-
|
|
504
|
+
mergedSchema.$id = `__fjs_merged_${schemaIdCounter++}`
|
|
505
|
+
context.refResolver.addSchema(mergedSchema)
|
|
506
|
+
location.addMergedSchema(mergedSchema, mergedSchema.$id)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function addIfThenElse (context, location, input) {
|
|
510
|
+
context.validatorSchemasIds.add(location.getSchemaId())
|
|
511
|
+
|
|
512
|
+
const schema = merge({}, location.schema)
|
|
513
|
+
const thenSchema = schema.then
|
|
514
|
+
const elseSchema = schema.else || { additionalProperties: true }
|
|
515
|
+
|
|
516
|
+
delete schema.if
|
|
517
|
+
delete schema.then
|
|
518
|
+
delete schema.else
|
|
519
|
+
|
|
520
|
+
const ifLocation = location.getPropertyLocation('if')
|
|
521
|
+
const ifSchemaRef = ifLocation.getSchemaRef()
|
|
522
|
+
|
|
523
|
+
const thenLocation = location.getPropertyLocation('then')
|
|
524
|
+
thenLocation.schema = merge(schema, thenSchema)
|
|
525
|
+
|
|
526
|
+
const elseLocation = location.getPropertyLocation('else')
|
|
527
|
+
elseLocation.schema = merge(schema, elseSchema)
|
|
528
|
+
|
|
529
|
+
return `
|
|
530
|
+
if (validator.validate("${ifSchemaRef}", ${input})) {
|
|
531
|
+
${buildValue(context, thenLocation, input)}
|
|
532
|
+
} else {
|
|
533
|
+
${buildValue(context, elseLocation, input)}
|
|
534
|
+
}
|
|
535
|
+
`
|
|
453
536
|
}
|
|
454
537
|
|
|
455
538
|
function toJSON (variableName) {
|
|
@@ -499,7 +582,7 @@ function buildArray (context, location) {
|
|
|
499
582
|
itemsLocation.schema = itemsLocation.schema || {}
|
|
500
583
|
|
|
501
584
|
if (itemsLocation.schema.$ref) {
|
|
502
|
-
itemsLocation = resolveRef(context, itemsLocation)
|
|
585
|
+
itemsLocation = resolveRef(context, itemsLocation, itemsLocation.schema.$ref)
|
|
503
586
|
}
|
|
504
587
|
|
|
505
588
|
const itemsSchema = itemsLocation.schema
|
|
@@ -777,193 +860,81 @@ function buildConstSerializer (location, input) {
|
|
|
777
860
|
return code
|
|
778
861
|
}
|
|
779
862
|
|
|
780
|
-
function
|
|
781
|
-
|
|
863
|
+
function buildValue (context, location, input) {
|
|
864
|
+
let schema = location.schema
|
|
782
865
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
const mergedLocation = getMergedLocation(context, mergedSchemaId)
|
|
786
|
-
return buildValue(context, mergedLocation, input)
|
|
866
|
+
if (typeof schema === 'boolean') {
|
|
867
|
+
return `json += JSON.stringify(${input})`
|
|
787
868
|
}
|
|
788
869
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
const { allOf, ...schemaWithoutAllOf } = location.schema
|
|
793
|
-
const locations = [
|
|
794
|
-
new Location(
|
|
795
|
-
schemaWithoutAllOf,
|
|
796
|
-
location.schemaId,
|
|
797
|
-
location.jsonPointer
|
|
798
|
-
)
|
|
799
|
-
]
|
|
800
|
-
|
|
801
|
-
const allOfsLocation = location.getPropertyLocation('allOf')
|
|
802
|
-
for (let i = 0; i < allOf.length; i++) {
|
|
803
|
-
locations.push(allOfsLocation.getPropertyLocation(i))
|
|
870
|
+
if (schema.$ref) {
|
|
871
|
+
location = resolveRef(context, location, schema.$ref)
|
|
872
|
+
schema = location.schema
|
|
804
873
|
}
|
|
805
874
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
function buildOneOf (context, location, input) {
|
|
811
|
-
context.validatorSchemasIds.add(location.schemaId)
|
|
812
|
-
|
|
813
|
-
const schema = location.schema
|
|
814
|
-
|
|
815
|
-
const type = schema.anyOf ? 'anyOf' : 'oneOf'
|
|
816
|
-
const { [type]: oneOfs, ...schemaWithoutAnyOf } = location.schema
|
|
817
|
-
|
|
818
|
-
const locationWithoutOneOf = new Location(
|
|
819
|
-
schemaWithoutAnyOf,
|
|
820
|
-
location.schemaId,
|
|
821
|
-
location.jsonPointer
|
|
822
|
-
)
|
|
823
|
-
const oneOfsLocation = location.getPropertyLocation(type)
|
|
824
|
-
|
|
825
|
-
let code = ''
|
|
826
|
-
|
|
827
|
-
for (let index = 0; index < oneOfs.length; index++) {
|
|
828
|
-
const optionLocation = oneOfsLocation.getPropertyLocation(index)
|
|
829
|
-
const optionSchema = optionLocation.schema
|
|
830
|
-
|
|
831
|
-
let mergedSchemaId = optionSchema[mergedSchemaRef]
|
|
832
|
-
let mergedLocation = null
|
|
833
|
-
if (mergedSchemaId) {
|
|
834
|
-
mergedLocation = getMergedLocation(context, mergedSchemaId)
|
|
835
|
-
} else {
|
|
836
|
-
mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
|
|
837
|
-
optionSchema[mergedSchemaRef] = mergedSchemaId
|
|
838
|
-
|
|
839
|
-
mergedLocation = mergeLocations(context, mergedSchemaId, [
|
|
840
|
-
locationWithoutOneOf,
|
|
841
|
-
optionLocation
|
|
842
|
-
])
|
|
875
|
+
if (schema.type === undefined) {
|
|
876
|
+
const inferredType = inferTypeByKeyword(schema)
|
|
877
|
+
if (inferredType) {
|
|
878
|
+
schema.type = inferredType
|
|
843
879
|
}
|
|
844
|
-
|
|
845
|
-
const nestedResult = buildValue(context, mergedLocation, input)
|
|
846
|
-
const schemaRef = optionLocation.getSchemaRef()
|
|
847
|
-
code += `
|
|
848
|
-
${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input}))
|
|
849
|
-
${nestedResult}
|
|
850
|
-
`
|
|
851
880
|
}
|
|
852
881
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
schemaRef = schemaRef.replace(context.rootSchemaId, '')
|
|
882
|
+
if (schema.if && schema.then) {
|
|
883
|
+
return addIfThenElse(context, location, input)
|
|
856
884
|
}
|
|
857
885
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
return code
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
function buildIfThenElse (context, location, input) {
|
|
866
|
-
context.validatorSchemasIds.add(location.schemaId)
|
|
867
|
-
|
|
868
|
-
const {
|
|
869
|
-
if: ifSchema,
|
|
870
|
-
then: thenSchema,
|
|
871
|
-
else: elseSchema,
|
|
872
|
-
...schemaWithoutIfThenElse
|
|
873
|
-
} = location.schema
|
|
874
|
-
|
|
875
|
-
const rootLocation = new Location(
|
|
876
|
-
schemaWithoutIfThenElse,
|
|
877
|
-
location.schemaId,
|
|
878
|
-
location.jsonPointer
|
|
879
|
-
)
|
|
880
|
-
|
|
881
|
-
const ifLocation = location.getPropertyLocation('if')
|
|
882
|
-
const ifSchemaRef = ifLocation.getSchemaRef()
|
|
883
|
-
|
|
884
|
-
const thenLocation = location.getPropertyLocation('then')
|
|
885
|
-
let thenMergedSchemaId = thenSchema[mergedSchemaRef]
|
|
886
|
-
let thenMergedLocation = null
|
|
887
|
-
if (thenMergedSchemaId) {
|
|
888
|
-
thenMergedLocation = getMergedLocation(context, thenMergedSchemaId)
|
|
889
|
-
} else {
|
|
890
|
-
thenMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
|
|
891
|
-
thenSchema[mergedSchemaRef] = thenMergedSchemaId
|
|
892
|
-
|
|
893
|
-
thenMergedLocation = mergeLocations(context, thenMergedSchemaId, [
|
|
894
|
-
rootLocation,
|
|
895
|
-
thenLocation
|
|
896
|
-
])
|
|
886
|
+
if (schema.allOf) {
|
|
887
|
+
mergeAllOfSchema(context, location, schema, clone(schema))
|
|
888
|
+
schema = location.schema
|
|
897
889
|
}
|
|
898
890
|
|
|
899
|
-
|
|
900
|
-
return `
|
|
901
|
-
if (validator.validate("${ifSchemaRef}", ${input})) {
|
|
902
|
-
${buildValue(context, thenMergedLocation, input)}
|
|
903
|
-
} else {
|
|
904
|
-
${buildValue(context, rootLocation, input)}
|
|
905
|
-
}
|
|
906
|
-
`
|
|
907
|
-
}
|
|
891
|
+
const type = schema.type
|
|
908
892
|
|
|
909
|
-
|
|
910
|
-
let elseMergedSchemaId = elseSchema[mergedSchemaRef]
|
|
911
|
-
let elseMergedLocation = null
|
|
912
|
-
if (elseMergedSchemaId) {
|
|
913
|
-
elseMergedLocation = getMergedLocation(context, elseMergedSchemaId)
|
|
914
|
-
} else {
|
|
915
|
-
elseMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
|
|
916
|
-
elseSchema[mergedSchemaRef] = elseMergedSchemaId
|
|
893
|
+
let code = ''
|
|
917
894
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
elseLocation
|
|
921
|
-
])
|
|
922
|
-
}
|
|
895
|
+
if ((type === undefined || type === 'object') && (schema.anyOf || schema.oneOf)) {
|
|
896
|
+
context.validatorSchemasIds.add(location.getSchemaId())
|
|
923
897
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
898
|
+
if (schema.type === 'object') {
|
|
899
|
+
context.wrapObjects = false
|
|
900
|
+
const funcName = buildObject(context, location)
|
|
901
|
+
code += `
|
|
902
|
+
json += '{'
|
|
903
|
+
json += ${funcName}(${input})
|
|
904
|
+
json += ','
|
|
905
|
+
`
|
|
929
906
|
}
|
|
930
|
-
`
|
|
931
|
-
}
|
|
932
907
|
|
|
933
|
-
|
|
934
|
-
|
|
908
|
+
const type = schema.anyOf ? 'anyOf' : 'oneOf'
|
|
909
|
+
const anyOfLocation = location.getPropertyLocation(type)
|
|
935
910
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
if (schema.allOf) {
|
|
946
|
-
return buildAllOf(context, location, input)
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
if (schema.anyOf || schema.oneOf) {
|
|
950
|
-
return buildOneOf(context, location, input)
|
|
951
|
-
}
|
|
911
|
+
for (let index = 0; index < location.schema[type].length; index++) {
|
|
912
|
+
const optionLocation = anyOfLocation.getPropertyLocation(index)
|
|
913
|
+
const schemaRef = optionLocation.getSchemaRef()
|
|
914
|
+
const nestedResult = buildValue(context, optionLocation, input)
|
|
915
|
+
code += `
|
|
916
|
+
${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input}))
|
|
917
|
+
${nestedResult}
|
|
918
|
+
`
|
|
919
|
+
}
|
|
952
920
|
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
921
|
+
let schemaRef = location.getSchemaRef()
|
|
922
|
+
if (schemaRef.startsWith(context.rootSchemaId)) {
|
|
923
|
+
schemaRef = schemaRef.replace(context.rootSchemaId, '')
|
|
924
|
+
}
|
|
956
925
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
926
|
+
code += `
|
|
927
|
+
else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
|
|
928
|
+
`
|
|
929
|
+
if (schema.type === 'object') {
|
|
930
|
+
code += `
|
|
931
|
+
json += '}'
|
|
932
|
+
`
|
|
933
|
+
context.wrapObjects = true
|
|
961
934
|
}
|
|
935
|
+
return code
|
|
962
936
|
}
|
|
963
937
|
|
|
964
|
-
let code = ''
|
|
965
|
-
|
|
966
|
-
const type = schema.type
|
|
967
938
|
const nullable = schema.nullable === true
|
|
968
939
|
if (nullable) {
|
|
969
940
|
code += `
|
package/lib/location.js
CHANGED
|
@@ -5,6 +5,7 @@ class Location {
|
|
|
5
5
|
this.schema = schema
|
|
6
6
|
this.schemaId = schemaId
|
|
7
7
|
this.jsonPointer = jsonPointer
|
|
8
|
+
this.mergedSchemaId = null
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
getPropertyLocation (propertyName) {
|
|
@@ -13,11 +14,39 @@ class Location {
|
|
|
13
14
|
this.schemaId,
|
|
14
15
|
this.jsonPointer + '/' + propertyName
|
|
15
16
|
)
|
|
17
|
+
|
|
18
|
+
if (this.mergedSchemaId !== null) {
|
|
19
|
+
propertyLocation.addMergedSchema(
|
|
20
|
+
this.schema[propertyName],
|
|
21
|
+
this.mergedSchemaId,
|
|
22
|
+
this.jsonPointer + '/' + propertyName
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
16
26
|
return propertyLocation
|
|
17
27
|
}
|
|
18
28
|
|
|
29
|
+
// Use this method to get current schema location.
|
|
30
|
+
// Use it when you need to create reference to the current location.
|
|
31
|
+
getSchemaId () {
|
|
32
|
+
return this.mergedSchemaId || this.schemaId
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Use this method to get original schema id for resolving user schema $refs
|
|
36
|
+
// Don't join it with a JSON pointer to get the current location.
|
|
37
|
+
getOriginSchemaId () {
|
|
38
|
+
return this.schemaId
|
|
39
|
+
}
|
|
40
|
+
|
|
19
41
|
getSchemaRef () {
|
|
20
|
-
|
|
42
|
+
const schemaId = this.getSchemaId()
|
|
43
|
+
return schemaId + this.jsonPointer
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
addMergedSchema (mergedSchema, schemaId, jsonPointer = '#') {
|
|
47
|
+
this.schema = mergedSchema
|
|
48
|
+
this.mergedSchemaId = schemaId
|
|
49
|
+
this.jsonPointer = jsonPointer
|
|
21
50
|
}
|
|
22
51
|
}
|
|
23
52
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-json-stringify",
|
|
3
|
-
"version": "5.11.
|
|
3
|
+
"version": "5.11.1",
|
|
4
4
|
"description": "Stringify your JSON at max speed",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
"fast-json-stringify": "."
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
+
"@fastify/deepmerge": "^1.0.0",
|
|
54
55
|
"ajv": "^8.10.0",
|
|
55
56
|
"ajv-formats": "^2.1.1",
|
|
56
57
|
"fast-deep-equal": "^3.1.3",
|
|
57
58
|
"fast-uri": "^2.1.0",
|
|
58
59
|
"rfdc": "^1.2.0",
|
|
59
|
-
"json-schema-ref-resolver": "^1.0.1"
|
|
60
|
-
"@fastify/merge-json-schemas": "^0.1.0"
|
|
60
|
+
"json-schema-ref-resolver": "^1.0.1"
|
|
61
61
|
},
|
|
62
62
|
"standard": {
|
|
63
63
|
"ignore": [
|
package/test/allof.test.js
CHANGED
|
@@ -121,7 +121,7 @@ test('object with allOf and multiple schema on the allOf', (t) => {
|
|
|
121
121
|
id: 1,
|
|
122
122
|
name: 'string',
|
|
123
123
|
tag: 'otherString'
|
|
124
|
-
}), '{"name":"string","
|
|
124
|
+
}), '{"name":"string","tag":"otherString","id":1}')
|
|
125
125
|
})
|
|
126
126
|
|
|
127
127
|
test('object with allOf and one schema on the allOf', (t) => {
|
|
@@ -553,60 +553,8 @@ test('allof with local anchor reference', (t) => {
|
|
|
553
553
|
t.equal(stringify(data), JSON.stringify(data))
|
|
554
554
|
})
|
|
555
555
|
|
|
556
|
-
test('allOf: multiple nested $ref properties', (t) => {
|
|
557
|
-
t.plan(2)
|
|
558
|
-
|
|
559
|
-
const externalSchema1 = {
|
|
560
|
-
$id: 'externalSchema1',
|
|
561
|
-
oneOf: [
|
|
562
|
-
{ $ref: '#/definitions/id1' }
|
|
563
|
-
],
|
|
564
|
-
definitions: {
|
|
565
|
-
id1: {
|
|
566
|
-
type: 'object',
|
|
567
|
-
properties: {
|
|
568
|
-
id1: {
|
|
569
|
-
type: 'integer'
|
|
570
|
-
}
|
|
571
|
-
},
|
|
572
|
-
additionalProperties: false
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
const externalSchema2 = {
|
|
578
|
-
$id: 'externalSchema2',
|
|
579
|
-
oneOf: [
|
|
580
|
-
{ $ref: '#/definitions/id2' }
|
|
581
|
-
],
|
|
582
|
-
definitions: {
|
|
583
|
-
id2: {
|
|
584
|
-
type: 'object',
|
|
585
|
-
properties: {
|
|
586
|
-
id2: {
|
|
587
|
-
type: 'integer'
|
|
588
|
-
}
|
|
589
|
-
},
|
|
590
|
-
additionalProperties: false
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
const schema = {
|
|
596
|
-
anyOf: [
|
|
597
|
-
{ $ref: 'externalSchema1' },
|
|
598
|
-
{ $ref: 'externalSchema2' }
|
|
599
|
-
]
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
const stringify = build(schema, { schema: [externalSchema1, externalSchema2] })
|
|
603
|
-
|
|
604
|
-
t.equal(stringify({ id1: 1 }), JSON.stringify({ id1: 1 }))
|
|
605
|
-
t.equal(stringify({ id2: 2 }), JSON.stringify({ id2: 2 }))
|
|
606
|
-
})
|
|
607
|
-
|
|
608
556
|
test('allOf: throw Error if types mismatch ', (t) => {
|
|
609
|
-
t.plan(
|
|
557
|
+
t.plan(1)
|
|
610
558
|
|
|
611
559
|
const schema = {
|
|
612
560
|
allOf: [
|
|
@@ -614,18 +562,11 @@ test('allOf: throw Error if types mismatch ', (t) => {
|
|
|
614
562
|
{ type: 'number' }
|
|
615
563
|
]
|
|
616
564
|
}
|
|
617
|
-
|
|
618
|
-
build(schema)
|
|
619
|
-
t.fail('should throw the MergeError')
|
|
620
|
-
} catch (error) {
|
|
621
|
-
t.ok(error instanceof Error)
|
|
622
|
-
t.equal(error.message, 'Failed to merge "type" keyword schemas.')
|
|
623
|
-
t.same(error.schemas, [['string'], ['number']])
|
|
624
|
-
}
|
|
565
|
+
t.throws(() => build(schema), new Error('allOf schemas have different type values'))
|
|
625
566
|
})
|
|
626
567
|
|
|
627
568
|
test('allOf: throw Error if format mismatch ', (t) => {
|
|
628
|
-
t.plan(
|
|
569
|
+
t.plan(1)
|
|
629
570
|
|
|
630
571
|
const schema = {
|
|
631
572
|
allOf: [
|
|
@@ -633,87 +574,29 @@ test('allOf: throw Error if format mismatch ', (t) => {
|
|
|
633
574
|
{ format: 'time' }
|
|
634
575
|
]
|
|
635
576
|
}
|
|
636
|
-
|
|
637
|
-
build(schema)
|
|
638
|
-
t.fail('should throw the MergeError')
|
|
639
|
-
} catch (error) {
|
|
640
|
-
t.ok(error instanceof Error)
|
|
641
|
-
t.equal(error.message, 'Failed to merge "format" keyword schemas.')
|
|
642
|
-
t.same(error.schemas, ['date', 'time'])
|
|
643
|
-
}
|
|
577
|
+
t.throws(() => build(schema), new Error('allOf schemas have different format values'))
|
|
644
578
|
})
|
|
645
579
|
|
|
646
|
-
test('
|
|
580
|
+
test('allOf: throw Error if nullable mismatch /1', (t) => {
|
|
647
581
|
t.plan(1)
|
|
648
582
|
|
|
649
583
|
const schema = {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
allOf: [{ $ref: '#' }]
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
const data = { foo: {} }
|
|
660
|
-
const stringify = build(schema)
|
|
661
|
-
t.equal(stringify(data), JSON.stringify(data))
|
|
662
|
-
})
|
|
663
|
-
|
|
664
|
-
test('recursive nested allOfs', (t) => {
|
|
665
|
-
t.plan(1)
|
|
666
|
-
|
|
667
|
-
const schema = {
|
|
668
|
-
type: 'object',
|
|
669
|
-
properties: {
|
|
670
|
-
foo: {
|
|
671
|
-
additionalProperties: false,
|
|
672
|
-
allOf: [{ allOf: [{ $ref: '#' }] }]
|
|
673
|
-
}
|
|
674
|
-
}
|
|
584
|
+
allOf: [
|
|
585
|
+
{ nullable: true },
|
|
586
|
+
{ nullable: false }
|
|
587
|
+
]
|
|
675
588
|
}
|
|
676
|
-
|
|
677
|
-
const data = { foo: {} }
|
|
678
|
-
const stringify = build(schema)
|
|
679
|
-
t.equal(stringify(data), JSON.stringify(data))
|
|
589
|
+
t.throws(() => build(schema), new Error('allOf schemas have different nullable values'))
|
|
680
590
|
})
|
|
681
591
|
|
|
682
|
-
test('
|
|
592
|
+
test('allOf: throw Error if nullable mismatch /2', (t) => {
|
|
683
593
|
t.plan(1)
|
|
684
594
|
|
|
685
|
-
const externalSchema = {
|
|
686
|
-
type: 'object',
|
|
687
|
-
properties: {
|
|
688
|
-
foo: {
|
|
689
|
-
properties: {
|
|
690
|
-
bar: { type: 'string' }
|
|
691
|
-
},
|
|
692
|
-
allOf: [{ $ref: '#' }]
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
|
|
697
595
|
const schema = {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
const data = {
|
|
706
|
-
a: {
|
|
707
|
-
foo: {},
|
|
708
|
-
bar: '42',
|
|
709
|
-
baz: 42
|
|
710
|
-
},
|
|
711
|
-
b: {
|
|
712
|
-
foo: {},
|
|
713
|
-
bar: '42',
|
|
714
|
-
baz: 42
|
|
715
|
-
}
|
|
596
|
+
allOf: [
|
|
597
|
+
{ nullable: false },
|
|
598
|
+
{ nullable: true }
|
|
599
|
+
]
|
|
716
600
|
}
|
|
717
|
-
|
|
718
|
-
t.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
|
|
601
|
+
t.throws(() => build(schema), new Error('allOf schemas have different nullable values'))
|
|
719
602
|
})
|
package/test/anyof.test.js
CHANGED
|
@@ -644,124 +644,3 @@ test('object with ref and validated properties', (t) => {
|
|
|
644
644
|
const stringify = build(schema, { schema: externalSchemas })
|
|
645
645
|
t.equal(stringify({ id: 1, reference: 'hi' }), '{"id":1,"reference":"hi"}')
|
|
646
646
|
})
|
|
647
|
-
|
|
648
|
-
test('anyOf required props', (t) => {
|
|
649
|
-
t.plan(3)
|
|
650
|
-
|
|
651
|
-
const schema = {
|
|
652
|
-
type: 'object',
|
|
653
|
-
properties: {
|
|
654
|
-
prop1: { type: 'string' },
|
|
655
|
-
prop2: { type: 'string' },
|
|
656
|
-
prop3: { type: 'string' }
|
|
657
|
-
},
|
|
658
|
-
required: ['prop1'],
|
|
659
|
-
anyOf: [{ required: ['prop2'] }, { required: ['prop3'] }]
|
|
660
|
-
}
|
|
661
|
-
const stringify = build(schema)
|
|
662
|
-
t.equal(stringify({ prop1: 'test', prop2: 'test2' }), '{"prop1":"test","prop2":"test2"}')
|
|
663
|
-
t.equal(stringify({ prop1: 'test', prop3: 'test3' }), '{"prop1":"test","prop3":"test3"}')
|
|
664
|
-
t.equal(stringify({ prop1: 'test', prop2: 'test2', prop3: 'test3' }), '{"prop1":"test","prop2":"test2","prop3":"test3"}')
|
|
665
|
-
})
|
|
666
|
-
|
|
667
|
-
test('anyOf required props', (t) => {
|
|
668
|
-
t.plan(3)
|
|
669
|
-
|
|
670
|
-
const schema = {
|
|
671
|
-
type: 'object',
|
|
672
|
-
properties: {
|
|
673
|
-
prop1: { type: 'string' }
|
|
674
|
-
},
|
|
675
|
-
anyOf: [
|
|
676
|
-
{
|
|
677
|
-
properties: {
|
|
678
|
-
prop2: { type: 'string' }
|
|
679
|
-
}
|
|
680
|
-
},
|
|
681
|
-
{
|
|
682
|
-
properties: {
|
|
683
|
-
prop3: { type: 'string' }
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
]
|
|
687
|
-
}
|
|
688
|
-
const stringify = build(schema)
|
|
689
|
-
t.equal(stringify({ prop1: 'test1' }), '{"prop1":"test1"}')
|
|
690
|
-
t.equal(stringify({ prop2: 'test2' }), '{"prop2":"test2"}')
|
|
691
|
-
t.equal(stringify({ prop1: 'test1', prop2: 'test2' }), '{"prop1":"test1","prop2":"test2"}')
|
|
692
|
-
})
|
|
693
|
-
|
|
694
|
-
test('recursive nested anyOfs', (t) => {
|
|
695
|
-
t.plan(1)
|
|
696
|
-
|
|
697
|
-
const schema = {
|
|
698
|
-
type: 'object',
|
|
699
|
-
properties: {
|
|
700
|
-
foo: {
|
|
701
|
-
additionalProperties: false,
|
|
702
|
-
anyOf: [{ $ref: '#' }]
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
const data = { foo: {} }
|
|
708
|
-
const stringify = build(schema)
|
|
709
|
-
t.equal(stringify(data), JSON.stringify(data))
|
|
710
|
-
})
|
|
711
|
-
|
|
712
|
-
test('recursive nested anyOfs', (t) => {
|
|
713
|
-
t.plan(1)
|
|
714
|
-
|
|
715
|
-
const schema = {
|
|
716
|
-
type: 'object',
|
|
717
|
-
properties: {
|
|
718
|
-
foo: {
|
|
719
|
-
additionalProperties: false,
|
|
720
|
-
anyOf: [{ anyOf: [{ $ref: '#' }] }]
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
const data = { foo: {} }
|
|
726
|
-
const stringify = build(schema)
|
|
727
|
-
t.equal(stringify(data), JSON.stringify(data))
|
|
728
|
-
})
|
|
729
|
-
|
|
730
|
-
test('external recursive anyOfs', (t) => {
|
|
731
|
-
t.plan(1)
|
|
732
|
-
|
|
733
|
-
const externalSchema = {
|
|
734
|
-
type: 'object',
|
|
735
|
-
properties: {
|
|
736
|
-
foo: {
|
|
737
|
-
properties: {
|
|
738
|
-
bar: { type: 'string' }
|
|
739
|
-
},
|
|
740
|
-
anyOf: [{ $ref: '#' }]
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
const schema = {
|
|
746
|
-
type: 'object',
|
|
747
|
-
properties: {
|
|
748
|
-
a: { $ref: 'externalSchema#/properties/foo' },
|
|
749
|
-
b: { $ref: 'externalSchema#/properties/foo' }
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
const data = {
|
|
754
|
-
a: {
|
|
755
|
-
foo: {},
|
|
756
|
-
bar: '42',
|
|
757
|
-
baz: 42
|
|
758
|
-
},
|
|
759
|
-
b: {
|
|
760
|
-
foo: {},
|
|
761
|
-
bar: '42',
|
|
762
|
-
baz: 42
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
const stringify = build(schema, { schema: { externalSchema } })
|
|
766
|
-
t.equal(stringify(data), '{"a":{"bar":"42","foo":{}},"b":{"bar":"42","foo":{}}}')
|
|
767
|
-
})
|
|
@@ -249,7 +249,15 @@ const alphabetOutput = JSON.stringify({
|
|
|
249
249
|
const deepFoobarOutput = JSON.stringify({
|
|
250
250
|
foobar: JSON.parse(foobarOutput)
|
|
251
251
|
})
|
|
252
|
-
const noElseGreetingOutput = JSON.stringify({
|
|
252
|
+
const noElseGreetingOutput = JSON.stringify({
|
|
253
|
+
kind: 'greeting',
|
|
254
|
+
foo: 'FOO',
|
|
255
|
+
bar: 42,
|
|
256
|
+
hi: 'HI',
|
|
257
|
+
hello: 45,
|
|
258
|
+
a: 'A',
|
|
259
|
+
b: 35
|
|
260
|
+
})
|
|
253
261
|
|
|
254
262
|
t.test('if-then-else', t => {
|
|
255
263
|
const tests = [
|
|
@@ -411,60 +419,3 @@ t.test('if/else with array', (t) => {
|
|
|
411
419
|
t.equal(stringify(['1']), JSON.stringify(['1']))
|
|
412
420
|
t.equal(stringify(['1', '2']), JSON.stringify([1, 2]))
|
|
413
421
|
})
|
|
414
|
-
|
|
415
|
-
t.test('external recursive if/then/else', (t) => {
|
|
416
|
-
t.plan(1)
|
|
417
|
-
|
|
418
|
-
const externalSchema = {
|
|
419
|
-
type: 'object',
|
|
420
|
-
properties: {
|
|
421
|
-
base: { type: 'string' },
|
|
422
|
-
self: { $ref: 'externalSchema#' }
|
|
423
|
-
},
|
|
424
|
-
if: {
|
|
425
|
-
type: 'object',
|
|
426
|
-
properties: {
|
|
427
|
-
foo: { type: 'string', const: '41' }
|
|
428
|
-
}
|
|
429
|
-
},
|
|
430
|
-
then: {
|
|
431
|
-
type: 'object',
|
|
432
|
-
properties: {
|
|
433
|
-
bar: { type: 'string', const: '42' }
|
|
434
|
-
}
|
|
435
|
-
},
|
|
436
|
-
else: {
|
|
437
|
-
type: 'object',
|
|
438
|
-
properties: {
|
|
439
|
-
baz: { type: 'string', const: '43' }
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
const schema = {
|
|
445
|
-
type: 'object',
|
|
446
|
-
properties: {
|
|
447
|
-
a: { $ref: 'externalSchema#/properties/self' },
|
|
448
|
-
b: { $ref: 'externalSchema#/properties/self' }
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const data = {
|
|
453
|
-
a: {
|
|
454
|
-
base: 'a',
|
|
455
|
-
foo: '41',
|
|
456
|
-
bar: '42',
|
|
457
|
-
baz: '43',
|
|
458
|
-
ignore: 'ignored'
|
|
459
|
-
},
|
|
460
|
-
b: {
|
|
461
|
-
base: 'b',
|
|
462
|
-
foo: 'not-41',
|
|
463
|
-
bar: '42',
|
|
464
|
-
baz: '43',
|
|
465
|
-
ignore: 'ignored'
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
const stringify = build(schema, { schema: { externalSchema } })
|
|
469
|
-
t.equal(stringify(data), '{"a":{"base":"a","bar":"42"},"b":{"base":"b","baz":"43"}}')
|
|
470
|
-
})
|
package/test/required.test.js
CHANGED
|
@@ -126,18 +126,17 @@ test('object with multiple required field not in properties schema', (t) => {
|
|
|
126
126
|
stringify({})
|
|
127
127
|
t.fail()
|
|
128
128
|
} catch (e) {
|
|
129
|
-
t.equal(e.message, '"
|
|
129
|
+
t.equal(e.message, '"num" is required!')
|
|
130
130
|
t.pass()
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
try {
|
|
134
134
|
stringify({
|
|
135
|
-
|
|
136
|
-
key2: 42
|
|
135
|
+
num: 42
|
|
137
136
|
})
|
|
138
137
|
t.fail()
|
|
139
138
|
} catch (e) {
|
|
140
|
-
t.equal(e.message, '"
|
|
139
|
+
t.equal(e.message, '"key1" is required!')
|
|
141
140
|
t.pass()
|
|
142
141
|
}
|
|
143
142
|
|
package/lib/merge-schemas.js
DELETED