Skip to content

Commit 01abf54

Browse files
committed
Handle recursion
1 parent e5502a0 commit 01abf54

File tree

2 files changed

+51
-25
lines changed

2 files changed

+51
-25
lines changed

src/openapi/RefResolver.ts

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,64 @@
11
import {OpenAPIV3} from "openapi-types";
2+
import * as lodash from "lodash";
23

34
export class RefResolver {
45
constructor(private doc: any) {
56

67
}
78

8-
resolveRef(ref: string): OpenAPIV3.SchemaObject {
9-
const refPath = ref.split('/').slice(1);
10-
let schema: any = this.doc;
11-
for (const path of refPath) {
12-
// @ts-ignore
13-
schema = schema[path];
14-
if (!schema) {
15-
throw new Error(`Schema not found for ref '${ref}'`);
16-
}
17-
}
18-
if ('$ref' in schema) {
19-
return this.resolveRef(schema['$ref']);
20-
}
21-
return schema;
22-
}
23-
24-
resolve<T>(schema: OpenAPIV3.ReferenceObject | T): T {
9+
/**
10+
* Resolve ref and return it if found
11+
* @param schema
12+
*/
13+
resolveRef<T>(schema: OpenAPIV3.ReferenceObject | T): [T, string[]?] {
2514
// @ts-ignore
2615
if ("oneOf" in schema) {
2716
// @ts-ignore
28-
return this.resolve(schema.oneOf[0]);
17+
schema = schema.oneOf[0]
2918
}
3019
// @ts-ignore
3120
if ("anyOf" in schema) {
3221
// @ts-ignore
33-
return this.resolve(schema.anyOf[0]);
22+
schema = schema.anyOf[0]
3423
}
3524
// @ts-ignore
3625
if ("allOf" in schema) {
3726
// @ts-ignore
38-
const schemas = schema.allOf.map((s) => this.resolve(s));
39-
return Object.assign({}, ...schemas) as T;
27+
const results = schema.allOf.map((s) => this.resolveRef(s));
28+
const schemas = results.map((r: any) => r[0]);
29+
const refs = results.map((r: any) => r[1]);
30+
const refsFlat = lodash.flatten<string>(refs);
31+
const object = Object.assign({}, ...schemas);
32+
return [object as T, refsFlat]
4033
}
4134
// @ts-ignore
4235
if ('$ref' in schema) {
43-
const schemaResolved = this.resolveRef(schema['$ref']);
36+
const schemaResolved = this.findRef(schema['$ref']);
4437
// Remove $ref from schema, add all other properties
4538
const {$ref, ...rest} = schema;
4639
Object.assign(rest, schemaResolved);
47-
return rest as T
40+
return [rest as T, [$ref]]
41+
}
42+
return [schema as T, undefined]
43+
}
44+
45+
resolve<T>(schema: OpenAPIV3.ReferenceObject | T): T {
46+
return this.resolveRef(schema)[0]
47+
}
48+
49+
private findRef(ref: string): OpenAPIV3.SchemaObject {
50+
const refPath = ref.split('/').slice(1);
51+
let schema: any = this.doc;
52+
for (const path of refPath) {
53+
// @ts-ignore
54+
schema = schema[path];
55+
if (!schema) {
56+
throw new Error(`Schema not found for ref '${ref}'`);
57+
}
58+
}
59+
if ('$ref' in schema) {
60+
return this.findRef(schema['$ref']);
4861
}
49-
return schema as T
62+
return schema;
5063
}
5164
}

src/openapi/SchemaExample.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@ import {RefResolver} from "./RefResolver";
22
import {OpenAPIV3} from "openapi-types";
33

44
class SchemaExampleBuilder {
5+
private visitedRefs: Set<string> = new Set<string>();
6+
57
constructor(private resolver: RefResolver) {
68
}
79

810
build(schema: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject): any {
9-
schema = this.resolver.resolve(schema)
11+
let refs: string[] | undefined
12+
[schema, refs] = this.resolver.resolveRef(schema)
13+
14+
if (refs) {
15+
// Prevent infinite recursion
16+
for (const ref of refs) {
17+
if (this.visitedRefs.has(ref)) {
18+
return {}
19+
}
20+
this.visitedRefs.add(ref);
21+
}
22+
}
1023
if ('oneOf' in schema) {
1124
return this.build(schema.oneOf!![0]);
1225
}

0 commit comments

Comments
 (0)