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.
- package/README.md +22 -21
- package/dist/cli.js +187 -10
- package/dist/index.js +187 -10
- package/dist/next/index.js +187 -10
- package/dist/react-router/index.js +187 -10
- package/dist/vite/index.js +187 -10
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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/dist/vite/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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",
|