@cerios/openapi-to-zod 1.4.0 → 1.5.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.
package/dist/index.js CHANGED
@@ -20,369 +20,35 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
- CircularReferenceError: () => CircularReferenceError,
24
- CliOptionsError: () => CliOptionsError,
25
- ConfigValidationError: () => ConfigValidationError,
26
- FileOperationError: () => FileOperationError,
27
- GeneratorError: () => GeneratorError,
23
+ CircularReferenceError: () => import_openapi_core7.CircularReferenceError,
24
+ CliOptionsError: () => import_openapi_core7.CliOptionsError,
25
+ ConfigValidationError: () => import_openapi_core7.ConfigValidationError,
26
+ FileOperationError: () => import_openapi_core7.FileOperationError,
27
+ GeneratorError: () => import_openapi_core7.GeneratorError,
28
28
  OpenApiGenerator: () => OpenApiGenerator,
29
- SchemaGenerationError: () => SchemaGenerationError,
30
- SpecValidationError: () => SpecValidationError,
29
+ PropertyGenerator: () => PropertyGenerator,
30
+ SchemaGenerationError: () => import_openapi_core7.SchemaGenerationError,
31
+ SpecValidationError: () => import_openapi_core7.SpecValidationError,
32
+ buildDateTimeValidation: () => buildDateTimeValidation,
31
33
  defineConfig: () => defineConfig
32
34
  });
33
35
  module.exports = __toCommonJS(src_exports);
36
+ var import_openapi_core7 = require("@cerios/openapi-core");
34
37
 
35
- // src/errors.ts
36
- var GeneratorError = class extends Error {
37
- constructor(message, code, context) {
38
- var _a;
39
- super(message);
40
- this.code = code;
41
- this.context = context;
42
- this.name = "GeneratorError";
43
- (_a = Error.captureStackTrace) == null ? void 0 : _a.call(Error, this, this.constructor);
44
- }
45
- };
46
- var SpecValidationError = class extends GeneratorError {
47
- constructor(message, context) {
48
- super(message, "SPEC_VALIDATION_ERROR", context);
49
- this.name = "SpecValidationError";
50
- }
51
- };
52
- var FileOperationError = class extends GeneratorError {
53
- constructor(message, filePath, context) {
54
- super(message, "FILE_OPERATION_ERROR", { ...context, filePath });
55
- this.filePath = filePath;
56
- this.name = "FileOperationError";
57
- }
58
- };
59
- var ConfigValidationError = class extends GeneratorError {
60
- constructor(message, configPath, context) {
61
- super(message, "CONFIG_VALIDATION_ERROR", { ...context, configPath });
62
- this.configPath = configPath;
63
- this.name = "ConfigValidationError";
64
- }
65
- };
66
- var SchemaGenerationError = class extends GeneratorError {
67
- constructor(message, schemaName, context) {
68
- super(message, "SCHEMA_GENERATION_ERROR", { ...context, schemaName });
69
- this.schemaName = schemaName;
70
- this.name = "SchemaGenerationError";
71
- }
72
- };
73
- var CircularReferenceError = class extends SchemaGenerationError {
74
- constructor(schemaName, referencePath) {
75
- const pathStr = referencePath.join(" -> ");
76
- super(`Circular reference detected in schema: ${pathStr}`, schemaName, { referencePath, circularPath: pathStr });
77
- this.referencePath = referencePath;
78
- this.name = "CircularReferenceError";
79
- }
80
- };
81
- var CliOptionsError = class extends GeneratorError {
82
- constructor(message, context) {
83
- super(message, "CLI_OPTIONS_ERROR", context);
84
- this.name = "CliOptionsError";
85
- }
86
- };
87
- var ConfigurationError = class extends GeneratorError {
88
- constructor(message, context) {
89
- super(message, "CONFIGURATION_ERROR", context);
90
- this.name = "ConfigurationError";
91
- }
92
- };
93
-
94
- // src/openapi-generator.ts
95
- var import_node_fs = require("fs");
96
- var import_node_path = require("path");
97
- var import_minimatch3 = require("minimatch");
98
- var import_yaml = require("yaml");
99
-
100
- // src/utils/name-utils.ts
101
- function sanitizeIdentifier(str) {
102
- return str.replace(/[^a-zA-Z0-9._\-\s]+/g, "_");
103
- }
104
- function toCamelCase(str, options) {
105
- const sanitized = sanitizeIdentifier(str);
106
- const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
107
- let name;
108
- if (words.length === 0) {
109
- name = str.charAt(0).toLowerCase() + str.slice(1);
110
- } else if (words.length === 1) {
111
- name = words[0].charAt(0).toLowerCase() + words[0].slice(1);
112
- } else {
113
- name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
114
- }
115
- if (options == null ? void 0 : options.prefix) {
116
- const prefix = options.prefix.charAt(0).toLowerCase() + options.prefix.slice(1);
117
- name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
118
- }
119
- if (options == null ? void 0 : options.suffix) {
120
- const suffix = options.suffix.charAt(0).toUpperCase() + options.suffix.slice(1);
121
- name = name + suffix;
122
- }
123
- return name;
124
- }
125
- function toPascalCase(str) {
126
- const stringValue = String(str);
127
- const isAlreadyValidCase = /^[a-zA-Z][a-zA-Z0-9]*$/.test(stringValue);
128
- if (isAlreadyValidCase) {
129
- return stringValue.charAt(0).toUpperCase() + stringValue.slice(1);
130
- }
131
- const sanitized = sanitizeIdentifier(stringValue);
132
- const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
133
- let result;
134
- if (words.length === 0) {
135
- result = "Value";
136
- } else {
137
- result = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
138
- }
139
- if (/^\d/.test(result)) {
140
- result = `N${result}`;
141
- }
142
- if (!result || /^_+$/.test(result)) {
143
- return "Value";
144
- }
145
- return result;
146
- }
147
- function resolveRef(ref) {
148
- const parts = ref.split("/");
149
- return parts[parts.length - 1];
150
- }
151
-
152
- // src/generators/enum-generator.ts
153
- function generateEnum(name, values, options) {
154
- const schemaName = `${toCamelCase(name, options)}Schema`;
155
- const typeName = toPascalCase(name);
156
- const allBooleans = values.every((v) => typeof v === "boolean");
157
- if (allBooleans) {
158
- const schemaCode2 = `export const ${schemaName} = z.boolean();`;
159
- const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
160
- return { schemaCode: schemaCode2, typeCode: typeCode2 };
161
- }
162
- const allStrings = values.every((v) => typeof v === "string");
163
- if (allStrings) {
164
- const enumValues = values.map((v) => `"${v}"`).join(", ");
165
- const schemaCode2 = `export const ${schemaName} = z.enum([${enumValues}]);`;
166
- const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
167
- return { schemaCode: schemaCode2, typeCode: typeCode2 };
168
- }
169
- const literalValues = values.map((v) => {
170
- if (typeof v === "string") {
171
- return `z.literal("${v}")`;
172
- }
173
- return `z.literal(${v})`;
174
- }).join(", ");
175
- const schemaCode = `export const ${schemaName} = z.union([${literalValues}]);`;
176
- const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
177
- return { schemaCode, typeCode };
178
- }
38
+ // src/generators/property-generator.ts
39
+ var import_openapi_core4 = require("@cerios/openapi-core");
179
40
 
180
41
  // src/utils/string-utils.ts
