@cerios/openapi-to-zod 1.2.0 → 1.3.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.
package/dist/cli.mjs CHANGED
@@ -5151,12 +5151,12 @@ function toCamelCase(str, options) {
5151
5151
  name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
5152
5152
  }
5153
5153
  if (options == null ? void 0 : options.prefix) {
5154
- const prefix = options.prefix.toLowerCase();
5154
+ const prefix = options.prefix.charAt(0).toLowerCase() + options.prefix.slice(1);
5155
5155
  name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
5156
5156
  }
5157
5157
  if (options == null ? void 0 : options.suffix) {
5158
- const suffix = options.suffix;
5159
- name = name + suffix.charAt(0).toUpperCase() + suffix.slice(1).toLowerCase();
5158
+ const suffix = options.suffix.charAt(0).toUpperCase() + options.suffix.slice(1);
5159
+ name = name + suffix;
5160
5160
  }
5161
5161
  return name;
5162
5162
  }
@@ -5514,12 +5514,56 @@ var init_array_validator = __esm({
5514
5514
  });
5515
5515
 
5516
5516
  // src/validators/composition-validator.ts
5517
+ function isDiscriminatorRequired(schemas, discriminator, context) {
5518
+ const invalidSchemas = [];
5519
+ for (const schema of schemas) {
5520
+ const resolved = resolveSchema(schema, context);
5521
+ const required = resolved.required || [];
5522
+ if (!required.includes(discriminator)) {
5523
+ const schemaName = schema.$ref ? schema.$ref.split("/").pop() || "inline" : "inline";
5524
+ invalidSchemas.push(schemaName);
5525
+ }
5526
+ }
5527
+ return {
5528
+ valid: invalidSchemas.length === 0,
5529
+ invalidSchemas
5530
+ };
5531
+ }
5517
5532
  function generateUnion(schemas, discriminator, isNullable2, context, options, currentSchema) {
5533
+ if (schemas.length === 0) {
5534
+ console.warn(
5535
+ "[openapi-to-zod] Warning: Empty oneOf/anyOf array encountered. This is likely a malformed OpenAPI spec. Generating z.never() as fallback."
5536
+ );
5537
+ return wrapNullable(
5538
+ 'z.never().describe("Empty oneOf/anyOf in OpenAPI spec - no valid schema defined")',
5539
+ isNullable2
5540
+ );
5541
+ }
5542
+ if (schemas.length === 1) {
5543
+ let singleSchema = context.generatePropertySchema(schemas[0], currentSchema);
5544
+ if ((options == null ? void 0 : options.passthrough) && !singleSchema.includes(".catchall(")) {
5545
+ singleSchema = `${singleSchema}.catchall(z.unknown())`;
5546
+ }
5547
+ return wrapNullable(singleSchema, isNullable2);
5548
+ }
5518
5549
  if (discriminator) {
5519
5550
  let resolvedSchemas = schemas;
5520
5551
  if ((options == null ? void 0 : options.discriminatorMapping) && context.resolveDiscriminatorMapping) {
5521
5552
  resolvedSchemas = context.resolveDiscriminatorMapping(options.discriminatorMapping, schemas);
5522
5553
  }
5554
+ const discriminatorCheck = isDiscriminatorRequired(resolvedSchemas, discriminator, context);
5555
+ if (!discriminatorCheck.valid) {
5556
+ console.warn(
5557
+ `[openapi-to-zod] Warning: Discriminator "${discriminator}" is not required in schemas: ${discriminatorCheck.invalidSchemas.join(", ")}. Falling back to z.union() instead of z.discriminatedUnion().`
5558
+ );
5559
+ let schemaStrings3 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
5560
+ if (options == null ? void 0 : options.passthrough) {
5561
+ schemaStrings3 = schemaStrings3.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
5562
+ }
5563
+ const fallbackDescription = `Discriminator "${discriminator}" is optional in some schemas (${discriminatorCheck.invalidSchemas.join(", ")}), using z.union() instead of z.discriminatedUnion()`;
5564
+ const union3 = `z.union([${schemaStrings3.join(", ")}]).describe("${fallbackDescription}")`;
5565
+ return wrapNullable(union3, isNullable2);
5566
+ }
5523
5567
  let schemaStrings2 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
5524
5568
  if (options == null ? void 0 : options.passthrough) {
5525
5569
  schemaStrings2 = schemaStrings2.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
@@ -5534,25 +5578,102 @@ function generateUnion(schemas, discriminator, isNullable2, context, options, cu
5534
5578
  const union = `z.union([${schemaStrings.join(", ")}])`;
5535
5579
  return wrapNullable(union, isNullable2);
5536
5580
  }
5537
- function generateAllOf(schemas, isNullable2, context, currentSchema) {
5581
+ function resolveSchema(schema, context) {
5582
+ if (schema.$ref && context.resolveSchemaRef) {
5583
+ const resolved = context.resolveSchemaRef(schema.$ref);
5584
+ if (resolved) {
5585
+ return resolved;
5586
+ }
5587
+ }
5588
+ return schema;
5589
+ }
5590
+ function collectProperties(schema, context) {
5591
+ const resolved = resolveSchema(schema, context);
5592
+ const props = /* @__PURE__ */ new Map();
5593
+ const sourceName = schema.$ref ? schema.$ref.split("/").pop() || "unknown" : "inline";
5594
+ if (resolved.properties) {
5595
+ for (const [key, value] of Object.entries(resolved.properties)) {
5596
+ props.set(key, { schema: value, source: sourceName });
5597
+ }
5598
+ }
5599
+ if (resolved.allOf) {
5600
+ for (const subSchema of resolved.allOf) {
5601
+ const subProps = collectProperties(subSchema, context);
5602
+ for (const [key, value] of subProps) {
5603
+ if (!props.has(key)) {
5604
+ props.set(key, value);
5605
+ }
5606
+ }
5607
+ }
5608
+ }
5609
+ return props;
5610
+ }
5611
+ function schemasMatch(a, b) {
5612
+ return JSON.stringify(a) === JSON.stringify(b);
5613
+ }
5614
+ function detectConflictingProperties(schemas, context) {
5615
+ const conflicts = [];
5616
+ const propertyMap = /* @__PURE__ */ new Map();
5617
+ for (const schema of schemas) {
5618
+ const schemaProps = collectProperties(schema, context);
5619
+ for (const [propName, propInfo] of schemaProps) {
5620
+ const existing = propertyMap.get(propName);
5621
+ if (existing) {
5622
+ if (!schemasMatch(existing.schema, propInfo.schema)) {
5623
+ conflicts.push(
5624
+ `Property "${propName}" has conflicting definitions in ${existing.source} and ${propInfo.source}`
5625
+ );
5626
+ }
5627
+ } else {
5628
+ propertyMap.set(propName, propInfo);
5629
+ }
5630
+ }
5631
+ }
5632
+ return conflicts;
5633
+ }
5634
+ function generateAllOf(schemas, isNullable2, context, currentSchema, explicitNullableFalse = false) {
5538
5635
  if (schemas.length === 1) {
5539
- const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false);
5636
+ const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false, explicitNullableFalse);
5540
5637
  return wrapNullable(singleSchema, isNullable2);
5541
5638
  }
5639
+ const conflicts = detectConflictingProperties(schemas, context);
5640
+ let conflictDescription = "";
5641
+ if (conflicts.length > 0) {
5642
+ for (const conflict of conflicts) {
5643
+ console.warn(`[openapi-to-zod] Warning: allOf composition conflict - ${conflict}`);
5644
+ }
5645
+ conflictDescription = `allOf property conflicts detected: ${conflicts.join("; ")}`;
5646
+ }
5542
5647
  const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.$ref || s.allOf);
5543
- const schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema, false));
5648
+ let result;
5544
5649
  if (allObjects) {
5545
- let merged2 = schemaStrings[0];
5650
+ let merged = context.generatePropertySchema(schemas[0], currentSchema, false);
5651
+ for (let i = 1; i < schemas.length; i++) {
5652
+ const schema = schemas[i];
5653
+ if (schema.$ref) {
5654
+ const refSchema = context.generatePropertySchema(schema, currentSchema, false);
5655
+ merged = `${merged}.extend(${refSchema}.shape)`;
5656
+ } else if (context.generateInlineObjectShape && (schema.properties || schema.type === "object")) {
5657
+ const inlineShape = context.generateInlineObjectShape(schema, currentSchema);
5658
+ merged = `${merged}.extend(${inlineShape})`;
5659
+ } else {
5660
+ const schemaString = context.generatePropertySchema(schema, currentSchema, false);
5661
+ merged = `${merged}.extend(${schemaString}.shape)`;
5662
+ }
5663
+ }
5664
+ result = merged;
5665
+ } else {
5666
+ const schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema, false));
5667
+ let merged = schemaStrings[0];
5546
5668
  for (let i = 1; i < schemaStrings.length; i++) {
5547
- merged2 = `${merged2}.merge(${schemaStrings[i]})`;
5669
+ merged = `${merged}.and(${schemaStrings[i]})`;
5548
5670
  }
