mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-21 01:53:26 +00:00
Merge simple alternatives (#3165)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/react-openapi": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Merge simple alternatives
|
||||||
@@ -35,6 +35,86 @@ describe('getSchemaAlternatives', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('merges string enum', () => {
|
||||||
|
expect(
|
||||||
|
getSchemaAlternatives({
|
||||||
|
oneOf: [
|
||||||
|
{
|
||||||
|
oneOf: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
enum: ['a', 'b'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
enum: ['c', 'd'],
|
||||||
|
nullable: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
enum: ['a', 'b', 'c', 'd'],
|
||||||
|
nullable: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('merges objects with allOf', () => {
|
||||||
|
expect(
|
||||||
|
getSchemaAlternatives({
|
||||||
|
allOf: [
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['name'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
externalId: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['map', 'externalId'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
map: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
externalId: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['name', 'map', 'externalId'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not flatten oneOf and allOf', () => {
|
it('should not flatten oneOf and allOf', () => {
|
||||||
expect(
|
expect(
|
||||||
getSchemaAlternatives({
|
getSchemaAlternatives({
|
||||||
|
|||||||
@@ -450,7 +450,91 @@ export function getSchemaAlternatives(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [type, schemas] = alternatives;
|
const [type, schemas] = alternatives;
|
||||||
return flattenAlternatives(type, schemas, new Set(ancestors).add(schema));
|
return mergeAlternatives(
|
||||||
|
type,
|
||||||
|
flattenAlternatives(type, schemas, new Set(ancestors).add(schema))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge alternatives of the same type into a single schema.
|
||||||
|
* - Merge string enums
|
||||||
|
*/
|
||||||
|
function mergeAlternatives(
|
||||||
|
alternativeType: AlternativeType,
|
||||||
|
schemasOrRefs: OpenAPIV3.SchemaObject[]
|
||||||
|
): OpenAPIV3.SchemaObject[] | null {
|
||||||
|
switch (alternativeType) {
|
||||||
|
case 'oneOf': {
|
||||||
|
return schemasOrRefs.reduce<OpenAPIV3.SchemaObject[]>((acc, schemaOrRef) => {
|
||||||
|
const latest = acc.at(-1);
|
||||||
|
|
||||||
|
if (
|
||||||
|
latest &&
|
||||||
|
latest.type === 'string' &&
|
||||||
|
latest.enum &&
|
||||||
|
schemaOrRef.type === 'string' &&
|
||||||
|
schemaOrRef.enum
|
||||||
|
) {
|
||||||
|
latest.enum = Array.from(new Set([...latest.enum, ...schemaOrRef.enum]));
|
||||||
|
latest.nullable = latest.nullable || schemaOrRef.nullable;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.push(schemaOrRef);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
case 'allOf': {
|
||||||
|
return schemasOrRefs.reduce<OpenAPIV3.SchemaObject[]>((acc, schemaOrRef) => {
|
||||||
|
const latest = acc.at(-1);
|
||||||
|
|
||||||
|
if (
|
||||||
|
latest &&
|
||||||
|
latest.type === 'string' &&
|
||||||
|
latest.enum &&
|
||||||
|
schemaOrRef.type === 'string' &&
|
||||||
|
schemaOrRef.enum
|
||||||
|
) {
|
||||||
|
const keys = Object.keys(schemaOrRef);
|
||||||
|
if (keys.every((key) => ['type', 'enum', 'nullable'].includes(key))) {
|
||||||
|
latest.enum = Array.from(new Set([...latest.enum, ...schemaOrRef.enum]));
|
||||||
|
latest.nullable = latest.nullable || schemaOrRef.nullable;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latest && latest.type === 'object' && schemaOrRef.type === 'object') {
|
||||||
|
const keys = Object.keys(schemaOrRef);
|
||||||
|
if (
|
||||||
|
keys.every((key) =>
|
||||||
|
['type', 'properties', 'required', 'nullable'].includes(key)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
latest.properties = {
|
||||||
|
...latest.properties,
|
||||||
|
...schemaOrRef.properties,
|
||||||
|
};
|
||||||
|
latest.required = Array.from(
|
||||||
|
new Set([
|
||||||
|
...(Array.isArray(latest.required) ? latest.required : []),
|
||||||
|
...(Array.isArray(schemaOrRef.required)
|
||||||
|
? schemaOrRef.required
|
||||||
|
: []),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
latest.nullable = latest.nullable || schemaOrRef.nullable;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.push(schemaOrRef);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return schemasOrRefs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function flattenAlternatives(
|
function flattenAlternatives(
|
||||||
|
|||||||
Reference in New Issue
Block a user