UNPKG

openapi-typescript

Version:

Convert OpenAPI 3.0 & 3.1 schemas to TypeScript

1 lines 10.5 kB
{"version":3,"file":"components-object.cjs","sources":["../../src/transform/components-object.ts"],"sourcesContent":["import { performance } from \"node:perf_hooks\";\nimport * as changeCase from \"change-case\";\nimport ts from \"typescript\";\nimport { addJSDocComment, NEVER, QUESTION_TOKEN, tsModifiers, tsPropertyIndex } from \"../lib/ts.js\";\nimport { createRef, debug, getEntries } from \"../lib/utils.js\";\nimport type { ComponentsObject, GlobalContext, SchemaObject, TransformNodeOptions } from \"../types.js\";\nimport transformHeaderObject from \"./header-object.js\";\nimport transformParameterObject from \"./parameter-object.js\";\nimport transformPathItemObject from \"./path-item-object.js\";\nimport transformRequestBodyObject from \"./request-body-object.js\";\nimport transformResponseObject from \"./response-object.js\";\nimport transformSchemaObject from \"./schema-object.js\";\n\n/**\n * Determines if a schema object represents an enum type to prevent duplicate exports\n * when using --root-types and --enum flags together.\n *\n * When both flags are enabled:\n * - --enum flag generates TypeScript enums at the bottom of the file\n * - --root-types flag would normally also export these as root type aliases\n * - This results in duplicate exports (both enum and type alias for the same schema)\n *\n * This function identifies enum schemas so they can be excluded from root type generation,\n * allowing only the TypeScript enum to be generated.\n *\n * @param schema The schema object to check\n * @returns true if the schema represents an enum type\n */\nexport function isEnumSchema(schema: unknown): boolean {\n return (\n typeof schema === \"object\" &&\n schema !== null &&\n !Array.isArray(schema) &&\n \"enum\" in schema &&\n Array.isArray((schema as any).enum) &&\n (!(\"type\" in schema) || (schema as any).type !== \"object\") &&\n !(\"properties\" in schema) &&\n !(\"additionalProperties\" in schema)\n );\n}\n\ntype ComponentTransforms = keyof Omit<ComponentsObject, \"examples\" | \"securitySchemes\" | \"links\" | \"callbacks\">;\n\nconst transformers: Record<ComponentTransforms, (node: any, options: TransformNodeOptions) => ts.TypeNode> = {\n schemas: transformSchemaObject,\n responses: transformResponseObject,\n parameters: transformParameterObject,\n requestBodies: transformRequestBodyObject,\n headers: transformHeaderObject,\n pathItems: transformPathItemObject,\n};\n\n/**\n * Transform the ComponentsObject (4.8.7)\n * @see https://spec.openapis.org/oas/latest.html#components-object\n */\nexport default function transformComponentsObject(componentsObject: ComponentsObject, ctx: GlobalContext): ts.Node[] {\n const type: ts.TypeElement[] = [];\n const rootTypeAliases: { [key: string]: ts.TypeAliasDeclaration } = {};\n for (const key of Object.keys(transformers) as ComponentTransforms[]) {\n const componentT = performance.now();\n\n const items: ts.TypeElement[] = [];\n if (componentsObject[key]) {\n for (const [name, item] of getEntries<SchemaObject>(componentsObject[key], ctx)) {\n let subType = transformers[key](item, {\n path: createRef([\"components\", key, name]),\n schema: item,\n ctx,\n });\n\n let hasQuestionToken = false;\n if (ctx.transform) {\n const result = ctx.transform(item, {\n path: createRef([\"components\", key, name]),\n schema: item,\n ctx,\n });\n if (result) {\n if (\"schema\" in result) {\n subType = result.schema;\n hasQuestionToken = result.questionToken;\n } else {\n subType = result;\n }\n }\n }\n\n const property = ts.factory.createPropertySignature(\n /* modifiers */ tsModifiers({ readonly: ctx.immutable }),\n /* name */ tsPropertyIndex(name),\n /* questionToken */ hasQuestionToken ? QUESTION_TOKEN : undefined,\n /* type */ subType,\n );\n addJSDocComment(item as unknown as any, property);\n items.push(property);\n\n if (ctx.rootTypes) {\n // Skip enum schemas when generating root types to prevent duplication (only when --enum flag is enabled)\n const shouldSkipEnumSchema = ctx.enum && key === \"schemas\" && isEnumSchema(item);\n\n if (!shouldSkipEnumSchema) {\n const componentKey = changeCase.pascalCase(singularizeComponentKey(key));\n let aliasName = `${componentKey}${changeCase.pascalCase(name)}`;\n\n // Add counter suffix (e.g. \"_2\") if conflict in name\n let conflictCounter = 1;\n\n while (rootTypeAliases[aliasName] !== undefined) {\n conflictCounter++;\n aliasName = `${componentKey}${changeCase.pascalCase(name)}_${conflictCounter}`;\n }\n const ref = ts.factory.createTypeReferenceNode(`components['${key}']['${name}']`);\n if (ctx.rootTypesNoSchemaPrefix && key === \"schemas\") {\n aliasName = aliasName.replace(componentKey, \"\");\n }\n const typeAlias = ts.factory.createTypeAliasDeclaration(\n /* modifiers */ tsModifiers({ export: true }),\n /* name */ aliasName,\n /* typeParameters */ undefined,\n /* type */ ref,\n );\n rootTypeAliases[aliasName] = typeAlias;\n }\n }\n }\n }\n type.push(\n ts.factory.createPropertySignature(\n /* modifiers */ undefined,\n /* name */ tsPropertyIndex(key),\n /* questionToken */ undefined,\n /* type */ items.length ? ts.factory.createTypeLiteralNode(items) : NEVER,\n ),\n );\n\n debug(`Transformed components → ${key}`, \"ts\", performance.now() - componentT);\n }\n\n // Extract root types\n let rootTypes: ts.TypeAliasDeclaration[] = [];\n if (ctx.rootTypes) {\n rootTypes = Object.keys(rootTypeAliases).map((k) => rootTypeAliases[k]);\n }\n\n return [ts.factory.createTypeLiteralNode(type), ...rootTypes];\n}\n\nexport function singularizeComponentKey(\n key: `x-${string}` | \"schemas\" | \"responses\" | \"parameters\" | \"requestBodies\" | \"headers\" | \"pathItems\",\n): string {\n switch (key) {\n // Handle special singular case\n case \"requestBodies\":\n return \"requestBody\";\n // Default to removing the \"s\"\n default:\n return key.slice(0, -1);\n }\n}\n"],"names":["transformSchemaObject","transformResponseObject","transformParameterObject","transformRequestBodyObject","transformHeaderObject","transformPathItemObject","performance","getEntries","createRef","ts","tsModifiers","tsPropertyIndex","QUESTION_TOKEN","addJSDocComment","changeCase","NEVER","debug"],"mappings":"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"}