fast-json-stringify 5.11.1 → 5.13.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/index.js CHANGED
@@ -2,14 +2,13 @@
2
2
 
3
3
  /* eslint no-prototype-builtins: 0 */
4
4
 
5
- const merge = require('@fastify/deepmerge')()
6
- const clone = require('rfdc')({ proto: true })
7
5
  const { RefResolver } = require('json-schema-ref-resolver')
8
6
 
9
- const validate = require('./lib/schema-validator')
10
7
  const Serializer = require('./lib/serializer')
11
8
  const Validator = require('./lib/validator')
12
9
  const Location = require('./lib/location')
10
+ const validate = require('./lib/schema-validator')
11
+ const mergeSchemas = require('./lib/merge-schemas')
13
12
 
14
13
  const SINGLE_TICK = /'/g
15
14
 
@@ -28,8 +27,6 @@ const validLargeArrayMechanisms = [
28
27
  'json-stringify'
29
28
  ]
30
29
 
31
- const addComma = '!addComma && (addComma = true) || (json += \',\')'
32
-
33
30
  let schemaIdCounter = 0
34
31
 
35
32
  function isValidSchema (schema, name) {
@@ -46,13 +43,15 @@ function isValidSchema (schema, name) {
46
43
  }
47
44
  }
48
45
 
