Skip to content

Commit 260edc7

Browse files
fix: serializing schema with allOf option (#453)
1 parent fdb820d commit 260edc7

File tree

2 files changed

+150
-20
lines changed

2 files changed

+150
-20
lines changed

index.js

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -676,35 +676,102 @@ function buildCode (location, code, laterCode, locationPath) {
676676
code += `if (obj['${requiredProperty}'] === undefined) throw new Error('"${requiredProperty}" is required!')\n`
677677
}
678678

679-
if (schema.allOf) {
680-
const builtCode = buildCodeWithAllOfs(location, code, laterCode, locationPath)
681-
code = builtCode.code
682-
laterCode = builtCode.laterCode
683-
}
684-
685679
return { code, laterCode }
686680
}
687681

688-
function buildCodeWithAllOfs (location, code, laterCode, locationPath) {
689-
if (location.schema.allOf) {
690-
location.schema.allOf.forEach((ss) => {
691-
const builtCode = buildCodeWithAllOfs(mergeLocation(location, { schema: ss }), code, laterCode, locationPath)
692-
code = builtCode.code
693-
laterCode = builtCode.laterCode
694-
})
695-
} else {
696-
const builtCode = buildCode(location, code, laterCode, locationPath)
682+
function mergeAllOfSchema (location, schema, mergedSchema) {
683+
for (let allOfSchema of schema.allOf) {
684+
if (allOfSchema.$ref) {
685+
allOfSchema = refFinder(allOfSchema.$ref, mergeLocation(location, { schema: allOfSchema })).schema
686+
}
697687

698-
code = builtCode.code
699-
laterCode = builtCode.laterCode
700-
}
688+
let allOfSchemaType = allOfSchema.type
689+
if (allOfSchemaType === undefined) {
690+
allOfSchemaType = inferTypeByKeyword(allOfSchema)
691+
}
701692

702-
return { code, laterCode }
693+
if (allOfSchemaType !== undefined) {
694+
if (
695+
mergedSchema.type !== undefined &&
696+
mergedSchema.type !== allOfSchemaType
697+
) {
698+
throw new Error('allOf schemas have different type values')
699+
}
700+
mergedSchema.type = allOfSchemaType
701+
}
702+
703+
if (allOfSchema.format !== undefined) {
704+
if (
705+
mergedSchema.format !== undefined &&
706+
mergedSchema.format !== allOfSchema.format
707+
) {
708+
throw new Error('allOf schemas have different format values')
709+
}
710+
mergedSchema.format = allOfSchema.format
711+
}
712+
713+
if (allOfSchema.nullable !== undefined) {
714+
if (
715+
mergedSchema.nullable !== undefined &&
716+
mergedSchema.nullable !== allOfSchema.nullable
717+
) {
718+
throw new Error('allOf schemas have different nullable values')
719+
}
720+
mergedSchema.nullable = allOfSchema.nullable
721+
}
722+
723+
if (allOfSchema.properties !== undefined) {
724+
if (mergedSchema.properties === undefined) {
725+
mergedSchema.properties = {}
726+
}
727+
Object.assign(mergedSchema.properties, allOfSchema.properties)
728+
}
729+
730+
if (allOfSchema.additionalProperties !== undefined) {
731+
if (mergedSchema.additionalProperties === undefined) {
732+
mergedSchema.additionalProperties = {}
733+
}
734+
Object.assign(mergedSchema.additionalProperties, allOfSchema.additionalProperties)
735+
}
736+
737+
if (allOfSchema.patternProperties !== undefined) {
738+
if (mergedSchema.patternProperties === undefined) {
739+
mergedSchema.patternProperties = {}
740+
}
741+
Object.assign(mergedSchema.patternProperties, allOfSchema.patternProperties)
742+
}
743+
744+
if (allOfSchema.required !== undefined) {
745+
if (mergedSchema.required === undefined) {
746+
mergedSchema.required = []
747+
}
748+
mergedSchema.required.push(...allOfSchema.required)
749+
}
750+
751+
if (allOfSchema.oneOf !== undefined) {
752+
if (mergedSchema.oneOf === undefined) {
753+
mergedSchema.oneOf = []
754+
}
755+
mergedSchema.oneOf.push(...allOfSchema.oneOf)
756+
}
757+
758+
if (allOfSchema.anyOf !== undefined) {
759+
if (mergedSchema.anyOf === undefined) {
760+
mergedSchema.anyOf = []
761+
}
762+
mergedSchema.anyOf.push(...allOfSchema.anyOf)
763+
}
764+
765+
if (allOfSchema.allOf !== undefined) {
766+
mergeAllOfSchema(location, allOfSchema, mergedSchema)
767+
}
768+
}
769+
delete mergedSchema.allOf
703770
}
704771

705772
function buildInnerObject (location, locationPath) {
706773
const schema = location.schema
707-
const result = buildCodeWithAllOfs(location, '', '', locationPath)
774+
const result = buildCode(location, '', '', locationPath)
708775
if (schema.patternProperties) {
709776
const { code, laterCode } = addPatternProperties(location)
710777
result.code += code
@@ -1030,6 +1097,13 @@ function buildValue (laterCode, locationPath, input, location) {
10301097
}
10311098
}
10321099

1100+
if (schema.allOf) {
1101+
const mergedSchema = clone(schema)
1102+
mergeAllOfSchema(location, schema, mergedSchema)
1103+
schema = mergedSchema
1104+
location.schema = mergedSchema
1105+
}
1106+
10331107
const type = schema.type
10341108
const nullable = schema.nullable === true
10351109

test/allof.test.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,64 @@
11
'use strict'
22

33
const test = require('tap').test
4+
const { DateTime } = require('luxon')
45
const build = require('..')
56

7+
test('allOf: combine type and format ', (t) => {
8+
t.plan(1)
9+
10+
const schema = {
11+
allOf: [
12+
{ type: 'string' },
13+
{ format: 'time' }
14+
]
15+
}
16+
const stringify = build(schema)
17+
const date = new Date()
18+
const value = stringify(date)
19+
t.equal(value, `"${DateTime.fromJSDate(date).toFormat('HH:mm:ss')}"`)
20+
})
21+
22+
test('allOf: combine additional properties ', (t) => {
23+
t.plan(1)
24+
25+
const schema = {
26+
allOf: [
27+
{ type: 'object' },
28+
{
29+
type: 'object',
30+
additionalProperties: { type: 'boolean' }
31+
}
32+
]
33+
}
34+
const stringify = build(schema)
35+
const data = { property: true }
36+
const value = stringify(data)
37+
t.equal(value, JSON.stringify(data))
38+
})
39+
40+
test('allOf: combine pattern properties', (t) => {
41+
t.plan(1)
42+
43+
const schema = {
44+
allOf: [
45+
{ type: 'object' },
46+
{
47+
type: 'object',
48+
patternProperties: {
49+
foo: {
50+
type: 'number'
51+
}
52+
}
53+
}
54+
]
55+
}
56+
const stringify = build(schema)
57+
const data = { foo: 42 }
58+
const value = stringify(data)
59+
t.equal(value, JSON.stringify(data))
60+
})
61+
662
test('object with allOf and multiple schema on the allOf', (t) => {
763
t.plan(4)
864

0 commit comments

Comments
 (0)