next-openapi-gen 0.1.2 → 0.2.1
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 +18 -14
- package/dist/commands/generate.js +21 -21
- package/dist/commands/init.js +111 -104
- package/dist/components/rapidoc.js +4 -4
- package/dist/components/redoc.js +4 -4
- package/dist/components/scalar.js +20 -0
- package/dist/components/stoplight.js +4 -4
- package/dist/components/swagger.js +8 -8
- package/dist/index.js +22 -22
- package/dist/lib/openapi-generator.js +34 -34
- package/dist/lib/route-processor.js +173 -145
- package/dist/lib/schema-processor.js +295 -250
- package/dist/lib/utils.js +88 -83
- package/dist/openapi-template.js +29 -29
- package/dist/types.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Interfaces
|
|
11
11
|
|
|
12
|
+
- Scalar
|
|
12
13
|
- Swagger
|
|
13
14
|
- Redoc
|
|
14
15
|
- Stoplight Elements
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
- **Automatic OpenAPI Generation**: Generate OpenAPI 3.0 documentation from your Next.js routes, automatically parsing TypeScript types for parameters, request bodies and responses. Field comments in TypeScript types are reflected as descriptions in the OpenAPI schema.
|
|
20
21
|
- **Complex TypeScript Types**: Use complex TypeScript types, such as `nested objects`, `arrays`, `enums` and `unions` (mapped to anyOf). This enables a more comprehensive representation of data structures directly in the OpenAPI schema.
|
|
21
22
|
- **JSDoc-Based Documentation**: Document API routes with optional JSDoc comments, including tags like `@openapi`, `@auth`, `@desc`, `@params`, `@body`, and `@response` to easily define route metadata.
|
|
22
|
-
- **Multiple UI Interfaces**: Choose between `Swagger UI`, `Redoc`, `Stoplight Elements` or `RapiDoc` to visualize your API documentation. Customize the interface to fit your preferences.
|
|
23
|
+
- **Multiple UI Interfaces**: Choose between `Scalar`, `Swagger UI`, `Redoc`, `Stoplight Elements` or `RapiDoc` to visualize your API documentation. Customize the interface to fit your preferences.
|
|
23
24
|
- **Real-time Documentation**: As your API evolves, regenerate the OpenAPI documentation with a single command, ensuring your documentation is always up to date.
|
|
24
25
|
- **Easy configuration**: Customize generator behavior using the `next.openapi.json` configuration file, allowing for quick adjustments without modifying the code.
|
|
25
26
|
|
|
@@ -33,20 +34,20 @@ yarn add next-openapi-gen
|
|
|
33
34
|
|
|
34
35
|
### Step 1: Initialize Configuration and Setup
|
|
35
36
|
|
|
36
|
-
Run the following command to generate the `next.openapi.json` configuration file and automatically set up
|
|
37
|
+
Run the following command to generate the `next.openapi.json` configuration file and automatically set up Scalar UI with `/api-docs` routes:
|
|
37
38
|
|
|
38
39
|
```bash
|
|
39
|
-
npx next-openapi-gen init --ui
|
|
40
|
+
npx next-openapi-gen init --ui scalar --docs-url api-docs
|
|
40
41
|
```
|
|
41
42
|
|
|
42
43
|
Parameters:
|
|
43
|
-
- **ui**: `swagger` | `redoc` | `stoplight` | `rapidoc`
|
|
44
|
+
- **ui**: `scalar` | `swagger` | `redoc` | `stoplight` | `rapidoc`
|
|
44
45
|
- **docs-url**: url on which api docs will be visible
|
|
45
46
|
|
|
46
47
|
This command does the following:
|
|
47
48
|
|
|
48
49
|
- Generates a `next.openapi.json` file, which stores the OpenAPI configuration for your project.
|
|
49
|
-
- Installs
|
|
50
|
+
- Installs Scalar UI to provide an API documentation interface.
|
|
50
51
|
- Adds an `/api-docs` route in the Next.js app for visualizing the generated OpenAPI documentation.
|
|
51
52
|
|
|
52
53
|
### Step 2: Add JSDoc Comments to Your API Routes
|
|
@@ -57,7 +58,7 @@ Annotate your API routes using JSDoc comments. Here's an example:
|
|
|
57
58
|
<table>
|
|
58
59
|
<tr>
|
|
59
60
|
<th>Login route</th>
|
|
60
|
-
<th>Swagger</th>
|
|
61
|
+
<th>Scalar / Swagger</th>
|
|
61
62
|
</tr>
|
|
62
63
|
<tr>
|
|
63
64
|
<td>
|
|
@@ -87,13 +88,14 @@ Annotate your API routes using JSDoc comments. Here's an example:
|
|
|
87
88
|
```
|
|
88
89
|
</td>
|
|
89
90
|
<td>
|
|
90
|
-
<img width="340" alt="api-login" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-login.png" alt-text="api-login"/>
|
|
91
|
+
<img width="340" alt="api-login-scalar" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-login-scalar.png" alt-text="api-login"/>
|
|
92
|
+
<img width="340" alt="api-login-swagger" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-login-swagger.png" alt-text="api-login-swagger"/>
|
|
91
93
|
</td>
|
|
92
94
|
</tr>
|
|
93
95
|
|
|
94
96
|
<tr>
|
|
95
97
|
<th>Users route</th>
|
|
96
|
-
<th>Swagger</th>
|
|
98
|
+
<th>Scalar / Swagger</th>
|
|
97
99
|
</tr>
|
|
98
100
|
<tr>
|
|
99
101
|
<td>
|
|
@@ -145,7 +147,8 @@ Annotate your API routes using JSDoc comments. Here's an example:
|
|
|
145
147
|
```
|
|
146
148
|
</td>
|
|
147
149
|
<td>
|
|
148
|
-
<img width="340" alt="api-users" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-users.png" alt-text="api-users"/>
|
|
150
|
+
<img width="340" alt="api-users-scalar" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-users-scalar.png" alt-text="api-users-scalar"/>
|
|
151
|
+
<img width="340" alt="api-users-swagger" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/api-users-swagger.png" alt-text="api-users-swagger"/>
|
|
149
152
|
</td>
|
|
150
153
|
</tr>
|
|
151
154
|
</table>
|
|
@@ -159,11 +162,11 @@ Run the following command to generate the OpenAPI schema based on your API route
|
|
|
159
162
|
npx next-openapi-gen generate
|
|
160
163
|
```
|
|
161
164
|
|
|
162
|
-
This command processes all your API routes, extracts the necessary information from JSDoc comments, and generates the OpenAPI schema, typically saved to a `
|
|
165
|
+
This command processes all your API routes, extracts the necessary information from JSDoc comments, and generates the OpenAPI schema, typically saved to a `openapi.json` file in the `public` folder.
|
|
163
166
|
|
|
164
167
|
### Step 4: View API Documentation
|
|
165
168
|
|
|
166
|
-
With the `/api-docs` route generated from the init command, you can now access your API documentation through
|
|
169
|
+
With the `/api-docs` route generated from the init command, you can now access your API documentation through Scalar UI by navigating to `http://localhost:3000/api-docs`.
|
|
167
170
|
|
|
168
171
|
## JSDoc tags
|
|
169
172
|
|
|
@@ -181,8 +184,8 @@ The `next.openapi.json` file allows you to configure the behavior of the OpenAPI
|
|
|
181
184
|
- **apiDir**: (default: `./src/app/api`) The directory where your API routes are stored.
|
|
182
185
|
- **schemaDir**: (default: `./src`) The directory where your schema definitions are stored.
|
|
183
186
|
- **docsUrl**: (default: `./api-docs`) Route where OpenAPI UI is available.
|
|
184
|
-
- **ui**: (default: `
|
|
185
|
-
- **outputFile**: (default: `./
|
|
187
|
+
- **ui**: (default: `scalar`) OpenAPI UI interface.
|
|
188
|
+
- **outputFile**: (default: `./openapi.json`) The file where the generated OpenAPI specification will be saved in `public` folder.
|
|
186
189
|
- **includeOpenApiRoutes**: (default: `false`) When `true`, the generator will only include routes that have the `@openapi` tag in their JSDoc comments.
|
|
187
190
|
|
|
188
191
|
## Interface providers
|
|
@@ -190,7 +193,8 @@ The `next.openapi.json` file allows you to configure the behavior of the OpenAPI
|
|
|
190
193
|
<div align="center">
|
|
191
194
|
<table>
|
|
192
195
|
<thead>
|
|
193
|
-
<th>
|
|
196
|
+
<th>Scalar</th>
|
|
197
|
+
<th>Swagger</th>
|
|
194
198
|
<th>Redoc</th>
|
|
195
199
|
<th>Stoplight Elements</th>
|
|
196
200
|
<th>RapiDoc</th>
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import fse from "fs-extra";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import ora from "ora";
|
|
5
|
-
import { OpenApiGenerator } from "../lib/openapi-generator.js";
|
|
6
|
-
export async function generate() {
|
|
7
|
-
const spinner = ora("Generating OpenAPI specification...\n").start();
|
|
8
|
-
const generator = new OpenApiGenerator();
|
|
9
|
-
const config = generator.getConfig();
|
|
10
|
-
// Create api dir if not exists
|
|
11
|
-
const apiDir = path.resolve(config.apiDir);
|
|
12
|
-
await fse.ensureDir(apiDir);
|
|
13
|
-
// Create public dir if not exists
|
|
14
|
-
const outputDir = path.resolve("./public");
|
|
15
|
-
await fse.ensureDir(outputDir);
|
|
16
|
-
const apiDocs = generator.generate();
|
|
17
|
-
// Write api docs
|
|
18
|
-
const outputFile = path.join(outputDir, config.outputFile);
|
|
19
|
-
fs.writeFileSync(outputFile, JSON.stringify(apiDocs, null, 2));
|
|
20
|
-
spinner.succeed(`OpenAPI specification generated at ${outputFile}`);
|
|
21
|
-
}
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import fse from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import { OpenApiGenerator } from "../lib/openapi-generator.js";
|
|
6
|
+
export async function generate() {
|
|
7
|
+
const spinner = ora("Generating OpenAPI specification...\n").start();
|
|
8
|
+
const generator = new OpenApiGenerator();
|
|
9
|
+
const config = generator.getConfig();
|
|
10
|
+
// Create api dir if not exists
|
|
11
|
+
const apiDir = path.resolve(config.apiDir);
|
|
12
|
+
await fse.ensureDir(apiDir);
|
|
13
|
+
// Create public dir if not exists
|
|
14
|
+
const outputDir = path.resolve("./public");
|
|
15
|
+
await fse.ensureDir(outputDir);
|
|
16
|
+
const apiDocs = generator.generate();
|
|
17
|
+
// Write api docs
|
|
18
|
+
const outputFile = path.join(outputDir, config.outputFile);
|
|
19
|
+
fs.writeFileSync(outputFile, JSON.stringify(apiDocs, null, 2));
|
|
20
|
+
spinner.succeed(`OpenAPI specification generated at ${outputFile}`);
|
|
21
|
+
}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,104 +1,111 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fse from "fs-extra";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import ora from "ora";
|
|
5
|
-
import { exec } from "child_process";
|
|
6
|
-
import util from "util";
|
|
7
|
-
import openapiTemplate from "../openapi-template.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fse from "fs-extra";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import { exec } from "child_process";
|
|
6
|
+
import util from "util";
|
|
7
|
+
import openapiTemplate from "../openapi-template.js";
|
|
8
|
+
import { scalarDeps, ScalarUI } from "../components/scalar.js";
|
|
9
|
+
import { swaggerDeps, SwaggerUI } from "../components/swagger.js";
|
|
10
|
+
import { redocDeps, RedocUI } from "../components/redoc.js";
|
|
11
|
+
import { stoplightDeps, StoplightUI } from "../components/stoplight.js";
|
|
12
|
+
import { rapidocDeps, RapidocUI } from "../components/rapidoc.js";
|
|
13
|
+
const execPromise = util.promisify(exec);
|
|
14
|
+
const spinner = ora("Initializing project with OpenAPI template...\n");
|
|
15
|
+
const getPackageManager = async () => {
|
|
16
|
+
let currentDir = process.cwd();
|
|
17
|
+
while (true) {
|
|
18
|
+
// Check for Yarn lock file
|
|
19
|
+
if (fs.existsSync(path.join(currentDir, "yarn.lock"))) {
|
|
20
|
+
return "yarn";
|
|
21
|
+
}
|
|
22
|
+
// Check for PNPM lock file
|
|
23
|
+
if (fs.existsSync(path.join(currentDir, "pnpm-lock.yaml"))) {
|
|
24
|
+
return "pnpm";
|
|
25
|
+
}
|
|
26
|
+
// If we're at the root directory, break the loop
|
|
27
|
+
const parentDir = path.dirname(currentDir);
|
|
28
|
+
if (parentDir === currentDir) {
|
|
29
|
+
break; // We've reached the root
|
|
30
|
+
}
|
|
31
|
+
currentDir = parentDir; // Move up one directory
|
|
32
|
+
}
|
|
33
|
+
// Default to npm if no lock files are found
|
|
34
|
+
return "npm";
|
|
35
|
+
};
|
|
36
|
+
function getDocsPage(ui, outputFile) {
|
|
37
|
+
let DocsComponent = ScalarUI;
|
|
38
|
+
if (ui === "swagger") {
|
|
39
|
+
DocsComponent = SwaggerUI;
|
|
40
|
+
}
|
|
41
|
+
else if (ui === "redoc") {
|
|
42
|
+
DocsComponent = RedocUI;
|
|
43
|
+
}
|
|
44
|
+
else if (ui === "stoplight") {
|
|
45
|
+
DocsComponent = StoplightUI;
|
|
46
|
+
}
|
|
47
|
+
else if (ui === "rapidoc") {
|
|
48
|
+
DocsComponent = RapidocUI;
|
|
49
|
+
}
|
|
50
|
+
return DocsComponent(outputFile);
|
|
51
|
+
}
|
|
52
|
+
function getDocsPageDependencies(ui) {
|
|
53
|
+
let deps = [];
|
|
54
|
+
if (ui === "scalar") {
|
|
55
|
+
deps = scalarDeps;
|
|
56
|
+
}
|
|
57
|
+
else if (ui === "swagger") {
|
|
58
|
+
deps = swaggerDeps;
|
|
59
|
+
}
|
|
60
|
+
else if (ui === "redoc") {
|
|
61
|
+
deps = redocDeps;
|
|
62
|
+
}
|
|
63
|
+
else if (ui === "stoplight") {
|
|
64
|
+
deps = stoplightDeps;
|
|
65
|
+
}
|
|
66
|
+
else if (ui === "rapidoc") {
|
|
67
|
+
deps = rapidocDeps;
|
|
68
|
+
}
|
|
69
|
+
return deps.join(" ");
|
|
70
|
+
}
|
|
71
|
+
async function createDocsPage(ui, outputFile) {
|
|
72
|
+
const paths = ["app", "api-docs"];
|
|
73
|
+
const srcPath = path.join(process.cwd(), "src");
|
|
74
|
+
if (fs.existsSync(srcPath)) {
|
|
75
|
+
paths.unshift("src");
|
|
76
|
+
}
|
|
77
|
+
const docsDir = path.join(process.cwd(), ...paths);
|
|
78
|
+
await fs.promises.mkdir(docsDir, { recursive: true });
|
|
79
|
+
const docsPage = getDocsPage(ui, outputFile);
|
|
80
|
+
const componentPath = path.join(docsDir, "page.tsx");
|
|
81
|
+
await fs.promises.writeFile(componentPath, docsPage.trim());
|
|
82
|
+
spinner.succeed(`Created ${paths.join("/")}/page.tsx for ${ui}.`);
|
|
83
|
+
}
|
|
84
|
+
async function installDependencies(ui) {
|
|
85
|
+
const packageManager = await getPackageManager();
|
|
86
|
+
const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"}`;
|
|
87
|
+
const deps = getDocsPageDependencies(ui);
|
|
88
|
+
spinner.succeed(`Installing ${deps} dependencies...`);
|
|
89
|
+
const resp = await execPromise(`${installCmd} ${deps}`);
|
|
90
|
+
spinner.succeed(`Successfully installed ${deps}.`);
|
|
91
|
+
}
|
|
92
|
+
function extendOpenApiTemplate(spec, options) {
|
|
93
|
+
spec.ui = options.ui ?? spec.ui;
|
|
94
|
+
spec.docsUrl = options.docsUrl ?? spec.docsUrl;
|
|
95
|
+
}
|
|
96
|
+
export async function init(options) {
|
|
97
|
+
const { ui, docsUrl } = options;
|
|
98
|
+
spinner.start();
|
|
99
|
+
try {
|
|
100
|
+
const outputPath = path.join(process.cwd(), "next.openapi.json");
|
|
101
|
+
const template = { ...openapiTemplate };
|
|
102
|
+
extendOpenApiTemplate(template, { docsUrl, ui });
|
|
103
|
+
await fse.writeJson(outputPath, template, { spaces: 2 });
|
|
104
|
+
spinner.succeed(`Created OpenAPI template in next.openapi.json`);
|
|
105
|
+
createDocsPage(ui, template.outputFile);
|
|
106
|
+
installDependencies(ui);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
spinner.fail(`Failed to initialize project: ${error.message}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export const rapidocDeps = ["rapidoc"];
|
|
2
|
-
export function RapidocUI(outputFile) {
|
|
1
|
+
export const rapidocDeps = ["rapidoc"];
|
|
2
|
+
export function RapidocUI(outputFile) {
|
|
3
3
|
return `
|
|
4
4
|
"use client";
|
|
5
5
|
|
|
@@ -16,5 +16,5 @@ export default function ApiDocsPage() {
|
|
|
16
16
|
</section>
|
|
17
17
|
);
|
|
18
18
|
}
|
|
19
|
-
`;
|
|
20
|
-
}
|
|
19
|
+
`;
|
|
20
|
+
}
|
package/dist/components/redoc.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export const redocDeps = ["redoc"];
|
|
2
|
-
export function RedocUI(outputFile) {
|
|
1
|
+
export const redocDeps = ["redoc"];
|
|
2
|
+
export function RedocUI(outputFile) {
|
|
3
3
|
return `
|
|
4
4
|
"use client";
|
|
5
5
|
|
|
@@ -12,5 +12,5 @@ export default async function ApiDocsPage() {
|
|
|
12
12
|
</section>
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
|
-
`;
|
|
16
|
-
}
|
|
15
|
+
`;
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const scalarDeps = ["@scalar/api-reference-react", "ajv"];
|
|
2
|
+
export function ScalarUI(outputFile) {
|
|
3
|
+
return `
|
|
4
|
+
"use client";
|
|
5
|
+
|
|
6
|
+
import { ApiReferenceReact } from "@scalar/api-reference-react";
|
|
7
|
+
|
|
8
|
+
import "@scalar/api-reference-react/style.css";
|
|
9
|
+
|
|
10
|
+
export default function ApiDocsPage() {
|
|
11
|
+
return (
|
|
12
|
+
<ApiReferenceReact
|
|
13
|
+
configuration={{
|
|
14
|
+
url: "/${outputFile}",
|
|
15
|
+
}}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export const stoplightDeps = ["@stoplight/elements"];
|
|
2
|
-
export function StoplightUI(outputFile) {
|
|
1
|
+
export const stoplightDeps = ["@stoplight/elements"];
|
|
2
|
+
export function StoplightUI(outputFile) {
|
|
3
3
|
return `
|
|
4
4
|
"use client";
|
|
5
5
|
|
|
@@ -13,5 +13,5 @@ export default function ApiDocsPage() {
|
|
|
13
13
|
</section>
|
|
14
14
|
);
|
|
15
15
|
}
|
|
16
|
-
`;
|
|
17
|
-
}
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export const swaggerDeps = [
|
|
2
|
-
"swagger-ui",
|
|
3
|
-
"swagger-ui-react",
|
|
4
|
-
"--legacy-peer-deps", // @temp: swagger-ui-react does not support React 19 now.
|
|
5
|
-
];
|
|
6
|
-
export function SwaggerUI(outputFile) {
|
|
1
|
+
export const swaggerDeps = [
|
|
2
|
+
"swagger-ui",
|
|
3
|
+
"swagger-ui-react",
|
|
4
|
+
"--legacy-peer-deps", // @temp: swagger-ui-react does not support React 19 now.
|
|
5
|
+
];
|
|
6
|
+
export function SwaggerUI(outputFile) {
|
|
7
7
|
return `
|
|
8
8
|
import "swagger-ui-react/swagger-ui.css";
|
|
9
9
|
|
|
@@ -21,5 +21,5 @@ export default async function ApiDocsPage() {
|
|
|
21
21
|
</section>
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
|
-
`;
|
|
25
|
-
}
|
|
24
|
+
`;
|
|
25
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command, Option } from "commander";
|
|
3
|
-
import { init } from "./commands/init.js";
|
|
4
|
-
import { generate } from "./commands/generate.js";
|
|
5
|
-
const program = new Command();
|
|
6
|
-
program
|
|
7
|
-
.name("next-openapi-gen")
|
|
8
|
-
.version("0.0.1")
|
|
9
|
-
.description("Super fast and easy way to generate OpenAPI documentation for Next.js");
|
|
10
|
-
program
|
|
11
|
-
.command("init")
|
|
12
|
-
.addOption(new Option("-i, --ui <type>", "Specify the UI type, e.g.,
|
|
13
|
-
.choices(["swagger", "redoc", "stoplight", "rapidoc"])
|
|
14
|
-
.default("swagger"))
|
|
15
|
-
.option("-u, --docs-url <url>", "Specify the docs URL", "api-docs")
|
|
16
|
-
.description("Initialize a openapi specification")
|
|
17
|
-
.action(init);
|
|
18
|
-
program
|
|
19
|
-
.command("generate")
|
|
20
|
-
.description("Generate a specification based on api routes")
|
|
21
|
-
.action(generate);
|
|
22
|
-
program.parse(process.argv);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command, Option } from "commander";
|
|
3
|
+
import { init } from "./commands/init.js";
|
|
4
|
+
import { generate } from "./commands/generate.js";
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name("next-openapi-gen")
|
|
8
|
+
.version("0.0.1")
|
|
9
|
+
.description("Super fast and easy way to generate OpenAPI documentation for Next.js");
|
|
10
|
+
program
|
|
11
|
+
.command("init")
|
|
12
|
+
.addOption(new Option("-i, --ui <type>", "Specify the UI type, e.g., scalar")
|
|
13
|
+
.choices(["scalar", "swagger", "redoc", "stoplight", "rapidoc"])
|
|
14
|
+
.default("swagger"))
|
|
15
|
+
.option("-u, --docs-url <url>", "Specify the docs URL", "api-docs")
|
|
16
|
+
.description("Initialize a openapi specification")
|
|
17
|
+
.action(init);
|
|
18
|
+
program
|
|
19
|
+
.command("generate")
|
|
20
|
+
.description("Generate a specification based on api routes")
|
|
21
|
+
.action(generate);
|
|
22
|
+
program.parse(process.argv);
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import { RouteProcessor } from "./route-processor.js";
|
|
4
|
-
import { cleanSpec } from "./utils.js";
|
|
5
|
-
export class OpenApiGenerator {
|
|
6
|
-
config;
|
|
7
|
-
template;
|
|
8
|
-
routeProcessor;
|
|
9
|
-
constructor() {
|
|
10
|
-
const templatePath = path.resolve("./next.openapi.json");
|
|
11
|
-
this.template = JSON.parse(fs.readFileSync(templatePath, "utf-8"));
|
|
12
|
-
this.config = this.getConfig();
|
|
13
|
-
this.routeProcessor = new RouteProcessor(this.config);
|
|
14
|
-
}
|
|
15
|
-
getConfig() {
|
|
16
|
-
// @ts-ignore
|
|
17
|
-
const { apiDir, schemaDir, docsUrl, ui, outputFile, includeOpenApiRoutes } = this.template;
|
|
18
|
-
return {
|
|
19
|
-
apiDir,
|
|
20
|
-
schemaDir,
|
|
21
|
-
docsUrl,
|
|
22
|
-
ui,
|
|
23
|
-
outputFile,
|
|
24
|
-
includeOpenApiRoutes,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
generate() {
|
|
28
|
-
const { apiDir } = this.config;
|
|
29
|
-
this.routeProcessor.scanApiRoutes(apiDir);
|
|
30
|
-
this.template.paths = this.routeProcessor.getSwaggerPaths();
|
|
31
|
-
const openapiSpec = cleanSpec(this.template);
|
|
32
|
-
return openapiSpec;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { RouteProcessor } from "./route-processor.js";
|
|
4
|
+
import { cleanSpec } from "./utils.js";
|
|
5
|
+
export class OpenApiGenerator {
|
|
6
|
+
config;
|
|
7
|
+
template;
|
|
8
|
+
routeProcessor;
|
|
9
|
+
constructor() {
|
|
10
|
+
const templatePath = path.resolve("./next.openapi.json");
|
|
11
|
+
this.template = JSON.parse(fs.readFileSync(templatePath, "utf-8"));
|
|
12
|
+
this.config = this.getConfig();
|
|
13
|
+
this.routeProcessor = new RouteProcessor(this.config);
|
|
14
|
+
}
|
|
15
|
+
getConfig() {
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
const { apiDir, schemaDir, docsUrl, ui, outputFile, includeOpenApiRoutes } = this.template;
|
|
18
|
+
return {
|
|
19
|
+
apiDir,
|
|
20
|
+
schemaDir,
|
|
21
|
+
docsUrl,
|
|
22
|
+
ui,
|
|
23
|
+
outputFile,
|
|
24
|
+
includeOpenApiRoutes,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
generate() {
|
|
28
|
+
const { apiDir } = this.config;
|
|
29
|
+
this.routeProcessor.scanApiRoutes(apiDir);
|
|
30
|
+
this.template.paths = this.routeProcessor.getSwaggerPaths();
|
|
31
|
+
const openapiSpec = cleanSpec(this.template);
|
|
32
|
+
return openapiSpec;
|
|
33
|
+
}
|
|
34
|
+
}
|