@cerios/openapi-to-zod 1.3.2 → 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.mjs CHANGED
@@ -1,193 +1,30 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- // src/errors.ts
9
- var GeneratorError = class extends Error {
10
- constructor(message, code, context) {
11
- var _a;
12
- super(message);
13
- this.code = code;
14
- this.context = context;
15
- this.name = "GeneratorError";
16
- (_a = Error.captureStackTrace) == null ? void 0 : _a.call(Error, this, this.constructor);
17
- }
18
- };
19
- var SpecValidationError = class extends GeneratorError {
20
- constructor(message, context) {
21
- super(message, "SPEC_VALIDATION_ERROR", context);
22
- this.name = "SpecValidationError";
23
- }
24
- };
25
- var FileOperationError = class extends GeneratorError {
26
- constructor(message, filePath, context) {
27
- super(message, "FILE_OPERATION_ERROR", { ...context, filePath });
28
- this.filePath = filePath;
29
- this.name = "FileOperationError";
30
- }
31
- };
32
- var ConfigValidationError = class extends GeneratorError {
33
- constructor(message, configPath, context) {
34
- super(message, "CONFIG_VALIDATION_ERROR", { ...context, configPath });
35
- this.configPath = configPath;
36
- this.name = "ConfigValidationError";
37
- }
38
- };
39
- var SchemaGenerationError = class extends GeneratorError {
40
- constructor(message, schemaName, context) {
41
- super(message, "SCHEMA_GENERATION_ERROR", { ...context, schemaName });
42
- this.schemaName = schemaName;
43
- this.name = "SchemaGenerationError";
44
- }
45
- };
46
- var CircularReferenceError = class extends SchemaGenerationError {
47
- constructor(schemaName, referencePath) {
48
- const pathStr = referencePath.join(" -> ");
49
- super(`Circular reference detected in schema: ${pathStr}`, schemaName, { referencePath, circularPath: pathStr });
50
- this.referencePath = referencePath;
51
- this.name = "CircularReferenceError";
52
- }
53
- };
54
- var CliOptionsError = class extends GeneratorError {
55
- constructor(message, context) {
56
- super(message, "CLI_OPTIONS_ERROR", context);
57
- this.name = "CliOptionsError";
58
- }
59
- };
60
- var ConfigurationError = class extends GeneratorError {
61
- constructor(message, context) {
62
- super(message, "CONFIGURATION_ERROR", context);
63
- this.name = "ConfigurationError";
64
- }
65
- };
66
-
67
- // src/openapi-generator.ts
68
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
69
- import { dirname, normalize } from "path";
70
- import { minimatch as minimatch3 } from "minimatch";
71
- import { parse } from "yaml";
72
-
73
- // src/utils/name-utils.ts
74
- function sanitizeIdentifier(str) {
75
- return str.replace(/[^a-zA-Z0-9._\-\s]+/g, "_");
76
- }
77
- function toCamelCase(str, options) {
78
- const sanitized = sanitizeIdentifier(str);
79
- const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
80
- let name;
81
- if (words.length === 0) {
82
- name = str.charAt(0).toLowerCase() + str.slice(1);
83
- } else if (words.length === 1) {
84
- name = words[0].charAt(0).toLowerCase() + words[0].slice(1);
85
- } else {
86
- name = words[0].charAt(0).toLowerCase() + words[0].slice(1) + words.slice(1).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
87
- }
88
- if (options == null ? void 0 : options.prefix) {
89
- const prefix = options.prefix.charAt(0).toLowerCase() + options.prefix.slice(1);
90
- name = prefix + name.charAt(0).toUpperCase() + name.slice(1);
91
- }
92
- if (options == null ? void 0 : options.suffix) {
93
- const suffix = options.suffix.charAt(0).toUpperCase() + options.suffix.slice(1);
94
- name = name + suffix;
95
- }
96
- return name;
97
- }
98
- function toPascalCase(str) {
99
- const stringValue = String(str);
100
- const isAlreadyValidCase = /^[a-zA-Z][a-zA-Z0-9]*$/.test(stringValue);
101
- if (isAlreadyValidCase) {
102
- return stringValue.charAt(0).toUpperCase() + stringValue.slice(1);
103
- }
104
- const sanitized = sanitizeIdentifier(stringValue);
105
- const words = sanitized.split(/[.\-_\s]+/).filter((word) => word.length > 0);
106
- let result;
107
- if (words.length === 0) {
108
- result = "Value";
109
- } else {
110
- result = words.map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
111
- }
112
- if (/^\d/.test(result)) {
113
- result = `N${result}`;
114
- }
115
- if (!result || /^_+$/.test(result)) {
116
- return "Value";
117
- }
118
- return result;
119
- }
120
- function resolveRef(ref) {
121
- const parts = ref.split("/");
122
- return parts[parts.length - 1];
123
- }
1
+ // src/index.ts
2
+ import {
3
+ CircularReferenceError,
4
+ CliOptionsError,
5
+ ConfigValidationError,
6
+ FileOperationError,
7
+ GeneratorError,
8
+ SchemaGenerationError as SchemaGenerationError2,
9
+ SpecValidationError as SpecValidationError2
10
+ } from "@cerios/openapi-core";
124
11
 
125
- // src/generators/enum-generator.ts
126
- function generateEnum(name, values, options) {
127
- const schemaName = `${toCamelCase(name, options)}Schema`;
128
- const typeName = toPascalCase(name);
129
- const allBooleans = values.every((v) => typeof v === "boolean");
130
- if (allBooleans) {
131
- const schemaCode2 = `export const ${schemaName} = z.boolean();`;
132
- const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
133
- return { schemaCode: schemaCode2, typeCode: typeCode2 };
134
- }
135
- const allStrings = values.every((v) => typeof v === "string");
136
- if (allStrings) {
137
- const enumValues = values.map((v) => `"${v}"`).join(", ");
138
- const schemaCode2 = `export const ${schemaName} = z.enum([${enumValues}]);`;
139
- const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
140
- return { schemaCode: schemaCode2, typeCode: typeCode2 };
141
- }
142
- const literalValues = values.map((v) => {
143
- if (typeof v === "string") {
144
- return `z.literal("${v}")`;
145
- }
146
- return `z.literal(${v})`;
147
- }).join(", ");
148
- const schemaCode = `export const ${schemaName} = z.union([${literalValues}]);`;
149
- const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
150
- return { schemaCode, typeCode };
151
- }
12
+ // src/generators/property-generator.ts
13
+ import {
14
+ getPrimaryType,
15
+ hasMultipleTypes,
16
+ isNullable,
17
+ LRUCache,
18
+ resolveRefName,
19
+ stripPrefix,
20
+ toCamelCase,
21
+ toPascalCase
22
+ } from "@cerios/openapi-core";
152
23
 
153
24
  // src/utils/string-utils.ts
