next-openapi-gen 1.3.0 → 1.4.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.
@@ -737,96 +737,100 @@ function typeToOpenApiSchema(type, checker, seen) {
737
737
  return { type: "object" };
738
738
  }
739
739
  seen.add(seenKey);
740
- if (type.isStringLiteral()) {
741
- return { type: "string", enum: [type.value] };
742
- }
743
- if (type.isNumberLiteral()) {
744
- return { type: "number", enum: [type.value] };
745
- }
746
- if (type.flags & ts2.TypeFlags.BooleanLiteral) {
747
- return {
748
- type: "boolean",
749
- enum: [checker.typeToString(type) === "true"]
750
- };
751
- }
752
- if (type.flags & ts2.TypeFlags.TemplateLiteral) {
753
- return { type: "string" };
754
- }
755
- if (type.flags & ts2.TypeFlags.StringLike) {
756
- return { type: "string" };
757
- }
758
- if (type.flags & ts2.TypeFlags.NumberLike) {
759
- return { type: "number" };
760
- }
761
- if (type.flags & ts2.TypeFlags.BooleanLike) {
762
- return { type: "boolean" };
763
- }
764
- if (type.flags & ts2.TypeFlags.Null) {
765
- return { type: "null" };
766
- }
767
- if (type.isUnion()) {
768
- const nullable2 = type.types.some((member) => member.flags & ts2.TypeFlags.Null);
769
- const nonNullTypes = type.types.filter((member) => !(member.flags & ts2.TypeFlags.Null));
770
- const soleNonNullType = nonNullTypes[0];
771
- if (nullable2 && soleNonNullType && nonNullTypes.length === 1) {
740
+ try {
741
+ if (type.isStringLiteral()) {
742
+ return { type: "string", enum: [type.value] };
743
+ }
744
+ if (type.isNumberLiteral()) {
745
+ return { type: "number", enum: [type.value] };
746
+ }
747
+ if (type.flags & ts2.TypeFlags.BooleanLiteral) {
772
748
  return {
773
- ...typeToOpenApiSchema(soleNonNullType, checker, seen),
774
- nullable: true
749
+ type: "boolean",
750
+ enum: [checker.typeToString(type) === "true"]
775
751
  };
776
752
  }
777
- return {
778
- oneOf: nonNullTypes.map((member) => typeToOpenApiSchema(member, checker, seen))
779
- };
780
- }
781
- if (checker.isTupleType(type)) {
782
- const itemTypes = checker.getTypeArguments(type);
783
- return {
784
- type: "array",
785
- prefixItems: itemTypes.map((itemType) => typeToOpenApiSchema(itemType, checker, seen)),
786
- items: false,
787
- minItems: itemTypes.length,
788
- maxItems: itemTypes.length
789
- };
790
- }
791
- if (checker.isArrayType(type)) {
792
- const elementType = checker.getTypeArguments(type)[0];
793
- return {
794
- type: "array",
795
- items: elementType ? typeToOpenApiSchema(elementType, checker, seen) : { type: "object" }
796
- };
797
- }
798
- const properties = checker.getPropertiesOfType(type);
799
- if (properties.length > 0) {
800
- const schemaProperties = {};
801
- const required2 = [];
802
- properties.forEach((property) => {
803
- const propertyDeclaration = property.valueDeclaration || property.declarations?.[0];
804
- if (!propertyDeclaration) {
805
- return;
806
- }
807
- const propertyType = checker.getTypeOfSymbolAtLocation(property, propertyDeclaration);
808
- schemaProperties[property.getName()] = typeToOpenApiSchema(propertyType, checker, seen);
809
- if (!(property.flags & ts2.SymbolFlags.Optional)) {
810
- required2.push(property.getName());
753
+ if (type.flags & ts2.TypeFlags.TemplateLiteral) {
754
+ return { type: "string" };
755
+ }
756
+ if (type.flags & ts2.TypeFlags.StringLike) {
757
+ return { type: "string" };
758
+ }
759
+ if (type.flags & ts2.TypeFlags.NumberLike) {
760
+ return { type: "number" };
761
+ }
762
+ if (type.flags & ts2.TypeFlags.BooleanLike) {
763
+ return { type: "boolean" };
764
+ }
765
+ if (type.flags & ts2.TypeFlags.Null) {
766
+ return { type: "null" };
767
+ }
768
+ if (type.isUnion()) {
769
+ const nullable2 = type.types.some((member) => member.flags & ts2.TypeFlags.Null);
770
+ const nonNullTypes = type.types.filter((member) => !(member.flags & ts2.TypeFlags.Null));
771
+ const soleNonNullType = nonNullTypes[0];
772
+ if (nullable2 && soleNonNullType && nonNullTypes.length === 1) {
773
+ return {
774
+ ...typeToOpenApiSchema(soleNonNullType, checker, seen),
775
+ nullable: true
776
+ };
811
777
  }
812
- });
813
- return required2.length > 0 ? {
814
- type: "object",
815
- properties: schemaProperties,
816
- required: required2
817
- } : {
818
- type: "object",
819
- properties: schemaProperties
820
- };
821
- }
822
- const stringIndexType = type.getStringIndexType();
823
- if (stringIndexType) {
824
- return {
825
- type: "object",
826
- additionalProperties: typeToOpenApiSchema(stringIndexType, checker, seen)
827
- };
778
+ return {
779
+ oneOf: nonNullTypes.map((member) => typeToOpenApiSchema(member, checker, seen))
780
+ };
781
+ }
782
+ if (checker.isTupleType(type)) {
783
+ const itemTypes = checker.getTypeArguments(type);
784
+ return {
785
+ type: "array",
786
+ prefixItems: itemTypes.map((itemType) => typeToOpenApiSchema(itemType, checker, seen)),
787
+ items: false,
788
+ minItems: itemTypes.length,
789
+ maxItems: itemTypes.length
790
+ };
791
+ }
792
+ if (checker.isArrayType(type)) {
793
+ const elementType = checker.getTypeArguments(type)[0];
794
+ return {
795
+ type: "array",
796
+ items: elementType ? typeToOpenApiSchema(elementType, checker, seen) : { type: "object" }
797
+ };
798
+ }
799
+ const properties = checker.getPropertiesOfType(type);
800
+ if (properties.length > 0) {
801
+ const schemaProperties = {};
802
+ const required2 = [];
803
+ properties.forEach((property) => {
804
+ const propertyDeclaration = property.valueDeclaration || property.declarations?.[0];
805
+ if (!propertyDeclaration) {
806
+ return;
807
+ }
808
+ const propertyType = checker.getTypeOfSymbolAtLocation(property, propertyDeclaration);
809
+ schemaProperties[property.getName()] = typeToOpenApiSchema(propertyType, checker, seen);
810
+ if (!(property.flags & ts2.SymbolFlags.Optional)) {
811
+ required2.push(property.getName());
812
+ }
813
+ });
814
+ return required2.length > 0 ? {
815
+ type: "object",
816
+ properties: schemaProperties,
817
+ required: required2
818
+ } : {
819
+ type: "object",
820
+ properties: schemaProperties
821
+ };
822
+ }
823
+ const stringIndexType = type.getStringIndexType();
824
+ if (stringIndexType) {
825
+ return {
826
+ type: "object",
827
+ additionalProperties: typeToOpenApiSchema(stringIndexType, checker, seen)
828
+ };
829
+ }
830
+ return { type: "object" };
831
+ } finally {
832
+ seen.delete(seenKey);
828
833
  }
829
- return { type: "object" };
830
834
  }
831
835
  function unwrapPromiseType(type, checker) {
832
836
  const symbolName = type.getSymbol()?.getName();
@@ -938,7 +942,7 @@ function parseJSDocBlock(commentValue, filePath) {
938
942
  result.cookieType = extractTypeFromComment(normalizedComment, "@cookie");
939
943
  const authValue = extractLineValue(normalizedComment, "@auth");
940
944
  if (authValue) {
941
- result.auth = performAuthPresetReplacements(authValue);
945
+ result.auth = authValue;
942
946
  }
943
947
  const querystring = parseQuerystringTag(normalizedComment);
944
948
  if (querystring) {
@@ -1614,16 +1618,17 @@ var INTERNAL_OPENAPI_CONFIG_KEYS = [
1614
1618
  "next",
1615
1619
  "diagnostics",
1616
1620
  "debug",
1621
+ "authPresets",
1617
1622
  "excludeSchemas"
1618
1623
  ];
1619
- var AUTH_PRESET_REPLACEMENTS = {
1624
+ var DEFAULT_AUTH_PRESET_REPLACEMENTS = {
1620
1625
  bearer: "BearerAuth",
1621
1626
  basic: "BasicAuth",
1622
1627
  apikey: "ApiKeyAuth"
1623
1628
  };
1624
- function performAuthPresetReplacements(authValue) {
1629
+ function performAuthPresetReplacements(authValue, presets = DEFAULT_AUTH_PRESET_REPLACEMENTS) {
1625
1630
  const authParts = authValue.split(",").map((part) => part.trim());
1626
- const mappedParts = authParts.map((part) => AUTH_PRESET_REPLACEMENTS[part.toLowerCase()] || part);
1631
+ const mappedParts = authParts.map((part) => presets[part.toLowerCase()] || part);
1627
1632
  return mappedParts.join(",");
1628
1633
  }
1629
1634
  function getOperationId(routePath, method) {
@@ -2342,6 +2347,7 @@ function normalizeOpenApiConfig(template) {
2342
2347
  adapterPath: template.next?.adapterPath
2343
2348
  },
2344
2349
  diagnostics: template.diagnostics ?? { enabled: DEFAULT_DIAGNOSTICS_ENABLED },
2350
+ authPresets: { ...DEFAULT_AUTH_PRESET_REPLACEMENTS, ...template.authPresets },
2345
2351
  debug: template.debug ?? DEFAULT_DEBUG
2346
2352
  };
2347
2353
  }
@@ -2823,8 +2829,10 @@ function downgradeSchemaForOpenApi30(schema, mediaTypeName) {
2823
2829
  const nullableBranch = nextSchema.anyOf.find((item) => item.type === "null");
2824
2830
  const baseBranch = nextSchema.anyOf.find((item) => item.type !== "null");
2825
2831
  if (nullableBranch && baseBranch) {
2832
+ const { anyOf: _anyOf, ...outerMeta } = nextSchema;
2826
2833
  nextSchema = {
2827
2834
  ...structuredClone(baseBranch),
2835
+ ...outerMeta,
2828
2836
  nullable: true
2829
2837
  };
2830
2838
  }
@@ -4699,7 +4707,7 @@ function processZodLiteral(node, context) {
4699
4707
  return { type: "string", enum: [arg.value] };
4700
4708
  }
4701
4709
  if (t9.isNumericLiteral(arg)) {
4702
- return { type: "number", enum: [arg.value] };
4710
+ return { type: Number.isInteger(arg.value) ? "integer" : "number", enum: [arg.value] };
4703
4711
  }
4704
4712
  if (t9.isBooleanLiteral(arg)) {
4705
4713
  return { type: "boolean", enum: [arg.value] };
@@ -4715,7 +4723,7 @@ function processZodLiteral(node, context) {
4715
4723
  if (typeof value === "string")
4716
4724
  return { type: "string", enum: [value] };
4717
4725
  if (typeof value === "number")
4718
- return { type: "number", enum: [value] };
4726
+ return { type: Number.isInteger(value) ? "integer" : "number", enum: [value] };
4719
4727
  if (typeof value === "boolean")
4720
4728
  return { type: "boolean", enum: [value] };
4721
4729
  if (value === null)
@@ -4810,7 +4818,7 @@ function processZodTuple(node, processNode, context) {
4810
4818
  if (t9.isIdentifier(node.arguments[0]) && context?.resolveConstArrayValues) {
4811
4819
  const values = context.resolveConstArrayValues(node.arguments[0].name);
4812
4820
  if (values && values.length > 0) {
4813
- const prefixItems = values.map((value) => typeof value === "number" ? { type: "number", enum: [value] } : { type: "string", enum: [value] });
4821
+ const prefixItems = values.map((value) => typeof value === "number" ? { type: Number.isInteger(value) ? "integer" : "number", enum: [value] } : { type: "string", enum: [value] });
4814
4822
  return {
4815
4823
  type: "array",
4816
4824
  prefixItems,
@@ -4854,7 +4862,7 @@ function processZodUnion(node, processNode, context) {
4854
4862
  if (t9.isIdentifier(node.arguments[0]) && context?.resolveConstArrayValues) {
4855
4863
  const values = context.resolveConstArrayValues(node.arguments[0].name);
4856
4864
  if (values && values.length > 0) {
4857
- const type = typeof values[0] === "number" ? "number" : "string";
4865
+ const type = typeof values[0] === "number" ? Number.isInteger(values[0]) ? "integer" : "number" : "string";
4858
4866
  return { type, enum: values };
4859
4867
  }
4860
4868
  }
@@ -12301,8 +12309,17 @@ var ZodRuntimeExporter = class {
12301
12309
  return node.arguments[0] ? literal(this.buildLiteralValue(node.arguments[0])) : null;
12302
12310
  case "enum":
12303
12311
  return this.buildEnum(node);
12304
- case "array":
12305
- return node.arguments[0] && isProcessableNode(node.arguments[0]) ? array(this.buildSchema(node.arguments[0]) ?? unknown()) : array(unknown());
12312
+ case "array": {
12313
+ const arg = node.arguments[0];
12314
+ if (!arg || !isProcessableNode(arg)) {
12315
+ return array(unknown());
12316
+ }
12317
+ const itemSchema = this.buildSchema(arg);
12318
+ if (!itemSchema) {
12319
+ return null;
12320
+ }
12321
+ return array(itemSchema);
12322
+ }
12306
12323
  case "strictObject": {
12307
12324
  const base = this.buildObject(node);
12308
12325
  return base && typeof base.strict === "function" ? base.strict() : base;
@@ -12434,13 +12451,17 @@ var ZodRuntimeExporter = class {
12434
12451
  if (node.arguments.length === 0 || !t10.isArrayExpression(node.arguments[0])) {
12435
12452
  return tuple([]);
12436
12453
  }
12437
- const items = node.arguments[0].elements.flatMap((element) => {
12454
+ const items = [];
12455
+ for (const element of node.arguments[0].elements) {
12438
12456
  if (!isProcessableNode(element)) {
12439
- return [];
12457
+ return null;
12440
12458
  }
12441
12459
  const schema = this.buildSchema(element);
12442
- return schema ? [schema] : [];
12443
- });
12460
+ if (!schema) {
12461
+ return null;
12462
+ }
12463
+ items.push(schema);
12464
+ }
12444
12465
  return tuple(items);
12445
12466
  }
12446
12467
  buildTemplateLiteral(node) {
@@ -13052,7 +13073,12 @@ var ZodSchemaConverter = class {
13052
13073
  if (this.isZodSchema(path19.node.init)) {
13053
13074
  const schema = this.processZodNode(path19.node.init);
13054
13075
  if (schema) {
13055
- this.storeResolvedSchema(schemaName, schema);
13076
+ const overrideId = this.extractMetaIdFromNode(path19.node.init);
13077
+ if (overrideId) {
13078
+ this.applyMetaIdOverride(schemaName, schema, overrideId, filePath);
13079
+ } else {
13080
+ this.storeResolvedSchema(schemaName, schema);
13081
+ }
13056
13082
  }
13057
13083
  return;
13058
13084
  }
@@ -13395,8 +13421,15 @@ var ZodSchemaConverter = class {
13395
13421
  };
13396
13422
  switch (methodName) {
13397
13423
  case "optional":
13424
+ break;
13398
13425
  case "nullable":
13399
13426
  case "nullish":
13427
+ schema = {
13428
+ anyOf: [
13429
+ { $ref: `#/components/schemas/${this.getSchemaReferenceName(schemaName)}` },
13430
+ { type: "null" }
13431
+ ]
13432
+ };
13400
13433
  break;
13401
13434
  case "describe":
13402
13435
  if (node.arguments.length > 0 && t11.isStringLiteral(node.arguments[0])) {
@@ -13891,7 +13924,7 @@ var ZodSchemaConverter = class {
13891
13924
  return helperName.startsWith("coerce.") || helperName === "templateLiteral" || helperName === "stringbool";
13892
13925
  }
13893
13926
  if (t11.isMemberExpression(node.callee) && t11.isIdentifier(node.callee.property)) {
13894
- const runtimeMethods = /* @__PURE__ */ new Set(["pipe", "meta"]);
13927
+ const runtimeMethods = /* @__PURE__ */ new Set(["pipe"]);
13895
13928
  if (runtimeMethods.has(node.callee.property.name)) {
13896
13929
  return true;
13897
13930
  }
@@ -13914,12 +13947,16 @@ var ZodSchemaConverter = class {
13914
13947
  case "optional":
13915
13948
  break;
13916
13949
  case "nullable":
13917
- if (!schema.allOf) {
13950
+ if (schema.allOf) {
13951
+ schema = { anyOf: [...schema.allOf, { type: "null" }] };
13952
+ } else {
13918
13953
  schema.nullable = true;
13919
13954
  }
13920
13955
  break;
13921
13956
  case "nullish":
13922
- if (!schema.allOf) {
13957
+ if (schema.allOf) {
13958
+ schema = { anyOf: [...schema.allOf, { type: "null" }] };
13959
+ } else {
13923
13960
  schema.nullable = true;
13924
13961
  }
13925
13962
  break;
@@ -14064,15 +14101,13 @@ var ZodSchemaConverter = class {
14064
14101
  schema.type = "integer";
14065
14102
  break;
14066
14103
  case "positive":
14067
- schema.minimum = 0;
14068
- schema.exclusiveMinimum = true;
14104
+ schema.exclusiveMinimum = 0;
14069
14105
  break;
14070
14106
  case "nonnegative":
14071
14107
  schema.minimum = 0;
14072
14108
  break;
14073
14109
  case "negative":
14074
- schema.maximum = 0;
14075
- schema.exclusiveMaximum = true;
14110
+ schema.exclusiveMaximum = 0;
14076
14111
  break;
14077
14112
  case "nonpositive":
14078
14113
  schema.maximum = 0;
@@ -14434,6 +14469,9 @@ var ZodSchemaConverter = class {
14434
14469
  if (!this.getStoredSchema(schemaName)) {
14435
14470
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
14436
14471
  this.processingSchemas.add(schemaName);
14472
+ this.currentFilePath = filePath;
14473
+ this.currentAST = ast;
14474
+ this.currentImports = importedModules;
14437
14475
  const schema = this.processZodNode(declaration.init);
14438
14476
  this.processingSchemas.delete(schemaName);
14439
14477
  if (schema) {
@@ -14466,6 +14504,9 @@ var ZodSchemaConverter = class {
14466
14504
  if (!this.getStoredSchema(schemaName) && !this.processingSchemas.has(schemaName)) {
14467
14505
  logger.debug(`Pre-processing Zod schema: ${schemaName}`);
14468
14506
  this.processingSchemas.add(schemaName);
14507
+ this.currentFilePath = filePath;
14508
+ this.currentAST = ast;
14509
+ this.currentImports = importedModules;
14469
14510
  const schema = this.processZodNode(declaration.init);
14470
14511
  this.processingSchemas.delete(schemaName);
14471
14512
  if (schema) {
@@ -17336,11 +17377,16 @@ var ResponseProcessor = class {
17336
17377
  var OperationProcessor = class {
17337
17378
  schemaProcessor;
17338
17379
  responseProcessor;
17380
+ authPresets;
17339
17381
  performanceProfile;
17340
- constructor(schemaProcessor, responseProcessor, performanceProfile) {
17382
+ constructor(schemaProcessor, responseProcessor, options = {}) {
17341
17383
  this.schemaProcessor = schemaProcessor;
17342
17384
  this.responseProcessor = responseProcessor;
17343
- this.performanceProfile = performanceProfile;
17385
+ this.authPresets = {
17386
+ ...DEFAULT_AUTH_PRESET_REPLACEMENTS,
17387
+ ...options.authPresets
17388
+ };
17389
+ this.performanceProfile = options.performanceProfile;
17344
17390
  }
17345
17391
  processOperation(varName, routePath, dataTypes, pathParamNames = []) {
17346
17392
  const method = varName.toLowerCase();
@@ -17365,9 +17411,10 @@ var OperationProcessor = class {
17365
17411
  definition.deprecated = true;
17366
17412
  }
17367
17413
  if (explicitSecurity && explicitSecurity.length > 0) {
17368
- definition.security = explicitSecurity;
17414
+ definition.security = explicitSecurity.map((req) => Object.fromEntries(Object.entries(req).map(([scheme, scopes]) => [this.applyPreset(scheme), scopes])));
17369
17415
  } else if (auth) {
17370
- const authItems = auth.split(",").map((item) => item.trim());
17416
+ const mapped = performAuthPresetReplacements(auth, this.authPresets);
17417
+ const authItems = mapped.split(",").map((item) => item.trim());
17371
17418
  definition.security = authItems.map((authItem) => ({
17372
17419
  [authItem]: []
17373
17420
  }));
@@ -17580,6 +17627,9 @@ ${suffix}`;
17580
17627
  response.links[link.name] = linkObject;
17581
17628
  }
17582
17629
  }
17630
+ applyPreset(scheme) {
17631
+ return this.authPresets[scheme.toLowerCase()] ?? scheme;
17632
+ }
17583
17633
  createQuerystringParameter(dataTypes) {
17584
17634
  if (!dataTypes.querystringType) {
17585
17635
  return void 0;
@@ -17668,7 +17718,10 @@ var RouteProcessor = class {
17668
17718
  return new RegExp(`^${regexPattern}$`);
17669
17719
  });
17670
17720
  this.responseProcessor = new ResponseProcessor(this.config, this.schemaProcessor);
17671
- this.operationProcessor = new OperationProcessor(this.schemaProcessor, this.responseProcessor, this.performanceProfile);
17721
+ this.operationProcessor = new OperationProcessor(this.schemaProcessor, this.responseProcessor, {
17722
+ authPresets: this.config.authPresets,
17723
+ performanceProfile: this.performanceProfile
17724
+ });
17672
17725
  }
17673
17726
  processResponsesFromConfig(dataTypes, method) {
17674
17727
  return this.responseProcessor.processResponses(dataTypes, method);
@@ -17910,6 +17963,7 @@ function applyExcludeSchemas(document, mergedSchemas, excludedSchemas) {
17910
17963
  if (excludedNames.size === 0)
17911
17964
  return;
17912
17965
  walkAndInline(document, excludedSchemas, excludedNames, /* @__PURE__ */ new Set());
17966
+ walkAndInline(mergedSchemas, excludedSchemas, excludedNames, /* @__PURE__ */ new Set());
17913
17967
  for (const name of excludedNames) {
17914
17968
  delete mergedSchemas[name];
17915
17969
  }