Skip to content

Commit

Permalink
feat: Throw error with circular schemas and inline refHandling option (
Browse files Browse the repository at this point in the history
  • Loading branch information
toomuchdesign authored Jan 26, 2024
1 parent 87015af commit 1b6a53d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/rude-oranges-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openapi-ts-json-schema': minor
---

Throw descriptive error with circular schemas and inline refHandling option
11 changes: 9 additions & 2 deletions src/openapiToTsJsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ export async function openapiToTsJsonSchema({

await clearFolder(outputPath);

const bundledOpenApiSchema = await $RefParser.bundle(openApiSchemaPath);
const schemaParser = new $RefParser();
const bundledOpenApiSchema = await schemaParser.bundle(openApiSchemaPath);
const initialJsonSchema = convertOpenApiToJsonSchema(bundledOpenApiSchema);

const inlinedRefs: Map<string, JSONSchema> = new Map();
const dereferencedJsonSchema = await $RefParser.dereference(
const dereferencedJsonSchema = await schemaParser.dereference(
initialJsonSchema,
{
dereference: {
Expand Down Expand Up @@ -106,6 +107,12 @@ export async function openapiToTsJsonSchema({
},
);

if (refHandling === 'inline' && schemaParser.$refs.circular) {
throw new Error(
'[openapi-ts-json-schema] Circular input definition detected. Use "import" or "keep" refHandling option, instead.',
);
}

const jsonSchema = convertOpenApiParameters(dereferencedJsonSchema);
const schemaMetaDataMap: SchemaMetaDataMap = new Map();

Expand Down
94 changes: 74 additions & 20 deletions test/circularReference.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,86 @@ import { fixtures, makeTestOutputPath } from './test-utils';
import { openapiToTsJsonSchema } from '../src';

describe('Circular reference', () => {
it("Doesn't break", async () => {
const { outputPath } = await openapiToTsJsonSchema({
openApiSchema: path.resolve(fixtures, 'circular-reference/specs.yaml'),
outputPath: makeTestOutputPath('circular'),
definitionPathsToGenerateFrom: ['components.schemas'],
refHandling: 'import',
silent: true,
describe('"refHandling" option', () => {
describe('inline', () => {
it('Throws expected error', async () => {
await expect(
openapiToTsJsonSchema({
openApiSchema: path.resolve(
fixtures,
'circular-reference/specs.yaml',
),
outputPath: makeTestOutputPath('circular-inline'),
definitionPathsToGenerateFrom: ['components.schemas'],
refHandling: 'inline',
}),
).rejects.toThrow(
'[openapi-ts-json-schema] Circular input definition detected. Use "import" or "keep" refHandling option, instead.',
);
});
});

const januarySchema = await import(
path.resolve(outputPath, 'components/schemas/January')
);
describe('import', () => {
it('Generates expected schema', async () => {
const { outputPath } = await openapiToTsJsonSchema({
openApiSchema: path.resolve(
fixtures,
'circular-reference/specs.yaml',
),
outputPath: makeTestOutputPath('circular-import'),
definitionPathsToGenerateFrom: ['components.schemas'],
refHandling: 'import',
silent: true,
});

expect(januarySchema.default).toEqual({
description: 'January description',
type: 'object',
properties: {
nextMonth: {
description: 'February description',
const januarySchema = await import(
path.resolve(outputPath, 'components/schemas/January')
);

expect(januarySchema.default).toEqual({
description: 'January description',
type: 'object',
properties: {
nextMonth: {
description: 'February description',
type: 'object',
properties: {
// Node stops recursion
previousMonth: undefined,
},
},
},
});
});
});

describe('keep', () => {
it('Generates expected schema', async () => {
const { outputPath } = await openapiToTsJsonSchema({
openApiSchema: path.resolve(
fixtures,
'circular-reference/specs.yaml',
),
outputPath: makeTestOutputPath('circular-keep'),
definitionPathsToGenerateFrom: ['components.schemas'],
refHandling: 'keep',
silent: true,
});

const januarySchema = await import(
path.resolve(outputPath, 'components/schemas/January')
);

expect(januarySchema.default).toEqual({
description: 'January description',
type: 'object',
properties: {
// Node stops recursion
previousMonth: undefined,
nextMonth: {
$ref: '#/components/schemas/February',
},
},
},
},
});
});
});
});
});

0 comments on commit 1b6a53d

Please sign in to comment.