@@ -27,8 +27,6 @@ const validLargeArrayMechanisms = [
27
27
'json-stringify'
28
28
]
29
29
30
- const addComma = '!addComma && (addComma = true) || (json += \',\')'
31
-
32
30
let schemaIdCounter = 0
33
31
34
32
const mergedSchemaRef = Symbol ( 'fjs-merged-schema-ref' )
@@ -262,7 +260,7 @@ function inferTypeByKeyword (schema) {
262
260
return schema . type
263
261
}
264
262
265
- function buildExtraObjectPropertiesSerializer ( context , location ) {
263
+ function buildExtraObjectPropertiesSerializer ( context , location , addComma ) {
266
264
const schema = location . schema
267
265
const propertiesKeys = Object . keys ( schema . properties || { } )
268
266
@@ -321,88 +319,76 @@ function buildExtraObjectPropertiesSerializer (context, location) {
321
319
}
322
320
323
321
function buildInnerObject ( context , location ) {
324
- let code = ''
325
322
const schema = location . schema
326
- const required = schema . required || [ ]
327
323
328
324
const propertiesLocation = location . getPropertyLocation ( 'properties' )
325
+ const requiredProperties = schema . required || [ ]
326
+
327
+ // Should serialize required properties first
328
+ const propertiesKeys = Object . keys ( schema . properties || { } ) . sort (
329
+ ( key1 , key2 ) => {
330
+ const required1 = requiredProperties . includes ( key1 )
331
+ const required2 = requiredProperties . includes ( key2 )
332
+ return required1 === required2 ? 0 : required1 ? - 1 : 1
333
+ }
334
+ )
335
+ const hasRequiredProperties = requiredProperties . includes ( propertiesKeys [ 0 ] )
329
336
330
- const requiredWithDefault = [ ]
331
- const requiredWithoutDefault = [ ]
332
- if ( schema . properties ) {
333
- for ( const key of Object . keys ( schema . properties ) ) {
334
- if ( required . indexOf ( key ) === - 1 ) {
335
- continue
336
- }
337
- let propertyLocation = propertiesLocation . getPropertyLocation ( key )
338
- if ( propertyLocation . schema . $ref ) {
339
- propertyLocation = resolveRef ( context , propertyLocation )
340
- }
341
-
342
- const sanitizedKey = JSON . stringify ( key )
337
+ let code = ''
343
338
344
- // Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
345
- // see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
346
- const defaultValue = propertyLocation . schema . default
347
- if ( defaultValue === undefined ) {
348
- code += `if (obj[${ sanitizedKey } ] === undefined) throw new Error('${ sanitizedKey } is required!')\n`
349
- requiredWithoutDefault . push ( key )
350
- }
351
- requiredWithDefault . push ( key )
339
+ for ( const key of requiredProperties ) {
340
+ if ( ! propertiesKeys . includes ( key ) ) {
341
+ code += `if (obj['${ key } '] === undefined) throw new Error('"${ key } " is required!')\n`
352
342
}
353
343
}
354
344
355
- // handle extraneous required fields
356
- for ( const requiredProperty of required ) {
357
- if ( requiredWithDefault . indexOf ( requiredProperty ) !== - 1 ) continue
358
- code += `if (obj['${ requiredProperty } '] === undefined) throw new Error('"${ requiredProperty } " is required!')\n`
359
- }
345
+ code += 'let json = \'{\'\n'
360
346
361
- code += `
362
- let addComma = false
363
- let json = '{'
364
- `
347
+ let addComma = ''
348
+ if ( ! hasRequiredProperties ) {
349
+ code += 'let addComma = false\n'
350
+ addComma = '!addComma && (addComma = true) || (json += \',\')'
351
+ }
365
352
366
- if ( schema . properties ) {
367
- for ( const key of Object . keys ( schema . properties ) ) {
368
- let propertyLocation = propertiesLocation . getPropertyLocation ( key )
369
- if ( propertyLocation . schema . $ref ) {
370
- propertyLocation = resolveRef ( context , propertyLocation )
371
- }
353
+ for ( const key of propertiesKeys ) {
354
+ let propertyLocation = propertiesLocation . getPropertyLocation ( key )
355
+ if ( propertyLocation . schema . $ref ) {
356
+ propertyLocation = resolveRef ( context , propertyLocation )
357
+ }
372
358
373
- const sanitizedKey = JSON . stringify ( key )
359
+ const sanitizedKey = JSON . stringify ( key )
360
+ const defaultValue = propertyLocation . schema . default
361
+ const isRequired = requiredProperties . includes ( key )
374
362
375
- if ( requiredWithoutDefault . indexOf ( key ) !== - 1 ) {
376
- code += `
363
+ code += `
364
+ if (obj[ ${ sanitizedKey } ] !== undefined) {
377
365
${ addComma }
378
366
json += ${ JSON . stringify ( sanitizedKey + ':' ) }
379
367
${ buildValue ( context , propertyLocation , `obj[${ sanitizedKey } ]` ) }
368
+ }`
369
+
370
+ if ( defaultValue !== undefined ) {
371
+ code += ` else {
372
+ ${ addComma }
373
+ json += ${ JSON . stringify ( sanitizedKey + ':' + JSON . stringify ( defaultValue ) ) }
374
+ }
380
375
`
381
- } else {
382
- // Using obj['key'] !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
383
- // see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
384
- code += `
385
- if (obj[${ sanitizedKey } ] !== undefined) {
386
- ${ addComma }
387
- json += ${ JSON . stringify ( sanitizedKey + ':' ) }
388
- ${ buildValue ( context , propertyLocation , `obj[${ sanitizedKey } ]` ) }
389
- }
390
- `
391
- const defaultValue = propertyLocation . schema . default
392
- if ( defaultValue !== undefined ) {
393
- code += `
394
- else {
395
- ${ addComma }
396
- json += ${ JSON . stringify ( sanitizedKey + ':' + JSON . stringify ( defaultValue ) ) }
397
- }
398
- `
399
- }
376
+ } else if ( isRequired ) {
377
+ code += ` else {
378
+ throw new Error('${ sanitizedKey } is required!')
400
379
}
380
+ `
381
+ } else {
382
+ code += '\n'
383
+ }
384
+
385
+ if ( hasRequiredProperties ) {
386
+ addComma = 'json += \',\''
401
387
}
402
388
}
403
389
404
390
if ( schema . patternProperties || schema . additionalProperties ) {
405
- code += buildExtraObjectPropertiesSerializer ( context , location )
391
+ code += buildExtraObjectPropertiesSerializer ( context , location , addComma )
406
392
}
407
393
408
394
code += `
0 commit comments