next-openapi-gen 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -184,6 +184,23 @@ z.number()
184
184
 
185
185
  Both work inside `z.object({...})` properties, in drizzle-zod override callbacks, and at the top level of named schemas. See [docs/zod4-support-matrix.md](./docs/zod4-support-matrix.md) for the full supported metadata surface.
186
186
 
187
+ ### Decouple component names from source identifiers
188
+
189
+ Use `.meta({ id })` for Zod schemas or `/** @id */` for TypeScript types to set the OpenAPI component name independently of the export name — useful when enforcing PascalCase naming or migrating from another generator without renaming existing exports:
190
+
191
+ ```ts
192
+ // Zod: use .meta({ id }) to decouple the component name from the variable name
193
+ export const audioSchema = z.object({ ... }).meta({ id: "Audio" });
194
+ // → components.schemas.Audio (not: audioSchema)
195
+
196
+ // TypeScript: use /** @id */ at the declaration level
197
+ /** @id Audio */
198
+ export interface AudioInterface { ... }
199
+ // → components.schemas.Audio (not: AudioInterface)
200
+ ```
201
+
202
+ Existing `@body audioSchema` or `@response audioSchema` references in route handlers continue to work — the generator resolves them transparently to the override name. See [docs/jsdoc-reference.md#component-naming](./docs/jsdoc-reference.md#component-naming) for details.
203
+
187
204
  ### Generate docs from Drizzle schemas
188
205
 
189
206
  `next-openapi-gen` works well with `drizzle-zod`, so your database schema, validation, and API docs can share the same source of truth.
package/dist/cli.js CHANGED
@@ -1406,6 +1406,17 @@ function mergeJSDocData(target, source) {
1406
1406
  function cleanComment(commentValue) {
1407
1407
  return commentValue.replace(/\*\s*/g, "").trim();
1408
1408
  }
1409
+ function extractSchemaIdFromComments(comments) {
1410
+ if (!comments)
1411
+ return null;
1412
+ for (const comment of comments) {
1413
+ const cleaned = cleanComment(comment.value);
1414
+ const id = extractTokenValue(cleaned, "@id");
1415
+ if (id)
1416
+ return id;
1417
+ }
1418
+ return null;
1419
+ }
1409
1420
  function extractLineValue(commentValue, tag) {
1410
1421
  return commentValue.match(new RegExp(`${escapeRegExp(tag)}\\s*(.*)`, "m"))?.[1]?.trim() || "";
1411
1422
  }
@@ -3585,7 +3596,8 @@ var DrizzleZodProcessor = class _DrizzleZodProcessor {
3585
3596
  if (firstArg && !t4.isSpreadElement(firstArg) && !t4.isArgumentPlaceholder(firstArg)) {
3586
3597
  const metadata = _DrizzleZodProcessor.extractStaticObject(firstArg);
3587
3598
  if (metadata) {
3588
- Object.assign(result, metadata);
3599
+ const { id: _id, ...rest } = metadata;
3600
+ Object.assign(result, rest);
3589
3601
  }
3590
3602
  }
3591
3603
  break;
@@ -11869,8 +11881,11 @@ var ZodRuntimeExporter = class {
11869
11881
  case "deprecated":
11870
11882
  return schema.meta({ deprecated: true });
11871
11883
  case "meta": {
11872
- const metadata = node.arguments[0] ? this.buildMetadataObject(node.arguments[0]) : null;
11873
- return metadata ? schema.meta(metadata) : schema;
11884
+ const rawMetadata = node.arguments[0] ? this.buildMetadataObject(node.arguments[0]) : null;
11885
+ if (!rawMetadata)
11886
+ return schema;
11887
+ const { id: _id, ...metadata } = rawMetadata;
11888
+ return Object.keys(metadata).length > 0 ? schema.meta(metadata) : schema;
11874
11889
  }
11875
11890
  case "default":
11876
11891
  case "prefault":
@@ -12127,6 +12142,9 @@ var ZodSchemaConverter = class {
12127
12142
  schemaNameToFiles = /* @__PURE__ */ new Map();
12128
12143
  /** Per-file import alias for the `zod` module (`import { z as zod }` sets this to `"zod"`). */
12129
12144
  zodImportAlias = /* @__PURE__ */ new Map();
12145
+ /** Schema variable names whose component name was overridden via .meta({ id }). These must
12146
+ * NOT be copied back under the original variable name in the OpenAPI components object. */
12147
+ metaIdSchemaNames = /* @__PURE__ */ new Set();
12130
12148
  // Current processing context (set during file processing)
12131
12149
  currentFilePath;
12132
12150
  currentAST;
@@ -12153,7 +12171,14 @@ var ZodSchemaConverter = class {
12153
12171
  }
12154
12172
  logger.debug(`Looking for Zod schema: ${schemaName}`);
12155
12173
  const requestedSchemaName = schemaName;
12156
- const mappedSchemaName = this.typeToSchemaMapping[schemaName];
12174
+ let mappedSchemaName = this.typeToSchemaMapping[schemaName];
12175
+ if (!mappedSchemaName) {
12176
+ const candidate = this.deriveSchemaNameByConvention(schemaName);
12177
+ if (candidate && this.locateSchemaByConvention(candidate)) {
12178
+ this.typeToSchemaMapping[schemaName] = candidate;
12179
+ mappedSchemaName = candidate;
12180
+ }
12181
+ }
12157
12182
  if (mappedSchemaName) {
12158
12183
  logger.debug(`Type '${schemaName}' is mapped to schema '${mappedSchemaName}'`);
12159
12184
  schemaName = mappedSchemaName;
@@ -12203,7 +12228,7 @@ var ZodSchemaConverter = class {
12203
12228
  this.processingSchemas.delete(schemaName);
12204
12229
  if (mappedSchemaName && requestedSchemaName !== schemaName) {
12205
12230
  const resolvedReference = this.getSchemaReferenceName(schemaName, this.currentContentType);
12206
- if (this.zodSchemas[resolvedReference] && !this.zodSchemas[requestedSchemaName]) {
12231
+ if (!this.metaIdSchemaNames.has(requestedSchemaName) && this.zodSchemas[resolvedReference] && !this.zodSchemas[requestedSchemaName]) {
12207
12232
  this.zodSchemas[requestedSchemaName] = this.zodSchemas[resolvedReference];
12208
12233
  }
12209
12234
  this.schemaVariantRefs.set(this.getVariantKey(requestedSchemaName, this.currentContentType), this.zodSchemas[requestedSchemaName] ? requestedSchemaName : resolvedReference);
@@ -12660,6 +12685,8 @@ var ZodSchemaConverter = class {
12660
12685
  try {
12661
12686
  const content = this.fileAccess.readFileSync(filePath, "utf-8");
12662
12687
  const ast = parseTypeScriptFile(content);
12688
+ this.currentFilePath = filePath;
12689
+ this.currentAST = ast;
12663
12690
  resolvedTraverse(ast, {
12664
12691
  ExportNamedDeclaration: (path25) => {
12665
12692
  if (t10.isVariableDeclaration(path25.node.declaration)) {
@@ -12674,6 +12701,17 @@ var ZodSchemaConverter = class {
12674
12701
  }
12675
12702
  this.processingSchemas.delete(schemaName);
12676
12703
  }
12704
+ } else if (t10.isIdentifier(declaration.id) && declaration.init) {
12705
+ const schemaName = declaration.id.name;
12706
+ const overrideId = this.extractMetaIdFromNode(declaration.init);
12707
+ if (overrideId && !this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
12708
+ this.processingSchemas.add(schemaName);
12709
+ const schema = this.processZodNode(declaration.init);
12710
+ this.processingSchemas.delete(schemaName);
12711
+ if (schema) {
12712
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
12713
+ }
12714
+ }
12677
12715
  }
12678
12716
  });
12679
12717
  }
@@ -13227,6 +13265,24 @@ var ZodSchemaConverter = class {
13227
13265
  }
13228
13266
  return void 0;
13229
13267
  }
13268
+ extractMetaIdFromNode(node) {
13269
+ if (!t10.isCallExpression(node))
13270
+ return null;
13271
+ if (t10.isMemberExpression(node.callee) && t10.isIdentifier(node.callee.property)) {
13272
+ if (node.callee.property.name === "meta" && node.arguments.length > 0) {
13273
+ const metadata = this.extractStaticJsonValue(node.arguments[0]);
13274
+ if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
13275
+ const id = metadata.id;
13276
+ if (typeof id === "string" && id.length > 0)
13277
+ return id;
13278
+ }
13279
+ }
13280
+ if (t10.isCallExpression(node.callee.object)) {
13281
+ return this.extractMetaIdFromNode(node.callee.object);
13282
+ }
13283
+ }
13284
+ return null;
13285
+ }
13230
13286
  shouldUseRuntimeExport(node) {
13231
13287
  if (!t10.isCallExpression(node)) {
13232
13288
  return false;
@@ -13467,7 +13523,8 @@ var ZodSchemaConverter = class {
13467
13523
  if (node.arguments.length > 0) {
13468
13524
  const metadata = this.extractStaticJsonValue(node.arguments[0]);
13469
13525
  if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
13470
- Object.assign(schema, metadata);
13526
+ const { id: _id, ...rest } = metadata;
13527
+ Object.assign(schema, rest);
13471
13528
  }
13472
13529
  }
13473
13530
  break;
@@ -13753,6 +13810,7 @@ var ZodSchemaConverter = class {
13753
13810
  this.currentFilePath = filePath;
13754
13811
  this.currentAST = ast;
13755
13812
  this.currentImports = importedModules;
13813
+ this.preprocessedFiles.add(filePath);
13756
13814
  resolvedTraverse(ast, {
13757
13815
  ExportNamedDeclaration: (path25) => {
13758
13816
  if (t10.isVariableDeclaration(path25.node.declaration)) {
@@ -13760,15 +13818,19 @@ var ZodSchemaConverter = class {
13760
13818
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13761
13819
  const schemaName = declaration.id.name;
13762
13820
  if (this.isZodSchema(declaration.init)) {
13763
- this.indexSchemaName(schemaName, filePath);
13764
13821
  if (!this.getStoredSchema(schemaName)) {
13765
13822
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13766
13823
  this.processingSchemas.add(schemaName);
13767
13824
  const schema = this.processZodNode(declaration.init);
13825
+ this.processingSchemas.delete(schemaName);
13768
13826
  if (schema) {
13769
- this.storeResolvedSchema(schemaName, schema);
13827
+ const overrideId = this.extractMetaIdFromNode(declaration.init);
13828
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
13829
+ } else {
13830
+ this.indexSchemaName(schemaName, filePath);
13770
13831
  }
13771
- this.processingSchemas.delete(schemaName);
13832
+ } else {
13833
+ this.indexSchemaName(schemaName, filePath);
13772
13834
  }
13773
13835
  }
13774
13836
  }
@@ -13781,22 +13843,25 @@ var ZodSchemaConverter = class {
13781
13843
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13782
13844
  const schemaName = declaration.id.name;
13783
13845
  if (this.isZodSchema(declaration.init)) {
13784
- this.indexSchemaName(schemaName, filePath);
13785
13846
  if (!this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
13786
13847
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13787
13848
  this.processingSchemas.add(schemaName);
13788
13849
  const schema = this.processZodNode(declaration.init);
13850
+ this.processingSchemas.delete(schemaName);
13789
13851
  if (schema) {
13790
- this.storeResolvedSchema(schemaName, schema);
13852
+ const overrideId = this.extractMetaIdFromNode(declaration.init);
13853
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
13854
+ } else {
13855
+ this.indexSchemaName(schemaName, filePath);
13791
13856
  }
13792
- this.processingSchemas.delete(schemaName);
13857
+ } else {
13858
+ this.indexSchemaName(schemaName, filePath);
13793
13859
  }
13794
13860
  }
13795
13861
  }
13796
13862
  });
13797
13863
  }
13798
13864
  });
13799
- this.preprocessedFiles.add(filePath);
13800
13865
  } catch (error2) {
13801
13866
  logger.error(`Error pre-processing file ${filePath}: ${error2}`);
13802
13867
  }
@@ -13814,6 +13879,63 @@ var ZodSchemaConverter = class {
13814
13879
  }
13815
13880
  bucket.add(filePath);
13816
13881
  }
13882
+ applyMetaIdOverride(schemaName, schema, overrideId, filePath) {
13883
+ const finalName = overrideId && overrideId !== schemaName ? overrideId : schemaName;
13884
+ this.indexSchemaName(schemaName, filePath);
13885
+ if (finalName !== schemaName) {
13886
+ this.indexSchemaName(finalName, filePath);
13887
+ }
13888
+ if (!this.zodSchemas[finalName]) {
13889
+ if (overrideId && overrideId !== schemaName) {
13890
+ this.typeToSchemaMapping[schemaName] = overrideId;
13891
+ this.metaIdSchemaNames.add(schemaName);
13892
+ if (this.typeToSchemaMapping[overrideId] === schemaName) {
13893
+ delete this.typeToSchemaMapping[overrideId];
13894
+ }
13895
+ }
13896
+ const variantKey = this.getVariantKey(finalName, this.currentContentType);
13897
+ this.zodSchemas[finalName] = schema;
13898
+ this.schemaVariantRefs.set(variantKey, finalName);
13899
+ } else {
13900
+ logger.warn(`Schema component name '${overrideId ?? finalName}' conflicts with an existing schema, ignoring .meta({ id }) on '${schemaName}'`);
13901
+ }
13902
+ }
13903
+ /**
13904
+ * Derives the conventional Zod schema name from a TypeScript type name.
13905
+ * e.g. "Slider" → "sliderSchema", "SliderItem" → "sliderItemSchema".
13906
+ * Returns null when the input is already a schema name or is not PascalCase.
13907
+ */
13908
+ deriveSchemaNameByConvention(typeName) {
13909
+ if (!typeName || !/^[A-Z]/.test(typeName) || typeName.endsWith("Schema")) {
13910
+ return null;
13911
+ }
13912
+ return typeName[0].toLowerCase() + typeName.slice(1) + "Schema";
13913
+ }
13914
+ /**
13915
+ * Checks whether a Zod schema with the given name is present in schemaDirs
13916
+ * WITHOUT populating the processed-schema cache. A file-content substring check
13917
+ * (the same heuristic used by processFileForZodSchema) is sufficient here: we
13918
+ * only want to know whether the candidate *might* live in schemaDirs so that the
13919
+ * convention mapping can be registered; the actual processing happens later in
13920
+ * the normal convertZodSchemaToOpenApi lookup flow.
13921
+ */
13922
+ locateSchemaByConvention(candidate) {
13923
+ if (this.schemaNameToFiles.has(candidate)) {
13924
+ return true;
13925
+ }
13926
+ for (const dir of this.schemaDirs) {
13927
+ for (const filePath of this.getSchemaFiles(dir)) {
13928
+ try {
13929
+ const content = this.fileAccess.readFileSync(filePath, "utf-8");
13930
+ if (content.includes(candidate)) {
13931
+ return true;
13932
+ }
13933
+ } catch {
13934
+ }
13935
+ }
13936
+ }
13937
+ return false;
13938
+ }
13817
13939
  /**
13818
13940
  * Check if node is Zod schema
13819
13941
  */
@@ -14045,7 +14167,7 @@ function parsePropertyComment(commentValue) {
14045
14167
  function getPropertyOptions(node, contentType) {
14046
14168
  const isOptional = !!node.optional;
14047
14169
  const options = {};
14048
- const leadingComment = node.leadingComments?.[node.leadingComments.length - 1];
14170
+ const leadingComment = node.leadingComments?.findLast((c) => c.type === "CommentBlock" || !node.trailingComments?.length);
14049
14171
  const trailingComment = node.trailingComments?.[0];
14050
14172
  const sourceComment = leadingComment ?? trailingComment;
14051
14173
  if (sourceComment) {
@@ -14448,31 +14570,60 @@ function resolveImportPath(importPath, fromFilePath, fileAccess) {
14448
14570
  }
14449
14571
  return null;
14450
14572
  }
14451
- function collectAllExportedDefinitions(ast, typeDefinitions, currentFile) {
14573
+ function collectFirstMemberLeadingComments(interfaceDecl) {
14574
+ const body = interfaceDecl?.body;
14575
+ if (!body)
14576
+ return [];
14577
+ const firstMember = body.body?.[0];
14578
+ return firstMember?.leadingComments ?? [];
14579
+ }
14580
+ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schemaIdAliases) {
14581
+ function registerDefinition(name, entry, allComments) {
14582
+ if (!typeDefinitions[name]) {
14583
+ typeDefinitions[name] = entry;
14584
+ }
14585
+ const overrideId = extractSchemaIdFromComments(allComments);
14586
+ if (overrideId && schemaIdAliases) {
14587
+ schemaIdAliases[name] = overrideId;
14588
+ if (!typeDefinitions[overrideId]) {
14589
+ typeDefinitions[overrideId] = entry;
14590
+ }
14591
+ }
14592
+ }
14452
14593
  resolvedTraverse(ast, {
14453
14594
  TSTypeAliasDeclaration: (path25) => {
14454
14595
  if (path25.node.id && t12.isIdentifier(path25.node.id)) {
14455
14596
  const name = path25.node.id.name;
14456
- if (!typeDefinitions[name]) {
14457
- const node = path25.node.typeParameters && path25.node.typeParameters.params.length > 0 ? path25.node : path25.node.typeAnnotation;
14458
- typeDefinitions[name] = { node, filePath: currentFile };
14459
- }
14597
+ const node = path25.node.typeParameters && path25.node.typeParameters.params.length > 0 ? path25.node : path25.node.typeAnnotation;
14598
+ const allComments = [
14599
+ ...path25.parentPath?.node?.leadingComments ?? [],
14600
+ ...path25.node.leadingComments ?? [],
14601
+ ...path25.node.trailingComments ?? []
14602
+ ];
14603
+ registerDefinition(name, { node, filePath: currentFile }, allComments);
14460
14604
  }
14461
14605
  },
14462
14606
  TSInterfaceDeclaration: (path25) => {
14463
14607
  if (path25.node.id && t12.isIdentifier(path25.node.id)) {
14464
14608
  const name = path25.node.id.name;
14465
- if (!typeDefinitions[name]) {
14466
- typeDefinitions[name] = { node: path25.node, filePath: currentFile };
14467
- }
14609
+ const allComments = [
14610
+ ...path25.parentPath?.node?.leadingComments ?? [],
14611
+ ...path25.node.leadingComments ?? [],
14612
+ ...path25.node.trailingComments ?? [],
14613
+ ...collectFirstMemberLeadingComments(path25.node)
14614
+ ];
14615
+ registerDefinition(name, { node: path25.node, filePath: currentFile }, allComments);
14468
14616
  }
14469
14617
  },
14470
14618
  TSEnumDeclaration: (path25) => {
14471
14619
  if (path25.node.id && t12.isIdentifier(path25.node.id)) {
14472
14620
  const name = path25.node.id.name;
14473
- if (!typeDefinitions[name]) {
14474
- typeDefinitions[name] = { node: path25.node, filePath: currentFile };
14475
- }
14621
+ const allComments = [
14622
+ ...path25.parentPath?.node?.leadingComments ?? [],
14623
+ ...path25.node.leadingComments ?? [],
14624
+ ...path25.node.trailingComments ?? []
14625
+ ];
14626
+ registerDefinition(name, { node: path25.node, filePath: currentFile }, allComments);
14476
14627
  }
14477
14628
  },
14478
14629
  ExportNamedDeclaration: (path25) => {
@@ -14480,19 +14631,26 @@ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile) {
14480
14631
  const interfaceDecl = path25.node.declaration;
14481
14632
  if (interfaceDecl.id && t12.isIdentifier(interfaceDecl.id)) {
14482
14633
  const name = interfaceDecl.id.name;
14483
- if (!typeDefinitions[name]) {
14484
- typeDefinitions[name] = { node: interfaceDecl, filePath: currentFile };
14485
- }
14634
+ const allComments = [
14635
+ ...path25.node.leadingComments ?? [],
14636
+ ...interfaceDecl.leadingComments ?? [],
14637
+ ...interfaceDecl.trailingComments ?? [],
14638
+ ...collectFirstMemberLeadingComments(interfaceDecl)
14639
+ ];
14640
+ registerDefinition(name, { node: interfaceDecl, filePath: currentFile }, allComments);
14486
14641
  }
14487
14642
  }
14488
14643
  if (t12.isTSTypeAliasDeclaration(path25.node.declaration)) {
14489
14644
  const typeDecl = path25.node.declaration;
14490
14645
  if (typeDecl.id && t12.isIdentifier(typeDecl.id)) {
14491
14646
  const name = typeDecl.id.name;
14492
- if (!typeDefinitions[name]) {
14493
- const node = typeDecl.typeParameters && typeDecl.typeParameters.params.length > 0 ? typeDecl : typeDecl.typeAnnotation;
14494
- typeDefinitions[name] = { node, filePath: currentFile };
14495
- }
14647
+ const node = typeDecl.typeParameters && typeDecl.typeParameters.params.length > 0 ? typeDecl : typeDecl.typeAnnotation;
14648
+ const allComments = [
14649
+ ...path25.node.leadingComments ?? [],
14650
+ ...typeDecl.leadingComments ?? [],
14651
+ ...typeDecl.trailingComments ?? []
14652
+ ];
14653
+ registerDefinition(name, { node, filePath: currentFile }, allComments);
14496
14654
  }
14497
14655
  }
14498
14656
  }
@@ -14909,6 +15067,7 @@ var SchemaProcessor = class {
14909
15067
  zodSchemaProcessor = null;
14910
15068
  schemaTypes;
14911
15069
  isResolvingPickOmitBase = false;
15070
+ schemaIdAliases = {};
14912
15071
  fileAccess;
14913
15072
  symbolResolver;
14914
15073
  // Track imports per file for resolving ReturnType<typeof func>
@@ -14949,7 +15108,7 @@ var SchemaProcessor = class {
14949
15108
  getDefinedSchemas() {
14950
15109
  const filteredSchemas = {};
14951
15110
  Object.entries(this.openapiDefinitions).forEach(([key, value]) => {
14952
- if (!this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key)) {
15111
+ if (!this.schemaIdAliases[key] && !this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key)) {
14953
15112
  filteredSchemas[key] = value;
14954
15113
  }
14955
15114
  });
@@ -14964,6 +15123,10 @@ var SchemaProcessor = class {
14964
15123
  if (schemaName.includes("<") && schemaName.includes(">")) {
14965
15124
  return this.resolveGenericTypeFromString(schemaName);
14966
15125
  }
15126
+ const overrideId = this.schemaIdAliases[schemaName];
15127
+ if (overrideId) {
15128
+ return this.findSchemaDefinition(overrideId, contentType);
15129
+ }
14967
15130
  if (this.openapiDefinitions[schemaName]) {
14968
15131
  return this.openapiDefinitions[schemaName];
14969
15132
  }
@@ -15045,6 +15208,7 @@ var SchemaProcessor = class {
15045
15208
  return;
15046
15209
  }
15047
15210
  this.collectImports(ast, filePath);
15211
+ const aliasesBeforeFile = new Set(Object.keys(this.schemaIdAliases));
15048
15212
  this.collectAllExportedDefinitions(ast, filePath);
15049
15213
  collectTopLevelDefinitionNames(ast).forEach((name) => {
15050
15214
  const indexedFiles = this.schemaDefinitionIndex[name];
@@ -15056,6 +15220,16 @@ var SchemaProcessor = class {
15056
15220
  }
15057
15221
  this.schemaDefinitionIndex[name] = [filePath];
15058
15222
  });
15223
+ Object.entries(this.schemaIdAliases).forEach(([originalName, aliasName]) => {
15224
+ if (aliasesBeforeFile.has(originalName))
15225
+ return;
15226
+ if (!this.schemaDefinitionIndex[aliasName]) {
15227
+ this.schemaDefinitionIndex[aliasName] = [];
15228
+ }
15229
+ if (!this.schemaDefinitionIndex[aliasName].includes(filePath)) {
15230
+ this.schemaDefinitionIndex[aliasName].push(filePath);
15231
+ }
15232
+ });
15059
15233
  }
15060
15234
  getParsedSchemaFile(filePath) {
15061
15235
  const cachedAst = this.fileASTCache.get(filePath);
@@ -15094,7 +15268,7 @@ var SchemaProcessor = class {
15094
15268
  * Used when processing imported files to ensure all referenced types are available
15095
15269
  */
15096
15270
  collectAllExportedDefinitions(ast, filePath) {
15097
- collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath);
15271
+ collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath, this.schemaIdAliases);
15098
15272
  }
15099
15273
  collectTypeDefinitions(ast, schemaName, filePath) {
15100
15274
  collectTypeDefinitions(ast, schemaName, this.typeDefinitions, filePath || this.currentFilePath);
@@ -15691,6 +15865,9 @@ var SchemaProcessor = class {
15691
15865
  logger.debug(`Record<...> used with ${node.typeParameters?.params.length ?? 0} type parameters; expected 2`);
15692
15866
  return { type: "object", additionalProperties: true };
15693
15867
  }
15868
+ if ((!node.typeParameters || node.typeParameters.params.length === 0) && this.schemaIdAliases[typeName] && this.openapiDefinitions[this.schemaIdAliases[typeName]]) {
15869
+ return { $ref: `#/components/schemas/${this.schemaIdAliases[typeName]}` };
15870
+ }
15694
15871
  const utilityType = resolveUtilityTypeReference(node, {
15695
15872
  currentFilePath: this.currentFilePath,
15696
15873
  contentType: this.contentType,
@@ -15866,7 +16043,9 @@ var SchemaProcessor = class {
15866
16043
  };
15867
16044
  }
15868
16045
  if (t15.isTSTypeReference(node) && t15.isIdentifier(node.typeName)) {
15869
- return { $ref: `#/components/schemas/${node.typeName.name}` };
16046
+ const refName = node.typeName.name;
16047
+ const aliasedName = this.schemaIdAliases[refName] ?? refName;
16048
+ return { $ref: `#/components/schemas/${aliasedName}` };
15870
16049
  }
15871
16050
  logger.debug("Unrecognized TypeScript type node:", node);
15872
16051
  return { type: "object" };
@@ -16007,7 +16186,8 @@ var SchemaProcessor = class {
16007
16186
  if (this.schemaTypes.includes("zod") && this.zodSchemaConverter) {
16008
16187
  return this.zodSchemaConverter.getSchemaReferenceName(baseTypeName, contentType);
16009
16188
  }
16010
- return baseTypeName;
16189
+ const aliasedName = this.schemaIdAliases[baseTypeName] ?? baseTypeName;
16190
+ return aliasedName;
16011
16191
  }
16012
16192
  /**
16013
16193
  * Parse and resolve a generic type from a string like "MyApiSuccessResponseBody<LLMSResponse>"