Skip to content

Commit c9e363e

Browse files
Add support for recursive references in object types (#366)
1 parent 8ca3081 commit c9e363e

File tree

2 files changed

+74
-9
lines changed

2 files changed

+74
-9
lines changed

index.js

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ function mergeLocation (source, dest) {
4747
}
4848
}
4949

50-
const referenceSerializersMap = new Map()
50+
const arrayItemsReferenceSerializersMap = new Map()
51+
const objectReferenceSerializersMap = new Map()
5152

5253
function build (schema, options) {
53-
referenceSerializersMap.clear()
54+
arrayItemsReferenceSerializersMap.clear()
55+
objectReferenceSerializersMap.clear()
5456
options = options || {}
5557
isValidSchema(schema)
5658
if (options.schema) {
@@ -147,7 +149,8 @@ function build (schema, options) {
147149
return dependenciesName
148150
}
149151

150-
referenceSerializersMap.clear()
152+
arrayItemsReferenceSerializersMap.clear()
153+
objectReferenceSerializersMap.clear()
151154

152155
return (Function.apply(null, dependenciesName).apply(null, dependencies))
153156
}
@@ -399,51 +402,60 @@ function addPatternProperties (location) {
399402
} catch (err) {
400403
throw new Error(`${err.message}. Found at ${regex} matching ${JSON.stringify(pp[regex])}`)
401404
}
402-
code += `
403-
if (/${regex.replace(/\\*\//g, '\\/')}/.test(keys[i])) {
404-
`
405+
406+
const ifPpKeyExists = `if (/${regex.replace(/\\*\//g, '\\/')}/.test(keys[i])) {`
407+
405408
if (type === 'object') {
406409
code += `${buildObject(ppLocation, '', 'buildObjectPP' + index)}
410+
${ifPpKeyExists}
407411
${addComma}
408412
json += $asString(keys[i]) + ':' + buildObjectPP${index}(obj[keys[i]])
409413
`
410414
} else if (type === 'array') {
411415
code += `${buildArray(ppLocation, '', 'buildArrayPP' + index)}
416+
${ifPpKeyExists}
412417
${addComma}
413418
json += $asString(keys[i]) + ':' + buildArrayPP${index}(obj[keys[i]])
414419
`
415420
} else if (type === 'null') {
416421
code += `
422+
${ifPpKeyExists}
417423
${addComma}
418424
json += $asString(keys[i]) +':null'
419425
`
420426
} else if (type === 'string') {
421427
code += `
428+
${ifPpKeyExists}
422429
${addComma}
423430
json += $asString(keys[i]) + ':' + ${stringSerializer}(obj[keys[i]])
424431
`
425432
} else if (type === 'integer') {
426433
code += `
434+
${ifPpKeyExists}
427435
${addComma}
428436
json += $asString(keys[i]) + ':' + $asInteger(obj[keys[i]])
429437
`
430438
} else if (type === 'number') {
431439
code += `
440+
${ifPpKeyExists}
432441
${addComma}
433442
json += $asString(keys[i]) + ':' + $asNumber(obj[keys[i]])
434443
`
435444
} else if (type === 'boolean') {
436445
code += `
446+
${ifPpKeyExists}
437447
${addComma}
438448
json += $asString(keys[i]) + ':' + $asBoolean(obj[keys[i]])
439449
`
440450
} else if (type === undefined) {
441451
code += `
452+
${ifPpKeyExists}
442453
${addComma}
443454
json += $asString(keys[i]) + ':' + $asAny(obj[keys[i]])
444455
`
445456
} else {
446457
code += `
458+
${ifPpKeyExists}
447459
throw new Error('Cannot coerce ' + obj[keys[i]] + ' to ' + ${JSON.stringify(type)})
448460
`
449461
}
@@ -922,6 +934,16 @@ function buildObject (location, code, name) {
922934
}
923935
`
924936
}
937+
938+
if (objectReferenceSerializersMap.has(schema)) {
939+
code += `
940+
return ${objectReferenceSerializersMap.get(schema)}(input)
941+
}
942+
`
943+
return code
944+
}
945+
objectReferenceSerializersMap.set(schema, name)
946+
925947
code += `
926948
var obj = ${toJSON('input')}
927949
var json = '{'
@@ -978,14 +1000,14 @@ function buildArray (location, code, name, key = null) {
9781000
location = refFinder(schema.items.$ref, location)
9791001
schema.items = location.schema
9801002

981-
if (referenceSerializersMap.has(schema.items)) {
1003+
if (arrayItemsReferenceSerializersMap.has(schema.items)) {
9821004
code += `
983-
return ${referenceSerializersMap.get(schema.items)}(obj)
1005+
return ${arrayItemsReferenceSerializersMap.get(schema.items)}(obj)
9841006
}
9851007
`
9861008
return code
9871009
}
988-
referenceSerializersMap.set(schema.items, name)
1010+
arrayItemsReferenceSerializersMap.set(schema.items, name)
9891011
}
9901012

9911013
let result = { code: '', laterCode: '' }

test/recursion.test.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,46 @@ test('use proper serialize function', t => {
135135
})
136136
t.equal(value, '{"people":{"name":"Elizabeth","children":[{"name":"Charles","children":[{"name":"William","children":[{"name":"George"},{"name":"Charlotte"}]},{"name":"Harry"}]}]},"directory":{"name":"directory 1","subDirectories":[{"name":"directory 1.1","subDirectories":[]},{"name":"directory 1.2","subDirectories":[{"name":"directory 1.2.1","subDirectories":[]},{"name":"directory 1.2.2","subDirectories":[]}]}]}}')
137137
})
138+
139+
test('can stringify recursive references in object types (issue #365)', t => {
140+
t.plan(1)
141+
142+
const schema = {
143+
type: 'object',
144+
definitions: {
145+
parentCategory: {
146+
type: 'object',
147+
properties: {
148+
parent: {
149+
$ref: '#/definitions/parentCategory'
150+
}
151+
}
152+
}
153+
},
154+
properties: {
155+
category: {
156+
type: 'object',
157+
properties: {
158+
parent: {
159+
$ref: '#/definitions/parentCategory'
160+
}
161+
}
162+
}
163+
}
164+
}
165+
166+
const stringify = build(schema)
167+
const data = {
168+
category: {
169+
parent: {
170+
parent: {
171+
parent: {
172+
parent: {}
173+
}
174+
}
175+
}
176+
}
177+
}
178+
const value = stringify(data)
179+
t.equal(value, '{"category":{"parent":{"parent":{"parent":{"parent":{}}}}}}')
180+
})

0 commit comments

Comments
 (0)