next-openapi-gen 0.5.5 → 0.6.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 +4 -3
- package/dist/lib/utils.js +2 -2
- package/dist/lib/zod-converter.js +160 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,7 +97,7 @@ type UserResponse = {
|
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
99
|
* Get user information
|
|
100
|
-
* @
|
|
100
|
+
* @description Fetches detailed user information by ID
|
|
101
101
|
* @pathParams UserParams
|
|
102
102
|
* @response UserResponse
|
|
103
103
|
* @openapi
|
|
@@ -130,7 +130,7 @@ export const ProductResponse = z.object({
|
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
132
|
* Get product information
|
|
133
|
-
* @
|
|
133
|
+
* @description Fetches detailed product information by ID
|
|
134
134
|
* @pathParams ProductParams
|
|
135
135
|
* @response ProductResponse
|
|
136
136
|
* @openapi
|
|
@@ -147,7 +147,7 @@ export async function GET(
|
|
|
147
147
|
|
|
148
148
|
| Tag | Description |
|
|
149
149
|
| ---------------------- | ----------------------------------------------------------------------------------- |
|
|
150
|
-
| `@
|
|
150
|
+
| `@description` | Endpoint description |
|
|
151
151
|
| `@pathParams` | Path parameters type/schema |
|
|
152
152
|
| `@params` | Query parameters type/schema |
|
|
153
153
|
| `@body` | Request body type/schema |
|
|
@@ -336,6 +336,7 @@ const UserSchema = z.object({
|
|
|
336
336
|
});
|
|
337
337
|
|
|
338
338
|
/**
|
|
339
|
+
* @body UserSchema
|
|
339
340
|
* @response UserResponse
|
|
340
341
|
*/
|
|
341
342
|
export async function GET() {
|
package/dist/lib/utils.js
CHANGED
|
@@ -67,8 +67,8 @@ export function extractJSDocComments(path) {
|
|
|
67
67
|
break;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
if (commentValue.includes("@
|
|
71
|
-
const regex = /@
|
|
70
|
+
if (commentValue.includes("@description")) {
|
|
71
|
+
const regex = /@description\s*(.*)/;
|
|
72
72
|
description = commentValue.match(regex)[1].trim();
|
|
73
73
|
}
|
|
74
74
|
if (commentValue.includes("@tag")) {
|
|
@@ -236,6 +236,145 @@ export class ZodSchemaConverter {
|
|
|
236
236
|
if (t.isIdentifier(path.node.id) &&
|
|
237
237
|
path.node.id.name === schemaName &&
|
|
238
238
|
path.node.init) {
|
|
239
|
+
// Check if this is any Zod schema (including chained calls)
|
|
240
|
+
if (this.isZodSchema(path.node.init)) {
|
|
241
|
+
const schema = this.processZodNode(path.node.init);
|
|
242
|
+
if (schema) {
|
|
243
|
+
this.zodSchemas[schemaName] = schema;
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
// Helper function for processing the call chain
|
|
248
|
+
const processChainedCall = (node, baseSchema) => {
|
|
249
|
+
if (!t.isCallExpression(node) ||
|
|
250
|
+
!t.isMemberExpression(node.callee)) {
|
|
251
|
+
return baseSchema;
|
|
252
|
+
}
|
|
253
|
+
// @ts-ignore
|
|
254
|
+
const methodName = node.callee.property.name;
|
|
255
|
+
let schema = baseSchema;
|
|
256
|
+
// If there is an even deeper call, process it first
|
|
257
|
+
if (t.isCallExpression(node.callee.object)) {
|
|
258
|
+
schema = processChainedCall(node.callee.object, baseSchema);
|
|
259
|
+
}
|
|
260
|
+
// Now apply the current method
|
|
261
|
+
switch (methodName) {
|
|
262
|
+
case "omit":
|
|
263
|
+
if (node.arguments.length > 0 &&
|
|
264
|
+
t.isObjectExpression(node.arguments[0])) {
|
|
265
|
+
node.arguments[0].properties.forEach((prop) => {
|
|
266
|
+
if (t.isObjectProperty(prop) &&
|
|
267
|
+
t.isBooleanLiteral(prop.value) &&
|
|
268
|
+
prop.value.value === true) {
|
|
269
|
+
const key = t.isIdentifier(prop.key)
|
|
270
|
+
? prop.key.name
|
|
271
|
+
: t.isStringLiteral(prop.key)
|
|
272
|
+
? prop.key.value
|
|
273
|
+
: null;
|
|
274
|
+
if (key && schema.properties) {
|
|
275
|
+
console.log(`Removing property: ${key}`);
|
|
276
|
+
delete schema.properties[key];
|
|
277
|
+
if (schema.required) {
|
|
278
|
+
schema.required = schema.required.filter((r) => r !== key);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
break;
|
|
285
|
+
case "partial":
|
|
286
|
+
// All fields become optional
|
|
287
|
+
if (schema.properties) {
|
|
288
|
+
Object.keys(schema.properties).forEach((key) => {
|
|
289
|
+
schema.properties[key].nullable = true;
|
|
290
|
+
});
|
|
291
|
+
// Remove all required
|
|
292
|
+
delete schema.required;
|
|
293
|
+
}
|
|
294
|
+
break;
|
|
295
|
+
case "pick":
|
|
296
|
+
if (node.arguments.length > 0 &&
|
|
297
|
+
t.isObjectExpression(node.arguments[0])) {
|
|
298
|
+
const keysToPick = [];
|
|
299
|
+
node.arguments[0].properties.forEach((prop) => {
|
|
300
|
+
if (t.isObjectProperty(prop) &&
|
|
301
|
+
t.isBooleanLiteral(prop.value) &&
|
|
302
|
+
prop.value.value === true) {
|
|
303
|
+
const key = t.isIdentifier(prop.key)
|
|
304
|
+
? prop.key.name
|
|
305
|
+
: t.isStringLiteral(prop.key)
|
|
306
|
+
? prop.key.value
|
|
307
|
+
: null;
|
|
308
|
+
if (key)
|
|
309
|
+
keysToPick.push(key);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
// Keep only selected properties
|
|
313
|
+
if (schema.properties) {
|
|
314
|
+
const newProperties = {};
|
|
315
|
+
keysToPick.forEach((key) => {
|
|
316
|
+
if (schema.properties[key]) {
|
|
317
|
+
newProperties[key] = schema.properties[key];
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
schema.properties = newProperties;
|
|
321
|
+
// Update required
|
|
322
|
+
if (schema.required) {
|
|
323
|
+
schema.required = schema.required.filter((key) => keysToPick.includes(key));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
case "required":
|
|
329
|
+
// All fields become required
|
|
330
|
+
if (schema.properties) {
|
|
331
|
+
const requiredFields = Object.keys(schema.properties);
|
|
332
|
+
schema.required = requiredFields;
|
|
333
|
+
// Remove nullable from fields
|
|
334
|
+
Object.keys(schema.properties).forEach((key) => {
|
|
335
|
+
delete schema.properties[key].nullable;
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
return schema;
|
|
341
|
+
};
|
|
342
|
+
// Find the underlying schema (the most nested object in the chain)
|
|
343
|
+
const findBaseSchema = (node) => {
|
|
344
|
+
if (t.isIdentifier(node)) {
|
|
345
|
+
return node.name;
|
|
346
|
+
}
|
|
347
|
+
else if (t.isMemberExpression(node)) {
|
|
348
|
+
return findBaseSchema(node.object);
|
|
349
|
+
}
|
|
350
|
+
else if (t.isCallExpression(node) &&
|
|
351
|
+
t.isMemberExpression(node.callee)) {
|
|
352
|
+
return findBaseSchema(node.callee.object);
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
};
|
|
356
|
+
// Check method calls on other schemas
|
|
357
|
+
if (t.isCallExpression(path.node.init)) {
|
|
358
|
+
const baseSchemaName = findBaseSchema(path.node.init);
|
|
359
|
+
if (baseSchemaName && baseSchemaName !== "z") {
|
|
360
|
+
console.log(`Found chained call starting from: ${baseSchemaName}`);
|
|
361
|
+
// First make sure the underlying schema is processed
|
|
362
|
+
if (!this.zodSchemas[baseSchemaName]) {
|
|
363
|
+
console.log(`Base schema ${baseSchemaName} not found, processing it first`);
|
|
364
|
+
this.processFileForZodSchema(filePath, baseSchemaName);
|
|
365
|
+
}
|
|
366
|
+
if (this.zodSchemas[baseSchemaName]) {
|
|
367
|
+
console.log(`Base schema found, applying transformations`);
|
|
368
|
+
// Copy base schema
|
|
369
|
+
const baseSchema = JSON.parse(JSON.stringify(this.zodSchemas[baseSchemaName]));
|
|
370
|
+
// Process the entire call chain
|
|
371
|
+
const finalSchema = processChainedCall(path.node.init, baseSchema);
|
|
372
|
+
this.zodSchemas[schemaName] = finalSchema;
|
|
373
|
+
console.log(`Created ${schemaName} with properties:`, Object.keys(finalSchema.properties || {}));
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
239
378
|
// Check if it is .extend()
|
|
240
379
|
if (t.isCallExpression(path.node.init) &&
|
|
241
380
|
t.isMemberExpression(path.node.init.callee) &&
|
|
@@ -1269,6 +1408,25 @@ export class ZodSchemaConverter {
|
|
|
1269
1408
|
});
|
|
1270
1409
|
}
|
|
1271
1410
|
},
|
|
1411
|
+
// Also process non-exported const declarations
|
|
1412
|
+
VariableDeclaration: (path) => {
|
|
1413
|
+
path.node.declarations.forEach((declaration) => {
|
|
1414
|
+
if (t.isIdentifier(declaration.id) && declaration.init) {
|
|
1415
|
+
const schemaName = declaration.id.name;
|
|
1416
|
+
if (this.isZodSchema(declaration.init) &&
|
|
1417
|
+
!this.zodSchemas[schemaName] &&
|
|
1418
|
+
!this.processingSchemas.has(schemaName)) {
|
|
1419
|
+
console.log(`Pre-processing Zod schema: ${schemaName}`);
|
|
1420
|
+
this.processingSchemas.add(schemaName);
|
|
1421
|
+
const schema = this.processZodNode(declaration.init);
|
|
1422
|
+
if (schema) {
|
|
1423
|
+
this.zodSchemas[schemaName] = schema;
|
|
1424
|
+
}
|
|
1425
|
+
this.processingSchemas.delete(schemaName);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
});
|
|
1429
|
+
},
|
|
1272
1430
|
});
|
|
1273
1431
|
}
|
|
1274
1432
|
catch (error) {
|
|
@@ -1280,11 +1438,13 @@ export class ZodSchemaConverter {
|
|
|
1280
1438
|
*/
|
|
1281
1439
|
isZodSchema(node) {
|
|
1282
1440
|
if (t.isCallExpression(node)) {
|
|
1441
|
+
// Check direct z.method() calls
|
|
1283
1442
|
if (t.isMemberExpression(node.callee) &&
|
|
1284
1443
|
t.isIdentifier(node.callee.object) &&
|
|
1285
1444
|
node.callee.object.name === "z") {
|
|
1286
1445
|
return true;
|
|
1287
1446
|
}
|
|
1447
|
+
// Check chained calls like z.string().regex()
|
|
1288
1448
|
if (t.isMemberExpression(node.callee) &&
|
|
1289
1449
|
t.isCallExpression(node.callee.object)) {
|
|
1290
1450
|
return this.isZodSchema(node.callee.object);
|
package/package.json
CHANGED