next-openapi-gen 0.8.9 → 0.9.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 CHANGED
@@ -14,15 +14,12 @@ Automatically generate OpenAPI 3.0 documentation from Next.js projects, with sup
14
14
 
15
15
  ## Supported interfaces
16
16
 
17
- - Scalar 🆕
17
+ - Scalar 💡(default)
18
18
  - Swagger
19
19
  - Redoc
20
20
  - Stoplight Elements
21
21
  - RapiDoc
22
22
 
23
- > [!TIP]
24
- > You can use the `--ui none` option during initialization to skip UI setup if you only care about generating the OpenAPI documentation.
25
-
26
23
  ## Installation
27
24
 
28
25
  ```bash
@@ -33,14 +30,27 @@ npm install next-openapi-gen --save-dev
33
30
 
34
31
  ```bash
35
32
  # Initialize OpenAPI configuration
36
- npx next-openapi-gen init --ui scalar --docs-url api-docs --schema zod
33
+ npx next-openapi-gen init
37
34
 
38
35
  # Generate OpenAPI documentation
39
36
  npx next-openapi-gen generate
40
37
  ```
41
38
 
42
39
  > [!TIP]
43
- > Use the `--output` option in the `init` command to specify a custom output file for the template. Then you can use the `--template` option in the `generate` command to point to that file.
40
+ > Scalar UI and Zod are set by default
41
+
42
+
43
+ ### Init Command Options
44
+
45
+ | Option | Choices | Default | Description |
46
+ |--------|---------|---------|-------------|
47
+ | `--ui` | `scalar`, `swagger`, `redoc`, `stoplight`, `rapidoc`, `none` | `scalar` | UI framework for API docs |
48
+ | `--schema` | `zod`, `typescript` | `zod` | Schema validation tool |
49
+ | `--docs-url` | any string | `api-docs` | URL path for documentation page |
50
+ | `--output` | any path | `next.openapi.json` | Output file for OpenAPI template |
51
+
52
+ > [!TIP]
53
+ > Use `--ui none` to skip UI setup and only generate the OpenAPI specification file.
44
54
 
45
55
  ## Configuration
46
56
 
@@ -5,13 +5,23 @@ import ora from "ora";
5
5
  import { exec } from "child_process";
6
6
  import util from "util";
7
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";
8
+ import { scalarDeps, scalarDevDeps, ScalarUI } from "../components/scalar.js";
9
+ import { swaggerDeps, swaggerDevDeps, SwaggerUI } from "../components/swagger.js";
10
+ import { redocDeps, redocDevDeps, RedocUI } from "../components/redoc.js";
11
+ import { stoplightDeps, stoplightDevDeps, StoplightUI } from "../components/stoplight.js";
12
+ import { rapidocDeps, rapidocDevDeps, RapidocUI } from "../components/rapidoc.js";
13
13
  const execPromise = util.promisify(exec);
14
14
  const spinner = ora("Initializing project with OpenAPI template...\n");
15
+ async function hasDependency(packageName) {
16
+ try {
17
+ const packageJsonPath = path.join(process.cwd(), "package.json");
18
+ const packageJson = await fse.readJson(packageJsonPath);
19
+ return !!(packageJson.dependencies?.[packageName] || packageJson.devDependencies?.[packageName]);
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
15
25
  const getPackageManager = async () => {
16
26
  let currentDir = process.cwd();
17
27
  while (true) {
@@ -84,6 +94,25 @@ function getDocsPageDependencies(ui) {
84
94
  }
85
95
  return deps.join(" ");
86
96
  }
97
+ function getDocsPageDevDependencies(ui) {
98
+ let devDeps = [];
99
+ if (ui === "scalar") {
100
+ devDeps = scalarDevDeps;
101
+ }
102
+ else if (ui === "swagger") {
103
+ devDeps = swaggerDevDeps;
104
+ }
105
+ else if (ui === "redoc") {
106
+ devDeps = redocDevDeps;
107
+ }
108
+ else if (ui === "stoplight") {
109
+ devDeps = stoplightDevDeps;
110
+ }
111
+ else if (ui === "rapidoc") {
112
+ devDeps = rapidocDevDeps;
113
+ }
114
+ return devDeps.join(" ");
115
+ }
87
116
  async function createDocsPage(ui, outputFile) {
88
117
  if (ui === "none") {
89
118
  return;
@@ -100,17 +129,41 @@ async function createDocsPage(ui, outputFile) {
100
129
  await fs.promises.writeFile(componentPath, docsPage.trim());
101
130
  spinner.succeed(`Created ${paths.join("/")}/page.tsx for ${ui}.`);
102
131
  }
103
- async function installDependencies(ui) {
104
- if (ui === "none") {
105
- return;
106
- }
132
+ async function installDependencies(ui, schema) {
107
133
  const packageManager = await getPackageManager();
108
134
  const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"}`;
