From 027e02f421b2d795e64b4c6f84ee87faf8fecf89 Mon Sep 17 00:00:00 2001 From: Andrea Carraro Date: Wed, 22 May 2024 12:26:33 +0200 Subject: [PATCH] refactor: generate metaData for all schemas for all refHandling modes --- src/openapiToTsJsonSchema.ts | 48 +++++++++++-------- src/plugins/fastifyIntegrationPlugin.ts | 3 +- src/utils/addSchemaToMetaData.ts | 45 ++++++++--------- src/utils/makeTsJsonSchemaFiles.ts | 20 ++++---- test/circularReference.test.ts | 39 ++++++++++++--- .../fastifyIntegrationPlugin.test.ts | 8 ++-- 6 files changed, 99 insertions(+), 64 deletions(-) diff --git a/src/openapiToTsJsonSchema.ts b/src/openapiToTsJsonSchema.ts index eb300076..3e4c486c 100644 --- a/src/openapiToTsJsonSchema.ts +++ b/src/openapiToTsJsonSchema.ts @@ -136,26 +136,6 @@ export async function openapiToTsJsonSchema( const jsonSchema = convertOpenApiPathsParameters(dereferencedJsonSchema); const schemaMetaDataMap: SchemaMetaDataMap = new Map(); - /** - * Create meta data for $ref schemas which have been previously dereferenced. - * It happens only with "import" and "keep" refHandling since they expect - * $ref schemas to be generated no matter of - */ - if (refHandling === 'import' || refHandling === 'keep') { - for (const [id, { openApiDefinition, jsonSchema }] of inlinedRefs) { - addSchemaToMetaData({ - id, - $id: $idMapper({ id }), - schemaMetaDataMap, - openApiDefinition, - jsonSchema, - outputPath, - isRef: true, - shouldBeGenerated: true, - }); - } - } - /** * Create meta data for each output schema */ @@ -183,6 +163,34 @@ export async function openapiToTsJsonSchema( } } + /** + * Create meta data for each $ref schemas which have been previously dereferenced. + */ + for (const [id, { openApiDefinition, jsonSchema }] of inlinedRefs) { + let shouldBeGenerated = true; + + /** + * In "inline" mode $ref schemas not explicitly marked for generation + * should not be generated + * + * All the other "refHandling" modes generate all $ref schemas + */ + if (refHandling === 'inline' && !schemaMetaDataMap.has(id)) { + shouldBeGenerated = false; + } + + addSchemaToMetaData({ + id, + $id: $idMapper({ id }), + schemaMetaDataMap, + openApiDefinition, + jsonSchema, + outputPath, + isRef: true, + shouldBeGenerated, + }); + } + const returnPayload: ReturnPayload = { outputPath, metaData: { schemas: schemaMetaDataMap }, diff --git a/src/plugins/fastifyIntegrationPlugin.ts b/src/plugins/fastifyIntegrationPlugin.ts index 025e848b..1f51823d 100644 --- a/src/plugins/fastifyIntegrationPlugin.ts +++ b/src/plugins/fastifyIntegrationPlugin.ts @@ -22,7 +22,8 @@ const fastifyIntegrationPlugin: Plugin = ({ onBeforeGeneration: async ({ outputPath, metaData, options, utils }) => { // Derive the schema data necessary to generate the declarations const allSchemas = [...metaData.schemas] - .map(([id, schema]) => schema) + .map(([_id, schema]) => schema) + .filter((schema) => schema.shouldBeGenerated) .map(({ absoluteImportPath, uniqueName, id, isRef }) => { return { importPath: utils.makeRelativeModulePath({ diff --git a/src/utils/addSchemaToMetaData.ts b/src/utils/addSchemaToMetaData.ts index e535a19a..07cbead9 100644 --- a/src/utils/addSchemaToMetaData.ts +++ b/src/utils/addSchemaToMetaData.ts @@ -37,32 +37,29 @@ export function addSchemaToMetaData({ shouldBeGenerated: boolean; outputPath: string; }): void { - // Do not override existing meta info of inlined schemas - if (!schemaMetaDataMap.has(id)) { - const { schemaRelativeDirName, schemaName } = parseId(id); - const absoluteDirName = path.join(outputPath, schemaRelativeDirName); - const schemaFileName = filenamify(schemaName); - const absoluteImportPath = path.join(absoluteDirName, schemaFileName); + const { schemaRelativeDirName, schemaName } = parseId(id); + const absoluteDirName = path.join(outputPath, schemaRelativeDirName); + const schemaFileName = filenamify(schemaName); + const absoluteImportPath = path.join(absoluteDirName, schemaFileName); - // Convert components.parameters after convertOpenApiPathsParameters is called - if (isOpenApiParameterObject(openApiDefinition)) { - jsonSchema = convertOpenApiParameterToJsonSchema(openApiDefinition); - } + // Convert components.parameters after convertOpenApiPathsParameters is called + if (isOpenApiParameterObject(openApiDefinition)) { + jsonSchema = convertOpenApiParameterToJsonSchema(openApiDefinition); + } - const metaInfo: SchemaMetaData = { - id, - $id, - uniqueName: namify(id), - isRef, - shouldBeGenerated, - openApiDefinition, - originalSchema: jsonSchema, + const metaInfo: SchemaMetaData = { + id, + $id, + uniqueName: namify(id), + isRef, + shouldBeGenerated, + openApiDefinition, + originalSchema: jsonSchema, - absoluteDirName, - absoluteImportPath, - absolutePath: absoluteImportPath + '.ts', - }; + absoluteDirName, + absoluteImportPath, + absolutePath: absoluteImportPath + '.ts', + }; - schemaMetaDataMap.set(id, metaInfo); - } + schemaMetaDataMap.set(id, metaInfo); } diff --git a/src/utils/makeTsJsonSchemaFiles.ts b/src/utils/makeTsJsonSchemaFiles.ts index fd6b2c0f..4c134abe 100644 --- a/src/utils/makeTsJsonSchemaFiles.ts +++ b/src/utils/makeTsJsonSchemaFiles.ts @@ -21,15 +21,17 @@ export async function makeTsJsonSchemaFiles({ $idMapper: $idMapper; }) { for (const [_, metaData] of schemaMetaDataMap) { - const tsSchema = await makeTsJsonSchema({ - metaData, - schemaMetaDataMap, - refHandling, - schemaPatcher, - $idMapper, - }); + if (metaData.shouldBeGenerated) { + const tsSchema = await makeTsJsonSchema({ + metaData, + schemaMetaDataMap, + refHandling, + schemaPatcher, + $idMapper, + }); - const { absolutePath } = metaData; - await saveFile({ path: [absolutePath], data: tsSchema }); + const { absolutePath } = metaData; + await saveFile({ path: [absolutePath], data: tsSchema }); + } } } diff --git a/test/circularReference.test.ts b/test/circularReference.test.ts index 554d1b0e..20b01595 100644 --- a/test/circularReference.test.ts +++ b/test/circularReference.test.ts @@ -32,21 +32,33 @@ describe('Circular reference', () => { description: 'February description', type: 'object', properties: { - previousMonth: {}, + previousMonth: { + description: 'January description', + properties: {}, + type: 'object', + }, }, }, nextMonthTwo: { description: 'February description', type: 'object', properties: { - previousMonth: {}, + previousMonth: { + description: 'January description', + properties: {}, + type: 'object', + }, }, }, nextMonthThree: { description: 'February description', type: 'object', properties: { - previousMonth: {}, + previousMonth: { + description: 'January description', + properties: {}, + type: 'object', + }, }, }, }, @@ -66,9 +78,24 @@ describe('Circular reference', () => { description: "January description", type: "object", properties: { - nextMonth: {}, - nextMonthTwo: {}, - nextMonthThree: {}, + nextMonth: { + // $ref: "#/components/schemas/February" + description: "February description", + type: "object", + properties: {}, + }, + nextMonthTwo: { + // $ref: "#/components/schemas/February" + description: "February description", + type: "object", + properties: {}, + }, + nextMonthThree: { + // $ref: "#/components/schemas/February" + description: "February description", + type: "object", + properties: {}, + }, }, },`; diff --git a/test/plugins/fastifyIntegrationPlugin/fastifyIntegrationPlugin.test.ts b/test/plugins/fastifyIntegrationPlugin/fastifyIntegrationPlugin.test.ts index a4ce4c83..6819be52 100644 --- a/test/plugins/fastifyIntegrationPlugin/fastifyIntegrationPlugin.test.ts +++ b/test/plugins/fastifyIntegrationPlugin/fastifyIntegrationPlugin.test.ts @@ -25,25 +25,25 @@ describe('fastifyIntegration plugin', () => { // @TODO find a better way to assert against generated types const expectedAsText = await formatTypeScript(` // File autogenerated by "openapi-ts-json-schema". Do not edit :) - import { with$id as componentsSchemasAnswer } from "./components/schemas/Answer"; import { with$id as componentsSchemasJanuary } from "./components/schemas/January"; import { with$id as componentsSchemasFebruary } from "./components/schemas/February"; import { with$id as componentsSchemasMarch } from "./components/schemas/March"; + import { with$id as componentsSchemasAnswer } from "./components/schemas/Answer"; // RefSchemas type: tuple of $ref schema types to enable json-schema-to-ts hydrate $refs via "references" option export type RefSchemas = [ - typeof componentsSchemasAnswer, typeof componentsSchemasJanuary, typeof componentsSchemasFebruary, typeof componentsSchemasMarch, + typeof componentsSchemasAnswer, ]; // schemas: array of JSON schemas to be registered with "fastify.addSchema" export const schemas = [ - componentsSchemasAnswer, componentsSchemasJanuary, componentsSchemasFebruary, componentsSchemasMarch, + componentsSchemasAnswer, ]`); expect(actualAsText).toBe(expectedAsText); @@ -68,10 +68,10 @@ describe('fastifyIntegration plugin', () => { ); expect(actual.schemas).toEqual([ - answerSchema.with$id, januarySchema.with$id, februarySchema.with$id, marchSchema.with$id, + answerSchema.with$id, ]); });