5549
- return wrapNullable(merged2, isNullable2);
5671
+ result = merged;
5550
5672
  }
5551
- let merged = schemaStrings[0];
5552
- for (let i = 1; i < schemaStrings.length; i++) {
5553
- merged = `${merged}.and(${schemaStrings[i]})`;
5673
+ if (conflictDescription) {
5674
+ result = `${result}.describe("${conflictDescription}")`;
5554
5675
  }
5555
- return wrapNullable(merged, isNullable2);
5676
+ return wrapNullable(result, isNullable2);
5556
5677
  }
5557
5678
  var init_composition_validator = __esm({
5558
5679
  "src/validators/composition-validator.ts"() {
@@ -6279,6 +6400,15 @@ var init_property_generator = __esm({
6279
6400
  }
6280
6401
  return mappedSchemas;
6281
6402
  }
6403
+ /**
6404
+ * Resolve a $ref string to the actual schema
6405
+ */
6406
+ resolveSchemaRef(ref) {
6407
+ var _a, _b;
6408
+ const schemaName = ref.split("/").pop();
6409
+ if (!schemaName) return void 0;
6410
+ return (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
6411
+ }
6282
6412
  /**
6283
6413
  * Resolve a schema name through any aliases to get the actual schema name
6284
6414
  * If the schema is an alias (allOf with single $ref), return the target name
@@ -6356,7 +6486,7 @@ var init_property_generator = __esm({
6356
6486
  let schemaWithCatchall = baseSchema;
6357
6487
  if (baseSchema.includes(".union([") || baseSchema.includes(".discriminatedUnion(")) {
6358
6488
  schemaWithCatchall = baseSchema;
6359
- } else if (baseSchema.includes(".merge(")) {
6489
+ } else if (baseSchema.includes(".extend(")) {
6360
6490
  schemaWithCatchall = `${baseSchema}.catchall(z.unknown())`;
6361
6491
  }
6362
6492
  if (schema.unevaluatedProperties === false) {
@@ -6369,12 +6499,21 @@ var init_property_generator = __esm({
6369
6499
  }
6370
6500
  /**
6371
6501
  * Generate Zod schema for a property
6502
+ * @param schema - The OpenAPI schema to generate
6503
+ * @param currentSchema - The name of the current schema being processed (for circular ref detection)
6504
+ * @param isTopLevel - Whether this is a top-level schema definition
6505
+ * @param suppressDefaultNullable - When true, don't apply defaultNullable (used when outer schema has explicit nullable: false)
6372
6506
  */
6373
- generatePropertySchema(schema, currentSchema, isTopLevel = false) {
6507
+ generatePropertySchema(schema, currentSchema, isTopLevel = false, suppressDefaultNullable = false) {
6374
6508
  var _a, _b, _c, _d, _e;
6375
6509
  const isCacheable = !schema.$ref && !schema.allOf && !schema.oneOf && !schema.anyOf && !currentSchema;
6376
6510
  if (isCacheable) {
6377
- const cacheKey = JSON.stringify({ schema, type: this.context.schemaType, mode: this.context.mode });
6511
+ const cacheKey = JSON.stringify({
6512
+ schema,
6513
+ type: this.context.schemaType,
6514
+ mode: this.context.mode,
6515
+ suppressDefaultNullable
6516
+ });
6378
6517
  const cached = this.schemaCache.get(cacheKey);
6379
6518
  if (cached) {
6380
6519
  return cached;
@@ -6383,7 +6522,10 @@ var init_property_generator = __esm({
6383
6522
  if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
6384
6523
  schema = this.filterNestedProperties(schema);
6385
6524
  }
6386
- const effectiveDefaultNullable = isTopLevel ? false : this.context.defaultNullable;
6525
+ const isEnum = !!schema.enum;
6526
+ const isConst = schema.const !== void 0;
6527
+ const shouldApplyDefaultNullable = !isTopLevel && !isEnum && !isConst && !suppressDefaultNullable;
6528
+ const effectiveDefaultNullable = shouldApplyDefaultNullable ? this.context.defaultNullable : false;
6387
6529
  const nullable = isNullable(schema, effectiveDefaultNullable);
6388
6530
  if (hasMultipleTypes(schema)) {
6389
6531
  const union = this.generateMultiTypeUnion(schema, currentSchema);
@@ -6433,11 +6575,17 @@ var init_property_generator = __esm({
6433
6575
  return wrapNullable(zodUnion, nullable);
6434
6576
  }
6435
6577
  if (schema.allOf) {
6578
+ const explicitNullableFalse = schema.nullable === false;
6436
6579
  let composition = generateAllOf(
6437
6580
  schema.allOf,
6438
6581
  nullable,
6439
- { generatePropertySchema: this.generatePropertySchema.bind(this) },
6440
- currentSchema
6582
+ {
6583
+ generatePropertySchema: this.generatePropertySchema.bind(this),
6584
+ generateInlineObjectShape: this.generateInlineObjectShape.bind(this),
6585
+ resolveSchemaRef: this.resolveSchemaRef.bind(this)
6586
+ },
6587
+ currentSchema,
6588
+ explicitNullableFalse
6441
6589
  );
6442
6590
  if (schema.unevaluatedProperties !== void 0) {
6443
6591
  composition = this.applyUnevaluatedProperties(composition, schema);
@@ -6452,7 +6600,8 @@ var init_property_generator = __esm({
6452
6600
  nullable,
6453
6601
  {
6454
6602
  generatePropertySchema: this.generatePropertySchema.bind(this),
6455
- resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
6603
+ resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
6604
+ resolveSchemaRef: this.resolveSchemaRef.bind(this)
6456
6605
  },
6457
6606
  {
6458
6607
  passthrough: needsPassthrough,
@@ -6473,7 +6622,8 @@ var init_property_generator = __esm({
6473
6622
  nullable,
6474
6623
  {
6475
6624
  generatePropertySchema: this.generatePropertySchema.bind(this),
6476
- resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
6625
+ resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
6626
+ resolveSchemaRef: this.resolveSchemaRef.bind(this)
6477
6627
  },
6478
6628
  {
6479
6629
  passthrough: needsPassthrough,
@@ -6536,7 +6686,17 @@ var init_property_generator = __esm({
6536
6686
  );
6537
6687
  validation = addDescription(validation, schema.description, this.context.useDescribe);
6538
6688
  } else {
6539
- validation = "z.record(z.string(), z.unknown())";
6689
+ switch (this.context.emptyObjectBehavior) {
6690
+ case "strict":
6691
+ validation = "z.strictObject({})";
6692
+ break;
6693
+ case "loose":
6694
+ validation = "z.looseObject({})";
6695
+ break;
6696
+ default:
6697
+ validation = "z.record(z.string(), z.unknown())";
6698
+ break;
6699
+ }
6540
6700
  validation = addDescription(validation, schema.description, this.context.useDescribe);
6541
6701
  }
6542
6702
  break;
@@ -6551,6 +6711,44 @@ var init_property_generator = __esm({
6551
6711
  }
6552
6712
  return result;
6553
6713
  }
6714
+ /**
6715
+ * Generate inline object shape for use with .extend()
6716
+ * Returns just the shape object literal: { prop1: z.string(), prop2: z.number() }
6717
+ *
6718
+ * This method is specifically for allOf compositions where we need to pass
6719
+ * the shape directly to .extend() instead of using z.object({...}).shape.
6720
+ * This avoids the .nullable().shape bug when inline objects have nullable: true.
6721
+ *
6722
+ * According to Zod docs (https://zod.dev/api?id=extend):
6723
+ * - .extend() accepts an object of shape definitions
6724
+ * - e.g., baseSchema.extend({ prop: z.string() })
6725
+ */
6726
+ generateInlineObjectShape(schema, currentSchema) {
6727
+ const required = new Set(schema.required || []);
6728
+ const properties = [];
6729
+ if (schema.properties) {
6730
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
6731
+ if (!this.shouldIncludeProperty(propSchema)) {
6732
+ continue;
6733
+ }
6734
+ const isRequired = required.has(propName);
6735
+ const zodSchema = this.generatePropertySchema(propSchema, currentSchema);
6736
+ const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
6737
+ const quotedPropName = validIdentifier.test(propName) ? propName : `"${propName}"`;
6738
+ let propertyDef = `${quotedPropName}: ${zodSchema}`;
6739
+ if (!isRequired) {
6740
+ propertyDef += ".optional()";
6741
+ }
6742
+ properties.push(propertyDef);
6743
+ }
6744
+ }
6745
+ if (properties.length === 0) {
6746
+ return "{}";
6747
+ }
6748
+ return `{
6749
+ ${properties.map((p) => ` ${p}`).join(",\n")}
6750
+ }`;
6751
+ }
6554
6752
  };
6555
6753
  // Performance optimization: Lookup table for faster inclusion checks
6556
6754
  _PropertyGenerator.INCLUSION_RULES = {
@@ -6702,6 +6900,65 @@ var init_operation_filters = __esm({
6702
6900
  }
6703
6901
  });
6704
6902
 
6903
+ // src/utils/ref-resolver.ts
6904
+ function resolveRef2(obj, spec, maxDepth = 10) {
6905
+ var _a, _b, _c, _d;
6906
+ if (!obj || typeof obj !== "object" || maxDepth <= 0) return obj;
6907
+ if (!obj.$ref) return obj;
6908
+ const ref = obj.$ref;
6909
+ let resolved = null;
6910
+ const paramMatch = ref.match(/^#\/components\/parameters\/(.+)$/);
6911
+ const requestBodyMatch = ref.match(/^#\/components\/requestBodies\/(.+)$/);
6912
+ const responseMatch = ref.match(/^#\/components\/responses\/(.+)$/);
6913
+ const schemaMatch = ref.match(/^#\/components\/schemas\/(.+)$/);
6914
+ if (paramMatch && ((_a = spec.components) == null ? void 0 : _a.parameters)) {
6915
+ const name = paramMatch[1];
6916
+ resolved = spec.components.parameters[name];
6917
+ } else if (requestBodyMatch && ((_b = spec.components) == null ? void 0 : _b.requestBodies)) {
6918
+ const name = requestBodyMatch[1];
6919
+ resolved = spec.components.requestBodies[name];
6920
+ } else if (responseMatch && ((_c = spec.components) == null ? void 0 : _c.responses)) {
6921
+ const name = responseMatch[1];
6922
+ resolved = spec.components.responses[name];
6923
+ } else if (schemaMatch && ((_d = spec.components) == null ? void 0 : _d.schemas)) {
6924
+ const name = schemaMatch[1];
6925
+ resolved = spec.components.schemas[name];
6926
+ }
6927
+ if (resolved) {
6928
+ if (resolved.$ref) {
6929
+ return resolveRef2(resolved, spec, maxDepth - 1);
6930
+ }
6931
+ return resolved;
6932
+ }
6933
+ return obj;
6934
+ }
6935
+ function resolveParameterRef(param, spec) {
6936
+ return resolveRef2(param, spec);
6937
+ }
6938
+ function mergeParameters(pathParams, operationParams, spec) {
6939
+ const resolvedPathParams = (pathParams || []).map((p) => resolveParameterRef(p, spec));
6940
+ const resolvedOperationParams = (operationParams || []).map((p) => resolveParameterRef(p, spec));
6941
+ const merged = [...resolvedPathParams];
6942
+ for (const opParam of resolvedOperationParams) {
6943
+ if (!opParam || typeof opParam !== "object") continue;
6944
+ const existingIndex = merged.findIndex(
6945
+ (p) => p && typeof p === "object" && p.name === opParam.name && p.in === opParam.in
6946
+ );
6947
+ if (existingIndex >= 0) {
6948
+ merged[existingIndex] = opParam;
6949
+ } else {
6950
+ merged.push(opParam);
6951
+ }
6952
+ }
6953
+ return merged;
6954
+ }
6955
+ var init_ref_resolver = __esm({
6956
+ "src/utils/ref-resolver.ts"() {
6957
+ "use strict";
6958
+ init_esm_shims();
6959
+ }
6960
+ });
6961
+
6705
6962
  // src/openapi-generator.ts
6706
6963
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
6707
6964
  import { dirname, normalize } from "path";
@@ -6719,6 +6976,7 @@ var init_openapi_generator = __esm({
6719
6976
  init_name_utils();
6720
6977
  init_operation_filters();
6721
6978
  init_pattern_utils();
6979
+ init_ref_resolver();
6722
6980
  init_string_validator();
6723
6981
  OpenApiGenerator = class {
6724
6982
  constructor(options) {
@@ -6728,7 +6986,7 @@ var init_openapi_generator = __esm({
6728
6986
  this.schemaUsageMap = /* @__PURE__ */ new Map();
6729
6987
  this.needsZodImport = true;
6730
6988
  this.filterStats = createFilterStatistics();
6731
- var _a, _b, _c, _d, _e, _f, _g;
6989
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
6732
6990
  if (!options.input) {
6733
6991
  throw new ConfigurationError("Input path is required", { providedOptions: options });
6734
6992
  }
@@ -6739,18 +6997,19 @@ var init_openapi_generator = __esm({
6739
6997
  includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
6740
6998
  useDescribe: (_b = options.useDescribe) != null ? _b : false,
6741
6999
  defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
7000
+ emptyObjectBehavior: (_d = options.emptyObjectBehavior) != null ? _d : "loose",
6742
7001
  schemaType: options.schemaType || "all",
6743
7002
  prefix: options.prefix,
6744
7003
  suffix: options.suffix,
6745
7004
  stripSchemaPrefix: options.stripSchemaPrefix,
6746
7005
  stripPathPrefix: options.stripPathPrefix,
6747
- showStats: (_d = options.showStats) != null ? _d : true,
7006
+ showStats: (_e = options.showStats) != null ? _e : true,
6748
7007
  request: options.request,
6749
7008
  response: options.response,
6750
7009
  operationFilters: options.operationFilters,
6751
7010
  ignoreHeaders: options.ignoreHeaders,
6752
- cacheSize: (_e = options.cacheSize) != null ? _e : 1e3,
6753
- batchSize: (_f = options.batchSize) != null ? _f : 10,
7011
+ cacheSize: (_f = options.cacheSize) != null ? _f : 1e3,
7012
+ batchSize: (_g = options.batchSize) != null ? _g : 10,
6754
7013
  customDateTimeFormatRegex: options.customDateTimeFormatRegex
6755
7014
  };
6756
7015
  if (this.options.cacheSize) {
@@ -6821,7 +7080,8 @@ var init_openapi_generator = __esm({
6821
7080
  mode: this.requestOptions.mode,
6822
7081
  includeDescriptions: this.requestOptions.includeDescriptions,
6823
7082
  useDescribe: this.requestOptions.useDescribe,
6824
- defaultNullable: (_g = this.options.defaultNullable) != null ? _g : false,
7083
+ defaultNullable: (_h = this.options.defaultNullable) != null ? _h : false,
7084
+ emptyObjectBehavior: (_i = this.options.emptyObjectBehavior) != null ? _i : "loose",
6825
7085
  namingOptions: {
6826
7086
  prefix: this.options.prefix,
6827
7087
  suffix: this.options.suffix
@@ -6891,12 +7151,6 @@ var init_openapi_generator = __esm({
6891
7151
  * Generate the complete output file
6892
7152
  */
6893
7153
  generate() {
6894
- if (!this.options.output) {
6895
- throw new ConfigurationError(
6896
- "Output path is required when calling generate(). Either provide an 'output' option or use generateString() to get the result as a string.",
6897
- { hasOutput: false }
6898
- );
6899
- }
6900
7154
  const output = this.generateString();
6901
7155
  const normalizedOutput = normalize(this.options.output);
6902
7156
  this.ensureDirectoryExists(normalizedOutput);
@@ -7175,7 +7429,7 @@ var init_openapi_generator = __esm({
7175
7429
  * Generate schema for a component
7176
7430
  */
7177
7431
  generateComponentSchema(name, schema) {
7178
- var _a, _b, _c;
7432
+ var _a, _b, _c, _d;
7179
7433
  if (!this.schemaDependencies.has(name)) {
7180
7434
  this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
7181
7435
  }
@@ -7208,6 +7462,7 @@ ${typeCode}`;
7208
7462
  includeDescriptions: resolvedOptions.includeDescriptions,
7209
7463
  useDescribe: resolvedOptions.useDescribe,
7210
7464
  defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
7465
+ emptyObjectBehavior: (_c = this.options.emptyObjectBehavior) != null ? _c : "loose",
7211
7466
  namingOptions: {
7212
7467
  prefix: this.options.prefix,
7213
7468
  suffix: this.options.suffix
@@ -7224,7 +7479,7 @@ ${typeCode}`;
7224
7479
  const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
7225
7480
  if (depMatch) {
7226
7481
  const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
7227
- (_c = this.schemaDependencies.get(name)) == null ? void 0 : _c.add(depName);
7482
+ (_d = this.schemaDependencies.get(name)) == null ? void 0 : _d.add(depName);
7228
7483
  }
7229
7484
  }
7230
7485
  }
@@ -7248,10 +7503,8 @@ ${typeCode}`;
7248
7503
  if (!shouldIncludeOperation(operation, path2, method, this.options.operationFilters)) {
7249
7504
  continue;
7250
7505
  }
7251
- if (!operation.parameters || !Array.isArray(operation.parameters)) {
7252
- continue;
7253
- }
7254
- const queryParams = operation.parameters.filter(
7506
+ const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
7507
+ const queryParams = allParams.filter(
7255
7508
  (param) => param && typeof param === "object" && param.in === "query"
7256
7509
  );
7257
7510
  if (queryParams.length === 0) {
@@ -7387,10 +7640,8 @@ ${propsCode}
7387
7640
  if (!shouldIncludeOperation(operation, path2, method, this.options.operationFilters)) {
7388
7641
  continue;
7389
7642
  }
7390
- if (!operation.parameters || !Array.isArray(operation.parameters)) {
7391
- continue;
7392
- }
7393
- const headerParams = operation.parameters.filter(
7643
+ const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
7644
+ const headerParams = allParams.filter(
7394
7645
  (param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
7395
7646
  );
7396
7647
  if (headerParams.length === 0) {
@@ -7480,13 +7731,23 @@ ${propsCode}
7480
7731
  }
7481
7732
  const type = schema.type;
7482
7733
  if (type === "string") {
7734
+ const formatMap = {
7735
+ email: "z.email()",
7736
+ uri: "z.url()",
7737
+ url: "z.url()",
7738
+ uuid: "z.uuid()"
7739
+ };
7740
+ if (schema.format && formatMap[schema.format]) {
7741
+ let zodType2 = formatMap[schema.format];
7742
+ if (schema.minLength !== void 0) zodType2 = `${zodType2}.min(${schema.minLength})`;
7743
+ if (schema.maxLength !== void 0) zodType2 = `${zodType2}.max(${schema.maxLength})`;
7744
+ if (schema.pattern) zodType2 = `${zodType2}.regex(/${schema.pattern}/)`;
7745
+ return zodType2;
7746
+ }
7483
7747
  let zodType = "z.string()";
7484
7748
  if (schema.minLength !== void 0) zodType = `${zodType}.min(${schema.minLength})`;
7485
7749
  if (schema.maxLength !== void 0) zodType = `${zodType}.max(${schema.maxLength})`;
7486
7750
  if (schema.pattern) zodType = `${zodType}.regex(/${schema.pattern}/)`;
7487
- if (schema.format === "email") zodType = `${zodType}.email()`;
7488
- if (schema.format === "uri" || schema.format === "url") zodType = `${zodType}.url()`;
7489
- if (schema.format === "uuid") zodType = `${zodType}.uuid()`;
7490
7751
  return zodType;
7491
7752
  }
7492
7753
  if (type === "number" || type === "integer") {
@@ -7511,11 +7772,6 @@ ${propsCode}
7511
7772
  }
7512
7773
  return "z.unknown()";
7513
7774
  }
7514
- // REMOVED: generateNativeEnum method - no longer needed as we only generate Zod schemas
7515
- // REMOVED: toEnumKey method - was only used by generateNativeEnum
7516
- // REMOVED: addConstraintsToJSDoc method - was only used for native TypeScript types
7517
- // REMOVED: generateNativeTypeDefinition method - was only used for native TypeScript types
7518
- // REMOVED: generateObjectType method - was only used for native TypeScript types
7519
7775
  /**
7520
7776
  * Topological sort for schema dependencies
7521
7777
  * Returns schemas in the order they should be declared
@@ -7623,7 +7879,8 @@ var init_config_schemas = __esm({
7623
7879
  mode: z.enum(["strict", "normal", "loose"]).optional(),
7624
7880
  useDescribe: z.boolean().optional(),
7625
7881
  includeDescriptions: z.boolean().optional(),
7626
- defaultNullable: z.boolean().optional()
7882
+ defaultNullable: z.boolean().optional(),
7883
+ emptyObjectBehavior: z.enum(["strict", "loose", "record"]).optional()
7627
7884
  });
7628
7885
  OperationFiltersSchema = z.strictObject({
7629
7886
  includeTags: z.array(z.string()).optional(),
@@ -7755,6 +8012,7 @@ function mergeConfigWithDefaults(config) {
7755
8012
  includeDescriptions: defaults.includeDescriptions,
7756
8013
  useDescribe: defaults.useDescribe,
7757
8014
  defaultNullable: defaults.defaultNullable,
8015
+ emptyObjectBehavior: defaults.emptyObjectBehavior,
7758
8016
  schemaType: defaults.schemaType,
7759
8017
  prefix: defaults.prefix,
7760
8018
  suffix: defaults.suffix,
@@ -7781,6 +8039,7 @@ var init_config_loader = __esm({
7781
8039
  includeDescriptions: z2.boolean().optional(),
7782
8040
  useDescribe: z2.boolean().optional(),
7783
8041
  defaultNullable: z2.boolean().optional(),
8042
+ emptyObjectBehavior: z2.enum(["strict", "loose", "record"]).optional(),
7784
8043
  schemaType: z2.enum(["all", "request", "response"]).optional(),
7785
8044
  prefix: z2.string().optional(),
7786
8045
  suffix: z2.string().optional(),
@@ -7813,6 +8072,7 @@ var init_config_loader = __esm({
7813
8072
  includeDescriptions: z2.boolean().optional(),
7814
8073
  useDescribe: z2.boolean().optional(),
7815
8074
  defaultNullable: z2.boolean().optional(),
8075
+ emptyObjectBehavior: z2.enum(["strict", "loose", "record"]).optional(),
7816
8076
  schemaType: z2.enum(["all", "request", "response"]).optional(),
7817
8077
  prefix: z2.string().optional(),
7818
8078
  suffix: z2.string().optional(),