next-openapi-gen 0.10.1 → 0.10.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 +21 -21
- package/dist/lib/pages-router-strategy.js +3 -1
- package/dist/lib/route-processor.js +4 -5
- package/dist/lib/schema-processor.js +20 -5
- package/dist/lib/utils.js +12 -0
- package/dist/lib/zod-converter.js +13 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ During initialization (`npx next-openapi-gen init`), a configuration file `next.
|
|
|
72
72
|
],
|
|
73
73
|
"apiDir": "src/app/api", // or "pages/api" for Pages Router
|
|
74
74
|
"routerType": "app", // "app" (default) or "pages" for legacy Pages Router
|
|
75
|
-
"schemaDir": "src/types", // or "src/schemas" for
|
|
75
|
+
"schemaDir": "src/types", // or ["src/types", "src/schemas"] for multiple directories
|
|
76
76
|
"schemaType": "zod", // or "typescript", or ["zod", "typescript"] for multiple
|
|
77
77
|
"schemaFiles": [], // Optional: ["./schemas/models.yaml", "./schemas/api.json"]
|
|
78
78
|
"outputFile": "openapi.json",
|
|
@@ -90,7 +90,7 @@ During initialization (`npx next-openapi-gen init`), a configuration file `next.
|
|
|
90
90
|
| ---------------------- | ----------------------------------------------------------------------------- |
|
|
91
91
|
| `apiDir` | Path to the API directory |
|
|
92
92
|
| `routerType` | Router type: `"app"` (default) or `"pages"` for legacy Pages Router |
|
|
93
|
-
| `schemaDir` | Path to
|
|
93
|
+
| `schemaDir` | Path to types/schemas directory, or array of paths for multiple directories |
|
|
94
94
|
| `schemaType` | Schema type: `"zod"`, `"typescript"`, or `["zod", "typescript"]` for multiple |
|
|
95
95
|
| `schemaFiles` | Optional: Array of custom OpenAPI schema files (YAML/JSON) to include |
|
|
96
96
|
| `outputFile` | Name of the OpenAPI output file |
|
|
@@ -210,25 +210,25 @@ export async function POST(request: NextRequest) {
|
|
|
210
210
|
|
|
211
211
|
## JSDoc Documentation Tags
|
|
212
212
|
|
|
213
|
-
| Tag | Description
|
|
214
|
-
|
|
215
|
-
| `@description` | Endpoint description
|
|
216
|
-
| `@operationId` | Custom operation ID (overrides auto-generated ID)
|
|
217
|
-
| `@pathParams` | Path parameters type/schema
|
|
218
|
-
| `@params` | Query parameters type/schema (use `@queryParams` if you have prettier-plugin-jsdoc conflicts)
|
|
219
|
-
| `@body` | Request body type/schema
|
|
220
|
-
| `@bodyDescription` | Request body description
|
|
221
|
-
| `@response` | Response type/schema with optional code and description (`User`, `201:User`, `User:Description`, `201:User:Description`)
|
|
222
|
-
| `@responseDescription` | Response description
|
|
223
|
-
| `@responseSet` | Override default response set (`public`, `auth`, `none`)
|
|
224
|
-
| `@add` | Add custom response codes (`409:ConflictResponse`, `429`)
|
|
225
|
-
| `@contentType` | Request body content type (`application/json`, `multipart/form-data`)
|
|
226
|
-
| `@auth` | Authorization type (`bearer`, `basic`, `apikey`)
|
|
227
|
-
| `@tag` | Custom tag
|
|
228
|
-
| `@deprecated` | Marks the route as deprecated
|
|
229
|
-
| `@openapi` | Marks the route for inclusion in documentation (if includeOpenApiRoutes is enabled)
|
|
230
|
-
| `@ignore` | Excludes the route from OpenAPI documentation
|
|
231
|
-
| `@method` | HTTP method for Pages Router (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) - required for Pages Router only
|
|
213
|
+
| Tag | Description |
|
|
214
|
+
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
215
|
+
| `@description` | Endpoint description |
|
|
216
|
+
| `@operationId` | Custom operation ID (overrides auto-generated ID) |
|
|
217
|
+
| `@pathParams` | Path parameters type/schema |
|
|
218
|
+
| `@params` | Query parameters type/schema (use `@queryParams` if you have prettier-plugin-jsdoc conflicts) |
|
|
219
|
+
| `@body` | Request body type/schema |
|
|
220
|
+
| `@bodyDescription` | Request body description |
|
|
221
|
+
| `@response` | Response type/schema with optional code and description (`User`, `201:User`, `User:Description`, `201:User:Description`) |
|
|
222
|
+
| `@responseDescription` | Response description |
|
|
223
|
+
| `@responseSet` | Override default response set (`public`, `auth`, `none`) |
|
|
224
|
+
| `@add` | Add custom response codes (`409:ConflictResponse`, `429`) |
|
|
225
|
+
| `@contentType` | Request body content type (`application/json`, `multipart/form-data`) |
|
|
226
|
+
| `@auth` | Authorization type (e.g., `bearer`, `basic`, `apikey`, or a custom type) — supports multiple auths using comma separator (e.g., `bearer, CustomType`) |
|
|
227
|
+
| `@tag` | Custom tag |
|
|
228
|
+
| `@deprecated` | Marks the route as deprecated |
|
|
229
|
+
| `@openapi` | Marks the route for inclusion in documentation (if includeOpenApiRoutes is enabled) |
|
|
230
|
+
| `@ignore` | Excludes the route from OpenAPI documentation |
|
|
231
|
+
| `@method` | HTTP method for Pages Router (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) - required for Pages Router only |
|
|
232
232
|
|
|
233
233
|
## Pages Router Support 🆕
|
|
234
234
|
|
|
@@ -2,7 +2,7 @@ import fs from "fs";
|
|
|
2
2
|
import traverseModule from "@babel/traverse";
|
|
3
3
|
const traverse = traverseModule.default || traverseModule;
|
|
4
4
|
import { HTTP_METHODS } from "./router-strategy.js";
|
|
5
|
-
import { parseTypeScriptFile } from "./utils.js";
|
|
5
|
+
import { parseTypeScriptFile, performAuthPresetReplacements } from "./utils.js";
|
|
6
6
|
export class PagesRouterStrategy {
|
|
7
7
|
config;
|
|
8
8
|
constructor(config) {
|
|
@@ -169,6 +169,8 @@ export class PagesRouterStrategy {
|
|
|
169
169
|
case "apikey":
|
|
170
170
|
auth = "ApiKeyAuth";
|
|
171
171
|
break;
|
|
172
|
+
default:
|
|
173
|
+
auth = performAuthPresetReplacements(authValue);
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
return {
|
|
@@ -250,11 +250,10 @@ export class RouteProcessor {
|
|
|
250
250
|
}
|
|
251
251
|
// Add auth
|
|
252
252
|
if (auth) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
];
|
|
253
|
+
const authItems = auth.split(",").map(item => item.trim());
|
|
254
|
+
definition.security = authItems.map(authItem => ({
|
|
255
|
+
[authItem]: [],
|
|
256
|
+
}));
|
|
258
257
|
}
|
|
259
258
|
if (params) {
|
|
260
259
|
definition.parameters =
|
|
@@ -14,8 +14,14 @@ import { logger } from "./logger.js";
|
|
|
14
14
|
function normalizeSchemaTypes(schemaType) {
|
|
15
15
|
return Array.isArray(schemaType) ? schemaType : [schemaType];
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Normalize schemaDir to array
|
|
19
|
+
*/
|
|
20
|
+
function normalizeSchemaDirs(schemaDir) {
|
|
21
|
+
return Array.isArray(schemaDir) ? schemaDir : [schemaDir];
|
|
22
|
+
}
|
|
17
23
|
export class SchemaProcessor {
|
|
18
|
-
|
|
24
|
+
schemaDirs;
|
|
19
25
|
typeDefinitions = {};
|
|
20
26
|
openapiDefinitions = {};
|
|
21
27
|
contentType = "";
|
|
@@ -31,7 +37,7 @@ export class SchemaProcessor {
|
|
|
31
37
|
importMap = {}; // { filePath: { importName: importPath } }
|
|
32
38
|
currentFilePath = ""; // Track the file being processed
|
|
33
39
|
constructor(schemaDir, schemaType = "typescript", schemaFiles) {
|
|
34
|
-
this.
|
|
40
|
+
this.schemaDirs = normalizeSchemaDirs(schemaDir).map((d) => path.resolve(d));
|
|
35
41
|
this.schemaTypes = normalizeSchemaTypes(schemaType);
|
|
36
42
|
// Initialize Zod converter if Zod is enabled
|
|
37
43
|
if (this.schemaTypes.includes("zod")) {
|
|
@@ -140,9 +146,18 @@ export class SchemaProcessor {
|
|
|
140
146
|
logger.debug(`No Zod schema found for ${schemaName}, trying TypeScript fallback`);
|
|
141
147
|
}
|
|
142
148
|
// Fall back to TypeScript types
|
|
143
|
-
this.
|
|
149
|
+
this.scanAllSchemaDirs(schemaName);
|
|
144
150
|
return this.openapiDefinitions[schemaName] || {};
|
|
145
151
|
}
|
|
152
|
+
scanAllSchemaDirs(schemaName) {
|
|
153
|
+
for (const dir of this.schemaDirs) {
|
|
154
|
+
if (!fs.existsSync(dir)) {
|
|
155
|
+
logger.warn(`Schema directory not found: ${dir}`);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
this.scanSchemaDir(dir, schemaName);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
146
161
|
scanSchemaDir(dir, schemaName) {
|
|
147
162
|
let files = this.directoryCache[dir];
|
|
148
163
|
if (typeof files === "undefined") {
|
|
@@ -1229,7 +1244,7 @@ export class SchemaProcessor {
|
|
|
1229
1244
|
}
|
|
1230
1245
|
const { baseTypeName, typeArguments } = parsed;
|
|
1231
1246
|
// Find the base generic type definition
|
|
1232
|
-
this.
|
|
1247
|
+
this.scanAllSchemaDirs(baseTypeName);
|
|
1233
1248
|
const genericDefEntry = this.typeDefinitions[baseTypeName];
|
|
1234
1249
|
const genericTypeDefinition = genericDefEntry?.node || genericDefEntry;
|
|
1235
1250
|
if (!genericTypeDefinition) {
|
|
@@ -1241,7 +1256,7 @@ export class SchemaProcessor {
|
|
|
1241
1256
|
// If it's a simple type reference (not another generic), find its definition
|
|
1242
1257
|
if (!argTypeName.includes("<") &&
|
|
1243
1258
|
!this.isGenericTypeParameter(argTypeName)) {
|
|
1244
|
-
this.
|
|
1259
|
+
this.scanAllSchemaDirs(argTypeName);
|
|
1245
1260
|
}
|
|
1246
1261
|
});
|
|
1247
1262
|
// Create AST nodes for the type arguments by parsing them
|
package/dist/lib/utils.js
CHANGED
|
@@ -73,6 +73,8 @@ export function extractJSDocComments(path) {
|
|
|
73
73
|
case "apikey":
|
|
74
74
|
auth = "ApiKeyAuth";
|
|
75
75
|
break;
|
|
76
|
+
default:
|
|
77
|
+
auth = performAuthPresetReplacements(value);
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
if (commentValue.includes("@description")) {
|
|
@@ -247,6 +249,16 @@ export function cleanSpec(spec) {
|
|
|
247
249
|
}
|
|
248
250
|
return newSpec;
|
|
249
251
|
}
|
|
252
|
+
const AUTH_PRESET_REPLACEMENTS = {
|
|
253
|
+
bearer: "BearerAuth",
|
|
254
|
+
basic: "BasicAuth",
|
|
255
|
+
apikey: "ApiKeyAuth",
|
|
256
|
+
};
|
|
257
|
+
export function performAuthPresetReplacements(authValue) {
|
|
258
|
+
const authParts = authValue.split(",").map((part) => part.trim());
|
|
259
|
+
const mappedParts = authParts.map((part) => AUTH_PRESET_REPLACEMENTS[part.toLowerCase()] || part);
|
|
260
|
+
return mappedParts.join(",");
|
|
261
|
+
}
|
|
250
262
|
export function getOperationId(routePath, method) {
|
|
251
263
|
const operation = routePath.replaceAll(/\//g, "-").replace(/^-/, "");
|
|
252
264
|
return `${method}-${operation}`;
|
|
@@ -11,7 +11,7 @@ import { DrizzleZodProcessor } from "./drizzle-zod-processor.js";
|
|
|
11
11
|
* Class for converting Zod schemas to OpenAPI specifications
|
|
12
12
|
*/
|
|
13
13
|
export class ZodSchemaConverter {
|
|
14
|
-
|
|
14
|
+
schemaDirs;
|
|
15
15
|
zodSchemas = {};
|
|
16
16
|
processingSchemas = new Set();
|
|
17
17
|
processedModules = new Set();
|
|
@@ -26,7 +26,8 @@ export class ZodSchemaConverter {
|
|
|
26
26
|
currentAST;
|
|
27
27
|
currentImports;
|
|
28
28
|
constructor(schemaDir) {
|
|
29
|
-
|
|
29
|
+
const dirs = Array.isArray(schemaDir) ? schemaDir : [schemaDir];
|
|
30
|
+
this.schemaDirs = dirs.map((d) => path.resolve(d));
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
32
33
|
* Find a Zod schema by name and convert it to OpenAPI spec
|
|
@@ -63,8 +64,12 @@ export class ZodSchemaConverter {
|
|
|
63
64
|
return this.zodSchemas[schemaName];
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
|
-
// Scan schema
|
|
67
|
-
|
|
67
|
+
// Scan schema directories
|
|
68
|
+
for (const dir of this.schemaDirs) {
|
|
69
|
+
this.scanDirectoryForZodSchema(dir, schemaName);
|
|
70
|
+
if (this.zodSchemas[schemaName])
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
68
73
|
// Return the schema if found, or null if not
|
|
69
74
|
if (this.zodSchemas[schemaName]) {
|
|
70
75
|
logger.debug(`Found and processed Zod schema: ${schemaName}`);
|
|
@@ -1554,8 +1559,10 @@ export class ZodSchemaConverter {
|
|
|
1554
1559
|
for (const routeFile of routeFiles) {
|
|
1555
1560
|
this.scanFileForTypeMappings(routeFile);
|
|
1556
1561
|
}
|
|
1557
|
-
// Scan schema
|
|
1558
|
-
|
|
1562
|
+
// Scan schema directories
|
|
1563
|
+
for (const dir of this.schemaDirs) {
|
|
1564
|
+
this.scanDirectoryForTypeMappings(dir);
|
|
1565
|
+
}
|
|
1559
1566
|
}
|
|
1560
1567
|
/**
|
|
1561
1568
|
* Scan a single file for type mappings
|
package/package.json
CHANGED