next-openapi-gen 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,16 +4,13 @@ Automatically generate OpenAPI 3.0 documentation from Next.js projects, with sup
4
4
 
5
5
  ## Features
6
6
 
7
- - ✅ Automatic OpenAPI documentation generation from Next.js code
8
- - ✅ Support for Next.js App Router (including `/api/users/[id]/route.ts` routes)
9
- - ✅ TypeScript types support
10
- - ✅ Zod schemas support
11
- - ✅ Drizzle-Zod support - Generate schemas from Drizzle ORM tables 🆕
12
- - ✅ JSDoc comments support
13
- - ✅ Multiple UI interfaces: `Scalar`, `Swagger`, `Redoc`, `Stoplight` and `Rapidoc` available at `/api-docs` url
14
- - ✅ Path parameters detection (`/users/{id}`)
15
- - ✅ Intelligent parameter examples
16
- - ✅ Intuitive CLI for initialization and documentation generation
7
+ - ✅ Automatic OpenAPI 3.0 documentation generation from Next.js App Router
8
+ - ✅ Multiple schema types: `TypeScript`, `Zod`, `Drizzle-Zod`, or `custom YAML/JSON` files 🆕
9
+ - ✅ Mix schema sources simultaneously - perfect for gradual migrations 🆕
10
+ - ✅ JSDoc comments with intelligent parameter examples
11
+ - ✅ Multiple UI interfaces: `Scalar`, `Swagger`, `Redoc`, `Stoplight`, and `RapiDoc` available at `/api-docs` url
12
+ - ✅ Auto-detection of path parameters (e.g., `/users/[id]/route.ts`)
13
+ - ✅ Intuitive CLI for quick setup and generation
17
14
 
18
15
  ## Supported interfaces
19
16
 
@@ -59,7 +56,8 @@ During initialization (`npx next-openapi-gen init`), a configuration file `next.
59
56
  ],
60
57
  "apiDir": "src/app/api",
61
58
  "schemaDir": "src/types", // or "src/schemas" for Zod schemas
62
- "schemaType": "zod", // or "typescript" for TypeScript types
59
+ "schemaType": "zod", // or "typescript", or ["zod", "typescript"] for multiple
60
+ "schemaFiles": [], // Optional: ["./schemas/models.yaml", "./schemas/api.json"]
63
61
  "outputFile": "openapi.json",
64
62
  "outputDir": "./public",
65
63
  "docsUrl": "/api-docs",
@@ -71,20 +69,21 @@ During initialization (`npx next-openapi-gen init`), a configuration file `next.
71
69
 
72
70
  ### Configuration Options
73
71
 
74
- | Option | Description |
75
- | ---------------------- | -------------------------------------------------------------------------- |
76
- | `apiDir` | Path to the API directory |
77
- | `schemaDir` | Path to the types/schemas directory |
78
- | `schemaType` | Schema type: `"zod"` or `"typescript"` |
79
- | `outputFile` | Name of the OpenAPI output file |
80
- | `outputDir` | Directory where OpenAPI file will be generated (default: `"./public"`) |
81
- | `docsUrl` | API documentation URL (for Swagger UI) |
82
- | `includeOpenApiRoutes` | Whether to include only routes with @openapi tag |
83
- | `ignoreRoutes` | Array of route patterns to exclude from documentation (supports wildcards) |
84
- | `defaultResponseSet` | Default error response set for all endpoints |
85
- | `responseSets` | Named sets of error response codes |
86
- | `errorConfig` | Error schema configuration |
87
- | `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"`, `"typescript"`, or `["zod", "typescript"]` for multiple |
77
+ | `schemaFiles` | Optional: Array of custom OpenAPI schema files (YAML/JSON) to include |
78
+ | `outputFile` | Name of the OpenAPI output file |
79
+ | `outputDir` | Directory where OpenAPI file will be generated (default: `"./public"`) |
80
+ | `docsUrl` | API documentation URL (for Swagger UI) |
81
+ | `includeOpenApiRoutes` | Whether to include only routes with @openapi tag |
82
+ | `ignoreRoutes` | Array of route patterns to exclude from documentation (supports wildcards) |
83
+ | `defaultResponseSet` | Default error response set for all endpoints |
84
+ | `responseSets` | Named sets of error response codes |
85
+ | `errorConfig` | Error schema configuration |
86
+ | `debug` | Enable detailed logging during generation |
88
87
 
