@@ -243,15 +243,6 @@ function inferTypeByKeyword (schema) {
243243 return schema . type
244244}
245245
246- function getStringSerializer ( format , nullable ) {
247- switch ( format ) {
248- case 'date-time' : return nullable ? 'serializer.asDatetimeNullable.bind(serializer)' : 'serializer.asDatetime.bind(serializer)'
249- case 'date' : return nullable ? 'serializer.asDateNullable.bind(serializer)' : 'serializer.asDate.bind(serializer)'
250- case 'time' : return nullable ? 'serializer.asTimeNullable.bind(serializer)' : 'serializer.asTime.bind(serializer)'
251- default : return nullable ? 'serializer.asStringNullable.bind(serializer)' : 'serializer.asString.bind(serializer)'
252- }
253- }
254-
255246function addPatternProperties ( location ) {
256247 const schema = location . schema
257248 const pp = schema . patternProperties
@@ -484,6 +475,16 @@ function mergeAllOfSchema (location, schema, mergedSchema) {
484475 mergedSchema . anyOf . push ( ...allOfSchema . anyOf )
485476 }
486477
478+ if ( allOfSchema . fjs_type !== undefined ) {
479+ if (
480+ mergedSchema . fjs_type !== undefined &&
481+ mergedSchema . fjs_type !== allOfSchema . fjs_type
482+ ) {
483+ throw new Error ( 'allOf schemas have different fjs_type values' )
484+ }
485+ mergedSchema . fjs_type = allOfSchema . fjs_type
486+ }
487+
487488 if ( allOfSchema . allOf !== undefined ) {
488489 mergeAllOfSchema ( location , allOfSchema , mergedSchema )
489490 }
@@ -790,20 +791,22 @@ function buildValue (location, input) {
790791 location . schema = mergedSchema
791792 }
792793
793- const type = schema . type
794+ let type = schema . type
794795 const nullable = schema . nullable === true
795796
796797 let code = ''
797798 let funcName
798799
800+ if ( schema . fjs_type === 'string' && schema . format === undefined && Array . isArray ( schema . type ) && schema . type . length === 2 ) {
801+ type = 'string'
802+ }
803+
799804 switch ( type ) {
800805 case 'null' :
801- code += `
802- json += serializer.asNull()
803- `
806+ code += 'json += serializer.asNull()'
804807 break
805808 case 'string' : {
806- funcName = getStringSerializer ( schema . format , nullable )
809+ funcName = nullable ? 'serializer.asStringNullable.bind(serializer)' : 'serializer.asString.bind(serializer)'
807810 code += `json += ${ funcName } (${ input } )`
808811 break
809812 }
@@ -820,19 +823,23 @@ function buildValue (location, input) {
820823 code += `json += ${ funcName } (${ input } )`
821824 break
822825 case 'object' :
823- funcName = buildObject ( location )
826+ if ( schema . format === 'date-time' ) {
827+ funcName = nullable ? 'serializer.asDateTimeNullable.bind(serializer)' : 'serializer.asDateTime.bind(serializer)'
828+ } else if ( schema . format === 'date' ) {
829+ funcName = nullable ? 'serializer.asDateNullable.bind(serializer)' : 'serializer.asDate.bind(serializer)'
830+ } else if ( schema . format === 'time' ) {
831+ funcName = nullable ? 'serializer.asTimeNullable.bind(serializer)' : 'serializer.asTime.bind(serializer)'
832+ } else {
833+ funcName = buildObject ( location )
834+ }
824835 code += `json += ${ funcName } (${ input } )`
825836 break
826837 case 'array' :
827838 funcName = buildArray ( location )
828839 code += `json += ${ funcName } (${ input } )`
829840 break
830841 case undefined :
831- if ( schema . fjs_date_type ) {
832- funcName = getStringSerializer ( schema . fjs_date_type , nullable )
833- code += `json += ${ funcName } (${ input } )`
834- break
835- } else if ( schema . anyOf || schema . oneOf ) {
842+ if ( schema . anyOf || schema . oneOf ) {
836843 // beware: dereferenceOfRefs has side effects and changes schema.anyOf
837844 const type = schema . anyOf ? 'anyOf' : 'oneOf'
838845 const anyOfLocation = mergeLocation ( location , type )
@@ -890,7 +897,7 @@ function buildValue (location, input) {
890897 switch ( type ) {
891898 case 'string' : {
892899 code += `
893- ${ statement } (${ input } === null || typeof ${ input } === "${ type } " || ${ input } instanceof Date || ${ input } instanceof RegExp || (typeof ${ input } === "object" && Object.hasOwnProperty.call(${ input } , "toString")))
900+ ${ statement } (${ input } === null || typeof ${ input } === "${ type } " || ${ input } instanceof RegExp || (typeof ${ input } === "object" && Object.hasOwnProperty.call(${ input } , "toString")))
894901 ${ nestedResult }
895902 `
896903 break
@@ -909,6 +916,20 @@ function buildValue (location, input) {
909916 `
910917 break
911918 }
919+ case 'object' : {
920+ if ( schema . fjs_type ) {
921+ code += `
922+ ${ statement } (${ input } instanceof Date || ${ input } === null)
923+ ${ nestedResult }
924+ `
925+ } else {
926+ code += `
927+ ${ statement } (typeof ${ input } === "object" || ${ input } === null)
928+ ${ nestedResult }
929+ `
930+ }
931+ break
932+ }
912933 default : {
913934 code += `
914935 ${ statement } (typeof ${ input } === "${ type } " || ${ input } === null)
@@ -936,15 +957,21 @@ function buildValue (location, input) {
936957}
937958
938959// Ajv does not support js date format. In order to properly validate objects containing a date,
939- // it needs to replace all occurrences of the string date format with a custom keyword fjs_date_type .
960+ // it needs to replace all occurrences of the string date format with a custom keyword fjs_type .
940961// (see https://github.com/fastify/fast-json-stringify/pull/441)
941962function extendDateTimeType ( schema ) {
942963 if ( schema === null ) return
943964
944- if ( schema . type === 'string' && [ 'date-time' , 'date' , 'time' ] . includes ( schema . format ) ) {
945- schema . fjs_date_type = schema . format
946- delete schema . type
947- delete schema . format
965+ if ( schema . type === 'string' ) {
966+ schema . fjs_type = 'string'
967+ schema . type = [ 'string' , 'object' ]
968+ } else if (
969+ Array . isArray ( schema . type ) &&
970+ schema . type . includes ( 'string' ) &&
971+ ! schema . type . includes ( 'object' )
972+ ) {
973+ schema . fjs_type = 'string'
974+ schema . type . push ( 'object' )
948975 }
949976 for ( const property in schema ) {
950977 if ( typeof schema [ property ] === 'object' ) {
0 commit comments