Skip to content

Commit

Permalink
feat: oas3.1 merge $refs
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanHotsiy committed Jun 9, 2021
1 parent 0a4d172 commit 4e6b1c6
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 29 deletions.
29 changes: 11 additions & 18 deletions demo/openapi-3-1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -964,8 +964,7 @@ components:
properties:
id:
description: Category ID
allOf:
- $ref: '#/components/schemas/Id'
$ref: '#/components/schemas/Id'
name:
description: Category name
type: string
Expand Down Expand Up @@ -1015,12 +1014,10 @@ components:
properties:
id:
description: Order ID
allOf:
- $ref: '#/components/schemas/Id'
$ref: '#/components/schemas/Id'
petId:
description: Pet ID
allOf:
- $ref: '#/components/schemas/Id'
$ref: '#/components/schemas/Id'
quantity:
type: integer
format: int32
Expand Down Expand Up @@ -1065,12 +1062,10 @@ components:
description: "Find more info here"
url: "https://example.com"
description: Pet ID
allOf:
- $ref: '#/components/schemas/Id'
$ref: '#/components/schemas/Id'
category:
description: Categories this pet belongs to
allOf:
- $ref: '#/components/schemas/Category'
$ref: '#/components/schemas/Category'
name:
description: The name given to a pet
type: string
Expand All @@ -1087,8 +1082,7 @@ components:
type: string
format: url
friend:
allOf:
- $ref: '#/components/schemas/Pet'
$ref: '#/components/schemas/Pet'
tags:
description: Tags attached to the pet
type: array
Expand Down Expand Up @@ -1117,8 +1111,7 @@ components:
properties:
id:
description: Tag ID
allOf:
- $ref: '#/components/schemas/Id'
$ref: '#/components/schemas/Id'
name:
description: Tag name
type: string
Expand All @@ -1133,6 +1126,7 @@ components:
pet:
oneOf:
- $ref: '#/components/schemas/Pet'
title: Pettie
- $ref: '#/components/schemas/Tag'
username:
description: User supplied username
Expand Down Expand Up @@ -1179,10 +1173,9 @@ components:
content:
application/json:
schema:
allOf:
- description: My Pet
title: Pettie
- $ref: '#/components/schemas/Pet'
description: My Pet
title: Pettie
$ref: '#/components/schemas/Pet'
application/xml:
schema:
type: 'object'
Expand Down
2 changes: 1 addition & 1 deletion demo/playground/hmr-playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const swagger = window.location.search.indexOf('swagger') > -1;
const userUrl = window.location.search.match(/url=(.*)$/);

const specUrl =
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi.yaml');
(userUrl && userUrl[1]) || (swagger ? 'swagger.yaml' : big ? 'big-openapi.json' : 'openapi-3-1.yaml');

const options: RedocRawOptions = { nativeScrollbars: false, maxDisplayedEnumValues: 3 };

Expand Down
38 changes: 28 additions & 10 deletions src/services/OpenAPIParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ class RefCounter {
export class OpenAPIParser {
specUrl?: string;
spec: OpenAPISpec;
mergeRefs: Set<string>;

private _refCounter: RefCounter = new RefCounter();
private allowMergeRefs: boolean = false;

constructor(
spec: OpenAPISpec,
Expand All @@ -58,8 +58,7 @@ export class OpenAPIParser {
this.preprocess(spec);

this.spec = spec;

this.mergeRefs = new Set();
this.allowMergeRefs = spec.openapi.startsWith('3.1');

const href = IS_BROWSER ? window.location.href : '';
if (typeof specUrl === 'string') {
Expand Down Expand Up @@ -165,16 +164,35 @@ export class OpenAPIParser {
return Object.assign({}, resolved, { 'x-circular-ref': true });
}
// deref again in case one more $ref is here
let result = resolved;
if (this.isRef(resolved)) {
const res = this.deref(resolved);
result = this.deref(resolved);
this.exitRef(resolved);
return res;
}
return resolved;
return this.allowMergeRefs ? this.mergeRefs(obj, resolved) : result;
}
return obj;
}

mergeRefs(ref, resolved) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { $ref, ...rest } = ref;
const keys = Object.keys(rest);
if (keys.length === 0) {
return resolved;
}
if (keys.some((k) => k !== 'description' && k !== 'title' && k !== 'externalDocs')) {
return {
allOf: [resolved, rest],
};
} else {
return {
...resolved,
...rest,
};
}
}

shalowDeref<T extends object>(obj: OpenAPIRef | T): T {
if (this.isRef(obj)) {
return this.byRef<T>(obj.$ref)!;
Expand Down Expand Up @@ -234,7 +252,7 @@ export class OpenAPIParser {
schema: subMerged,
};
})
.filter(child => child !== undefined) as Array<{
.filter((child) => child !== undefined) as Array<{
$ref: string | undefined;
schema: MergedOpenAPISchema;
}>;
Expand Down Expand Up @@ -265,7 +283,7 @@ export class OpenAPIParser {
{ allOf: [receiver.properties[prop], subSchema.properties[prop]] },
$ref + '/properties/' + prop,
);
receiver.properties[prop] = mergedProp
receiver.properties[prop] = mergedProp;
this.exitParents(mergedProp); // every prop resolution should have separate recursive stack
}
}
Expand Down Expand Up @@ -313,7 +331,7 @@ export class OpenAPIParser {
const def = this.deref(schemas[defName]);
if (
def.allOf !== undefined &&
def.allOf.find(obj => obj.$ref !== undefined && $refs.indexOf(obj.$ref) > -1)
def.allOf.find((obj) => obj.$ref !== undefined && $refs.indexOf(obj.$ref) > -1)
) {
res['#/components/schemas/' + defName] = [def['x-discriminator-value'] || defName];
}
Expand All @@ -339,7 +357,7 @@ export class OpenAPIParser {
const beforeAllOf = allOf.slice(0, i);
const afterAllOf = allOf.slice(i + 1);
return {
oneOf: sub.oneOf.map(part => {
oneOf: sub.oneOf.map((part) => {
const merged = this.mergeAllOf({
allOf: [...beforeAllOf, part, ...afterAllOf],
});
Expand Down

0 comments on commit 4e6b1c6

Please sign in to comment.