From 61e4cfe378dbbfb5d9df65bcc946b760548ac786 Mon Sep 17 00:00:00 2001 From: Andrea Carraro Date: Wed, 13 Sep 2023 18:34:06 +0200 Subject: [PATCH] feat: introduce plugins --- src/plugins/generateRefTypesAsArrayPlugin.ts | 58 +++++++++++++++++++ src/plugins/types.ts | 0 src/types.ts | 5 ++ .../generateRefTypesAsArrayPlugin.test.ts | 58 +++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 src/plugins/generateRefTypesAsArrayPlugin.ts create mode 100644 src/plugins/types.ts create mode 100644 test/plugins/generateRefTypesAsArrayPlugin.test.ts diff --git a/src/plugins/generateRefTypesAsArrayPlugin.ts b/src/plugins/generateRefTypesAsArrayPlugin.ts new file mode 100644 index 0000000..6622684 --- /dev/null +++ b/src/plugins/generateRefTypesAsArrayPlugin.ts @@ -0,0 +1,58 @@ +import { makeRelativePath, formatTypeScript, saveFile } from '../utils'; +import type { Plugin, SchemaMetaData } from '../types'; + +const FILE_NAME = 'refTypesAsArray.ts'; + +const generateRefTypesAsArrayPlugin: Plugin = async ({ + outputPath, + metaData, +}) => { + const refs: SchemaMetaData[] = []; + metaData.schemas.forEach((schema) => { + if (schema.isRef) { + refs.push(schema); + } + }); + + const schemas = refs.map( + ({ schemaAbsoluteImportPath, schemaUniqueName, schemaId }) => { + return { + importPath: makeRelativePath({ + fromDirectory: outputPath, + to: schemaAbsoluteImportPath, + }), + schemaUniqueName, + schemaId, + }; + }, + ); + + let output = ''; + + schemas.forEach((schema) => { + output += `\n import ${schema.schemaUniqueName} from "${schema.importPath}";`; + }); + + output += '\n\n'; + + schemas.forEach((schema) => { + output += `\n const ${schema.schemaUniqueName}WithId = {...${schema.schemaUniqueName}, $id: "${schema.schemaId}"} as const;`; + }); + + output += `\n\n + type RefTypes = [ + ${schemas + .map((schema) => `typeof ${schema.schemaUniqueName}WithId`) + .join(',')} + ];`; + + output += '\n\nexport default RefTypes'; + + const formattedOutput = await formatTypeScript(output); + await saveFile({ + path: [outputPath, FILE_NAME], + data: formattedOutput, + }); +}; + +export default generateRefTypesAsArrayPlugin; diff --git a/src/plugins/types.ts b/src/plugins/types.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types.ts b/src/types.ts index 517915b..7f9c19e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -27,3 +27,8 @@ export type SchemaMetaDataMap = Map< string, // Schema file relative path SchemaMetaData >; + +export type Plugin = (args: { + outputPath: string; + metaData: { schemas: SchemaMetaDataMap }; +}) => Promise; diff --git a/test/plugins/generateRefTypesAsArrayPlugin.test.ts b/test/plugins/generateRefTypesAsArrayPlugin.test.ts new file mode 100644 index 0000000..bf9f82b --- /dev/null +++ b/test/plugins/generateRefTypesAsArrayPlugin.test.ts @@ -0,0 +1,58 @@ +import path from 'path'; +import fs from 'fs/promises'; +import { describe, it, expect } from 'vitest'; +import { openapiToTsJsonSchema } from '../../src'; +import generateRefTypesAsArrayPlugin from '../../src/plugins/generateRefTypesAsArrayPlugin'; +import { importFresh } from '../test-utils'; +import { formatTypeScript } from '../../src/utils'; + +const fixtures = path.resolve(__dirname, '../fixtures'); + +describe('generateRefTypesAsArrayPlugin plugin', async () => { + it('generates expected file', async () => { + const { outputPath, metaData } = await openapiToTsJsonSchema({ + openApiSchema: path.resolve(fixtures, 'complex/specs.yaml'), + definitionPathsToGenerateFrom: ['components.months', 'paths'], + refHandling: 'keep', + silent: true, + }); + + await generateRefTypesAsArrayPlugin({ outputPath, metaData }); + + const actual = await fs.readFile( + path.resolve(outputPath, 'refTypesAsArray.ts'), + { + encoding: 'utf8', + }, + ); + + // @TODO find a better way to assert against generated types + const expected = await formatTypeScript(` + import componentsSchemasAnswer from "./components/schemas/Answer"; + import componentsMonthsJanuary from "./components/months/January"; + import componentsMonthsFebruary from "./components/months/February"; + + const componentsSchemasAnswerWithId = { + ...componentsSchemasAnswer, + $id: "#/components/schemas/Answer", + } as const; + const componentsMonthsJanuaryWithId = { + ...componentsMonthsJanuary, + $id: "#/components/months/January", + } as const; + const componentsMonthsFebruaryWithId = { + ...componentsMonthsFebruary, + $id: "#/components/months/February", + } as const; + + type RefTypes = [ + typeof componentsSchemasAnswerWithId, + typeof componentsMonthsJanuaryWithId, + typeof componentsMonthsFebruaryWithId, + ]; + + export default RefTypes;`); + + expect(actual).toBe(expected); + }); +});