@@ -9,8 +9,8 @@ const { randomUUID } = require('crypto')
9
9
10
10
const validate = require ( './schema-validator' )
11
11
const Serializer = require ( './serializer' )
12
+ const Validator = require ( './validator' )
12
13
const RefResolver = require ( './ref-resolver' )
13
- const buildAjv = require ( './ajv' )
14
14
15
15
let largeArraySize = 2e4
16
16
let largeArrayMechanism = 'default'
@@ -75,51 +75,31 @@ const arrayItemsReferenceSerializersMap = new Map()
75
75
const objectReferenceSerializersMap = new Map ( )
76
76
77
77
let rootSchemaId = null
78
- let ajvInstance = null
79
78
let refResolver = null
79
+ let validator = null
80
80
let contextFunctions = null
81
81
82
82
function build ( schema , options ) {
83
- schema = clone ( schema )
84
-
85
83
arrayItemsReferenceSerializersMap . clear ( )
86
84
objectReferenceSerializersMap . clear ( )
87
85
88
86
contextFunctions = [ ]
89
87
options = options || { }
90
88
91
- ajvInstance = buildAjv ( options . ajv )
92
89
refResolver = new RefResolver ( )
90
+ validator = new Validator ( options . ajv )
91
+
93
92
rootSchemaId = schema . $id || randomUUID ( )
94
93
95
94
isValidSchema ( schema )
96
- extendDateTimeType ( schema )
97
- ajvInstance . addSchema ( schema , rootSchemaId )
95
+ validator . addSchema ( schema , rootSchemaId )
98
96
refResolver . addSchema ( schema , rootSchemaId )
99
97
100
98
if ( options . schema ) {
101
- const externalSchemas = clone ( options . schema )
102
-
103
- for ( const key of Object . keys ( externalSchemas ) ) {
104
- const externalSchema = externalSchemas [ key ]
105
- isValidSchema ( externalSchema , key )
106
- extendDateTimeType ( externalSchema )
107
-
108
- let schemaKey = externalSchema . $id || key
109
- if ( externalSchema . $id !== undefined && externalSchema . $id [ 0 ] === '#' ) {
110
- schemaKey = key + externalSchema . $id // relative URI
111
- }
112
-
113
- if ( refResolver . getSchema ( schemaKey ) === undefined ) {
114
- refResolver . addSchema ( externalSchema , key )
115
- }
116
-
117
- if (
118
- ajvInstance . refs [ schemaKey ] === undefined &&
119
- ajvInstance . schemas [ schemaKey ] === undefined
120
- ) {
121
- ajvInstance . addSchema ( externalSchema , schemaKey )
122
- }
99
+ for ( const key of Object . keys ( options . schema ) ) {
100
+ isValidSchema ( options . schema [ key ] , key )
101
+ validator . addSchema ( options . schema [ key ] , key )
102
+ refResolver . addSchema ( options . schema [ key ] , key )
123
103
}
124
104
}
125
105
@@ -160,28 +140,28 @@ function build (schema, options) {
160
140
return main
161
141
`
162
142
163
- const dependenciesName = [ 'ajv ' , 'serializer' , contextFunctionCode ]
143
+ const dependenciesName = [ 'validator ' , 'serializer' , contextFunctionCode ]
164
144
165
145
if ( options . debugMode ) {
166
146
options . mode = 'debug'
167
147
}
168
148
169
149
if ( options . mode === 'debug' ) {
170
- return { code : dependenciesName . join ( '\n' ) , ajv : ajvInstance }
150
+ return { code : dependenciesName . join ( '\n' ) , validator }
171
151
}
172
152
173
153
if ( options . mode === 'standalone' ) {
174
154
// lazy load
175
155
const buildStandaloneCode = require ( './standalone' )
176
- return buildStandaloneCode ( options , ajvInstance , contextFunctionCode )
156
+ return buildStandaloneCode ( options , validator , contextFunctionCode )
177
157
}
178
158
179
159
/* eslint no-new-func: "off" */
180
- const contextFunc = new Function ( 'ajv ' , 'serializer' , contextFunctionCode )
181
- const stringifyFunc = contextFunc ( ajvInstance , serializer )
160
+ const contextFunc = new Function ( 'validator ' , 'serializer' , contextFunctionCode )
161
+ const stringifyFunc = contextFunc ( validator , serializer )
182
162
183
- ajvInstance = null
184
163
refResolver = null
164
+ validator = null
185
165
rootSchemaId = null
186
166
contextFunctions = null
187
167
arrayItemsReferenceSerializersMap . clear ( )
@@ -345,9 +325,8 @@ function buildCode (location) {
345
325
const propertiesLocation = mergeLocation ( location , 'properties' )
346
326
Object . keys ( schema . properties || { } ) . forEach ( ( key ) => {
347
327
let propertyLocation = mergeLocation ( propertiesLocation , key )
348
- if ( schema . properties [ key ] . $ref ) {
349
- propertyLocation = resolveRef ( location , schema . properties [ key ] . $ref )
350
- schema . properties [ key ] = propertyLocation . schema
328
+ if ( propertyLocation . $ref ) {
329
+ propertyLocation = resolveRef ( location , propertyLocation . $ref )
351
330
}
352
331
353
332
// Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
@@ -364,7 +343,7 @@ function buildCode (location) {
364
343
365
344
code += buildValue ( propertyLocation , `obj[${ JSON . stringify ( key ) } ]` )
366
345
367
- const defaultValue = schema . properties [ key ] . default
346
+ const defaultValue = propertyLocation . schema . default
368
347
if ( defaultValue !== undefined ) {
369
348
code += `
370
349
} else {
@@ -479,24 +458,14 @@ function mergeAllOfSchema (location, schema, mergedSchema) {
479
458
mergedSchema . anyOf . push ( ...allOfSchema . anyOf )
480
459
}
481
460
482
- if ( allOfSchema . fjs_type !== undefined ) {
483
- if (
484
- mergedSchema . fjs_type !== undefined &&
485
- mergedSchema . fjs_type !== allOfSchema . fjs_type
486
- ) {
487
- throw new Error ( 'allOf schemas have different fjs_type values' )
488
- }
489
- mergedSchema . fjs_type = allOfSchema . fjs_type
490
- }
491
-
492
461
if ( allOfSchema . allOf !== undefined ) {
493
462
mergeAllOfSchema ( location , allOfSchema , mergedSchema )
494
463
}
495
464
}
496
465
delete mergedSchema . allOf
497
466
498
467
mergedSchema . $id = `merged_${ randomUUID ( ) } `
499
- ajvInstance . addSchema ( mergedSchema )
468
+ validator . addSchema ( mergedSchema )
500
469
refResolver . addSchema ( mergedSchema )
501
470
location . schemaId = mergedSchema . $id
502
471
location . jsonPointer = '#'
@@ -526,7 +495,7 @@ function addIfThenElse (location) {
526
495
const ifSchemaRef = ifLocation . schemaId + ifLocation . jsonPointer
527
496
528
497
let code = `
529
- if (ajv .validate("${ ifSchemaRef } ", obj)) {
498
+ if (validator .validate("${ ifSchemaRef } ", obj)) {
530
499
`
531
500
532
501
const thenLocation = mergeLocation ( location , 'then' )
@@ -800,22 +769,26 @@ function buildValue (location, input) {
800
769
location . schema = mergedSchema
801
770
}
802
771
803
- let type = schema . type
772
+ const type = schema . type
804
773
const nullable = schema . nullable === true
805
774
806
775
let code = ''
807
776
let funcName
808
777
809
- if ( schema . fjs_type === 'string' && schema . format === undefined && Array . isArray ( schema . type ) && schema . type . length === 2 ) {
810
- type = 'string'
811
- }
812
-
813
778
switch ( type ) {
814
779
case 'null' :
815
780
code += 'json += serializer.asNull()'
816
781
break
817
782
case 'string' : {
818
- funcName = nullable ? 'serializer.asStringNullable.bind(serializer)' : 'serializer.asString.bind(serializer)'
783
+ if ( schema . format === 'date-time' ) {
784
+ funcName = nullable ? 'serializer.asDateTimeNullable.bind(serializer)' : 'serializer.asDateTime.bind(serializer)'
785
+ } else if ( schema . format === 'date' ) {
786
+ funcName = nullable ? 'serializer.asDateNullable.bind(serializer)' : 'serializer.asDate.bind(serializer)'
787
+ } else if ( schema . format === 'time' ) {
788
+ funcName = nullable ? 'serializer.asTimeNullable.bind(serializer)' : 'serializer.asTime.bind(serializer)'
789
+ } else {
790
+ funcName = nullable ? 'serializer.asStringNullable.bind(serializer)' : 'serializer.asString.bind(serializer)'
791
+ }
819
792
code += `json += ${ funcName } (${ input } )`
820
793
break
821
794
}
@@ -832,15 +805,7 @@ function buildValue (location, input) {
832
805
code += `json += ${ funcName } (${ input } )`
833
806
break
834
807
case 'object' :
835
- if ( schema . format === 'date-time' ) {
836
- funcName = nullable ? 'serializer.asDateTimeNullable.bind(serializer)' : 'serializer.asDateTime.bind(serializer)'
837
- } else if ( schema . format === 'date' ) {
838
- funcName = nullable ? 'serializer.asDateNullable.bind(serializer)' : 'serializer.asDate.bind(serializer)'
839
- } else if ( schema . format === 'time' ) {
840
- funcName = nullable ? 'serializer.asTimeNullable.bind(serializer)' : 'serializer.asTime.bind(serializer)'
841
- } else {
842
- funcName = buildObject ( location )
843
- }
808
+ funcName = buildObject ( location )
844
809
code += `json += ${ funcName } (${ input } )`
845
810
break
846
811
case 'array' :
@@ -858,7 +823,7 @@ function buildValue (location, input) {
858
823
const schemaRef = optionLocation . schemaId + optionLocation . jsonPointer
859
824
const nestedResult = buildValue ( optionLocation , input )
860
825
code += `
861
- ${ index === 0 ? 'if' : 'else if' } (ajv .validate("${ schemaRef } ", ${ input } ))
826
+ ${ index === 0 ? 'if' : 'else if' } (validator .validate("${ schemaRef } ", ${ input } ))
862
827
${ nestedResult }
863
828
`
864
829
}
@@ -872,7 +837,7 @@ function buildValue (location, input) {
872
837
`
873
838
} else if ( 'const' in schema ) {
874
839
code += `
875
- if(ajv .validate(${ JSON . stringify ( schema ) } , ${ input } ))
840
+ if(validator .validate(${ JSON . stringify ( schema ) } , ${ input } ))
876
841
json += '${ JSON . stringify ( schema . const ) } '
877
842
else
878
843
throw new Error(\`Item $\{JSON.stringify(${ input } )} does not match schema definition.\`)
@@ -906,7 +871,7 @@ function buildValue (location, input) {
906
871
switch ( type ) {
907
872
case 'string' : {
908
873
code += `
909
- ${ statement } (${ input } === null || typeof ${ input } === "${ type } " || ${ input } instanceof RegExp || (typeof ${ input } === "object" && Object.hasOwnProperty.call(${ input } , "toString")))
874
+ ${ statement } (${ input } === null || typeof ${ input } === "${ type } " || ${ input } instanceof RegExp || ${ input } instanceof Date || (typeof ${ input } === "object" && Object.hasOwnProperty.call(${ input } , "toString")))
910
875
${ nestedResult }
911
876
`
912
877
break
@@ -926,17 +891,10 @@ function buildValue (location, input) {
926
891
break
927
892
}
928
893
case 'object' : {
929
- if ( schema . fjs_type ) {
930
- code += `
931
- ${ statement } (${ input } instanceof Date || ${ input } === null)
932
- ${ nestedResult }
933
- `
934
- } else {
935
- code += `
936
- ${ statement } (typeof ${ input } === "object" || ${ input } === null)
937
- ${ nestedResult }
938
- `
939
- }
894
+ code += `
895
+ ${ statement } (typeof ${ input } === "object" || ${ input } === null)
896
+ ${ nestedResult }
897
+ `
940
898
break
941
899
}
942
900
default : {
@@ -965,30 +923,6 @@ function buildValue (location, input) {
965
923
return code
966
924
}
967
925
968
- // Ajv does not support js date format. In order to properly validate objects containing a date,
969
- // it needs to replace all occurrences of the string date format with a custom keyword fjs_type.
970
- // (see https://github.com/fastify/fast-json-stringify/pull/441)
971
- function extendDateTimeType ( schema ) {
972
- if ( schema === null ) return
973
-
974
- if ( schema . type === 'string' ) {
975
- schema . fjs_type = 'string'
976
- schema . type = [ 'string' , 'object' ]
977
- } else if (
978
- Array . isArray ( schema . type ) &&
979
- schema . type . includes ( 'string' ) &&
980
- ! schema . type . includes ( 'object' )
981
- ) {
982
- schema . fjs_type = 'string'
983
- schema . type . push ( 'object' )
984
- }
985
- for ( const property in schema ) {
986
- if ( typeof schema [ property ] === 'object' ) {
987
- extendDateTimeType ( schema [ property ] )
988
- }
989
- }
990
- }
991
-
992
926
function isEmpty ( schema ) {
993
927
// eslint-disable-next-line
994
928
for ( var key in schema ) {
@@ -1003,9 +937,9 @@ module.exports = build
1003
937
1004
938
module . exports . validLargeArrayMechanisms = validLargeArrayMechanisms
1005
939
1006
- module . exports . restore = function ( { code, ajv } ) {
940
+ module . exports . restore = function ( { code, validator } ) {
1007
941
const serializer = new Serializer ( )
1008
942
// eslint-disable-next-line
1009
- return ( Function . apply ( null , [ 'ajv ' , 'serializer' , code ] )
1010
- . apply ( null , [ ajv , serializer ] ) )
943
+ return ( Function . apply ( null , [ 'validator ' , 'serializer' , code ] )
944
+ . apply ( null , [ validator , serializer ] ) )
1011
945
}
0 commit comments