next-openapi-gen 1.2.2 → 1.3.0

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.
@@ -756,6 +756,17 @@ function mergeJSDocData(target, source) {
756
756
  function cleanComment(commentValue) {
757
757
  return commentValue.replace(/\*\s*/g, "").trim();
758
758
  }
759
+ function extractInternalFlagFromComments(comments) {
760
+ if (!comments)
761
+ return false;
762
+ for (const comment of comments) {
763
+ const cleaned = cleanComment(comment.value);
764
+ if (/@internal\b/.test(cleaned) || /@schema\s+false\b/.test(cleaned)) {
765
+ return true;
766
+ }
767
+ }
768
+ return false;
769
+ }
759
770
  function extractSchemaIdFromComments(comments) {
760
771
  if (!comments)
761
772
  return null;
@@ -1052,7 +1063,8 @@ var INTERNAL_OPENAPI_CONFIG_KEYS = [
1052
1063
  "framework",
1053
1064
  "next",
1054
1065
  "diagnostics",
1055
- "debug"
1066
+ "debug",
1067
+ "excludeSchemas"
1056
1068
  ];
1057
1069
  var AUTH_PRESET_REPLACEMENTS = {
1058
1070
  bearer: "BearerAuth",
@@ -1320,6 +1332,7 @@ function normalizeOpenApiConfig(template) {
1320
1332
  outputDir: template.outputDir ?? DEFAULT_OUTPUT_DIR,
1321
1333
  includeOpenApiRoutes: template.includeOpenApiRoutes ?? DEFAULT_INCLUDE_OPENAPI_ROUTES,
1322
1334
  ignoreRoutes: template.ignoreRoutes ?? [],
1335
+ excludeSchemas: template.excludeSchemas ?? [],
1323
1336
  schemaType: template.schemaType ?? DEFAULT_RUNTIME_SCHEMA_TYPE,
1324
1337
  schemaBackends,
1325
1338
  schemaFiles: template.schemaFiles ?? [],
@@ -11729,6 +11742,11 @@ var ZodSchemaConverter = class {
11729
11742
  schemaNameToFiles = /* @__PURE__ */ new Map();
11730
11743
  /** Per-file import alias for the `zod` module (`import { z as zod }` sets this to `"zod"`). */
11731
11744
  zodImportAlias = /* @__PURE__ */ new Map();
11745
+ /** Schema variable names whose component name was overridden via .meta({ id }). These must
11746
+ * NOT be copied back under the original variable name in the OpenAPI components object. */
11747
+ metaIdSchemaNames = /* @__PURE__ */ new Set();
11748
+ /** Schema variable names marked @internal — excluded from components/schemas output. */
11749
+ internalSchemaNames = /* @__PURE__ */ new Set();
11732
11750
  // Current processing context (set during file processing)
11733
11751
  currentFilePath;
11734
11752
  currentAST;
@@ -11755,7 +11773,14 @@ var ZodSchemaConverter = class {
11755
11773
  }
11756
11774
  logger.debug(`Looking for Zod schema: ${schemaName}`);
11757
11775
  const requestedSchemaName = schemaName;
11758
- const mappedSchemaName = this.typeToSchemaMapping[schemaName];
11776
+ let mappedSchemaName = this.typeToSchemaMapping[schemaName];
11777
+ if (!mappedSchemaName) {
11778
+ const candidate = this.deriveSchemaNameByConvention(schemaName);
11779
+ if (candidate && this.locateSchemaByConvention(candidate)) {
11780
+ this.typeToSchemaMapping[schemaName] = candidate;
11781
+ mappedSchemaName = candidate;
11782
+ }
11783
+ }
11759
11784
  if (mappedSchemaName) {
11760
11785
  logger.debug(`Type '${schemaName}' is mapped to schema '${mappedSchemaName}'`);
11761
11786
  schemaName = mappedSchemaName;
@@ -11805,7 +11830,7 @@ var ZodSchemaConverter = class {
11805
11830
  this.processingSchemas.delete(schemaName);
11806
11831
  if (mappedSchemaName && requestedSchemaName !== schemaName) {
11807
11832
  const resolvedReference = this.getSchemaReferenceName(schemaName, this.currentContentType);
11808
- if (this.zodSchemas[resolvedReference] && !this.zodSchemas[requestedSchemaName]) {
11833
+ if (!this.metaIdSchemaNames.has(requestedSchemaName) && this.zodSchemas[resolvedReference] && !this.zodSchemas[requestedSchemaName]) {
11809
11834
  this.zodSchemas[requestedSchemaName] = this.zodSchemas[resolvedReference];
11810
11835
  }
11811
11836
  this.schemaVariantRefs.set(this.getVariantKey(requestedSchemaName, this.currentContentType), this.zodSchemas[requestedSchemaName] ? requestedSchemaName : resolvedReference);
@@ -13343,7 +13368,13 @@ var ZodSchemaConverter = class {
13343
13368
  * Get all processed Zod schemas
13344
13369
  */
13345
13370
  getProcessedSchemas() {
13346
- return this.zodSchemas;
13371
+ const result = {};
13372
+ for (const [name, schema] of Object.entries(this.zodSchemas)) {
13373
+ if (!this.internalSchemaNames.has(name)) {
13374
+ result[name] = schema;
13375
+ }
13376
+ }
13377
+ return result;
13347
13378
  }
13348
13379
  /**
13349
13380
  * Pre-scan all files to build type mappings
@@ -13395,6 +13426,15 @@ var ZodSchemaConverter = class {
13395
13426
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13396
13427
  const schemaName = declaration.id.name;
13397
13428
  if (this.isZodSchema(declaration.init)) {
13429
+ const decl = path17.node.declaration;
13430
+ const allComments = [
13431
+ ...path17.node.leadingComments ?? [],
13432
+ ...decl?.leadingComments ?? [],
13433
+ ...declaration.leadingComments ?? []
13434
+ ];
13435
+ if (extractInternalFlagFromComments(allComments)) {
13436
+ this.internalSchemaNames.add(schemaName);
13437
+ }
13398
13438
  if (!this.getStoredSchema(schemaName)) {
13399
13439
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13400
13440
  this.processingSchemas.add(schemaName);
@@ -13420,6 +13460,13 @@ var ZodSchemaConverter = class {
13420
13460
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13421
13461
  const schemaName = declaration.id.name;
13422
13462
  if (this.isZodSchema(declaration.init)) {
13463
+ const allComments = [
13464
+ ...path17.node.leadingComments ?? [],
13465
+ ...declaration.leadingComments ?? []
13466
+ ];
13467
+ if (extractInternalFlagFromComments(allComments)) {
13468
+ this.internalSchemaNames.add(schemaName);
13469
+ }
13423
13470
  if (!this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
13424
13471
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13425
13472
  this.processingSchemas.add(schemaName);
@@ -13462,15 +13509,57 @@ var ZodSchemaConverter = class {
13462
13509
  if (finalName !== schemaName) {
13463
13510
  this.indexSchemaName(finalName, filePath);
13464
13511
  }
13465
- if (!this.getStoredSchema(finalName)) {
13512
+ if (!this.zodSchemas[finalName]) {
13466
13513
  if (overrideId && overrideId !== schemaName) {
13467
13514
  this.typeToSchemaMapping[schemaName] = overrideId;
13515
+ this.metaIdSchemaNames.add(schemaName);
13516
+ if (this.typeToSchemaMapping[overrideId] === schemaName) {
13517
+ delete this.typeToSchemaMapping[overrideId];
13518
+ }
13468
13519
  }
13469
- this.storeResolvedSchema(finalName, schema);
13520
+ const variantKey = this.getVariantKey(finalName, this.currentContentType);
13521
+ this.zodSchemas[finalName] = schema;
13522
+ this.schemaVariantRefs.set(variantKey, finalName);
13470
13523
  } else {
13471
13524
  logger.warn(`Schema component name '${overrideId ?? finalName}' conflicts with an existing schema, ignoring .meta({ id }) on '${schemaName}'`);
13472
13525
  }
13473
13526
  }
13527
+ /**
13528
+ * Derives the conventional Zod schema name from a TypeScript type name.
13529
+ * e.g. "Slider" → "sliderSchema", "SliderItem" → "sliderItemSchema".
13530
+ * Returns null when the input is already a schema name or is not PascalCase.
13531
+ */
13532
+ deriveSchemaNameByConvention(typeName) {
13533
+ if (!typeName || !/^[A-Z]/.test(typeName) || typeName.endsWith("Schema")) {
13534
+ return null;
13535
+ }
13536
+ return typeName[0].toLowerCase() + typeName.slice(1) + "Schema";
13537
+ }
13538
+ /**
13539
+ * Checks whether a Zod schema with the given name is present in schemaDirs
13540
+ * WITHOUT populating the processed-schema cache. A file-content substring check
13541
+ * (the same heuristic used by processFileForZodSchema) is sufficient here: we
13542
+ * only want to know whether the candidate *might* live in schemaDirs so that the
13543
+ * convention mapping can be registered; the actual processing happens later in
13544
+ * the normal convertZodSchemaToOpenApi lookup flow.
13545
+ */
13546
+ locateSchemaByConvention(candidate) {
13547
+ if (this.schemaNameToFiles.has(candidate)) {
13548
+ return true;
13549
+ }
13550
+ for (const dir of this.schemaDirs) {
13551
+ for (const filePath of this.getSchemaFiles(dir)) {
13552
+ try {
13553
+ const content = this.fileAccess.readFileSync(filePath, "utf-8");
13554
+ if (content.includes(candidate)) {
13555
+ return true;
13556
+ }
13557
+ } catch {
13558
+ }
13559
+ }
13560
+ }
13561
+ return false;
13562
+ }
13474
13563
  /**
13475
13564
  * Check if node is Zod schema
13476
13565
  */
@@ -14112,7 +14201,7 @@ function collectFirstMemberLeadingComments(interfaceDecl) {
14112
14201
  const firstMember = body.body?.[0];
14113
14202
  return firstMember?.leadingComments ?? [];
14114
14203
  }
14115
- function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schemaIdAliases) {
14204
+ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schemaIdAliases, internalSchemaNames) {
14116
14205
  function registerDefinition(name, entry, allComments) {
14117
14206
  if (!typeDefinitions[name]) {
14118
14207
  typeDefinitions[name] = entry;
@@ -14124,6 +14213,9 @@ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schema
14124
14213
  typeDefinitions[overrideId] = entry;
14125
14214
  }
14126
14215
  }
14216
+ if (internalSchemaNames && extractInternalFlagFromComments(allComments)) {
14217
+ internalSchemaNames.add(name);
14218
+ }
14127
14219
  }
14128
14220
  resolvedTraverse(ast, {
14129
14221
  TSTypeAliasDeclaration: (path17) => {
@@ -14603,6 +14695,7 @@ var SchemaProcessor = class {
14603
14695
  schemaTypes;
14604
14696
  isResolvingPickOmitBase = false;
14605
14697
  schemaIdAliases = {};
14698
+ internalSchemaNames = /* @__PURE__ */ new Set();
14606
14699
  fileAccess;
14607
14700
  symbolResolver;
14608
14701
  // Track imports per file for resolving ReturnType<typeof func>
@@ -14643,7 +14736,7 @@ var SchemaProcessor = class {
14643
14736
  getDefinedSchemas() {
14644
14737
  const filteredSchemas = {};
14645
14738
  Object.entries(this.openapiDefinitions).forEach(([key, value]) => {
14646
- if (!this.schemaIdAliases[key] && !this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key)) {
14739
+ if (!this.schemaIdAliases[key] && !this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key) && !this.internalSchemaNames.has(key)) {
14647
14740
  filteredSchemas[key] = value;
14648
14741
  }
14649
14742
  });
@@ -14653,6 +14746,22 @@ var SchemaProcessor = class {
14653
14746
  this.customSchemaProcessor.getDefinedSchemas()
14654
14747
  ]);
14655
14748
  }
14749
+ getInternalSchemas() {
14750
+ const result = {};
14751
+ for (const name of this.internalSchemaNames) {
14752
+ const def = this.openapiDefinitions[name];
14753
+ if (def)
14754
+ result[name] = def;
14755
+ }
14756
+ if (this.zodSchemaConverter) {
14757
+ for (const name of this.zodSchemaConverter.internalSchemaNames) {
14758
+ const schema = this.zodSchemaConverter.zodSchemas[name];
14759
+ if (schema)
14760
+ result[name] = schema;
14761
+ }
14762
+ }
14763
+ return result;
14764
+ }
14656
14765
  findSchemaDefinition(schemaName, contentType) {
14657
14766
  this.contentType = contentType;
14658
14767
  if (schemaName.includes("<") && schemaName.includes(">")) {
@@ -14803,7 +14912,7 @@ var SchemaProcessor = class {
14803
14912
  * Used when processing imported files to ensure all referenced types are available
14804
14913
  */
14805
14914
  collectAllExportedDefinitions(ast, filePath) {
14806
- collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath, this.schemaIdAliases);
14915
+ collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath, this.schemaIdAliases, this.internalSchemaNames);
14807
14916
  }
14808
14917
  collectTypeDefinitions(ast, schemaName, filePath) {
14809
14918
  collectTypeDefinitions(ast, schemaName, this.typeDefinitions, filePath || this.currentFilePath);
@@ -16789,6 +16898,64 @@ function generateErrorResponsesFromConfig(document, errorConfig) {
16789
16898
  });
16790
16899
  }
16791
16900
 
16901
+ // ../openapi-core/dist/core/exclude-schemas.js
16902
+ function patternToRegExp(pattern) {
16903
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
16904
+ return new RegExp(`^${escaped.replace(/\*/g, ".*")}$`);
16905
+ }
16906
+ function matchExcludePatterns(names, patterns) {
16907
+ if (patterns.length === 0)
16908
+ return [];
16909
+ const regexes = patterns.map(patternToRegExp);
16910
+ return names.filter((name) => regexes.some((re) => re.test(name)));
16911
+ }
16912
+ function applyExcludeSchemas(document, mergedSchemas, excludedSchemas) {
16913
+ const excludedNames = new Set(Object.keys(excludedSchemas));
16914
+ if (excludedNames.size === 0)
16915
+ return;
16916
+ walkAndInline(document, excludedSchemas, excludedNames, /* @__PURE__ */ new Set());
16917
+ for (const name of excludedNames) {
16918
+ delete mergedSchemas[name];
16919
+ }
16920
+ }
16921
+ function walkAndInline(obj, excluded, excludedNames, visiting) {
16922
+ if (!obj || typeof obj !== "object")
16923
+ return;
16924
+ if (Array.isArray(obj)) {
16925
+ for (const item of obj) {
16926
+ walkAndInline(item, excluded, excludedNames, visiting);
16927
+ }
16928
+ return;
16929
+ }
16930
+ const rec = obj;
16931
+ const ref = rec["$ref"];
16932
+ if (typeof ref === "string") {
16933
+ const match = ref.match(/^#\/components\/schemas\/(.+)$/);
16934
+ const name = match?.[1];
16935
+ if (name && excludedNames.has(name)) {
16936
+ if (visiting.has(name)) {
16937
+ logger.warn(`Circular reference to internal schema "${name}", keeping $ref`);
16938
+ return;
16939
+ }
16940
+ const schemaDef = excluded[name];
16941
+ if (schemaDef) {
16942
+ const cloned = JSON.parse(JSON.stringify(schemaDef));
16943
+ delete rec["$ref"];
16944
+ Object.assign(rec, cloned);
16945
+ const newVisiting = new Set(visiting);
16946
+ newVisiting.add(name);
16947
+ for (const key of Object.keys(rec)) {
16948
+ walkAndInline(rec[key], excluded, excludedNames, newVisiting);
16949
+ }
16950
+ return;
16951
+ }
16952
+ }
16953
+ }
16954
+ for (const key of Object.keys(rec)) {
16955
+ walkAndInline(rec[key], excluded, excludedNames, visiting);
16956
+ }
16957
+ }
16958
+
16792
16959
  // ../openapi-core/dist/core/orchestrator.js
16793
16960
  function runGenerationOrchestrator({ config: config2, template, hooks, runtime, createFrameworkSource }) {
16794
16961
  const diagnostics = new DiagnosticsCollector();
@@ -16859,11 +17026,21 @@ function runGenerationOrchestrator({ config: config2, template, hooks, runtime,
16859
17026
  }
16860
17027
  profile.defaultComponentsAndErrorsMs = performance.now() - phaseStartedAt;
16861
17028
  phaseStartedAt = performance.now();
16862
- const definedSchemas = routeProcessor.getSchemaProcessor().getDefinedSchemas();
17029
+ const schemaProcessor = routeProcessor.getSchemaProcessor();
17030
+ const definedSchemas = schemaProcessor.getDefinedSchemas();
16863
17031
  const mergedSchemas = {
16864
17032
  ...document.components.schemas,
16865
17033
  ...definedSchemas
16866
17034
  };
17035
+ const internalSchemas = schemaProcessor.getInternalSchemas();
17036
+ const patternExcludedNames = matchExcludePatterns(Object.keys(mergedSchemas), config2.excludeSchemas ?? []);
17037
+ const allExcludedSchemas = {
17038
+ ...internalSchemas,
17039
+ ...Object.fromEntries(patternExcludedNames.map((name) => [name, mergedSchemas[name]]))
17040
+ };
17041
+ if (Object.keys(allExcludedSchemas).length > 0) {
17042
+ applyExcludeSchemas(document, mergedSchemas, allExcludedSchemas);
17043
+ }
16867
17044
  if (Object.keys(mergedSchemas).length > 0) {
16868
17045
  document.components.schemas = Object.fromEntries(Object.entries(mergedSchemas).sort(([a], [b]) => a.localeCompare(b, "en", { sensitivity: "base" })));
16869
17046
  }
@@ -756,6 +756,17 @@ function mergeJSDocData(target, source) {
756
756
  function cleanComment(commentValue) {
757
757
  return commentValue.replace(/\*\s*/g, "").trim();
758
758
  }
759
+ function extractInternalFlagFromComments(comments) {
760
+ if (!comments)
761
+ return false;
762
+ for (const comment of comments) {
763
+ const cleaned = cleanComment(comment.value);
764
+ if (/@internal\b/.test(cleaned) || /@schema\s+false\b/.test(cleaned)) {
765
+ return true;
766
+ }
767
+ }
768
+ return false;
769
+ }
759
770
  function extractSchemaIdFromComments(comments) {
760
771
  if (!comments)
761
772
  return null;
@@ -1052,7 +1063,8 @@ var INTERNAL_OPENAPI_CONFIG_KEYS = [
1052
1063
  "framework",
1053
1064
  "next",
1054
1065
  "diagnostics",
1055
- "debug"
1066
+ "debug",
1067
+ "excludeSchemas"
1056
1068
  ];
1057
1069
  var AUTH_PRESET_REPLACEMENTS = {
1058
1070
  bearer: "BearerAuth",
@@ -1320,6 +1332,7 @@ function normalizeOpenApiConfig(template) {
1320
1332
  outputDir: template.outputDir ?? DEFAULT_OUTPUT_DIR,
1321
1333
  includeOpenApiRoutes: template.includeOpenApiRoutes ?? DEFAULT_INCLUDE_OPENAPI_ROUTES,
1322
1334
  ignoreRoutes: template.ignoreRoutes ?? [],
1335
+ excludeSchemas: template.excludeSchemas ?? [],
1323
1336
  schemaType: template.schemaType ?? DEFAULT_RUNTIME_SCHEMA_TYPE,
1324
1337
  schemaBackends,
1325
1338
  schemaFiles: template.schemaFiles ?? [],
@@ -11729,6 +11742,11 @@ var ZodSchemaConverter = class {
11729
11742
  schemaNameToFiles = /* @__PURE__ */ new Map();
11730
11743
  /** Per-file import alias for the `zod` module (`import { z as zod }` sets this to `"zod"`). */
11731
11744
  zodImportAlias = /* @__PURE__ */ new Map();
11745
+ /** Schema variable names whose component name was overridden via .meta({ id }). These must
11746
+ * NOT be copied back under the original variable name in the OpenAPI components object. */
11747
+ metaIdSchemaNames = /* @__PURE__ */ new Set();
11748
+ /** Schema variable names marked @internal — excluded from components/schemas output. */
11749
+ internalSchemaNames = /* @__PURE__ */ new Set();
11732
11750
  // Current processing context (set during file processing)
11733
11751
  currentFilePath;
11734
11752
  currentAST;
@@ -11755,7 +11773,14 @@ var ZodSchemaConverter = class {
11755
11773
  }
11756
11774
  logger.debug(`Looking for Zod schema: ${schemaName}`);
11757
11775
  const requestedSchemaName = schemaName;
11758
- const mappedSchemaName = this.typeToSchemaMapping[schemaName];
11776
+ let mappedSchemaName = this.typeToSchemaMapping[schemaName];
11777
+ if (!mappedSchemaName) {
11778
+ const candidate = this.deriveSchemaNameByConvention(schemaName);
11779
+ if (candidate && this.locateSchemaByConvention(candidate)) {
11780
+ this.typeToSchemaMapping[schemaName] = candidate;
11781
+ mappedSchemaName = candidate;
11782
+ }
11783
+ }
11759
11784
  if (mappedSchemaName) {
11760
11785
  logger.debug(`Type '${schemaName}' is mapped to schema '${mappedSchemaName}'`);
11761
11786
  schemaName = mappedSchemaName;
@@ -11805,7 +11830,7 @@ var ZodSchemaConverter = class {
11805
11830
  this.processingSchemas.delete(schemaName);
11806
11831
  if (mappedSchemaName && requestedSchemaName !== schemaName) {
11807
11832
  const resolvedReference = this.getSchemaReferenceName(schemaName, this.currentContentType);
11808
- if (this.zodSchemas[resolvedReference] && !this.zodSchemas[requestedSchemaName]) {
11833
+ if (!this.metaIdSchemaNames.has(requestedSchemaName) && this.zodSchemas[resolvedReference] && !this.zodSchemas[requestedSchemaName]) {
11809
11834
  this.zodSchemas[requestedSchemaName] = this.zodSchemas[resolvedReference];
11810
11835
  }
11811
11836
  this.schemaVariantRefs.set(this.getVariantKey(requestedSchemaName, this.currentContentType), this.zodSchemas[requestedSchemaName] ? requestedSchemaName : resolvedReference);
@@ -13343,7 +13368,13 @@ var ZodSchemaConverter = class {
13343
13368
  * Get all processed Zod schemas
13344
13369
  */
13345
13370
  getProcessedSchemas() {
13346
- return this.zodSchemas;
13371
+ const result = {};
13372
+ for (const [name, schema] of Object.entries(this.zodSchemas)) {
13373
+ if (!this.internalSchemaNames.has(name)) {
13374
+ result[name] = schema;
13375
+ }
13376
+ }
13377
+ return result;
13347
13378
  }
13348
13379
  /**
13349
13380
  * Pre-scan all files to build type mappings
@@ -13395,6 +13426,15 @@ var ZodSchemaConverter = class {
13395
13426
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13396
13427
  const schemaName = declaration.id.name;
13397
13428
  if (this.isZodSchema(declaration.init)) {
13429
+ const decl = path17.node.declaration;
13430
+ const allComments = [
13431
+ ...path17.node.leadingComments ?? [],
13432
+ ...decl?.leadingComments ?? [],
13433
+ ...declaration.leadingComments ?? []
13434
+ ];
13435
+ if (extractInternalFlagFromComments(allComments)) {
13436
+ this.internalSchemaNames.add(schemaName);
13437
+ }
13398
13438
  if (!this.getStoredSchema(schemaName)) {
13399
13439
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13400
13440
  this.processingSchemas.add(schemaName);
@@ -13420,6 +13460,13 @@ var ZodSchemaConverter = class {
13420
13460
  if (t10.isIdentifier(declaration.id) && declaration.init) {
13421
13461
  const schemaName = declaration.id.name;
13422
13462
  if (this.isZodSchema(declaration.init)) {
13463
+ const allComments = [
13464
+ ...path17.node.leadingComments ?? [],
13465
+ ...declaration.leadingComments ?? []
13466
+ ];
13467
+ if (extractInternalFlagFromComments(allComments)) {
13468
+ this.internalSchemaNames.add(schemaName);
13469
+ }
13423
13470
  if (!this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
13424
13471
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13425
13472
  this.processingSchemas.add(schemaName);
@@ -13462,15 +13509,57 @@ var ZodSchemaConverter = class {
13462
13509
  if (finalName !== schemaName) {
13463
13510
  this.indexSchemaName(finalName, filePath);
13464
13511
  }
13465
- if (!this.getStoredSchema(finalName)) {
13512
+ if (!this.zodSchemas[finalName]) {
13466
13513
  if (overrideId && overrideId !== schemaName) {
13467
13514
  this.typeToSchemaMapping[schemaName] = overrideId;
13515
+ this.metaIdSchemaNames.add(schemaName);
13516
+ if (this.typeToSchemaMapping[overrideId] === schemaName) {
13517
+ delete this.typeToSchemaMapping[overrideId];
13518
+ }
13468
13519
  }
13469
- this.storeResolvedSchema(finalName, schema);
13520
+ const variantKey = this.getVariantKey(finalName, this.currentContentType);
13521
+ this.zodSchemas[finalName] = schema;
13522
+ this.schemaVariantRefs.set(variantKey, finalName);
13470
13523
  } else {
13471
13524
  logger.warn(`Schema component name '${overrideId ?? finalName}' conflicts with an existing schema, ignoring .meta({ id }) on '${schemaName}'`);
13472
13525
  }
13473
13526
  }
13527
+ /**
13528
+ * Derives the conventional Zod schema name from a TypeScript type name.
13529
+ * e.g. "Slider" → "sliderSchema", "SliderItem" → "sliderItemSchema".
13530
+ * Returns null when the input is already a schema name or is not PascalCase.
13531
+ */
13532
+ deriveSchemaNameByConvention(typeName) {
13533
+ if (!typeName || !/^[A-Z]/.test(typeName) || typeName.endsWith("Schema")) {
13534
+ return null;
13535
+ }
13536
+ return typeName[0].toLowerCase() + typeName.slice(1) + "Schema";
13537
+ }
13538
+ /**
13539
+ * Checks whether a Zod schema with the given name is present in schemaDirs
13540
+ * WITHOUT populating the processed-schema cache. A file-content substring check
13541
+ * (the same heuristic used by processFileForZodSchema) is sufficient here: we
13542
+ * only want to know whether the candidate *might* live in schemaDirs so that the
13543
+ * convention mapping can be registered; the actual processing happens later in
13544
+ * the normal convertZodSchemaToOpenApi lookup flow.
13545
+ */
13546
+ locateSchemaByConvention(candidate) {
13547
+ if (this.schemaNameToFiles.has(candidate)) {
13548
+ return true;
13549
+ }
13550
+ for (const dir of this.schemaDirs) {
13551
+ for (const filePath of this.getSchemaFiles(dir)) {
13552
+ try {
13553
+ const content = this.fileAccess.readFileSync(filePath, "utf-8");
13554
+ if (content.includes(candidate)) {
13555
+ return true;
13556
+ }
13557
+ } catch {
13558
+ }
13559
+ }
13560
+ }
13561
+ return false;
13562
+ }
13474
13563
  /**
13475
13564
  * Check if node is Zod schema
13476
13565
  */
@@ -14112,7 +14201,7 @@ function collectFirstMemberLeadingComments(interfaceDecl) {
14112
14201
  const firstMember = body.body?.[0];
14113
14202
  return firstMember?.leadingComments ?? [];
14114
14203
  }
14115
- function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schemaIdAliases) {
14204
+ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schemaIdAliases, internalSchemaNames) {
14116
14205
  function registerDefinition(name, entry, allComments) {
14117
14206
  if (!typeDefinitions[name]) {
14118
14207
  typeDefinitions[name] = entry;
@@ -14124,6 +14213,9 @@ function collectAllExportedDefinitions(ast, typeDefinitions, currentFile, schema
14124
14213
  typeDefinitions[overrideId] = entry;
14125
14214
  }
14126
14215
  }
14216
+ if (internalSchemaNames && extractInternalFlagFromComments(allComments)) {
14217
+ internalSchemaNames.add(name);
14218
+ }
14127
14219
  }
14128
14220
  resolvedTraverse(ast, {
14129
14221
  TSTypeAliasDeclaration: (path17) => {
@@ -14603,6 +14695,7 @@ var SchemaProcessor = class {
14603
14695
  schemaTypes;
14604
14696
  isResolvingPickOmitBase = false;
14605
14697
  schemaIdAliases = {};
14698
+ internalSchemaNames = /* @__PURE__ */ new Set();
14606
14699
  fileAccess;
14607
14700
  symbolResolver;
14608
14701
  // Track imports per file for resolving ReturnType<typeof func>
@@ -14643,7 +14736,7 @@ var SchemaProcessor = class {
14643
14736
  getDefinedSchemas() {
14644
14737
  const filteredSchemas = {};
14645
14738
  Object.entries(this.openapiDefinitions).forEach(([key, value]) => {
14646
- if (!this.schemaIdAliases[key] && !this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key)) {
14739
+ if (!this.schemaIdAliases[key] && !this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key) && !this.isBuiltInUtilityType(key) && !this.isFunctionSchema(key) && !this.internalSchemaNames.has(key)) {
14647
14740
  filteredSchemas[key] = value;
14648
14741
  }
14649
14742
  });
@@ -14653,6 +14746,22 @@ var SchemaProcessor = class {
14653
14746
  this.customSchemaProcessor.getDefinedSchemas()
14654
14747
  ]);
14655
14748
  }
14749
+ getInternalSchemas() {
14750
+ const result = {};
14751
+ for (const name of this.internalSchemaNames) {
14752
+ const def = this.openapiDefinitions[name];
14753
+ if (def)
14754
+ result[name] = def;
14755
+ }
14756
+ if (this.zodSchemaConverter) {
14757
+ for (const name of this.zodSchemaConverter.internalSchemaNames) {
14758
+ const schema = this.zodSchemaConverter.zodSchemas[name];
14759
+ if (schema)
14760
+ result[name] = schema;
14761
+ }
14762
+ }
14763
+ return result;
14764
+ }
14656
14765
  findSchemaDefinition(schemaName, contentType) {
14657
14766
  this.contentType = contentType;
14658
14767
  if (schemaName.includes("<") && schemaName.includes(">")) {
@@ -14803,7 +14912,7 @@ var SchemaProcessor = class {
14803
14912
  * Used when processing imported files to ensure all referenced types are available
14804
14913
  */
14805
14914
  collectAllExportedDefinitions(ast, filePath) {
14806
- collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath, this.schemaIdAliases);
14915
+ collectAllExportedDefinitions(ast, this.typeDefinitions, filePath || this.currentFilePath, this.schemaIdAliases, this.internalSchemaNames);
14807
14916
  }
14808
14917
  collectTypeDefinitions(ast, schemaName, filePath) {
14809
14918
  collectTypeDefinitions(ast, schemaName, this.typeDefinitions, filePath || this.currentFilePath);
@@ -16789,6 +16898,64 @@ function generateErrorResponsesFromConfig(document, errorConfig) {
16789
16898
  });
16790
16899
  }
16791
16900
 
16901
+ // ../openapi-core/dist/core/exclude-schemas.js
16902
+ function patternToRegExp(pattern) {
16903
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
16904
+ return new RegExp(`^${escaped.replace(/\*/g, ".*")}$`);
16905
+ }
16906
+ function matchExcludePatterns(names, patterns) {
16907
+ if (patterns.length === 0)
16908
+ return [];
16909
+ const regexes = patterns.map(patternToRegExp);
16910
+ return names.filter((name) => regexes.some((re) => re.test(name)));
16911
+ }
16912
+ function applyExcludeSchemas(document, mergedSchemas, excludedSchemas) {
16913
+ const excludedNames = new Set(Object.keys(excludedSchemas));
16914
+ if (excludedNames.size === 0)
16915
+ return;
16916
+ walkAndInline(document, excludedSchemas, excludedNames, /* @__PURE__ */ new Set());
16917
+ for (const name of excludedNames) {
16918
+ delete mergedSchemas[name];
16919
+ }
16920
+ }
16921
+ function walkAndInline(obj, excluded, excludedNames, visiting) {
16922
+ if (!obj || typeof obj !== "object")
16923
+ return;
16924
+ if (Array.isArray(obj)) {
16925
+ for (const item of obj) {
16926
+ walkAndInline(item, excluded, excludedNames, visiting);
16927
+ }
16928
+ return;
16929
+ }
16930
+ const rec = obj;
16931
+ const ref = rec["$ref"];
16932
+ if (typeof ref === "string") {
16933
+ const match = ref.match(/^#\/components\/schemas\/(.+)$/);
16934
+ const name = match?.[1];
16935
+ if (name && excludedNames.has(name)) {
16936
+ if (visiting.has(name)) {
16937
+ logger.warn(`Circular reference to internal schema "${name}", keeping $ref`);
16938
+ return;
16939
+ }
16940
+ const schemaDef = excluded[name];
16941
+ if (schemaDef) {
16942
+ const cloned = JSON.parse(JSON.stringify(schemaDef));
16943
+ delete rec["$ref"];
16944
+ Object.assign(rec, cloned);
16945
+ const newVisiting = new Set(visiting);
16946
+ newVisiting.add(name);
16947
+ for (const key of Object.keys(rec)) {
16948
+ walkAndInline(rec[key], excluded, excludedNames, newVisiting);
16949
+ }
16950
+ return;
16951
+ }
16952
+ }
16953
+ }
16954
+ for (const key of Object.keys(rec)) {
16955
+ walkAndInline(rec[key], excluded, excludedNames, visiting);
16956
+ }
16957
+ }
16958
+
16792
16959
  // ../openapi-core/dist/core/orchestrator.js
16793
16960
  function runGenerationOrchestrator({ config: config2, template, hooks, runtime, createFrameworkSource }) {
16794
16961
  const diagnostics = new DiagnosticsCollector();
@@ -16859,11 +17026,21 @@ function runGenerationOrchestrator({ config: config2, template, hooks, runtime,
16859
17026
  }
16860
17027
  profile.defaultComponentsAndErrorsMs = performance.now() - phaseStartedAt;
16861
17028
  phaseStartedAt = performance.now();
16862
- const definedSchemas = routeProcessor.getSchemaProcessor().getDefinedSchemas();
17029
+ const schemaProcessor = routeProcessor.getSchemaProcessor();
17030
+ const definedSchemas = schemaProcessor.getDefinedSchemas();
16863
17031
  const mergedSchemas = {
16864
17032
  ...document.components.schemas,
16865
17033
  ...definedSchemas
16866
17034
  };
17035
+ const internalSchemas = schemaProcessor.getInternalSchemas();
17036
+ const patternExcludedNames = matchExcludePatterns(Object.keys(mergedSchemas), config2.excludeSchemas ?? []);
17037
+ const allExcludedSchemas = {
17038
+ ...internalSchemas,
17039
+ ...Object.fromEntries(patternExcludedNames.map((name) => [name, mergedSchemas[name]]))
17040
+ };
17041
+ if (Object.keys(allExcludedSchemas).length > 0) {
17042
+ applyExcludeSchemas(document, mergedSchemas, allExcludedSchemas);
17043
+ }
16867
17044
  if (Object.keys(mergedSchemas).length > 0) {
16868
17045
  document.components.schemas = Object.fromEntries(Object.entries(mergedSchemas).sort(([a], [b]) => a.localeCompare(b, "en", { sensitivity: "base" })));
16869
17046
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-openapi-gen",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "Automatically generate OpenAPI 3.0, 3.1, and 3.2 documentation from Next.js projects, with support for Zod schemas, TypeScript types, and reusable OpenAPI fragments.",
5
5
  "keywords": [
6
6
  "api",