89
88
  ## Documenting Your API
90
89
 
@@ -766,19 +765,61 @@ export const CreatePostSchema = createInsertSchema(posts, {
766
765
 
767
766
  See the [complete Drizzle-Zod example](./examples/next15-app-drizzle-zod) for a full working implementation with a blog API.
768
767
 
768
+ ## Multiple Schema Types Support 🆕
769
+
770
+ Use **multiple schema types simultaneously** in a single project - perfect for gradual migrations, combining hand-written schemas with generated ones (protobuf, GraphQL), or using existing OpenAPI specs.
771
+
772
+ ### Configuration
773
+
774
+ ```json
775
+ {
776
+ "schemaType": ["zod", "typescript"],
777
+ "schemaDir": "./src/schemas",
778
+ "schemaFiles": ["./schemas/external-api.yaml"]
779
+ }
780
+ ```
781
+
782
+ ### Schema Resolution Priority
783
+
784
+ 1. **Custom files** (highest) - from `schemaFiles` array
785
+ 2. **Zod schemas** (medium) - if `"zod"` in `schemaType`
786
+ 3. **TypeScript types** (fallback) - if `"typescript"` in `schemaType`
787
+
788
+ ### Common Use Cases
789
+
790
+ ```json
791
+ // Gradual TypeScript → Zod migration
792
+ { "schemaType": ["zod", "typescript"] }
793
+
794
+ // Zod + protobuf schemas
795
+ {
796
+ "schemaType": ["zod"],
797
+ "schemaFiles": ["./proto/schemas.yaml"]
798
+ }
799
+
800
+ // Everything together
801
+ {
802
+ "schemaType": ["zod", "typescript"],
803
+ "schemaFiles": ["./openapi-models.yaml"]
804
+ }
805
+ ```
806
+
807
+ Custom schema files support YAML/JSON in OpenAPI 3.0 format. See **[next15-app-mixed-schemas](./examples/next15-app-mixed-schemas)** for a complete working example.
808
+
769
809
  ## Examples
770
810
 
771
811
  This repository includes several complete example projects:
772
812
 
773
813
  ### 📦 Available Examples
774
814
 
775
- | Example | Description | Features |
776
- | --------------------------------------------------------------- | -------------------------- | ----------------------------------------------- |
777
- | **[next15-app-zod](./examples/next15-app-zod)** | Zod schemas example | Users, Products, Orders API with Zod validation |
778
- | **[next15-app-drizzle-zod](./examples/next15-app-drizzle-zod)** | Drizzle-Zod integration 🆕 | Blog API with Drizzle ORM + drizzle-zod |
779
- | **[next15-app-typescript](./examples/next15-app-typescript)** | TypeScript types | API with pure TypeScript type definitions |
780
- | **[next15-app-scalar](./examples/next15-app-scalar)** | Scalar UI | Modern API documentation interface |
781
- | **[next15-app-swagger](./examples/next15-app-swagger)** | Swagger UI | Classic Swagger documentation |
815
+ | Example | Description | Features |
816
+ | --------------------------------------------------------------- | ----------------------- | ----------------------------------------------- |
817
+ | **[next15-app-zod](./examples/next15-app-zod)** | Zod schemas example | Users, Products, Orders API with Zod validation |
818
+ | **[next15-app-drizzle-zod](./examples/next15-app-drizzle-zod)** | Drizzle-Zod integration | Blog API with Drizzle ORM + drizzle-zod |
819
+ | **[next15-app-mixed-schemas](./examples/next15-app-mixed-schemas)** 🆕 | Multiple schema types | Zod + TypeScript + Custom YAML schemas combined |
820
+ | **[next15-app-typescript](./examples/next15-app-typescript)** | TypeScript types | API with pure TypeScript type definitions |
821
+ | **[next15-app-scalar](./examples/next15-app-scalar)** | Scalar UI | Modern API documentation interface |
822
+ | **[next15-app-swagger](./examples/next15-app-swagger)** | Swagger UI | Classic Swagger documentation |
782
823
 
783
824
  ### 🚀 Running Examples
784
825
 
@@ -824,15 +865,15 @@ Visit `http://localhost:3000/api-docs` to see the generated documentation.
824
865
  </table>
825
866
  </div>
826
867
 
827
- ## Learn More
868
+ ## Contributing
869
+
870
+ We welcome contributions! 🎉
871
+
872
+ Please read our [Contributing Guide](CONTRIBUTING.md) for details.
873
+
874
+ ## Changelog
828
875
 
829
- - **[Drizzle-Zod Example](./examples/next15-app-drizzle-zod)** - Complete example with Drizzle ORM integration
830
- - **[Drizzle ORM](https://orm.drizzle.team/)** - TypeScript ORM for SQL databases
831
- - **[drizzle-zod](https://orm.drizzle.team/docs/zod)** - Zod schema generator for Drizzle
832
- - **[Zod Documentation](https://zod.dev/)** - TypeScript-first schema validation
833
- - **[Next.js Documentation](https://nextjs.org/docs)** - React framework documentation
834
- - **[OpenAPI Specification](https://swagger.io/specification/)** - OpenAPI 3.0 spec
835
- - **[Scalar Documentation](https://docs.scalar.com/)** - Modern API documentation UI
876
+ See [CHANGELOG.md](CHANGELOG.md) for release history and changes.
836
877
 
837
878
  ## License
838
879
 
@@ -17,7 +17,7 @@ export class OpenApiGenerator {
17
17
  }
18
18
  getConfig() {
19
19
  // @ts-ignore
20
- const { apiDir, schemaDir, docsUrl, ui, outputFile, outputDir, includeOpenApiRoutes, ignoreRoutes, schemaType = "typescript", defaultResponseSet, responseSets, errorConfig, debug } = this.template;
20
+ const { apiDir, schemaDir, docsUrl, ui, outputFile, outputDir, includeOpenApiRoutes, ignoreRoutes, schemaType = "typescript", schemaFiles, defaultResponseSet, responseSets, errorConfig, debug } = this.template;
21
21
  return {
22
22
  apiDir: apiDir || "./src/app/api",
23
23
  schemaDir: schemaDir || "./src",
@@ -28,6 +28,7 @@ export class OpenApiGenerator {
28
28
  includeOpenApiRoutes: includeOpenApiRoutes || false,
29
29
  ignoreRoutes: ignoreRoutes || [],
30
30
  schemaType,
31
+ schemaFiles: schemaFiles || [],
31
32
  defaultResponseSet,
32
33
  responseSets,
33
34
  errorConfig,
@@ -18,7 +18,7 @@ export class RouteProcessor {
18
18
  processFileTracker = {};
19
19
  constructor(config) {
20
20
  this.config = config;
21
- this.schemaProcessor = new SchemaProcessor(config.schemaDir, config.schemaType);
21
+ this.schemaProcessor = new SchemaProcessor(config.schemaDir, config.schemaType, config.schemaFiles);
22
22
  }
23
23
  buildResponsesFromConfig(dataTypes, method) {
24
24
  const responses = {};
@@ -2,50 +2,107 @@ import fs from "fs";
2
2
  import path from "path";
3
3
  import traverseModule from "@babel/traverse";
4
4
  import * as t from "@babel/types";
5
+ import yaml from "js-yaml";
5
6
  // Handle both ES modules and CommonJS
6
7
  const traverse = traverseModule.default || traverseModule;
7
8
  import { parseTypeScriptFile } from "./utils.js";
8
9
  import { ZodSchemaConverter } from "./zod-converter.js";
9
10
  import { logger } from "./logger.js";
11
+ /**
12
+ * Normalize schemaType to array
13
+ */
14
+ function normalizeSchemaTypes(schemaType) {
15
+ return Array.isArray(schemaType) ? schemaType : [schemaType];
16
+ }
10
17
  export class SchemaProcessor {
11
18
  schemaDir;
12
19
  typeDefinitions = {};
13
20
  openapiDefinitions = {};
14
21
  contentType = "";
22
+ customSchemas = {};
15
23
  directoryCache = {};
16
24
  statCache = {};
17
25
  processSchemaTracker = {};
18
26
  processingTypes = new Set();
19
- zodSchemaConverter;
20
- schemaType;
27
+ zodSchemaConverter = null;
28
+ schemaTypes;
21
29
  isResolvingPickOmitBase = false;
22
- constructor(schemaDir, schemaType = "typescript") {
30
+ constructor(schemaDir, schemaType = "typescript", schemaFiles) {
23
31
  this.schemaDir = path.resolve(schemaDir);
24
- this.schemaType = schemaType;
25
- if (schemaType === "zod") {
32
+ this.schemaTypes = normalizeSchemaTypes(schemaType);
33
+ // Initialize Zod converter if Zod is enabled
34
+ if (this.schemaTypes.includes("zod")) {
26
35
  this.zodSchemaConverter = new ZodSchemaConverter(schemaDir);
27
36
  }
37
+ // Load custom schema files if provided
38
+ if (schemaFiles && schemaFiles.length > 0) {
39
+ this.loadCustomSchemas(schemaFiles);
40
+ }
41
+ }
42
+ /**
43
+ * Load custom OpenAPI schema files (YAML/JSON)
44
+ */
45
+ loadCustomSchemas(schemaFiles) {
46
+ for (const filePath of schemaFiles) {
47
+ try {
48
+ const resolvedPath = path.resolve(filePath);
49
+ if (!fs.existsSync(resolvedPath)) {
50
+ logger.warn(`Schema file not found: ${filePath}`);
51
+ continue;
52
+ }
53
+ const content = fs.readFileSync(resolvedPath, "utf-8");
54
+ const ext = path.extname(filePath).toLowerCase();
55
+ let parsed;
56
+ if (ext === ".yaml" || ext === ".yml") {
57
+ parsed = yaml.load(content);
58
+ }
59
+ else if (ext === ".json") {
60
+ parsed = JSON.parse(content);
61
+ }
62
+ else {
63
+ logger.warn(`Unsupported file type: ${filePath} (use .json, .yaml, or .yml)`);
64
+ continue;
65
+ }
66
+ // Extract schemas from OpenAPI structure or use file content directly
67
+ const schemas = parsed?.components?.schemas || parsed?.schemas || parsed;
68
+ if (typeof schemas === "object" && schemas !== null) {
69
+ Object.assign(this.customSchemas, schemas);
70
+ logger.log(`✓ Loaded custom schemas from: ${filePath}`);
71
+ }
72
+ else {
73
+ logger.warn(`No valid schemas found in ${filePath}. Expected OpenAPI format with components.schemas or plain object.`);
74
+ }
75
+ }
76
+ catch (error) {
77
+ logger.warn(`Failed to load schema file ${filePath}: ${error.message}`);
78
+ }
79
+ }
28
80
  }
29
81
  /**
30
82
  * Get all defined schemas (for components.schemas section)
83
+ * Merges schemas from all sources with proper priority:
84
+ * 1. TypeScript types (lowest priority - base layer)
85
+ * 2. Zod schemas (medium priority)
86
+ * 3. Custom files (highest priority - overrides all)
31
87
  */
32
88
  getDefinedSchemas() {
33
- // Filter out generic type parameters and invalid schema names
89
+ const merged = {};
90
+ // Layer 1: TypeScript types (base layer)
34
91
  const filteredSchemas = {};
35
92
  Object.entries(this.openapiDefinitions).forEach(([key, value]) => {
36
93
  if (!this.isGenericTypeParameter(key) && !this.isInvalidSchemaName(key)) {
37
94
  filteredSchemas[key] = value;
38
95
  }
39
96
  });
40
- // If using Zod, also include all processed Zod schemas
41
- if (this.schemaType === "zod" && this.zodSchemaConverter) {
97
+ Object.assign(merged, filteredSchemas);
98
+ // Layer 2: Zod schemas (if enabled - overrides TypeScript)
99
+ if (this.schemaTypes.includes("zod") && this.zodSchemaConverter) {
42
100
  const zodSchemas = this.zodSchemaConverter.getProcessedSchemas();
43
- return {
44
- ...filteredSchemas,
45
- ...zodSchemas,
46
- };
101
+ Object.assign(merged, zodSchemas);
47
102
  }
48
- return filteredSchemas;
103
+ // Layer 3: Custom files (highest priority - overrides all)
104
+ Object.assign(merged, this.customSchemas);
105
+ return merged;
49
106
  }
50
107
  findSchemaDefinition(schemaName, contentType) {
51
108
  let schemaNode = null;
@@ -55,8 +112,13 @@ export class SchemaProcessor {
55
112
  if (schemaName.includes("<") && schemaName.includes(">")) {
56
113
  return this.resolveGenericTypeFromString(schemaName);
57
114
  }
58
- // Check if we should use Zod schemas
59
- if (this.schemaType === "zod") {
115
+ // Priority 1: Check custom schemas first (highest priority)
116
+ if (this.customSchemas[schemaName]) {
117
+ logger.debug(`Found schema in custom files: ${schemaName}`);
118
+ return this.customSchemas[schemaName];
119
+ }
120
+ // Priority 2: Try Zod schemas if enabled
121
+ if (this.schemaTypes.includes("zod") && this.zodSchemaConverter) {
60
122
  logger.debug(`Looking for Zod schema: ${schemaName}`);
61
123
  // Check type mapping first
62
124
  const mappedSchemaName = this.zodSchemaConverter.typeToSchemaMapping[schemaName];
@@ -160,7 +222,8 @@ export class SchemaProcessor {
160
222
  this.processingTypes.add(typeName);
161
223
  try {
162
224
  // If we are using Zod and the given type is not found yet, try using Zod converter first
163
- if (this.schemaType === "zod" && !this.openapiDefinitions[typeName]) {
225
+ if (this.schemaTypes.includes("zod") &&
226
+ !this.openapiDefinitions[typeName]) {
164
227
  const zodSchema = this.zodSchemaConverter.convertZodSchemaToOpenApi(typeName);
165
228
  if (zodSchema) {
166
229
  this.openapiDefinitions[typeName] = zodSchema;
@@ -182,7 +245,7 @@ export class SchemaProcessor {
182
245
  t.isMemberExpression(typeNode.callee) &&
183
246
  t.isIdentifier(typeNode.callee.object) &&
184
247
  typeNode.callee.object.name === "z") {
185
- if (this.schemaType === "zod") {
248
+ if (this.schemaTypes.includes("zod")) {
186
249
  const zodSchema = this.zodSchemaConverter.processZodNode(typeNode);
187
250
  if (zodSchema) {
188
251
  this.openapiDefinitions[typeName] = zodSchema;
@@ -784,7 +847,7 @@ export class SchemaProcessor {
784
847
  this.findSchemaDefinition(responseType, "response");
785
848
  responses = this.openapiDefinitions[responseType] || {};
786
849
  }
787
- if (this.schemaType === "zod") {
850
+ if (this.schemaTypes.includes("zod")) {
788
851
  const schemasToProcess = [
789
852
  paramsType,
790
853
  pathParamsType,
@@ -87,7 +87,8 @@ export default {
87
87
  },
88
88
  apiDir: "./src/app/api",
89
89
  schemaDir: "./src",
90
- schemaType: "zod", // or "typescript"
90
+ schemaType: "zod", // or "typescript" or ["zod", "typescript"]
91
+ schemaFiles: [], // Optional: ["./openapi-models.yaml", "./schemas.json"]
91
92
  docsUrl: "api-docs",
92
93
  ui: "scalar",
93
94
  outputFile: "openapi.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-openapi-gen",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
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",
@@ -19,7 +19,9 @@
19
19
  "test": "vitest run",
20
20
  "test:watch": "vitest",
21
21
  "test:ui": "vitest --ui",
22
- "test:coverage": "vitest run --coverage"
22
+ "test:coverage": "vitest run --coverage",
23
+ "release": "np --no-cleanup --no-tests",
24
+ "version": "conventional-changelog -p angular -i CHANGELOG.md -s -n .changelogrc.cjs && git add CHANGELOG.md"
23
25
  },
24
26
  "repository": {
25
27
  "type": "git",
@@ -36,7 +38,8 @@
36
38
  "docs",
37
39
  "react",
38
40
  "scalar",
39
- "redoc"
41
+ "redoc",
42
+ "drizzle"
40
43
  ],
41
44
  "publishConfig": {
42
45
  "access": "public"
@@ -52,12 +55,25 @@
52
55
  "@babel/types": "^7.28.2",
53
56
  "commander": "^14.0.0",
54
57
  "fs-extra": "^11.3.1",
58
+ "js-yaml": "^4.1.0",
55
59
  "ora": "^8.2.0"
56
60
  },
57
61
  "devDependencies": {
62
+ "@types/js-yaml": "^4.0.9",
58
63
  "@types/node": "^24.3.0",
59
64
  "@vitest/ui": "^3.2.4",
65
+ "conventional-changelog-cli": "^5.0.0",
66
+ "np": "^10.2.0",
60
67
  "typescript": "^5.9.2",
61
68
  "vitest": "^3.2.4"
69
+ },
70
+ "np": {
71
+ "yarn": false,
72
+ "anyBranch": false,
73
+ "branch": "main",
74
+ "cleanup": false,
75
+ "tests": false,
76
+ "2fa": false,
77
+ "releaseDraft": false
62
78
  }
63
79
  }