next-openapi-gen 0.10.5 → 1.0.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 +407 -1047
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +8599 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +8645 -26
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.js +7965 -0
- package/dist/react-router/index.d.ts +1 -0
- package/dist/react-router/index.js +7134 -0
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.js +7134 -0
- package/package.json +103 -79
- package/{dist/components/rapidoc.js → templates/init/ui/nextjs/rapidoc.tsx} +16 -20
- package/templates/init/ui/nextjs/redoc.tsx +11 -0
- package/{dist/components/scalar.js → templates/init/ui/nextjs/scalar.tsx} +15 -21
- package/{dist/components/stoplight.js → templates/init/ui/nextjs/stoplight.tsx} +11 -17
- package/templates/init/ui/nextjs/swagger.tsx +17 -0
- package/templates/init/ui/reactrouter/rapidoc.tsx +15 -0
- package/templates/init/ui/reactrouter/redoc.tsx +9 -0
- package/templates/init/ui/reactrouter/scalar.tsx +14 -0
- package/templates/init/ui/reactrouter/stoplight.tsx +10 -0
- package/templates/init/ui/reactrouter/swagger.tsx +11 -0
- package/templates/init/ui/tanstack/rapidoc.tsx +21 -0
- package/templates/init/ui/tanstack/redoc.tsx +14 -0
- package/templates/init/ui/tanstack/scalar.tsx +19 -0
- package/templates/init/ui/tanstack/stoplight.tsx +15 -0
- package/templates/init/ui/tanstack/swagger.tsx +16 -0
- package/templates/init/ui/template-types.d.ts +9 -0
- package/dist/commands/generate.js +0 -24
- package/dist/commands/init.js +0 -194
- package/dist/components/redoc.js +0 -17
- package/dist/components/swagger.js +0 -21
- package/dist/lib/app-router-strategy.js +0 -66
- package/dist/lib/drizzle-zod-processor.js +0 -329
- package/dist/lib/logger.js +0 -39
- package/dist/lib/openapi-generator.js +0 -171
- package/dist/lib/pages-router-strategy.js +0 -198
- package/dist/lib/route-processor.js +0 -349
- package/dist/lib/router-strategy.js +0 -1
- package/dist/lib/schema-processor.js +0 -1612
- package/dist/lib/utils.js +0 -283
- package/dist/lib/zod-converter.js +0 -2133
- package/dist/openapi-template.js +0 -99
- package/dist/types.js +0 -1
package/dist/lib/utils.js
DELETED
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
import { parse } from "@babel/parser";
|
|
2
|
-
export function capitalize(string) {
|
|
3
|
-
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Extract path parameters from a route path
|
|
7
|
-
* e.g. /users/{id}/posts/{postId} -> ['id', 'postId']
|
|
8
|
-
*/
|
|
9
|
-
export function extractPathParameters(routePath) {
|
|
10
|
-
const paramRegex = /{([^}]+)}/g;
|
|
11
|
-
const params = [];
|
|
12
|
-
let match;
|
|
13
|
-
while ((match = paramRegex.exec(routePath)) !== null) {
|
|
14
|
-
params.push(match[1]);
|
|
15
|
-
}
|
|
16
|
-
return params;
|
|
17
|
-
}
|
|
18
|
-
export function extractJSDocComments(path) {
|
|
19
|
-
const comments = path.node.leadingComments;
|
|
20
|
-
let tag = "";
|
|
21
|
-
let summary = "";
|
|
22
|
-
let description = "";
|
|
23
|
-
let paramsType = "";
|
|
24
|
-
let pathParamsType = "";
|
|
25
|
-
let bodyType = "";
|
|
26
|
-
let auth = "";
|
|
27
|
-
let isOpenApi = false;
|
|
28
|
-
let isIgnored = false;
|
|
29
|
-
let deprecated = false;
|
|
30
|
-
let bodyDescription = "";
|
|
31
|
-
let contentType = "";
|
|
32
|
-
let responseType = "";
|
|
33
|
-
let responseDescription = "";
|
|
34
|
-
let responseSet = "";
|
|
35
|
-
let addResponses = "";
|
|
36
|
-
let successCode = "";
|
|
37
|
-
let operationId = "";
|
|
38
|
-
let method = "";
|
|
39
|
-
if (comments) {
|
|
40
|
-
comments.forEach((comment) => {
|
|
41
|
-
const commentValue = cleanComment(comment.value);
|
|
42
|
-
isOpenApi = commentValue.includes("@openapi");
|
|
43
|
-
if (commentValue.includes("@ignore")) {
|
|
44
|
-
isIgnored = true;
|
|
45
|
-
}
|
|
46
|
-
if (commentValue.includes("@deprecated")) {
|
|
47
|
-
deprecated = true;
|
|
48
|
-
}
|
|
49
|
-
if (commentValue.includes("@bodyDescription")) {
|
|
50
|
-
const regex = /@bodyDescription\s*(.*)/;
|
|
51
|
-
const match = commentValue.match(regex);
|
|
52
|
-
if (match && match[1]) {
|
|
53
|
-
bodyDescription = match[1].trim();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (!summary) {
|
|
57
|
-
const firstLine = commentValue.split("\n")[0];
|
|
58
|
-
// Don't use tags as summary - only use actual descriptions
|
|
59
|
-
if (!firstLine.trim().startsWith("@")) {
|
|
60
|
-
summary = firstLine;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (commentValue.includes("@auth")) {
|
|
64
|
-
const regex = /@auth\s*(.*)/;
|
|
65
|
-
const value = commentValue.match(regex)[1].trim();
|
|
66
|
-
switch (value) {
|
|
67
|
-
case "bearer":
|
|
68
|
-
auth = "BearerAuth";
|
|
69
|
-
break;
|
|
70
|
-
case "basic":
|
|
71
|
-
auth = "BasicAuth";
|
|
72
|
-
break;
|
|
73
|
-
case "apikey":
|
|
74
|
-
auth = "ApiKeyAuth";
|
|
75
|
-
break;
|
|
76
|
-
default:
|
|
77
|
-
auth = performAuthPresetReplacements(value);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (commentValue.includes("@description")) {
|
|
81
|
-
const regex = /@description\s*(.*)/;
|
|
82
|
-
description = commentValue.match(regex)[1].trim();
|
|
83
|
-
}
|
|
84
|
-
if (commentValue.includes("@tag")) {
|
|
85
|
-
const regex = /@tag\s*(.*)/;
|
|
86
|
-
const match = commentValue.match(regex);
|
|
87
|
-
if (match && match[1]) {
|
|
88
|
-
tag = match[1].trim();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (commentValue.includes("@params") || commentValue.includes("@queryParams")) {
|
|
92
|
-
paramsType = extractTypeFromComment(commentValue, "@queryParams") ||
|
|
93
|
-
extractTypeFromComment(commentValue, "@params");
|
|
94
|
-
}
|
|
95
|
-
if (commentValue.includes("@pathParams")) {
|
|
96
|
-
pathParamsType = extractTypeFromComment(commentValue, "@pathParams");
|
|
97
|
-
}
|
|
98
|
-
if (commentValue.includes("@body")) {
|
|
99
|
-
bodyType = extractTypeFromComment(commentValue, "@body");
|
|
100
|
-
}
|
|
101
|
-
if (commentValue.includes("@response")) {
|
|
102
|
-
responseType = extractTypeFromComment(commentValue, "@response");
|
|
103
|
-
}
|
|
104
|
-
if (commentValue.includes("@contentType")) {
|
|
105
|
-
const regex = /@contentType\s*(.*)/;
|
|
106
|
-
const match = commentValue.match(regex);
|
|
107
|
-
if (match && match[1]) {
|
|
108
|
-
contentType = match[1].trim();
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (commentValue.includes("@responseDescription")) {
|
|
112
|
-
const regex = /@responseDescription\s*(.*)/;
|
|
113
|
-
const match = commentValue.match(regex);
|
|
114
|
-
if (match && match[1]) {
|
|
115
|
-
responseDescription = match[1].trim();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (commentValue.includes("@responseSet")) {
|
|
119
|
-
const regex = /@responseSet\s*(.*)/;
|
|
120
|
-
const match = commentValue.match(regex);
|
|
121
|
-
if (match && match[1]) {
|
|
122
|
-
responseSet = match[1].trim();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (commentValue.includes("@add")) {
|
|
126
|
-
const matches = [...commentValue.matchAll(/@add\s+([^\n\r@]*)/g)];
|
|
127
|
-
if (matches.length > 0) {
|
|
128
|
-
addResponses = matches.map((m) => m[1].trim()).join(",");
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (commentValue.includes("@operationId")) {
|
|
132
|
-
const regex = /@operationId\s+(\S+)/;
|
|
133
|
-
const match = commentValue.match(regex);
|
|
134
|
-
if (match && match[1]) {
|
|
135
|
-
operationId = match[1].trim();
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (commentValue.includes("@method")) {
|
|
139
|
-
const regex = /@method\s+(\S+)/;
|
|
140
|
-
const match = commentValue.match(regex);
|
|
141
|
-
if (match && match[1]) {
|
|
142
|
-
method = match[1].trim().toUpperCase();
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (commentValue.includes("@response")) {
|
|
146
|
-
// Updated regex to support generic types
|
|
147
|
-
const responseMatch = commentValue.match(/@response\s+(?:(\d+):)?([^@\n\r]+)(?:\s+(.*))?/);
|
|
148
|
-
if (responseMatch) {
|
|
149
|
-
const [, code, type] = responseMatch;
|
|
150
|
-
const trimmedType = type?.trim();
|
|
151
|
-
// Check if the type is just a status code (e.g., "@response 204")
|
|
152
|
-
if (!code && trimmedType && /^\d{3}$/.test(trimmedType)) {
|
|
153
|
-
// Type is actually a status code without a schema
|
|
154
|
-
successCode = trimmedType;
|
|
155
|
-
responseType = undefined;
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
successCode = code || "";
|
|
159
|
-
responseType = trimmedType;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
responseType = extractTypeFromComment(commentValue, "@response");
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
return {
|
|
169
|
-
tag,
|
|
170
|
-
auth,
|
|
171
|
-
summary,
|
|
172
|
-
description,
|
|
173
|
-
paramsType,
|
|
174
|
-
pathParamsType,
|
|
175
|
-
bodyType,
|
|
176
|
-
isOpenApi,
|
|
177
|
-
isIgnored,
|
|
178
|
-
deprecated,
|
|
179
|
-
bodyDescription,
|
|
180
|
-
contentType,
|
|
181
|
-
responseType,
|
|
182
|
-
responseDescription,
|
|
183
|
-
responseSet,
|
|
184
|
-
addResponses,
|
|
185
|
-
successCode,
|
|
186
|
-
operationId,
|
|
187
|
-
method,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
export function extractTypeFromComment(commentValue, tag) {
|
|
191
|
-
// Updated regex to support generic types with angle brackets and array brackets
|
|
192
|
-
// Use multiline mode (m flag) to match tag at start of line (after optional * from JSDoc)
|
|
193
|
-
return (commentValue
|
|
194
|
-
.match(new RegExp(`^\\s*\\*?\\s*${tag}\\s+([\\w<>,\\s\\[\\]]+)`, 'm'))?.[1]
|
|
195
|
-
?.trim() || "");
|
|
196
|
-
}
|
|
197
|
-
export function cleanComment(commentValue) {
|
|
198
|
-
return commentValue.replace(/\*\s*/g, "").trim();
|
|
199
|
-
}
|
|
200
|
-
export function cleanSpec(spec) {
|
|
201
|
-
const propsToRemove = [
|
|
202
|
-
"apiDir",
|
|
203
|
-
"routerType",
|
|
204
|
-
"schemaDir",
|
|
205
|
-
"docsUrl",
|
|
206
|
-
"ui",
|
|
207
|
-
"outputFile",
|
|
208
|
-
"includeOpenApiRoutes",
|
|
209
|
-
"ignoreRoutes",
|
|
210
|
-
"schemaType",
|
|
211
|
-
"defaultResponseSet",
|
|
212
|
-
"responseSets",
|
|
213
|
-
"errorConfig",
|
|
214
|
-
"debug",
|
|
215
|
-
"schemaFiles",
|
|
216
|
-
"outputDir",
|
|
217
|
-
];
|
|
218
|
-
const newSpec = { ...spec };
|
|
219
|
-
propsToRemove.forEach((key) => delete newSpec[key]);
|
|
220
|
-
// Process paths to ensure good examples for path parameters
|
|
221
|
-
if (newSpec.paths) {
|
|
222
|
-
Object.keys(newSpec.paths).forEach((path) => {
|
|
223
|
-
// Check if path contains parameters
|
|
224
|
-
if (path.includes("{") && path.includes("}")) {
|
|
225
|
-
// For each HTTP method in this path
|
|
226
|
-
Object.keys(newSpec.paths[path]).forEach((method) => {
|
|
227
|
-
const operation = newSpec.paths[path][method];
|
|
228
|
-
// Set example properties for each path parameter
|
|
229
|
-
if (operation.parameters) {
|
|
230
|
-
operation.parameters.forEach((param) => {
|
|
231
|
-
if (param.in === "path" && !param.example) {
|
|
232
|
-
// Generate an example based on parameter name
|
|
233
|
-
if (param.name === "id" || param.name.endsWith("Id")) {
|
|
234
|
-
param.example = 123;
|
|
235
|
-
}
|
|
236
|
-
else if (param.name === "slug") {
|
|
237
|
-
param.example = "example-slug";
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
param.example = "example";
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
return newSpec;
|
|
250
|
-
}
|
|
251
|
-
const AUTH_PRESET_REPLACEMENTS = {
|
|
252
|
-
bearer: "BearerAuth",
|
|
253
|
-
basic: "BasicAuth",
|
|
254
|
-
apikey: "ApiKeyAuth",
|
|
255
|
-
};
|
|
256
|
-
export function performAuthPresetReplacements(authValue) {
|
|
257
|
-
const authParts = authValue.split(",").map((part) => part.trim());
|
|
258
|
-
const mappedParts = authParts.map((part) => AUTH_PRESET_REPLACEMENTS[part.toLowerCase()] || part);
|
|
259
|
-
return mappedParts.join(",");
|
|
260
|
-
}
|
|
261
|
-
export function getOperationId(routePath, method) {
|
|
262
|
-
const operation = routePath.replaceAll(/\//g, "-").replace(/^-/, "");
|
|
263
|
-
return `${method}-${operation}`;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Common Babel parser configuration for TypeScript files with JSX support
|
|
267
|
-
*/
|
|
268
|
-
const DEFAULT_PARSER_OPTIONS = {
|
|
269
|
-
sourceType: "module",
|
|
270
|
-
plugins: ["typescript", "jsx", "decorators-legacy"],
|
|
271
|
-
};
|
|
272
|
-
/**
|
|
273
|
-
* Parse TypeScript/TSX file content with the standard configuration
|
|
274
|
-
* @param content - File content to parse
|
|
275
|
-
* @param options - Optional parser options to override defaults
|
|
276
|
-
* @returns Parsed AST
|
|
277
|
-
*/
|
|
278
|
-
export function parseTypeScriptFile(content, options) {
|
|
279
|
-
return parse(content, {
|
|
280
|
-
...DEFAULT_PARSER_OPTIONS,
|
|
281
|
-
...options,
|
|
282
|
-
});
|
|
283
|
-
}
|