next-openapi-gen 1.2.1 → 1.2.2

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/dist/index.js CHANGED
@@ -950,6 +950,17 @@ function mergeJSDocData(target, source) {
950
950
  function cleanComment(commentValue) {
951
951
  return commentValue.replace(/\*\s*/g, "").trim();
952
952
  }
953
+ function extractSchemaIdFromComments(comments) {
954
+ if (!comments)
955
+ return null;
956
+ for (const comment of comments) {
957
+ const cleaned = cleanComment(comment.value);
958
+ const id = extractTokenValue(cleaned, "@id");
959
+ if (id)
960
+ return id;
961
+ }
962
+ return null;
963
+ }
953
964
  function extractLineValue(commentValue, tag) {
954
965
  return commentValue.match(new RegExp(`${escapeRegExp(tag)}\\s*(.*)`, "m"))?.[1]?.trim() || "";
955
966
  }
@@ -3134,7 +3145,8 @@ var DrizzleZodProcessor = class _DrizzleZodProcessor {
3134
3145
  if (firstArg && !t4.isSpreadElement(firstArg) && !t4.isArgumentPlaceholder(firstArg)) {
3135
3146
  const metadata = _DrizzleZodProcessor.extractStaticObject(firstArg);
3136
3147
  if (metadata) {
3137
- Object.assign(result, metadata);
3148
+ const { id: _id, ...rest } = metadata;
3149
+ Object.assign(result, rest);
3138
3150
  }
3139
3151
  }
3140
3152
  break;
@@ -11418,8 +11430,11 @@ var ZodRuntimeExporter = class {
11418
11430
  case "deprecated":
11419
11431
  return schema.meta({ deprecated: true });
11420
11432
  case "meta": {
11421
- const metadata = node.arguments[0] ? this.buildMetadataObject(node.arguments[0]) : null;
11422
- return metadata ? schema.meta(metadata) : schema;
11433
+ const rawMetadata = node.arguments[0] ? this.buildMetadataObject(node.arguments[0]) : null;
11434
+ if (!rawMetadata)
11435
+ return schema;
11436
+ const { id: _id, ...metadata } = rawMetadata;
11437
+ return Object.keys(metadata).length > 0 ? schema.meta(metadata) : schema;
11423
11438
  }
11424
11439
  case "default":
11425
11440
  case "prefault":
@@ -12209,6 +12224,8 @@ var ZodSchemaConverter = class {
12209
12224
  try {
12210
12225
  const content = this.fileAccess.readFileSync(filePath, "utf-8");
12211
12226
  const ast = parseTypeScriptFile(content);
12227
+ this.currentFilePath = filePath;
12228
+ this.currentAST = ast;
12212
12229
  resolvedTraverse(ast, {
12213
12230
  ExportNamedDeclaration: (path25) => {
12214
12231
  if (t10.isVariableDeclaration(path25.node.declaration)) {
@@ -12223,6 +12240,17 @@ var ZodSchemaConverter = class {
12223
12240
  }
12224
12241
  this.processingSchemas.delete(schemaName);
12225
12242
  }
12243
+ } else if (t10.isIdentifier(declaration.id) && declaration.init) {
12244
+ const schemaName = declaration.id.name;
12245
+ const overrideId = this.extractMetaIdFromNode(declaration.init);
12246
+ if (overrideId && !this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
12247
+ this.processingSchemas.add(schemaName);
12248
+ const schema = this.processZodNode(declaration.init);
12249
+ this.processingSchemas.delete(schemaName);
12250
+ if (schema) {
12251
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
12252
+ }
12253
+ }
12226
12254
  }
12227
12255
  });
12228
12256
  }
@@ -12776,6 +12804,24 @@ var ZodSchemaConverter = class {
12776
12804
  }
12777
12805
  return void 0;
12778
12806
  }
12807
+ extractMetaIdFromNode(node) {
12808
+ if (!t10.isCallExpression(node))
12809
+ return null;
12810
+ if (t10.isMemberExpression(node.callee) && t10.isIdentifier(node.callee.property)) {
12811
+ if (node.callee.property.name === "meta" && node.arguments.length > 0) {
12812
+ const metadata = this.extractStaticJsonValue(node.arguments[0]);
12813
+ if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
12814
+ const id = metadata.id;
12815
+ if (typeof id === "string" && id.length > 0)
12816
+ return id;
12817
+ }
12818
+ }
12819
+ if (t10.isCallExpression(node.callee.object)) {
12820
+ return this.extractMetaIdFromNode(node.callee.object);
12821
+ }
12822
+ }
12823
+ return null;
12824
+ }
12779
12825
  shouldUseRuntimeExport(node) {
12780
12826
  if (!t10.isCallExpression(node)) {
12781
12827
  return false;
@@ -13016,7 +13062,8 @@ var ZodSchemaConverter = class {
13016
13062
  if (node.arguments.length > 0) {
13017
13063
  const metadata = this.extractStaticJsonValue(node.arguments[0]);
13018
13064
  if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
13019
- Object.assign(schema, metadata);
13065
+ const { id: _id, ...rest } = metadata;
13066
+ Object.assign(schema, rest);
13020
13067
  }
13021
13068
  }
13022
13069
  break;
@@ -13302,6 +13349,7 @@ var ZodSchemaConverter = class {
13302
13349
  this.currentFilePath = filePath;
13303
13350
  this.currentAST = ast;
13304
13351
  this.currentImports = importedModules;
13352
+ this.preprocessedFiles.add(filePath);
13305
13353
  resolvedTraverse(ast, {
13306
13354
  ExportNamedDeclaration: (path25) => {
13307
13355
  if (t10.isVariableDeclaration(path25.node.declaration)) {
@@ -13309,15 +13357,19 @@ var ZodSchemaConverter = class {
13309
13357
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13310
13358
  const schemaName = declaration.id.name;
13311
13359
  if (this.isZodSchema(declaration.init)) {
13312
- this.indexSchemaName(schemaName, filePath);
13313
13360
  if (!this.getStoredSchema(schemaName)) {
13314
13361
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13315
13362
  this.processingSchemas.add(schemaName);
13316
13363
  const schema = this.processZodNode(declaration.init);
13364
+ this.processingSchemas.delete(schemaName);
13317
13365
  if (schema) {
13318
- this.storeResolvedSchema(schemaName, schema);
13366
+ const overrideId = this.extractMetaIdFromNode(declaration.init);
13367
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
13368
+ } else {
13369
+ this.indexSchemaName(schemaName, filePath);
13319
13370
  }
13320
- this.processingSchemas.delete(schemaName);
13371
+ } else {
13372
+ this.indexSchemaName(schemaName, filePath);
13321
13373
  }
13322
13374
  }
13323
13375
  }
@@ -13330,22 +13382,25 @@ var ZodSchemaConverter = class {
13330
13382
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13331
13383
  const schemaName = declaration.id.name;
13332
13384
  if (this.isZodSchema(declaration.init)) {
13333
- this.indexSchemaName(schemaName, filePath);
13334
13385
  if (!this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
13335
13386
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13336
13387
  this.processingSchemas.add(schemaName);
13337
13388
  const schema = this.processZodNode(declaration.init);
13389
+ this.processingSchemas.delete(schemaName);
13338
13390
  if (schema) {
13339
- this.storeResolvedSchema(schemaName, schema);
13391
+ const overrideId = this.extractMetaIdFromNode(declaration.init);
13392
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
13393
+ } else {
13394
+ this.indexSchemaName(schemaName, filePath);
13340
13395
  }
13341
- this.processingSchemas.delete(schemaName);
13396
+ } else {
13397
+ this.indexSchemaName(schemaName, filePath);
13342
13398
  }
13343
13399
  }
13344
13400
  }
13345
13401
  });
13346
13402
  }
13347
13403
  });
13348
- this.preprocessedFiles.add(filePath);
13349
13404
  } catch (error2) {
13350
13405
  logger.error(`Error pre-processing file ${filePath}: ${error2}`);
13351
13406
  }
@@ -13363,6 +13418,21 @@ var ZodSchemaConverter = class {
13363
13418
  }
13364
13419
  bucket.add(filePath);
13365
13420
  }
13421
+ applyMetaIdOverride(schemaName, schema, overrideId, filePath) {
13422
+ const finalName = overrideId && overrideId !== schemaName ? overrideId : schemaName;
13423
+ this.indexSchemaName(schemaName, filePath);
13424
+ if (finalName !== schemaName) {
13425
+ this.indexSchemaName(finalName, filePath);
13426
+ }
13427
+ if (!this.getStoredSchema(finalName)) {
13428
+ if (overrideId && overrideId !== schemaName) {
13429
+ this.typeToSchemaMapping[schemaName] = overrideId;
13430
+ }
13431
+ this.storeResolvedSchema(finalName, schema);
13432
+ } else {
13433
+ logger.warn(`Schema component name '${overrideId ?? finalName}' conflicts with an existing schema, ignoring .meta({ id }) on '${schemaName}'`);
13434
+ }
13435
+ }
13366
13436
  /**
13367
13437
  * Check if node is Zod schema
13368
13438
  */
@@ -13594,7 +13664,7 @@ function parsePropertyComment(commentValue) {
13594
13664
  function getPropertyOptions(node, contentType) {
13595
13665
  const isOptional = !!node.optional;
13596
13666
  const options = {};
13597
- const leadingComment = node.leadingComments?.[node.leadingComments.length - 1];
13667
+ const leadingComment = node.leadingComments?.findLast((c) => c.type === "CommentBlock" || !node.trailingComments?.length);
13598
13668
  const trailingComment = node.trailingComments?.[0];
13599
13669
  const sourceComment = leadingComment ?? trailingComment;
13600
13670
  if (sourceComment) {
@@ -13997,31 +14067,60 @@ function resolveImportPath(importPath, fromFilePath, fileAccess) {
13997
14067
  }
13998
14068
  return null;
13999
14069
  }
14000
- function collectAllExportedDefinitions(ast, typeDefinitions, currentFile) {
14070
+ function collectFirstMemberLeadingComments(interfaceDecl) {
14071
+ const body = interfaceDecl?.body;
14072
+ if (!body)
14073
+ return [];
14074
+ const firstMember = body.body?.[0];
14075
+ return firstMember?.leadingComments ?? [];
14076
+ }
14077
+ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schemaIdAliases) {
14078
+ function registerDefinition(name, entry, allComments) {
14079
+ if (!typeDefinitions[name]) {
14080
+ typeDefinitions[name] = entry;
14081
+ }
14082
+ const overrideId = extractSchemaIdFromComments(allComments);
14083
+ if (overrideId && schemaIdAliases) {
14084
+ schemaIdAliases[name] = overrideId;
14085
+ if (!typeDefinitions[overrideId]) {
14086
+ typeDefinitions[overrideId] = entry;
14087
+ }
14088
+ }
14089
+ }
14001
14090
  resolvedTraverse(ast, {
14002
14091
  TSTypeAliasDeclaration: (path25) => {
14003
14092
  if (path25.node.id && t12.isIdentifier(path25.node.id)) {
14004
14093
  const name = path25.node.id.name;
14005
- if (!typeDefinitions[name]) {
14006
- const node = path25.node.typeParameters && path25.node.typeParameters.params.length > 0 ? path25.node : path25.node.typeAnnotation;
14007
- typeDefinitions[name] = { node, filePath: currentFile };
14008
- }
14094
+ const node = path25.node.typeParameters && path25.node.typeParameters.params.length > 0 ? path25.node : path25.node.typeAnnotation;
14095
+ const allComments = [
14096
+ ...path25.parentPath?.node?.leadingComments ?? [],
14097
+ ...path25.node.leadingComments ?? [],
14098
+ ...path25.node.trailingComments ?? []
14099
+ ];
14100
+ registerDefinition(name, { node, filePath: currentFile }, allComments);
14009
14101
  }
14010
14102
  },
14011
14103
  TSInterfaceDeclaration: (path25) => {
14012
14104
  if (path25.node.id && t12.isIdentifier(path25.node.id)) {
14013
14105
  const name = path25.node.id.name;
14014
- if (!typeDefinitions[name]) {
14015
- typeDefinitions[name] = { node: path25.node, filePath: currentFile };
14016
- }
14106
+ const allComments = [
14107
+ ...path25.parentPath?.node?.leadingComments ?? [],
14108
+ ...path25.node.leadingComments ?? [],
14109
+ ...path25.node.trailingComments ?? [],
14110
+ ...collectFirstMemberLeadingComments(path25.node)
14111
+ ];
14112
+ registerDefinition(name, { node: path25.node, filePath: currentFile }, allComments);
14017
14113
  }
14018
14114
  },
14019
14115
  TSEnumDeclaration: (path25) => {
14020
14116
  if (path25.node.id && t12.isIdentifier(path25.node.id)) {
14021
14117
  const name = path25.node.id.name;
14022
- if (!typeDefinitions[name]) {
14023
- typeDefinitions[name] = { node: path25.node, filePath: currentFile };
14024
- }
14118
+ const allComments = [
14119
+ ...path25.parentPath?.node?.leadingComments ?? [],
14120
+ ...path25.node.leadingComments ?? [],
14121
+ ...path25.node.trailingComments ?? []
14122
+ ];
14123
+ registerDefinition(name, { node: path25.node, filePath: currentFile }, allComments);
14025
14124
  }
14026
14125
  },
14027
14126
  ExportNamedDeclaration: (path25) => {
@@ -14029,19 +14128,26 @@ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile) {
14029
14128
  const interfaceDecl = path25.node.declaration;
14030
14129
  if (interfaceDecl.id && t12.isIdentifier(interfaceDecl.id)) {
14031
14130
  const name = interfaceDecl.id.name;
14032
- if (!typeDefinitions[name]) {
14033
- typeDefinitions[name] = { node: interfaceDecl, filePath: currentFile };
14034
- }
14131
+ const allComments = [
14132
+ ...path25.node.leadingComments ?? [],
14133
+ ...interfaceDecl.leadingComments ?? [],
14134
+ ...interfaceDecl.trailingComments ?? [],
14135
+ ...collectFirstMemberLeadingComments(interfaceDecl)
14136
+ ];
14137
+ registerDefinition(name, { node: interfaceDecl, filePath: currentFile }, allComments);
14035
14138
  }
14036
14139
  }
14037
14140
  if (t12.isTSTypeAliasDeclaration(path25.node.declaration)) {
14038
14141
  const typeDecl = path25.node.declaration;
14039
14142
  if (typeDecl.id && t12.isIdentifier(typeDecl.id)) {
14040
14143
  const name = typeDecl.id.name;
14041
- if (!typeDefinitions[name]) {
14042
- const node = typeDecl.typeParameters && typeDecl.typeParameters.params.length > 0 ? typeDecl : typeDecl.typeAnnotation;
14043
- typeDefinitions[name] = { node, filePath: currentFile };
14044
- }
14144
+ const node = typeDecl.typeParameters && typeDecl.typeParameters.params.length > 0 ? typeDecl : typeDecl.typeAnnotation;
14145
+ const allComments = [
14146
+ ...path25.node.leadingComments ?? [],
14147
+ ...typeDecl.leadingComments ?? [],
14148
+ ...typeDecl.trailingComments ?? []
14149
+ ];
14150
+ registerDefinition(name, { node, filePath: currentFile }, allComments);
14045
14151
  }
14046
14152
  }
14047
14153
  }
@@ -14458,6 +14564,7 @@ var SchemaProcessor = class {
14458
14564
  zodSchemaProcessor = null;
14459
14565
  schemaTypes;
14460
14566
  isResolvingPickOmitBase = false;
14567
+ schemaIdAliases = {};
14461
14568
  fileAccess;
14462
14569
  symbolResolver;
14463
14570
  // Track imports per file for resolving ReturnType<typeof func>
@@ -14498,7 +14605,7 @@ var SchemaProcessor = class {
14498
14605
  getDefinedSchemas() {
14499
14606
  const filteredSchemas = {};
14500
14607
  Object.entries(this.openapiDefinitions).forEach(([key, value]) => {
14501
- if (!this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key)) {
14608
+ if (!this.schemaIdAliases[key] && !this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key)) {
14502
14609
  filteredSchemas[key] = value;
14503
14610
  }
14504
14611
  });
@@ -14513,6 +14620,10 @@ var SchemaProcessor = class {
14513
14620
  if (schemaName.includes("<") && schemaName.includes(">")) {
14514
14621
  return this.resolveGenericTypeFromString(schemaName);
14515
14622
  }
14623
+ const overrideId = this.schemaIdAliases[schemaName];
14624
+ if (overrideId) {
14625
+ return this.findSchemaDefinition(overrideId, contentType);
14626
+ }
14516
14627
  if (this.openapiDefinitions[schemaName]) {
14517
14628
  return this.openapiDefinitions[schemaName];
14518
14629
  }
@@ -14594,6 +14705,7 @@ var SchemaProcessor = class {
14594
14705
  return;
14595
14706
  }
14596
14707
  this.collectImports(ast, filePath);
14708
+ const aliasesBeforeFile = new Set(Object.keys(this.schemaIdAliases));
14597
14709
  this.collectAllExportedDefinitions(ast, filePath);
14598
14710
  collectTopLevelDefinitionNames(ast).forEach((name) => {
14599
14711
  const indexedFiles = this.schemaDefinitionIndex[name];
@@ -14605,6 +14717,16 @@ var SchemaProcessor = class {
14605
14717
  }
14606
14718
  this.schemaDefinitionIndex[name] = [filePath];
14607
14719
  });
14720
+ Object.entries(this.schemaIdAliases).forEach(([originalName, aliasName]) => {
14721
+ if (aliasesBeforeFile.has(originalName))
14722
+ return;
14723
+ if (!this.schemaDefinitionIndex[aliasName]) {
14724
+ this.schemaDefinitionIndex[aliasName] = [];
14725
+ }
14726
+ if (!this.schemaDefinitionIndex[aliasName].includes(filePath)) {
14727
+ this.schemaDefinitionIndex[aliasName].push(filePath);
14728
+ }
14729
+ });
14608
14730
  }
14609
14731
  getParsedSchemaFile(filePath) {
14610
14732
  const cachedAst = this.fileASTCache.get(filePath);
@@ -14643,7 +14765,7 @@ var SchemaProcessor = class {
14643
14765
  * Used when processing imported files to ensure all referenced types are available
14644
14766
  */
14645
14767
  collectAllExportedDefinitions(ast, filePath) {
14646
- collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath);
14768
+ collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath, this.schemaIdAliases);
14647
14769
  }
14648
14770
  collectTypeDefinitions(ast, schemaName, filePath) {
14649
14771
  collectTypeDefinitions(ast, schemaName, this.typeDefinitions, filePath || this.currentFilePath);
@@ -15240,6 +15362,9 @@ var SchemaProcessor = class {
15240
15362
  logger.debug(`Record<...> used with ${node.typeParameters?.params.length ?? 0} type parameters; expected 2`);
15241
15363
  return { type: "object", additionalProperties: true };
15242
15364
  }
15365
+ if ((!node.typeParameters || node.typeParameters.params.length === 0) && this.schemaIdAliases[typeName] && this.openapiDefinitions[this.schemaIdAliases[typeName]]) {
15366
+ return { $ref: `#/components/schemas/${this.schemaIdAliases[typeName]}` };
15367
+ }
15243
15368
  const utilityType = resolveUtilityTypeReference(node, {
15244
15369
  currentFilePath: this.currentFilePath,
15245
15370
  contentType: this.contentType,
@@ -15415,7 +15540,9 @@ var SchemaProcessor = class {
15415
15540
  };
15416
15541
  }
15417
15542
  if (t15.isTSTypeReference(node) && t15.isIdentifier(node.typeName)) {
15418
- return { $ref: `#/components/schemas/${node.typeName.name}` };
15543
+ const refName = node.typeName.name;
15544
+ const aliasedName = this.schemaIdAliases[refName] ?? refName;
15545
+ return { $ref: `#/components/schemas/${aliasedName}` };
15419
15546
  }
15420
15547
  logger.debug("Unrecognized TypeScript type node:", node);
15421
15548
  return { type: "object" };
@@ -15556,7 +15683,8 @@ var SchemaProcessor = class {
15556
15683
  if (this.schemaTypes.includes("zod") && this.zodSchemaConverter) {
15557
15684
  return this.zodSchemaConverter.getSchemaReferenceName(baseTypeName, contentType);
15558
15685
  }
15559
- return baseTypeName;
15686
+ const aliasedName = this.schemaIdAliases[baseTypeName] ?? baseTypeName;
15687
+ return aliasedName;
15560
15688
  }
15561
15689
  /**
15562
15690
  * Parse and resolve a generic type from a string like "MyApiSuccessResponseBody<LLMSResponse>"