feat(samples): add support for uniqueItems keyword (#8893)
This change is specific to JSON Schema 2020-12 and OpenAPI 3.1.0. Refs #8577
This commit is contained in:
@@ -72,6 +72,31 @@ const isURI = (uri) => {
|
||||
}
|
||||
}
|
||||
|
||||
const applyArrayConstraints = (array, constraints = {}) => {
|
||||
const { minItems, maxItems, uniqueItems } = constraints
|
||||
let constrainedArray = [...array]
|
||||
|
||||
if (Number.isInteger(maxItems) && maxItems > 0) {
|
||||
constrainedArray = array.slice(0, maxItems)
|
||||
}
|
||||
if (Number.isInteger(minItems) && minItems > 0) {
|
||||
for (let i = 0; constrainedArray.length < minItems; i += 1) {
|
||||
constrainedArray.push(constrainedArray[i % constrainedArray.length])
|
||||
}
|
||||
}
|
||||
/**
|
||||
* If uniqueItems is true, it implies that every item in the array must be unique.
|
||||
* This overrides any minItems constraint that cannot be satisfied with unique items.
|
||||
* So if minItems is greater than the number of unique items,
|
||||
* it should be reduced to the number of unique items.
|
||||
*/
|
||||
if (uniqueItems === true) {
|
||||
constrainedArray = Array.from(new Set(constrainedArray))
|
||||
}
|
||||
|
||||
return constrainedArray
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a couple of quick sanity tests to ensure the value
|
||||
* looks like a $$ref that swagger-client generates.
|
||||
@@ -80,7 +105,7 @@ const sanitizeRef = (value) =>
|
||||
deeplyStripKey(value, "$$ref", (val) => typeof val === "string" && isURI(val))
|
||||
|
||||
const objectContracts = ["maxProperties", "minProperties"]
|
||||
const arrayContracts = ["minItems", "maxItems"]
|
||||
const arrayConstraints = ["minItems", "maxItems", "uniqueItems"]
|
||||
const numberConstraints = [
|
||||
"minimum",
|
||||
"maximum",
|
||||
@@ -105,7 +130,7 @@ const liftSampleHelper = (oldSchema, target, config = {}) => {
|
||||
"type",
|
||||
"const",
|
||||
...objectContracts,
|
||||
...arrayContracts,
|
||||
...arrayConstraints,
|
||||
...numberConstraints,
|
||||
...stringConstraints,
|
||||
].forEach((key) => setIfNotDefinedInTarget(key))
|
||||
@@ -271,7 +296,7 @@ export const sampleFromSchemaGeneric = (
|
||||
if (schema && typeof type !== "string" && !Array.isArray(type)) {
|
||||
if (properties || additionalProperties || schemaHasAny(objectContracts)) {
|
||||
type = "object"
|
||||
} else if (items || schemaHasAny(arrayContracts)) {
|
||||
} else if (items || schemaHasAny(arrayConstraints)) {
|
||||
type = "array"
|
||||
} else if (schemaHasAny(numberConstraints)) {
|
||||
type = "number"
|
||||
@@ -296,19 +321,6 @@ export const sampleFromSchemaGeneric = (
|
||||
}
|
||||
}
|
||||
|
||||
const handleMinMaxItems = (sampleArray) => {
|
||||
if (schema?.maxItems !== null && schema?.maxItems !== undefined) {
|
||||
sampleArray = sampleArray.slice(0, schema?.maxItems)
|
||||
}
|
||||
if (schema?.minItems !== null && schema?.minItems !== undefined) {
|
||||
let i = 0
|
||||
while (sampleArray.length < schema?.minItems) {
|
||||
sampleArray.push(sampleArray[i++ % sampleArray.length])
|
||||
}
|
||||
}
|
||||
return sampleArray
|
||||
}
|
||||
|
||||
// add to result helper init for xml or json
|
||||
const props = objectify(properties)
|
||||
let addPropertyToResult
|
||||
@@ -505,7 +517,7 @@ export const sampleFromSchemaGeneric = (
|
||||
let itemSamples = sample.map((s) =>
|
||||
sampleFromSchemaGeneric(itemSchema, config, s, respectXML)
|
||||
)
|
||||
itemSamples = handleMinMaxItems(itemSamples)
|
||||
itemSamples = applyArrayConstraints(itemSamples, schema)
|
||||
if (xml.wrapped) {
|
||||
res[displayName] = itemSamples
|
||||
if (!isEmpty(_attr)) {
|
||||
@@ -602,7 +614,7 @@ export const sampleFromSchemaGeneric = (
|
||||
} else {
|
||||
return sampleFromSchemaGeneric(items, config, undefined, respectXML)
|
||||
}
|
||||
sampleArray = handleMinMaxItems(sampleArray)
|
||||
sampleArray = applyArrayConstraints(sampleArray, schema)
|
||||
if (respectXML && xml.wrapped) {
|
||||
res[displayName] = sampleArray
|
||||
if (!isEmpty(_attr)) {
|
||||
|
||||
@@ -1233,6 +1233,37 @@ describe("sampleFromSchema", () => {
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
it("should handle maxItems", () => {
|
||||
const definition = {
|
||||
type: "array",
|
||||
minItems: 4,
|
||||
maxItems: 7,
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
}
|
||||
|
||||
const expected = sampleFromSchema(definition).length
|
||||
|
||||
expect(expected).toBeGreaterThanOrEqual(4)
|
||||
expect(expected).toBeLessThanOrEqual(7)
|
||||
})
|
||||
|
||||
it("should handle uniqueItems", () => {
|
||||
const definition = {
|
||||
type: "array",
|
||||
minItems: 2,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
}
|
||||
|
||||
const expected = ["string"]
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
it("should handle minItems with example", () => {
|
||||
const definition = {
|
||||
type: "array",
|
||||
|
||||
Reference in New Issue
Block a user