49
- function resolveRef (context, location, ref) {
46
+ function resolveRef (context, location) {
47
+ const ref = location.schema.$ref
48
+
50
49
  let hashIndex = ref.indexOf('#')
51
50
  if (hashIndex === -1) {
52
51
  hashIndex = ref.length
53
52
  }
54
53
 
55
- const schemaId = ref.slice(0, hashIndex) || location.getOriginSchemaId()
54
+ const schemaId = ref.slice(0, hashIndex) || location.schemaId
56
55
  const jsonPointer = ref.slice(hashIndex) || '#'
57
56
 
58
57
  const schema = context.refResolver.getSchema(schemaId, jsonPointer)
@@ -62,12 +61,17 @@ function resolveRef (context, location, ref) {
62
61
 
63
62
  const newLocation = new Location(schema, schemaId, jsonPointer)
64
63
  if (schema.$ref !== undefined) {
65
- return resolveRef(context, newLocation, schema.$ref)
64
+ return resolveRef(context, newLocation)
66
65
  }
67
66
 
68
67
  return newLocation
69
68
  }
70
69
 
70
+ function getMergedLocation (context, mergedSchemaId) {
71
+ const mergedSchema = context.refResolver.getSchema(mergedSchemaId, '#')
72
+ return new Location(mergedSchema, mergedSchemaId, '#')
73
+ }
74
+
71
75
  function getSchemaId (schema, rootSchemaId) {
72
76
  if (schema.$id && schema.$id.charAt(0) !== '#') {
73
77
  return schema.$id
@@ -85,10 +89,10 @@ function build (schema, options) {
85
89
  functionsCounter: 0,
86
90
  functionsNamesBySchema: new Map(),
87
91
  options,
88
- wrapObjects: true,
89
92
  refResolver: new RefResolver(),
90
93
  rootSchemaId: schema.$id || `__fjs_root_${schemaIdCounter++}`,
91
- validatorSchemasIds: new Set()
94
+ validatorSchemasIds: new Set(),
95
+ mergedSchemasIds: new Map()
92
96
  }
93
97
 
94
98
  const schemaId = getSchemaId(schema, context.rootSchemaId)
@@ -255,7 +259,7 @@ function inferTypeByKeyword (schema) {
255
259
  return schema.type
256
260
  }
257
261
 
258
- function buildExtraObjectPropertiesSerializer (context, location) {
262
+ function buildExtraObjectPropertiesSerializer (context, location, addComma) {
259
263
  const schema = location.schema
260
264
  const propertiesKeys = Object.keys(schema.properties || {})
261
265
 
@@ -314,225 +318,138 @@ function buildExtraObjectPropertiesSerializer (context, location) {
314
318
  }
315
319
 
316
320
  function buildInnerObject (context, location) {
317
- let code = ''
318
321
  const schema = location.schema
319
- const required = schema.required || []
320
322
 
321
323
  const propertiesLocation = location.getPropertyLocation('properties')
324
+ const requiredProperties = schema.required || []
322
325
 
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
- }
326
+ // Should serialize required properties first
327
+ const propertiesKeys = Object.keys(schema.properties || {}).sort(
328
+ (key1, key2) => {
329
+ const required1 = requiredProperties.includes(key1)
330
+ const required2 = requiredProperties.includes(key2)
331
+ return required1 === required2 ? 0 : required1 ? -1 : 1
332
+ }
333
+ )
334
+ const hasRequiredProperties = requiredProperties.includes(propertiesKeys[0])
334
335
 
335
- const sanitizedKey = JSON.stringify(key)
336
+ let code = ''
336
337
 
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)
338
+ for (const key of requiredProperties) {
339
+ if (!propertiesKeys.includes(key)) {
340
+ code += `if (obj['${key}'] === undefined) throw new Error('"${key}" is required!')\n`
345
341
  }
346
342
  }
347
343
 
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`
344
+ code += 'let json = \'{\'\n'
345
+
346
+ let addComma = ''
347
+ if (!hasRequiredProperties) {
348
+ code += 'let addComma = false\n'
349
+ addComma = '!addComma && (addComma = true) || (json += \',\')'
352
350
  }
353
351
 
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
- }
352
+ for (const key of propertiesKeys) {
353
+ let propertyLocation = propertiesLocation.getPropertyLocation(key)
354
+ if (propertyLocation.schema.$ref) {
355
+ propertyLocation = resolveRef(context, propertyLocation)
356
+ }
367
357
 
368
- const sanitizedKey = JSON.stringify(key)
358
+ const sanitizedKey = JSON.stringify(key)
359
+ const defaultValue = propertyLocation.schema.default
360
+ const isRequired = requiredProperties.includes(key)
369
361
 
370
- if (requiredWithoutDefault.indexOf(key) !== -1) {
371
- code += `
362
+ code += `
363
+ if (obj[${sanitizedKey}] !== undefined) {
372
364
  ${addComma}
373
365
  json += ${JSON.stringify(sanitizedKey + ':')}
374
366
  ${buildValue(context, propertyLocation, `obj[${sanitizedKey}]`)}
367
+ }`
368
+
369
+ if (defaultValue !== undefined) {
370
+ code += ` else {
371
+ ${addComma}
372
+ json += ${JSON.stringify(sanitizedKey + ':' + JSON.stringify(defaultValue))}
373
+ }
375
374
  `
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
- }
375
+ } else if (isRequired) {
376
+ code += ` else {
377
+ throw new Error('${sanitizedKey} is required!')
395
378
  }
379
+ `
380
+ } else {
381
+ code += '\n'
382
+ }
383
+
384
+ if (hasRequiredProperties) {
385
+ addComma = 'json += \',\''
396
386
  }
397
387
  }
398
388
 
399
389
  if (schema.patternProperties || schema.additionalProperties) {
400
- code += buildExtraObjectPropertiesSerializer(context, location)
390
+ code += buildExtraObjectPropertiesSerializer(context, location, addComma)
401
391
  }
402
392
 
403
- context.wrapObjects = wrapObjects
404
393
  code += `
405
- return json${context.wrapObjects ? ' + \'}\'' : ''}
394
+ return json + '}'
406
395
  `
407
396
  return code
408
397
  }
409
398
 
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
399
+ function mergeLocations (context, mergedSchemaId, mergedLocations) {
400
+ for (let i = 0; i < mergedLocations.length; i++) {
401
+ const location = mergedLocations[i]
402
+ const schema = location.schema
403
+ if (schema.$ref) {
404
+ mergedLocations[i] = resolveRef(context, location)
419
405
  }
406
+ }
420
407
 
421
- let allOfSchemaType = allOfSchema.type
422
- if (allOfSchemaType === undefined) {
423
- allOfSchemaType = inferTypeByKeyword(allOfSchema)
424
- }
408
+ const mergedSchemas = []
409
+ for (const location of mergedLocations) {
410
+ const schema = cloneOriginSchema(context, location.schema, location.schemaId)
411
+ delete schema.$id
425
412
 
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
- }
413
+ mergedSchemas.push(schema)
414
+ }
435
415
 
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
- }
416
+ const mergedSchema = mergeSchemas(mergedSchemas)
417
+ const mergedLocation = new Location(mergedSchema, mergedSchemaId)
445
418
 
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
- }
419
+ context.refResolver.addSchema(mergedSchema, mergedSchemaId)
420
+ return mergedLocation
421
+ }
455
422
 