154
- function escapeDescription(str) {
155
- return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
156
- }
157
- function escapePattern(str) {
158
- return str.replace(/\//g, "\\/");
159
- }
160
- function escapeJSDoc(str) {
161
- return str.replace(/\*\//g, "*\\/");
162
- }
163
- function wrapNullable(validation, isNullable2) {
164
- return isNullable2 ? `${validation}.nullable()` : validation;
165
- }
166
- function isNullable(schema, defaultNullable = false) {
167
- if (schema.nullable === true) {
168
- return true;
169
- }
170
- if (schema.nullable === false) {
171
- return false;
172
- }
173
- if (Array.isArray(schema.type)) {
174
- return schema.type.includes("null");
175
- }
176
- return defaultNullable;
177
- }
178
- function getPrimaryType(schema) {
179
- if (Array.isArray(schema.type)) {
180
- const nonNullType = schema.type.find((t) => t !== "null");
181
- return nonNullType;
182
- }
183
- return schema.type;
184
- }
185
- function hasMultipleTypes(schema) {
186
- if (Array.isArray(schema.type)) {
187
- const nonNullTypes = schema.type.filter((t) => t !== "null");
188
- return nonNullTypes.length > 1;
189
- }
190
- return false;
25
+ import { escapeDescription } from "@cerios/openapi-core";
26
+ function wrapNullable(validation, nullable) {
27
+ return nullable ? `${validation}.nullable()` : validation;
191
28
  }
192
29
  function addDescription(validation, description, useDescribe) {
193
30
  if (!description || !useDescribe) return validation;
@@ -195,167 +32,6 @@ function addDescription(validation, description, useDescribe) {
195
32
  return `${validation}.describe("${escapedDesc}")`;
196
33
  }
197
34
 
198
- // src/generators/jsdoc-generator.ts
199
- function generateJSDoc(schema, name, options = { includeDescriptions: true }) {
200
- if (!schema || typeof schema !== "object") {
201
- return "";
202
- }
203
- if (!options.includeDescriptions) {
204
- if (schema.deprecated) {
205
- return "/** @deprecated */\n";
206
- }
207
- return "";
208
- }
209
- if (!schema.description && !schema.title && !schema.deprecated && !schema.examples && schema.example === void 0) {
210
- return "";
211
- }
212
- const parts = [];
213
- if (schema.title && typeof schema.title === "string" && (!name || schema.title !== name)) {
214
- const sanitizedTitle = escapeJSDoc(schema.title).replace(/@/g, "\\@");
215
- parts.push(sanitizedTitle);
216
- }
217
- if (schema.description && typeof schema.description === "string") {
218
- const sanitizedDesc = escapeJSDoc(schema.description).replace(/@/g, "\\@").replace(/\*\//g, "*\\/");
219
- parts.push(sanitizedDesc);
220
- }
221
- if (schema.examples && Array.isArray(schema.examples) && schema.examples.length > 0) {
222
- try {
223
- const examplesStr = schema.examples.map((ex) => JSON.stringify(ex)).join(", ");
224
- parts.push(`@example ${examplesStr}`);
225
- } catch (error) {
226
- console.warn("Warning: Could not serialize schema examples", error);
227
- }
228
- } else if (schema.example !== void 0) {
229
- try {
230
- parts.push(`@example ${JSON.stringify(schema.example)}`);
231
- } catch (error) {
232
- console.warn("Warning: Could not serialize schema example", error);
233
- }
234
- }
235
- if (schema.deprecated) {
236
- parts.push("@deprecated");
237
- }
238
- if (parts.length === 0) {
239
- return "";
240
- }
241
- const fullComment = parts.join(" ");
242
- return `/** ${fullComment} */
243
- `;
244
- }
245
-
246
- // src/utils/lru-cache.ts
247
- var LRUCache = class {
248
- constructor(maxSize) {
249
- this.cache = /* @__PURE__ */ new Map();
250
- this.maxSize = maxSize;
251
- }
252
- get capacity() {
253
- return this.maxSize;
254
- }
255
- get(key) {
256
- if (!this.cache.has(key)) return void 0;
257
- const value = this.cache.get(key);
258
- if (value === void 0) return void 0;
259
- this.cache.delete(key);
260
- this.cache.set(key, value);
261
- return value;
262
- }
263
- set(key, value) {
264
- if (this.cache.has(key)) {
265
- this.cache.delete(key);
266
- } else if (this.cache.size >= this.maxSize) {
267
- const firstKey = this.cache.keys().next().value;
268
- if (firstKey !== void 0) {
269
- this.cache.delete(firstKey);
270
- }
271
- }
272
- this.cache.set(key, value);
273
- }
274
- has(key) {
275
- return this.cache.has(key);
276
- }
277
- clear() {
278
- this.cache.clear();
279
- }
280
- size() {
281
- return this.cache.size;
282
- }
283
- };
284
-
285
- // src/utils/pattern-utils.ts
286
- import { minimatch } from "minimatch";
287
- function isValidGlobPattern(pattern) {
288
- try {
289
- new minimatch.Minimatch(pattern);
290
- return true;
291
- } catch {
292
- return false;
293
- }
294
- }
295
- function isGlobPattern(pattern) {
296
- return /[*?[\]{}!]/.test(pattern);
297
- }
298
- function stripPrefix(input, pattern, ensureLeadingChar) {
299
- if (!pattern) {
300
- return input;
301
- }
302
- if (isGlobPattern(pattern) && !isValidGlobPattern(pattern)) {
303
- console.warn(`\u26A0\uFE0F Invalid glob pattern "${pattern}": Pattern is malformed`);
304
- return input;
305
- }
306
- if (isGlobPattern(pattern)) {
307
- let longestMatch = -1;
308
- for (let i = 1; i <= input.length; i++) {
309
- const testPrefix = input.substring(0, i);
310
- if (minimatch(testPrefix, pattern)) {
311
- longestMatch = i;
312
- }
313
- }
314
- if (longestMatch > 0) {
315
- const stripped = input.substring(longestMatch);
316
- if (ensureLeadingChar) {
317
- if (stripped === "") {
318
- return ensureLeadingChar;
319
- }
320
- if (!stripped.startsWith(ensureLeadingChar)) {
321
- return `${ensureLeadingChar}${stripped}`;
322
- }
323
- }
324
- return stripped === "" && !ensureLeadingChar ? input : stripped;
325
- }
326
- return input;
327
- }
328
- if (input.startsWith(pattern)) {
329
- const stripped = input.substring(pattern.length);
330
- if (ensureLeadingChar) {
331
- if (stripped === "") {
332
- return ensureLeadingChar;
333
- }
334
- if (!stripped.startsWith(ensureLeadingChar)) {
335
- return `${ensureLeadingChar}${stripped}`;
336
- }
337
- }
338
- return stripped;
339
- }
340
- return input;
341
- }
342
- function stripPathPrefix(path, pattern) {
343
- if (!pattern) {
344
- return path;
345
- }
346
- if (!isGlobPattern(pattern)) {
347
- let normalizedPattern = pattern.trim();
348
- if (!normalizedPattern.startsWith("/")) {
349
- normalizedPattern = `/${normalizedPattern}`;
350
- }
351
- if (normalizedPattern.endsWith("/") && normalizedPattern !== "/") {
352
- normalizedPattern = normalizedPattern.slice(0, -1);
353
- }
354
- return stripPrefix(path, normalizedPattern, "/");
355
- }
356
- return stripPrefix(path, pattern, "/");
357
- }
358
-
359
35
  // src/validators/array-validator.ts
360
36
  function generateArrayValidation(schema, context) {
361
37
  var _a;
@@ -523,15 +199,14 @@ function detectConflictingProperties(schemas, context) {
523
199
  function generateAllOf(schemas, isNullable2, context, currentSchema) {
524
200
  if (schemas.length === 1) {
525
201
  const singleSchema = context.generatePropertySchema(schemas[0], currentSchema, false, true);
526
- return wrapNullable(singleSchema, isNullable2);
202
+ return { schema: wrapNullable(singleSchema, isNullable2), conflicts: [] };
527
203
  }
528
204
  const conflicts = detectConflictingProperties(schemas, context);
529
- let conflictDescription = "";
530
- if (conflicts.length > 0) {
531
- for (const conflict of conflicts) {
205
+ const uniqueConflicts = [...new Set(conflicts)];
206
+ if (uniqueConflicts.length > 0) {
207
+ for (const conflict of uniqueConflicts) {
532
208
  console.warn(`[openapi-to-zod] Warning: allOf composition conflict - ${conflict}`);
533
209
  }
534
- conflictDescription = `allOf property conflicts detected: ${conflicts.join("; ")}`;
535
210
  }
536
211
  const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.$ref || s.allOf);
537
212
  let result;
@@ -559,10 +234,7 @@ function generateAllOf(schemas, isNullable2, context, currentSchema) {
559
234
  }
560
235
  result = merged;
561
236
  }
562
- if (conflictDescription) {
563
- result = `${result}.describe("${conflictDescription}")`;
564
- }
565
- return wrapNullable(result, isNullable2);
237
+ return { schema: wrapNullable(result, isNullable2), conflicts: uniqueConflicts };
566
238
  }
567
239
 
568
240
  // src/validators/number-validator.ts
@@ -586,6 +258,53 @@ function generateNumberValidation(schema, isInt, useDescribe) {
586
258
  return addDescription(validation, schema.description, useDescribe);
587
259
  }
588
260
 
261
+ // src/generators/jsdoc-generator.ts
262
+ import { escapeJSDoc } from "@cerios/openapi-core";
263
+ function generateJSDoc(schema, name, options = { includeDescriptions: true }) {
264
+ if (!schema || typeof schema !== "object") {
265
+ return "";
266
+ }
267
+ if (!options.includeDescriptions) {
268
+ if (schema.deprecated) {
269
+ return "/** @deprecated */\n";
270
+ }
271
+ return "";
272
+ }
273
+ if (!schema.description && !schema.title && !schema.deprecated && !schema.examples && schema.example === void 0) {
274
+ return "";
275
+ }
276
+ const parts = [];
277
+ if (schema.title && typeof schema.title === "string" && (!name || schema.title !== name)) {
278
+ parts.push(escapeJSDoc(schema.title));
279
+ }
280
+ if (schema.description && typeof schema.description === "string") {
281
+ parts.push(escapeJSDoc(schema.description));
282
+ }
283
+ if (schema.examples && Array.isArray(schema.examples) && schema.examples.length > 0) {
284
+ try {
285
+ const examplesStr = schema.examples.map((ex) => JSON.stringify(ex)).join(", ");
286
+ parts.push(`@example ${examplesStr}`);
287
+ } catch (error) {
288
+ console.warn("Warning: Could not serialize schema examples", error);
289
+ }
290
+ } else if (schema.example !== void 0) {
291
+ try {
292
+ parts.push(`@example ${JSON.stringify(schema.example)}`);
293
+ } catch (error) {
294
+ console.warn("Warning: Could not serialize schema example", error);
295
+ }
296
+ }
297
+ if (schema.deprecated) {
298
+ parts.push("@deprecated");
299
+ }
300
+ if (parts.length === 0) {
301
+ return "";
302
+ }
303
+ const fullComment = parts.join(" ");
304
+ return `/** ${fullComment} */
305
+ `;
306
+ }
307
+
589
308
  // src/validators/conditional-validator.ts
590
309
  function generatePropertyAccess(propName) {
591
310
  const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
@@ -644,7 +363,8 @@ function generateConditionalCheck(schema) {
644
363
  for (const [prop, propSchema] of Object.entries(schema.properties)) {
645
364
  const propAccess = generatePropertyAccess(prop);
646
365
  if (propSchema.type) {
647
- conditions.push(`typeof ${propAccess} === "${propSchema.type}"`);
366
+ const schemaType = Array.isArray(propSchema.type) ? propSchema.type[0] : propSchema.type;
367
+ conditions.push(`typeof ${propAccess} === "${schemaType}"`);
648
368
  }
649
369
  if (propSchema.const !== void 0) {
650
370
  const value = typeof propSchema.const === "string" ? `"${propSchema.const}"` : propSchema.const;
@@ -703,7 +423,7 @@ function generateIfThenElse(schema) {
703
423
  if (!thenValid) {
704
424
  ${thenRequiredProps.length > 0 ? `
705
425
  const missingThenProps = ${JSON.stringify(thenRequiredProps)}.filter(p => obj[p] === undefined);
706
- const message = missingThenProps.length > 0
426
+ const message = missingThenProps.length > 0
707
427
  ? \`When condition is met, required properties are missing: \${missingThenProps.join(', ')}\`
708
428
  : "When condition is met, validation constraints failed";
709
429
  ` : `
@@ -721,7 +441,7 @@ function generateIfThenElse(schema) {
721
441
  if (!elseValid) {
722
442
  ${elseRequiredProps2.length > 0 ? `
723
443
  const missingElseProps = ${JSON.stringify(elseRequiredProps2)}.filter(p => obj[p] === undefined);
724
- const message = missingElseProps.length > 0
444
+ const message = missingElseProps.length > 0
725
445
  ? \`When condition is not met, required properties are missing: \${missingElseProps.join(', ')}\`
726
446
  : "When condition is not met, validation constraints failed";
727
447
  ` : `
@@ -746,7 +466,7 @@ function generateIfThenElse(schema) {
746
466
  if (!thenValid) {
747
467
  ${thenRequiredProps.length > 0 ? `
748
468
  const missingProps = ${JSON.stringify(thenRequiredProps)}.filter(p => obj[p] === undefined);
749
- const message = missingProps.length > 0
469
+ const message = missingProps.length > 0
750
470
  ? \`When condition is met, required properties are missing: \${missingProps.join(', ')}\`
751
471
  : "When condition is met, validation constraints failed";
752
472
  ` : `
@@ -771,7 +491,7 @@ function generateIfThenElse(schema) {
771
491
  if (!elseValid) {
772
492
  ${elseRequiredProps.length > 0 ? `
773
493
  const missingProps = ${JSON.stringify(elseRequiredProps)}.filter(p => obj[p] === undefined);
774
- const message = missingProps.length > 0
494
+ const message = missingProps.length > 0
775
495
  ? \`When condition is not met, required properties are missing: \${missingProps.join(', ')}\`
776
496
  : "When condition is not met, validation constraints failed";
777
497
  ` : `
@@ -859,8 +579,9 @@ ${propertyDef}`);
859
579
  case "loose":
860
580
  objectMethod = "z.looseObject";
861
581
  break;
862
- default:
582
+ case "normal":
863
583
  objectMethod = "z.object";
584
+ break;
864
585
  }
865
586
  }
866
587
  let objectDef = `${objectMethod}({
@@ -870,7 +591,7 @@ ${properties.join(",\n")}
870
591
  if (typeof schema.additionalProperties === "object") {
871
592
  const additionalSchema = context.generatePropertySchema(schema.additionalProperties, currentSchema);
872
593
  objectDef += `.catchall(${additionalSchema})`;
873
- } else if (schema.additionalProperties === true) {
594
+ } else if (schema.additionalProperties) {
874
595
  objectDef += ".catchall(z.unknown())";
875
596
  }
876
597
  } else if (schema.patternProperties) {
@@ -995,12 +716,7 @@ ${properties.join(",\n")}
995
716
  }
996
717
 
997
718
  // src/validators/string-validator.ts
998
- var PATTERN_CACHE = new LRUCache(1e3);
999
- function configurePatternCache(size) {
1000
- if (size > 0 && size !== PATTERN_CACHE.capacity) {
1001
- PATTERN_CACHE = new LRUCache(size);
1002
- }
1003
- }
719
+ import { escapePattern } from "@cerios/openapi-core";
1004
720
  var DEFAULT_FORMAT_MAP = {
1005
721
  uuid: "z.uuid()",
1006
722
  email: "z.email()",
@@ -1029,19 +745,13 @@ var DEFAULT_FORMAT_MAP = {
1029
745
  "json-pointer": 'z.string().refine((val) => val === "" || /^(\\/([^~/]|~0|~1)+)+$/.test(val), { message: "Must be a valid JSON Pointer (RFC 6901)" })',
1030
746
  "relative-json-pointer": 'z.string().refine((val) => /^(0|[1-9]\\d*)(#|(\\/([^~/]|~0|~1)+)*)$/.test(val), { message: "Must be a valid relative JSON Pointer" })'
1031
747
  };
1032
- var FORMAT_MAP = {
1033
- ...DEFAULT_FORMAT_MAP,
1034
- "date-time": "z.iso.datetime()"
1035
- };
1036
- function configureDateTimeFormat(pattern) {
748
+ function buildDateTimeValidation(pattern) {
1037
749
  if (!pattern) {
1038
- FORMAT_MAP["date-time"] = "z.iso.datetime()";
1039
- return;
750
+ return "z.iso.datetime()";
1040
751
  }
1041
752
  const patternStr = pattern instanceof RegExp ? pattern.source : pattern;
1042
753
  if (patternStr === "") {
1043
- FORMAT_MAP["date-time"] = "z.iso.datetime()";
1044
- return;
754
+ return "z.iso.datetime()";
1045
755
  }
1046
756
  try {
1047
757
  new RegExp(patternStr);
@@ -1051,10 +761,16 @@ function configureDateTimeFormat(pattern) {
1051
761
  );
1052
762
  }
1053
763
  const escapedPattern = escapePattern(patternStr);
1054
- FORMAT_MAP["date-time"] = `z.string().regex(/${escapedPattern}/)`;
764
+ return `z.string().regex(/${escapedPattern}/)`;
1055
765
  }
1056
- function generateStringValidation(schema, useDescribe) {
1057
- let validation = FORMAT_MAP[schema.format || ""] || "z.string()";
766
+ function generateStringValidation(schema, useDescribe, context) {
767
+ let validation;
768
+ const format = schema.format || "";
769
+ if (format === "date-time") {
770
+ validation = context.dateTimeValidation;
771
+ } else {
772
+ validation = DEFAULT_FORMAT_MAP[format] || "z.string()";
773
+ }
1058
774
  if (schema.minLength !== void 0) {
1059
775
  validation += `.min(${schema.minLength})`;
1060
776
  }
@@ -1062,10 +778,10 @@ function generateStringValidation(schema, useDescribe) {
1062
778
  validation += `.max(${schema.maxLength})`;
1063
779
  }
1064
780
  if (schema.pattern) {
1065
- let escapedPattern = PATTERN_CACHE.get(schema.pattern);
781
+ let escapedPattern = context.patternCache.get(schema.pattern);
1066
782
  if (escapedPattern === void 0) {
1067
783
  escapedPattern = escapePattern(schema.pattern);
1068
- PATTERN_CACHE.set(schema.pattern, escapedPattern);
784
+ context.patternCache.set(schema.pattern, escapedPattern);
1069
785
  }
1070
786
  validation += `.regex(/${escapedPattern}/)`;
1071
787
  }
@@ -1095,10 +811,10 @@ function generateStringValidation(schema, useDescribe) {
1095
811
  validation += `.max(${schema.maxLength})`;
1096
812
  }
1097
813
  if (schema.pattern) {
1098
- let escapedPattern = PATTERN_CACHE.get(schema.pattern);
814
+ let escapedPattern = context.patternCache.get(schema.pattern);
1099
815
  if (escapedPattern === void 0) {
1100
816
  escapedPattern = escapePattern(schema.pattern);
1101
- PATTERN_CACHE.set(schema.pattern, escapedPattern);
817
+ context.patternCache.set(schema.pattern, escapedPattern);
1102
818
  }
1103
819
  validation += `.regex(/${escapedPattern}/)`;
1104
820
  }
@@ -1126,8 +842,32 @@ var _PropertyGenerator = class _PropertyGenerator {
1126
842
  this.filteredPropsCache = /* @__PURE__ */ new Map();
1127
843
  // Performance optimization: LRU cache for generated schemas
1128
844
  this.schemaCache = new LRUCache(500);
845
+ // Track allOf conflicts detected during schema generation
846
+ this.allOfConflicts = [];
847
+ // Schemas that are part of circular dependency chains (need z.lazy for forward refs)
848
+ this.circularDependencies = /* @__PURE__ */ new Set();
1129
849
  this.context = context;
1130
850
  }
851
+ /**
852
+ * Set the schemas that are involved in circular dependency chains.
853
+ * These schemas will use z.lazy() for forward references.
854
+ */
855
+ setCircularDependencies(deps) {
856
+ this.circularDependencies = deps;
857
+ }
858
+ /**
859
+ * Get allOf conflicts detected during the last schema generation
860
+ * @returns Array of conflict description strings
861
+ */
862
+ getAllOfConflicts() {
863
+ return [...this.allOfConflicts];
864
+ }
865
+ /**
866
+ * Clear tracked allOf conflicts (call before generating a new schema)
867
+ */
868
+ clearAllOfConflicts() {
869
+ this.allOfConflicts = [];
870
+ }
1131
871
  /**
1132
872
  * Check if a property should be included based on schemaType and readOnly/writeOnly flags
1133
873
  */
@@ -1160,7 +900,9 @@ var _PropertyGenerator = class _PropertyGenerator {
1160
900
  filterNestedProperties(schema) {
1161
901
  var _a, _b;
1162
902
  const propKeys = schema.properties ? Object.keys(schema.properties).sort().join(",") : "";
1163
- const cacheKey = `${this.context.schemaType}:${schema.type || "unknown"}:${propKeys}:${((_a = schema.required) == null ? void 0 : _a.join(",")) || ""}`;
903
+ const requiredKeys = Array.isArray(schema.required) ? schema.required.join(",") : String((_a = schema.required) != null ? _a : "");
904
+ const schemaType = Array.isArray(schema.type) ? schema.type.join("|") : schema.type || "unknown";
905
+ const cacheKey = `${this.context.schemaType}:${schemaType}:${propKeys}:${requiredKeys}`;
1164
906
  const cached = this.filteredPropsCache.get(cacheKey);
1165
907
  if (cached) {
1166
908
  return cached;
@@ -1256,7 +998,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1256
998
  const schema = (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
1257
999
  if (!schema) return schemaName;
1258
1000
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref && !schema.properties && !schema.oneOf && !schema.anyOf) {
1259
- const targetName = resolveRef(schema.allOf[0].$ref);
1001
+ const targetName = resolveRefName(schema.allOf[0].$ref);
1260
1002
  return this.resolveSchemaAlias(targetName);
1261
1003
  }
1262
1004
  return schemaName;
@@ -1269,7 +1011,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1269
1011
  const toSchemaSpec = (_b = (_a = this.context.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[toSchema];
1270
1012
  if (!toSchemaSpec) return false;
1271
1013
  if (toSchemaSpec.allOf && toSchemaSpec.allOf.length === 1 && toSchemaSpec.allOf[0].$ref) {
1272
- const aliasTarget = resolveRef(toSchemaSpec.allOf[0].$ref);
1014
+ const aliasTarget = resolveRefName(toSchemaSpec.allOf[0].$ref);
1273
1015
  return aliasTarget === fromSchema;
1274
1016
  }
1275
1017
  return false;
@@ -1370,7 +1112,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1370
1112
  return wrapNullable(union, nullable);
1371
1113
  }
1372
1114
  if (schema.$ref) {
1373
- const refName = resolveRef(schema.$ref);
1115
+ const refName = resolveRefName(schema.$ref);
1374
1116
  const resolvedRefName = this.resolveSchemaAlias(refName);
1375
1117
  if (currentSchema && refName !== currentSchema && !isTopLevel) {
1376
1118
  if (!this.context.schemaDependencies.has(currentSchema)) {
@@ -1380,8 +1122,13 @@ var _PropertyGenerator = class _PropertyGenerator {
1380
1122
  }
1381
1123
  const strippedRefName = stripPrefix(resolvedRefName, this.context.stripSchemaPrefix);
1382
1124
  const schemaName = `${toCamelCase(strippedRefName, this.context.namingOptions)}Schema`;
1383
- if (currentSchema && (refName === currentSchema || this.isCircularThroughAlias(currentSchema, refName))) {
1384
- const lazySchema = `z.lazy((): z.ZodTypeAny => ${schemaName})`;
1125
+ const typeName = toPascalCase(strippedRefName);
1126
+ const isDirectSelfRef = currentSchema && refName === currentSchema;
1127
+ const isCircularAlias = currentSchema && this.isCircularThroughAlias(currentSchema, refName);
1128
+ const isMutuallyCircular = currentSchema && this.circularDependencies.has(currentSchema) && this.circularDependencies.has(refName);
1129
+ if (isDirectSelfRef || isCircularAlias || isMutuallyCircular) {
1130
+ const lazyTypeAnnotation = this.context.separateTypesFile ? `z.ZodType<${typeName}>` : "z.ZodTypeAny";
1131
+ const lazySchema = `z.lazy((): ${lazyTypeAnnotation} => ${schemaName})`;
1385
1132
  return wrapNullable(lazySchema, nullable);
1386
1133
  }
1387
1134
  return wrapNullable(schemaName, nullable);
@@ -1414,7 +1161,7 @@ var _PropertyGenerator = class _PropertyGenerator {
1414
1161
  }
1415
1162
  if (schema.allOf) {
1416
1163
  const compositionNullable = isNullable(schema, false);
1417
- let composition = generateAllOf(
1164
+ const allOfResult = generateAllOf(
1418
1165
  schema.allOf,
1419
1166
  compositionNullable,
1420
1167
  {
@@ -1424,6 +1171,10 @@ var _PropertyGenerator = class _PropertyGenerator {
1424
1171
  },
1425
1172
  currentSchema
1426
1173
  );
1174
+ if (allOfResult.conflicts.length > 0) {
1175
+ this.allOfConflicts.push(...allOfResult.conflicts);
1176
+ }
1177
+ let composition = allOfResult.schema;
1427
1178
  if (schema.unevaluatedProperties !== void 0) {
1428
1179
  composition = this.applyUnevaluatedProperties(composition, schema);
1429
1180
  }
@@ -1491,7 +1242,10 @@ var _PropertyGenerator = class _PropertyGenerator {
1491
1242
  const primaryType = getPrimaryType(schema);
1492
1243
  switch (primaryType) {
1493
1244
  case "string":
1494
- validation = generateStringValidation(schema, this.context.useDescribe);
1245
+ validation = generateStringValidation(schema, this.context.useDescribe, {
1246
+ dateTimeValidation: this.context.dateTimeValidation,
1247
+ patternCache: this.context.patternCache
1248
+ });
1495
1249
  break;
1496
1250
  case "number":
1497
1251
  validation = generateNumberValidation(schema, false, this.context.useDescribe);
@@ -1532,13 +1286,14 @@ var _PropertyGenerator = class _PropertyGenerator {
1532
1286
  case "loose":
1533
1287
  validation = "z.looseObject({})";
1534
1288
  break;
1535
- default:
1289
+ case "record":
1536
1290
  validation = "z.record(z.string(), z.unknown())";
1537
1291
  break;
1538
1292
  }
1539
1293
  validation = addDescription(validation, schema.description, this.context.useDescribe);
1540
1294
  }
1541
1295
  break;
1296
+ case void 0:
1542
1297
  default:
1543
1298
  validation = "z.unknown()";
1544
1299
  validation = addDescription(validation, schema.description, this.context.useDescribe);
@@ -1597,194 +1352,71 @@ _PropertyGenerator.INCLUSION_RULES = {
1597
1352
  };
1598
1353
  var PropertyGenerator = _PropertyGenerator;
1599
1354
 
1600
- // src/utils/operation-filters.ts
1601
- import { minimatch as minimatch2 } from "minimatch";
1602
- function createFilterStatistics() {
1603
- return {
1604
- totalOperations: 0,
1605
- includedOperations: 0,
1606
- filteredByTags: 0,
1607
- filteredByPaths: 0,
1608
- filteredByMethods: 0,
1609
- filteredByOperationIds: 0,
1610
- filteredByDeprecated: 0
1611
- };
1612
- }
1613
- function matchesAnyPattern(value, patterns) {
1614
- if (!patterns || patterns.length === 0) {
1615
- return false;
1616
- }
1617
- if (!value) {
1618
- return false;
1355
+ // src/openapi-generator.ts
1356
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
1357
+ import { dirname, normalize, relative } from "path";
1358
+ import {
1359
+ analyzeSchemaUsage,
1360
+ ConfigurationError,
1361
+ createFilterStatistics,
1362
+ detectCircularReferences,
1363
+ expandTransitiveReferences,
1364
+ extractSchemaRefs,
1365
+ formatFilterStatistics,
1366
+ getOperationName,
1367
+ LRUCache as LRUCache2,
1368
+ loadOpenAPISpec,
1369
+ mergeParameters,
1370
+ resolveRefName as resolveRefName2,
1371
+ SchemaGenerationError,
1372
+ SpecValidationError,
1373
+ shouldIncludeOperation,
1374
+ stripPathPrefix,
1375
+ stripPrefix as stripPrefix2,
1376
+ toCamelCase as toCamelCase3,
1377
+ toPascalCase as toPascalCase3,
1378
+ validateFilters
1379
+ } from "@cerios/openapi-core";
1380
+ import { TypeScriptGenerator } from "@cerios/openapi-to-typescript";
1381
+ import { minimatch } from "minimatch";
1382
+
1383
+ // src/generators/enum-generator.ts
1384
+ import { toCamelCase as toCamelCase2, toPascalCase as toPascalCase2 } from "@cerios/openapi-core";
1385
+ function generateEnum(name, values, options) {
1386
+ const schemaName = `${toCamelCase2(name, options)}Schema`;
1387
+ const typeName = toPascalCase2(name);
1388
+ const allBooleans = values.every((v) => typeof v === "boolean");
1389
+ if (allBooleans) {
1390
+ const schemaCode2 = `export const ${schemaName} = z.boolean();`;
1391
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
1392
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
1619
1393
  }
1620
- return patterns.some((pattern) => minimatch2(value, pattern));
1621
- }
1622
- function containsAny(arr, values) {
1623
- if (!values || values.length === 0) {
1624
- return false;
1394
+ const allStrings = values.every((v) => typeof v === "string");
1395
+ if (allStrings) {
1396
+ const enumValues = values.map((v) => `"${v}"`).join(", ");
1397
+ const schemaCode2 = `export const ${schemaName} = z.enum([${enumValues}]);`;
1398
+ const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
1399
+ return { schemaCode: schemaCode2, typeCode: typeCode2 };
1625
1400
  }
1626
- if (!arr || arr.length === 0) {
1627
- return false;
1628
- }
1629
- return values.some((value) => arr.includes(value));
1630
- }
1631
- function shouldIncludeOperation(operation, path, method, filters, stats) {
1632
- if (!filters) {
1633
- return true;
1634
- }
1635
- const methodLower = method.toLowerCase();
1636
- const operationId = operation == null ? void 0 : operation.operationId;
1637
- const tags = (operation == null ? void 0 : operation.tags) || [];
1638
- const deprecated = (operation == null ? void 0 : operation.deprecated) === true;
1639
- if (filters.includeTags && filters.includeTags.length > 0) {
1640
- if (!containsAny(tags, filters.includeTags)) {
1641
- if (stats) stats.filteredByTags++;
1642
- return false;
1643
- }
1644
- }
1645
- if (filters.includePaths && filters.includePaths.length > 0) {
1646
- if (!matchesAnyPattern(path, filters.includePaths)) {
1647
- if (stats) stats.filteredByPaths++;
1648
- return false;
1649
- }
1650
- }
1651
- if (filters.includeMethods && filters.includeMethods.length > 0) {
1652
- const methodsLower = filters.includeMethods.map((m) => m.toLowerCase());
1653
- if (!methodsLower.includes(methodLower)) {
1654
- if (stats) stats.filteredByMethods++;
1655
- return false;
1656
- }
1657
- }
1658
- if (filters.includeOperationIds && filters.includeOperationIds.length > 0) {
1659
- if (!matchesAnyPattern(operationId, filters.includeOperationIds)) {
1660
- if (stats) stats.filteredByOperationIds++;
1661
- return false;
1662
- }
1663
- }
1664
- if (filters.excludeDeprecated === true && deprecated) {
1665
- if (stats) stats.filteredByDeprecated++;
1666
- return false;
1667
- }
1668
- if (filters.excludeTags && filters.excludeTags.length > 0) {
1669
- if (containsAny(tags, filters.excludeTags)) {
1670
- if (stats) stats.filteredByTags++;
1671
- return false;
1672
- }
1673
- }
1674
- if (filters.excludePaths && filters.excludePaths.length > 0) {
1675
- if (matchesAnyPattern(path, filters.excludePaths)) {
1676
- if (stats) stats.filteredByPaths++;
1677
- return false;
1678
- }
1679
- }
1680
- if (filters.excludeMethods && filters.excludeMethods.length > 0) {
1681
- const methodsLower = filters.excludeMethods.map((m) => m.toLowerCase());
1682
- if (methodsLower.includes(methodLower)) {
1683
- if (stats) stats.filteredByMethods++;
1684
- return false;
1685
- }
1686
- }
1687
- if (filters.excludeOperationIds && filters.excludeOperationIds.length > 0) {
1688
- if (matchesAnyPattern(operationId, filters.excludeOperationIds)) {
1689
- if (stats) stats.filteredByOperationIds++;
1690
- return false;
1691
- }
1692
- }
1693
- return true;
1694
- }
1695
- function validateFilters(stats, filters) {
1696
- if (!filters || stats.totalOperations === 0) {
1697
- return;
1698
- }
1699
- if (stats.includedOperations === 0) {
1700
- console.warn(
1701
- `\u26A0\uFE0F Warning: All ${stats.totalOperations} operations were filtered out. Check your operationFilters configuration.`
1702
- );
1703
- const filterBreakdown = [];
1704
- if (stats.filteredByTags > 0) filterBreakdown.push(`${stats.filteredByTags} by tags`);
1705
- if (stats.filteredByPaths > 0) filterBreakdown.push(`${stats.filteredByPaths} by paths`);
1706
- if (stats.filteredByMethods > 0) filterBreakdown.push(`${stats.filteredByMethods} by methods`);
1707
- if (stats.filteredByOperationIds > 0) filterBreakdown.push(`${stats.filteredByOperationIds} by operationIds`);
1708
- if (stats.filteredByDeprecated > 0) filterBreakdown.push(`${stats.filteredByDeprecated} by deprecated flag`);
1709
- if (filterBreakdown.length > 0) {
1710
- console.warn(` Filtered: ${filterBreakdown.join(", ")}`);
1401
+ const literalValues = values.map((v) => {
1402
+ if (typeof v === "string") {
1403
+ return `z.literal("${v}")`;
1711
1404
  }
1712
- }
1713
- }
1714
- function formatFilterStatistics(stats) {
1715
- if (stats.totalOperations === 0) {
1716
- return "";
1717
- }
1718
- const lines = [];
1719
- lines.push("Operation Filtering:");
1720
- lines.push(` Total operations: ${stats.totalOperations}`);
1721
- lines.push(` Included operations: ${stats.includedOperations}`);
1722
- const filteredCount = stats.filteredByTags + stats.filteredByPaths + stats.filteredByMethods + stats.filteredByOperationIds + stats.filteredByDeprecated;
1723
- if (filteredCount > 0) {
1724
- lines.push(` Filtered operations: ${filteredCount}`);
1725
- if (stats.filteredByTags > 0) lines.push(` - By tags: ${stats.filteredByTags}`);
1726
- if (stats.filteredByPaths > 0) lines.push(` - By paths: ${stats.filteredByPaths}`);
1727
- if (stats.filteredByMethods > 0) lines.push(` - By methods: ${stats.filteredByMethods}`);
1728
- if (stats.filteredByOperationIds > 0) lines.push(` - By operationIds: ${stats.filteredByOperationIds}`);
1729
- if (stats.filteredByDeprecated > 0) lines.push(` - By deprecated: ${stats.filteredByDeprecated}`);
1730
- }
1731
- return lines.join("\n");
1405
+ return `z.literal(${v})`;
1406
+ }).join(", ");
1407
+ const schemaCode = `export const ${schemaName} = z.union([${literalValues}]);`;
1408
+ const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
1409
+ return { schemaCode, typeCode };
1732
1410
  }
1733
1411
 
1734
- // src/utils/ref-resolver.ts
1735
- function resolveRef2(obj, spec, maxDepth = 10) {
1736
- var _a, _b, _c, _d;
1737
- if (!obj || typeof obj !== "object" || maxDepth <= 0) return obj;
1738
- if (!obj.$ref) return obj;
1739
- const ref = obj.$ref;
1740
- let resolved = null;
1741
- const paramMatch = ref.match(/^#\/components\/parameters\/(.+)$/);
1742
- const requestBodyMatch = ref.match(/^#\/components\/requestBodies\/(.+)$/);
1743
- const responseMatch = ref.match(/^#\/components\/responses\/(.+)$/);
1744
- const schemaMatch = ref.match(/^#\/components\/schemas\/(.+)$/);
1745
- if (paramMatch && ((_a = spec.components) == null ? void 0 : _a.parameters)) {
1746
- const name = paramMatch[1];
1747
- resolved = spec.components.parameters[name];
1748
- } else if (requestBodyMatch && ((_b = spec.components) == null ? void 0 : _b.requestBodies)) {
1749
- const name = requestBodyMatch[1];
1750
- resolved = spec.components.requestBodies[name];
1751
- } else if (responseMatch && ((_c = spec.components) == null ? void 0 : _c.responses)) {
1752
- const name = responseMatch[1];
1753
- resolved = spec.components.responses[name];
1754
- } else if (schemaMatch && ((_d = spec.components) == null ? void 0 : _d.schemas)) {
1755
- const name = schemaMatch[1];
1756
- resolved = spec.components.schemas[name];
1757
- }
1758
- if (resolved) {
1759
- if (resolved.$ref) {
1760
- return resolveRef2(resolved, spec, maxDepth - 1);
1761
- }
1762
- return resolved;
1763
- }
1764
- return obj;
1765
- }
1766
- function resolveParameterRef(param, spec) {
1767
- return resolveRef2(param, spec);
1412
+ // src/openapi-generator.ts
1413
+ var HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"];
1414
+ function isResolvedParameter(param) {
1415
+ return typeof param === "object" && param !== null && "name" in param && typeof param.name === "string" && "in" in param;
1768
1416
  }
1769
- function mergeParameters(pathParams, operationParams, spec) {
1770
- const resolvedPathParams = (pathParams || []).map((p) => resolveParameterRef(p, spec));
1771
- const resolvedOperationParams = (operationParams || []).map((p) => resolveParameterRef(p, spec));
1772
- const merged = [...resolvedPathParams];
1773
- for (const opParam of resolvedOperationParams) {
1774
- if (!opParam || typeof opParam !== "object") continue;
1775
- const existingIndex = merged.findIndex(
1776
- (p) => p && typeof p === "object" && p.name === opParam.name && p.in === opParam.in
1777
- );
1778
- if (existingIndex >= 0) {
1779
- merged[existingIndex] = opParam;
1780
- } else {
1781
- merged.push(opParam);
1782
- }
1783
- }
1784
- return merged;
1417
+ function isOpenAPIPathItem(value) {
1418
+ return typeof value === "object" && value !== null;
1785
1419
  }
1786
-
1787
- // src/openapi-generator.ts
1788
1420
  var OpenApiGenerator = class {
1789
1421
  constructor(options) {
1790
1422
  this.schemas = /* @__PURE__ */ new Map();
@@ -1793,93 +1425,48 @@ var OpenApiGenerator = class {
1793
1425
  this.schemaUsageMap = /* @__PURE__ */ new Map();
1794
1426
  this.needsZodImport = true;
1795
1427
  this.filterStats = createFilterStatistics();
1796
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1428
+ /** Track total allOf conflicts detected across all schemas */
1429
+ this.allOfConflictCount = 0;
1430
+ /** Track schemas involved in circular dependency chains */
1431
+ this.circularDependencies = /* @__PURE__ */ new Set();
1432
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1797
1433
  if (!options.input) {
1798
1434
  throw new ConfigurationError("Input path is required", { providedOptions: options });
1799
1435
  }
1436
+ this.separateSchemasMode = Boolean(options.outputZodSchemas);
1800
1437
  this.options = {
1801
1438
  mode: options.mode || "normal",
1802
1439
  input: options.input,
1803
- output: options.output,
1804
- includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
1805
- useDescribe: (_b = options.useDescribe) != null ? _b : false,
1806
- defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
1807
- emptyObjectBehavior: (_d = options.emptyObjectBehavior) != null ? _d : "loose",
1440
+ outputTypes: options.outputTypes,
1441
+ outputZodSchemas: options.outputZodSchemas,
1442
+ enumFormat: options.enumFormat,
1443
+ typeAssertionThreshold: (_a = options.typeAssertionThreshold) != null ? _a : 0,
1444
+ includeDescriptions: (_b = options.includeDescriptions) != null ? _b : true,
1445
+ useDescribe: (_c = options.useDescribe) != null ? _c : false,
1446
+ defaultNullable: (_d = options.defaultNullable) != null ? _d : false,
1447
+ emptyObjectBehavior: (_e = options.emptyObjectBehavior) != null ? _e : "loose",
1808
1448
  schemaType: options.schemaType || "all",
1809
1449
  prefix: options.prefix,
1810
1450
  suffix: options.suffix,
1811
1451
  stripSchemaPrefix: options.stripSchemaPrefix,
1812
1452
  stripPathPrefix: options.stripPathPrefix,
1813
- showStats: (_e = options.showStats) != null ? _e : true,
1453
+ useOperationId: (_f = options.useOperationId) != null ? _f : true,
1454
+ showStats: (_g = options.showStats) != null ? _g : true,
1814
1455
  request: options.request,
1815
1456
  response: options.response,
1816
1457
  operationFilters: options.operationFilters,
1817
1458
  ignoreHeaders: options.ignoreHeaders,
1818
- cacheSize: (_f = options.cacheSize) != null ? _f : 1e3,
1819
- batchSize: (_g = options.batchSize) != null ? _g : 10,
1459
+ cacheSize: (_h = options.cacheSize) != null ? _h : 1e3,
1460
+ batchSize: (_i = options.batchSize) != null ? _i : 10,
1820
1461
  customDateTimeFormatRegex: options.customDateTimeFormatRegex
1821
1462
  };
1822
- if (this.options.cacheSize) {
1823
- configurePatternCache(this.options.cacheSize);
1824
- }
1825
- if (this.options.customDateTimeFormatRegex) {
1826
- configureDateTimeFormat(this.options.customDateTimeFormatRegex);
1827
- }
1828
- try {
1829
- const fs = __require("fs");
1830
- if (!fs.existsSync(this.options.input)) {
1831
- throw new FileOperationError(`Input file not found: ${this.options.input}`, this.options.input);
1832
- }
1833
- } catch (error) {
1834
- if (error instanceof FileOperationError) {
1835
- throw error;
1836
- }
1837
- }
1838
- try {
1839
- const content = readFileSync(this.options.input, "utf-8");
1840
- try {
1841
- this.spec = parse(content);
1842
- } catch (yamlError) {
1843
- try {
1844
- this.spec = JSON.parse(content);
1845
- } catch {
1846
- if (yamlError instanceof Error) {
1847
- const errorMessage = [
1848
- `Failed to parse OpenAPI specification from: ${this.options.input}`,
1849
- "",
1850
- `Error: ${yamlError.message}`,
1851
- "",
1852
- "Please ensure:",
1853
- " - The file exists and is readable",
1854
- " - The file contains valid YAML or JSON syntax",
1855
- " - The file is a valid OpenAPI 3.x specification"
1856
- ].join("\n");
1857
- throw new SpecValidationError(errorMessage, {
1858
- filePath: this.options.input,
1859
- originalError: yamlError.message
1860
- });
1861
- }
1862
- throw yamlError;
1863
- }
1864
- }
1865
- } catch (error) {
1866
- if (error instanceof SpecValidationError) {
1867
- throw error;
1868
- }
1869
- if (error instanceof Error) {
1870
- const errorMessage = [
1871
- `Failed to read OpenAPI specification from: ${this.options.input}`,
1872
- "",
1873
- `Error: ${error.message}`
1874
- ].join("\n");
1875
- throw new SpecValidationError(errorMessage, { filePath: this.options.input, originalError: error.message });
1876
- }
1877
- throw error;
1878
- }
1463
+ this.patternCache = new LRUCache2((_j = this.options.cacheSize) != null ? _j : 1e3);
1464
+ this.dateTimeValidation = buildDateTimeValidation(this.options.customDateTimeFormatRegex);
1465
+ this.spec = loadOpenAPISpec(this.options.input);
1879
1466
  this.validateSpec();
1880
1467
  this.requestOptions = this.resolveOptionsForContext("request");
1881
1468
  this.responseOptions = this.resolveOptionsForContext("response");
1882
- this.analyzeSchemaUsage();
1469
+ this.initializeSchemaUsage();
1883
1470
  this.propertyGenerator = new PropertyGenerator({
1884
1471
  spec: this.spec,
1885
1472
  schemaDependencies: this.schemaDependencies,
@@ -1887,17 +1474,21 @@ var OpenApiGenerator = class {
1887
1474
  mode: this.requestOptions.mode,
1888
1475
  includeDescriptions: this.requestOptions.includeDescriptions,
1889
1476
  useDescribe: this.requestOptions.useDescribe,
1890
- defaultNullable: (_h = this.options.defaultNullable) != null ? _h : false,
1891
- emptyObjectBehavior: (_i = this.options.emptyObjectBehavior) != null ? _i : "loose",
1477
+ defaultNullable: (_k = this.options.defaultNullable) != null ? _k : false,
1478
+ emptyObjectBehavior: (_l = this.options.emptyObjectBehavior) != null ? _l : "loose",
1892
1479
  namingOptions: {
1893
1480
  prefix: this.options.prefix,
1894
1481
  suffix: this.options.suffix
1895
1482
  },
1896
- stripSchemaPrefix: this.options.stripSchemaPrefix
1483
+ stripSchemaPrefix: this.options.stripSchemaPrefix,
1484
+ dateTimeValidation: this.dateTimeValidation,
1485
+ patternCache: this.patternCache,
1486
+ separateTypesFile: this.separateSchemasMode
1897
1487
  });
1898
1488
  }
1899
1489
  /**
1900
1490
  * Generate schemas as a string (without writing to file)
1491
+ * When separateSchemasMode is active, generates Zod schemas with explicit type annotations
1901
1492
  * @returns The generated TypeScript code as a string
1902
1493
  */
1903
1494
  generateString() {
@@ -1905,6 +1496,11 @@ var OpenApiGenerator = class {
1905
1496
  if (!((_a = this.spec.components) == null ? void 0 : _a.schemas)) {
1906
1497
  throw new SpecValidationError("No schemas found in OpenAPI spec", { filePath: this.options.input });
1907
1498
  }
1499
+ if (this.separateSchemasMode) {
1500
+ return this.generateSeparateSchemasString();
1501
+ }
1502
+ this.analyzeCircularDependencies();
1503
+ this.propertyGenerator.setCircularDependencies(this.circularDependencies);
1908
1504
  for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
1909
1505
  if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
1910
1506
  continue;
@@ -1930,10 +1526,10 @@ var OpenApiGenerator = class {
1930
1526
  const typeCode = this.types.get(name);
1931
1527
  if (schemaCode) {
1932
1528
  output.push(schemaCode);
1933
- const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
1934
- const typeName = toPascalCase(strippedName);
1529
+ const strippedName = stripPrefix2(name, this.options.stripSchemaPrefix);
1530
+ const typeName = toPascalCase3(strippedName);
1935
1531
  if (!schemaCode.includes(`export type ${typeName}`)) {
1936
- const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1532
+ const schemaName = `${toCamelCase3(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1937
1533
  output.push(`export type ${typeName} = z.infer<typeof ${schemaName}>;`);
1938
1534
  }
1939
1535
  output.push("");
@@ -1955,14 +1551,224 @@ var OpenApiGenerator = class {
1955
1551
  }
1956
1552
  }
1957
1553
  /**
1958
- * Generate the complete output file
1554
+ * Generate the complete output file(s)
1555
+ * When separateSchemasMode is active, generates both types and schemas files
1959
1556
  */
1960
1557
  generate() {
1961
- const output = this.generateString();
1962
- const normalizedOutput = normalize(this.options.output);
1963
- this.ensureDirectoryExists(normalizedOutput);
1964
- writeFileSync(normalizedOutput, output);
1965
- console.log(` \u2713 Generated ${normalizedOutput}`);
1558
+ if (this.separateSchemasMode) {
1559
+ const typesContent = this.generateTypesString();
1560
+ const schemasContent = this.generateString();
1561
+ const normalizedTypes = normalize(this.options.outputTypes);
1562
+ this.ensureDirectoryExists(normalizedTypes);
1563
+ writeFileSync(normalizedTypes, typesContent, "utf-8");
1564
+ console.log(` \u2713 Generated ${normalizedTypes}`);
1565
+ if (!this.options.outputZodSchemas) {
1566
+ throw new Error("Internal error: outputZodSchemas should be defined in separateSchemasMode");
1567
+ }
1568
+ const outputZodSchemas = this.options.outputZodSchemas;
1569
+ const normalizedSchemas = normalize(outputZodSchemas);
1570
+ this.ensureDirectoryExists(normalizedSchemas);
1571
+ writeFileSync(normalizedSchemas, schemasContent, "utf-8");
1572
+ console.log(` \u2713 Generated ${normalizedSchemas}`);
1573
+ } else {
1574
+ const output = this.generateString();
1575
+ const normalizedOutput = normalize(this.options.outputTypes);
1576
+ this.ensureDirectoryExists(normalizedOutput);
1577
+ writeFileSync(normalizedOutput, output);
1578
+ console.log(` \u2713 Generated ${normalizedOutput}`);
1579
+ }
1580
+ }
1581
+ /**
1582
+ * Generate Zod schemas with explicit type annotations (for outputZodSchemas mode)
1583
+ * Generates schemas like: `export const userSchema: z.ZodType<User> = z.object({...})`
1584
+ * @returns The generated Zod schemas TypeScript code
1585
+ */
1586
+ generateSeparateSchemasString() {
1587
+ var _a;
1588
+ const schemas = (_a = this.spec.components) == null ? void 0 : _a.schemas;
1589
+ if (!schemas) {
1590
+ return "";
1591
+ }
1592
+ if (!this.options.outputZodSchemas) {
1593
+ throw new Error("Internal error: outputZodSchemas should be defined in separateSchemasMode");
1594
+ }
1595
+ const outputZodSchemas = this.options.outputZodSchemas;
1596
+ this.analyzeCircularDependencies();
1597
+ this.propertyGenerator.setCircularDependencies(this.circularDependencies);
1598
+ for (const [name, schema] of Object.entries(schemas)) {
1599
+ if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
1600
+ continue;
1601
+ }
1602
+ this.generateComponentSchema(name, schema);
1603
+ }
1604
+ this.generateQueryParameterSchemas();
1605
+ this.generateHeaderParameterSchemas();
1606
+ validateFilters(this.filterStats, this.options.operationFilters);
1607
+ const orderedSchemaNames = this.topologicalSort();
1608
+ const output = ["// Auto-generated by @cerios/openapi-to-zod", "// Do not edit this file manually", ""];
1609
+ if (this.options.showStats === true) {
1610
+ output.push(...this.generateStats());
1611
+ output.push("");
1612
+ }
1613
+ output.push('import { z } from "zod";');
1614
+ const typesImportPath = this.calculateRelativeImportPath(outputZodSchemas, this.options.outputTypes);
1615
+ const typeNames = [];
1616
+ for (const name of orderedSchemaNames) {
1617
+ const strippedName = stripPrefix2(name, this.options.stripSchemaPrefix);
1618
+ const typeName = toPascalCase3(strippedName);
1619
+ typeNames.push(typeName);
1620
+ }
1621
+ if (typeNames.length > 0) {
1622
+ output.push(`import type { ${typeNames.join(", ")} } from "${typesImportPath}";`);
1623
+ }
1624
+ output.push("");
1625
+ output.push("// Schemas");
1626
+ for (const name of orderedSchemaNames) {
1627
+ const schemaCode = this.schemas.get(name);
1628
+ if (schemaCode) {
1629
+ const strippedName = stripPrefix2(name, this.options.stripSchemaPrefix);
1630
+ const typeName = toPascalCase3(strippedName);
1631
+ const schemaName = `${toCamelCase3(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1632
+ const schemaDefinition = this.isRecordObject(schemas[name]) ? schemas[name] : void 0;
1633
+ const transformedCode = this.addExplicitTypeAnnotation(schemaCode, schemaName, typeName, schemaDefinition);
1634
+ output.push(transformedCode);
1635
+ output.push("");
1636
+ }
1637
+ }
1638
+ return output.join("\n");
1639
+ }
1640
+ /**
1641
+ * Generate TypeScript types as a string (for outputZodSchemas mode)
1642
+ * Uses @cerios/openapi-to-typescript internally
1643
+ * @returns The generated TypeScript types code
1644
+ */
1645
+ generateTypesString() {
1646
+ var _a;
1647
+ const tsGenerator = new TypeScriptGenerator({
1648
+ input: this.options.input,
1649
+ outputTypes: this.options.outputTypes,
1650
+ includeDescriptions: this.options.includeDescriptions,
1651
+ defaultNullable: this.options.defaultNullable,
1652
+ prefix: this.options.prefix,
1653
+ suffix: this.options.suffix,
1654
+ stripSchemaPrefix: this.options.stripSchemaPrefix,
1655
+ stripPathPrefix: this.options.stripPathPrefix,
1656
+ operationFilters: this.options.operationFilters,
1657
+ showStats: this.options.showStats,
1658
+ enumFormat: (_a = this.options.enumFormat) != null ? _a : "const-object"
1659
+ });
1660
+ return tsGenerator.generateString();
1661
+ }
1662
+ /**
1663
+ * Add explicit type annotation to a schema declaration
1664
+ * Transforms: `export const userSchema = z.object({...})`
1665
+ * To: `export const userSchema: z.ZodType<User> = z.object({...})` (annotation)
1666
+ * Or: `export const userSchema = z.object({...}) as unknown as z.ZodType<User>` (double assertion)
1667
+ *
1668
+ * Uses double assertion via `unknown` when typeAssertionThreshold is set and schema complexity
1669
+ * meets or exceeds the threshold. This completely bypasses TypeScript's structural checking
1670
+ * to avoid "Type instantiation is excessively deep" errors on very large schemas.
1671
+ *
1672
+ * Also removes any `export type X = z.infer<...>` lines since types
1673
+ * are imported from the separate types file.
1674
+ */
1675
+ addExplicitTypeAnnotation(schemaCode, schemaName, typeName, schemaDefinition) {
1676
+ var _a;
1677
+ const code = schemaCode.replace(/\nexport type \w+ = z\.infer<typeof \w+>;/g, "");
1678
+ const jsdocMatch = code.match(/^(\/\*\*[\s\S]*?\*\/\n)?/);
1679
+ const jsdoc = (jsdocMatch == null ? void 0 : jsdocMatch[1]) || "";
1680
+ const codeWithoutJsdoc = code.slice(jsdoc.length);
1681
+ const threshold = (_a = this.options.typeAssertionThreshold) != null ? _a : 0;
1682
+ const useAssertion = threshold > 0 && schemaDefinition && this.calculateSchemaComplexity(schemaDefinition) >= threshold;
1683
+ const pattern = new RegExp(`export const ${schemaName} = `);
1684
+ if (pattern.test(codeWithoutJsdoc)) {
1685
+ let schemaBody = codeWithoutJsdoc.replace(pattern, "");
1686
+ if (useAssertion) {
1687
+ schemaBody = schemaBody.replace(/;$/, "");
1688
+ return `${jsdoc}export const ${schemaName} = ${schemaBody} as unknown as z.ZodType<${typeName}>;`;
1689
+ }
1690
+ return `${jsdoc}export const ${schemaName}: z.ZodType<${typeName}> = ${schemaBody}`;
1691
+ }
1692
+ return code;
1693
+ }
1694
+ /**
1695
+ * Type guard to check if a value is a Record<string, unknown>
1696
+ */
1697
+ isRecordObject(value) {
1698
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1699
+ }
1700
+ /**
1701
+ * Calculate the complexity of a schema for threshold comparison
1702
+ * Complexity formula: properties + (nested levels * 10) + (array/union members * 2)
1703
+ */
1704
+ calculateSchemaComplexity(schema, depth = 0) {
1705
+ if (!schema || typeof schema !== "object") {
1706
+ return 0;
1707
+ }
1708
+ let complexity = depth * 10;
1709
+ if (schema.$ref) {
1710
+ return complexity + 5;
1711
+ }
1712
+ const properties = schema.properties;
1713
+ if (this.isRecordObject(properties)) {
1714
+ const propCount = Object.keys(properties).length;
1715
+ complexity += propCount;
1716
+ for (const prop of Object.values(properties)) {
1717
+ if (this.isRecordObject(prop)) {
1718
+ complexity += this.calculateSchemaComplexity(prop, depth + 1);
1719
+ }
1720
+ }
1721
+ }
1722
+ const allOf = schema.allOf;
1723
+ if (Array.isArray(allOf)) {
1724
+ complexity += allOf.length * 2;
1725
+ for (const subSchema of allOf) {
1726
+ if (this.isRecordObject(subSchema)) {
1727
+ complexity += this.calculateSchemaComplexity(subSchema, depth + 1);
1728
+ }
1729
+ }
1730
+ }
1731
+ const oneOf = schema.oneOf;
1732
+ if (Array.isArray(oneOf)) {
1733
+ complexity += oneOf.length * 2;
1734
+ for (const subSchema of oneOf) {
1735
+ if (this.isRecordObject(subSchema)) {
1736
+ complexity += this.calculateSchemaComplexity(subSchema, depth + 1);
1737
+ }
1738
+ }
1739
+ }
1740
+ const anyOf = schema.anyOf;
1741
+ if (Array.isArray(anyOf)) {
1742
+ complexity += anyOf.length * 2;
1743
+ for (const subSchema of anyOf) {
1744
+ if (this.isRecordObject(subSchema)) {
1745
+ complexity += this.calculateSchemaComplexity(subSchema, depth + 1);
1746
+ }
1747
+ }
1748
+ }
1749
+ const items = schema.items;
1750
+ if (this.isRecordObject(items)) {
1751
+ complexity += 2;
1752
+ complexity += this.calculateSchemaComplexity(items, depth + 1);
1753
+ }
1754
+ const additionalProps = schema.additionalProperties;
1755
+ if (this.isRecordObject(additionalProps)) {
1756
+ complexity += 2;
1757
+ complexity += this.calculateSchemaComplexity(additionalProps, depth + 1);
1758
+ }
1759
+ return complexity;
1760
+ }
1761
+ /**
1762
+ * Calculate relative import path from schema file to types file
1763
+ */
1764
+ calculateRelativeImportPath(fromPath, toPath) {
1765
+ const fromDir = dirname(normalize(fromPath));
1766
+ const toFile = normalize(toPath).replace(/\.[tj]s$/, "");
1767
+ let relativePath = relative(fromDir, toFile);
1768
+ if (!relativePath.startsWith(".") && !relativePath.startsWith("..")) {
1769
+ relativePath = `./${relativePath}`;
1770
+ }
1771
+ return relativePath.replace(/\\/g, "/");
1966
1772
  }
1967
1773
  /**
1968
1774
  * Resolve options for a specific context (request or response)
@@ -1978,191 +1784,84 @@ var OpenApiGenerator = class {
1978
1784
  };
1979
1785
  }
1980
1786
  /**
1981
- * Analyze schema usage across the OpenAPI spec to determine if schemas
1982
- * are used in request, response, or both contexts
1787
+ * Initialize schema usage map using core utilities with operation filtering
1788
+ * This is a wrapper around core's analyzeSchemaUsage that adds operation filtering
1983
1789
  */
1984
- analyzeSchemaUsage() {
1985
- var _a, _b;
1986
- const requestSchemas = /* @__PURE__ */ new Set();
1987
- const responseSchemas = /* @__PURE__ */ new Set();
1988
- if (this.spec.paths) {
1790
+ initializeSchemaUsage() {
1791
+ var _a;
1792
+ if (this.options.operationFilters && this.spec.paths) {
1793
+ const requestSchemas = /* @__PURE__ */ new Set();
1794
+ const responseSchemas = /* @__PURE__ */ new Set();
1989
1795
  for (const [path, pathItem] of Object.entries(this.spec.paths)) {
1990
- const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
1991
- for (const method of methods) {
1796
+ if (!isOpenAPIPathItem(pathItem)) continue;
1797
+ for (const method of HTTP_METHODS) {
1992
1798
  const operation = pathItem[method];
1993
- if (typeof operation !== "object" || !operation) continue;
1799
+ if (!operation) continue;
1994
1800
  this.filterStats.totalOperations++;
1995
1801
  if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters, this.filterStats)) {
1996
1802
  continue;
1997
1803
  }
1998
1804
  this.filterStats.includedOperations++;
1999
- if ("requestBody" in operation && operation.requestBody && typeof operation.requestBody === "object" && "content" in operation.requestBody && operation.requestBody.content) {
2000
- for (const mediaType of Object.values(operation.requestBody.content)) {
2001
- if (mediaType && typeof mediaType === "object" && "schema" in mediaType && mediaType.schema) {
2002
- this.extractSchemaRefs(mediaType.schema, requestSchemas);
1805
+ if (operation.requestBody && typeof operation.requestBody === "object") {
1806
+ const reqBody = operation.requestBody;
1807
+ if (reqBody.content && typeof reqBody.content === "object") {
1808
+ for (const mediaType of Object.values(reqBody.content)) {
1809
+ if (mediaType && typeof mediaType === "object" && "schema" in mediaType && mediaType.schema) {
1810
+ extractSchemaRefs(mediaType.schema, requestSchemas);
1811
+ }
2003
1812
  }
2004
1813
  }
2005
1814
  }
2006
- if ("responses" in operation && operation.responses && typeof operation.responses === "object") {
1815
+ if (operation.responses && typeof operation.responses === "object") {
2007
1816
  for (const response of Object.values(operation.responses)) {
2008
1817
  if (response && typeof response === "object" && "content" in response && response.content && typeof response.content === "object") {
2009
1818
  for (const mediaType of Object.values(response.content)) {
2010
1819
  if (mediaType && typeof mediaType === "object" && "schema" in mediaType && mediaType.schema) {
2011
- this.extractSchemaRefs(mediaType.schema, responseSchemas);
1820
+ extractSchemaRefs(mediaType.schema, responseSchemas);
2012
1821
  }
2013
1822
  }
2014
1823
  }
2015
1824
  }
2016
1825
  }
2017
- if ("parameters" in operation && Array.isArray(operation.parameters)) {
1826
+ if (operation.parameters && Array.isArray(operation.parameters)) {
2018
1827
  for (const param of operation.parameters) {
2019
- if (param && typeof param === "object" && "schema" in param && param.schema) {
2020
- this.extractSchemaRefs(param.schema, requestSchemas);
1828
+ if (isResolvedParameter(param) && param.schema) {
1829
+ extractSchemaRefs(param.schema, requestSchemas);
2021
1830
  }
2022
1831
  }
2023
1832
  }
2024
1833
  }
2025
1834
  }
2026
- this.expandTransitiveReferences(requestSchemas);
2027
- this.expandTransitiveReferences(responseSchemas);
2028
- }
2029
- if (!this.spec.paths || requestSchemas.size === 0 && responseSchemas.size === 0) {
2030
- for (const [name, schema] of Object.entries(((_a = this.spec.components) == null ? void 0 : _a.schemas) || {})) {
2031
- const hasReadOnly = this.hasReadOnlyProperties(schema);
2032
- const hasWriteOnly = this.hasWriteOnlyProperties(schema);
2033
- if (hasWriteOnly && !hasReadOnly) {
2034
- requestSchemas.add(name);
2035
- } else if (hasReadOnly && !hasWriteOnly) {
2036
- responseSchemas.add(name);
1835
+ expandTransitiveReferences(requestSchemas, this.spec);
1836
+ expandTransitiveReferences(responseSchemas, this.spec);
1837
+ for (const [name] of Object.entries(((_a = this.spec.components) == null ? void 0 : _a.schemas) || {})) {
1838
+ if (requestSchemas.has(name) && responseSchemas.has(name)) {
1839
+ this.schemaUsageMap.set(name, "both");
1840
+ } else if (requestSchemas.has(name)) {
1841
+ this.schemaUsageMap.set(name, "request");
1842
+ } else if (responseSchemas.has(name)) {
1843
+ this.schemaUsageMap.set(name, "response");
2037
1844
  }
2038
1845
  }
2039
- }
2040
- for (const [name] of Object.entries(((_b = this.spec.components) == null ? void 0 : _b.schemas) || {})) {
2041
- if (requestSchemas.has(name) && responseSchemas.has(name)) {
1846
+ const circularSchemas = detectCircularReferences(this.spec);
1847
+ for (const name of circularSchemas) {
2042
1848
  this.schemaUsageMap.set(name, "both");
2043
- } else if (requestSchemas.has(name)) {
2044
- this.schemaUsageMap.set(name, "request");
2045
- } else if (responseSchemas.has(name)) {
2046
- this.schemaUsageMap.set(name, "response");
2047
- }
2048
- }
2049
- this.detectCircularReferences();
2050
- }
2051
- /**
2052
- * Expand a set of schemas to include all transitively referenced schemas
2053
- */
2054
- expandTransitiveReferences(schemas) {
2055
- var _a, _b;
2056
- const toProcess = Array.from(schemas);
2057
- const processed = /* @__PURE__ */ new Set();
2058
- while (toProcess.length > 0) {
2059
- const schemaName = toProcess.pop();
2060
- if (!schemaName || processed.has(schemaName)) continue;
2061
- processed.add(schemaName);
2062
- const schema = (_b = (_a = this.spec.components) == null ? void 0 : _a.schemas) == null ? void 0 : _b[schemaName];
2063
- if (schema) {
2064
- const refs = /* @__PURE__ */ new Set();
2065
- this.extractSchemaRefs(schema, refs);
2066
- for (const ref of refs) {
2067
- if (!schemas.has(ref)) {
2068
- schemas.add(ref);
2069
- toProcess.push(ref);
2070
- }
2071
- }
2072
- }
2073
- }
2074
- }
2075
- /**
2076
- * Extract schema names from $ref and nested structures
2077
- */
2078
- extractSchemaRefs(schema, refs) {
2079
- if (!schema) return;
2080
- if (schema.$ref) {
2081
- const refName = resolveRef(schema.$ref);
2082
- refs.add(refName);
2083
- }
2084
- if (schema.allOf) {
2085
- for (const subSchema of schema.allOf) {
2086
- this.extractSchemaRefs(subSchema, refs);
2087
- }
2088
- }
2089
- if (schema.oneOf) {
2090
- for (const subSchema of schema.oneOf) {
2091
- this.extractSchemaRefs(subSchema, refs);
2092
- }
2093
- }
2094
- if (schema.anyOf) {
2095
- for (const subSchema of schema.anyOf) {
2096
- this.extractSchemaRefs(subSchema, refs);
2097
- }
2098
- }
2099
- if (schema.items) {
2100
- this.extractSchemaRefs(schema.items, refs);
2101
- }
2102
- if (schema.properties) {
2103
- for (const prop of Object.values(schema.properties)) {
2104
- this.extractSchemaRefs(prop, refs);
2105
- }
2106
- }
2107
- }
2108
- /**
2109
- * Check if schema has readOnly properties
2110
- */
2111
- hasReadOnlyProperties(schema) {
2112
- if (schema.readOnly) return true;
2113
- if (schema.properties) {
2114
- for (const prop of Object.values(schema.properties)) {
2115
- if (this.hasReadOnlyProperties(prop)) return true;
2116
- }
2117
- }
2118
- return false;
2119
- }
2120
- /**
2121
- * Check if schema has writeOnly properties
2122
- */
2123
- hasWriteOnlyProperties(schema) {
2124
- if (schema.writeOnly) return true;
2125
- if (schema.properties) {
2126
- for (const prop of Object.values(schema.properties)) {
2127
- if (this.hasWriteOnlyProperties(prop)) return true;
2128
- }
2129
- }
2130
- return false;
2131
- }
2132
- /**
2133
- * Detect circular references and mark them as "both" context for safety
2134
- */
2135
- detectCircularReferences() {
2136
- var _a;
2137
- const visited = /* @__PURE__ */ new Set();
2138
- const recursionStack = /* @__PURE__ */ new Set();
2139
- const detectCycle = (name) => {
2140
- var _a2, _b;
2141
- if (recursionStack.has(name)) {
2142
- return true;
2143
1849
  }
2144
- if (visited.has(name)) {
2145
- return false;
2146
- }
2147
- visited.add(name);
2148
- recursionStack.add(name);
2149
- const schema = (_b = (_a2 = this.spec.components) == null ? void 0 : _a2.schemas) == null ? void 0 : _b[name];
2150
- if (schema) {
2151
- const refs = /* @__PURE__ */ new Set();
2152
- this.extractSchemaRefs(schema, refs);
2153
- for (const ref of refs) {
2154
- if (detectCycle(ref)) {
2155
- this.schemaUsageMap.set(name, "both");
2156
- recursionStack.delete(name);
2157
- return true;
1850
+ } else {
1851
+ const analysis = analyzeSchemaUsage(this.spec);
1852
+ this.schemaUsageMap = analysis.usageMap;
1853
+ if (this.spec.paths) {
1854
+ for (const pathItem of Object.values(this.spec.paths)) {
1855
+ if (!isOpenAPIPathItem(pathItem)) continue;
1856
+ for (const method of HTTP_METHODS) {
1857
+ const operation = pathItem[method];
1858
+ if (typeof operation === "object" && operation) {
1859
+ this.filterStats.totalOperations++;
1860
+ this.filterStats.includedOperations++;
1861
+ }
2158
1862
  }
2159
1863
  }
2160
1864
  }
2161
- recursionStack.delete(name);
2162
- return false;
2163
- };
2164
- for (const name of Object.keys(((_a = this.spec.components) == null ? void 0 : _a.schemas) || {})) {
2165
- detectCycle(name);
2166
1865
  }
2167
1866
  }
2168
1867
  /**
@@ -2195,7 +1894,7 @@ var OpenApiGenerator = class {
2195
1894
  */
2196
1895
  validateSchemaRefs(schemaName, schema, allSchemas, path = "") {
2197
1896
  if (schema.$ref) {
2198
- const refName = resolveRef(schema.$ref);
1897
+ const refName = resolveRefName2(schema.$ref);
2199
1898
  if (!allSchemas.includes(refName)) {
2200
1899
  throw new SpecValidationError(
2201
1900
  `Invalid reference${path ? ` at '${path}'` : ""}: '${schema.$ref}' points to non-existent schema '${refName}'`,
@@ -2244,7 +1943,7 @@ var OpenApiGenerator = class {
2244
1943
  const resolvedOptions = context === "response" ? this.responseOptions : this.requestOptions;
2245
1944
  if (schema.enum) {
2246
1945
  const jsdoc2 = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
2247
- const strippedName2 = stripPrefix(name, this.options.stripSchemaPrefix);
1946
+ const strippedName2 = stripPrefix2(name, this.options.stripSchemaPrefix);
2248
1947
  const { schemaCode, typeCode } = generateEnum(strippedName2, schema.enum, {
2249
1948
  prefix: this.options.prefix,
2250
1949
  suffix: this.options.suffix
@@ -2254,11 +1953,11 @@ ${typeCode}`;
2254
1953
  this.schemas.set(name, enumSchemaCode);
2255
1954
  return;
2256
1955
  }
2257
- const strippedName = stripPrefix(name, this.options.stripSchemaPrefix);
2258
- const schemaName = `${toCamelCase(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
2259
- const jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
1956
+ const strippedName = stripPrefix2(name, this.options.stripSchemaPrefix);
1957
+ const schemaName = `${toCamelCase3(strippedName, { prefix: this.options.prefix, suffix: this.options.suffix })}Schema`;
1958
+ let jsdoc = generateJSDoc(schema, name, { includeDescriptions: resolvedOptions.includeDescriptions });
2260
1959
  if (schema.allOf && schema.allOf.length === 1 && schema.allOf[0].$ref) {
2261
- const refName = resolveRef(schema.allOf[0].$ref);
1960
+ const refName = resolveRefName2(schema.allOf[0].$ref);
2262
1961
  (_a = this.schemaDependencies.get(name)) == null ? void 0 : _a.add(refName);
2263
1962
  }
2264
1963
  this.propertyGenerator = new PropertyGenerator({
@@ -2274,9 +1973,28 @@ ${typeCode}`;
2274
1973
  prefix: this.options.prefix,
2275
1974
  suffix: this.options.suffix
2276
1975
  },
2277
- stripSchemaPrefix: this.options.stripSchemaPrefix
1976
+ stripSchemaPrefix: this.options.stripSchemaPrefix,
1977
+ dateTimeValidation: this.dateTimeValidation,
1978
+ patternCache: this.patternCache,
1979
+ separateTypesFile: this.separateSchemasMode
2278
1980
  });
1981
+ this.propertyGenerator.setCircularDependencies(this.circularDependencies);
1982
+ this.propertyGenerator.clearAllOfConflicts();
2279
1983
  const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, true);
1984
+ const allOfConflicts = this.propertyGenerator.getAllOfConflicts();
1985
+ if (allOfConflicts.length > 0) {
1986
+ this.allOfConflictCount += allOfConflicts.length;
1987
+ const conflictWarning = this.generateConflictJSDoc(allOfConflicts);
1988
+ if (jsdoc) {
1989
+ jsdoc = jsdoc.replace(/ \*\/\n$/, `
1990
+ ${conflictWarning} */
1991
+ `);
1992
+ } else {
1993
+ jsdoc = `/**
1994
+ ${conflictWarning} */
1995
+ `;
1996
+ }
1997
+ }
2280
1998
  const zodSchemaCode = `${jsdoc}export const ${schemaName} = ${zodSchema};`;
2281
1999
  if (zodSchema.includes("z.discriminatedUnion(")) {
2282
2000
  const match = zodSchema.match(/z\.discriminatedUnion\([^,]+,\s*\[([^\]]+)\]/);
@@ -2302,9 +2020,8 @@ ${typeCode}`;
2302
2020
  return;
2303
2021
  }
2304
2022
  for (const [path, pathItem] of Object.entries(this.spec.paths)) {
2305
- if (!pathItem || typeof pathItem !== "object") continue;
2306
- const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
2307
- for (const method of methods) {
2023
+ if (!isOpenAPIPathItem(pathItem)) continue;
2024
+ for (const method of HTTP_METHODS) {
2308
2025
  const operation = pathItem[method];
2309
2026
  if (!operation) continue;
2310
2027
  if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
@@ -2312,18 +2029,18 @@ ${typeCode}`;
2312
2029
  }
2313
2030
  const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
2314
2031
  const queryParams = allParams.filter(
2315
- (param) => param && typeof param === "object" && param.in === "query"
2032
+ (param) => isResolvedParameter(param) && param.in === "query"
2316
2033
  );
2317
2034
  if (queryParams.length === 0) {
2318
2035
  continue;
2319
2036
  }
2320
- let pascalOperationId;
2321
- if (operation.operationId) {
2322
- pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
2323
- } else {
2324
- const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
2325
- pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
2326
- }
2037
+ const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
2038
+ const pascalOperationId = getOperationName(
2039
+ operation.operationId,
2040
+ method,
2041
+ strippedPath,
2042
+ this.options.useOperationId
2043
+ );
2327
2044
  const schemaName = `${pascalOperationId}QueryParams`;
2328
2045
  if (!this.schemaDependencies.has(schemaName)) {
2329
2046
  this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
@@ -2353,7 +2070,7 @@ ${typeCode}`;
2353
2070
  required.push(paramName);
2354
2071
  }
2355
2072
  if (paramSchema.$ref) {
2356
- const refName = resolveRef(paramSchema.$ref);
2073
+ const refName = resolveRefName2(paramSchema.$ref);
2357
2074
  (_a = this.schemaDependencies.get(schemaName)) == null ? void 0 : _a.add(refName);
2358
2075
  }
2359
2076
  }
@@ -2368,9 +2085,7 @@ ${typeCode}`;
2368
2085
  ${propsCode}
2369
2086
  })`;
2370
2087
  const operationName = pascalOperationId;
2371
- const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
2372
- const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
2373
- const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}QueryParamsSchema`;
2088
+ const camelCaseSchemaName = `${toCamelCase3(operationName, { prefix: this.options.prefix, suffix: this.options.suffix })}QueryParamsSchema`;
2374
2089
  const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
2375
2090
  const jsdoc = `/**
2376
2091
  * Query parameters for ${jsdocOperationName}
@@ -2382,35 +2097,6 @@ ${propsCode}
2382
2097
  }
2383
2098
  }
2384
2099
  }
2385
- /**
2386
- * Generate a PascalCase method name from HTTP method and path
2387
- * Used as fallback when operationId is not available
2388
- * @internal
2389
- */
2390
- generateMethodNameFromPath(method, path) {
2391
- const segments = path.split("/").filter(Boolean).map((segment) => {
2392
- if (segment.startsWith("{") && segment.endsWith("}")) {
2393
- const paramName = segment.slice(1, -1);
2394
- return `By${this.capitalizeSegment(paramName)}`;
2395
- }
2396
- return this.capitalizeSegment(segment);
2397
- }).join("");
2398
- const capitalizedMethod = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
2399
- return `${capitalizedMethod}${segments}`;
2400
- }
2401
- /**
2402
- * Capitalizes a path segment, handling special characters like dashes, underscores, and dots
2403
- * @internal
2404
- */
2405
- capitalizeSegment(str) {
2406
- if (str.includes("-") || str.includes("_") || str.includes(".")) {
2407
- return str.split(/[-_.]/).map((part) => {
2408
- if (!part) return "";
2409
- return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
2410
- }).join("");
2411
- }
2412
- return str.charAt(0).toUpperCase() + str.slice(1);
2413
- }
2414
2100
  /**
2415
2101
  * Check if a header should be ignored based on filter patterns
2416
2102
  * @internal
@@ -2426,7 +2112,7 @@ ${propsCode}
2426
2112
  const headerLower = headerName.toLowerCase();
2427
2113
  return ignorePatterns.some((pattern) => {
2428
2114
  const patternLower = pattern.toLowerCase();
2429
- return minimatch3(headerLower, patternLower);
2115
+ return minimatch(headerLower, patternLower);
2430
2116
  });
2431
2117
  }
2432
2118
  /**
@@ -2439,9 +2125,8 @@ ${propsCode}
2439
2125
  return;
2440
2126
  }
2441
2127
  for (const [path, pathItem] of Object.entries(this.spec.paths)) {
2442
- if (!pathItem || typeof pathItem !== "object") continue;
2443
- const methods = ["get", "post", "put", "patch", "delete", "head", "options"];
2444
- for (const method of methods) {
2128
+ if (!isOpenAPIPathItem(pathItem)) continue;
2129
+ for (const method of HTTP_METHODS) {
2445
2130
  const operation = pathItem[method];
2446
2131
  if (!operation) continue;
2447
2132
  if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
@@ -2449,18 +2134,18 @@ ${propsCode}
2449
2134
  }
2450
2135
  const allParams = mergeParameters(pathItem.parameters, operation.parameters, this.spec);
2451
2136
  const headerParams = allParams.filter(
2452
- (param) => param && typeof param === "object" && param.in === "header" && !this.shouldIgnoreHeader(param.name)
2137
+ (param) => isResolvedParameter(param) && param.in === "header" && !this.shouldIgnoreHeader(param.name)
2453
2138
  );
2454
2139
  if (headerParams.length === 0) {
2455
2140
  continue;
2456
2141
  }
2457
- let pascalOperationId;
2458
- if (operation.operationId) {
2459
- pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
2460
- } else {
2461
- const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
2462
- pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
2463
- }
2142
+ const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
2143
+ const pascalOperationId = getOperationName(
2144
+ operation.operationId,
2145
+ method,
2146
+ strippedPath,
2147
+ this.options.useOperationId
2148
+ );
2464
2149
  const schemaName = `${pascalOperationId}HeaderParams`;
2465
2150
  if (!this.schemaDependencies.has(schemaName)) {
2466
2151
  this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
@@ -2479,7 +2164,7 @@ ${propsCode}
2479
2164
  zodType = `${zodType}.optional()`;
2480
2165
  properties[paramName] = zodType;
2481
2166
  if (paramSchema.$ref) {
2482
- const refName = resolveRef(paramSchema.$ref);
2167
+ const refName = resolveRefName2(paramSchema.$ref);
2483
2168
  (_a = this.schemaDependencies.get(schemaName)) == null ? void 0 : _a.add(refName);
2484
2169
  }
2485
2170
  }
@@ -2494,9 +2179,7 @@ ${propsCode}
2494
2179
  ${propsCode}
2495
2180
  })`;
2496
2181
  const operationName = pascalOperationId;
2497
- const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
2498
- const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
2499
- const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}HeaderParamsSchema`;
2182
+ const camelCaseSchemaName = `${toCamelCase3(operationName, { prefix: this.options.prefix, suffix: this.options.suffix })}HeaderParamsSchema`;
2500
2183
  const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
2501
2184
  const jsdoc = `/**
2502
2185
  * Header parameters for ${jsdocOperationName}
@@ -2513,9 +2196,9 @@ ${propsCode}
2513
2196
  */
2514
2197
  generateQueryParamType(schema, param) {
2515
2198
  if (schema.$ref) {
2516
- const refName = resolveRef(schema.$ref);
2517
- const strippedRefName = stripPrefix(refName, this.options.stripSchemaPrefix);
2518
- const schemaName = toCamelCase(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
2199
+ const refName = resolveRefName2(schema.$ref);
2200
+ const strippedRefName = stripPrefix2(refName, this.options.stripSchemaPrefix);
2201
+ const schemaName = toCamelCase3(strippedRefName, { prefix: this.options.prefix, suffix: this.options.suffix });
2519
2202
  return `${schemaName}Schema`;
2520
2203
  }
2521
2204
  if (schema.enum) {
@@ -2532,7 +2215,7 @@ ${propsCode}
2532
2215
  if (typeof v === "string") {
2533
2216
  return `z.literal("${v}")`;
2534
2217
  }
2535
- return `z.literal(${v})`;
2218
+ return `z.literal(${String(v)})`;
2536
2219
  }).join(", ");
2537
2220
  return `z.union([${literalValues}])`;
2538
2221
  }
@@ -2612,17 +2295,23 @@ ${propsCode}
2612
2295
  return;
2613
2296
  }
2614
2297
  const deps = this.schemaDependencies.get(name);
2298
+ let dependsOnCircular = false;
2615
2299
  if (deps && deps.size > 0) {
2616
2300
  for (const dep of deps) {
2617
2301
  if (this.schemas.has(dep) || this.types.has(dep)) {
2618
2302
  visit(dep);
2303
+ if (circularDeps.has(dep)) {
2304
+ dependsOnCircular = true;
2305
+ }
2619
2306
  }
2620
2307
  }
2621
2308
  }
2622
2309
  visiting.delete(name);
2623
2310
  visited.add(name);
2624
- if (!circularDeps.has(name)) {
2311
+ if (!circularDeps.has(name) && !dependsOnCircular) {
2625
2312
  sorted.push(name);
2313
+ } else if (dependsOnCircular && !circularDeps.has(name)) {
2314
+ circularDeps.add(name);
2626
2315
  }
2627
2316
  };
2628
2317
  const allNames = /* @__PURE__ */ new Set([...this.schemas.keys(), ...this.types.keys()]);
@@ -2630,9 +2319,8 @@ ${propsCode}
2630
2319
  visit(name);
2631
2320
  }
2632
2321
  for (const name of circularDeps) {
2633
- if (!visited.has(name)) {
2322
+ if (!sorted.includes(name)) {
2634
2323
  sorted.push(name);
2635
- visited.add(name);
2636
2324
  }
2637
2325
  }
2638
2326
  return [...sorted, ...aliases];
@@ -2659,7 +2347,8 @@ ${propsCode}
2659
2347
  `// Total schemas: ${stats.totalSchemas}`,
2660
2348
  `// Circular references: ${stats.withCircularRefs}`,
2661
2349
  `// Discriminated unions: ${stats.withDiscriminators}`,
2662
- `// With constraints: ${stats.withConstraints}`
2350
+ `// With constraints: ${stats.withConstraints}`,
2351
+ `// AllOf conflicts: ${this.allOfConflictCount}`
2663
2352
  ];
2664
2353
  if (this.options.operationFilters && this.filterStats.totalOperations > 0) {
2665
2354
  output.push("//");
@@ -2671,6 +2360,106 @@ ${propsCode}
2671
2360
  output.push(`// Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`);
2672
2361
  return output;
2673
2362
  }
2363
+ /**
2364
+ * Pre-analyze schemas to detect circular dependencies before code generation.
2365
+ * This allows the property generator to use z.lazy() for forward references.
2366
+ */
2367
+ analyzeCircularDependencies() {
2368
+ var _a;
2369
+ if (!((_a = this.spec.components) == null ? void 0 : _a.schemas)) return;
2370
+ const dependencies = /* @__PURE__ */ new Map();
2371
+ const collectDependencies = (name, schema, visited2 = /* @__PURE__ */ new Set()) => {
2372
+ if (visited2.has(name)) return /* @__PURE__ */ new Set();
2373
+ visited2.add(name);
2374
+ const deps = /* @__PURE__ */ new Set();
2375
+ if (schema.$ref) {
2376
+ const refName = resolveRefName2(schema.$ref);
2377
+ deps.add(refName);
2378
+ }
2379
+ if (schema.allOf) {
2380
+ for (const item of schema.allOf) {
2381
+ const itemDeps = collectDependencies(`${name}_allOf`, item, new Set(visited2));
2382
+ for (const dep of itemDeps) deps.add(dep);
2383
+ }
2384
+ }
2385
+ if (schema.oneOf) {
2386
+ for (const item of schema.oneOf) {
2387
+ const itemDeps = collectDependencies(`${name}_oneOf`, item, new Set(visited2));
2388
+ for (const dep of itemDeps) deps.add(dep);
2389
+ }
2390
+ }
2391
+ if (schema.anyOf) {
2392
+ for (const item of schema.anyOf) {
2393
+ const itemDeps = collectDependencies(`${name}_anyOf`, item, new Set(visited2));
2394
+ for (const dep of itemDeps) deps.add(dep);
2395
+ }
2396
+ }
2397
+ if (schema.properties) {
2398
+ for (const propSchema of Object.values(schema.properties)) {
2399
+ const propDeps = collectDependencies(`${name}_prop`, propSchema, new Set(visited2));
2400
+ for (const dep of propDeps) deps.add(dep);
2401
+ }
2402
+ }
2403
+ if (schema.items) {
2404
+ const itemDeps = collectDependencies(`${name}_items`, schema.items, new Set(visited2));
2405
+ for (const dep of itemDeps) deps.add(dep);
2406
+ }
2407
+ if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
2408
+ const addDeps = collectDependencies(`${name}_additional`, schema.additionalProperties, new Set(visited2));
2409
+ for (const dep of addDeps) deps.add(dep);
2410
+ }
2411
+ return deps;
2412
+ };
2413
+ for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
2414
+ if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
2415
+ continue;
2416
+ }
2417
+ dependencies.set(name, collectDependencies(name, schema));
2418
+ }
2419
+ const visited = /* @__PURE__ */ new Set();
2420
+ const visiting = /* @__PURE__ */ new Set();
2421
+ const detectCircular = (name, path = []) => {
2422
+ if (visited.has(name)) return;
2423
+ if (visiting.has(name)) {
2424
+ const cycleStart = path.indexOf(name);
2425
+ if (cycleStart >= 0) {
2426
+ for (let i = cycleStart; i < path.length; i++) {
2427
+ this.circularDependencies.add(path[i]);
2428
+ }
2429
+ }
2430
+ this.circularDependencies.add(name);
2431
+ return;
2432
+ }
2433
+ visiting.add(name);
2434
+ path.push(name);
2435
+ const deps = dependencies.get(name);
2436
+ if (deps) {
2437
+ for (const dep of deps) {
2438
+ if (dependencies.has(dep)) {
2439
+ detectCircular(dep, [...path]);
2440
+ }
2441
+ }
2442
+ }
2443
+ visiting.delete(name);
2444
+ visited.add(name);
2445
+ };
2446
+ for (const name of dependencies.keys()) {
2447
+ detectCircular(name, []);
2448
+ }
2449
+ }
2450
+ /**
2451
+ * Generate JSDoc warning for allOf conflicts
2452
+ * @param conflicts Array of conflict description strings
2453
+ * @returns JSDoc formatted warning string
2454
+ */
2455
+ generateConflictJSDoc(conflicts) {
2456
+ const lines = [" * @warning allOf property conflicts detected:"];
2457
+ for (const conflict of conflicts) {
2458
+ lines.push(` * - ${conflict}`);
2459
+ }
2460
+ return `${lines.join("\n")}
2461
+ `;
2462
+ }
2674
2463
  };
2675
2464
 
2676
2465
  // src/types.ts
@@ -2684,8 +2473,10 @@ export {
2684
2473
  FileOperationError,
2685
2474
  GeneratorError,
2686
2475
  OpenApiGenerator,
2687
- SchemaGenerationError,
2688
- SpecValidationError,
2476
+ PropertyGenerator,
2477
+ SchemaGenerationError2 as SchemaGenerationError,
2478
+ SpecValidationError2 as SpecValidationError,
2479
+ buildDateTimeValidation,
2689
2480
  defineConfig
2690
2481
  };
2691
2482
  //# sourceMappingURL=index.mjs.map