{"version":3,"file":"components-object.mjs","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":[],"mappings":"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"}