456
- if (allOfSchema.properties !== undefined) {
457
- if (mergedSchema.properties === undefined) {
458
- mergedSchema.properties = {}
459
- }
460
- Object.assign(mergedSchema.properties, allOfSchema.properties)
461
- }
423
+ function cloneOriginSchema (context, schema, schemaId) {
424
+ const clonedSchema = Array.isArray(schema) ? [] : {}
462
425
 
463
- if (allOfSchema.additionalProperties !== undefined) {
464
- if (mergedSchema.additionalProperties === undefined) {
465
- mergedSchema.additionalProperties = {}
466
- }
467
- Object.assign(mergedSchema.additionalProperties, allOfSchema.additionalProperties)
468
- }
426
+ if (
427
+ schema.$id !== undefined &&
428
+ schema.$id.charAt(0) !== '#'
429
+ ) {
430
+ schemaId = schema.$id
431
+ }
469
432
 
470
- if (allOfSchema.patternProperties !== undefined) {
471
- if (mergedSchema.patternProperties === undefined) {
472
- mergedSchema.patternProperties = {}
473
- }
474
- Object.assign(mergedSchema.patternProperties, allOfSchema.patternProperties)
475
- }
433
+ const mergedSchemaRef = context.mergedSchemasIds.get(schema)
434
+ if (mergedSchemaRef) {
435
+ context.mergedSchemasIds.set(clonedSchema, mergedSchemaRef)
436
+ }
476
437
 
477
- if (allOfSchema.required !== undefined) {
478
- if (mergedSchema.required === undefined) {
479
- mergedSchema.required = []
480
- }
481
- mergedSchema.required.push(...allOfSchema.required)
482
- }
438
+ for (const key in schema) {
439
+ let value = schema[key]
483
440
 
484
- if (allOfSchema.oneOf !== undefined) {
485
- if (mergedSchema.oneOf === undefined) {
486
- mergedSchema.oneOf = []
487
- }
488
- mergedSchema.oneOf.push(...allOfSchema.oneOf)
441
+ if (key === '$ref' && value.charAt(0) === '#') {
442
+ value = schemaId + value
489
443
  }
490
444
 
491
- if (allOfSchema.anyOf !== undefined) {
492
- if (mergedSchema.anyOf === undefined) {
493
- mergedSchema.anyOf = []
494
- }
495
- mergedSchema.anyOf.push(...allOfSchema.anyOf)
445
+ if (typeof value === 'object' && value !== null) {
446
+ value = cloneOriginSchema(context, value, schemaId)
496
447
  }
497
448
 
498
- if (allOfSchema.allOf !== undefined) {
499
- mergeAllOfSchema(context, location, allOfSchema, mergedSchema)
500
- }
449
+ clonedSchema[key] = value
501
450
  }
502
- delete mergedSchema.allOf
503
-
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
451
 
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
- `
452
+ return clonedSchema
536
453
  }
537
454
 
538
455
  function toJSON (variableName) {
@@ -582,7 +499,7 @@ function buildArray (context, location) {
582
499
  itemsLocation.schema = itemsLocation.schema || {}
583
500
 
584
501
  if (itemsLocation.schema.$ref) {
585
- itemsLocation = resolveRef(context, itemsLocation, itemsLocation.schema.$ref)
502
+ itemsLocation = resolveRef(context, itemsLocation)
586
503
  }
587
504
 
588
505
  const itemsSchema = itemsLocation.schema
@@ -808,8 +725,24 @@ function buildSingleTypeSerializer (context, location, input) {
808
725
  return `json += serializer.asDate(${input})`
809
726
  } else if (schema.format === 'time') {
810
727
  return `json += serializer.asTime(${input})`
728
+ } else if (schema.format === 'unsafe') {
729
+ return `json += serializer.asUnsafeString(${input})`
811
730
  } else {
812
- return `json += serializer.asString(${input})`
731
+ return `
732
+ if (typeof ${input} !== 'string') {
733
+ if (${input} === null) {
734
+ json += '""'
735
+ } else if (${input} instanceof Date) {
736
+ json += '"' + ${input}.toISOString() + '"'
737
+ } else if (${input} instanceof RegExp) {
738
+ json += serializer.asString(${input}.source)
739
+ } else {
740
+ json += serializer.asString(${input}.toString())
741
+ }
742
+ } else {
743
+ json += serializer.asString(${input})
744
+ }
745
+ `
813
746
  }
814
747
  }
815
748
  case 'integer':
@@ -860,81 +793,193 @@ function buildConstSerializer (location, input) {
860
793
  return code
861
794
  }
862
795
 
863
- function buildValue (context, location, input) {
864
- let schema = location.schema
796
+ function buildAllOf (context, location, input) {
797
+ const schema = location.schema
865
798
 
866
- if (typeof schema === 'boolean') {
867
- return `json += JSON.stringify(${input})`
799
+ let mergedSchemaId = context.mergedSchemasIds.get(schema)
800
+ if (mergedSchemaId) {
801
+ const mergedLocation = getMergedLocation(context, mergedSchemaId)
802
+ return buildValue(context, mergedLocation, input)
868
803
  }
869
804
 
870
- if (schema.$ref) {
871
- location = resolveRef(context, location, schema.$ref)
872
- schema = location.schema
805
+ mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
806
+ context.mergedSchemasIds.set(schema, mergedSchemaId)
807
+
808
+ const { allOf, ...schemaWithoutAllOf } = location.schema
809
+ const locations = [
810
+ new Location(
811
+ schemaWithoutAllOf,
812
+ location.schemaId,
813
+ location.jsonPointer
814
+ )
815
+ ]
816
+
817
+ const allOfsLocation = location.getPropertyLocation('allOf')
818
+ for (let i = 0; i < allOf.length; i++) {
819
+ locations.push(allOfsLocation.getPropertyLocation(i))
873
820
  }
874
821
 
875
- if (schema.type === undefined) {
876
- const inferredType = inferTypeByKeyword(schema)
877
- if (inferredType) {
878
- schema.type = inferredType
822
+ const mergedLocation = mergeLocations(context, mergedSchemaId, locations)
823
+ return buildValue(context, mergedLocation, input)
824
+ }
825
+
826
+ function buildOneOf (context, location, input) {
827
+ context.validatorSchemasIds.add(location.schemaId)
828
+
829
+ const schema = location.schema
830
+
831
+ const type = schema.anyOf ? 'anyOf' : 'oneOf'
832
+ const { [type]: oneOfs, ...schemaWithoutAnyOf } = location.schema
833
+
834
+ const locationWithoutOneOf = new Location(
835
+ schemaWithoutAnyOf,
836
+ location.schemaId,
837
+ location.jsonPointer
838
+ )
839
+ const oneOfsLocation = location.getPropertyLocation(type)
840
+
841
+ let code = ''
842
+
843
+ for (let index = 0; index < oneOfs.length; index++) {
844
+ const optionLocation = oneOfsLocation.getPropertyLocation(index)
845
+ const optionSchema = optionLocation.schema
846
+
847
+ let mergedSchemaId = context.mergedSchemasIds.get(optionSchema)
848
+ let mergedLocation = null
849
+ if (mergedSchemaId) {
850
+ mergedLocation = getMergedLocation(context, mergedSchemaId)
851
+ } else {
852
+ mergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
853
+ context.mergedSchemasIds.set(optionSchema, mergedSchemaId)
854
+
855
+ mergedLocation = mergeLocations(context, mergedSchemaId, [
856
+ locationWithoutOneOf,
857
+ optionLocation
858
+ ])
879
859
  }
860
+
861
+ const nestedResult = buildValue(context, mergedLocation, input)
862
+ const schemaRef = optionLocation.getSchemaRef()
863
+ code += `
864
+ ${index === 0 ? 'if' : 'else if'}(validator.validate("${schemaRef}", ${input}))
865
+ ${nestedResult}
866
+ `
880
867
  }
881
868
 
882
- if (schema.if && schema.then) {
883
- return addIfThenElse(context, location, input)
869
+ let schemaRef = location.getSchemaRef()
870
+ if (schemaRef.startsWith(context.rootSchemaId)) {
871
+ schemaRef = schemaRef.replace(context.rootSchemaId, '')
884
872
  }
885
873
 
886
- if (schema.allOf) {
887
- mergeAllOfSchema(context, location, schema, clone(schema))
888
- schema = location.schema
874
+ code += `
875
+ else throw new TypeError(\`The value of '${schemaRef}' does not match schema definition.\`)
876
+ `
877
+
878
+ return code
879
+ }
880
+
881
+ function buildIfThenElse (context, location, input) {
882
+ context.validatorSchemasIds.add(location.schemaId)
883
+
884
+ const {
885
+ if: ifSchema,
886
+ then: thenSchema,
887
+ else: elseSchema,
888
+ ...schemaWithoutIfThenElse
889
+ } = location.schema
890
+
891
+ const rootLocation = new Location(
892
+ schemaWithoutIfThenElse,
893
+ location.schemaId,
894
+ location.jsonPointer
895
+ )
896
+
897
+ const ifLocation = location.getPropertyLocation('if')
898
+ const ifSchemaRef = ifLocation.getSchemaRef()
899
+
900
+ const thenLocation = location.getPropertyLocation('then')
901
+ let thenMergedSchemaId = context.mergedSchemasIds.get(thenSchema)
902
+ let thenMergedLocation = null
903
+ if (thenMergedSchemaId) {
904
+ thenMergedLocation = getMergedLocation(context, thenMergedSchemaId)
905
+ } else {
906
+ thenMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
907
+ context.mergedSchemasIds.set(thenSchema, thenMergedSchemaId)
908
+
909
+ thenMergedLocation = mergeLocations(context, thenMergedSchemaId, [
910
+ rootLocation,
911
+ thenLocation
912
+ ])
889
913
  }
890
914
 
891
- const type = schema.type
915
+ if (!elseSchema) {
916
+ return `
917
+ if (validator.validate("${ifSchemaRef}", ${input})) {
918
+ ${buildValue(context, thenMergedLocation, input)}
919
+ } else {
920
+ ${buildValue(context, rootLocation, input)}
921
+ }
922
+ `
923
+ }
892
924
 
893
- let code = ''
925
+ const elseLocation = location.getPropertyLocation('else')
926
+ let elseMergedSchemaId = context.mergedSchemasIds.get(elseSchema)
927
+ let elseMergedLocation = null
928
+ if (elseMergedSchemaId) {
929
+ elseMergedLocation = getMergedLocation(context, elseMergedSchemaId)
930
+ } else {
931
+ elseMergedSchemaId = `__fjs_merged_${schemaIdCounter++}`
932
+ context.mergedSchemasIds.set(elseSchema, elseMergedSchemaId)
894
933
 
895
- if ((type === undefined || type === 'object') && (schema.anyOf || schema.oneOf)) {
896
- context.validatorSchemasIds.add(location.getSchemaId())
934
+ elseMergedLocation = mergeLocations(context, elseMergedSchemaId, [
935
+ rootLocation,
936
+ elseLocation
937
+ ])
938
+ }
897
939
 
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
- `
940
+ return `
941
+ if (validator.validate("${ifSchemaRef}", ${input})) {
942
+ ${buildValue(context, thenMergedLocation, input)}
943
+ } else {
944
+ ${buildValue(context, elseMergedLocation, input)}
906
945
  }
946
+ `
947
+ }
907
948
 
908
- const type = schema.anyOf ? 'anyOf' : 'oneOf'
909
- const anyOfLocation = location.getPropertyLocation(type)
949
+ function buildValue (context, location, input) {
950
+ let schema = location.schema
910
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
+ if (typeof schema === 'boolean') {
953
+ return `json += JSON.stringify(${input})`
954
+ }
920
955
 
921
- let schemaRef = location.getSchemaRef()
922
- if (schemaRef.startsWith(context.rootSchemaId)) {
923
- schemaRef = schemaRef.replace(context.rootSchemaId, '')
924
- }
956
+ if (schema.$ref) {
957
+ location = resolveRef(context, location)
958
+ schema = location.schema
959
+ }
925
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
+ if (schema.allOf) {
962
+ return buildAllOf(context, location, input)
963
+ }
964
+
965
+ if (schema.anyOf || schema.oneOf) {
966
+ return buildOneOf(context, location, input)
967
+ }
968
+
969
+ if (schema.if && schema.then) {
970
+ return buildIfThenElse(context, location, input)
971
+ }
972
+
973
+ if (schema.type === undefined) {
974
+ const inferredType = inferTypeByKeyword(schema)
975
+ if (inferredType) {
976
+ schema.type = inferredType
934
977
  }
935
- return code
936
978
  }
937
979
 
980
+ let code = ''
981
+
982
+ const type = schema.type
938
983
  const nullable = schema.nullable === true
939
984
  if (nullable) {
940
985
  code += `