@@ -27,8 +27,6 @@ const validLargeArrayMechanisms = [
2727 'json-stringify'
2828]
2929
30- const addComma = '!addComma && (addComma = true) || (json += \',\')'
31-
3230let schemaIdCounter = 0
3331
3432const mergedSchemaRef = Symbol ( 'fjs-merged-schema-ref' )
@@ -262,7 +260,7 @@ function inferTypeByKeyword (schema) {
262260 return schema . type
263261}
264262
265- function buildExtraObjectPropertiesSerializer ( context , location ) {
263+ function buildExtraObjectPropertiesSerializer ( context , location , addComma ) {
266264 const schema = location . schema
267265 const propertiesKeys = Object . keys ( schema . properties || { } )
268266
@@ -321,88 +319,76 @@ function buildExtraObjectPropertiesSerializer (context, location) {
321319}
322320
323321function buildInnerObject ( context , location ) {
324- let code = ''
325322 const schema = location . schema
326- const required = schema . required || [ ]
327323
328324 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 ] )
329336
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 = ''
343338
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`
352342 }
353343 }
354344
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'
360346
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+ }
365352
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+ }
372358
373- const sanitizedKey = JSON . stringify ( key )
359+ const sanitizedKey = JSON . stringify ( key )
360+ const defaultValue = propertyLocation . schema . default
361+ const isRequired = requiredProperties . includes ( key )
374362
375- if ( requiredWithoutDefault . indexOf ( key ) !== - 1 ) {
376- code += `
363+ code += `
364+ if (obj[ ${ sanitizedKey } ] !== undefined) {
377365 ${ addComma }
378366 json += ${ JSON . stringify ( sanitizedKey + ':' ) }
379367 ${ 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+ }
380375 `
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!')
400379 }
380+ `
381+ } else {
382+ code += '\n'
383+ }
384+
385+ if ( hasRequiredProperties ) {
386+ addComma = 'json += \',\''
401387 }
402388 }
403389
404390 if ( schema . patternProperties || schema . additionalProperties ) {
405- code += buildExtraObjectPropertiesSerializer ( context , location )
391+ code += buildExtraObjectPropertiesSerializer ( context , location , addComma )
406392 }
407393
408394 code += `
0 commit comments