181
- function escapeDescription(str) {
182
- return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
183
- }
184
- function escapePattern(str) {
185
- return str.replace(/(?<!\\)\//g, "\\/");
186
- }
187
- function escapeJSDoc(str) {
188
- return str.replace(/\*\//g, "*\\/");
189
- }
190
- function wrapNullable(validation, isNullable2) {
191
- return isNullable2 ? `${validation}.nullable()` : validation;
192
- }
193
- function isNullable(schema, defaultNullable = false) {
194
- if (schema.nullable === true) {
195
- return true;
196
- }
197
- if (schema.nullable === false) {
198
- return false;
199
- }
200
- if (Array.isArray(schema.type)) {
201
- return schema.type.includes("null");
202
- }
203
- return defaultNullable;
204
- }
205
- function getPrimaryType(schema) {
206
- if (Array.isArray(schema.type)) {
207
- const nonNullType = schema.type.find((t) => t !== "null");
208
- return nonNullType;
209
- }
210
- return schema.type;
211
- }
212
- function hasMultipleTypes(schema) {
213
- if (Array.isArray(schema.type)) {
214
- const nonNullTypes = schema.type.filter((t) => t !== "null");
215
- return nonNullTypes.length > 1;
216
- }
217
- return false;
42
+ var import_openapi_core = require("@cerios/openapi-core");
43
+ function wrapNullable(validation, nullable) {
44
+ return nullable ? `${validation}.nullable()` : validation;
218
45
  }
219
46
  function addDescription(validation, description, useDescribe) {
220
47
  if (!description || !useDescribe) return validation;
221
- const escapedDesc = escapeDescription(description);
48
+ const escapedDesc = (0, import_openapi_core.escapeDescription)(description);
222
49
  return `${validation}.describe("${escapedDesc}")`;
223
50
  }
224
51
 
225
- // src/generators/jsdoc-generator.ts
226
- function generateJSDoc(schema, name, options = { includeDescriptions: true }) {
227
- if (!schema || typeof schema !== "object") {
228
- return "";
229
- }
230
- if (!options.includeDescriptions) {
231
- if (schema.deprecated) {
232
- return "/** @deprecated */\n";
233
- }
234
- return "";
235
- }
236
- if (!schema.description && !schema.title && !schema.deprecated && !schema.examples && schema.example === void 0) {
237
- return "";
238
- }
239
- const parts = [];
240
- if (schema.title && typeof schema.title === "string" && (!name || schema.title !== name)) {
241
- const sanitizedTitle = escapeJSDoc(schema.title).replace(/@/g, "\\@");
242
- parts.push(sanitizedTitle);
243
- }
244
- if (schema.description && typeof schema.description === "string") {
245
- const sanitizedDesc = escapeJSDoc(schema.description).replace(/@/g, "\\@").replace(/\*\//g, "*\\/");
246
- parts.push(sanitizedDesc);
247
- }
248
- if (schema.examples && Array.isArray(schema.examples) && schema.examples.length > 0) {
249
- try {
250
- const examplesStr = schema.examples.map((ex) => JSON.stringify(ex)).join(", ");
251
- parts.push(`@example ${examplesStr}`);
252
- } catch (error) {
253
- console.warn("Warning: Could not serialize schema examples", error);
254
- }
255
- } else if (schema.example !== void 0) {
256
- try {
257
- parts.push(`@example ${JSON.stringify(schema.example)}`);
258
- } catch (error) {
259
- console.warn("Warning: Could not serialize schema example", error);
260
- }
261
- }
262
- if (schema.deprecated) {
263
- parts.push("@deprecated");
264
- }
265
- if (parts.length === 0) {
266
- return "";
267
- }
268
- const fullComment = parts.join(" ");
269
- return `/** ${fullComment} */
270
- `;
271
- }
272
-
273
- // src/utils/lru-cache.ts
274
- var LRUCache = class {
275
- constructor(maxSize) {
276
- this.cache = /* @__PURE__ */ new Map();
277
- this.maxSize = maxSize;
278
- }
279
- get capacity() {
280
- return this.maxSize;
281
- }
282
- get(key) {
283
- if (!this.cache.has(key)) return void 0;
284
- const value = this.cache.get(key);
285
- if (value === void 0) return void 0;
286
- this.cache.delete(key);
287
- this.cache.set(key, value);
288
- return value;
289
- }
290
- set(key, value) {
291
- if (this.cache.has(key)) {
292
- this.cache.delete(key);
293
- } else if (this.cache.size >= this.maxSize) {
294
- const firstKey = this.cache.keys().next().value;
295
- if (firstKey !== void 0) {
296
- this.cache.delete(firstKey);
297
- }
298
- }
299
- this.cache.set(key, value);
300
- }
301
- has(key) {
302
- return this.cache.has(key);
303
- }
304
- clear() {
305
- this.cache.clear();
306
- }
307
- size() {
308
- return this.cache.size;
309
- }
310
- };
311
-
312
- // src/utils/pattern-utils.ts
313
- var import_minimatch = require("minimatch");
314
- function isValidGlobPattern(pattern) {
315
- try {
316
- new import_minimatch.minimatch.Minimatch(pattern);
317
- return true;
318
- } catch {
319
- return false;
320
- }
321
- }
322
- function isGlobPattern(pattern) {
323
- return /[*?[\]{}!]/.test(pattern);
324
- }
325
- function stripPrefix(input, pattern, ensureLeadingChar) {
326
- if (!pattern) {
327
- return input;
328
- }
329
- if (isGlobPattern(pattern) && !isValidGlobPattern(pattern)) {
330
- console.warn(`\u26A0\uFE0F Invalid glob pattern "${pattern}": Pattern is malformed`);
331
- return input;
332
- }
333
- if (isGlobPattern(pattern)) {
334
- let longestMatch = -1;
335
- for (let i = 1; i <= input.length; i++) {
336
- const testPrefix = input.substring(0, i);
337
- if ((0, import_minimatch.minimatch)(testPrefix, pattern)) {
338
- longestMatch = i;
339
- }
340
- }
341
- if (longestMatch > 0) {
342
- const stripped = input.substring(longestMatch);
343
- if (ensureLeadingChar) {
344
- if (stripped === "") {
345
- return ensureLeadingChar;
346
- }
347
- if (!stripped.startsWith(ensureLeadingChar)) {
348
- return `${ensureLeadingChar}${stripped}`;
349
- }
350
- }
351
- return stripped === "" && !ensureLeadingChar ? input : stripped;
352
- }
353
- return input;
354
- }
355
- if (input.startsWith(pattern)) {
356
- const stripped = input.substring(pattern.length);
357
- if (ensureLeadingChar) {
358
- if (stripped === "") {
359
- return ensureLeadingChar;
360
- }
361
- if (!stripped.startsWith(ensureLeadingChar)) {
362
- return `${ensureLeadingChar}${stripped}`;
363
- }
364
- }
365
- return stripped;
366
- }
367
- return input;
368
- }
369
- function stripPathPrefix(path, pattern) {
370
- if (!pattern) {
371
- return path;
372
- }
373
- if (!isGlobPattern(pattern)) {
374
- let normalizedPattern = pattern.trim();
375
- if (!normalizedPattern.startsWith("/")) {
376
- normalizedPattern = `/${normalizedPattern}`;
377
- }
378
- if (normalizedPattern.endsWith("/") && normalizedPattern !== "/") {
379
- normalizedPattern = normalizedPattern.slice(0, -1);
380
- }
381
- return stripPrefix(path, normalizedPattern, "/");
382
- }
383
- return stripPrefix(path, pattern, "/");
384
- }
385
-
386
52
  // src/validators/array-validator.ts
387
53
  function generateArrayValidation(schema, context) {
388
54
  var _a;
@@ -550,15 +216,14 @@ function detectConflictingProperties(schemas, context) {
550
216
  function generateAllOf(schemas, isNullable2, context, currentSchema) {
551
217
  if (schemas.length === 1) {
552
218
  const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false, true);
553
- return wrapNullable(singleSchema, isNullable2);
219
+ return { schema: wrapNullable(singleSchema, isNullable2), conflicts: [] };
554
220
  }
555
221
  const conflicts = detectConflictingProperties(schemas, context);
556
- let conflictDescription = "";
557
- if (conflicts.length > 0) {
558
- for (const conflict of conflicts) {
222
+ const uniqueConflicts = [...new Set(conflicts)];
223
+ if (uniqueConflicts.length > 0) {
224
+ for (const conflict of uniqueConflicts) {
559
225
  console.warn(`[openapi-to-zod] Warning: allOf composition conflict - ${conflict}`);
560
226
  }
561
- conflictDescription = `allOf property conflicts detected: ${conflicts.join("; ")}`;
562
227
  }
563
228
  const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.$ref || s.allOf);
564
229
  let result;
@@ -586,10 +251,7 @@ function generateAllOf(schemas, isNullable2, context, currentSchema) {
586
251
  }
587
252
  result = merged;
588
253
  }
589
- if (conflictDescription) {
590
- result = `${result}.describe("${conflictDescription}")`;
591
- }
592
- return wrapNullable(result, isNullable2);
254
+ return { schema: wrapNullable(result, isNullable2), conflicts: uniqueConflicts };
593
255
  }
594
256
 
595
257
  // src/validators/number-validator.ts
@@ -613,6 +275,53 @@ function generateNumberValidation(schema, isInt, useDescribe) {
613
275
  return addDescription(validation, schema.description, useDescribe);
614
276
  }
615
277
 
278
+ // src/generators/jsdoc-generator.ts
279
+ var import_openapi_core2 = require("@cerios/openapi-core");
280
+ function generateJSDoc(schema, name, options = { includeDescriptions: true }) {
281
+ if (!schema || typeof schema !== "object") {
282
+ return "";
283
+ }
284
+ if (!options.includeDescriptions) {
285
+ if (schema.deprecated) {
286
+ return "/** @deprecated */\n";
287
+ }
288
+ return "";
289
+ }
290
+ if (!schema.description && !schema.title && !schema.deprecated && !schema.examples && schema.example === void 0) {
291
+ return "";
292
+ }
293
+ const parts = [];
294
+ if (schema.title && typeof schema.title === "string" && (!name || schema.title !== name)) {
295
+ parts.push((0, import_openapi_core2.escapeJSDoc)(schema.title));
296
+ }
297
+ if (schema.description && typeof schema.description === "string") {
298
+ parts.push((0, import_openapi_core2.escapeJSDoc)(schema.description));
299
+ }
300
+ if (schema.examples && Array.isArray(schema.examples) && schema.examples.length > 0) {
301
+ try {
302
+ const examplesStr = schema.examples.map((ex) => JSON.stringify(ex)).join(", ");
303
+ parts.push(`@example ${examplesStr}`);
304
+ } catch (error) {
305
+ console.warn("Warning: Could not serialize schema examples", error);
306
+ }
307
+ } else if (schema.example !== void 0) {
308
+ try {
309
+ parts.push(`@example ${JSON.stringify(schema.example)}`);
310
+ } catch (error) {
311
+ console.warn("Warning: Could not serialize schema example", error);
312
+ }
313
+ }
314
+ if (schema.deprecated) {
315
+ parts.push("@deprecated");
316
+ }
317
+ if (parts.length === 0) {
318
+ return "";
319
+ }
320
+ const fullComment = parts.join(" ");
321
+ return `/** ${fullComment} */
322
+ `;
323
+ }
324
+
616
325
  // src/validators/conditional-validator.ts
617
326
  function generatePropertyAccess(propName) {
618
327
  const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
@@ -671,7 +380,8 @@ function generateConditionalCheck(schema) {
671
380
  for (const [prop, propSchema] of Object.entries(schema.properties)) {
672
381
  const propAccess = generatePropertyAccess(prop);
673
382
  if (propSchema.type) {
674
- conditions.push(`typeof ${propAccess} === "${propSchema.type}"`);
383
+ const schemaType = Array.isArray(propSchema.type) ? propSchema.type[0] : propSchema.type;
384
+ conditions.push(`typeof ${propAccess} === "${schemaType}"`);
675
385
  }
676
386
  if (propSchema.const !== void 0) {
677
387
  const value = typeof propSchema.const === "string" ? `"${propSchema.const}"` : propSchema.const;
@@ -730,7 +440,7 @@ function generateIfThenElse(schema) {
730
440
  if (!thenValid) {
731
441
  ${thenRequiredProps.length > 0 ? `
732
442
  const missingThenProps = ${JSON.stringify(thenRequiredProps)}.filter(p => obj[p] === undefined);
733
- const message = missingThenProps.length > 0
443
+ const message = missingThenProps.length > 0
734
444
  ? \`When condition is met, required properties are missing: \${missingThenProps.join(', ')}\`
735
445
  : "When condition is met, validation constraints failed";
736
446
  ` : `
@@ -748,7 +458,7 @@ function generateIfThenElse(schema) {
748
458
  if (!elseValid) {
749
459
  ${elseRequiredProps2.length > 0 ? `
750
460
  const missingElseProps = ${JSON.stringify(elseRequiredProps2)}.filter(p => obj[p] === undefined);
751
- const message = missingElseProps.length > 0
461
+ const message = missingElseProps.length > 0
752
462
  ? \`When condition is not met, required properties are missing: \${missingElseProps.join(', ')}\`
753
463
  : "When condition is not met, validation constraints failed";
754
464
  ` : `
@@ -773,7 +483,7 @@ function generateIfThenElse(schema) {
773
483
  if (!thenValid) {
774
484
  ${thenRequiredProps.length > 0 ? `
775
485
  const missingProps = ${JSON.stringify(thenRequiredProps)}.filter(p => obj[p] === undefined);
776
- const message = missingProps.length > 0
486
+ const message = missingProps.length > 0
777
487
  ? \`When condition is met, required properties are missing: \${missingProps.join(', ')}\`
778
488
  : "When condition is met, validation constraints failed";
779
489
  ` : `
@@ -798,7 +508,7 @@ function generateIfThenElse(schema) {
798
508
  if (!elseValid) {
799
509
  ${elseRequiredProps.length > 0 ? `
800
510
  const missingProps = ${JSON.stringify(elseRequiredProps)}.filter(p => obj[p] === undefined);
801
- const message = missingProps.length > 0
511
+ const message = missingProps.length > 0
802
512
  ? \`When condition is not met, required properties are missing: \${missingProps.join(', ')}\`
803
513
  : "When condition is not met, validation constraints failed";
804
514
  ` : `
@@ -886,8 +596,9 @@ ${propertyDef}`);
886
596
  case "loose":
887
597
  objectMethod = "z.looseObject";
888
598
  break;
889
- default:
599
+ case "normal":
890
600
  objectMethod = "z.object";
601
+ break;
891
602
  }
892
603
  }
893
604
  let objectDef = `${objectMethod}({
@@ -897,7 +608,7 @@ ${properties.join(",\n")}
897
608
  if (typeof schema.additionalProperties === "object") {
898
609
  const additionalSchema = context.generatePropertySchema(schema.additionalProperties, currentSchema);
899
610
  objectDef += `.catchall(${additionalSchema})`;
900
- } else if (schema.additionalProperties === true) {
611
+ } else if (schema.additionalProperties) {
901
612
  objectDef += ".catchall(z.unknown())";
902
613
  }
903
614
  } else if (schema.patternProperties) {
@@ -1022,6 +733,7 @@ ${properties.join(",\n")}
1022
733
  }
1023
734
 
1024
735
  // src/validators/string-validator.ts
736
+ var import_openapi_core3 = require("@cerios/openapi-core");
1025
737
  var DEFAULT_FORMAT_MAP = {
1026
738
  uuid: "z.uuid()",
1027
739
  email: "z.email()",
@@ -1065,7 +777,7 @@ function buildDateTimeValidation(pattern) {
1065
777
  `Invalid regular expression pattern for customDateTimeFormatRegex: ${patternStr}. ${error instanceof Error ? error.message : "Pattern is malformed"}`
1066
778
  );
1067
779
  }
1068
- const escapedPattern = escapePattern(patternStr);
780
+ const escapedPattern = (0, import_openapi_core3.escapePattern)(patternStr);
1069
781
  return `z.string().regex(/${escapedPattern}/)`;
1070
782
  }
1071
783
  function generateStringValidation(schema, useDescribe, context) {
@@ -1085,7 +797,7 @@ function generateStringValidation(schema, useDescribe, context) {
1085
797
  if (schema.pattern) {
1086
798
  let escapedPattern = context.patternCache.get(schema.pattern);
1087
799
  if (escapedPattern === void 0) {
1088
- escapedPattern = escapePattern(schema.pattern);
800
+ escapedPattern = (0, import_openapi_core3.escapePattern)(schema.pattern);
1089
801
  context.patternCache.set(schema.pattern, escapedPattern);
1090
802
  }
1091
803
  validation += `.regex(/${escapedPattern}/)`;
@@ -1118,7 +830,7 @@ function generateStringValidation(schema, useDescribe, context) {
1118
830
  if (schema.pattern) {
1119
831
  let escapedPattern = context.patternCache.get(schema.pattern);
1120
832
  if (escapedPattern === void 0) {
1121
- escapedPattern = escapePattern(schema.pattern);
833
+ escapedPattern = (0, import_openapi_core3.escapePattern)(schema.pattern);
1122
834
  context.patternCache.set(schema.pattern, escapedPattern);
1123
835
  }
1124
836
  validation += `.regex(/${escapedPattern}/)`;
@@ -1146,9 +858,33 @@ var _PropertyGenerator = class _PropertyGenerator {
1146
858
  // Performance optimization: Memoize filtered property results
1147
859
  this.filteredPropsCache = /* @__PURE__ */ new Map();
1148
860
  // Performance optimization: LRU cache for generated schemas
1149
- this.schemaCache = new LRUCache(500);
861
+ this.schemaCache = new import_openapi_core4.LRUCache(500);
862
+ // Track allOf conflicts detected during schema generation
863
+ this.allOfConflicts = [];
864
+ // Schemas that are part of circular dependency chains (need z.lazy for forward refs)
865
+ this.circularDependencies = /* @__PURE__ */ new Set();
1150
866
  this.context = context;
1151
867
  }
868
+ /**
869
+ * Set the schemas that are involved in circular dependency chains.
870
+ * These schemas will use z.lazy() for forward references.
871
+ */
872
+ setCircularDependencies(deps) {
873
+ this.circularDependencies = deps;
874
+ }
875
+ /**
876
+ * Get allOf conflicts detected during the last schema generation
877
+ * @returns Array of conflict description strings
878
+ */
879
+ getAllOfConflicts() {
880
+ return [...this.allOfConflicts];
881
+ }
882
+ /**
883
+ * Clear tracked allOf conflicts (call before generating a new schema)
884
+ */
885
+ clearAllOfConflicts() {
886
+ this.allOfConflicts = [];
887
+ }
1152
888
  /**
1153
889
  * Check if a property should be included based on schemaType and readOnly/writeOnly flags
1154
890
  */
@@ -1181,7 +917,9 @@ var _PropertyGenerator = class _PropertyGenerator {
1181
917
  filterNestedProperties(schema) {
1182
918
  var _a, _b;
1183
919
  const propKeys = schema.properties ? Object.keys(schema.properties).sort().join(",") : "";
1184
- const cacheKey = `${this.context.schemaType}:${schema.type || "unknown"}:${propKeys}:${((_a = schema.required) == null ? void 0 : _a.join(",")) || ""}`;
920
+ const requiredKeys = Array.isArray(schema.required) ? schema.required.join(",") : String((_a = schema.required) != null ? _a : "");
921
+ const schemaType = Array.isArray(schema.type) ? schema.type.join("|") : schema.type || "unknown";
922
+ const cacheKey = `${this.context.schemaType}:${schemaType}:${propKeys}:${requiredKeys}`;
1185
923
  const cached = this.filteredPropsCache.get(cacheKey);
1186
924
  if (cached) {
1187
925
  return cached;
@@ -1277,7 +1015,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1277
1015
  const schema = (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
1278
1016
  if (!schema) return schemaName;
1279
1017
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref && !schema.properties && !schema.oneOf && !schema.anyOf) {
1280
- const targetName = resolveRef(schema.allOf[0].$ref);
1018
+ const targetName = (0, import_openapi_core4.resolveRefName)(schema.allOf[0].$ref);
1281
1019
  return this.resolveSchemaAlias(targetName);
1282
1020
  }
1283
1021
  return schemaName;
@@ -1290,7 +1028,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1290
1028
  const toSchemaSpec = (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[toSchema];
1291
1029
  if (!toSchemaSpec) return false;
1292
1030
  if (toSchemaSpec.allOf && toSchemaSpec.allOf.length === 1 && toSchemaSpec.allOf[0].$ref) {
1293
- const aliasTarget = resolveRef(toSchemaSpec.allOf[0].$ref);
1031
+ const aliasTarget = (0, import_openapi_core4.resolveRefName)(toSchemaSpec.allOf[0].$ref);
1294
1032
  return aliasTarget === fromSchema;
1295
1033
  }
1296
1034
  return false;
@@ -1385,13 +1123,13 @@ var _PropertyGenerator = class _PropertyGenerator {
1385
1123
  const isConst = schema.const !== void 0;
1386
1124
  const shouldApplyDefaultNullable = !isTopLevel && !isEnum && !isConst && !suppressDefaultNullable;
1387
1125
  const effectiveDefaultNullable = shouldApplyDefaultNullable ? this.context.defaultNullable : false;
1388
- const nullable = isNullable(schema, effectiveDefaultNullable);
1389
- if (hasMultipleTypes(schema)) {
1126
+ const nullable = (0, import_openapi_core4.isNullable)(schema, effectiveDefaultNullable);
1127
+ if ((0, import_openapi_core4.hasMultipleTypes)(schema)) {
1390
1128
  const union = this.generateMultiTypeUnion(schema, currentSchema);
1391
1129
  return wrapNullable(union, nullable);
1392
1130
  }
1393
1131
  if (schema.$ref) {
1394
- const refName = resolveRef(schema.$ref);
1132
+ const refName = (0, import_openapi_core4.resolveRefName)(schema.$ref);
1395
1133
  const resolvedRefName = this.resolveSchemaAlias(refName);
1396
1134
  if (currentSchema && refName !== currentSchema && !isTopLevel) {
1397
1135
  if (!this.context.schemaDependencies.has(currentSchema)) {
@@ -1399,10 +1137,15 @@ var _PropertyGenerator = class _PropertyGenerator {
1399
1137
  }
1400
1138
  (_a = this.context.schemaDependencies.get(currentSchema)) == null ? void 0 : _a.add(refName);
1401
1139
  }
1402
- const strippedRefName = stripPrefix(resolvedRefName, this.context.stripSchemaPrefix);
1403
- const schemaName = `${toCamelCase(strippedRefName, this.context.namingOptions)}Schema`;
1404
- if (currentSchema && (refName === currentSchema || this.isCircularThroughAlias(currentSchema, refName))) {
1405
- const lazySchema = `z.lazy((): z.ZodTypeAny => ${schemaName})`;
1140
+ const strippedRefName = (0, import_openapi_core4.stripPrefix)(resolvedRefName, this.context.stripSchemaPrefix);
1141
+ const schemaName = `${(0, import_openapi_core4.toCamelCase)(strippedRefName, this.context.namingOptions)}Schema`;
1142
+ const typeName = (0, import_openapi_core4.toPascalCase)(strippedRefName);
1143
+ const isDirectSelfRef = currentSchema && refName === currentSchema;
1144
+ const isCircularAlias = currentSchema && this.isCircularThroughAlias(currentSchema, refName);
1145
+ const isMutuallyCircular = currentSchema && this.circularDependencies.has(currentSchema) && this.circularDependencies.has(refName);
1146
+ if (isDirectSelfRef || isCircularAlias || isMutuallyCircular) {
1147
+ const lazyTypeAnnotation = this.context.separateTypesFile ? `z.ZodType<${typeName}>` : "z.ZodTypeAny";
1148
+ const lazySchema = `z.lazy((): ${lazyTypeAnnotation} => ${schemaName})`;
1406
1149
  return wrapNullable(lazySchema, nullable);
1407
1150
  }
1408
1151
  return wrapNullable(schemaName, nullable);
@@ -1434,8 +1177,8 @@ var _PropertyGenerator = class _PropertyGenerator {
1434
1177
  return wrapNullable(zodUnion, nullable);
1435
1178
  }
1436
1179
  if (schema.allOf) {
1437
- const compositionNullable = isNullable(schema, false);
1438
- let composition = generateAllOf(
1180
+ const compositionNullable = (0, import_openapi_core4.isNullable)(schema, false);
1181
+ const allOfResult = generateAllOf(
1439
1182
  schema.allOf,
1440
1183
  compositionNullable,
1441
1184
  {
@@ -1445,13 +1188,17 @@ var _PropertyGenerator = class _PropertyGenerator {
1445
1188
  },
1446
1189
  currentSchema
1447
1190
  );
1191
+ if (allOfResult.conflicts.length > 0) {
1192
+ this.allOfConflicts.push(...allOfResult.conflicts);
1193
+ }
1194
+ let composition = allOfResult.schema;
1448
1195
  if (schema.unevaluatedProperties !== void 0) {
1449
1196
  composition = this.applyUnevaluatedProperties(composition, schema);
1450
1197
  }
1451
1198
  return composition;
1452
1199
  }
1453
1200
  if (schema.oneOf) {
1454
- const compositionNullable = isNullable(schema, false);
1201
+ const compositionNullable = (0, import_openapi_core4.isNullable)(schema, false);
1455
1202
  const needsPassthrough = schema.unevaluatedProperties !== void 0;
1456
1203
  let composition = generateUnion(
1457
1204
  schema.oneOf,
@@ -1474,7 +1221,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1474
1221
  return composition;
1475
1222
  }
1476
1223
  if (schema.anyOf) {
1477
- const compositionNullable = isNullable(schema, false);
1224
+ const compositionNullable = (0, import_openapi_core4.isNullable)(schema, false);
1478
1225
  const needsPassthrough = schema.unevaluatedProperties !== void 0;
1479
1226
  let composition = generateUnion(
1480
1227
  schema.anyOf,
@@ -1509,7 +1256,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1509
1256
  return wrapNullable(refined, nullable);
1510
1257
  }
1511
1258
  let validation = "";
1512
- const primaryType = getPrimaryType(schema);
1259
+ const primaryType = (0, import_openapi_core4.getPrimaryType)(schema);
1513
1260
  switch (primaryType) {
1514
1261
  case "string":
1515
1262
  validation = generateStringValidation(schema, this.context.useDescribe, {
@@ -1556,13 +1303,14 @@ var _PropertyGenerator = class _PropertyGenerator {
1556
1303
  case "loose":
1557
1304
  validation = "z.looseObject({})";
1558
1305
  break;
1559
- default:
1306
+ case "record":
1560
1307
  validation = "z.record(z.string(), z.unknown())";
1561
1308
  break;
1562
1309
  }
1563
1310
  validation = addDescription(validation, schema.description, this.context.useDescribe);
1564
1311
  }
1565
1312
  break;
1313
+ case void 0:
1566
1314
  default:
1567
1315
  validation = "z.unknown()";
1568
1316
  validation = addDescription(validation, schema.description, this.context.useDescribe);
@@ -1621,194 +1369,50 @@ _PropertyGenerator.INCLUSION_RULES = {
1621
1369
  };
1622
1370
  var PropertyGenerator = _PropertyGenerator;
1623
1371
 
1624
- // src/utils/operation-filters.ts
1625
- var import_minimatch2 = require("minimatch");
1626
- function createFilterStatistics() {
1627
- return {
1628
- totalOperations: 0,
1629
- includedOperations: 0,
1630
- filteredByTags: 0,
1631
- filteredByPaths: 0,
1632
- filteredByMethods: 0,
1633
- filteredByOperationIds: 0,
1634
- filteredByDeprecated: 0
1635
- };
1636
- }
1637
- function matchesAnyPattern(value, patterns) {
1638
- if (!patterns || patterns.length === 0) {
1639
- return false;
1640
- }
1641
- if (!value) {
1642
- return false;
1643
- }
1644
- return patterns.some((pattern) => (0, import_minimatch2.minimatch)(value, pattern));
1645
- }
1646
- function containsAny(arr, values) {
1647
- if (!values || values.length === 0) {
1648
- return false;
1649
- }
1650
- if (!arr || arr.length === 0) {
1651
- return false;
1372
+ // src/openapi-generator.ts
1373
+ var import_node_fs = require("fs");
1374
+ var import_node_path = require("path");
1375
+ var import_openapi_core6 = require("@cerios/openapi-core");
1376
+ var import_openapi_to_typescript = require("@cerios/openapi-to-typescript");
1377
+ var import_minimatch = require("minimatch");
1378
+
1379
+ // src/generators/enum-generator.ts
1380
+ var import_openapi_core5 = require("@cerios/openapi-core");
1381
+ function generateEnum(name, values, options) {
1382
+ const schemaName = `${(0, import_openapi_core5.toCamelCase)(name, options)}Schema`;
1383
+ const typeName = (0, import_openapi_core5.toPascalCase)(name);
1384
+ const allBooleans = values.every((v) => typeof v === "boolean");
1385
+ if (allBooleans) {
1386
+ const schemaCode2 = `export const ${schemaName} = z.boolean();`;
1387
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
1388
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
1652
1389
  }
1653
- return values.some((value) => arr.includes(value));
1654
- }
1655
- function shouldIncludeOperation(operation, path, method, filters, stats) {
1656
- if (!filters) {
1657
- return true;
1658
- }
1659
- const methodLower = method.toLowerCase();
1660
- const operationId = operation == null ? void 0 : operation.operationId;
1661
- const tags = (operation == null ? void 0 : operation.tags) || [];
1662
- const deprecated = (operation == null ? void 0 : operation.deprecated) === true;
1663
- if (filters.includeTags && filters.includeTags.length > 0) {
1664
- if (!containsAny(tags, filters.includeTags)) {
1665
- if (stats) stats.filteredByTags++;
1666
- return false;
1667
- }
1390
+ const allStrings = values.every((v) => typeof v === "string");
1391
+ if (allStrings) {
1392
+ const enumValues = values.map((v) => `"${v}"`).join(", ");
1393
+ const schemaCode2 = `export const ${schemaName} = z.enum([${enumValues}]);`;
1394
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
1395
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
1668
1396
  }
1669
- if (filters.includePaths && filters.includePaths.length > 0) {
1670
- if (!matchesAnyPattern(path, filters.includePaths)) {
1671
- if (stats) stats.filteredByPaths++;
1672
- return false;
1397
+ const literalValues = values.map((v) => {
1398
+ if (typeof v === "string") {
1399
+ return `z.literal("${v}")`;
1673
1400
  }
1674
- }
1675
- if (filters.includeMethods && filters.includeMethods.length > 0) {
1676
- const methodsLower = filters.includeMethods.map((m) => m.toLowerCase());
1677
- if (!methodsLower.includes(methodLower)) {
1678
- if (stats) stats.filteredByMethods++;
1679
- return false;
1680
- }
1681
- }
1682
- if (filters.includeOperationIds && filters.includeOperationIds.length > 0) {
1683
- if (!matchesAnyPattern(operationId, filters.includeOperationIds)) {
1684
- if (stats) stats.filteredByOperationIds++;
1685
- return false;
1686
- }
1687
- }
1688
- if (filters.excludeDeprecated === true && deprecated) {
1689
- if (stats) stats.filteredByDeprecated++;
1690
- return false;
1691
- }
1692
- if (filters.excludeTags && filters.excludeTags.length > 0) {
1693
- if (containsAny(tags, filters.excludeTags)) {
1694
- if (stats) stats.filteredByTags++;
1695
- return false;
1696
- }
1697
- }
1698
- if (filters.excludePaths && filters.excludePaths.length > 0) {
1699
- if (matchesAnyPattern(path, filters.excludePaths)) {
1700
- if (stats) stats.filteredByPaths++;
1701
- return false;
1702
- }
1703
- }
1704
- if (filters.excludeMethods && filters.excludeMethods.length > 0) {
1705
- const methodsLower = filters.excludeMethods.map((m) => m.toLowerCase());
1706
- if (methodsLower.includes(methodLower)) {
1707
- if (stats) stats.filteredByMethods++;
1708
- return false;
1709
- }
1710
- }
1711
- if (filters.excludeOperationIds && filters.excludeOperationIds.length > 0) {
1712
- if (matchesAnyPattern(operationId, filters.excludeOperationIds)) {
1713
- if (stats) stats.filteredByOperationIds++;
1714
- return false;
1715
- }
1716
- }
1717
- return true;
1718
- }
1719
- function validateFilters(stats, filters) {
1720
- if (!filters || stats.totalOperations === 0) {
1721
- return;
1722
- }
1723
- if (stats.includedOperations === 0) {
1724
- console.warn(
1725
- `\u26A0\uFE0F Warning: All ${stats.totalOperations} operations were filtered out. Check your operationFilters configuration.`
1726
- );
1727
- const filterBreakdown = [];
1728
- if (stats.filteredByTags > 0) filterBreakdown.push(`${stats.filteredByTags} by tags`);
1729
- if (stats.filteredByPaths > 0) filterBreakdown.push(`${stats.filteredByPaths} by paths`);
1730
- if (stats.filteredByMethods > 0) filterBreakdown.push(`${stats.filteredByMethods} by methods`);
1731
- if (stats.filteredByOperationIds > 0) filterBreakdown.push(`${stats.filteredByOperationIds} by operationIds`);
1732
- if (stats.filteredByDeprecated > 0) filterBreakdown.push(`${stats.filteredByDeprecated} by deprecated flag`);
1733
- if (filterBreakdown.length > 0) {
1734
- console.warn(` Filtered: ${filterBreakdown.join(", ")}`);
1735
- }
1736
- }
1737
- }
1738
- function formatFilterStatistics(stats) {
1739
- if (stats.totalOperations === 0) {
1740
- return "";
1741
- }
1742
- const lines = [];
1743
- lines.push("Operation Filtering:");
1744
- lines.push(` Total operations: ${stats.totalOperations}`);
1745
- lines.push(` Included operations: ${stats.includedOperations}`);
1746
- const filteredCount = stats.filteredByTags + stats.filteredByPaths + stats.filteredByMethods + stats.filteredByOperationIds + stats.filteredByDeprecated;
1747
- if (filteredCount > 0) {
1748
- lines.push(` Filtered operations: ${filteredCount}`);
1749
- if (stats.filteredByTags > 0) lines.push(` - By tags: ${stats.filteredByTags}`);
1750
- if (stats.filteredByPaths > 0) lines.push(` - By paths: ${stats.filteredByPaths}`);
1751
- if (stats.filteredByMethods > 0) lines.push(` - By methods: ${stats.filteredByMethods}`);
1752
- if (stats.filteredByOperationIds > 0) lines.push(` - By operationIds: ${stats.filteredByOperationIds}`);
1753
- if (stats.filteredByDeprecated > 0) lines.push(` - By deprecated: ${stats.filteredByDeprecated}`);
1754
- }
1755
- return lines.join("\n");
1401
+ return `z.literal(${v})`;
1402
+ }).join(", ");
1403
+ const schemaCode = `export const ${schemaName} = z.union([${literalValues}]);`;
1404
+ const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
1405
+ return { schemaCode, typeCode };
1756
1406
  }
1757
1407
 
1758
- // src/utils/ref-resolver.ts
1759
- function resolveRef2(obj, spec, maxDepth = 10) {
1760
- var _a, _b, _c, _d;
1761
- if (!obj || typeof obj !== "object" || maxDepth <= 0) return obj;
1762
- if (!obj.$ref) return obj;
1763
- const ref = obj.$ref;
1764
- let resolved = null;
1765
- const paramMatch = ref.match(/^#\/components\/parameters\/(.+)$/);
1766
- const requestBodyMatch = ref.match(/^#\/components\/requestBodies\/(.+)$/);
1767
- const responseMatch = ref.match(/^#\/components\/responses\/(.+)$/);
1768
- const schemaMatch = ref.match(/^#\/components\/schemas\/(.+)$/);
1769
- if (paramMatch && ((_a = spec.components) == null ? void 0 : _a.parameters)) {
1770
- const name = paramMatch[1];
1771
- resolved = spec.components.parameters[name];
1772
- } else if (requestBodyMatch && ((_b = spec.components) == null ? void 0 : _b.requestBodies)) {
1773
- const name = requestBodyMatch[1];
1774
- resolved = spec.components.requestBodies[name];
1775
- } else if (responseMatch && ((_c = spec.components) == null ? void 0 : _c.responses)) {
1776
- const name = responseMatch[1];
1777
- resolved = spec.components.responses[name];
1778
- } else if (schemaMatch && ((_d = spec.components) == null ? void 0 : _d.schemas)) {
1779
- const name = schemaMatch[1];
1780
- resolved = spec.components.schemas[name];
1781
- }
1782
- if (resolved) {
1783
- if (resolved.$ref) {
1784
- return resolveRef2(resolved, spec, maxDepth - 1);
1785
- }
1786
- return resolved;
1787
- }
1788
- return obj;
1789
- }
1790
- function resolveParameterRef(param, spec) {
1791
- return resolveRef2(param, spec);
1408
+ // src/openapi-generator.ts
1409
+ var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"];
1410
+ function isResolvedParameter(param) {
1411
+ return typeof param === "object" && param !== null && "name" in param && typeof param.name === "string" && "in" in param;
1792
1412
  }
1793
- function mergeParameters(pathParams, operationParams, spec) {
1794
- const resolvedPathParams = (pathParams || []).map((p) => resolveParameterRef(p, spec));
1795
- const resolvedOperationParams = (operationParams || []).map((p) => resolveParameterRef(p, spec));
1796
- const merged = [...resolvedPathParams];
1797
- for (const opParam of resolvedOperationParams) {
1798
- if (!opParam || typeof opParam !== "object") continue;
1799
- const existingIndex = merged.findIndex(
1800
- (p) => p && typeof p === "object" && p.name === opParam.name && p.in === opParam.in
1801
- );
1802
- if (existingIndex >= 0) {
1803
- merged[existingIndex] = opParam;
1804
- } else {
1805
- merged.push(opParam);
1806
- }
1807
- }
1808
- return merged;
1413
+ function isOpenAPIPathItem(value) {
1414
+ return typeof value === "object" && value !== null;
1809
1415
  }
1810
-
1811
- // src/openapi-generator.ts
1812
1416
  var OpenApiGenerator = class {
1813
1417
  constructor(options) {
1814
1418
  this.schemas = /* @__PURE__ */ new Map();
@@ -1816,90 +1420,49 @@ var OpenApiGenerator = class {
1816
1420
  this.schemaDependencies = /* @__PURE__ */ new Map();
1817
1421
  this.schemaUsageMap = /* @__PURE__ */ new Map();
1818
1422
  this.needsZodImport = true;
1819
- this.filterStats = createFilterStatistics();
1820
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1423
+ this.filterStats = (0, import_openapi_core6.createFilterStatistics)();
1424
+ /** Track total allOf conflicts detected across all schemas */
1425
+ this.allOfConflictCount = 0;
1426
+ /** Track schemas involved in circular dependency chains */
1427
+ this.circularDependencies = /* @__PURE__ */ new Set();
1428
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1821
1429
  if (!options.input) {
1822
- throw new ConfigurationError("Input path is required", { providedOptions: options });
1430
+ throw new import_openapi_core6.ConfigurationError("Input path is required", { providedOptions: options });
1823
1431
  }
1432
+ this.separateSchemasMode = Boolean(options.outputZodSchemas);
1824
1433
  this.options = {
1825
1434
  mode: options.mode || "normal",
1826
1435
  input: options.input,
1827
- output: options.output,
1828
- includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
1829
- useDescribe: (_b = options.useDescribe) != null ? _b : false,
1830
- defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
1831
- emptyObjectBehavior: (_d = options.emptyObjectBehavior) != null ? _d : "loose",
1436
+ outputTypes: options.outputTypes,
1437
+ outputZodSchemas: options.outputZodSchemas,
1438
+ enumFormat: options.enumFormat,
1439
+ typeAssertionThreshold: (_a = options.typeAssertionThreshold) != null ? _a : 0,
1440
+ includeDescriptions: (_b = options.includeDescriptions) != null ? _b : true,
1441
+ useDescribe: (_c = options.useDescribe) != null ? _c : false,
1442
+ defaultNullable: (_d = options.defaultNullable) != null ? _d : false,
1443
+ emptyObjectBehavior: (_e = options.emptyObjectBehavior) != null ? _e : "loose",
1832
1444
  schemaType: options.schemaType || "all",
1833
1445
  prefix: options.prefix,
1834
1446
  suffix: options.suffix,
1835
1447
  stripSchemaPrefix: options.stripSchemaPrefix,
1836
1448
  stripPathPrefix: options.stripPathPrefix,
1837
- showStats: (_e = options.showStats) != null ? _e : true,
1449
+ useOperationId: (_f = options.useOperationId) != null ? _f : true,
1450
+ showStats: (_g = options.showStats) != null ? _g : true,
1838
1451
  request: options.request,
1839
1452
  response: options.response,
1840
1453
  operationFilters: options.operationFilters,
1841
1454
  ignoreHeaders: options.ignoreHeaders,
1842
- cacheSize: (_f = options.cacheSize) != null ? _f : 1e3,
1843
- batchSize: (_g = options.batchSize) != null ? _g : 10,
1455
+ cacheSize: (_h = options.cacheSize) != null ? _h : 1e3,
1456
+ batchSize: (_i = options.batchSize) != null ? _i : 10,
1844
1457
  customDateTimeFormatRegex: options.customDateTimeFormatRegex
1845
1458
  };
1846
- this.patternCache = new LRUCache((_h = this.options.cacheSize) != null ? _h : 1e3);
1459
+ this.patternCache = new import_openapi_core6.LRUCache((_j = this.options.cacheSize) != null ? _j : 1e3);
1847
1460
  this.dateTimeValidation = buildDateTimeValidation(this.options.customDateTimeFormatRegex);
1848
- try {
1849
- const fs = require("fs");
1850
- if (!fs.existsSync(this.options.input)) {
1851
- throw new FileOperationError(`Input file not found: ${this.options.input}`, this.options.input);
1852
- }
1853
- } catch (error) {
1854
- if (error instanceof FileOperationError) {
1855
- throw error;
1856
- }
1857
- }
1858
- try {
1859
- const content = (0, import_node_fs.readFileSync)(this.options.input, "utf-8");
1860
- try {
1861
- this.spec = (0, import_yaml.parse)(content);
1862
- } catch (yamlError) {
1863
- try {
1864
- this.spec = JSON.parse(content);
1865
- } catch {
1866
- if (yamlError instanceof Error) {
1867
- const errorMessage = [
1868
- `Failed to parse OpenAPI specification from: ${this.options.input}`,
1869
- "",
1870
- `Error: ${yamlError.message}`,
1871
- "",
1872
- "Please ensure:",
1873
- " - The file exists and is readable",
1874
- " - The file contains valid YAML or JSON syntax",
1875
- " - The file is a valid OpenAPI 3.x specification"
1876
- ].join("\n");
1877
- throw new SpecValidationError(errorMessage, {
1878
- filePath: this.options.input,
1879
- originalError: yamlError.message
1880
- });
1881
- }
1882
- throw yamlError;
1883
- }
1884
- }
1885
- } catch (error) {
1886
- if (error instanceof SpecValidationError) {
1887
- throw error;
1888
- }
1889
- if (error instanceof Error) {
1890
- const errorMessage = [
1891
- `Failed to read OpenAPI specification from: ${this.options.input}`,
1892
- "",
1893
- `Error: ${error.message}`
1894
- ].join("\n");
1895
- throw new SpecValidationError(errorMessage, { filePath: this.options.input, originalError: error.message });
1896
- }
1897
- throw error;
1898
- }
1461
+ this.spec = (0, import_openapi_core6.loadOpenAPISpec)(this.options.input);
1899
1462
  this.validateSpec();
1900
1463
  this.requestOptions = this.resolveOptionsForContext("request");
1901
1464
  this.responseOptions = this.resolveOptionsForContext("response");
1902
- this.analyzeSchemaUsage();
1465
+ this.initializeSchemaUsage();
1903
1466
  this.propertyGenerator = new PropertyGenerator({
1904
1467
  spec: this.spec,
1905
1468
  schemaDependencies: this.schemaDependencies,
@@ -1907,26 +1470,33 @@ var OpenApiGenerator = class {
1907
1470
  mode: this.requestOptions.mode,
1908
1471
  includeDescriptions: this.requestOptions.includeDescriptions,
1909
1472
  useDescribe: this.requestOptions.useDescribe,
1910
- defaultNullable: (_i = this.options.defaultNullable) != null ? _i : false,
1911
- emptyObjectBehavior: (_j = this.options.emptyObjectBehavior) != null ? _j : "loose",
1473
+ defaultNullable: (_k = this.options.defaultNullable) != null ? _k : false,
1474
+ emptyObjectBehavior: (_l = this.options.emptyObjectBehavior) != null ? _l : "loose",
1912
1475
  namingOptions: {
1913
1476
  prefix: this.options.prefix,
1914
1477
  suffix: this.options.suffix
1915
1478
  },
1916
1479
  stripSchemaPrefix: this.options.stripSchemaPrefix,
1917
1480
  dateTimeValidation: this.dateTimeValidation,
1918
- patternCache: this.patternCache
1481
+ patternCache: this.patternCache,
1482
+ separateTypesFile: this.separateSchemasMode
1919
1483
  });
1920
1484
  }
1921
1485
  /**
1922
1486
  * Generate schemas as a string (without writing to file)
1487
+ * When separateSchemasMode is active, generates Zod schemas with explicit type annotations
1923
1488
  * @returns The generated TypeScript code as a string
1924
1489
  */
1925
1490
  generateString() {
1926
1491
  var _a;
1927
1492
  if (!((_a = this.spec.components) == null ? void 0 : _a.schemas)) {
1928
- throw new SpecValidationError("No schemas found in OpenAPI spec", { filePath: this.options.input });
1493
+ throw new import_openapi_core6.SpecValidationError("No schemas found in OpenAPI spec", { filePath: this.options.input });
1494
+ }
1495
+ if (this.separateSchemasMode) {
1496
+ return this.generateSeparateSchemasString();
1929
1497
  }
1498
+ this.analyzeCircularDependencies();
1499
+ this.propertyGenerator.setCircularDependencies(this.circularDependencies);
1930
1500
  for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
1931
1501
  if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
1932
1502
  continue;
@@ -1935,7 +1505,7 @@ var OpenApiGenerator = class {
1935
1505
  }
1936
1506
  this.generateQueryParameterSchemas();
1937
1507
  this.generateHeaderParameterSchemas();
1938
- validateFilters(this.filterStats, this.options.operationFilters);
1508
+ (0, import_openapi_core6.validateFilters)(this.filterStats, this.options.operationFilters);
1939
1509
  const orderedSchemaNames = this.topologicalSort();
1940
1510
  const output = ["// Auto-generated by @cerios/openapi-to-zod", "// Do not edit this file manually", ""];
1941
1511
  if (this.options.showStats === true) {
@@ -1952,10 +1522,10 @@ var OpenApiGenerator = class {
1952
1522
  const typeCode = this.types.get(name);
1953
1523
  if (schemaCode) {
1954
1524
  output.push(schemaCode);
1955
- const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
1956
- const typeName = toPascalCase(strippedName);
1525
+ const strippedName = (0, import_openapi_core6.stripPrefix)(name, this.options.stripSchemaPrefix);
1526
+ const typeName = (0, import_openapi_core6.toPascalCase)(strippedName);
1957
1527
  if (!schemaCode.includes(`export type ${typeName}`)) {
1958
- const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1528
+ const schemaName = `${(0, import_openapi_core6.toCamelCase)(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1959
1529
  output.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);
1960
1530
  }
1961
1531
  output.push("");
@@ -1977,14 +1547,224 @@ var OpenApiGenerator = class {
1977
1547
  }
1978
1548
  }
1979
1549
  /**
1980
- * Generate the complete output file
1550
+ * Generate the complete output file(s)
1551
+ * When separateSchemasMode is active, generates both types and schemas files
1981
1552
  */
1982
1553
  generate() {
1983
- const output = this.generateString();
1984
- const normalizedOutput = (0, import_node_path.normalize)(this.options.output);
1985
- this.ensureDirectoryExists(normalizedOutput);
1986
- (0, import_node_fs.writeFileSync)(normalizedOutput, output);
1987
- console.log(` \u2713 Generated ${normalizedOutput}`);
1554
+ if (this.separateSchemasMode) {
1555
+ const typesContent = this.generateTypesString();
1556
+ const schemasContent = this.generateString();
1557
+ const normalizedTypes = (0, import_node_path.normalize)(this.options.outputTypes);
1558
+ this.ensureDirectoryExists(normalizedTypes);
1559
+ (0, import_node_fs.writeFileSync)(normalizedTypes, typesContent, "utf-8");
1560
+ console.log(` \u2713 Generated ${normalizedTypes}`);
1561
+ if (!this.options.outputZodSchemas) {
1562
+ throw new Error("Internal error: outputZodSchemas should be defined in separateSchemasMode");
1563
+ }
1564
+ const outputZodSchemas = this.options.outputZodSchemas;
1565
+ const normalizedSchemas = (0, import_node_path.normalize)(outputZodSchemas);
1566
+ this.ensureDirectoryExists(normalizedSchemas);
1567
+ (0, import_node_fs.writeFileSync)(normalizedSchemas, schemasContent, "utf-8");
1568
+ console.log(` \u2713 Generated ${normalizedSchemas}`);
1569
+ } else {
1570
+ const output = this.generateString();
1571
+ const normalizedOutput = (0, import_node_path.normalize)(this.options.outputTypes);
1572
+ this.ensureDirectoryExists(normalizedOutput);
1573
+ (0, import_node_fs.writeFileSync)(normalizedOutput, output);
1574
+ console.log(` \u2713 Generated ${normalizedOutput}`);
1575
+ }
1576
+ }
1577
+ /**
1578
+ * Generate Zod schemas with explicit type annotations (for outputZodSchemas mode)
1579
+ * Generates schemas like: `export const userSchema: z.ZodType<User> = z.object({...})`
1580
+ * @returns The generated Zod schemas TypeScript code
1581
+ */
1582
+ generateSeparateSchemasString() {
1583
+ var _a;
1584
+ const schemas = (_a = this.spec.components) == null ? void 0 : _a.schemas;
1585
+ if (!schemas) {
1586
+ return "";
1587
+ }
1588
+ if (!this.options.outputZodSchemas) {
1589
+ throw new Error("Internal error: outputZodSchemas should be defined in separateSchemasMode");
1590
+ }
1591
+ const outputZodSchemas = this.options.outputZodSchemas;
1592
+ this.analyzeCircularDependencies();
1593
+ this.propertyGenerator.setCircularDependencies(this.circularDependencies);
1594
+ for (const [name, schema] of Object.entries(schemas)) {
1595
+ if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
1596
+ continue;
1597
+ }
1598
+ this.generateComponentSchema(name, schema);
1599
+ }
1600
+ this.generateQueryParameterSchemas();
1601
+ this.generateHeaderParameterSchemas();
1602
+ (0, import_openapi_core6.validateFilters)(this.filterStats, this.options.operationFilters);
1603
+ const orderedSchemaNames = this.topologicalSort();
1604
+ const output = ["// Auto-generated by @cerios/openapi-to-zod", "// Do not edit this file manually", ""];
1605
+ if (this.options.showStats === true) {
1606
+ output.push(...this.generateStats());
1607
+ output.push("");
1608
+ }
1609
+ output.push('import { z } from "zod";');
1610
+ const typesImportPath = this.calculateRelativeImportPath(outputZodSchemas, this.options.outputTypes);
1611
+ const typeNames = [];
1612
+ for (const name of orderedSchemaNames) {
1613
+ const strippedName = (0, import_openapi_core6.stripPrefix)(name, this.options.stripSchemaPrefix);
1614
+ const typeName = (0, import_openapi_core6.toPascalCase)(strippedName);
1615
+ typeNames.push(typeName);
1616
+ }
1617
+ if (typeNames.length > 0) {
1618
+ output.push(`import type { ${typeNames.join(", ")} } from "${typesImportPath}";`);
1619
+ }
1620
+ output.push("");
1621
+ output.push("// Schemas");
1622
+ for (const name of orderedSchemaNames) {
1623
+ const schemaCode = this.schemas.get(name);
1624
+ if (schemaCode) {
1625
+ const strippedName = (0, import_openapi_core6.stripPrefix)(name, this.options.stripSchemaPrefix);
1626
+ const typeName = (0, import_openapi_core6.toPascalCase)(strippedName);
1627
+ const schemaName = `${(0, import_openapi_core6.toCamelCase)(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1628
+ const schemaDefinition = this.isRecordObject(schemas[name]) ? schemas[name] : void 0;
1629
+ const transformedCode = this.addExplicitTypeAnnotation(schemaCode, schemaName, typeName, schemaDefinition);
1630
+ output.push(transformedCode);
1631
+ output.push("");
1632
+ }
1633
+ }
1634
+ return output.join("\n");
1635
+ }
1636
+ /**
1637
+ * Generate TypeScript types as a string (for outputZodSchemas mode)
1638
+ * Uses @cerios/openapi-to-typescript internally
1639
+ * @returns The generated TypeScript types code
1640
+ */
1641
+ generateTypesString() {
1642
+ var _a;
1643
+ const tsGenerator = new import_openapi_to_typescript.TypeScriptGenerator({
1644
+ input: this.options.input,
1645
+ outputTypes: this.options.outputTypes,
1646
+ includeDescriptions: this.options.includeDescriptions,
1647
+ defaultNullable: this.options.defaultNullable,
1648
+ prefix: this.options.prefix,
1649
+ suffix: this.options.suffix,
1650
+ stripSchemaPrefix: this.options.stripSchemaPrefix,
1651
+ stripPathPrefix: this.options.stripPathPrefix,
1652
+ operationFilters: this.options.operationFilters,
1653
+ showStats: this.options.showStats,
1654
+ enumFormat: (_a = this.options.enumFormat) != null ? _a : "const-object"
1655
+ });
1656
+ return tsGenerator.generateString();
1657
+ }
1658
+ /**
1659
+ * Add explicit type annotation to a schema declaration
1660
+ * Transforms: `export const userSchema = z.object({...})`
1661
+ * To: `export const userSchema: z.ZodType<User> = z.object({...})` (annotation)
1662
+ * Or: `export const userSchema = z.object({...}) as unknown as z.ZodType<User>` (double assertion)
1663
+ *
1664
+ * Uses double assertion via `unknown` when typeAssertionThreshold is set and schema complexity
1665
+ * meets or exceeds the threshold. This completely bypasses TypeScript's structural checking
1666
+ * to avoid "Type instantiation is excessively deep" errors on very large schemas.
1667
+ *
1668
+ * Also removes any `export type X = z.infer<...>` lines since types
1669
+ * are imported from the separate types file.
1670
+ */
1671
+ addExplicitTypeAnnotation(schemaCode, schemaName, typeName, schemaDefinition) {
1672
+ var _a;
1673
+ const code = schemaCode.replace(/\nexport type \w+ = z\.infer<typeof \w+>;/g, "");
1674
+ const jsdocMatch = code.match(/^(\/\*\*[\s\S]*?\*\/\n)?/);
1675
+ const jsdoc = (jsdocMatch == null ? void 0 : jsdocMatch[1]) || "";
1676
+ const codeWithoutJsdoc = code.slice(jsdoc.length);
1677
+ const threshold = (_a = this.options.typeAssertionThreshold) != null ? _a : 0;
1678
+ const useAssertion = threshold > 0 && schemaDefinition && this.calculateSchemaComplexity(schemaDefinition) >= threshold;
1679
+ const pattern = new RegExp(`export const ${schemaName} = `);
1680
+ if (pattern.test(codeWithoutJsdoc)) {
1681
+ let schemaBody = codeWithoutJsdoc.replace(pattern, "");
1682
+ if (useAssertion) {
1683
+ schemaBody = schemaBody.replace(/;$/, "");
1684
+ return `${jsdoc}export const ${schemaName} = ${schemaBody} as unknown as z.ZodType<${typeName}>;`;
1685
+ }
1686
+ return `${jsdoc}export const ${schemaName}: z.ZodType<${typeName}> = ${schemaBody}`;
1687
+ }
1688
+ return code;
1689
+ }
1690
+ /**
1691
+ * Type guard to check if a value is a Record<string, unknown>
1692
+ */
1693
+ isRecordObject(value) {
1694
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1695
+ }
1696
+ /**
1697
+ * Calculate the complexity of a schema for threshold comparison
1698
+ * Complexity formula: properties + (nested levels * 10) + (array/union members * 2)
1699
+ */
1700
+ calculateSchemaComplexity(schema, depth = 0) {
1701
+ if (!schema || typeof schema !== "object") {
1702
+ return 0;
1703
+ }
1704
+ let complexity = depth * 10;
1705
+ if (schema.$ref) {
1706
+ return complexity + 5;
1707
+ }
1708
+ const properties = schema.properties;
1709
+ if (this.isRecordObject(properties)) {
1710
+ const propCount = Object.keys(properties).length;
1711
+ complexity += propCount;
1712
+ for (const prop of Object.values(properties)) {
1713
+ if (this.isRecordObject(prop)) {
1714
+ complexity += this.calculateSchemaComplexity(prop, depth + 1);
1715
+ }
1716
+ }
1717
+ }
1718
+ const allOf = schema.allOf;
1719
+ if (Array.isArray(allOf)) {
1720
+ complexity += allOf.length * 2;
1721
+ for (const subSchema of allOf) {
1722
+ if (this.isRecordObject(subSchema)) {
1723
+ complexity += this.calculateSchemaComplexity(subSchema, depth + 1);
1724
+ }
1725
+ }
1726
+ }
1727
+ const oneOf = schema.oneOf;
1728
+ if (Array.isArray(oneOf)) {
1729
+ complexity += oneOf.length * 2;
1730
+ for (const subSchema of oneOf) {
1731
+ if (this.isRecordObject(subSchema)) {
1732
+ complexity += this.calculateSchemaComplexity(subSchema, depth + 1);
1733
+ }
1734
+ }
1735
+ }
1736
+ const anyOf = schema.anyOf;
1737
+ if (Array.isArray(anyOf)) {
1738
+ complexity += anyOf.length * 2;
1739
+ for (const subSchema of anyOf) {
1740
+ if (this.isRecordObject(subSchema)) {
1741
+ complexity += this.calculateSchemaComplexity(subSchema, depth + 1);
1742
+ }
1743
+ }
1744
+ }
1745
+ const items = schema.items;
1746
+ if (this.isRecordObject(items)) {
1747
+ complexity += 2;
1748
+ complexity += this.calculateSchemaComplexity(items, depth + 1);
1749
+ }
1750
+ const additionalProps = schema.additionalProperties;
1751
+ if (this.isRecordObject(additionalProps)) {
1752
+ complexity += 2;
1753
+ complexity += this.calculateSchemaComplexity(additionalProps, depth + 1);
1754
+ }
1755
+ return complexity;
1756
+ }
1757
+ /**
1758
+ * Calculate relative import path from schema file to types file
1759
+ */
1760
+ calculateRelativeImportPath(fromPath, toPath) {
1761
+ const fromDir = (0, import_node_path.dirname)((0, import_node_path.normalize)(fromPath));
1762
+ const toFile = (0, import_node_path.normalize)(toPath).replace(/\.[tj]s$/, "");
1763
+ let relativePath = (0, import_node_path.relative)(fromDir, toFile);
1764
+ if (!relativePath.startsWith(".") && !relativePath.startsWith("..")) {
1765
+ relativePath = `./${relativePath}`;
1766
+ }
1767
+ return relativePath.replace(/\\/g, "/");
1988
1768
  }
1989
1769
  /**
1990
1770
  * Resolve options for a specific context (request or response)
@@ -2000,191 +1780,84 @@ var OpenApiGenerator = class {
2000
1780
  };
2001
1781
  }
2002
1782
  /**
2003
- * Analyze schema usage across the OpenAPI spec to determine if schemas
2004
- * are used in request, response, or both contexts
1783
+ * Initialize schema usage map using core utilities with operation filtering
1784
+ * This is a wrapper around core's analyzeSchemaUsage that adds operation filtering
2005
1785
  */
2006
- analyzeSchemaUsage() {
2007
- var _a, _b;
2008
- const requestSchemas = /* @__PURE__ */ new Set();
2009
- const responseSchemas = /* @__PURE__ */ new Set();
2010
- if (this.spec.paths) {
1786
+ initializeSchemaUsage() {
1787
+ var _a;
1788
+ if (this.options.operationFilters && this.spec.paths) {
1789
+ const requestSchemas = /* @__PURE__ */ new Set();
1790
+ const responseSchemas = /* @__PURE__ */ new Set();
2011
1791
  for (const [path, pathItem] of Object.entries(this.spec.paths)) {
2012
- const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
2013
- for (const method of methods) {
1792
+ if (!isOpenAPIPathItem(pathItem)) continue;
1793
+ for (const method of HTTP_METHODS) {
2014
1794
  const operation = pathItem[method];
2015
- if (typeof operation !== "object" || !operation) continue;
1795
+ if (!operation) continue;
2016
1796
  this.filterStats.totalOperations++;
2017
- if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters, this.filterStats)) {
1797
+ if (!(0, import_openapi_core6.shouldIncludeOperation)(operation, path, method, this.options.operationFilters, this.filterStats)) {
2018
1798
  continue;
2019
1799
  }
2020
1800
  this.filterStats.includedOperations++;
2021
- if ("requestBody" in operation && operation.requestBody && typeof operation.requestBody === "object" && "content" in operation.requestBody && operation.requestBody.content) {
2022
- for (const mediaType of Object.values(operation.requestBody.content)) {
2023
- if (mediaType && typeof mediaType === "object" && "schema" in mediaType && mediaType.schema) {
2024
- this.extractSchemaRefs(mediaType.schema, requestSchemas);
1801
+ if (operation.requestBody && typeof operation.requestBody === "object") {
1802
+ const reqBody = operation.requestBody;
1803
+ if (reqBody.content && typeof reqBody.content === "object") {
1804
+ for (const mediaType of Object.values(reqBody.content)) {
1805
+ if (mediaType && typeof mediaType === "object" && "schema" in mediaType && mediaType.schema) {
1806
+ (0, import_openapi_core6.extractSchemaRefs)(mediaType.schema, requestSchemas);
1807
+ }
2025
1808
  }
2026
1809
  }
2027
1810
  }
2028
- if ("responses" in operation && operation.responses && typeof operation.responses === "object") {
1811
+ if (operation.responses && typeof operation.responses === "object") {
2029
1812
  for (const response of Object.values(operation.responses)) {
2030
1813
  if (response && typeof response === "object" && "content" in response && response.content && typeof response.content === "object") {
2031
1814
  for (const mediaType of Object.values(response.content)) {
2032
1815
  if (mediaType && typeof mediaType === "object" && "schema" in mediaType && mediaType.schema) {
2033
- this.extractSchemaRefs(mediaType.schema, responseSchemas);
1816
+ (0, import_openapi_core6.extractSchemaRefs)(mediaType.schema, responseSchemas);
2034
1817
  }
2035
1818
  }
2036
1819
  }
2037
1820
  }
2038
1821
  }
2039
- if ("parameters" in operation && Array.isArray(operation.parameters)) {
1822
+ if (operation.parameters && Array.isArray(operation.parameters)) {
2040
1823
  for (const param of operation.parameters) {
2041
- if (param && typeof param === "object" && "schema" in param && param.schema) {
2042
- this.extractSchemaRefs(param.schema, requestSchemas);
1824
+ if (isResolvedParameter(param) && param.schema) {
1825
+ (0, import_openapi_core6.extractSchemaRefs)(param.schema, requestSchemas);
2043
1826
  }
2044
1827
  }
2045
1828
  }
2046
1829
  }
2047
1830
  }
2048
- this.expandTransitiveReferences(requestSchemas);
2049
- this.expandTransitiveReferences(responseSchemas);
2050
- }
2051
- if (!this.spec.paths || requestSchemas.size === 0 && responseSchemas.size === 0) {
2052
- for (const [name, schema] of Object.entries(((_a = this.spec.components) == null ? void 0 : _a.schemas) || {})) {
2053
- const hasReadOnly = this.hasReadOnlyProperties(schema);
2054
- const hasWriteOnly = this.hasWriteOnlyProperties(schema);
2055
- if (hasWriteOnly && !hasReadOnly) {
2056
- requestSchemas.add(name);
2057
- } else if (hasReadOnly && !hasWriteOnly) {
2058
- responseSchemas.add(name);
1831
+ (0, import_openapi_core6.expandTransitiveReferences)(requestSchemas, this.spec);
1832
+ (0, import_openapi_core6.expandTransitiveReferences)(responseSchemas, this.spec);
1833
+ for (const [name] of Object.entries(((_a = this.spec.components) == null ? void 0 : _a.schemas) || {})) {
1834
+ if (requestSchemas.has(name) && responseSchemas.has(name)) {
1835
+ this.schemaUsageMap.set(name, "both");
1836
+ } else if (requestSchemas.has(name)) {
1837
+ this.schemaUsageMap.set(name, "request");
1838
+ } else if (responseSchemas.has(name)) {
1839
+ this.schemaUsageMap.set(name, "response");
2059
1840
  }
2060
1841
  }
2061
- }
2062
- for (const [name] of Object.entries(((_b = this.spec.components) == null ? void 0 : _b.schemas) || {})) {
2063
- if (requestSchemas.has(name) && responseSchemas.has(name)) {
1842
+ const circularSchemas = (0, import_openapi_core6.detectCircularReferences)(this.spec);
1843
+ for (const name of circularSchemas) {
2064
1844
  this.schemaUsageMap.set(name, "both");
2065
- } else if (requestSchemas.has(name)) {
2066
- this.schemaUsageMap.set(name, "request");
2067
- } else if (responseSchemas.has(name)) {
2068
- this.schemaUsageMap.set(name, "response");
2069
1845
  }
2070
- }
2071
- this.detectCircularReferences();
2072
- }
2073
- /**
2074
- * Expand a set of schemas to include all transitively referenced schemas
2075
- */
2076
- expandTransitiveReferences(schemas) {
2077
- var _a, _b;
2078
- const toProcess = Array.from(schemas);
2079
- const processed = /* @__PURE__ */ new Set();
2080
- while (toProcess.length > 0) {
2081
- const schemaName = toProcess.pop();
2082
- if (!schemaName || processed.has(schemaName)) continue;
2083
- processed.add(schemaName);
2084
- const schema = (_b = (_a = this.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
2085
- if (schema) {
2086
- const refs = /* @__PURE__ */ new Set();
2087
- this.extractSchemaRefs(schema, refs);
2088
- for (const ref of refs) {
2089
- if (!schemas.has(ref)) {
2090
- schemas.add(ref);
2091
- toProcess.push(ref);
2092
- }
2093
- }
2094
- }
2095
- }
2096
- }
2097
- /**
2098
- * Extract schema names from $ref and nested structures
2099
- */
2100
- extractSchemaRefs(schema, refs) {
2101
- if (!schema) return;
2102
- if (schema.$ref) {
2103
- const refName = resolveRef(schema.$ref);
2104
- refs.add(refName);
2105
- }
2106
- if (schema.allOf) {
2107
- for (const subSchema of schema.allOf) {
2108
- this.extractSchemaRefs(subSchema, refs);
2109
- }
2110
- }
2111
- if (schema.oneOf) {
2112
- for (const subSchema of schema.oneOf) {
2113
- this.extractSchemaRefs(subSchema, refs);
2114
- }
2115
- }
2116
- if (schema.anyOf) {
2117
- for (const subSchema of schema.anyOf) {
2118
- this.extractSchemaRefs(subSchema, refs);
2119
- }
2120
- }
2121
- if (schema.items) {
2122
- this.extractSchemaRefs(schema.items, refs);
2123
- }
2124
- if (schema.properties) {
2125
- for (const prop of Object.values(schema.properties)) {
2126
- this.extractSchemaRefs(prop, refs);
2127
- }
2128
- }
2129
- }
2130
- /**
2131
- * Check if schema has readOnly properties
2132
- */
2133
- hasReadOnlyProperties(schema) {
2134
- if (schema.readOnly) return true;
2135
- if (schema.properties) {
2136
- for (const prop of Object.values(schema.properties)) {
2137
- if (this.hasReadOnlyProperties(prop)) return true;
2138
- }
2139
- }
2140
- return false;
2141
- }
2142
- /**
2143
- * Check if schema has writeOnly properties
2144
- */
2145
- hasWriteOnlyProperties(schema) {
2146
- if (schema.writeOnly) return true;
2147
- if (schema.properties) {
2148
- for (const prop of Object.values(schema.properties)) {
2149
- if (this.hasWriteOnlyProperties(prop)) return true;
2150
- }
2151
- }
2152
- return false;
2153
- }
2154
- /**
2155
- * Detect circular references and mark them as "both" context for safety
2156
- */
2157
- detectCircularReferences() {
2158
- var _a;
2159
- const visited = /* @__PURE__ */ new Set();
2160
- const recursionStack = /* @__PURE__ */ new Set();
2161
- const detectCycle = (name) => {
2162
- var _a2, _b;
2163
- if (recursionStack.has(name)) {
2164
- return true;
2165
- }
2166
- if (visited.has(name)) {
2167
- return false;
2168
- }
2169
- visited.add(name);
2170
- recursionStack.add(name);
2171
- const schema = (_b = (_a2 = this.spec.components) == null ? void 0 : _a2.schemas) == null ? void 0 : _b[name];
2172
- if (schema) {
2173
- const refs = /* @__PURE__ */ new Set();
2174
- this.extractSchemaRefs(schema, refs);
2175
- for (const ref of refs) {
2176
- if (detectCycle(ref)) {
2177
- this.schemaUsageMap.set(name, "both");
2178
- recursionStack.delete(name);
2179
- return true;
1846
+ } else {
1847
+ const analysis = (0, import_openapi_core6.analyzeSchemaUsage)(this.spec);
1848
+ this.schemaUsageMap = analysis.usageMap;
1849
+ if (this.spec.paths) {
1850
+ for (const pathItem of Object.values(this.spec.paths)) {
1851
+ if (!isOpenAPIPathItem(pathItem)) continue;
1852
+ for (const method of HTTP_METHODS) {
1853
+ const operation = pathItem[method];
1854
+ if (typeof operation === "object" && operation) {
1855
+ this.filterStats.totalOperations++;
1856
+ this.filterStats.includedOperations++;
1857
+ }
2180
1858
  }
2181
1859
  }
2182
1860
  }
2183
- recursionStack.delete(name);
2184
- return false;
2185
- };
2186
- for (const name of Object.keys(((_a = this.spec.components) == null ? void 0 : _a.schemas) || {})) {
2187
- detectCycle(name);
2188
1861
  }
2189
1862
  }
2190
1863
  /**
@@ -2193,7 +1866,7 @@ var OpenApiGenerator = class {
2193
1866
  validateSpec() {
2194
1867
  var _a;
2195
1868
  if (!((_a = this.spec.components) == null ? void 0 : _a.schemas)) {
2196
- throw new SpecValidationError(
1869
+ throw new import_openapi_core6.SpecValidationError(
2197
1870
  `No schemas found in OpenAPI spec at ${this.options.input}. Expected to find schemas at components.schemas`,
2198
1871
  { filePath: this.options.input }
2199
1872
  );
@@ -2204,7 +1877,7 @@ var OpenApiGenerator = class {
2204
1877
  this.validateSchemaRefs(name, schema, allSchemas);
2205
1878
  } catch (error) {
2206
1879
  if (error instanceof Error) {
2207
- throw new SchemaGenerationError(`Invalid schema '${name}': ${error.message}`, name, {
1880
+ throw new import_openapi_core6.SchemaGenerationError(`Invalid schema '${name}': ${error.message}`, name, {
2208
1881
  originalError: error.message
2209
1882
  });
2210
1883
  }
@@ -2217,9 +1890,9 @@ var OpenApiGenerator = class {
2217
1890
  */
2218
1891
  validateSchemaRefs(schemaName, schema, allSchemas, path = "") {
2219
1892
  if (schema.$ref) {
2220
- const refName = resolveRef(schema.$ref);
1893
+ const refName = (0, import_openapi_core6.resolveRefName)(schema.$ref);
2221
1894
  if (!allSchemas.includes(refName)) {
2222
- throw new SpecValidationError(
1895
+ throw new import_openapi_core6.SpecValidationError(
2223
1896
  `Invalid reference${path ? ` at '${path}'` : ""}: '${schema.$ref}' points to non-existent schema '${refName}'`,
2224
1897
  { schemaName, path, ref: schema.$ref, refName }
2225
1898
  );
@@ -2266,7 +1939,7 @@ var OpenApiGenerator = class {
2266
1939
  const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
2267
1940
  if (schema.enum) {
2268
1941
  const jsdoc2 = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
2269
- const strippedName2 = stripPrefix(name, this.options.stripSchemaPrefix);
1942
+ const strippedName2 = (0, import_openapi_core6.stripPrefix)(name, this.options.stripSchemaPrefix);
2270
1943
  const { schemaCode, typeCode } = generateEnum(strippedName2, schema.enum, {
2271
1944
  prefix: this.options.prefix,
2272
1945
  suffix: this.options.suffix
@@ -2276,11 +1949,11 @@ ${typeCode}`;
2276
1949
  this.schemas.set(name, enumSchemaCode);
2277
1950
  return;
2278
1951
  }
2279
- const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
2280
- const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
2281
- const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1952
+ const strippedName = (0, import_openapi_core6.stripPrefix)(name, this.options.stripSchemaPrefix);
1953
+ const schemaName = `${(0, import_openapi_core6.toCamelCase)(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1954
+ let jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
2282
1955
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref) {
2283
- const refName = resolveRef(schema.allOf[0].$ref);
1956
+ const refName = (0, import_openapi_core6.resolveRefName)(schema.allOf[0].$ref);
2284
1957
  (_a = this.schemaDependencies.get(name)) == null ? void 0 : _a.add(refName);
2285
1958
  }
2286
1959
  this.propertyGenerator = new PropertyGenerator({
@@ -2298,9 +1971,26 @@ ${typeCode}`;
2298
1971
  },
2299
1972
  stripSchemaPrefix: this.options.stripSchemaPrefix,
2300
1973
  dateTimeValidation: this.dateTimeValidation,
2301
- patternCache: this.patternCache
1974
+ patternCache: this.patternCache,
1975
+ separateTypesFile: this.separateSchemasMode
2302
1976
  });
1977
+ this.propertyGenerator.setCircularDependencies(this.circularDependencies);
1978
+ this.propertyGenerator.clearAllOfConflicts();
2303
1979
  const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, true);
1980
+ const allOfConflicts = this.propertyGenerator.getAllOfConflicts();
1981
+ if (allOfConflicts.length > 0) {
1982
+ this.allOfConflictCount += allOfConflicts.length;
1983
+ const conflictWarning = this.generateConflictJSDoc(allOfConflicts);
1984
+ if (jsdoc) {
1985
+ jsdoc = jsdoc.replace(/ \*\/\n$/, `
1986
+ ${conflictWarning} */
1987
+ `);
1988
+ } else {
1989
+ jsdoc = `/**
1990
+ ${conflictWarning} */
1991
+ `;
1992
+ }
1993
+ }
2304
1994
  const zodSchemaCode = `${jsdoc}export const ${schemaName} = ${zodSchema};`;
2305
1995
  if (zodSchema.includes("z.discriminatedUnion(")) {
2306
1996
  const match = zodSchema.match(/z\.discriminatedUnion\([^,]+,\s*\[([^\]]+)\]/);
@@ -2326,28 +2016,27 @@ ${typeCode}`;
2326
2016
  return;
2327
2017
  }
2328
2018
  for (const [path, pathItem] of Object.entries(this.spec.paths)) {
2329
- if (!pathItem || typeof pathItem !== "object") continue;
2330
- const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
2331
- for (const method of methods) {
2019
+ if (!isOpenAPIPathItem(pathItem)) continue;
2020
+ for (const method of HTTP_METHODS) {
2332
2021
  const operation = pathItem[method];
2333
2022
  if (!operation) continue;
2334
- if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
2023
+ if (!(0, import_openapi_core6.shouldIncludeOperation)(operation, path, method, this.options.operationFilters)) {
2335
2024
  continue;
2336
2025
  }
2337
- const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
2026
+ const allParams = (0, import_openapi_core6.mergeParameters)(pathItem.parameters, operation.parameters, this.spec);
2338
2027
  const queryParams = allParams.filter(
2339
- (param) => param && typeof param === "object" && param.in === "query"
2028
+ (param) => isResolvedParameter(param) && param.in === "query"
2340
2029
  );
2341
2030
  if (queryParams.length === 0) {
2342
2031
  continue;
2343
2032
  }
2344
- let pascalOperationId;
2345
- if (operation.operationId) {
2346
- pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
2347
- } else {
2348
- const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
2349
- pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
2350
- }
2033
+ const strippedPath = (0, import_openapi_core6.stripPathPrefix)(path, this.options.stripPathPrefix);
2034
+ const pascalOperationId = (0, import_openapi_core6.getOperationName)(
2035
+ operation.operationId,
2036
+ method,
2037
+ strippedPath,
2038
+ this.options.useOperationId
2039
+ );
2351
2040
  const schemaName = `${pascalOperationId}QueryParams`;
2352
2041
  if (!this.schemaDependencies.has(schemaName)) {
2353
2042
  this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
@@ -2377,7 +2066,7 @@ ${typeCode}`;
2377
2066
  required.push(paramName);
2378
2067
  }
2379
2068
  if (paramSchema.$ref) {
2380
- const refName = resolveRef(paramSchema.$ref);
2069
+ const refName = (0, import_openapi_core6.resolveRefName)(paramSchema.$ref);
2381
2070
  (_a = this.schemaDependencies.get(schemaName)) == null ? void 0 : _a.add(refName);
2382
2071
  }
2383
2072
  }
@@ -2392,9 +2081,7 @@ ${typeCode}`;
2392
2081
  ${propsCode}
2393
2082
  })`;
2394
2083
  const operationName = pascalOperationId;
2395
- const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
2396
- const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
2397
- const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}QueryParamsSchema`;
2084
+ const camelCaseSchemaName = `${(0, import_openapi_core6.toCamelCase)(operationName, { prefix: this.options.prefix, suffix: this.options.suffix })}QueryParamsSchema`;
2398
2085
  const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
2399
2086
  const jsdoc = `/**
2400
2087
  * Query parameters for ${jsdocOperationName}
@@ -2406,35 +2093,6 @@ ${propsCode}
2406
2093
  }
2407
2094
  }
2408
2095
  }
2409
- /**
2410
- * Generate a PascalCase method name from HTTP method and path
2411
- * Used as fallback when operationId is not available
2412
- * @internal
2413
- */
2414
- generateMethodNameFromPath(method, path) {
2415
- const segments = path.split("/").filter(Boolean).map((segment) => {
2416
- if (segment.startsWith("{") && segment.endsWith("}")) {
2417
- const paramName = segment.slice(1, -1);
2418
- return `By${this.capitalizeSegment(paramName)}`;
2419
- }
2420
- return this.capitalizeSegment(segment);
2421
- }).join("");
2422
- const capitalizedMethod = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
2423
- return `${capitalizedMethod}${segments}`;
2424
- }
2425
- /**
2426
- * Capitalizes a path segment, handling special characters like dashes, underscores, and dots
2427
- * @internal
2428
- */
2429
- capitalizeSegment(str) {
2430
- if (str.includes("-") || str.includes("_") || str.includes(".")) {
2431
- return str.split(/[-_.]/).map((part) => {
2432
- if (!part) return "";
2433
- return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
2434
- }).join("");
2435
- }
2436
- return str.charAt(0).toUpperCase() + str.slice(1);
2437
- }
2438
2096
  /**
2439
2097
  * Check if a header should be ignored based on filter patterns
2440
2098
  * @internal
@@ -2450,7 +2108,7 @@ ${propsCode}
2450
2108
  const headerLower = headerName.toLowerCase();
2451
2109
  return ignorePatterns.some((pattern) => {
2452
2110
  const patternLower = pattern.toLowerCase();
2453
- return (0, import_minimatch3.minimatch)(headerLower, patternLower);
2111
+ return (0, import_minimatch.minimatch)(headerLower, patternLower);
2454
2112
  });
2455
2113
  }
2456
2114
  /**
@@ -2463,28 +2121,27 @@ ${propsCode}
2463
2121
  return;
2464
2122
  }
2465
2123
  for (const [path, pathItem] of Object.entries(this.spec.paths)) {
2466
- if (!pathItem || typeof pathItem !== "object") continue;
2467
- const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
2468
- for (const method of methods) {
2124
+ if (!isOpenAPIPathItem(pathItem)) continue;
2125
+ for (const method of HTTP_METHODS) {
2469
2126
  const operation = pathItem[method];
2470
2127
  if (!operation) continue;
2471
- if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
2128
+ if (!(0, import_openapi_core6.shouldIncludeOperation)(operation, path, method, this.options.operationFilters)) {
2472
2129
  continue;
2473
2130
  }
2474
- const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
2131
+ const allParams = (0, import_openapi_core6.mergeParameters)(pathItem.parameters, operation.parameters, this.spec);
2475
2132
  const headerParams = allParams.filter(
2476
- (param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
2133
+ (param) => isResolvedParameter(param) && param.in === "header" && !this.shouldIgnoreHeader(param.name)
2477
2134
  );
2478
2135
  if (headerParams.length === 0) {
2479
2136
  continue;
2480
2137
  }
2481
- let pascalOperationId;
2482
- if (operation.operationId) {
2483
- pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
2484
- } else {
2485
- const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
2486
- pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
2487
- }
2138
+ const strippedPath = (0, import_openapi_core6.stripPathPrefix)(path, this.options.stripPathPrefix);
2139
+ const pascalOperationId = (0, import_openapi_core6.getOperationName)(
2140
+ operation.operationId,
2141
+ method,
2142
+ strippedPath,
2143
+ this.options.useOperationId
2144
+ );
2488
2145
  const schemaName = `${pascalOperationId}HeaderParams`;
2489
2146
  if (!this.schemaDependencies.has(schemaName)) {
2490
2147
  this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
@@ -2503,7 +2160,7 @@ ${propsCode}
2503
2160
  zodType = `${zodType}.optional()`;
2504
2161
  properties[paramName] = zodType;
2505
2162
  if (paramSchema.$ref) {
2506
- const refName = resolveRef(paramSchema.$ref);
2163
+ const refName = (0, import_openapi_core6.resolveRefName)(paramSchema.$ref);
2507
2164
  (_a = this.schemaDependencies.get(schemaName)) == null ? void 0 : _a.add(refName);
2508
2165
  }
2509
2166
  }
@@ -2518,9 +2175,7 @@ ${propsCode}
2518
2175
  ${propsCode}
2519
2176
  })`;
2520
2177
  const operationName = pascalOperationId;
2521
- const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
2522
- const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
2523
- const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}HeaderParamsSchema`;
2178
+ const camelCaseSchemaName = `${(0, import_openapi_core6.toCamelCase)(operationName, { prefix: this.options.prefix, suffix: this.options.suffix })}HeaderParamsSchema`;
2524
2179
  const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
2525
2180
  const jsdoc = `/**
2526
2181
  * Header parameters for ${jsdocOperationName}
@@ -2537,9 +2192,9 @@ ${propsCode}
2537
2192
  */
2538
2193
  generateQueryParamType(schema, param) {
2539
2194
  if (schema.$ref) {
2540
- const refName = resolveRef(schema.$ref);
2541
- const strippedRefName = stripPrefix(refName, this.options.stripSchemaPrefix);
2542
- const schemaName = toCamelCase(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
2195
+ const refName = (0, import_openapi_core6.resolveRefName)(schema.$ref);
2196
+ const strippedRefName = (0, import_openapi_core6.stripPrefix)(refName, this.options.stripSchemaPrefix);
2197
+ const schemaName = (0, import_openapi_core6.toCamelCase)(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
2543
2198
  return `${schemaName}Schema`;
2544
2199
  }
2545
2200
  if (schema.enum) {
@@ -2556,7 +2211,7 @@ ${propsCode}
2556
2211
  if (typeof v === "string") {
2557
2212
  return `z.literal("${v}")`;
2558
2213
  }
2559
- return `z.literal(${v})`;
2214
+ return `z.literal(${String(v)})`;
2560
2215
  }).join(", ");
2561
2216
  return `z.union([${literalValues}])`;
2562
2217
  }
@@ -2636,17 +2291,23 @@ ${propsCode}
2636
2291
  return;
2637
2292
  }
2638
2293
  const deps = this.schemaDependencies.get(name);
2294
+ let dependsOnCircular = false;
2639
2295
  if (deps && deps.size > 0) {
2640
2296
  for (const dep of deps) {
2641
2297
  if (this.schemas.has(dep) || this.types.has(dep)) {
2642
2298
  visit(dep);
2299
+ if (circularDeps.has(dep)) {
2300
+ dependsOnCircular = true;
2301
+ }
2643
2302
  }
2644
2303
  }
2645
2304
  }
2646
2305
  visiting.delete(name);
2647
2306
  visited.add(name);
2648
- if (!circularDeps.has(name)) {
2307
+ if (!circularDeps.has(name) && !dependsOnCircular) {
2649
2308
  sorted.push(name);
2309
+ } else if (dependsOnCircular && !circularDeps.has(name)) {
2310
+ circularDeps.add(name);
2650
2311
  }
2651
2312
  };
2652
2313
  const allNames = /* @__PURE__ */ new Set([...this.schemas.keys(), ...this.types.keys()]);
@@ -2654,9 +2315,8 @@ ${propsCode}
2654
2315
  visit(name);
2655
2316
  }
2656
2317
  for (const name of circularDeps) {
2657
- if (!visited.has(name)) {
2318
+ if (!sorted.includes(name)) {
2658
2319
  sorted.push(name);
2659
- visited.add(name);
2660
2320
  }
2661
2321
  }
2662
2322
  return [...sorted, ...aliases];
@@ -2683,11 +2343,12 @@ ${propsCode}
2683
2343
  `// Total schemas: ${stats.totalSchemas}`,
2684
2344
  `// Circular references: ${stats.withCircularRefs}`,
2685
2345
  `// Discriminated unions: ${stats.withDiscriminators}`,
2686
- `// With constraints: ${stats.withConstraints}`
2346
+ `// With constraints: ${stats.withConstraints}`,
2347
+ `// AllOf conflicts: ${this.allOfConflictCount}`
2687
2348
  ];
2688
2349
  if (this.options.operationFilters && this.filterStats.totalOperations > 0) {
2689
2350
  output.push("//");
2690
- const filterStatsStr = formatFilterStatistics(this.filterStats);
2351
+ const filterStatsStr = (0, import_openapi_core6.formatFilterStatistics)(this.filterStats);
2691
2352
  for (const line of filterStatsStr.split("\n")) {
2692
2353
  output.push(`// ${line}`);
2693
2354
  }
@@ -2695,6 +2356,106 @@ ${propsCode}
2695
2356
  output.push(`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`);
2696
2357
  return output;
2697
2358
  }
2359
+ /**
2360
+ * Pre-analyze schemas to detect circular dependencies before code generation.
2361
+ * This allows the property generator to use z.lazy() for forward references.
2362
+ */
2363
+ analyzeCircularDependencies() {
2364
+ var _a;
2365
+ if (!((_a = this.spec.components) == null ? void 0 : _a.schemas)) return;
2366
+ const dependencies = /* @__PURE__ */ new Map();
2367
+ const collectDependencies = (name, schema, visited2 = /* @__PURE__ */ new Set()) => {
2368
+ if (visited2.has(name)) return /* @__PURE__ */ new Set();
2369
+ visited2.add(name);
2370
+ const deps = /* @__PURE__ */ new Set();
2371
+ if (schema.$ref) {
2372
+ const refName = (0, import_openapi_core6.resolveRefName)(schema.$ref);
2373
+ deps.add(refName);
2374
+ }
2375
+ if (schema.allOf) {
2376
+ for (const item of schema.allOf) {
2377
+ const itemDeps = collectDependencies(`${name}_allOf`, item, new Set(visited2));
2378
+ for (const dep of itemDeps) deps.add(dep);
2379
+ }
2380
+ }
2381
+ if (schema.oneOf) {
2382
+ for (const item of schema.oneOf) {
2383
+ const itemDeps = collectDependencies(`${name}_oneOf`, item, new Set(visited2));
2384
+ for (const dep of itemDeps) deps.add(dep);
2385
+ }
2386
+ }
2387
+ if (schema.anyOf) {
2388
+ for (const item of schema.anyOf) {
2389
+ const itemDeps = collectDependencies(`${name}_anyOf`, item, new Set(visited2));
2390
+ for (const dep of itemDeps) deps.add(dep);
2391
+ }
2392
+ }
2393
+ if (schema.properties) {
2394
+ for (const propSchema of Object.values(schema.properties)) {
2395
+ const propDeps = collectDependencies(`${name}_prop`, propSchema, new Set(visited2));
2396
+ for (const dep of propDeps) deps.add(dep);
2397
+ }
2398
+ }
2399
+ if (schema.items) {
2400
+ const itemDeps = collectDependencies(`${name}_items`, schema.items, new Set(visited2));
2401
+ for (const dep of itemDeps) deps.add(dep);
2402
+ }
2403
+ if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
2404
+ const addDeps = collectDependencies(`${name}_additional`, schema.additionalProperties, new Set(visited2));
2405
+ for (const dep of addDeps) deps.add(dep);
2406
+ }
2407
+ return deps;
2408
+ };
2409
+ for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
2410
+ if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
2411
+ continue;
2412
+ }
2413
+ dependencies.set(name, collectDependencies(name, schema));
2414
+ }
2415
+ const visited = /* @__PURE__ */ new Set();
2416
+ const visiting = /* @__PURE__ */ new Set();
2417
+ const detectCircular = (name, path = []) => {
2418
+ if (visited.has(name)) return;
2419
+ if (visiting.has(name)) {
2420
+ const cycleStart = path.indexOf(name);
2421
+ if (cycleStart >= 0) {
2422
+ for (let i = cycleStart; i < path.length; i++) {
2423
+ this.circularDependencies.add(path[i]);
2424
+ }
2425
+ }
2426
+ this.circularDependencies.add(name);
2427
+ return;
2428
+ }
2429
+ visiting.add(name);
2430
+ path.push(name);
2431
+ const deps = dependencies.get(name);
2432
+ if (deps) {
2433
+ for (const dep of deps) {
2434
+ if (dependencies.has(dep)) {
2435
+ detectCircular(dep, [...path]);
2436
+ }
2437
+ }
2438
+ }
2439
+ visiting.delete(name);
2440
+ visited.add(name);
2441
+ };
2442
+ for (const name of dependencies.keys()) {
2443
+ detectCircular(name, []);
2444
+ }
2445
+ }
2446
+ /**
2447
+ * Generate JSDoc warning for allOf conflicts
2448
+ * @param conflicts Array of conflict description strings
2449
+ * @returns JSDoc formatted warning string
2450
+ */
2451
+ generateConflictJSDoc(conflicts) {
2452
+ const lines = [" * @warning allOf property conflicts detected:"];
2453
+ for (const conflict of conflicts) {
2454
+ lines.push(` * - ${conflict}`);
2455
+ }
2456
+ return `${lines.join("\n")}
2457
+ `;
2458
+ }
2698
2459
  };
2699
2460
 
2700
2461
  // src/types.ts
@@ -2709,8 +2470,10 @@ function defineConfig(config) {
2709
2470
  FileOperationError,
2710
2471
  GeneratorError,
2711
2472
  OpenApiGenerator,
2473
+ PropertyGenerator,
2712
2474
  SchemaGenerationError,
2713
2475
  SpecValidationError,
2476
+ buildDateTimeValidation,
2714
2477
  defineConfig
2715
2478
  });
2716
2479
  //# sourceMappingURL=index.js.map