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