next-openapi-gen 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,6 +60,7 @@ During initialization (`npx next-openapi-gen init`), a configuration file `next.
60
60
  "schemaDir": "src/types", // or "src/schemas" for Zod schemas
61
61
  "schemaType": "zod", // or "typescript" for TypeScript types
62
62
  "outputFile": "openapi.json",
63
+ "outputDir": "./public",
63
64
  "docsUrl": "/api-docs",
64
65
  "includeOpenApiRoutes": false,
65
66
  "debug": false
@@ -68,18 +69,19 @@ During initialization (`npx next-openapi-gen init`), a configuration file `next.
68
69
 
69
70
  ### Configuration Options
70
71
 
71
- | Option | Description |
72
- | ---------------------- | ------------------------------------------------ |
73
- | `apiDir` | Path to the API directory |
74
- | `schemaDir` | Path to the types/schemas directory |
75
- | `schemaType` | Schema type: `"zod"` or `"typescript"` |
76
- | `outputFile` | Path to the OpenAPI output file |
77
- | `docsUrl` | API documentation URL (for Swagger UI) |
78
- | `includeOpenApiRoutes` | Whether to include only routes with @openapi tag |
79
- | `defaultResponseSet` | Default error response set for all endpoints |
80
- | `responseSets` | Named sets of error response codes |
81
- | `errorConfig` | Error schema configuration |
82
- | `debug` | Enable detailed logging during generation |
72
+ | Option | Description |
73
+ | ---------------------- | ---------------------------------------------------------------------- |
74
+ | `apiDir` | Path to the API directory |
75
+ | `schemaDir` | Path to the types/schemas directory |
76
+ | `schemaType` | Schema type: `"zod"` or `"typescript"` |
77
+ | `outputFile` | Name of the OpenAPI output file |
78
+ | `outputDir` | Directory where OpenAPI file will be generated (default: `"./public"`) |
79
+ | `docsUrl` | API documentation URL (for Swagger UI) |
80
+ | `includeOpenApiRoutes` | Whether to include only routes with @openapi tag |
81
+ | `defaultResponseSet` | Default error response set for all endpoints |
82
+ | `responseSets` | Named sets of error response codes |
83
+ | `errorConfig` | Error schema configuration |
84
+ | `debug` | Enable detailed logging during generation |
83
85
 
84
86
  ## Documenting Your API
85
87
 
@@ -192,7 +194,7 @@ This command will generate OpenAPI documentation based on your API code:
192
194
 
193
195
  - Scan API directories for routes
194
196
  - Analyze types/schemas
195
- - Generate OpenAPI file (`openapi.json`) in `public` folder
197
+ - Generate OpenAPI file (`openapi.json`) in specified output directory (default: `public` folder)
196
198
  - Create Scalar/Swagger UI endpoint and page (if enabled)
197
199
 
198
200
  ### 3. View API Documentation
