@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.js CHANGED
@@ -5152,12 +5152,12 @@ function toCamelCase(str, options) {
5152
5152
  name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
5153
5153
  }
5154
5154
  if (options == null ? void 0 : options.prefix) {
5155
- const prefix = options.prefix.toLowerCase();
5155
+ const prefix = options.prefix.charAt(0).toLowerCase() + options.prefix.slice(1);
5156
5156
  name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
5157
5157
  }
5158
5158
  if (options == null ? void 0 : options.suffix) {
5159
- const suffix = options.suffix;
5160
- name = name + suffix.charAt(0).toUpperCase() + suffix.slice(1).toLowerCase();
5159
+ const suffix = options.suffix.charAt(0).toUpperCase() + options.suffix.slice(1);
5160
+ name = name + suffix;
5161
5161
  }
5162
5162
  return name;
5163
5163
  }
@@ -5480,12 +5480,56 @@ function generateArrayValidation(schema, context) {
5480
5480
 
5481
5481
  // src/validators/composition-validator.ts
5482
5482
  init_cjs_shims();
5483
+ function isDiscriminatorRequired(schemas, discriminator, context) {
5484
+ const invalidSchemas = [];
5485
+ for (const schema of schemas) {
5486
+ const resolved = resolveSchema(schema, context);
5487
+ const required = resolved.required || [];
5488
+ if (!required.includes(discriminator)) {
5489
+ const schemaName = schema.$ref ? schema.$ref.split("/").pop() || "inline" : "inline";
5490
+ invalidSchemas.push(schemaName);
5491
+ }
5492
+ }
5493
+ return {
5494
+ valid: invalidSchemas.length === 0,
5495
+ invalidSchemas
5496
+ };
5497
+ }
5483
5498
  function generateUnion(schemas, discriminator, isNullable2, context, options, currentSchema) {
5499
+ if (schemas.length === 0) {
5500
+ console.warn(
5501
+ "[openapi-to-zod] Warning: Empty oneOf/anyOf array encountered. This is likely a malformed OpenAPI spec. Generating z.never() as fallback."
5502
+ );
5503
+ return wrapNullable(
5504
+ 'z.never().describe("Empty oneOf/anyOf in OpenAPI spec - no valid schema defined")',
5505
+ isNullable2
5506
+ );
5507
+ }
5508
+ if (schemas.length === 1) {
5509
+ let singleSchema = context.generatePropertySchema(schemas[0], currentSchema);
5510
+ if ((options == null ? void 0 : options.passthrough) && !singleSchema.includes(".catchall(")) {
5511
+ singleSchema = `${singleSchema}.catchall(z.unknown())`;
5512
+ }
5513
+ return wrapNullable(singleSchema, isNullable2);
5514
+ }
5484
5515
  if (discriminator) {
5485
5516
  let resolvedSchemas = schemas;
5486
5517
  if ((options == null ? void 0 : options.discriminatorMapping) && context.resolveDiscriminatorMapping) {
5487
5518
  resolvedSchemas = context.resolveDiscriminatorMapping(options.discriminatorMapping, schemas);
5488
5519
  }
5520
+ const discriminatorCheck = isDiscriminatorRequired(resolvedSchemas, discriminator, context);
5521
+ if (!discriminatorCheck.valid) {
5522
+ console.warn(
5523
+ `[openapi-to-zod] Warning: Discriminator "${discriminator}" is not required in schemas: ${discriminatorCheck.invalidSchemas.join(", ")}. Falling back to z.union() instead of z.discriminatedUnion().`
5524
+ );
5525
+ let schemaStrings3 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
5526
+ if (options == null ? void 0 : options.passthrough) {
5527
+ schemaStrings3 = schemaStrings3.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
5528
+ }
5529
+ const fallbackDescription = `Discriminator "${discriminator}" is optional in some schemas (${discriminatorCheck.invalidSchemas.join(", ")}), using z.union() instead of z.discriminatedUnion()`;
5530
+ const union3 = `z.union([${schemaStrings3.join(", ")}]).describe("${fallbackDescription}")`;
5531
+ return wrapNullable(union3, isNullable2);
5532
+ }
5489
5533
  let schemaStrings2 = resolvedSchemas.map((s) => context.generatePropertySchema(s, currentSchema));
5490
5534
  if (options == null ? void 0 : options.passthrough) {
5491
5535
  schemaStrings2 = schemaStrings2.map((s) => s.includes(".catchall(") ? s : `${s}.catchall(z.unknown())`);
@@ -5500,25 +5544,102 @@ function generateUnion(schemas, discriminator, isNullable2, context, options, cu
5500
5544
  const union = `z.union([${schemaStrings.join(", ")}])`;
5501
5545
  return wrapNullable(union, isNullable2);
5502
5546
  }
5503
- function generateAllOf(schemas, isNullable2, context, currentSchema) {
5547
+ function resolveSchema(schema, context) {
5548
+ if (schema.$ref && context.resolveSchemaRef) {
5549
+ const resolved = context.resolveSchemaRef(schema.$ref);
5550
+ if (resolved) {
5551
+ return resolved;
5552
+ }
5553
+ }
5554
+ return schema;
5555
+ }
5556
+ function collectProperties(schema, context) {
5557
+ const resolved = resolveSchema(schema, context);
5558
+ const props = /* @__PURE__ */ new Map();
5559
+ const sourceName = schema.$ref ? schema.$ref.split("/").pop() || "unknown" : "inline";
5560
+ if (resolved.properties) {
5561
+ for (const [key, value] of Object.entries(resolved.properties)) {
5562
+ props.set(key, { schema: value, source: sourceName });
5563
+ }
5564
+ }
5565
+ if (resolved.allOf) {
5566
+ for (const subSchema of resolved.allOf) {
5567
+ const subProps = collectProperties(subSchema, context);
5568
+ for (const [key, value] of subProps) {
5569
+ if (!props.has(key)) {
5570
+ props.set(key, value);
5571
+ }
5572
+ }
5573
+ }
5574
+ }
5575
+ return props;
5576
+ }
5577
+ function schemasMatch(a, b) {
5578
+ return JSON.stringify(a) === JSON.stringify(b);
5579
+ }
5580
+ function detectConflictingProperties(schemas, context) {
5581
+ const conflicts = [];
5582
+ const propertyMap = /* @__PURE__ */ new Map();
5583
+ for (const schema of schemas) {
5584
+ const schemaProps = collectProperties(schema, context);
5585
+ for (const [propName, propInfo] of schemaProps) {
5586
+ const existing = propertyMap.get(propName);
5587
+ if (existing) {
5588
+ if (!schemasMatch(existing.schema, propInfo.schema)) {
5589
+ conflicts.push(
5590
+ `Property "${propName}" has conflicting definitions in ${existing.source} and ${propInfo.source}`
5591
+ );
5592
+ }
5593
+ } else {
5594
+ propertyMap.set(propName, propInfo);
5595
+ }
5596
+ }
5597
+ }
5598
+ return conflicts;
5599
+ }
5600
+ function generateAllOf(schemas, isNullable2, context, currentSchema, explicitNullableFalse = false) {
5504
5601
  if (schemas.length === 1) {
5505
- const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false);
5602
+ const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false, explicitNullableFalse);
5506
5603
  return wrapNullable(singleSchema, isNullable2);
5507
5604
  }
5605
+ const conflicts = detectConflictingProperties(schemas, context);
5606
+ let conflictDescription = "";
5607
+ if (conflicts.length > 0) {
5608
+ for (const conflict of conflicts) {
5609
+ console.warn(`[openapi-to-zod] Warning: allOf composition conflict - ${conflict}`);
5610
+ }
5611
+ conflictDescription = `allOf property conflicts detected: ${conflicts.join("; ")}`;
5612
+ }
5508
5613
  const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.$ref || s.allOf);
5509
- const schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema, false));
5614
+ let result;
5510
5615
  if (allObjects) {
5511
- let merged2 = schemaStrings[0];
5616
+ let merged = context.generatePropertySchema(schemas[0], currentSchema, false);
5617
+ for (let i = 1; i < schemas.length; i++) {
5618
+ const schema = schemas[i];
5619
+ if (schema.$ref) {
5620
+ const refSchema = context.generatePropertySchema(schema, currentSchema, false);
5621
+ merged = `${merged}.extend(${refSchema}.shape)`;
5622
+ } else if (context.generateInlineObjectShape && (schema.properties || schema.type === "object")) {
5623
+ const inlineShape = context.generateInlineObjectShape(schema, currentSchema);
5624
+ merged = `${merged}.extend(${inlineShape})`;
5625
+ } else {
5626
+ const schemaString = context.generatePropertySchema(schema, currentSchema, false);
5627
+ merged = `${merged}.extend(${schemaString}.shape)`;
5628
+ }
5629
+ }
5630
+ result = merged;
5631
+ } else {
5632
+ const schemaStrings = schemas.map((s) => context.generatePropertySchema(s, currentSchema, false));
5633
+ let merged = schemaStrings[0];
5512
5634
  for (let i = 1; i < schemaStrings.length; i++) {
5513
- merged2 = `${merged2}.merge(${schemaStrings[i]})`;
5635
+ merged = `${merged}.and(${schemaStrings[i]})`;
5514
5636
  }
5515
- return wrapNullable(merged2, isNullable2);
5637
+ result = merged;
5516
5638
  }
5517
- let merged = schemaStrings[0];
5518
- for (let i = 1; i < schemaStrings.length; i++) {
5519
- merged = `${merged}.and(${schemaStrings[i]})`;
5639
+ if (conflictDescription) {
5640
+ result = `${result}.describe("${conflictDescription}")`;
5520
5641
  }
5521
- return wrapNullable(merged, isNullable2);
5642
+ return wrapNullable(result, isNullable2);
5522
5643
  }
5523
5644
 
5524
5645
  // src/validators/number-validator.ts
@@ -6200,6 +6321,15 @@ var _PropertyGenerator = class _PropertyGenerator {
6200
6321
  }
6201
6322
  return mappedSchemas;
6202
6323
  }
