@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/LICENSE +8 -0
- package/README.md +546 -395
- package/dist/cli.js +806 -1293
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +839 -1343
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +468 -59
- package/dist/index.d.ts +468 -59
- package/dist/index.js +644 -881
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +650 -856
- package/dist/index.mjs.map +1 -1
- package/package.json +89 -104
- package/dist/internal.d.mts +0 -470
- package/dist/internal.d.ts +0 -470
- package/dist/internal.js +0 -2025
- package/dist/internal.js.map +0 -1
- package/dist/internal.mjs +0 -1972
- package/dist/internal.mjs.map +0 -1
- package/dist/types-DZ4Bw-D5.d.mts +0 -505
- package/dist/types-DZ4Bw-D5.d.ts +0 -505
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
|
-
|
|
30
|
-
|
|
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/
|
|
36
|
-
var
|
|
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
|
-
|
|
182
|
-
|
|
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
|
-
|
|
557
|
-
if (
|
|
558
|
-
for (const conflict of
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
1405
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
1625
|
-
var
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
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
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
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
|
-
|
|
1670
|
-
if (
|
|
1671
|
-
|
|
1672
|
-
return false;
|
|
1397
|
+
const literalValues = values.map((v) => {
|
|
1398
|
+
if (typeof v === "string") {
|
|
1399
|
+
return `z.literal("${v}")`;
|
|
1673
1400
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
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/
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
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
|
|
1794
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
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
|
-
|
|
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: (
|
|
1843
|
-
batchSize: (
|
|
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((
|
|
1459
|
+
this.patternCache = new import_openapi_core6.LRUCache((_j = this.options.cacheSize) != null ? _j : 1e3);
|
|
1847
1460
|
this.dateTimeValidation = buildDateTimeValidation(this.options.customDateTimeFormatRegex);
|
|
1848
|
-
|
|
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.
|
|
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: (
|
|
1911
|
-
emptyObjectBehavior: (
|
|
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
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
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
|
-
*
|
|
2004
|
-
*
|
|
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
|
-
|
|
2007
|
-
var _a
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
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
|
-
|
|
2013
|
-
for (const method of
|
|
1792
|
+
if (!isOpenAPIPathItem(pathItem)) continue;
|
|
1793
|
+
for (const method of HTTP_METHODS) {
|
|
2014
1794
|
const operation = pathItem[method];
|
|
2015
|
-
if (
|
|
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 (
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
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 (
|
|
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
|
-
|
|
1816
|
+
(0, import_openapi_core6.extractSchemaRefs)(mediaType.schema, responseSchemas);
|
|
2034
1817
|
}
|
|
2035
1818
|
}
|
|
2036
1819
|
}
|
|
2037
1820
|
}
|
|
2038
1821
|
}
|
|
2039
|
-
if (
|
|
1822
|
+
if (operation.parameters && Array.isArray(operation.parameters)) {
|
|
2040
1823
|
for (const param of operation.parameters) {
|
|
2041
|
-
if (param &&
|
|
2042
|
-
|
|
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
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
if (
|
|
2056
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
|
2330
|
-
const
|
|
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 &&
|
|
2028
|
+
(param) => isResolvedParameter(param) && param.in === "query"
|
|
2340
2029
|
);
|
|
2341
2030
|
if (queryParams.length === 0) {
|
|
2342
2031
|
continue;
|
|
2343
2032
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
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 =
|
|
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
|
|
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,
|
|
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
|
|
2467
|
-
const
|
|
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 &&
|
|
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
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
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 (!
|
|
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
|