@@ -549,13 +549,6 @@ function buildObject (location) {
549
549
function ${ functionName } (input) {
550
550
// ${ schemaId + location . jsonPointer }
551
551
`
552
- if ( schema . nullable ) {
553
- functionCode += `
554
- if (input === null) {
555
- return 'null';
556
- }
557
- `
558
- }
559
552
560
553
functionCode += `
561
554
var obj = ${ toJSON ( 'input' ) }
@@ -604,14 +597,6 @@ function buildArray (location) {
604
597
// ${ schemaId + location . jsonPointer }
605
598
`
606
599
607
- if ( schema . nullable ) {
608
- functionCode += `
609
- if (obj === null) {
610
- return 'null';
611
- }
612
- `
613
- }
614
-
615
600
functionCode += `
616
601
if (!Array.isArray(obj)) {
617
602
throw new TypeError(\`The value '$\{obj}' does not match schema definition.\`)
@@ -732,6 +717,137 @@ function generateFuncName () {
732
717
return 'anonymous' + genFuncNameCounter ++
733
718
}
734
719
720
+ function buildMultiTypeSerializer ( location , input ) {
721
+ const schema = location . schema
722
+ const types = schema . type . sort ( t1 => t1 === 'null' ? - 1 : 1 )
723
+
724
+ let code = ''
725
+
726
+ const locationClone = clone ( location )
727
+ types . forEach ( ( type , index ) => {
728
+ const statement = index === 0 ? 'if' : 'else if'
729
+ locationClone . schema . type = type
730
+ const nestedResult = buildSingleTypeSerializer ( locationClone , input )
731
+ switch ( type ) {
732
+ case 'null' :
733
+ code += `
734
+ ${ statement } (${ input } === null)
735
+ ${ nestedResult }
736
+ `
737
+ break
738
+ case 'string' : {
739
+ code += `
740
+ ${ statement } (
741
+ typeof ${ input } === "string" ||
742
+ ${ input } === null ||
743
+ ${ input } instanceof Date ||
744
+ ${ input } instanceof RegExp ||
745
+ (
746
+ typeof ${ input } === "object" &&
747
+ typeof ${ input } .toString === "function" &&
748
+ ${ input } .toString !== Object.prototype.toString &&
749
+ !(${ input } instanceof Date)
750
+ )
751
+ )
752
+ ${ nestedResult }
753
+ `
754
+ break
755
+ }
756
+ case 'array' : {
757
+ code += `
758
+ ${ statement } (Array.isArray(${ input } ))
759
+ ${ nestedResult }
760
+ `
761
+ break
762
+ }
763
+ case 'integer' : {
764
+ code += `
765
+ ${ statement } (Number.isInteger(${ input } ) || ${ input } === null)
766
+ ${ nestedResult }
767
+ `
768
+ break
769
+ }
770
+ default : {
771
+ code += `
772
+ ${ statement } (typeof ${ input } === "${ type } " || ${ input } === null)
773
+ ${ nestedResult }
774
+ `
775
+ break
776
+ }
777
+ }
778
+ } )
779
+ code += `
780
+ else throw new Error(\`The value $\{JSON.stringify(${ input } )} does not match schema definition.\`)
781
+ `
782
+
783
+ return code
784
+ }
785
+
786
+ function buildSingleTypeSerializer ( location , input ) {
787
+ const schema = location . schema
788
+
789
+ switch ( schema . type ) {
790
+ case 'null' :
791
+ return 'json += \'null\''
792
+ case 'string' : {
793
+ if ( schema . format === 'date-time' ) {
794
+ return `json += serializer.asDateTime(${ input } )`
795
+ } else if ( schema . format === 'date' ) {
796
+ return `json += serializer.asDate(${ input } )`
797
+ } else if ( schema . format === 'time' ) {
798
+ return `json += serializer.asTime(${ input } )`
799
+ } else {
800
+ return `json += serializer.asString(${ input } )`
801
+ }
802
+ }
803
+ case 'integer' :
804
+ return `json += serializer.asInteger(${ input } )`
805
+ case 'number' :
806
+ return `json += serializer.asNumber(${ input } )`
807
+ case 'boolean' :
808
+ return `json += serializer.asBoolean(${ input } )`
809
+ case 'object' : {
810
+ const funcName = buildObject ( location )
811
+ return `json += ${ funcName } (${ input } )`
812
+ }
813
+ case 'array' : {
814
+ const funcName = buildArray ( location )
815
+ return `json += ${ funcName } (${ input } )`
816
+ }
817
+ case undefined :
818
+ return `json += JSON.stringify(${ input } )`
819
+ default :
820
+ throw new Error ( `${ schema . type } unsupported` )
821
+ }
822
+ }
823
+
824
+ function buildConstSerializer ( location , input ) {
825
+ const schema = location . schema
826
+ const type = schema . type
827
+
828
+ const hasNullType = Array . isArray ( type ) && type . includes ( 'null' )
829
+
830
+ let code = ''
831
+
832
+ if ( hasNullType ) {
833
+ code += `
834
+ if (${ input } === null) {
835
+ json += 'null'
836
+ } else {
837
+ `
838
+ }
839
+
840
+ code += `json += '${ JSON . stringify ( schema . const ) } '`
841
+
842
+ if ( hasNullType ) {
843
+ code += `
844
+ }
845
+ `
846
+ }
847
+
848
+ return code
849
+ }
850
+
735
851
function buildValue ( location , input ) {
736
852
let schema = location . schema
737
853
@@ -759,163 +875,50 @@ function buildValue (location, input) {
759
875
}
760
876
761
877
const type = schema . type
762
- const nullable = schema . nullable === true || ( Array . isArray ( type ) && type . includes ( 'null' ) )
763
878
764
879
let code = ''
765
- let funcName
766
880
767
- if ( 'const' in schema ) {
768
- if ( nullable ) {
881
+ if ( type === undefined && ( schema . anyOf || schema . oneOf ) ) {
882
+ const type = schema . anyOf ? 'anyOf' : 'oneOf'
883
+ const anyOfLocation = mergeLocation ( location , type )
884
+
885
+ for ( let index = 0 ; index < location . schema [ type ] . length ; index ++ ) {
886
+ const optionLocation = mergeLocation ( anyOfLocation , index )
887
+ const schemaRef = optionLocation . schemaId + optionLocation . jsonPointer
888
+ const nestedResult = buildValue ( optionLocation , input )
769
889
code += `
770
- json += ${ input } === null ? 'null' : '${ JSON . stringify ( schema . const ) } '
890
+ ${ index === 0 ? 'if' : 'else if' } (validator.validate("${ schemaRef } ", ${ input } ))
891
+ ${ nestedResult }
771
892
`
772
- return code
773
893
}
774
- code += `json += '${ JSON . stringify ( schema . const ) } '`
894
+
895
+ code += `
896
+ else throw new Error(\`The value $\{JSON.stringify(${ input } )} does not match schema definition.\`)
897
+ `
775
898
return code
776
899
}
777
900
778
- switch ( type ) {
779
- case 'null' :
780
- code += 'json += serializer.asNull()'
781
- break
782
- case 'string' : {
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
- }
792
- code += `json += ${ funcName } (${ input } )`
793
- break
794
- }
795
- case 'integer' :
796
- funcName = nullable ? 'serializer.asIntegerNullable.bind(serializer)' : 'serializer.asInteger.bind(serializer)'
797
- code += `json += ${ funcName } (${ input } )`
798
- break
799
- case 'number' :
800
- funcName = nullable ? 'serializer.asNumberNullable.bind(serializer)' : 'serializer.asNumber.bind(serializer)'
801
- code += `json += ${ funcName } (${ input } )`
802
- break
803
- case 'boolean' :
804
- funcName = nullable ? 'serializer.asBooleanNullable.bind(serializer)' : 'serializer.asBoolean.bind(serializer)'
805
- code += `json += ${ funcName } (${ input } )`
806
- break
807
- case 'object' :
808
- funcName = buildObject ( location )
809
- code += `json += ${ funcName } (${ input } )`
810
- break
811
- case 'array' :
812
- funcName = buildArray ( location )
813
- code += `json += ${ funcName } (${ input } )`
814
- break
815
- case undefined :
816
- if ( schema . anyOf || schema . oneOf ) {
817
- // beware: dereferenceOfRefs has side effects and changes schema.anyOf
818
- const type = schema . anyOf ? 'anyOf' : 'oneOf'
819
- const anyOfLocation = mergeLocation ( location , type )
820
-
821
- for ( let index = 0 ; index < location . schema [ type ] . length ; index ++ ) {
822
- const optionLocation = mergeLocation ( anyOfLocation , index )
823
- const schemaRef = optionLocation . schemaId + optionLocation . jsonPointer
824
- const nestedResult = buildValue ( optionLocation , input )
825
- code += `
826
- ${ index === 0 ? 'if' : 'else if' } (validator.validate("${ schemaRef } ", ${ input } ))
827
- ${ nestedResult }
828
- `
829
- }
830
-
831
- code += `
832
- else throw new Error(\`The value $\{JSON.stringify(${ input } )} does not match schema definition.\`)
833
- `
901
+ const nullable = schema . nullable === true
902
+ if ( nullable ) {
903
+ code += `
904
+ if (${ input } === null) {
905
+ json += 'null'
834
906
} else {
835
- code += `
836
- json += JSON.stringify(${ input } )
837
- `
838
- }
839
- break
840
- default :
841
- if ( Array . isArray ( type ) ) {
842
- let sortedTypes = type
843
- const nullable = schema . nullable === true || type . includes ( 'null' )
844
-
845
- if ( nullable ) {
846
- sortedTypes = sortedTypes . filter ( type => type !== 'null' )
847
- code += `
848
- if (${ input } === null) {
849
- json += null
850
- } else {`
851
- }
907
+ `
908
+ }
852
909
853
- const locationClone = clone ( location )
854
- sortedTypes . forEach ( ( type , index ) => {
855
- const statement = index === 0 ? 'if' : 'else if'
856
- locationClone . schema . type = type
857
- const nestedResult = buildValue ( locationClone , input )
858
- switch ( type ) {
859
- case 'string' : {
860
- code += `
861
- ${ statement } (
862
- typeof ${ input } === "string" ||
863
- ${ input } === null ||
864
- ${ input } instanceof Date ||
865
- ${ input } instanceof RegExp ||
866
- (
867
- typeof ${ input } === "object" &&
868
- typeof ${ input } .toString === "function" &&
869
- ${ input } .toString !== Object.prototype.toString &&
870
- !(${ input } instanceof Date)
871
- )
872
- )
873
- ${ nestedResult }
874
- `
875
- break
876
- }
877
- case 'array' : {
878
- code += `
879
- ${ statement } (Array.isArray(${ input } ))
880
- ${ nestedResult }
881
- `
882
- break
883
- }
884
- case 'integer' : {
885
- code += `
886
- ${ statement } (Number.isInteger(${ input } ) || ${ input } === null)
887
- ${ nestedResult }
888
- `
889
- break
890
- }
891
- case 'object' : {
892
- code += `
893
- ${ statement } (typeof ${ input } === "object" || ${ input } === null)
894
- ${ nestedResult }
895
- `
896
- break
897
- }
898
- default : {
899
- code += `
900
- ${ statement } (typeof ${ input } === "${ type } " || ${ input } === null)
901
- ${ nestedResult }
902
- `
903
- break
904
- }
905
- }
906
- } )
907
- code += `
908
- else throw new Error(\`The value $\{JSON.stringify(${ input } )} does not match schema definition.\`)
909
- `
910
+ if ( schema . const !== undefined ) {
911
+ code += buildConstSerializer ( location , input )
912
+ } else if ( Array . isArray ( type ) ) {
913
+ code += buildMultiTypeSerializer ( location , input )
914
+ } else {
915
+ code += buildSingleTypeSerializer ( location , input )
916
+ }
910
917
911
- if ( nullable ) {
912
- code += `
913
- }
914
- `
915
- }
916
- } else {
917
- throw new Error ( `${ type } unsupported` )
918
+ if ( nullable ) {
919
+ code += `
918
920
}
921
+ `
919
922
}
920
923
921
924
return code
0 commit comments