Skip to content

Commit

Permalink
feat(plugins): expose JSON Schema merging mechanism from samples plug…
Browse files Browse the repository at this point in the history
…ins (#9766)

Refs #9765
  • Loading branch information
glowcloud committed Mar 29, 2024
1 parent c0e3eb6 commit 6a493fb
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/core/plugins/json-schema-2020-12-samples/fn/index.js
Expand Up @@ -11,3 +11,4 @@ export {
export { default as encoderAPI } from "./api/encoderAPI"
export { default as formatAPI } from "./api/formatAPI"
export { default as mediaTypeAPI } from "./api/mediaTypeAPI"
export { default as mergeJsonSchema } from "./core/merge"
2 changes: 2 additions & 0 deletions src/core/plugins/json-schema-2020-12-samples/index.js
Expand Up @@ -10,6 +10,7 @@ import {
encoderAPI,
mediaTypeAPI,
formatAPI,
mergeJsonSchema,
} from "./fn/index"
import makeGetJsonSampleSchema from "./fn/get-json-sample-schema"
import makeGetYamlSampleSchema from "./fn/get-yaml-sample-schema"
Expand Down Expand Up @@ -37,6 +38,7 @@ const JSONSchema202012SamplesPlugin = ({ getSystem }) => {
getYamlSampleSchema,
getXmlSampleSchema,
getSampleSchema,
mergeJsonSchema,
},
},
}
Expand Down
56 changes: 29 additions & 27 deletions src/core/plugins/json-schema-5-samples/fn/index.js
Expand Up @@ -56,10 +56,12 @@ const numberContracts = [
]
const stringContracts = ["minLength", "maxLength"]

