next-openapi-gen 0.5.6 → 0.6.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.
@@ -188,6 +188,9 @@ export class SchemaProcessor {
188
188
  items: this.resolveTSNodeType(typeNode.elementType),
189
189
  };
190
190
  }
191
+ if (t.isTSUnionType(typeNode)) {
192
+ return this.resolveTSNodeType(typeNode);
193
+ }
191
194
  return {};
192
195
  }
193
196
  finally {
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-openapi-gen",
3
- "version": "0.5.6",
3
+ "version": "0.6.1",
4
4
  "description": "Automatically generate OpenAPI 3.0 documentation from Next.js projects, with support for TypeScript types and Zod schemas.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",