Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ module.exports = {
coverageThreshold: {
global: {
branches: 90,
functions: 89,
lines: 89,
statements: 89
functions: 100,
lines: 96,
statements: 96
}
}
};
30 changes: 17 additions & 13 deletions src/jsonschema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
import { OpenAPIV3_1 } from "openapi-types";
import { debug } from "./debug.js";

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

if (schema.type === 'object') {
if (schema.properties) {
for (const key in schema.properties) {
const property = schema.properties[key];
walk(property, defs, history);
if (walk(property, defs, history)) {
delete((schema.properties as any)[key]);
}
}
}
} else if ((schema as any)["$ref"]) {
return false;
}
if ((schema as any)["$ref"]) {
const canonicalRef = (schema as any)['$ref'];

const paths = canonicalRef.split('/');
Expand All @@ -20,17 +24,17 @@ function walk(schema: OpenAPIV3_1.SchemaObject, defs: any, history: any): void {
if (history.includes(ref)) {
debug("Circular reference detected for " + ref + " in history: " + history);
delete((schema as any)["$ref"]);
} else {
const def = defs[ref];
for (const k in def) {
(schema as any)[k] = def[k];
}

delete((schema as any)["$ref"]);

walk(schema, defs, [...history, ref]);
}
return true;
}
const def = defs[ref];
for (const k in def) {
(schema as any)[k] = def[k];
}
delete((schema as any)["$ref"]);
walk(schema, defs, [...history, ref]);
return false
}
return false
}

export function expandJSONSchemaDefinition(schema: any, defs: any): any {
Expand Down
82 changes: 82 additions & 0 deletions tests/jsonschema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,85 @@ test('expandJSONSchemaDefinition $ref using definitions for properties', () => {
expect(expandJSONSchemaDefinition(schema, defs)).toEqual(schemaRef);
});

test('expandJSONSchemaDefinition removes $ref definition from attribute', () => {
const schema = {
type: 'object',
properties: {
borrower: {
type: 'object',
properties: {
name: { type: 'string' },
spouse: { $ref: "#/components/schemas/toto" }
}
}
}
};
const expected = {
type: 'object',
properties: {
borrower: {
type: 'object',
properties: {
name: { type: 'string' },
spouse: { }
}
}
}
};
const result = expandJSONSchemaDefinition(schema, {});
expect(result).toEqual(expected);

// Explicitly verify that borrower.spouse is an empty object
const spouse = result.properties.borrower.properties.spouse;
expect(spouse).toEqual({});
expect(Object.keys(spouse).length).toBe(0);
});

test('expandJSONSchemaDefinition removes attributes with circular $ref definition', () => {
const defs = {
borrower: {
type: 'object',
properties: {
name: { type: 'string' },
spouse: { $ref: "#/components/schemas/borrower" }
}
}
};

const schema = {
type: 'object',
properties: {
input: {
type: "object",
properties: {
borrower: {
"$ref": "#/components/schemas/borrower"
}
}
},
}
};

const expected = {
type: 'object',
properties: {
input: {
type: "object",
properties: {
borrower: {
type: 'object',
properties: {
name: { type: 'string' },
}
}
}
}
}
};
const result = expandJSONSchemaDefinition(schema, defs);
expect(result).toEqual(expected);

// Explicitly verify that borrower.spouse is undefined
const spouse = result.properties.input.properties.borrower.properties.spouse;
expect(spouse).toBeUndefined();
});