const liftSampleHelper = (oldSchema, target, config = {}) => {
export const mergeJsonSchema = (target, source, config = {}) => {
const merged = { ...target }

const setIfNotDefinedInTarget = (key) => {
if(target[key] === undefined && oldSchema[key] !== undefined) {
target[key] = oldSchema[key]
if(merged[key] === undefined && source[key] !== undefined) {
merged[key] = source[key]
}
}

Expand All @@ -75,22 +77,22 @@ const liftSampleHelper = (oldSchema, target, config = {}) => {
...stringContracts,
].forEach(key => setIfNotDefinedInTarget(key))

if(oldSchema.required !== undefined && Array.isArray(oldSchema.required)) {
if(target.required === undefined || !target.required.length) {
target.required = []
if(source.required !== undefined && Array.isArray(source.required)) {
if(merged.required === undefined || !merged.required.length) {
merged.required = []
}
oldSchema.required.forEach(key => {
if(target.required.includes(key)) {
source.required.forEach(key => {
if(merged.required.includes(key)) {
return
}
target.required.push(key)
merged.required.push(key)
})
}
if(oldSchema.properties) {
if(!target.properties) {
target.properties = {}
if(source.properties) {
if(!merged.properties) {
merged.properties = {}
}
let props = objectify(oldSchema.properties)
let props = objectify(source.properties)
for (let propName in props) {
if (!Object.prototype.hasOwnProperty.call(props, propName)) {
continue
Expand All @@ -104,26 +106,26 @@ const liftSampleHelper = (oldSchema, target, config = {}) => {
if ( props[propName] && props[propName].writeOnly && !config.includeWriteOnly ) {
continue
}
if(!target.properties[propName]) {
target.properties[propName] = props[propName]
if(!oldSchema.required && Array.isArray(oldSchema.required) && oldSchema.required.indexOf(propName) !== -1) {
if(!target.required) {
target.required = [propName]
if(!merged.properties[propName]) {
merged.properties[propName] = props[propName]
if(!source.required && Array.isArray(source.required) && source.required.indexOf(propName) !== -1) {
if(!merged.required) {
merged.required = [propName]
} else {
target.required.push(propName)
merged.required.push(propName)
}
}
}
}
}
if(oldSchema.items) {
if(!target.items) {
target.items = {}
if(source.items) {
if(!merged.items) {
merged.items = {}
}
target.items = liftSampleHelper(oldSchema.items, target.items, config)
merged.items = mergeJsonSchema(merged.items, source.items, config)
}

return target
return merged
}

export const sampleFromSchemaGeneric = (schema, config={}, exampleOverride = undefined, respectXML = false) => {
Expand All @@ -138,7 +140,7 @@ export const sampleFromSchemaGeneric = (schema, config={}, exampleOverride = und
? schema.oneOf[0]
: schema.anyOf[0]
)
liftSampleHelper(schemaToAdd, schema, config)
schema = mergeJsonSchema(schema, schemaToAdd, config)
if(!schema.xml && schemaToAdd.xml) {
schema.xml = schemaToAdd.xml
}
Expand Down Expand Up @@ -537,9 +539,9 @@ export const sampleFromSchemaGeneric = (schema, config={}, exampleOverride = und
}

if(Array.isArray(items.anyOf)) {
sampleArray = items.anyOf.map(i => sampleFromSchemaGeneric(liftSampleHelper(items, i, config), config, undefined, respectXML))
sampleArray = items.anyOf.map(i => sampleFromSchemaGeneric(mergeJsonSchema(i, items, config), config, undefined, respectXML))
} else if(Array.isArray(items.oneOf)) {
sampleArray = items.oneOf.map(i => sampleFromSchemaGeneric(liftSampleHelper(items, i, config), config, undefined, respectXML))
sampleArray = items.oneOf.map(i => sampleFromSchemaGeneric(mergeJsonSchema(i, items, config), config, undefined, respectXML))
} else if(!respectXML || respectXML && xml.wrapped) {
sampleArray = [sampleFromSchemaGeneric(items, config, undefined, respectXML)]
} else {
Expand Down
3 changes: 3 additions & 0 deletions src/core/plugins/json-schema-5-samples/index.js
Expand Up @@ -8,6 +8,7 @@ import {
createXMLExample,
memoizedCreateXMLExample,
memoizedSampleFromSchema,
mergeJsonSchema,
} from "./fn/index"
import makeGetJsonSampleSchema from "./fn/get-json-sample-schema"
import makeGetYamlSampleSchema from "./fn/get-yaml-sample-schema"
Expand All @@ -33,6 +34,7 @@ const JSONSchema5SamplesPlugin = ({ getSystem }) => {
getYamlSampleSchema,
getXmlSampleSchema,
getSampleSchema,
mergeJsonSchema,
},
inferSchema,
sampleFromSchema,
Expand All @@ -44,6 +46,7 @@ const JSONSchema5SamplesPlugin = ({ getSystem }) => {
getYamlSampleSchema,
getXmlSampleSchema,
getSampleSchema,
mergeJsonSchema,
},
}
}
Expand Down
1 change: 1 addition & 0 deletions src/core/plugins/oas31/after-load.js
Expand Up @@ -31,6 +31,7 @@ function afterLoad({ fn, getSystem }) {
getYamlSampleSchema: fn.jsonSchema202012.getYamlSampleSchema,
getXmlSampleSchema: fn.jsonSchema202012.getXmlSampleSchema,
getSampleSchema: fn.jsonSchema202012.getSampleSchema,
mergeJsonSchema: fn.jsonSchema202012.mergeJsonSchema,
},
getSystem()
)
Expand Down
53 changes: 53 additions & 0 deletions test/unit/core/plugins/json-schema-2020-12-samples/fn.js
Expand Up @@ -8,6 +8,7 @@ import {
sampleFromSchema,
memoizedCreateXMLExample,
memoizedSampleFromSchema,
mergeJsonSchema,
} from "core/plugins/json-schema-2020-12-samples/fn"

describe("sampleFromSchema", () => {
Expand Down Expand Up @@ -2983,3 +2984,55 @@ describe("memoizedCreateXMLExample", () => {
).toEqual(updatedExpected)
})
})

describe("merge", function () {
it("should merge two schemas", function () {
const schema = {
properties: {
name: {
type: "string",
},
id: {
type: "integer",
},
},
example: {
name: "test",
id: 1,
},
required: ["name"],
}

const target = {
type: "object",
properties: {
username: {
type: "string",
},
},
required: ["username"],
}

const result = mergeJsonSchema(target, schema)

expect(result).toStrictEqual({
type: "object",
properties: {
username: {
type: "string",
},
name: {
type: "string",
},
id: {
type: "integer",
},
},
example: {
name: "test",
id: 1,
},
required: ["username", "name"],
})
})
})
60 changes: 59 additions & 1 deletion test/unit/core/plugins/json-schema-5-samples/fn/index.js
@@ -1,5 +1,11 @@
import { fromJS } from "immutable"
import { createXMLExample, sampleFromSchema, memoizedCreateXMLExample, memoizedSampleFromSchema } from "core/plugins/json-schema-5-samples/fn/index"
import {
createXMLExample,
sampleFromSchema,
memoizedCreateXMLExample,
memoizedSampleFromSchema,
mergeJsonSchema,
} from "core/plugins/json-schema-5-samples/fn/index"

describe("sampleFromSchema", () => {
it("handles Immutable.js objects for nested schemas", function () {
Expand Down Expand Up @@ -2438,3 +2444,55 @@ describe("memoizedCreateXMLExample", () => {
expect(memoizedCreateXMLExample(definition, {}, updatedOverrideExample)).toEqual(updatedExpected)
})
})

describe("mergeJsonSchema", function () {
it("should merge two schemas", function () {
const schema = {
properties: {
name: {
type: "string",
},
id: {
type: "integer",
},
},
example: {
name: "test",
id: 1,
},
required: ["name"],
}

const target = {
type: "object",
properties: {
username: {
type: "string",
},
},
required: ["username"],
}

const result = mergeJsonSchema(target, schema)

expect(result).toStrictEqual({
type: "object",
properties: {
username: {
type: "string",
},
name: {
type: "string",
},
id: {
type: "integer",
},
},
example: {
name: "test",
id: 1,
},
required: ["username", "name"],
})
})
})

0 comments on commit 6a493fb

Please sign in to comment.