109
- const deps = getDocsPageDependencies(ui);
110
- const flags = getDocsPageInstallFlags(ui, packageManager);
111
- spinner.succeed(`Installing ${deps} dependencies...`);
112
- const resp = await execPromise(`${installCmd} ${deps} ${flags}`);
113
- spinner.succeed(`Successfully installed ${deps}.`);
135
+ // Install UI dependencies
136
+ if (ui !== "none") {
137
+ const deps = getDocsPageDependencies(ui);
138
+ const devDeps = getDocsPageDevDependencies(ui);
139
+ const flags = getDocsPageInstallFlags(ui, packageManager);
140
+ if (deps) {
141
+ spinner.succeed(`Installing ${deps} dependencies...`);
142
+ await execPromise(`${installCmd} ${deps} ${flags}`);
143
+ spinner.succeed(`Successfully installed ${deps}.`);
144
+ }
145
+ if (devDeps) {
146
+ const devFlag = packageManager === "npm" ? "--save-dev" : "-D";
147
+ spinner.succeed(`Installing ${devDeps} dev dependencies...`);
148
+ await execPromise(`${installCmd} ${devFlag} ${devDeps} ${flags}`);
149
+ spinner.succeed(`Successfully installed ${devDeps}.`);
150
+ }
151
+ }
152
+ // Install schema dependencies
153
+ const schemaTypes = Array.isArray(schema) ? schema : [schema];
154
+ for (const schemaType of schemaTypes) {
155
+ if (schemaType === "zod" && !(await hasDependency("zod"))) {
156
+ spinner.succeed(`Installing zod...`);
157
+ await execPromise(`${installCmd} zod`);
158
+ spinner.succeed(`Successfully installed zod.`);
159
+ }
160
+ else if (schemaType === "typescript" && !(await hasDependency("typescript"))) {
161
+ const devFlag = packageManager === "npm" ? "--save-dev" : "-D";
162
+ spinner.succeed(`Installing typescript...`);
163
+ await execPromise(`${installCmd} ${devFlag} typescript`);
164
+ spinner.succeed(`Successfully installed typescript.`);
165
+ }
166
+ }
114
167
  }
115
168
  function extendOpenApiTemplate(spec, options) {
116
169
  spec.ui = options.ui ?? spec.ui;
@@ -124,7 +177,7 @@ function getOutputPath(output) {
124
177
  return path.join(process.cwd(), "next.openapi.json");
125
178
  }
126
179
  export async function init(options) {
127
- const { ui, output } = options;
180
+ const { ui, output, schema } = options;
128
181
  spinner.start();
129
182
  try {
130
183
  const outputPath = getOutputPath(output);
@@ -133,7 +186,7 @@ export async function init(options) {
133
186
  await fse.writeJson(outputPath, template, { spaces: 2 });
134
187
  spinner.succeed(`Created OpenAPI template in ${outputPath}`);
135
188
  createDocsPage(ui, template.outputFile);
136
- installDependencies(ui);
189
+ installDependencies(ui, schema);
137
190
  }
138
191
  catch (error) {
139
192
  spinner.fail(`Failed to initialize project: ${error.message}`);
@@ -1,4 +1,5 @@
1
1
  export const rapidocDeps = ["rapidoc"];
2
+ export const rapidocDevDeps = [];
2
3
  export function RapidocUI(outputFile) {
3
4
  return `
4
5
  "use client";
@@ -1,4 +1,5 @@
1
1
  export const redocDeps = ["redoc"];
2
+ export const redocDevDeps = [];
2
3
  export function RedocUI(outputFile) {
3
4
  return `
4
5
  "use client";
@@ -1,4 +1,5 @@
1
1
  export const scalarDeps = ["@scalar/api-reference-react", "ajv"];
2
+ export const scalarDevDeps = [];
2
3
  export function ScalarUI(outputFile) {
3
4
  return `
4
5
  "use client";
@@ -1,4 +1,5 @@
1
1
  export const stoplightDeps = ["@stoplight/elements"];
2
+ export const stoplightDevDeps = [];
2
3
  export function StoplightUI(outputFile) {
3
4
  return `
4
5
  "use client";
@@ -1,4 +1,5 @@
1
1
  export const swaggerDeps = ["swagger-ui", "swagger-ui-react"];
2
+ export const swaggerDevDeps = ["@types/swagger-ui-react"];
2
3
  export function SwaggerUI(outputFile) {
3
4
  return `
4
5
  import "swagger-ui-react/swagger-ui.css";
@@ -6,7 +7,6 @@ import "swagger-ui-react/swagger-ui.css";
6
7
  import dynamic from "next/dynamic";
7
8
 
8
9
  const SwaggerUI = dynamic(() => import("swagger-ui-react"), {
9
- ssr: false,
10
10
  loading: () => <p>Loading Component...</p>,
11
11
  });
12
12
 
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ program
11
11
  .command("init")
12
12
  .addOption(new Option("-i, --ui <type>", "Specify the UI type, e.g., scalar. Use \"none\" for no UI")
13
13
  .choices(["scalar", "swagger", "redoc", "stoplight", "rapidoc", "none"])
14
- .default("swagger"))
14
+ .default("scalar"))
15
15
  .option("-u, --docs-url <url>", "Specify the docs URL", "api-docs")
16
16
  .addOption(new Option("-s, --schema <schemaType>", "Specify the schema tool")
17
17
  .choices(["zod", "typescript"])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-openapi-gen",
3
- "version": "0.8.9",
3
+ "version": "0.9.0",
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",