@@ -10,8 +10,8 @@ export async function generate() {
10
10
  // Create api dir if not exists
11
11
  const apiDir = path.resolve(config.apiDir);
12
12
  await fse.ensureDir(apiDir);
13
- // Create public dir if not exists
14
- const outputDir = path.resolve("./public");
13
+ // Use user-defined output directory
14
+ const outputDir = path.resolve(config.outputDir);
15
15
  await fse.ensureDir(outputDir);
16
16
  const apiDocs = generator.generate();
17
17
  // Write api docs
@@ -17,13 +17,14 @@ export class OpenApiGenerator {
17
17
  }
18
18
  getConfig() {
19
19
  // @ts-ignore
20
- const { apiDir, schemaDir, docsUrl, ui, outputFile, includeOpenApiRoutes, schemaType = "typescript", defaultResponseSet, responseSets, errorConfig, debug } = this.template;
20
+ const { apiDir, schemaDir, docsUrl, ui, outputFile, outputDir, includeOpenApiRoutes, schemaType = "typescript", defaultResponseSet, responseSets, errorConfig, debug } = this.template;
21
21
  return {
22
22
  apiDir,
23
23
  schemaDir,
24
24
  docsUrl,
25
25
  ui,
26
26
  outputFile,
27
+ outputDir,
27
28
  includeOpenApiRoutes,
28
29
  schemaType,
29
30
  defaultResponseSet,
@@ -2,9 +2,8 @@ import * as t from "@babel/types";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
4
  import traverse from "@babel/traverse";
5
- import { parse } from "@babel/parser";
6
5
  import { SchemaProcessor } from "./schema-processor.js";
7
- import { capitalize, extractJSDocComments, extractPathParameters, getOperationId, } from "./utils.js";
6
+ import { capitalize, extractJSDocComments, parseTypeScriptFile, extractPathParameters, getOperationId, } from "./utils.js";
8
7
  import { logger } from "./logger.js";
9
8
  const HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
10
9
  const MUTATION_HTTP_METHODS = ["PATCH", "POST", "PUT"];
@@ -118,10 +117,7 @@ export class RouteProcessor {
118
117
  if (this.processFileTracker[filePath])
119
118
  return;
120
119
  const content = fs.readFileSync(filePath, "utf-8");
121
- const ast = parse(content, {
122
- sourceType: "module",
123
- plugins: ["typescript", "decorators-legacy"],
124
- });
120
+ const ast = parseTypeScriptFile(content);
125
121
  traverse.default(ast, {
126
122
  ExportNamedDeclaration: (path) => {
127
123
  const declaration = path.node.declaration;
@@ -1,8 +1,8 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { parse } from "@babel/parser";
4
3
  import traverse from "@babel/traverse";
5
4
  import * as t from "@babel/types";
5
+ import { parseTypeScriptFile } from "./utils.js";
6
6
  import { ZodSchemaConverter } from "./zod-converter.js";
7
7
  import { logger } from "./logger.js";
8
8
  export class SchemaProcessor {
@@ -167,10 +167,14 @@ export class SchemaProcessor {
167
167
  const enumValues = this.processEnum(typeNode);
168
168
  return enumValues;
169
169
  }
170
- if (t.isTSTypeLiteral(typeNode) || t.isTSInterfaceBody(typeNode) || t.isTSInterfaceDeclaration(typeNode)) {
170
+ if (t.isTSTypeLiteral(typeNode) ||
171
+ t.isTSInterfaceBody(typeNode) ||
172
+ t.isTSInterfaceDeclaration(typeNode)) {
171
173
  const properties = {};
172
174
  // Handle interface extends clause
173
- if (t.isTSInterfaceDeclaration(typeNode) && typeNode.extends && typeNode.extends.length > 0) {
175
+ if (t.isTSInterfaceDeclaration(typeNode) &&
176
+ typeNode.extends &&
177
+ typeNode.extends.length > 0) {
174
178
  typeNode.extends.forEach((extendedType) => {
175
179
  const extendedSchema = this.resolveTSNodeType(extendedType);
176
180
  if (extendedSchema.properties) {
@@ -179,7 +183,9 @@ export class SchemaProcessor {
179
183
  });
180
184
  }
181
185
  // Get members from interface declaration body or direct members
182
- const members = t.isTSInterfaceDeclaration(typeNode) ? typeNode.body.body : typeNode.members;
186
+ const members = t.isTSInterfaceDeclaration(typeNode)
187
+ ? typeNode.body.body
188
+ : typeNode.members;
183
189
  if (members) {
184
190
  (members || []).forEach((member) => {
185
191
  if (t.isTSPropertySignature(member) && t.isIdentifier(member.key)) {
@@ -270,9 +276,9 @@ export class SchemaProcessor {
270
276
  if (t.isIdentifier(node.expression)) {
271
277
  // Convert to TSTypeReference-like structure for processing
272
278
  const syntheticNode = {
273
- type: 'TSTypeReference',
279
+ type: "TSTypeReference",
274
280
  typeName: node.expression,
275
- typeParameters: node.typeParameters
281
+ typeParameters: node.typeParameters,
276
282
  };
277
283
  return this.resolveTSNodeType(syntheticNode);
278
284
  }
@@ -322,13 +328,14 @@ export class SchemaProcessor {
322
328
  const properties = {};
323
329
  const keyNames = this.extractKeysFromLiteralType(keysParam);
324
330
  if (typeName === "Pick") {
325
- keyNames.forEach(key => {
331
+ keyNames.forEach((key) => {
326
332
  if (baseType.properties[key]) {
327
333
  properties[key] = baseType.properties[key];
328
334
  }
329
335
  });
330
336
  }
331
- else { // Omit
337
+ else {
338
+ // Omit
332
339
  Object.entries(baseType.properties).forEach(([key, value]) => {
333
340
  if (!keyNames.includes(key)) {
334
341
  properties[key] = value;
@@ -460,10 +467,7 @@ export class SchemaProcessor {
460
467
  try {
461
468
  // Recognizes different elements of TS like variable, type, interface, enum
462
469
  const content = fs.readFileSync(filePath, "utf-8");
463
- const ast = parse(content, {
464
- sourceType: "module",
465
- plugins: ["typescript", "decorators-legacy"],
466
- });
470
+ const ast = parseTypeScriptFile(content);
467
471
  this.collectTypeDefinitions(ast, schemaName);
468
472
  // Reset the set of processed types before each schema processing
469
473
  this.processingTypes.clear();
package/dist/lib/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { parse } from "@babel/parser";
1
2
  export function capitalize(string) {
2
3
  return string.charAt(0).toUpperCase() + string.slice(1);
3
4
  }
@@ -208,3 +209,22 @@ export function getOperationId(routePath, method) {
208
209
  const operation = routePath.replaceAll(/\//g, "-").replace(/^-/, "");
209
210
  return `${method}-${operation}`;
210
211
  }
212
+ /**
213
+ * Common Babel parser configuration for TypeScript files with JSX support
214
+ */
215
+ const DEFAULT_PARSER_OPTIONS = {
216
+ sourceType: "module",
217
+ plugins: ["typescript", "jsx", "decorators-legacy"],
218
+ };
219
+ /**
220
+ * Parse TypeScript/TSX file content with the standard configuration
221
+ * @param content - File content to parse
222
+ * @param options - Optional parser options to override defaults
223
+ * @returns Parsed AST
224
+ */
225
+ export function parseTypeScriptFile(content, options) {
226
+ return parse(content, {
227
+ ...DEFAULT_PARSER_OPTIONS,
228
+ ...options,
229
+ });
230
+ }
@@ -1,8 +1,8 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { parse } from "@babel/parser";
4
3
  import traverse from "@babel/traverse";
5
4
  import * as t from "@babel/types";
5
+ import { parseTypeScriptFile } from "./utils.js";
6
6
  import { logger } from "./logger.js";
7
7
  /**
8
8
  * Class for converting Zod schemas to OpenAPI specifications
@@ -146,10 +146,7 @@ export class ZodSchemaConverter {
146
146
  return;
147
147
  }
148
148
  // Parse the file
149
- const ast = parse(content, {
150
- sourceType: "module",
151
- plugins: ["typescript", "decorators-legacy"],
152
- });
149
+ const ast = parseTypeScriptFile(content);
153
150
  // Create a map to store imported modules
154
151
  const importedModules = {};
155
152
  // Look for all exported Zod schemas
@@ -459,10 +456,7 @@ export class ZodSchemaConverter {
459
456
  processAllSchemasInFile(filePath) {
460
457
  try {
461
458
  const content = fs.readFileSync(filePath, "utf-8");
462
- const ast = parse(content, {
463
- sourceType: "module",
464
- plugins: ["typescript", "decorators-legacy"],
465
- });
459
+ const ast = parseTypeScriptFile(content);
466
460
  traverse.default(ast, {
467
461
  ExportNamedDeclaration: (path) => {
468
462
  if (t.isVariableDeclaration(path.node.declaration)) {
@@ -1343,10 +1337,7 @@ export class ZodSchemaConverter {
1343
1337
  scanFileForTypeMappings(filePath) {
1344
1338
  try {
1345
1339
  const content = fs.readFileSync(filePath, "utf-8");
1346
- const ast = parse(content, {
1347
- sourceType: "module",
1348
- plugins: ["typescript", "decorators-legacy"],
1349
- });
1340
+ const ast = parseTypeScriptFile(content);
1350
1341
  traverse.default(ast, {
1351
1342
  TSTypeAliasDeclaration: (path) => {
1352
1343
  if (t.isIdentifier(path.node.id)) {
@@ -1413,10 +1404,7 @@ export class ZodSchemaConverter {
1413
1404
  preprocessAllSchemasInFile(filePath) {
1414
1405
  try {
1415
1406
  const content = fs.readFileSync(filePath, "utf-8");
1416
- const ast = parse(content, {
1417
- sourceType: "module",
1418
- plugins: ["typescript", "decorators-legacy"],
1419
- });
1407
+ const ast = parseTypeScriptFile(content);
1420
1408
  // Collect all exported Zod schemas
1421
1409
  traverse.default(ast, {
1422
1410
  ExportNamedDeclaration: (path) => {
@@ -91,6 +91,7 @@ export default {
91
91
  docsUrl: "api-docs",
92
92
  ui: "scalar",
93
93
  outputFile: "openapi.json",
94
+ outputDir: "./public",
94
95
  includeOpenApiRoutes: false,
95
96
  debug: false,
96
97
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-openapi-gen",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "Automatically generate OpenAPI 3.0 documentation from Next.js projects, with support for Zod schemas and TypeScript types.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -42,15 +42,15 @@
42
42
  "node": ">=18.0.0"
43
43
  },
44
44
  "dependencies": {
45
- "@babel/parser": "^7.25.7",
46
- "@babel/traverse": "^7.25.7",
47
- "@babel/types": "^7.25.7",
48
- "commander": "^12.1.0",
49
- "fs-extra": "^10.0.0",
50
- "ora": "^8.1.0"
45
+ "@babel/parser": "^7.28.3",
46
+ "@babel/traverse": "^7.28.3",
47
+ "@babel/types": "^7.28.2",
48
+ "commander": "^14.0.0",
49
+ "fs-extra": "^11.3.1",
50
+ "ora": "^8.2.0"
51
51
  },
52
52
  "devDependencies": {
53
- "@types/node": "^22.7.4",
54
- "typescript": "^4.5.4"
53
+ "@types/node": "^24.3.0",
54
+ "typescript": "^5.9.2"
55
55
  }
56
56
  }