next-openapi-gen 1.3.0 → 1.4.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.
@@ -388,7 +388,7 @@ function parseJSDocBlock(commentValue, filePath) {
388
388
  result.cookieType = extractTypeFromComment(normalizedComment, "@cookie");
389
389
  const authValue = extractLineValue(normalizedComment, "@auth");
390
390
  if (authValue) {
391
- result.auth = performAuthPresetReplacements(authValue);
391
+ result.auth = authValue;
392
392
  }
393
393
  const querystring = parseQuerystringTag(normalizedComment);
394
394
  if (querystring) {
@@ -1064,16 +1064,17 @@ var INTERNAL_OPENAPI_CONFIG_KEYS = [
1064
1064
  "next",
1065
1065
  "diagnostics",
1066
1066
  "debug",
1067
+ "authPresets",
1067
1068
  "excludeSchemas"
1068
1069
  ];
1069
- var AUTH_PRESET_REPLACEMENTS = {
1070
+ var DEFAULT_AUTH_PRESET_REPLACEMENTS = {
1070
1071
  bearer: "BearerAuth",
1071
1072
  basic: "BasicAuth",
1072
1073
  apikey: "ApiKeyAuth"
1073
1074
  };
1074
- function performAuthPresetReplacements(authValue) {
1075
+ function performAuthPresetReplacements(authValue, presets = DEFAULT_AUTH_PRESET_REPLACEMENTS) {
1075
1076
  const authParts = authValue.split(",").map((part) => part.trim());
1076
- const mappedParts = authParts.map((part) => AUTH_PRESET_REPLACEMENTS[part.toLowerCase()] || part);
1077
+ const mappedParts = authParts.map((part) => presets[part.toLowerCase()] || part);
1077
1078
  return mappedParts.join(",");
1078
1079
  }
1079
1080
  function getOperationId(routePath, method) {
@@ -1346,6 +1347,7 @@ function normalizeOpenApiConfig(template) {
1346
1347
  adapterPath: template.next?.adapterPath
1347
1348
  },
1348
1349
  diagnostics: template.diagnostics ?? { enabled: DEFAULT_DIAGNOSTICS_ENABLED },
1350
+ authPresets: { ...DEFAULT_AUTH_PRESET_REPLACEMENTS, ...template.authPresets },
1349
1351
  debug: template.debug ?? DEFAULT_DEBUG
1350
1352
  };
1351
1353
  }
@@ -1827,8 +1829,10 @@ function downgradeSchemaForOpenApi30(schema, mediaTypeName) {
1827
1829
  const nullableBranch = nextSchema.anyOf.find((item) => item.type === "null");
1828
1830
  const baseBranch = nextSchema.anyOf.find((item) => item.type !== "null");
1829
1831
  if (nullableBranch && baseBranch) {
1832
+ const { anyOf: _anyOf, ...outerMeta } = nextSchema;
1830
1833
  nextSchema = {
1831
1834
  ...structuredClone(baseBranch),
1835
+ ...outerMeta,
1832
1836
  nullable: true
1833
1837
  };
1834
1838
  }
@@ -3703,7 +3707,7 @@ function processZodLiteral(node, context) {
3703
3707
  return { type: "string", enum: [arg.value] };
3704
3708
  }
3705
3709
  if (t8.isNumericLiteral(arg)) {
3706
- return { type: "number", enum: [arg.value] };
3710
+ return { type: Number.isInteger(arg.value) ? "integer" : "number", enum: [arg.value] };
3707
3711
  }
3708
3712
  if (t8.isBooleanLiteral(arg)) {
3709
3713
  return { type: "boolean", enum: [arg.value] };
@@ -3719,7 +3723,7 @@ function processZodLiteral(node, context) {
3719
3723
  if (typeof value === "string")
3720
3724
  return { type: "string", enum: [value] };
3721
3725
  if (typeof value === "number")
3722
- return { type: "number", enum: [value] };
3726
+ return { type: Number.isInteger(value) ? "integer" : "number", enum: [value] };
3723
3727
  if (typeof value === "boolean")
3724
3728
  return { type: "boolean", enum: [value] };
3725
3729
  if (value === null)
@@ -3814,7 +3818,7 @@ function processZodTuple(node, processNode, context) {
3814
3818
  if (t8.isIdentifier(node.arguments[0]) && context?.resolveConstArrayValues) {
3815
3819
  const values = context.resolveConstArrayValues(node.arguments[0].name);
3816
3820
  if (values && values.length > 0) {
3817
- const prefixItems = values.map((value) => typeof value === "number" ? { type: "number", enum: [value] } : { type: "string", enum: [value] });
3821
+ const prefixItems = values.map((value) => typeof value === "number" ? { type: Number.isInteger(value) ? "integer" : "number", enum: [value] } : { type: "string", enum: [value] });
3818
3822
  return {
3819
3823
  type: "array",
3820
3824
  prefixItems,
@@ -3858,7 +3862,7 @@ function processZodUnion(node, processNode, context) {
3858
3862
  if (t8.isIdentifier(node.arguments[0]) && context?.resolveConstArrayValues) {
3859
3863
  const values = context.resolveConstArrayValues(node.arguments[0].name);
3860
3864
  if (values && values.length > 0) {
3861
- const type = typeof values[0] === "number" ? "number" : "string";
3865
+ const type = typeof values[0] === "number" ? Number.isInteger(values[0]) ? "integer" : "number" : "string";
3862
3866
  return { type, enum: values };
3863
3867
  }
3864
3868
  }
@@ -11305,8 +11309,17 @@ var ZodRuntimeExporter = class {
11305
11309
  return node.arguments[0] ? literal(this.buildLiteralValue(node.arguments[0])) : null;
11306
11310
  case "enum":
11307
11311
  return this.buildEnum(node);
11308
- case "array":
11309
- return node.arguments[0] && isProcessableNode(node.arguments[0]) ? array(this.buildSchema(node.arguments[0]) ?? unknown()) : array(unknown());
11312
+ case "array": {
11313
+ const arg = node.arguments[0];
11314
+ if (!arg || !isProcessableNode(arg)) {
11315
+ return array(unknown());
11316
+ }
11317
+ const itemSchema = this.buildSchema(arg);
11318
+ if (!itemSchema) {
11319
+ return null;
11320
+ }
11321
+ return array(itemSchema);
11322
+ }
11310
11323
  case "strictObject": {
11311
11324
  const base = this.buildObject(node);
11312
11325
  return base && typeof base.strict === "function" ? base.strict() : base;
@@ -11438,13 +11451,17 @@ var ZodRuntimeExporter = class {
11438
11451
  if (node.arguments.length === 0 || !t9.isArrayExpression(node.arguments[0])) {
11439
11452
  return tuple([]);
11440
11453
  }
11441
- const items = node.arguments[0].elements.flatMap((element) => {
11454
+ const items = [];
11455
+ for (const element of node.arguments[0].elements) {
11442
11456
  if (!isProcessableNode(element)) {
11443
- return [];
11457
+ return null;
11444
11458
  }
11445
11459
  const schema = this.buildSchema(element);
11446
- return schema ? [schema] : [];
11447
- });
11460
+ if (!schema) {
11461
+ return null;
11462
+ }
11463
+ items.push(schema);
11464
+ }
11448
11465
  return tuple(items);
11449
11466
  }
11450
11467
  buildTemplateLiteral(node) {
@@ -12056,7 +12073,12 @@ var ZodSchemaConverter = class {
12056
12073
  if (this.isZodSchema(path17.node.init)) {
12057
12074
  const schema = this.processZodNode(path17.node.init);
12058
12075
  if (schema) {
12059
- this.storeResolvedSchema(schemaName, schema);
12076
+ const overrideId = this.extractMetaIdFromNode(path17.node.init);
12077
+ if (overrideId) {
12078
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
12079
+ } else {
12080
+ this.storeResolvedSchema(schemaName, schema);
12081
+ }
12060
12082
  }
12061
12083
  return;
12062
12084
  }
@@ -12399,8 +12421,15 @@ var ZodSchemaConverter = class {
12399
12421
  };
12400
12422
  switch (methodName) {
12401
12423
  case "optional":
12424
+ break;
12402
12425
  case "nullable":
12403
12426
  case "nullish":
12427
+ schema = {
12428
+ anyOf: [
12429
+ { $ref: `#/components/schemas/${this.getSchemaReferenceName(schemaName)}` },
12430
+ { type: "null" }
12431
+ ]
12432
+ };
12404
12433
  break;
12405
12434
  case "describe":
12406
12435
  if (node.arguments.length > 0 && t10.isStringLiteral(node.arguments[0])) {
@@ -12918,12 +12947,16 @@ var ZodSchemaConverter = class {
12918
12947
  case "optional":
12919
12948
  break;
12920
12949
  case "nullable":
12921
- if (!schema.allOf) {
12950
+ if (schema.allOf) {
12951
+ schema = { anyOf: [...schema.allOf, { type: "null" }] };
12952
+ } else {
12922
12953
  schema.nullable = true;
12923
12954
  }
12924
12955
  break;
12925
12956
  case "nullish":
12926
- if (!schema.allOf) {
12957
+ if (schema.allOf) {
12958
+ schema = { anyOf: [...schema.allOf, { type: "null" }] };
12959
+ } else {
12927
12960
  schema.nullable = true;
12928
12961
  }
12929
12962
  break;
@@ -13438,6 +13471,9 @@ var ZodSchemaConverter = class {
13438
13471
  if (!this.getStoredSchema(schemaName)) {
13439
13472
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13440
13473
  this.processingSchemas.add(schemaName);
13474
+ this.currentFilePath = filePath;
13475
+ this.currentAST = ast;
13476
+ this.currentImports = importedModules;
13441
13477
  const schema = this.processZodNode(declaration.init);
13442
13478
  this.processingSchemas.delete(schemaName);
13443
13479
  if (schema) {
@@ -13470,6 +13506,9 @@ var ZodSchemaConverter = class {
13470
13506
  if (!this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
13471
13507
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
13472
13508
  this.processingSchemas.add(schemaName);
13509
+ this.currentFilePath = filePath;
13510
+ this.currentAST = ast;
13511
+ this.currentImports = importedModules;
13473
13512
  const schema = this.processZodNode(declaration.init);
13474
13513
  this.processingSchemas.delete(schemaName);
13475
13514
  if (schema) {
@@ -16340,11 +16379,16 @@ var ResponseProcessor = class {
16340
16379
  var OperationProcessor = class {
16341
16380
  schemaProcessor;
16342
16381
  responseProcessor;
16382
+ authPresets;
16343
16383
  performanceProfile;
16344
- constructor(schemaProcessor, responseProcessor, performanceProfile) {
16384
+ constructor(schemaProcessor, responseProcessor, options = {}) {
16345
16385
  this.schemaProcessor = schemaProcessor;
16346
16386
  this.responseProcessor = responseProcessor;
16347
- this.performanceProfile = performanceProfile;
16387
+ this.authPresets = {
16388
+ ...DEFAULT_AUTH_PRESET_REPLACEMENTS,
16389
+ ...options.authPresets
16390
+ };
16391
+ this.performanceProfile = options.performanceProfile;
16348
16392
  }
16349
16393
  processOperation(varName, routePath, dataTypes, pathParamNames = []) {
16350
16394
  const method = varName.toLowerCase();
@@ -16369,9 +16413,10 @@ var OperationProcessor = class {
16369
16413
  definition.deprecated = true;
16370
16414
  }
16371
16415
  if (explicitSecurity && explicitSecurity.length > 0) {
16372
- definition.security = explicitSecurity;
16416
+ definition.security = explicitSecurity.map((req) => Object.fromEntries(Object.entries(req).map(([scheme, scopes]) => [this.applyPreset(scheme), scopes])));
16373
16417
  } else if (auth) {
16374
- const authItems = auth.split(",").map((item) => item.trim());
16418
+ const mapped = performAuthPresetReplacements(auth, this.authPresets);
16419
+ const authItems = mapped.split(",").map((item) => item.trim());
16375
16420
  definition.security = authItems.map((authItem) => ({
16376
16421
  [authItem]: []
16377
16422
  }));
@@ -16584,6 +16629,9 @@ ${suffix}`;
16584
16629
  response.links[link.name] = linkObject;
16585
16630
  }
16586
16631
  }
16632
+ applyPreset(scheme) {
16633
+ return this.authPresets[scheme.toLowerCase()] ?? scheme;
16634
+ }
16587
16635
  createQuerystringParameter(dataTypes) {
16588
16636
  if (!dataTypes.querystringType) {
16589
16637
  return void 0;
@@ -16672,7 +16720,10 @@ var RouteProcessor = class {
16672
16720
  return new RegExp(`^${regexPattern}$`);
16673
16721
  });
16674
16722
  this.responseProcessor = new ResponseProcessor(this.config, this.schemaProcessor);
16675
- this.operationProcessor = new OperationProcessor(this.schemaProcessor, this.responseProcessor, this.performanceProfile);
16723
+ this.operationProcessor = new OperationProcessor(this.schemaProcessor, this.responseProcessor, {
16724
+ authPresets: this.config.authPresets,
16725
+ performanceProfile: this.performanceProfile
16726
+ });
16676
16727
  }
16677
16728
  processResponsesFromConfig(dataTypes, method) {
16678
16729
  return this.responseProcessor.processResponses(dataTypes, method);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-openapi-gen",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Automatically generate OpenAPI 3.0, 3.1, and 3.2 documentation from Next.js projects, with support for Zod schemas, TypeScript types, and reusable OpenAPI fragments.",
5
5
  "keywords": [
6
6
  "api",