@omer-x/next-openapi-json-generator 1.1.2 → 1.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/dist/index.cjs +90 -20
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +90 -20
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -35,8 +35,39 @@ __export(src_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(src_exports);
|
|
36
36
|
|
|
37
37
|
// src/core/generateOpenApiSpec.ts
|
|
38
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
38
39
|
var import_package_metadata = __toESM(require("@omer-x/package-metadata"), 1);
|
|
39
40
|
|
|
41
|
+
// src/utils/object.ts
|
|
42
|
+
function omit(object, ...keys) {
|
|
43
|
+
return Object.fromEntries(Object.entries(object).filter(([key]) => !keys.includes(key)));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// src/core/clearUnusedSchemas.ts
|
|
47
|
+
function countReferences(schemaName, source) {
|
|
48
|
+
return (source.match(new RegExp(`"#/components/schemas/${schemaName}"`, "g")) ?? []).length;
|
|
49
|
+
}
|
|
50
|
+
function clearUnusedSchemas({
|
|
51
|
+
paths,
|
|
52
|
+
components
|
|
53
|
+
}) {
|
|
54
|
+
if (!components.schemas) return { paths, components };
|
|
55
|
+
const stringifiedPaths = JSON.stringify(paths);
|
|
56
|
+
const stringifiedSchemas = Object.fromEntries(Object.entries(components.schemas).map(([schemaName, schema]) => {
|
|
57
|
+
return [schemaName, JSON.stringify(schema)];
|
|
58
|
+
}));
|
|
59
|
+
return {
|
|
60
|
+
paths,
|
|
61
|
+
components: {
|
|
62
|
+
...components,
|
|
63
|
+
schemas: Object.fromEntries(Object.entries(components.schemas).filter(([schemaName]) => {
|
|
64
|
+
const otherSchemas = omit(stringifiedSchemas, schemaName);
|
|
65
|
+
return countReferences(schemaName, stringifiedPaths) > 0 || countReferences(schemaName, Object.values(otherSchemas).join("")) > 0;
|
|
66
|
+
}))
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
40
71
|
// src/core/dir.ts
|
|
41
72
|
var import_fs = require("fs");
|
|
42
73
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
@@ -46,7 +77,7 @@ async function directoryExists(dirPath) {
|
|
|
46
77
|
try {
|
|
47
78
|
await import_promises.default.access(dirPath, import_fs.constants.F_OK);
|
|
48
79
|
return true;
|
|
49
|
-
} catch
|
|
80
|
+
} catch {
|
|
50
81
|
return false;
|
|
51
82
|
}
|
|
52
83
|
}
|
|
@@ -91,6 +122,33 @@ async function isDocumentedRoute(routePath2) {
|
|
|
91
122
|
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
92
123
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
93
124
|
|
|
125
|
+
// src/core/injectSchemas.ts
|
|
126
|
+
function generateRandomString(length) {
|
|
127
|
+
return [...Array(length)].map(() => Math.random().toString(36)[2]).join("");
|
|
128
|
+
}
|
|
129
|
+
function preserveStrings(code2) {
|
|
130
|
+
let replacements = {};
|
|
131
|
+
const output = code2.replace(/(['"`])([^'`"]+)\1/g, (replacedString) => {
|
|
132
|
+
const replacementId = generateRandomString(32);
|
|
133
|
+
replacements = {
|
|
134
|
+
...replacements,
|
|
135
|
+
[replacementId]: replacedString
|
|
136
|
+
};
|
|
137
|
+
return `<@~${replacementId}~@>`;
|
|
138
|
+
});
|
|
139
|
+
return { output, replacements };
|
|
140
|
+
}
|
|
141
|
+
function restoreStrings(code2, replacements) {
|
|
142
|
+
return code2.replace(/<@~(.*?)~@>/g, (_, replacementId) => {
|
|
143
|
+
return replacements[replacementId];
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function injectSchemas(code2, refName) {
|
|
147
|
+
const { output: preservedCode, replacements } = preserveStrings(code2);
|
|
148
|
+
const preservedCodeWithSchemasInjected = preservedCode.replace(new RegExp(`\\b${refName}\\.`, "g"), `global.schemas[${refName}].`).replace(new RegExp(`\\b${refName}\\b`, "g"), `"${refName}"`);
|
|
149
|
+
return restoreStrings(preservedCodeWithSchemasInjected, replacements);
|
|
150
|
+
}
|
|
151
|
+
|
|
94
152
|
// src/core/middleware.ts
|
|
95
153
|
function detectMiddlewareName(code2) {
|
|
96
154
|
const match = code2.match(/middleware:\s*(\w+)/);
|
|
@@ -99,9 +157,13 @@ function detectMiddlewareName(code2) {
|
|
|
99
157
|
|
|
100
158
|
// src/core/transpile.ts
|
|
101
159
|
var import_typescript = require("typescript");
|
|
160
|
+
|
|
161
|
+
// src/utils/removeImports.ts
|
|
102
162
|
function removeImports(code2) {
|
|
103
|
-
return code2.replace(
|
|
163
|
+
return code2.replace(/(^import\s+[^;]+;?$|^import\s+[^;]*\sfrom\s.+;?$)/gm, "").replace(/(^import\s+{[\s\S]+?}\s+from\s+["'][^"']+["'];?)/gm, "").trim();
|
|
104
164
|
}
|
|
165
|
+
|
|
166
|
+
// src/core/transpile.ts
|
|
105
167
|
function fixExports(code2) {
|
|
106
168
|
const validMethods = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
107
169
|
const exportFixer1 = validMethods.map((method) => `exports.${method} = void 0;
|
|
@@ -137,9 +199,6 @@ async function findAppFolderPath() {
|
|
|
137
199
|
}
|
|
138
200
|
return null;
|
|
139
201
|
}
|
|
140
|
-
function injectSchemas(code2, refName) {
|
|
141
|
-
return code2.replace(new RegExp(`\\b${refName}\\.`, "g"), `global.schemas[${refName}].`).replace(new RegExp(`\\b${refName}\\b`, "g"), `"${refName}"`);
|
|
142
|
-
}
|
|
143
202
|
function safeEval(code, routePath) {
|
|
144
203
|
try {
|
|
145
204
|
return eval(code);
|
|
@@ -154,12 +213,8 @@ async function getRouteExports(routePath2, routeDefinerName, schemas) {
|
|
|
154
213
|
const code2 = transpile(rawCode, routeDefinerName, middlewareName);
|
|
155
214
|
const fixedCode = Object.keys(schemas).reduce(injectSchemas, code2);
|
|
156
215
|
global.schemas = schemas;
|
|
157
|
-
if (middlewareName) {
|
|
158
|
-
}
|
|
159
216
|
const result = safeEval(fixedCode, routePath2);
|
|
160
217
|
delete global.schemas;
|
|
161
|
-
if (middlewareName) {
|
|
162
|
-
}
|
|
163
218
|
return result;
|
|
164
219
|
}
|
|
165
220
|
|
|
@@ -183,6 +238,13 @@ function verifyOptions(include, exclude) {
|
|
|
183
238
|
};
|
|
184
239
|
}
|
|
185
240
|
|
|
241
|
+
// src/core/getRoutePathName.ts
|
|
242
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
243
|
+
function getRoutePathName(filePath, rootPath) {
|
|
244
|
+
const dirName = import_node_path3.default.dirname(filePath);
|
|
245
|
+
return "/" + import_node_path3.default.relative(rootPath, dirName).replaceAll("[", "{").replaceAll("]", "}").replaceAll("\\", "/");
|
|
246
|
+
}
|
|
247
|
+
|
|
186
248
|
// src/utils/deepEqual.ts
|
|
187
249
|
function deepEqual(a, b) {
|
|
188
250
|
if (typeof a !== typeof b) return false;
|
|
@@ -327,9 +389,6 @@ function maskOperationSchemas(operation, storedSchemas) {
|
|
|
327
389
|
}
|
|
328
390
|
|
|
329
391
|
// src/core/route.ts
|
|
330
|
-
function getRoutePathName(filePath, rootPath) {
|
|
331
|
-
return filePath.replace(rootPath, "").replace("[", "{").replace("]", "}").replaceAll("\\", "/").replace("/route.ts", "");
|
|
332
|
-
}
|
|
333
392
|
function createRouteRecord(method, filePath, rootPath, apiData) {
|
|
334
393
|
return {
|
|
335
394
|
method: method.toLocaleLowerCase(),
|
|
@@ -366,13 +425,18 @@ function bundleSchemas(schemas) {
|
|
|
366
425
|
async function generateOpenApiSpec(schemas, {
|
|
367
426
|
include: includeOption = [],
|
|
368
427
|
exclude: excludeOption = [],
|
|
369
|
-
routeDefinerName = "defineRoute"
|
|
428
|
+
routeDefinerName = "defineRoute",
|
|
429
|
+
rootPath: additionalRootPath,
|
|
430
|
+
servers,
|
|
431
|
+
security,
|
|
432
|
+
securitySchemes
|
|
370
433
|
} = {}) {
|
|
371
434
|
const verifiedOptions = verifyOptions(includeOption, excludeOption);
|
|
372
435
|
const appFolderPath = await findAppFolderPath();
|
|
373
436
|
if (!appFolderPath) throw new Error("This is not a Next.js application!");
|
|
374
|
-
const
|
|
375
|
-
const
|
|
437
|
+
const rootPath = additionalRootPath ? import_node_path4.default.resolve(appFolderPath, "./" + additionalRootPath) : appFolderPath;
|
|
438
|
+
const routes = await getDirectoryItems(rootPath, "route.ts");
|
|
439
|
+
const verifiedRoutes = filterDirectoryItems(rootPath, routes, verifiedOptions.include, verifiedOptions.exclude);
|
|
376
440
|
const validRoutes = [];
|
|
377
441
|
for (const route of verifiedRoutes) {
|
|
378
442
|
const isDocumented = await isDocumentedRoute(route);
|
|
@@ -383,22 +447,28 @@ async function generateOpenApiSpec(schemas, {
|
|
|
383
447
|
validRoutes.push(createRouteRecord(
|
|
384
448
|
method.toLocaleLowerCase(),
|
|
385
449
|
route,
|
|
386
|
-
|
|
450
|
+
rootPath,
|
|
387
451
|
routeHandler.apiData
|
|
388
452
|
));
|
|
389
453
|
}
|
|
390
454
|
}
|
|
391
455
|
const metadata = (0, import_package_metadata.default)();
|
|
456
|
+
const pathsAndComponents = {
|
|
457
|
+
paths: bundlePaths(validRoutes, schemas),
|
|
458
|
+
components: {
|
|
459
|
+
schemas: bundleSchemas(schemas),
|
|
460
|
+
securitySchemes
|
|
461
|
+
}
|
|
462
|
+
};
|
|
392
463
|
return {
|
|
393
464
|
openapi: "3.1.0",
|
|
394
465
|
info: {
|
|
395
466
|
title: metadata.serviceName,
|
|
396
467
|
version: metadata.version
|
|
397
468
|
},
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
},
|
|
469
|
+
servers,
|
|
470
|
+
...clearUnusedSchemas(pathsAndComponents),
|
|
471
|
+
security,
|
|
402
472
|
tags: []
|
|
403
473
|
};
|
|
404
474
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { OpenApiDocument } from '@omer-x/openapi-types';
|
|
2
|
+
import { ComponentsObject } from '@omer-x/openapi-types/components';
|
|
3
|
+
import { ServerObject } from '@omer-x/openapi-types/server';
|
|
2
4
|
import { ZodType } from 'zod';
|
|
3
5
|
|
|
4
6
|
type GeneratorOptions = {
|
|
5
7
|
include?: string[];
|
|
6
8
|
exclude?: string[];
|
|
7
9
|
routeDefinerName?: string;
|
|
10
|
+
rootPath?: string;
|
|
11
|
+
servers?: ServerObject[];
|
|
12
|
+
security?: OpenApiDocument["security"];
|
|
13
|
+
securitySchemes?: ComponentsObject["securitySchemes"];
|
|
8
14
|
};
|
|
9
|
-
declare function generateOpenApiSpec(schemas: Record<string, ZodType>, { include: includeOption, exclude: excludeOption, routeDefinerName, }?: GeneratorOptions): Promise<Omit<OpenApiDocument, "components"> & Required<Pick<OpenApiDocument, "components">>>;
|
|
15
|
+
declare function generateOpenApiSpec(schemas: Record<string, ZodType>, { include: includeOption, exclude: excludeOption, routeDefinerName, rootPath: additionalRootPath, servers, security, securitySchemes, }?: GeneratorOptions): Promise<Omit<OpenApiDocument, "components"> & Required<Pick<OpenApiDocument, "components">>>;
|
|
10
16
|
|
|
11
17
|
export { generateOpenApiSpec as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { OpenApiDocument } from '@omer-x/openapi-types';
|
|
2
|
+
import { ComponentsObject } from '@omer-x/openapi-types/components';
|
|
3
|
+
import { ServerObject } from '@omer-x/openapi-types/server';
|
|
2
4
|
import { ZodType } from 'zod';
|
|
3
5
|
|
|
4
6
|
type GeneratorOptions = {
|
|
5
7
|
include?: string[];
|
|
6
8
|
exclude?: string[];
|
|
7
9
|
routeDefinerName?: string;
|
|
10
|
+
rootPath?: string;
|
|
11
|
+
servers?: ServerObject[];
|
|
12
|
+
security?: OpenApiDocument["security"];
|
|
13
|
+
securitySchemes?: ComponentsObject["securitySchemes"];
|
|
8
14
|
};
|
|
9
|
-
declare function generateOpenApiSpec(schemas: Record<string, ZodType>, { include: includeOption, exclude: excludeOption, routeDefinerName, }?: GeneratorOptions): Promise<Omit<OpenApiDocument, "components"> & Required<Pick<OpenApiDocument, "components">>>;
|
|
15
|
+
declare function generateOpenApiSpec(schemas: Record<string, ZodType>, { include: includeOption, exclude: excludeOption, routeDefinerName, rootPath: additionalRootPath, servers, security, securitySchemes, }?: GeneratorOptions): Promise<Omit<OpenApiDocument, "components"> & Required<Pick<OpenApiDocument, "components">>>;
|
|
10
16
|
|
|
11
17
|
export { generateOpenApiSpec as default };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
// src/core/generateOpenApiSpec.ts
|
|
2
|
+
import path4 from "node:path";
|
|
2
3
|
import getPackageMetadata from "@omer-x/package-metadata";
|
|
3
4
|
|
|
5
|
+
// src/utils/object.ts
|
|
6
|
+
function omit(object, ...keys) {
|
|
7
|
+
return Object.fromEntries(Object.entries(object).filter(([key]) => !keys.includes(key)));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// src/core/clearUnusedSchemas.ts
|
|
11
|
+
function countReferences(schemaName, source) {
|
|
12
|
+
return (source.match(new RegExp(`"#/components/schemas/${schemaName}"`, "g")) ?? []).length;
|
|
13
|
+
}
|
|
14
|
+
function clearUnusedSchemas({
|
|
15
|
+
paths,
|
|
16
|
+
components
|
|
17
|
+
}) {
|
|
18
|
+
if (!components.schemas) return { paths, components };
|
|
19
|
+
const stringifiedPaths = JSON.stringify(paths);
|
|
20
|
+
const stringifiedSchemas = Object.fromEntries(Object.entries(components.schemas).map(([schemaName, schema]) => {
|
|
21
|
+
return [schemaName, JSON.stringify(schema)];
|
|
22
|
+
}));
|
|
23
|
+
return {
|
|
24
|
+
paths,
|
|
25
|
+
components: {
|
|
26
|
+
...components,
|
|
27
|
+
schemas: Object.fromEntries(Object.entries(components.schemas).filter(([schemaName]) => {
|
|
28
|
+
const otherSchemas = omit(stringifiedSchemas, schemaName);
|
|
29
|
+
return countReferences(schemaName, stringifiedPaths) > 0 || countReferences(schemaName, Object.values(otherSchemas).join("")) > 0;
|
|
30
|
+
}))
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
4
35
|
// src/core/dir.ts
|
|
5
36
|
import { constants } from "fs";
|
|
6
37
|
import fs from "fs/promises";
|
|
@@ -10,7 +41,7 @@ async function directoryExists(dirPath) {
|
|
|
10
41
|
try {
|
|
11
42
|
await fs.access(dirPath, constants.F_OK);
|
|
12
43
|
return true;
|
|
13
|
-
} catch
|
|
44
|
+
} catch {
|
|
14
45
|
return false;
|
|
15
46
|
}
|
|
16
47
|
}
|
|
@@ -55,6 +86,33 @@ async function isDocumentedRoute(routePath2) {
|
|
|
55
86
|
import fs3 from "node:fs/promises";
|
|
56
87
|
import path2 from "node:path";
|
|
57
88
|
|
|
89
|
+
// src/core/injectSchemas.ts
|
|
90
|
+
function generateRandomString(length) {
|
|
91
|
+
return [...Array(length)].map(() => Math.random().toString(36)[2]).join("");
|
|
92
|
+
}
|
|
93
|
+
function preserveStrings(code2) {
|
|
94
|
+
let replacements = {};
|
|
95
|
+
const output = code2.replace(/(['"`])([^'`"]+)\1/g, (replacedString) => {
|
|
96
|
+
const replacementId = generateRandomString(32);
|
|
97
|
+
replacements = {
|
|
98
|
+
...replacements,
|
|
99
|
+
[replacementId]: replacedString
|
|
100
|
+
};
|
|
101
|
+
return `<@~${replacementId}~@>`;
|
|
102
|
+
});
|
|
103
|
+
return { output, replacements };
|
|
104
|
+
}
|
|
105
|
+
function restoreStrings(code2, replacements) {
|
|
106
|
+
return code2.replace(/<@~(.*?)~@>/g, (_, replacementId) => {
|
|
107
|
+
return replacements[replacementId];
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function injectSchemas(code2, refName) {
|
|
111
|
+
const { output: preservedCode, replacements } = preserveStrings(code2);
|
|
112
|
+
const preservedCodeWithSchemasInjected = preservedCode.replace(new RegExp(`\\b${refName}\\.`, "g"), `global.schemas[${refName}].`).replace(new RegExp(`\\b${refName}\\b`, "g"), `"${refName}"`);
|
|
113
|
+
return restoreStrings(preservedCodeWithSchemasInjected, replacements);
|
|
114
|
+
}
|
|
115
|
+
|
|
58
116
|
// src/core/middleware.ts
|
|
59
117
|
function detectMiddlewareName(code2) {
|
|
60
118
|
const match = code2.match(/middleware:\s*(\w+)/);
|
|
@@ -63,9 +121,13 @@ function detectMiddlewareName(code2) {
|
|
|
63
121
|
|
|
64
122
|
// src/core/transpile.ts
|
|
65
123
|
import { transpile as tsTranspile } from "typescript";
|
|
124
|
+
|
|
125
|
+
// src/utils/removeImports.ts
|
|
66
126
|
function removeImports(code2) {
|
|
67
|
-
return code2.replace(
|
|
127
|
+
return code2.replace(/(^import\s+[^;]+;?$|^import\s+[^;]*\sfrom\s.+;?$)/gm, "").replace(/(^import\s+{[\s\S]+?}\s+from\s+["'][^"']+["'];?)/gm, "").trim();
|
|
68
128
|
}
|
|
129
|
+
|
|
130
|
+
// src/core/transpile.ts
|
|
69
131
|
function fixExports(code2) {
|
|
70
132
|
const validMethods = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
71
133
|
const exportFixer1 = validMethods.map((method) => `exports.${method} = void 0;
|
|
@@ -101,9 +163,6 @@ async function findAppFolderPath() {
|
|
|
101
163
|
}
|
|
102
164
|
return null;
|
|
103
165
|
}
|
|
104
|
-
function injectSchemas(code2, refName) {
|
|
105
|
-
return code2.replace(new RegExp(`\\b${refName}\\.`, "g"), `global.schemas[${refName}].`).replace(new RegExp(`\\b${refName}\\b`, "g"), `"${refName}"`);
|
|
106
|
-
}
|
|
107
166
|
function safeEval(code, routePath) {
|
|
108
167
|
try {
|
|
109
168
|
return eval(code);
|
|
@@ -118,12 +177,8 @@ async function getRouteExports(routePath2, routeDefinerName, schemas) {
|
|
|
118
177
|
const code2 = transpile(rawCode, routeDefinerName, middlewareName);
|
|
119
178
|
const fixedCode = Object.keys(schemas).reduce(injectSchemas, code2);
|
|
120
179
|
global.schemas = schemas;
|
|
121
|
-
if (middlewareName) {
|
|
122
|
-
}
|
|
123
180
|
const result = safeEval(fixedCode, routePath2);
|
|
124
181
|
delete global.schemas;
|
|
125
|
-
if (middlewareName) {
|
|
126
|
-
}
|
|
127
182
|
return result;
|
|
128
183
|
}
|
|
129
184
|
|
|
@@ -147,6 +202,13 @@ function verifyOptions(include, exclude) {
|
|
|
147
202
|
};
|
|
148
203
|
}
|
|
149
204
|
|
|
205
|
+
// src/core/getRoutePathName.ts
|
|
206
|
+
import path3 from "node:path";
|
|
207
|
+
function getRoutePathName(filePath, rootPath) {
|
|
208
|
+
const dirName = path3.dirname(filePath);
|
|
209
|
+
return "/" + path3.relative(rootPath, dirName).replaceAll("[", "{").replaceAll("]", "}").replaceAll("\\", "/");
|
|
210
|
+
}
|
|
211
|
+
|
|
150
212
|
// src/utils/deepEqual.ts
|
|
151
213
|
function deepEqual(a, b) {
|
|
152
214
|
if (typeof a !== typeof b) return false;
|
|
@@ -291,9 +353,6 @@ function maskOperationSchemas(operation, storedSchemas) {
|
|
|
291
353
|
}
|
|
292
354
|
|
|
293
355
|
// src/core/route.ts
|
|
294
|
-
function getRoutePathName(filePath, rootPath) {
|
|
295
|
-
return filePath.replace(rootPath, "").replace("[", "{").replace("]", "}").replaceAll("\\", "/").replace("/route.ts", "");
|
|
296
|
-
}
|
|
297
356
|
function createRouteRecord(method, filePath, rootPath, apiData) {
|
|
298
357
|
return {
|
|
299
358
|
method: method.toLocaleLowerCase(),
|
|
@@ -330,13 +389,18 @@ function bundleSchemas(schemas) {
|
|
|
330
389
|
async function generateOpenApiSpec(schemas, {
|
|
331
390
|
include: includeOption = [],
|
|
332
391
|
exclude: excludeOption = [],
|
|
333
|
-
routeDefinerName = "defineRoute"
|
|
392
|
+
routeDefinerName = "defineRoute",
|
|
393
|
+
rootPath: additionalRootPath,
|
|
394
|
+
servers,
|
|
395
|
+
security,
|
|
396
|
+
securitySchemes
|
|
334
397
|
} = {}) {
|
|
335
398
|
const verifiedOptions = verifyOptions(includeOption, excludeOption);
|
|
336
399
|
const appFolderPath = await findAppFolderPath();
|
|
337
400
|
if (!appFolderPath) throw new Error("This is not a Next.js application!");
|
|
338
|
-
const
|
|
339
|
-
const
|
|
401
|
+
const rootPath = additionalRootPath ? path4.resolve(appFolderPath, "./" + additionalRootPath) : appFolderPath;
|
|
402
|
+
const routes = await getDirectoryItems(rootPath, "route.ts");
|
|
403
|
+
const verifiedRoutes = filterDirectoryItems(rootPath, routes, verifiedOptions.include, verifiedOptions.exclude);
|
|
340
404
|
const validRoutes = [];
|
|
341
405
|
for (const route of verifiedRoutes) {
|
|
342
406
|
const isDocumented = await isDocumentedRoute(route);
|
|
@@ -347,22 +411,28 @@ async function generateOpenApiSpec(schemas, {
|
|
|
347
411
|
validRoutes.push(createRouteRecord(
|
|
348
412
|
method.toLocaleLowerCase(),
|
|
349
413
|
route,
|
|
350
|
-
|
|
414
|
+
rootPath,
|
|
351
415
|
routeHandler.apiData
|
|
352
416
|
));
|
|
353
417
|
}
|
|
354
418
|
}
|
|
355
419
|
const metadata = getPackageMetadata();
|
|
420
|
+
const pathsAndComponents = {
|
|
421
|
+
paths: bundlePaths(validRoutes, schemas),
|
|
422
|
+
components: {
|
|
423
|
+
schemas: bundleSchemas(schemas),
|
|
424
|
+
securitySchemes
|
|
425
|
+
}
|
|
426
|
+
};
|
|
356
427
|
return {
|
|
357
428
|
openapi: "3.1.0",
|
|
358
429
|
info: {
|
|
359
430
|
title: metadata.serviceName,
|
|
360
431
|
version: metadata.version
|
|
361
432
|
},
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
},
|
|
433
|
+
servers,
|
|
434
|
+
...clearUnusedSchemas(pathsAndComponents),
|
|
435
|
+
security,
|
|
366
436
|
tags: []
|
|
367
437
|
};
|
|
368
438
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omer-x/next-openapi-json-generator",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "a Next.js plugin to generate OpenAPI documentation from route handlers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"next.js",
|
|
@@ -48,20 +48,20 @@
|
|
|
48
48
|
"@omer-x/package-metadata": "^1.0.0",
|
|
49
49
|
"minimatch": "^10.0.1",
|
|
50
50
|
"typescript": "^5.6.3",
|
|
51
|
-
"zod-to-json-schema": "^3.23.
|
|
51
|
+
"zod-to-json-schema": "^3.23.5"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@omer-x/eslint-config": "^
|
|
55
|
-
"@
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"semantic-release": "^24.1.3",
|
|
54
|
+
"@omer-x/eslint-config": "^2.0.2",
|
|
55
|
+
"@types/node": "^22.8.4",
|
|
56
|
+
"eslint": "^9.13.0",
|
|
57
|
+
"semantic-release": "^24.2.0",
|
|
59
58
|
"ts-jest": "^29.2.5",
|
|
60
59
|
"ts-node": "^10.9.2",
|
|
61
|
-
"tsup": "^8.3.
|
|
60
|
+
"tsup": "^8.3.5",
|
|
62
61
|
"zod": "^3.23.8"
|
|
63
62
|
},
|
|
64
63
|
"peerDependencies": {
|
|
65
|
-
"@omer-x/next-openapi-route-handler": "^1"
|
|
64
|
+
"@omer-x/next-openapi-route-handler": "^1",
|
|
65
|
+
"@omer-x/openapi-types": "^1"
|
|
66
66
|
}
|
|
67
67
|
}
|