6324
+ /**
6325
+ * Resolve a $ref string to the actual schema
6326
+ */
6327
+ resolveSchemaRef(ref) {
6328
+ var _a, _b;
6329
+ const schemaName = ref.split("/").pop();
6330
+ if (!schemaName) return void 0;
6331
+ return (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
6332
+ }
6203
6333
  /**
6204
6334
  * Resolve a schema name through any aliases to get the actual schema name
6205
6335
  * If the schema is an alias (allOf with single $ref), return the target name
@@ -6277,7 +6407,7 @@ var _PropertyGenerator = class _PropertyGenerator {
6277
6407
  let schemaWithCatchall = baseSchema;
6278
6408
  if (baseSchema.includes(".union([") || baseSchema.includes(".discriminatedUnion(")) {
6279
6409
  schemaWithCatchall = baseSchema;
6280
- } else if (baseSchema.includes(".merge(")) {
6410
+ } else if (baseSchema.includes(".extend(")) {
6281
6411
  schemaWithCatchall = `${baseSchema}.catchall(z.unknown())`;
6282
6412
  }
6283
6413
  if (schema.unevaluatedProperties === false) {
@@ -6290,12 +6420,21 @@ var _PropertyGenerator = class _PropertyGenerator {
6290
6420
  }
6291
6421
  /**
6292
6422
  * Generate Zod schema for a property
6423
+ * @param schema - The OpenAPI schema to generate
6424
+ * @param currentSchema - The name of the current schema being processed (for circular ref detection)
6425
+ * @param isTopLevel - Whether this is a top-level schema definition
6426
+ * @param suppressDefaultNullable - When true, don't apply defaultNullable (used when outer schema has explicit nullable: false)
6293
6427
  */
6294
- generatePropertySchema(schema, currentSchema, isTopLevel = false) {
6428
+ generatePropertySchema(schema, currentSchema, isTopLevel = false, suppressDefaultNullable = false) {
6295
6429
  var _a, _b, _c, _d, _e;
6296
6430
  const isCacheable = !schema.$ref && !schema.allOf && !schema.oneOf && !schema.anyOf && !currentSchema;
6297
6431
  if (isCacheable) {
6298
- const cacheKey = JSON.stringify({ schema, type: this.context.schemaType, mode: this.context.mode });
6432
+ const cacheKey = JSON.stringify({
6433
+ schema,
6434
+ type: this.context.schemaType,
6435
+ mode: this.context.mode,
6436
+ suppressDefaultNullable
6437
+ });
6299
6438
  const cached = this.schemaCache.get(cacheKey);
6300
6439
  if (cached) {
6301
6440
  return cached;
@@ -6304,7 +6443,10 @@ var _PropertyGenerator = class _PropertyGenerator {
6304
6443
  if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
6305
6444
  schema = this.filterNestedProperties(schema);
6306
6445
  }
6307
- const effectiveDefaultNullable = isTopLevel ? false : this.context.defaultNullable;
6446
+ const isEnum = !!schema.enum;
6447
+ const isConst = schema.const !== void 0;
6448
+ const shouldApplyDefaultNullable = !isTopLevel && !isEnum && !isConst && !suppressDefaultNullable;
6449
+ const effectiveDefaultNullable = shouldApplyDefaultNullable ? this.context.defaultNullable : false;
6308
6450
  const nullable = isNullable(schema, effectiveDefaultNullable);
6309
6451
  if (hasMultipleTypes(schema)) {
6310
6452
  const union = this.generateMultiTypeUnion(schema, currentSchema);
@@ -6354,11 +6496,17 @@ var _PropertyGenerator = class _PropertyGenerator {
6354
6496
  return wrapNullable(zodUnion, nullable);
6355
6497
  }
6356
6498
  if (schema.allOf) {
6499
+ const explicitNullableFalse = schema.nullable === false;
6357
6500
  let composition = generateAllOf(
6358
6501
  schema.allOf,
6359
6502
  nullable,
6360
- { generatePropertySchema: this.generatePropertySchema.bind(this) },
6361
- currentSchema
6503
+ {
6504
+ generatePropertySchema: this.generatePropertySchema.bind(this),
6505
+ generateInlineObjectShape: this.generateInlineObjectShape.bind(this),
6506
+ resolveSchemaRef: this.resolveSchemaRef.bind(this)
6507
+ },
6508
+ currentSchema,
6509
+ explicitNullableFalse
6362
6510
  );
6363
6511
  if (schema.unevaluatedProperties !== void 0) {
6364
6512
  composition = this.applyUnevaluatedProperties(composition, schema);
@@ -6373,7 +6521,8 @@ var _PropertyGenerator = class _PropertyGenerator {
6373
6521
  nullable,
6374
6522
  {
6375
6523
  generatePropertySchema: this.generatePropertySchema.bind(this),
6376
- resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
6524
+ resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
6525
+ resolveSchemaRef: this.resolveSchemaRef.bind(this)
6377
6526
  },
6378
6527
  {
6379
6528
  passthrough: needsPassthrough,
@@ -6394,7 +6543,8 @@ var _PropertyGenerator = class _PropertyGenerator {
6394
6543
  nullable,
6395
6544
  {
6396
6545
  generatePropertySchema: this.generatePropertySchema.bind(this),
6397
- resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this)
6546
+ resolveDiscriminatorMapping: this.resolveDiscriminatorMapping.bind(this),
6547
+ resolveSchemaRef: this.resolveSchemaRef.bind(this)
6398
6548
  },
6399
6549
  {
6400
6550
  passthrough: needsPassthrough,
@@ -6457,7 +6607,17 @@ var _PropertyGenerator = class _PropertyGenerator {
6457
6607
  );
6458
6608
  validation = addDescription(validation, schema.description, this.context.useDescribe);
6459
6609
  } else {
6460
- validation = "z.record(z.string(), z.unknown())";
6610
+ switch (this.context.emptyObjectBehavior) {
6611
+ case "strict":
6612
+ validation = "z.strictObject({})";
6613
+ break;
6614
+ case "loose":
6615
+ validation = "z.looseObject({})";
6616
+ break;
6617
+ default:
6618
+ validation = "z.record(z.string(), z.unknown())";
6619
+ break;
6620
+ }
6461
6621
  validation = addDescription(validation, schema.description, this.context.useDescribe);
6462
6622
  }
6463
6623
  break;
@@ -6472,6 +6632,44 @@ var _PropertyGenerator = class _PropertyGenerator {
6472
6632
  }
6473
6633
  return result;
6474
6634
  }
6635
+ /**
6636
+ * Generate inline object shape for use with .extend()
6637
+ * Returns just the shape object literal: { prop1: z.string(), prop2: z.number() }
6638
+ *
6639
+ * This method is specifically for allOf compositions where we need to pass
6640
+ * the shape directly to .extend() instead of using z.object({...}).shape.
6641
+ * This avoids the .nullable().shape bug when inline objects have nullable: true.
6642
+ *
6643
+ * According to Zod docs (https://zod.dev/api?id=extend):
6644
+ * - .extend() accepts an object of shape definitions
6645
+ * - e.g., baseSchema.extend({ prop: z.string() })
6646
+ */
6647
+ generateInlineObjectShape(schema, currentSchema) {
6648
+ const required = new Set(schema.required || []);
6649
+ const properties = [];
6650
+ if (schema.properties) {
6651
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
6652
+ if (!this.shouldIncludeProperty(propSchema)) {
6653
+ continue;
6654
+ }
6655
+ const isRequired = required.has(propName);
6656
+ const zodSchema = this.generatePropertySchema(propSchema, currentSchema);
6657
+ const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
6658
+ const quotedPropName = validIdentifier.test(propName) ? propName : `"${propName}"`;
6659
+ let propertyDef = `${quotedPropName}: ${zodSchema}`;
6660
+ if (!isRequired) {
6661
+ propertyDef += ".optional()";
6662
+ }
6663
+ properties.push(propertyDef);
6664
+ }
6665
+ }
6666
+ if (properties.length === 0) {
6667
+ return "{}";
6668
+ }
6669
+ return `{
6670
+ ${properties.map((p) => ` ${p}`).join(",\n")}
6671
+ }`;
6672
+ }
6475
6673
  };
6476
6674
  // Performance optimization: Lookup table for faster inclusion checks
6477
6675
  _PropertyGenerator.INCLUSION_RULES = {
@@ -6616,6 +6814,60 @@ function formatFilterStatistics(stats) {
6616
6814
  return lines.join("\n");
6617
6815
  }
6618
6816
 
6817
+ // src/utils/ref-resolver.ts
6818
+ init_cjs_shims();
6819
+ function resolveRef2(obj, spec, maxDepth = 10) {
6820
+ var _a, _b, _c, _d;
6821
+ if (!obj || typeof obj !== "object" || maxDepth <= 0) return obj;
6822
+ if (!obj.$ref) return obj;
6823
+ const ref = obj.$ref;
6824
+ let resolved = null;
6825
+ const paramMatch = ref.match(/^#\/components\/parameters\/(.+)$/);
6826
+ const requestBodyMatch = ref.match(/^#\/components\/requestBodies\/(.+)$/);
6827
+ const responseMatch = ref.match(/^#\/components\/responses\/(.+)$/);
6828
+ const schemaMatch = ref.match(/^#\/components\/schemas\/(.+)$/);
6829
+ if (paramMatch && ((_a = spec.components) == null ? void 0 : _a.parameters)) {
6830
+ const name = paramMatch[1];
6831
+ resolved = spec.components.parameters[name];
6832
+ } else if (requestBodyMatch && ((_b = spec.components) == null ? void 0 : _b.requestBodies)) {
6833
+ const name = requestBodyMatch[1];
6834
+ resolved = spec.components.requestBodies[name];
6835
+ } else if (responseMatch && ((_c = spec.components) == null ? void 0 : _c.responses)) {
6836
+ const name = responseMatch[1];
6837
+ resolved = spec.components.responses[name];
6838
+ } else if (schemaMatch && ((_d = spec.components) == null ? void 0 : _d.schemas)) {
6839
+ const name = schemaMatch[1];
6840
+ resolved = spec.components.schemas[name];
6841
+ }
6842
+ if (resolved) {
6843
+ if (resolved.$ref) {
6844
+ return resolveRef2(resolved, spec, maxDepth - 1);
6845
+ }
6846
+ return resolved;
6847
+ }
6848
+ return obj;
6849
+ }
6850
+ function resolveParameterRef(param, spec) {
6851
+ return resolveRef2(param, spec);
6852
+ }
6853
+ function mergeParameters(pathParams, operationParams, spec) {
6854
+ const resolvedPathParams = (pathParams || []).map((p) => resolveParameterRef(p, spec));
6855
+ const resolvedOperationParams = (operationParams || []).map((p) => resolveParameterRef(p, spec));
6856
+ const merged = [...resolvedPathParams];
6857
+ for (const opParam of resolvedOperationParams) {
6858
+ if (!opParam || typeof opParam !== "object") continue;
6859
+ const existingIndex = merged.findIndex(
6860
+ (p) => p && typeof p === "object" && p.name === opParam.name && p.in === opParam.in
6861
+ );
6862
+ if (existingIndex >= 0) {
6863
+ merged[existingIndex] = opParam;
6864
+ } else {
6865
+ merged.push(opParam);
6866
+ }
6867
+ }
6868
+ return merged;
6869
+ }
6870
+
6619
6871
  // src/openapi-generator.ts
6620
6872
  var OpenApiGenerator = class {
6621
6873
  constructor(options) {
@@ -6625,7 +6877,7 @@ var OpenApiGenerator = class {
6625
6877
  this.schemaUsageMap = /* @__PURE__ */ new Map();
6626
6878
  this.needsZodImport = true;
6627
6879
  this.filterStats = createFilterStatistics();
6628
- var _a, _b, _c, _d, _e, _f, _g;
6880
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
6629
6881
  if (!options.input) {
6630
6882
  throw new ConfigurationError("Input path is required", { providedOptions: options });
6631
6883
  }
@@ -6636,18 +6888,19 @@ var OpenApiGenerator = class {
6636
6888
  includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
6637
6889
  useDescribe: (_b = options.useDescribe) != null ? _b : false,
6638
6890
  defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
6891
+ emptyObjectBehavior: (_d = options.emptyObjectBehavior) != null ? _d : "loose",
6639
6892
  schemaType: options.schemaType || "all",
6640
6893
  prefix: options.prefix,
6641
6894
  suffix: options.suffix,
6642
6895
  stripSchemaPrefix: options.stripSchemaPrefix,
6643
6896
  stripPathPrefix: options.stripPathPrefix,
6644
- showStats: (_d = options.showStats) != null ? _d : true,
6897
+ showStats: (_e = options.showStats) != null ? _e : true,
6645
6898
  request: options.request,
6646
6899
  response: options.response,
6647
6900
  operationFilters: options.operationFilters,
6648
6901
  ignoreHeaders: options.ignoreHeaders,
6649
- cacheSize: (_e = options.cacheSize) != null ? _e : 1e3,
6650
- batchSize: (_f = options.batchSize) != null ? _f : 10,
6902
+ cacheSize: (_f = options.cacheSize) != null ? _f : 1e3,
6903
+ batchSize: (_g = options.batchSize) != null ? _g : 10,
6651
6904
  customDateTimeFormatRegex: options.customDateTimeFormatRegex
6652
6905
  };
6653
6906
  if (this.options.cacheSize) {
@@ -6718,7 +6971,8 @@ var OpenApiGenerator = class {
6718
6971
  mode: this.requestOptions.mode,
6719
6972
  includeDescriptions: this.requestOptions.includeDescriptions,
6720
6973
  useDescribe: this.requestOptions.useDescribe,
6721
- defaultNullable: (_g = this.options.defaultNullable) != null ? _g : false,
6974
+ defaultNullable: (_h = this.options.defaultNullable) != null ? _h : false,
6975
+ emptyObjectBehavior: (_i = this.options.emptyObjectBehavior) != null ? _i : "loose",
6722
6976
  namingOptions: {
6723
6977
  prefix: this.options.prefix,
6724
6978
  suffix: this.options.suffix
@@ -6788,12 +7042,6 @@ var OpenApiGenerator = class {
6788
7042
  * Generate the complete output file
6789
7043
  */
6790
7044
  generate() {
6791
- if (!this.options.output) {
6792
- throw new ConfigurationError(
6793
- "Output path is required when calling generate(). Either provide an 'output' option or use generateString() to get the result as a string.",
6794
- { hasOutput: false }
6795
- );
6796
- }
6797
7045
  const output = this.generateString();
6798
7046
  const normalizedOutput = (0, import_node_path.normalize)(this.options.output);
6799
7047
  this.ensureDirectoryExists(normalizedOutput);
@@ -7072,7 +7320,7 @@ var OpenApiGenerator = class {
7072
7320
  * Generate schema for a component
7073
7321
  */
7074
7322
  generateComponentSchema(name, schema) {
7075
- var _a, _b, _c;
7323
+ var _a, _b, _c, _d;
7076
7324
  if (!this.schemaDependencies.has(name)) {
7077
7325
  this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
7078
7326
  }
@@ -7105,6 +7353,7 @@ ${typeCode}`;
7105
7353
  includeDescriptions: resolvedOptions.includeDescriptions,
7106
7354
  useDescribe: resolvedOptions.useDescribe,
7107
7355
  defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
7356
+ emptyObjectBehavior: (_c = this.options.emptyObjectBehavior) != null ? _c : "loose",
7108
7357
  namingOptions: {
7109
7358
  prefix: this.options.prefix,
7110
7359
  suffix: this.options.suffix
@@ -7121,7 +7370,7 @@ ${typeCode}`;
7121
7370
  const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
7122
7371
  if (depMatch) {
7123
7372
  const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
7124
- (_c = this.schemaDependencies.get(name)) == null ? void 0 : _c.add(depName);
7373
+ (_d = this.schemaDependencies.get(name)) == null ? void 0 : _d.add(depName);
7125
7374
  }
7126
7375
  }
7127
7376
  }
@@ -7145,10 +7394,8 @@ ${typeCode}`;
7145
7394
  if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
7146
7395
  continue;
7147
7396
  }
7148
- if (!operation.parameters || !Array.isArray(operation.parameters)) {
7149
- continue;
7150
- }
7151
- const queryParams = operation.parameters.filter(
7397
+ const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
7398
+ const queryParams = allParams.filter(
7152
7399
  (param) => param && typeof param === "object" && param.in === "query"
7153
7400
  );
7154
7401
  if (queryParams.length === 0) {
@@ -7284,10 +7531,8 @@ ${propsCode}
7284
7531
  if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
7285
7532
  continue;
7286
7533
  }
7287
- if (!operation.parameters || !Array.isArray(operation.parameters)) {
7288
- continue;
7289
- }
7290
- const headerParams = operation.parameters.filter(
7534
+ const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
7535
+ const headerParams = allParams.filter(
7291
7536
  (param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
7292
7537
  );
7293
7538
  if (headerParams.length === 0) {
@@ -7377,13 +7622,23 @@ ${propsCode}
7377
7622
  }
7378
7623
  const type = schema.type;
7379
7624
  if (type === "string") {
7625
+ const formatMap = {
7626
+ email: "z.email()",
7627
+ uri: "z.url()",
7628
+ url: "z.url()",
7629
+ uuid: "z.uuid()"
7630
+ };
7631
+ if (schema.format && formatMap[schema.format]) {
7632
+ let zodType2 = formatMap[schema.format];
7633
+ if (schema.minLength !== void 0) zodType2 = `${zodType2}.min(${schema.minLength})`;
7634
+ if (schema.maxLength !== void 0) zodType2 = `${zodType2}.max(${schema.maxLength})`;
7635
+ if (schema.pattern) zodType2 = `${zodType2}.regex(/${schema.pattern}/)`;
7636
+ return zodType2;
7637
+ }
7380
7638
  let zodType = "z.string()";
7381
7639
  if (schema.minLength !== void 0) zodType = `${zodType}.min(${schema.minLength})`;
7382
7640
  if (schema.maxLength !== void 0) zodType = `${zodType}.max(${schema.maxLength})`;
7383
7641
  if (schema.pattern) zodType = `${zodType}.regex(/${schema.pattern}/)`;
7384
- if (schema.format === "email") zodType = `${zodType}.email()`;
7385
- if (schema.format === "uri" || schema.format === "url") zodType = `${zodType}.url()`;
7386
- if (schema.format === "uuid") zodType = `${zodType}.uuid()`;
7387
7642
  return zodType;
7388
7643
  }
7389
7644
  if (type === "number" || type === "integer") {
@@ -7408,11 +7663,6 @@ ${propsCode}
7408
7663
  }
7409
7664
  return "z.unknown()";
7410
7665
  }
7411
- // REMOVED: generateNativeEnum method - no longer needed as we only generate Zod schemas
7412
- // REMOVED: toEnumKey method - was only used by generateNativeEnum
7413
- // REMOVED: addConstraintsToJSDoc method - was only used for native TypeScript types
7414
- // REMOVED: generateNativeTypeDefinition method - was only used for native TypeScript types
7415
- // REMOVED: generateObjectType method - was only used for native TypeScript types
7416
7666
  /**
7417
7667
  * Topological sort for schema dependencies
7418
7668
  * Returns schemas in the order they should be declared
@@ -7519,7 +7769,8 @@ var RequestResponseOptionsSchema = import_zod.z.strictObject({
7519
7769
  mode: import_zod.z.enum(["strict", "normal", "loose"]).optional(),
7520
7770
  useDescribe: import_zod.z.boolean().optional(),
7521
7771
  includeDescriptions: import_zod.z.boolean().optional(),
7522
- defaultNullable: import_zod.z.boolean().optional()
7772
+ defaultNullable: import_zod.z.boolean().optional(),
7773
+ emptyObjectBehavior: import_zod.z.enum(["strict", "loose", "record"]).optional()
7523
7774
  });
7524
7775
  var OperationFiltersSchema = import_zod.z.strictObject({
7525
7776
  includeTags: import_zod.z.array(import_zod.z.string()).optional(),
@@ -7603,6 +7854,7 @@ var OpenApiGeneratorOptionsSchema = import_zod2.z.strictObject({
7603
7854
  includeDescriptions: import_zod2.z.boolean().optional(),
7604
7855
  useDescribe: import_zod2.z.boolean().optional(),
7605
7856
  defaultNullable: import_zod2.z.boolean().optional(),
7857
+ emptyObjectBehavior: import_zod2.z.enum(["strict", "loose", "record"]).optional(),
7606
7858
  schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
7607
7859
  prefix: import_zod2.z.string().optional(),
7608
7860
  suffix: import_zod2.z.string().optional(),
@@ -7635,6 +7887,7 @@ var ConfigFileSchema = import_zod2.z.strictObject({
7635
7887
  includeDescriptions: import_zod2.z.boolean().optional(),
7636
7888
  useDescribe: import_zod2.z.boolean().optional(),
7637
7889
  defaultNullable: import_zod2.z.boolean().optional(),
7890
+ emptyObjectBehavior: import_zod2.z.enum(["strict", "loose", "record"]).optional(),
7638
7891
  schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
7639
7892
  prefix: import_zod2.z.string().optional(),
7640
7893
  suffix: import_zod2.z.string().optional(),
@@ -7708,6 +7961,7 @@ function mergeConfigWithDefaults(config) {
7708
7961
  includeDescriptions: defaults.includeDescriptions,
7709
7962
  useDescribe: defaults.useDescribe,
7710
7963
  defaultNullable: defaults.defaultNullable,
7964
+ emptyObjectBehavior: defaults.emptyObjectBehavior,
7711
7965
  schemaType: defaults.schemaType,
7712
7966
  prefix: defaults.prefix,
7713
7967
  suffix: defaults.suffix,