next-openapi-gen 0.1.2 → 0.2.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.
@@ -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
+ }
@@ -1,104 +1,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 { swaggerDeps, SwaggerUI } from "../components/swagger.js";
9
- import { redocDeps, RedocUI } from "../components/redoc.js";
10
- import { stoplightDeps, StoplightUI } from "../components/stoplight.js";
11
- import { rapidocDeps, RapidocUI } from "../components/rapidoc.js";
12
- const execPromise = util.promisify(exec);
13
- const spinner = ora("Initializing project with OpenAPI template...\n");
14
- const getPackageManager = async () => {
15
- let currentDir = process.cwd();
16
- while (true) {
17
- // Check for Yarn lock file
18
- if (fs.existsSync(path.join(currentDir, "yarn.lock"))) {
19
- return "yarn";
20
- }
21
- // Check for PNPM lock file
22
- if (fs.existsSync(path.join(currentDir, "pnpm-lock.yaml"))) {
23
- return "pnpm";
24
- }
25
- // If we're at the root directory, break the loop
26
- const parentDir = path.dirname(currentDir);
27
- if (parentDir === currentDir) {
28
- break; // We've reached the root
29
- }
30
- currentDir = parentDir; // Move up one directory
31
- }
32
- // Default to npm if no lock files are found
33
- return "npm";
34
- };
35
- function getDocsPage(ui, outputFile) {
36
- let DocsComponent = SwaggerUI;
37
- if (ui === "redoc") {
38
- DocsComponent = RedocUI;
39
- }
40
- else if (ui === "stoplight") {
41
- DocsComponent = StoplightUI;
42
- }
43
- else if (ui === "rapidoc") {
44
- DocsComponent = RapidocUI;
45
- }
46
- return DocsComponent(outputFile);
47
- }
48
- function getDocsPageDependencies(ui) {
49
- let deps = [];
50
- if (ui === "swagger") {
51
- deps = swaggerDeps;
52
- }
53
- else if (ui === "redoc") {
54
- deps = redocDeps;
55
- }
56
- else if (ui === "stoplight") {
57
- deps = stoplightDeps;
58
- }
59
- else if (ui === "rapidoc") {
60
- deps = rapidocDeps;
61
- }
62
- return deps.join(" ");
63
- }
64
- async function createDocsPage(ui, outputFile) {
65
- const paths = ["app", "api-docs"];
66
- const srcPath = path.join(process.cwd(), "src");
67
- if (fs.existsSync(srcPath)) {
68
- paths.unshift("src");
69
- }
70
- const docsDir = path.join(process.cwd(), ...paths);
71
- await fs.promises.mkdir(docsDir, { recursive: true });
72
- const docsPage = getDocsPage(ui, outputFile);
73
- const componentPath = path.join(docsDir, "page.tsx");
74
- await fs.promises.writeFile(componentPath, docsPage.trim());
75
- spinner.succeed(`Created ${paths.join("/")}/page.tsx for ${ui}.`);
76
- }
77
- async function installDependencies(ui) {
78
- const packageManager = await getPackageManager();
79
- const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"}`;
80
- const deps = getDocsPageDependencies(ui);
81
- spinner.succeed(`Installing ${deps} dependencies...`);
82
- const resp = await execPromise(`${installCmd} ${deps}`);
83
- spinner.succeed(`Successfully installed ${deps}.`);
84
- }
85
- function extendOpenApiTemplate(spec, options) {
86
- spec.ui = options.ui ?? spec.ui;
87
- spec.docsUrl = options.docsUrl ?? spec.docsUrl;
88
- }
89
- export async function init(options) {
90
- const { ui, docsUrl } = options;
91
- spinner.start();
92
- try {
93
- const outputPath = path.join(process.cwd(), "next.openapi.json");
94
- const template = { ...openapiTemplate };
95
- extendOpenApiTemplate(template, { docsUrl, ui });
96
- await fse.writeJson(outputPath, template, { spaces: 2 });
97
- spinner.succeed(`Created OpenAPI template in next.openapi.json`);
98
- createDocsPage(ui, template.outputFile);
99
- installDependencies(ui);
100
- }
101
- catch (error) {
102
- spinner.fail(`Failed to initialize project: ${error.message}`);
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 { swaggerDeps, SwaggerUI } from "../components/swagger.js";
9
+ import { redocDeps, RedocUI } from "../components/redoc.js";
10
+ import { stoplightDeps, StoplightUI } from "../components/stoplight.js";
11
+ import { rapidocDeps, RapidocUI } from "../components/rapidoc.js";
12
+ const execPromise = util.promisify(exec);
13
+ const spinner = ora("Initializing project with OpenAPI template...\n");
14
+ const getPackageManager = async () => {
15
+ let currentDir = process.cwd();
16
+ while (true) {
17
+ // Check for Yarn lock file
18
+ if (fs.existsSync(path.join(currentDir, "yarn.lock"))) {
19
+ return "yarn";
20
+ }
21
+ // Check for PNPM lock file
22
+ if (fs.existsSync(path.join(currentDir, "pnpm-lock.yaml"))) {
23
+ return "pnpm";
24
+ }
25
+ // If we're at the root directory, break the loop
26
+ const parentDir = path.dirname(currentDir);
27
+ if (parentDir === currentDir) {
28
+ break; // We've reached the root
29
+ }
30
+ currentDir = parentDir; // Move up one directory
31
+ }
32
+ // Default to npm if no lock files are found
33
+ return "npm";
34
+ };
35
+ function getDocsPage(ui, outputFile) {
36
+ let DocsComponent = SwaggerUI;
37
+ if (ui === "redoc") {
38
+ DocsComponent = RedocUI;
39
+ }
40
+ else if (ui === "stoplight") {
41
+ DocsComponent = StoplightUI;
42
+ }
43
+ else if (ui === "rapidoc") {
44
+ DocsComponent = RapidocUI;
45
+ }
46
+ return DocsComponent(outputFile);
47
+ }
48
+ function getDocsPageDependencies(ui) {
49
+ let deps = [];
50
+ if (ui === "swagger") {
51
+ deps = swaggerDeps;
52
+ }
53
+ else if (ui === "redoc") {
54
+ deps = redocDeps;
55
+ }
56
+ else if (ui === "stoplight") {
57
+ deps = stoplightDeps;
58
+ }
59
+ else if (ui === "rapidoc") {
60
+ deps = rapidocDeps;
61
+ }
62
+ return deps.join(" ");
63
+ }
64
+ async function createDocsPage(ui, outputFile) {
65
+ const paths = ["app", "api-docs"];
66
+ const srcPath = path.join(process.cwd(), "src");
67
+ if (fs.existsSync(srcPath)) {
68
+ paths.unshift("src");
69
+ }
70
+ const docsDir = path.join(process.cwd(), ...paths);
71
+ await fs.promises.mkdir(docsDir, { recursive: true });
72
+ const docsPage = getDocsPage(ui, outputFile);
73
+ const componentPath = path.join(docsDir, "page.tsx");
74
+ await fs.promises.writeFile(componentPath, docsPage.trim());
75
+ spinner.succeed(`Created ${paths.join("/")}/page.tsx for ${ui}.`);
76
+ }
77
+ async function installDependencies(ui) {
78
+ const packageManager = await getPackageManager();
79
+ const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"}`;
80
+ const deps = getDocsPageDependencies(ui);
81
+ spinner.succeed(`Installing ${deps} dependencies...`);
82
+ const resp = await execPromise(`${installCmd} ${deps}`);
83
+ spinner.succeed(`Successfully installed ${deps}.`);
84
+ }
85
+ function extendOpenApiTemplate(spec, options) {
86
+ spec.ui = options.ui ?? spec.ui;
87
+ spec.docsUrl = options.docsUrl ?? spec.docsUrl;
88
+ }
89
+ export async function init(options) {
90
+ const { ui, docsUrl } = options;
91
+ spinner.start();
92
+ try {
93
+ const outputPath = path.join(process.cwd(), "next.openapi.json");
94
+ const template = { ...openapiTemplate };
95
+ extendOpenApiTemplate(template, { docsUrl, ui });
96
+ await fse.writeJson(outputPath, template, { spaces: 2 });
97
+ spinner.succeed(`Created OpenAPI template in next.openapi.json`);
98
+ createDocsPage(ui, template.outputFile);
99
+ installDependencies(ui);
100
+ }
101
+ catch (error) {
102
+ spinner.fail(`Failed to initialize project: ${error.message}`);
103
+ }
104
+ }
@@ -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
+ }
@@ -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
+ }
@@ -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., swagger")
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., swagger")
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,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
+ }