diff --git a/packages/openapi-generator/src/cli.ts b/packages/openapi-generator/src/cli.ts index 4decd888..0437538c 100644 --- a/packages/openapi-generator/src/cli.ts +++ b/packages/openapi-generator/src/cli.ts @@ -1,6 +1,15 @@ #!/usr/bin/env node -import { command, run, option, string, flag, boolean, positional } from 'cmd-ts'; +import { + command, + run, + option, + string, + optional, + flag, + boolean, + positional, +} from 'cmd-ts'; import * as E from 'fp-ts/Either'; import * as fs from 'fs'; import * as p from 'path'; @@ -11,6 +20,7 @@ import { convertRoutesToOpenAPI } from './openapi'; import type { Route } from './route'; import type { Schema } from './ir'; import { Project } from './project'; +import { KNOWN_IMPORTS } from './knownImports'; const app = command({ name: 'api-ts', @@ -57,11 +67,30 @@ const app = command({ short: 'i', defaultValue: () => false, }), + codecFile: option({ + type: optional(string), + description: 'Custom codec definition file', + long: 'codec-file', + short: 'c', + defaultValue: () => undefined, + }), }, - handler: async ({ input, name, version }) => { + handler: async ({ input, name, version, codecFile }) => { const filePath = p.resolve(input); - const project = await new Project().parseEntryPoint(filePath); + let knownImports = KNOWN_IMPORTS; + if (codecFile !== undefined) { + const codecFilePath = p.resolve(codecFile); + const codecModule = await import(codecFilePath); + if (codecModule.default === undefined) { + console.error(`Could not find default export in ${codecFilePath}`); + process.exit(1); + } + const customCodecs = codecModule.default(E); + knownImports = { ...knownImports, ...customCodecs }; + } + + const project = await new Project({}, knownImports).parseEntryPoint(filePath); if (E.isLeft(project)) { console.error(project.left); process.exit(1); diff --git a/packages/openapi-generator/src/codec.ts b/packages/openapi-generator/src/codec.ts index 9cb46d14..9327208f 100644 --- a/packages/openapi-generator/src/codec.ts +++ b/packages/openapi-generator/src/codec.ts @@ -9,7 +9,7 @@ import type { Project } from './project'; import { findSymbolInitializer, resolveLiteralOrIdentifier } from './resolveInit'; import type { SourceFile } from './sourceFile'; -import { KNOWN_IMPORTS, type KnownCodec } from './knownImports'; +import type { KnownCodec } from './knownImports'; type ResolvedRef = { type: 'ref'; name: string; location: string }; @@ -32,7 +32,7 @@ function codecIdentifier( } else if (imp.type === 'star') { return E.left(`Tried to use star import as codec ${id.value}`); } - const knownImport = KNOWN_IMPORTS[imp.from]?.[imp.importedName]; + const knownImport = project.knownImports[imp.from]?.[imp.importedName]; if (knownImport !== undefined) { return E.right({ type: 'codec', schema: knownImport }); } @@ -67,7 +67,7 @@ function codecIdentifier( } const name = id.property.value; - const knownImport = KNOWN_IMPORTS[objectSym.from]?.[name]; + const knownImport = project.knownImports[objectSym.from]?.[name]; if (knownImport !== undefined) { return E.right({ type: 'codec', schema: knownImport }); } diff --git a/packages/openapi-generator/src/project.ts b/packages/openapi-generator/src/project.ts index cff295b9..c40f2d61 100644 --- a/packages/openapi-generator/src/project.ts +++ b/packages/openapi-generator/src/project.ts @@ -4,15 +4,19 @@ import { promisify } from 'util'; import * as E from 'fp-ts/Either'; import resolve from 'resolve'; +import { KNOWN_IMPORTS, type KnownCodec } from './knownImports'; import { parseSource, type SourceFile } from './sourceFile'; const readFile = promisify(fs.readFile); export class Project { + readonly knownImports: Record>; + private files: Record; - constructor(files: Record = {}) { + constructor(files: Record = {}, knownImports = KNOWN_IMPORTS) { this.files = files; + this.knownImports = knownImports; } add(path: string, sourceFile: SourceFile): void {