UNPKG

openapi-typescript

Version:

Convert OpenAPI 3.0 & 3.1 schemas to TypeScript

93 lines (85 loc) 3.23 kB
import ts, { InterfaceDeclaration, TypeLiteralNode } from "typescript"; import { NEVER, STRING, tsModifiers, tsRecord } from "../lib/ts.js"; import { createRef, debug } from "../lib/utils.js"; import { GlobalContext, OpenAPI3 } from "../types.js"; import transformComponentsObject from "./components-object.js"; import transformPathsObject from "./paths-object.js"; import transformSchemaObject from "./schema-object.js"; import transformWebhooksObject from "./webhooks-object.js"; type SchemaTransforms = keyof Pick< OpenAPI3, "paths" | "webhooks" | "components" | "$defs" >; const transformers: Record< SchemaTransforms, (node: any, options: GlobalContext) => ts.TypeNode // eslint-disable-line @typescript-eslint/no-explicit-any > = { paths: transformPathsObject, webhooks: transformWebhooksObject, components: transformComponentsObject, $defs: (node, options) => transformSchemaObject(node, { path: createRef(["$defs"]), ctx: options }), }; export default function transformSchema(schema: OpenAPI3, ctx: GlobalContext) { const type: ts.Node[] = []; for (const root of Object.keys(transformers) as SchemaTransforms[]) { const emptyObj = ts.factory.createTypeAliasDeclaration( /* modifiers */ tsModifiers({ export: true }), /* name */ root, /* typeParameters */ undefined, /* type */ tsRecord(STRING, NEVER), ); if (schema[root] && typeof schema[root] === "object") { const rootT = performance.now(); const subType = transformers[root](schema[root], ctx); if ((subType as ts.TypeLiteralNode).members?.length) { type.push( ctx.exportType ? ts.factory.createTypeAliasDeclaration( /* modifiers */ tsModifiers({ export: true }), /* name */ root, /* typeParameters */ undefined, /* type */ subType, ) : ts.factory.createInterfaceDeclaration( /* modifiers */ tsModifiers({ export: true }), /* name */ root, /* typeParameters */ undefined, /* heritageClauses */ undefined, /* members */ (subType as TypeLiteralNode).members, ), ); debug(`${root} done`, "ts", performance.now() - rootT); } else { type.push(emptyObj); debug(`${root} done (skipped)`, "ts", 0); } } else { type.push(emptyObj); debug(`${root} done (skipped)`, "ts", 0); } } // inject let hasOperations = false; for (const injectedType of ctx.injectFooter) { if ( !hasOperations && (injectedType as InterfaceDeclaration)?.name?.escapedText === "operations" ) { hasOperations = true; } type.push(injectedType); } if (!hasOperations) { // if no operations created, inject empty operations type type.push( ts.factory.createTypeAliasDeclaration( /* modifiers */ tsModifiers({ export: true }), /* name */ "operations", /* typeParameters */ undefined, /* type */ tsRecord(STRING, NEVER), ), ); } return type; }