diff --git a/index.js b/index.js index 34d44cda..9a0ba030 100644 --- a/index.js +++ b/index.js @@ -47,7 +47,10 @@ function mergeLocation (source, dest) { } } +const referenceSerializersMap = new Map() + function build (schema, options) { + referenceSerializersMap.clear() options = options || {} isValidSchema(schema) if (options.schema) { @@ -144,6 +147,8 @@ function build (schema, options) { return dependenciesName } + referenceSerializersMap.clear() + return (Function.apply(null, dependenciesName).apply(null, dependencies)) } @@ -969,8 +974,18 @@ function buildArray (location, code, name, key = null) { schema = location.schema schema[fjsCloned] = true } + location = refFinder(schema.items.$ref, location) schema.items = location.schema + + if (referenceSerializersMap.has(schema.items)) { + code += ` + return ${referenceSerializersMap.get(schema.items)}(obj) + } + ` + return code + } + referenceSerializersMap.set(schema.items, name) } let result = { code: '', laterCode: '' } diff --git a/test/recursion.test.js b/test/recursion.test.js new file mode 100644 index 00000000..f89dd365 --- /dev/null +++ b/test/recursion.test.js @@ -0,0 +1,137 @@ +'use strict' + +const test = require('tap').test +const build = require('..') + +test('can stringify recursive directory tree (issue #181)', (t) => { + t.plan(1) + + const schema = { + definitions: { + directory: { + type: 'object', + properties: { + name: { type: 'string' }, + subDirectories: { + type: 'array', + items: { $ref: '#/definitions/directory' }, + default: [] + } + } + } + }, + type: 'array', + items: { $ref: '#/definitions/directory' } + } + const stringify = build(schema) + + t.equal(stringify([ + { name: 'directory 1', subDirectories: [] }, + { + name: 'directory 2', + subDirectories: [ + { name: 'directory 2.1', subDirectories: [] }, + { name: 'directory 2.2', subDirectories: [] } + ] + } + ]), '[{"name":"directory 1","subDirectories":[]},{"name":"directory 2","subDirectories":[{"name":"directory 2.1","subDirectories":[]},{"name":"directory 2.2","subDirectories":[]}]}]') +}) + +test('can stringify when recursion in external schema', t => { + t.plan(1) + + const referenceSchema = { + $id: 'person', + type: 'object', + properties: { + name: { type: 'string' }, + children: { + type: 'array', + items: { $ref: '#' } + } + } + } + + const schema = { + $id: 'mainSchema', + type: 'object', + properties: { + people: { + $ref: 'person' + } + } + } + const stringify = build(schema, { + schema: { + [referenceSchema.$id]: referenceSchema + } + }) + + const value = stringify({ people: { name: 'Elizabeth', children: [{ name: 'Charles' }] } }) + t.equal(value, '{"people":{"name":"Elizabeth","children":[{"name":"Charles"}]}}') +}) + +test('use proper serialize function', t => { + t.plan(1) + + const personSchema = { + $id: 'person', + type: 'object', + properties: { + name: { type: 'string' }, + children: { + type: 'array', + items: { $ref: '#' } + } + } + } + + const directorySchema = { + $id: 'directory', + type: 'object', + properties: { + name: { type: 'string' }, + subDirectories: { + type: 'array', + items: { $ref: '#' }, + default: [] + } + } + } + + const schema = { + $id: 'mainSchema', + type: 'object', + properties: { + people: { $ref: 'person' }, + directory: { $ref: 'directory' } + } + } + const stringify = build(schema, { + schema: { + [personSchema.$id]: personSchema, + [directorySchema.$id]: directorySchema + } + }) + + const value = stringify({ + 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' }, { name: 'directory 1.2.2' }] + } + ] + } + }) + 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":[]}]}]}}') +})