Skip to content

Commit f3aafea

Browse files
committed
Remove whole attribute when circular reference is found in schema (no empty object)
1 parent 0701304 commit f3aafea

File tree

2 files changed

+99
-13
lines changed

2 files changed

+99
-13
lines changed

src/jsonschema.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@
22
import { OpenAPIV3_1 } from "openapi-types";
33
import { debug } from "./debug.js";
44

5-
function walk(schema: OpenAPIV3_1.SchemaObject, defs: any, history: any): void {
5+
function walk(schema: OpenAPIV3_1.SchemaObject, defs: any, history: any): boolean {
66

77
if (schema.type === 'object') {
88
if (schema.properties) {
99
for (const key in schema.properties) {
1010
const property = schema.properties[key];
11-
walk(property, defs, history);
11+
if (walk(property, defs, history)) {
12+
delete((schema.properties as any)[key]);
13+
}
1214
}
1315
}
14-
} else if ((schema as any)["$ref"]) {
16+
return false;
17+
}
18+
if ((schema as any)["$ref"]) {
1519
const canonicalRef = (schema as any)['$ref'];
1620

1721
const paths = canonicalRef.split('/');
@@ -20,17 +24,17 @@ function walk(schema: OpenAPIV3_1.SchemaObject, defs: any, history: any): void {
2024
if (history.includes(ref)) {
2125
debug("Circular reference detected for " + ref + " in history: " + history);
2226
delete((schema as any)["$ref"]);
23-
} else {
24-
const def = defs[ref];
25-
for (const k in def) {
26-
(schema as any)[k] = def[k];
27-
}
28-
29-
delete((schema as any)["$ref"]);
30-
31-
walk(schema, defs, [...history, ref]);
32-
}
27+
return true;
28+
}
29+
const def = defs[ref];
30+
for (const k in def) {
31+
(schema as any)[k] = def[k];
32+
}
33+
delete((schema as any)["$ref"]);
34+
walk(schema, defs, [...history, ref]);
35+
return false
3336
}
37+
return false
3438
}
3539

3640
export function expandJSONSchemaDefinition(schema: any, defs: any): any {

tests/jsonschema.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,85 @@ test('expandJSONSchemaDefinition $ref using definitions for properties', () => {
7777
expect(expandJSONSchemaDefinition(schema, defs)).toEqual(schemaRef);
7878
});
7979

80+
test('expandJSONSchemaDefinition removes $ref definition from attribute', () => {
81+
const schema = {
82+
type: 'object',
83+
properties: {
84+
borrower: {
85+
type: 'object',
86+
properties: {
87+
name: { type: 'string' },
88+
spouse: { $ref: "#/components/schemas/toto" }
89+
}
90+
}
91+
}
92+
};
93+
const expected = {
94+
type: 'object',
95+
properties: {
96+
borrower: {
97+
type: 'object',
98+
properties: {
99+
name: { type: 'string' },
100+
spouse: { }
101+
}
102+
}
103+
}
104+
};
105+
const result = expandJSONSchemaDefinition(schema, {});
106+
expect(result).toEqual(expected);
107+
108+
// Explicitly verify that borrower.spouse is an empty object
109+
const spouse = result.properties.borrower.properties.spouse;
110+
expect(spouse).toEqual({});
111+
expect(Object.keys(spouse).length).toBe(0);
112+
});
113+
114+
test('expandJSONSchemaDefinition removes attributes with circular $ref definition', () => {
115+
const defs = {
116+
borrower: {
117+
type: 'object',
118+
properties: {
119+
name: { type: 'string' },
120+
spouse: { $ref: "#/components/schemas/borrower" }
121+
}
122+
}
123+
};
124+
125+
const schema = {
126+
type: 'object',
127+
properties: {
128+
input: {
129+
type: "object",
130+
properties: {
131+
borrower: {
132+
"$ref": "#/components/schemas/borrower"
133+
}
134+
}
135+
},
136+
}
137+
};
138+
139+
const expected = {
140+
type: 'object',
141+
properties: {
142+
input: {
143+
type: "object",
144+
properties: {
145+
borrower: {
146+
type: 'object',
147+
properties: {
148+
name: { type: 'string' },
149+
}
150+
}
151+
}
152+
}
153+
}
154+
};
155+
const result = expandJSONSchemaDefinition(schema, defs);
156+
expect(result).toEqual(expected);
157+
158+
// Explicitly verify that borrower.spouse is undefined
159+
const spouse = result.properties.input.properties.borrower.properties.spouse;
160+
expect(spouse).toBeUndefined();
161+
});

0 commit comments

Comments
 (0)