next-openapi-gen 0.5.3 → 0.5.5
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 +47 -12
- package/dist/lib/route-processor.js +6 -4
- package/dist/lib/schema-processor.js +8 -4
- package/dist/lib/utils.js +23 -0
- package/dist/lib/zod-converter.js +13 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ During initialization (`npx next-openapi-gen init`), a configuration file `next.
|
|
|
57
57
|
}
|
|
58
58
|
],
|
|
59
59
|
"apiDir": "src/app/api",
|
|
60
|
-
"schemaDir": "src/types", // or
|
|
60
|
+
"schemaDir": "src/types", // or "src/schemas" for Zod schemas
|
|
61
61
|
"schemaType": "typescript", // or "zod" for Zod schemas
|
|
62
62
|
"outputFile": "openapi.json",
|
|
63
63
|
"docsUrl": "/api-docs",
|
|
@@ -145,16 +145,19 @@ export async function GET(
|
|
|
145
145
|
|
|
146
146
|
## JSDoc Documentation Tags
|
|
147
147
|
|
|
148
|
-
| Tag
|
|
149
|
-
|
|
|
150
|
-
| `@desc`
|
|
151
|
-
| `@pathParams`
|
|
152
|
-
| `@params`
|
|
153
|
-
| `@body`
|
|
154
|
-
| `@
|
|
155
|
-
| `@
|
|
156
|
-
| `@
|
|
157
|
-
| `@
|
|
148
|
+
| Tag | Description |
|
|
149
|
+
| ---------------------- | ----------------------------------------------------------------------------------- |
|
|
150
|
+
| `@desc` | Endpoint description |
|
|
151
|
+
| `@pathParams` | Path parameters type/schema |
|
|
152
|
+
| `@params` | Query parameters type/schema |
|
|
153
|
+
| `@body` | Request body type/schema |
|
|
154
|
+
| `@bodyDescription` | Request body description |
|
|
155
|
+
| `@response` | Response type/schema |
|
|
156
|
+
| `@responseDescription` | Response description |
|
|
157
|
+
| `@auth` | Authorization type (`bearer`, `basic`, `apikey`) |
|
|
158
|
+
| `@tag` | Custom tag |
|
|
159
|
+
| `@deprecated` | Marks the route as deprecated |
|
|
160
|
+
| `@openapi` | Marks the route for inclusion in documentation (if includeOpenApiRoutes is enabled) |
|
|
158
161
|
|
|
159
162
|
## CLI Usage
|
|
160
163
|
|
|
@@ -260,6 +263,7 @@ const CreateUserBody = z.object({
|
|
|
260
263
|
|
|
261
264
|
/**
|
|
262
265
|
* @body CreateUserBody
|
|
266
|
+
* @bodyDescription User registration data including email and password
|
|
263
267
|
*/
|
|
264
268
|
export async function POST() {
|
|
265
269
|
// ...
|
|
@@ -289,6 +293,7 @@ const UserResponse = z.object({
|
|
|
289
293
|
|
|
290
294
|
/**
|
|
291
295
|
* @response UserResponse
|
|
296
|
+
* @responseDescription Returns newly created user object
|
|
292
297
|
*/
|
|
293
298
|
export async function GET() {
|
|
294
299
|
// ...
|
|
@@ -308,6 +313,36 @@ export async function GET() {
|
|
|
308
313
|
}
|
|
309
314
|
```
|
|
310
315
|
|
|
316
|
+
### Deprecated
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
// src/app/api/v1/route.ts
|
|
320
|
+
|
|
321
|
+
// TypeScript
|
|
322
|
+
type UserResponse = {
|
|
323
|
+
id: string;
|
|
324
|
+
name: string;
|
|
325
|
+
/** @deprecated Use firstName and lastName instead */
|
|
326
|
+
fullName?: string;
|
|
327
|
+
email: string;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// Or Zod
|
|
331
|
+
const UserSchema = z.object({
|
|
332
|
+
id: z.string(),
|
|
333
|
+
name: z.string(),
|
|
334
|
+
fullName: z.string().optional().describe("@deprecated Use name instead"),
|
|
335
|
+
email: z.string().email(),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* @response UserResponse
|
|
340
|
+
*/
|
|
341
|
+
export async function GET() {
|
|
342
|
+
// ...
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
311
346
|
## Advanced Usage
|
|
312
347
|
|
|
313
348
|
### Automatic Path Parameter Detection
|
|
@@ -370,7 +405,7 @@ const UserSchema = z.object({
|
|
|
370
405
|
// Use z.infer to create a TypeScript type
|
|
371
406
|
type User = z.infer<typeof UserSchema>;
|
|
372
407
|
|
|
373
|
-
// The library will be able to recognize this schema by reference
|
|
408
|
+
// The library will be able to recognize this schema by reference `UserSchema` or `User` type.
|
|
374
409
|
```
|
|
375
410
|
|
|
376
411
|
## Available UI providers
|
|
@@ -109,7 +109,7 @@ export class RouteProcessor {
|
|
|
109
109
|
const routePath = this.getRoutePath(filePath);
|
|
110
110
|
const rootPath = capitalize(routePath.split("/")[1]);
|
|
111
111
|
const operationId = getOperationId(routePath, method);
|
|
112
|
-
const { tag, summary, description, auth, isOpenApi } = dataTypes;
|
|
112
|
+
const { tag, summary, description, auth, isOpenApi, deprecated, bodyDescription, responseDescription, } = dataTypes;
|
|
113
113
|
if (this.config.includeOpenApiRoutes && !isOpenApi) {
|
|
114
114
|
// If flag is enabled and there is no @openapi tag, then skip path
|
|
115
115
|
return;
|
|
@@ -125,6 +125,9 @@ export class RouteProcessor {
|
|
|
125
125
|
tags: [tag || rootPath],
|
|
126
126
|
parameters: [],
|
|
127
127
|
};
|
|
128
|
+
if (deprecated) {
|
|
129
|
+
definition.deprecated = true;
|
|
130
|
+
}
|
|
128
131
|
// Add auth
|
|
129
132
|
if (auth) {
|
|
130
133
|
definition.security = [
|
|
@@ -157,12 +160,11 @@ export class RouteProcessor {
|
|
|
157
160
|
}
|
|
158
161
|
// Add request body
|
|
159
162
|
if (MUTATION_HTTP_METHODS.includes(method.toUpperCase())) {
|
|
160
|
-
definition.requestBody =
|
|
161
|
-
this.schemaProcessor.createRequestBodySchema(body);
|
|
163
|
+
definition.requestBody = this.schemaProcessor.createRequestBodySchema(body, bodyDescription);
|
|
162
164
|
}
|
|
163
165
|
// Add responses
|
|
164
166
|
definition.responses = responses
|
|
165
|
-
? this.schemaProcessor.createResponseSchema(responses)
|
|
167
|
+
? this.schemaProcessor.createResponseSchema(responses, responseDescription)
|
|
166
168
|
: {};
|
|
167
169
|
this.swaggerPaths[routePath][method] = definition;
|
|
168
170
|
}
|
|
@@ -555,19 +555,23 @@ export class SchemaProcessor {
|
|
|
555
555
|
}
|
|
556
556
|
return queryParams;
|
|
557
557
|
}
|
|
558
|
-
createRequestBodySchema(body) {
|
|
559
|
-
|
|
558
|
+
createRequestBodySchema(body, description) {
|
|
559
|
+
const schema = {
|
|
560
560
|
content: {
|
|
561
561
|
"application/json": {
|
|
562
562
|
schema: body,
|
|
563
563
|
},
|
|
564
564
|
},
|
|
565
565
|
};
|
|
566
|
+
if (description) {
|
|
567
|
+
schema.description = description;
|
|
568
|
+
}
|
|
569
|
+
return schema;
|
|
566
570
|
}
|
|
567
|
-
createResponseSchema(responses) {
|
|
571
|
+
createResponseSchema(responses, description) {
|
|
568
572
|
return {
|
|
569
573
|
200: {
|
|
570
|
-
description: "Successful response",
|
|
574
|
+
description: description || "Successful response",
|
|
571
575
|
content: {
|
|
572
576
|
"application/json": {
|
|
573
577
|
schema: responses,
|
package/dist/lib/utils.js
CHANGED
|
@@ -25,10 +25,30 @@ export function extractJSDocComments(path) {
|
|
|
25
25
|
let responseType = "";
|
|
26
26
|
let auth = "";
|
|
27
27
|
let isOpenApi = false;
|
|
28
|
+
let deprecated = false;
|
|
29
|
+
let bodyDescription = "";
|
|
30
|
+
let responseDescription = "";
|
|
28
31
|
if (comments) {
|
|
29
32
|
comments.forEach((comment) => {
|
|
30
33
|
const commentValue = cleanComment(comment.value);
|
|
31
34
|
isOpenApi = commentValue.includes("@openapi");
|
|
35
|
+
if (commentValue.includes("@deprecated")) {
|
|
36
|
+
deprecated = true;
|
|
37
|
+
}
|
|
38
|
+
if (commentValue.includes("@bodyDescription")) {
|
|
39
|
+
const regex = /@bodyDescription\s*(.*)/;
|
|
40
|
+
const match = commentValue.match(regex);
|
|
41
|
+
if (match && match[1]) {
|
|
42
|
+
bodyDescription = match[1].trim();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (commentValue.includes("@responseDescription")) {
|
|
46
|
+
const regex = /@responseDescription\s*(.*)/;
|
|
47
|
+
const match = commentValue.match(regex);
|
|
48
|
+
if (match && match[1]) {
|
|
49
|
+
responseDescription = match[1].trim();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
32
52
|
if (!summary) {
|
|
33
53
|
summary = commentValue.split("\n")[0];
|
|
34
54
|
}
|
|
@@ -82,6 +102,9 @@ export function extractJSDocComments(path) {
|
|
|
82
102
|
bodyType,
|
|
83
103
|
responseType,
|
|
84
104
|
isOpenApi,
|
|
105
|
+
deprecated,
|
|
106
|
+
bodyDescription,
|
|
107
|
+
responseDescription,
|
|
85
108
|
};
|
|
86
109
|
}
|
|
87
110
|
export function extractTypeFromComment(commentValue, tag) {
|
|
@@ -874,9 +874,21 @@ export class ZodSchemaConverter {
|
|
|
874
874
|
break;
|
|
875
875
|
case "describe":
|
|
876
876
|
if (node.arguments.length > 0 && t.isStringLiteral(node.arguments[0])) {
|
|
877
|
-
|
|
877
|
+
const description = node.arguments[0].value;
|
|
878
|
+
// Check if description includes @deprecated
|
|
879
|
+
if (description.startsWith("@deprecated")) {
|
|
880
|
+
schema.deprecated = true;
|
|
881
|
+
// Remove @deprecated from description
|
|
882
|
+
schema.description = description.replace("@deprecated", "").trim();
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
schema.description = description;
|
|
886
|
+
}
|
|
878
887
|
}
|
|
879
888
|
break;
|
|
889
|
+
case "deprecated":
|
|
890
|
+
schema.deprecated = true;
|
|
891
|
+
break;
|
|
880
892
|
case "min":
|
|
881
893
|
if (node.arguments.length > 0 &&
|
|
882
894
|
t.isNumericLiteral(node.arguments[0])) {
|
package/package.json
CHANGED