@@ -265,9 +265,6 @@ function build (schema, options) {
265
265
266
266
const serializer = new Serializer ( options )
267
267
268
- /* eslint no-new-func: "off" */
269
- let code = '\'use strict\''
270
-
271
268
let location = {
272
269
schema,
273
270
root : schema ,
@@ -283,50 +280,26 @@ function build (schema, options) {
283
280
schema . type = inferTypeByKeyword ( schema )
284
281
}
285
282
286
- let main
287
-
288
- switch ( schema . type ) {
289
- case 'object' :
290
- main = '$main'
291
- code = buildObject ( location , code , main , main )
292
- break
293
- case 'array' :
294
- main = '$main'
295
- code = buildArray ( location , code , main , main )
296
- schema = location . schema
297
- break
298
- case 'string' :
299
- switch ( schema . format ) {
300
- case 'date-time' : return schema . nullable ? serializer . asDatetimeNullable . bind ( serializer ) : serializer . asDatetime . bind ( serializer )
301
- case 'date' : return schema . nullable ? serializer . asDateNullable . bind ( serializer ) : serializer . asDate . bind ( serializer )
302
- case 'time' : return schema . nullable ? serializer . asTimeNullable . bind ( serializer ) : serializer . asTime . bind ( serializer )
303
- default : return schema . nullable ? serializer . asStringNullable . bind ( serializer ) : serializer . asString . bind ( serializer )
304
- }
305
- case 'integer' :
306
- return schema . nullable ? serializer . asIntegerNullable . bind ( serializer ) : serializer . asInteger . bind ( serializer )
307
- case 'number' :
308
- return schema . nullable ? serializer . asNumberNullable . bind ( serializer ) : serializer . asNumber . bind ( serializer )
309
- case 'boolean' :
310
- return schema . nullable ? serializer . asBooleanNullable . bind ( serializer ) : serializer . asBoolean . bind ( serializer )
311
- case 'null' :
312
- return serializer . asNull . bind ( serializer )
313
- case undefined :
314
- return serializer . asAny . bind ( serializer )
315
- default :
316
- throw new Error ( `${ schema . type } unsupported` )
317
- }
318
-
319
- code += `
320
- return ${ main }
321
- `
283
+ const { code, laterCode } = buildValue ( '' , 'main' , 'input' , location , false )
284
+ const contextFunctionCode = `
285
+ 'use strict'
286
+ function main (input) {
287
+ let json = ''
288
+ ${ code }
289
+ return json
290
+ }
291
+ ${ laterCode }
292
+ return main
293
+ `
322
294
323
- const dependenciesName = [ 'ajv' , 'serializer' , code ]
295
+ const dependenciesName = [ 'ajv' , 'serializer' , contextFunctionCode ]
324
296
325
297
if ( options . debugMode ) {
326
298
return { code : dependenciesName . join ( '\n' ) , ajv : ajvInstance }
327
299
}
328
300
329
- const contextFunc = new Function ( 'ajv' , 'serializer' , code )
301
+ /* eslint no-new-func: "off" */
302
+ const contextFunc = new Function ( 'ajv' , 'serializer' , contextFunctionCode )
330
303
const stringifyFunc = contextFunc ( ajvInstance , serializer )
331
304
332
305
ajvInstance = null
@@ -752,7 +725,7 @@ function buildCode (location, code, laterCode, locationPath) {
752
725
json += ${ asString } + ':'
753
726
`
754
727
755
- const result = nested ( laterCode , locationPath , key , mergeLocation ( propertyLocation , { schema : schema . properties [ key ] } ) , undefined , false )
728
+ const result = buildValue ( laterCode , locationPath + key , `obj[ ${ JSON . stringify ( key ) } ]` , mergeLocation ( propertyLocation , { schema : schema . properties [ key ] } ) , false )
756
729
code += result . code
757
730
laterCode = result . laterCode
758
731
@@ -937,7 +910,7 @@ function buildObject (location, code, functionName, locationPath) {
937
910
return code
938
911
}
939
912
940
- function buildArray ( location , code , functionName , locationPath , key = null ) {
913
+ function buildArray ( location , code , functionName , locationPath , isObjectProperty = false ) {
941
914
let schema = location . schema
942
915
if ( schema . $id !== undefined ) {
943
916
schemaReferenceMap . set ( schema . $id , schema )
@@ -984,7 +957,7 @@ function buildArray (location, code, functionName, locationPath, key = null) {
984
957
const accessor = '[i]'
985
958
if ( Array . isArray ( schema . items ) ) {
986
959
result = schema . items . reduce ( ( res , item , i ) => {
987
- const tmpRes = nested ( laterCode , locationPath , accessor , mergeLocation ( location , { schema : item } ) , i , true )
960
+ const tmpRes = buildValue ( laterCode , locationPath + accessor + i , 'obj[i]' , mergeLocation ( location , { schema : item } ) , true )
988
961
const condition = `i === ${ i } && ${ buildArrayTypeCondition ( item . type , accessor ) } `
989
962
return {
990
963
code : `${ res . code }
@@ -997,7 +970,7 @@ function buildArray (location, code, functionName, locationPath, key = null) {
997
970
} , result )
998
971
999
972
if ( schema . additionalItems ) {
1000
- const tmpRes = nested ( laterCode , locationPath , accessor , mergeLocation ( location , { schema : schema . items } ) , undefined , true )
973
+ const tmpRes = buildValue ( laterCode , locationPath + accessor , 'obj[i]' , mergeLocation ( location , { schema : schema . items } ) , true )
1001
974
result . code += `
1002
975
else if (i >= ${ schema . items . length } ) {
1003
976
${ tmpRes . code }
@@ -1011,13 +984,13 @@ function buildArray (location, code, functionName, locationPath, key = null) {
1011
984
}
1012
985
`
1013
986
} else {
1014
- result = nested ( laterCode , locationPath , accessor , mergeLocation ( location , { schema : schema . items } ) , undefined , true )
987
+ result = buildValue ( laterCode , locationPath + accessor , 'obj[i]' , mergeLocation ( location , { schema : schema . items } ) , true )
1015
988
}
1016
989
1017
- if ( key ) {
990
+ if ( isObjectProperty ) {
1018
991
code += `
1019
992
if(!Array.isArray(obj)) {
1020
- throw new TypeError(\`Property ' ${ key } ' should be of type array, received '$\{obj}' instead .\`)
993
+ throw new TypeError(\`The value '$\{obj }' does not match schema definition .\`)
1021
994
}
1022
995
`
1023
996
}
@@ -1118,9 +1091,7 @@ function generateFuncName () {
1118
1091
return 'anonymous' + genFuncNameCounter ++
1119
1092
}
1120
1093
1121
- function nested ( laterCode , locationPath , key , location , subKey , isArray ) {
1122
- subKey = subKey || ''
1123
-
1094
+ function buildValue ( laterCode , locationPath , input , location , isArray ) {
1124
1095
let schema = location . schema
1125
1096
1126
1097
if ( schema . $ref ) {
@@ -1137,8 +1108,6 @@ function nested (laterCode, locationPath, key, location, subKey, isArray) {
1137
1108
const type = schema . type
1138
1109
const nullable = schema . nullable === true
1139
1110
1140
- const accessor = isArray ? key : `[${ JSON . stringify ( key ) } ]`
1141
-
1142
1111
let code = ''
1143
1112
let funcName
1144
1113
@@ -1150,42 +1119,42 @@ function nested (laterCode, locationPath, key, location, subKey, isArray) {
1150
1119
break
1151
1120
case 'string' : {
1152
1121
funcName = getStringSerializer ( schema . format , nullable )
1153
- code += `json += ${ funcName } (obj ${ accessor } )`
1122
+ code += `json += ${ funcName } (${ input } )`
1154
1123
break
1155
1124
}
1156
1125
case 'integer' :
1157
1126
funcName = nullable ? 'serializer.asIntegerNullable.bind(serializer)' : 'serializer.asInteger.bind(serializer)'
1158
- code += `json += ${ funcName } (obj ${ accessor } )`
1127
+ code += `json += ${ funcName } (${ input } )`
1159
1128
break
1160
1129
case 'number' :
1161
1130
funcName = nullable ? 'serializer.asNumberNullable.bind(serializer)' : 'serializer.asNumber.bind(serializer)'
1162
- code += `json += ${ funcName } (obj ${ accessor } )`
1131
+ code += `json += ${ funcName } (${ input } )`
1163
1132
break
1164
1133
case 'boolean' :
1165
1134
funcName = nullable ? 'serializer.asBooleanNullable.bind(serializer)' : 'serializer.asBoolean.bind(serializer)'
1166
- code += `json += ${ funcName } (obj ${ accessor } )`
1135
+ code += `json += ${ funcName } (${ input } )`
1167
1136
break
1168
1137
case 'object' :
1169
1138
funcName = generateFuncName ( )
1170
- laterCode = buildObject ( location , laterCode , funcName , locationPath + key + subKey )
1171
- code += `json += ${ funcName } (obj ${ accessor } )`
1139
+ laterCode = buildObject ( location , laterCode , funcName , locationPath )
1140
+ code += `json += ${ funcName } (${ input } )`
1172
1141
break
1173
1142
case 'array' :
1174
1143
funcName = generateFuncName ( )
1175
- laterCode = buildArray ( location , laterCode , funcName , locationPath + key + subKey , key )
1176
- code += `json += ${ funcName } (obj ${ accessor } )`
1144
+ laterCode = buildArray ( location , laterCode , funcName , locationPath , true )
1145
+ code += `json += ${ funcName } (${ input } )`
1177
1146
break
1178
1147
case undefined :
1179
1148
if ( schema . anyOf || schema . oneOf ) {
1180
1149
// beware: dereferenceOfRefs has side effects and changes schema.anyOf
1181
1150
const locations = dereferenceOfRefs ( location , schema . anyOf ? 'anyOf' : 'oneOf' )
1182
1151
locations . forEach ( ( location , index ) => {
1183
- const nestedResult = nested ( laterCode , locationPath , key , location , subKey !== '' ? subKey : ' i' + index , isArray )
1152
+ const nestedResult = buildValue ( laterCode , locationPath + ' i' + index , input , location , isArray )
1184
1153
// We need a test serializer as the String serializer will not work with
1185
1154
// date/time ajv validations
1186
1155
// see: https://github.com/fastify/fast-json-stringify/issues/325
1187
1156
const testSerializer = getTestSerializer ( location . schema . format )
1188
- const testValue = testSerializer !== undefined ? `${ testSerializer } (obj ${ accessor } , true)` : `obj ${ accessor } `
1157
+ const testValue = testSerializer !== undefined ? `${ testSerializer } (${ input } , true)` : `${ input } `
1189
1158
1190
1159
// Since we are only passing the relevant schema to ajv.validate, it needs to be full dereferenced
1191
1160
// otherwise any $ref pointing to an external schema would result in an error.
@@ -1210,18 +1179,18 @@ function nested (laterCode, locationPath, key, location, subKey, isArray) {
1210
1179
`
1211
1180
} else if ( isEmpty ( schema ) ) {
1212
1181
code += `
1213
- json += JSON.stringify(obj ${ accessor } )
1182
+ json += JSON.stringify(${ input } )
1214
1183
`
1215
1184
} else if ( 'const' in schema ) {
1216
1185
code += `
1217
- if(ajv.validate(${ JSON . stringify ( schema ) } , obj ${ accessor } ))
1186
+ if(ajv.validate(${ JSON . stringify ( schema ) } , ${ input } ))
1218
1187
json += '${ JSON . stringify ( schema . const ) } '
1219
1188
else
1220
- throw new Error(\`Item $\{JSON.stringify(obj ${ accessor } )} does not match schema definition.\`)
1189
+ throw new Error(\`Item $\{JSON.stringify(${ input } )} does not match schema definition.\`)
1221
1190
`
1222
1191
} else if ( schema . type === undefined ) {
1223
1192
code += `
1224
- json += JSON.stringify(obj ${ accessor } )
1193
+ json += JSON.stringify(${ input } )
1225
1194
`
1226
1195
} else {
1227
1196
throw new Error ( `${ schema . type } unsupported` )
@@ -1234,46 +1203,46 @@ function nested (laterCode, locationPath, key, location, subKey, isArray) {
1234
1203
sortedTypes . forEach ( ( type , index ) => {
1235
1204
const statement = index === 0 ? 'if' : 'else if'
1236
1205
const tempSchema = Object . assign ( { } , schema , { type } )
1237
- const nestedResult = nested ( laterCode , locationPath , key , mergeLocation ( location , { schema : tempSchema } ) , subKey , isArray )
1206
+ const nestedResult = buildValue ( laterCode , locationPath , input , mergeLocation ( location , { schema : tempSchema } ) , isArray )
1238
1207
switch ( type ) {
1239
1208
case 'string' : {
1240
1209
code += `
1241
- ${ statement } (obj ${ accessor } === null || typeof obj ${ accessor } === "${ type } " || obj ${ accessor } instanceof Date || typeof obj ${ accessor } .toISOString === "function" || obj ${ accessor } instanceof RegExp || (typeof obj ${ accessor } === "object" && Object.hasOwnProperty.call(obj ${ accessor } , "toString")))
1210
+ ${ statement } (${ input } === null || typeof ${ input } === "${ type } " || ${ input } instanceof Date || typeof ${ input } .toISOString === "function" || ${ input } instanceof RegExp || (typeof ${ input } === "object" && Object.hasOwnProperty.call(${ input } , "toString")))
1242
1211
${ nestedResult . code }
1243
1212
`
1244
1213
break
1245
1214
}
1246
1215
case 'null' : {
1247
1216
code += `
1248
- ${ statement } (obj ${ accessor } == null)
1217
+ ${ statement } (${ input } == null)
1249
1218
${ nestedResult . code }
1250
1219
`
1251
1220
break
1252
1221
}
1253
1222
case 'array' : {
1254
1223
code += `
1255
- ${ statement } (Array.isArray(obj ${ accessor } ))
1224
+ ${ statement } (Array.isArray(${ input } ))
1256
1225
${ nestedResult . code }
1257
1226
`
1258
1227
break
1259
1228
}
1260
1229
case 'integer' : {
1261
1230
code += `
1262
- ${ statement } (Number.isInteger(obj ${ accessor } ) || obj ${ accessor } === null)
1231
+ ${ statement } (Number.isInteger(${ input } ) || ${ input } === null)
1263
1232
${ nestedResult . code }
1264
1233
`
1265
1234
break
1266
1235
}
1267
1236
case 'number' : {
1268
1237
code += `
1269
- ${ statement } (isNaN(obj ${ accessor } ) === false)
1238
+ ${ statement } (isNaN(${ input } ) === false)
1270
1239
${ nestedResult . code }
1271
1240
`
1272
1241
break
1273
1242
}
1274
1243
default : {
1275
1244
code += `
1276
- ${ statement } (typeof obj ${ accessor } === "${ type } ")
1245
+ ${ statement } (typeof ${ input } === "${ type } ")
1277
1246
${ nestedResult . code }
1278
1247
`
1279
1248
break
0 commit comments