@cerios/openapi-to-zod 1.1.0 → 1.2.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/README.md +209 -28
- package/dist/cli.js +245 -80
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +246 -81
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +209 -77
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +209 -77
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.mts +34 -19
- package/dist/internal.d.ts +34 -19
- package/dist/internal.js +106 -50
- package/dist/internal.js.map +1 -1
- package/dist/internal.mjs +104 -50
- package/dist/internal.mjs.map +1 -1
- package/dist/{types-B7ePTDjr.d.mts → types--r0d47sd.d.mts} +86 -8
- package/dist/{types-B7ePTDjr.d.ts → types--r0d47sd.d.ts} +86 -8
- package/package.json +105 -102
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as OpenApiGeneratorOptions } from './types
|
|
2
|
-
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types
|
|
1
|
+
import { O as OpenApiGeneratorOptions } from './types--r0d47sd.mjs';
|
|
2
|
+
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types--r0d47sd.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Custom error classes for better error handling and debugging
|
|
@@ -125,6 +125,17 @@ declare class OpenApiGenerator {
|
|
|
125
125
|
* Generate query parameter schemas for each operation
|
|
126
126
|
*/
|
|
127
127
|
private generateQueryParameterSchemas;
|
|
128
|
+
/**
|
|
129
|
+
* Generate a PascalCase method name from HTTP method and path
|
|
130
|
+
* Used as fallback when operationId is not available
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
private generateMethodNameFromPath;
|
|
134
|
+
/**
|
|
135
|
+
* Capitalizes a path segment, handling special characters like dashes, underscores, and dots
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
private capitalizeSegment;
|
|
128
139
|
/**
|
|
129
140
|
* Check if a header should be ignored based on filter patterns
|
|
130
141
|
* @internal
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as OpenApiGeneratorOptions } from './types
|
|
2
|
-
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types
|
|
1
|
+
import { O as OpenApiGeneratorOptions } from './types--r0d47sd.js';
|
|
2
|
+
export { C as CommonSchemaOptions, a as ConfigFile, E as ExecutionMode, b as OpenAPISchema, c as OpenAPISpec, d as OperationFilters, R as RequestOptions, e as ResponseOptions, f as defineConfig } from './types--r0d47sd.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Custom error classes for better error handling and debugging
|
|
@@ -125,6 +125,17 @@ declare class OpenApiGenerator {
|
|
|
125
125
|
* Generate query parameter schemas for each operation
|
|
126
126
|
*/
|
|
127
127
|
private generateQueryParameterSchemas;
|
|
128
|
+
/**
|
|
129
|
+
* Generate a PascalCase method name from HTTP method and path
|
|
130
|
+
* Used as fallback when operationId is not available
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
private generateMethodNameFromPath;
|
|
134
|
+
/**
|
|
135
|
+
* Capitalizes a path segment, handling special characters like dashes, underscores, and dots
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
private capitalizeSegment;
|
|
128
139
|
/**
|
|
129
140
|
* Check if a header should be ignored based on filter patterns
|
|
130
141
|
* @internal
|
package/dist/index.js
CHANGED
|
@@ -94,7 +94,7 @@ var ConfigurationError = class extends GeneratorError {
|
|
|
94
94
|
// src/openapi-generator.ts
|
|
95
95
|
var import_node_fs = require("fs");
|
|
96
96
|
var import_node_path = require("path");
|
|
97
|
-
var
|
|
97
|
+
var import_minimatch3 = require("minimatch");
|
|
98
98
|
var import_yaml = require("yaml");
|
|
99
99
|
|
|
100
100
|
// src/utils/name-utils.ts
|
|
@@ -153,8 +153,26 @@ function resolveRef(ref) {
|
|
|
153
153
|
function generateEnum(name, values, options) {
|
|
154
154
|
const schemaName = `${toCamelCase(name, options)}Schema`;
|
|
155
155
|
const typeName = toPascalCase(name);
|
|
156
|
-
const
|
|
157
|
-
|
|
156
|
+
const allBooleans = values.every((v) => typeof v === "boolean");
|
|
157
|
+
if (allBooleans) {
|
|
158
|
+
const schemaCode2 = `export const ${schemaName} = z.boolean();`;
|
|
159
|
+
const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
|
|
160
|
+
return { schemaCode: schemaCode2, typeCode: typeCode2 };
|
|
161
|
+
}
|
|
162
|
+
const allStrings = values.every((v) => typeof v === "string");
|
|
163
|
+
if (allStrings) {
|
|
164
|
+
const enumValues = values.map((v) => `"${v}"`).join(", ");
|
|
165
|
+
const schemaCode2 = `export const ${schemaName} = z.enum([${enumValues}]);`;
|
|
166
|
+
const typeCode2 = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
|
|
167
|
+
return { schemaCode: schemaCode2, typeCode: typeCode2 };
|
|
168
|
+
}
|
|
169
|
+
const literalValues = values.map((v) => {
|
|
170
|
+
if (typeof v === "string") {
|
|
171
|
+
return `z.literal("${v}")`;
|
|
172
|
+
}
|
|
173
|
+
return `z.literal(${v})`;
|
|
174
|
+
}).join(", ");
|
|
175
|
+
const schemaCode = `export const ${schemaName} = z.union([${literalValues}]);`;
|
|
158
176
|
const typeCode = `export type ${typeName} = z.infer<typeof ${schemaName}>;`;
|
|
159
177
|
return { schemaCode, typeCode };
|
|
160
178
|
}
|
|
@@ -164,7 +182,7 @@ function escapeDescription(str) {
|
|
|
164
182
|
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
165
183
|
}
|
|
166
184
|
function escapePattern(str) {
|
|
167
|
-
return str.replace(
|
|
185
|
+
return str.replace(/\//g, "\\/");
|
|
168
186
|
}
|
|
169
187
|
function escapeJSDoc(str) {
|
|
170
188
|
return str.replace(/\*\//g, "*\\/");
|
|
@@ -172,14 +190,17 @@ function escapeJSDoc(str) {
|
|
|
172
190
|
function wrapNullable(validation, isNullable2) {
|
|
173
191
|
return isNullable2 ? `${validation}.nullable()` : validation;
|
|
174
192
|
}
|
|
175
|
-
function isNullable(schema) {
|
|
193
|
+
function isNullable(schema, defaultNullable = false) {
|
|
176
194
|
if (schema.nullable === true) {
|
|
177
195
|
return true;
|
|
178
196
|
}
|
|
197
|
+
if (schema.nullable === false) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
179
200
|
if (Array.isArray(schema.type)) {
|
|
180
201
|
return schema.type.includes("null");
|
|
181
202
|
}
|
|
182
|
-
return
|
|
203
|
+
return defaultNullable;
|
|
183
204
|
}
|
|
184
205
|
function getPrimaryType(schema) {
|
|
185
206
|
if (Array.isArray(schema.type)) {
|
|
@@ -289,61 +310,36 @@ var LRUCache = class {
|
|
|
289
310
|
};
|
|
290
311
|
|
|
291
312
|
// src/utils/pattern-utils.ts
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (/\\[dDwWsS]/.test(pattern)) {
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
if (/\.\*|\.\+/.test(pattern)) {
|
|
300
|
-
return true;
|
|
301
|
-
}
|
|
302
|
-
if (/[[\]()]/.test(pattern)) {
|
|
303
|
-
return true;
|
|
304
|
-
}
|
|
305
|
-
if (/[^/][+?*]\{/.test(pattern)) {
|
|
313
|
+
var import_minimatch = require("minimatch");
|
|
314
|
+
function isValidGlobPattern(pattern) {
|
|
315
|
+
try {
|
|
316
|
+
new import_minimatch.minimatch.Minimatch(pattern);
|
|
306
317
|
return true;
|
|
318
|
+
} catch {
|
|
319
|
+
return false;
|
|
307
320
|
}
|
|
308
|
-
return false;
|
|
309
321
|
}
|
|
310
|
-
function
|
|
311
|
-
|
|
312
|
-
return pattern;
|
|
313
|
-
}
|
|
314
|
-
if (isRegexPattern(pattern)) {
|
|
315
|
-
try {
|
|
316
|
-
return new RegExp(pattern);
|
|
317
|
-
} catch (error) {
|
|
318
|
-
console.warn(`\u26A0\uFE0F Invalid regex pattern "${pattern}": ${error instanceof Error ? error.message : String(error)}`);
|
|
319
|
-
return null;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return null;
|
|
322
|
+
function isGlobPattern(pattern) {
|
|
323
|
+
return /[*?[\]{}!]/.test(pattern);
|
|
323
324
|
}
|
|
324
325
|
function stripPrefix(input, pattern, ensureLeadingChar) {
|
|
325
326
|
if (!pattern) {
|
|
326
327
|
return input;
|
|
327
328
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
return `${ensureLeadingChar}${stripped}`;
|
|
339
|
-
}
|
|
329
|
+
if (isGlobPattern(pattern) && !isValidGlobPattern(pattern)) {
|
|
330
|
+
console.warn(`\u26A0\uFE0F Invalid glob pattern "${pattern}": Pattern is malformed`);
|
|
331
|
+
return input;
|
|
332
|
+
}
|
|
333
|
+
if (isGlobPattern(pattern)) {
|
|
334
|
+
let longestMatch = -1;
|
|
335
|
+
for (let i = 1; i <= input.length; i++) {
|
|
336
|
+
const testPrefix = input.substring(0, i);
|
|
337
|
+
if ((0, import_minimatch.minimatch)(testPrefix, pattern)) {
|
|
338
|
+
longestMatch = i;
|
|
340
339
|
}
|
|
341
|
-
return stripped;
|
|
342
340
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (input.startsWith(stringPattern)) {
|
|
346
|
-
const stripped = input.substring(stringPattern.length);
|
|
341
|
+
if (longestMatch > 0) {
|
|
342
|
+
const stripped = input.substring(longestMatch);
|
|
347
343
|
if (ensureLeadingChar) {
|
|
348
344
|
if (stripped === "") {
|
|
349
345
|
return ensureLeadingChar;
|
|
@@ -352,11 +348,40 @@ function stripPrefix(input, pattern, ensureLeadingChar) {
|
|
|
352
348
|
return `${ensureLeadingChar}${stripped}`;
|
|
353
349
|
}
|
|
354
350
|
}
|
|
355
|
-
return stripped;
|
|
351
|
+
return stripped === "" && !ensureLeadingChar ? input : stripped;
|
|
356
352
|
}
|
|
353
|
+
return input;
|
|
354
|
+
}
|
|
355
|
+
if (input.startsWith(pattern)) {
|
|
356
|
+
const stripped = input.substring(pattern.length);
|
|
357
|
+
if (ensureLeadingChar) {
|
|
358
|
+
if (stripped === "") {
|
|
359
|
+
return ensureLeadingChar;
|
|
360
|
+
}
|
|
361
|
+
if (!stripped.startsWith(ensureLeadingChar)) {
|
|
362
|
+
return `${ensureLeadingChar}${stripped}`;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return stripped;
|
|
357
366
|
}
|
|
358
367
|
return input;
|
|
359
368
|
}
|
|
369
|
+
function stripPathPrefix(path, pattern) {
|
|
370
|
+
if (!pattern) {
|
|
371
|
+
return path;
|
|
372
|
+
}
|
|
373
|
+
if (!isGlobPattern(pattern)) {
|
|
374
|
+
let normalizedPattern = pattern.trim();
|
|
375
|
+
if (!normalizedPattern.startsWith("/")) {
|
|
376
|
+
normalizedPattern = `/${normalizedPattern}`;
|
|
377
|
+
}
|
|
378
|
+
if (normalizedPattern.endsWith("/") && normalizedPattern !== "/") {
|
|
379
|
+
normalizedPattern = normalizedPattern.slice(0, -1);
|
|
380
|
+
}
|
|
381
|
+
return stripPrefix(path, normalizedPattern, "/");
|
|
382
|
+
}
|
|
383
|
+
return stripPrefix(path, pattern, "/");
|
|
384
|
+
}
|
|
360
385
|
|
|
361
386
|
// src/validators/array-validator.ts
|
|
362
387
|
function generateArrayValidation(schema, context) {
|
|
@@ -882,7 +907,7 @@ function configurePatternCache(size) {
|
|
|
882
907
|
PATTERN_CACHE = new LRUCache(size);
|
|
883
908
|
}
|
|
884
909
|
}
|
|
885
|
-
var
|
|
910
|
+
var DEFAULT_FORMAT_MAP = {
|
|
886
911
|
uuid: "z.uuid()",
|
|
887
912
|
email: "z.email()",
|
|
888
913
|
uri: "z.url()",
|
|
@@ -892,7 +917,6 @@ var FORMAT_MAP = {
|
|
|
892
917
|
byte: "z.base64()",
|
|
893
918
|
binary: "z.string()",
|
|
894
919
|
date: "z.iso.date()",
|
|
895
|
-
"date-time": "z.iso.datetime()",
|
|
896
920
|
time: "z.iso.time()",
|
|
897
921
|
duration: 'z.string().refine((val) => /^P(?:(?:\\d+Y)?(?:\\d+M)?(?:\\d+D)?(?:T(?:\\d+H)?(?:\\d+M)?(?:\\d+(?:\\.\\d+)?S)?)?|\\d+W)$/.test(val) && !/^PT?$/.test(val), { message: "Must be a valid ISO 8601 duration" })',
|
|
898
922
|
ipv4: "z.ipv4()",
|
|
@@ -911,6 +935,30 @@ var FORMAT_MAP = {
|
|
|
911
935
|
"json-pointer": 'z.string().refine((val) => val === "" || /^(\\/([^~/]|~0|~1)+)+$/.test(val), { message: "Must be a valid JSON Pointer (RFC 6901)" })',
|
|
912
936
|
"relative-json-pointer": 'z.string().refine((val) => /^(0|[1-9]\\d*)(#|(\\/([^~/]|~0|~1)+)*)$/.test(val), { message: "Must be a valid relative JSON Pointer" })'
|
|
913
937
|
};
|
|
938
|
+
var FORMAT_MAP = {
|
|
939
|
+
...DEFAULT_FORMAT_MAP,
|
|
940
|
+
"date-time": "z.iso.datetime()"
|
|
941
|
+
};
|
|
942
|
+
function configureDateTimeFormat(pattern) {
|
|
943
|
+
if (!pattern) {
|
|
944
|
+
FORMAT_MAP["date-time"] = "z.iso.datetime()";
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
const patternStr = pattern instanceof RegExp ? pattern.source : pattern;
|
|
948
|
+
if (patternStr === "") {
|
|
949
|
+
FORMAT_MAP["date-time"] = "z.iso.datetime()";
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
try {
|
|
953
|
+
new RegExp(patternStr);
|
|
954
|
+
} catch (error) {
|
|
955
|
+
throw new Error(
|
|
956
|
+
`Invalid regular expression pattern for customDateTimeFormatRegex: ${patternStr}. ${error instanceof Error ? error.message : "Pattern is malformed"}`
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
const escapedPattern = escapePattern(patternStr);
|
|
960
|
+
FORMAT_MAP["date-time"] = `z.string().regex(/${escapedPattern}/)`;
|
|
961
|
+
}
|
|
914
962
|
function generateStringValidation(schema, useDescribe) {
|
|
915
963
|
let validation = FORMAT_MAP[schema.format || ""] || "z.string()";
|
|
916
964
|
if (schema.minLength !== void 0) {
|
|
@@ -1200,7 +1248,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1200
1248
|
if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
|
|
1201
1249
|
schema = this.filterNestedProperties(schema);
|
|
1202
1250
|
}
|
|
1203
|
-
const
|
|
1251
|
+
const effectiveDefaultNullable = isTopLevel ? false : this.context.defaultNullable;
|
|
1252
|
+
const nullable = isNullable(schema, effectiveDefaultNullable);
|
|
1204
1253
|
if (hasMultipleTypes(schema)) {
|
|
1205
1254
|
const union = this.generateMultiTypeUnion(schema, currentSchema);
|
|
1206
1255
|
return wrapNullable(union, nullable);
|
|
@@ -1228,9 +1277,25 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1228
1277
|
return wrapNullable(zodLiteral, nullable);
|
|
1229
1278
|
}
|
|
1230
1279
|
if (schema.enum) {
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
|
|
1280
|
+
const allBooleans = schema.enum.every((v) => typeof v === "boolean");
|
|
1281
|
+
if (allBooleans) {
|
|
1282
|
+
const zodBoolean = "z.boolean()";
|
|
1283
|
+
return wrapNullable(zodBoolean, nullable);
|
|
1284
|
+
}
|
|
1285
|
+
const allStrings = schema.enum.every((v) => typeof v === "string");
|
|
1286
|
+
if (allStrings) {
|
|
1287
|
+
const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
|
|
1288
|
+
const zodEnum = `z.enum([${enumValues}])`;
|
|
1289
|
+
return wrapNullable(zodEnum, nullable);
|
|
1290
|
+
}
|
|
1291
|
+
const literalValues = schema.enum.map((v) => {
|
|
1292
|
+
if (typeof v === "string") {
|
|
1293
|
+
return `z.literal("${v}")`;
|
|
1294
|
+
}
|
|
1295
|
+
return `z.literal(${v})`;
|
|
1296
|
+
}).join(", ");
|
|
1297
|
+
const zodUnion = `z.union([${literalValues}])`;
|
|
1298
|
+
return wrapNullable(zodUnion, nullable);
|
|
1234
1299
|
}
|
|
1235
1300
|
if (schema.allOf) {
|
|
1236
1301
|
let composition = generateAllOf(
|
|
@@ -1361,7 +1426,7 @@ _PropertyGenerator.INCLUSION_RULES = {
|
|
|
1361
1426
|
var PropertyGenerator = _PropertyGenerator;
|
|
1362
1427
|
|
|
1363
1428
|
// src/utils/operation-filters.ts
|
|
1364
|
-
var
|
|
1429
|
+
var import_minimatch2 = require("minimatch");
|
|
1365
1430
|
function createFilterStatistics() {
|
|
1366
1431
|
return {
|
|
1367
1432
|
totalOperations: 0,
|
|
@@ -1380,7 +1445,7 @@ function matchesAnyPattern(value, patterns) {
|
|
|
1380
1445
|
if (!value) {
|
|
1381
1446
|
return false;
|
|
1382
1447
|
}
|
|
1383
|
-
return patterns.some((pattern) => (0,
|
|
1448
|
+
return patterns.some((pattern) => (0, import_minimatch2.minimatch)(value, pattern));
|
|
1384
1449
|
}
|
|
1385
1450
|
function containsAny(arr, values) {
|
|
1386
1451
|
if (!values || values.length === 0) {
|
|
@@ -1503,7 +1568,7 @@ var OpenApiGenerator = class {
|
|
|
1503
1568
|
this.schemaUsageMap = /* @__PURE__ */ new Map();
|
|
1504
1569
|
this.needsZodImport = true;
|
|
1505
1570
|
this.filterStats = createFilterStatistics();
|
|
1506
|
-
var _a, _b, _c, _d, _e;
|
|
1571
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1507
1572
|
if (!options.input) {
|
|
1508
1573
|
throw new ConfigurationError("Input path is required", { providedOptions: options });
|
|
1509
1574
|
}
|
|
@@ -1513,21 +1578,27 @@ var OpenApiGenerator = class {
|
|
|
1513
1578
|
output: options.output,
|
|
1514
1579
|
includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
|
|
1515
1580
|
useDescribe: (_b = options.useDescribe) != null ? _b : false,
|
|
1581
|
+
defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
|
|
1516
1582
|
schemaType: options.schemaType || "all",
|
|
1517
1583
|
prefix: options.prefix,
|
|
1518
1584
|
suffix: options.suffix,
|
|
1519
1585
|
stripSchemaPrefix: options.stripSchemaPrefix,
|
|
1520
|
-
|
|
1586
|
+
stripPathPrefix: options.stripPathPrefix,
|
|
1587
|
+
showStats: (_d = options.showStats) != null ? _d : true,
|
|
1521
1588
|
request: options.request,
|
|
1522
1589
|
response: options.response,
|
|
1523
1590
|
operationFilters: options.operationFilters,
|
|
1524
1591
|
ignoreHeaders: options.ignoreHeaders,
|
|
1525
|
-
cacheSize: (
|
|
1526
|
-
batchSize: (
|
|
1592
|
+
cacheSize: (_e = options.cacheSize) != null ? _e : 1e3,
|
|
1593
|
+
batchSize: (_f = options.batchSize) != null ? _f : 10,
|
|
1594
|
+
customDateTimeFormatRegex: options.customDateTimeFormatRegex
|
|
1527
1595
|
};
|
|
1528
1596
|
if (this.options.cacheSize) {
|
|
1529
1597
|
configurePatternCache(this.options.cacheSize);
|
|
1530
1598
|
}
|
|
1599
|
+
if (this.options.customDateTimeFormatRegex) {
|
|
1600
|
+
configureDateTimeFormat(this.options.customDateTimeFormatRegex);
|
|
1601
|
+
}
|
|
1531
1602
|
try {
|
|
1532
1603
|
const fs = require("fs");
|
|
1533
1604
|
if (!fs.existsSync(this.options.input)) {
|
|
@@ -1590,6 +1661,7 @@ var OpenApiGenerator = class {
|
|
|
1590
1661
|
mode: this.requestOptions.mode,
|
|
1591
1662
|
includeDescriptions: this.requestOptions.includeDescriptions,
|
|
1592
1663
|
useDescribe: this.requestOptions.useDescribe,
|
|
1664
|
+
defaultNullable: (_g = this.options.defaultNullable) != null ? _g : false,
|
|
1593
1665
|
namingOptions: {
|
|
1594
1666
|
prefix: this.options.prefix,
|
|
1595
1667
|
suffix: this.options.suffix
|
|
@@ -1607,6 +1679,9 @@ var OpenApiGenerator = class {
|
|
|
1607
1679
|
throw new SpecValidationError("No schemas found in OpenAPI spec", { filePath: this.options.input });
|
|
1608
1680
|
}
|
|
1609
1681
|
for (const [name, schema] of Object.entries(this.spec.components.schemas)) {
|
|
1682
|
+
if (this.options.operationFilters && this.schemaUsageMap.size > 0 && !this.schemaUsageMap.has(name)) {
|
|
1683
|
+
continue;
|
|
1684
|
+
}
|
|
1610
1685
|
this.generateComponentSchema(name, schema);
|
|
1611
1686
|
}
|
|
1612
1687
|
this.generateQueryParameterSchemas();
|
|
@@ -1940,7 +2015,7 @@ var OpenApiGenerator = class {
|
|
|
1940
2015
|
* Generate schema for a component
|
|
1941
2016
|
*/
|
|
1942
2017
|
generateComponentSchema(name, schema) {
|
|
1943
|
-
var _a, _b;
|
|
2018
|
+
var _a, _b, _c;
|
|
1944
2019
|
if (!this.schemaDependencies.has(name)) {
|
|
1945
2020
|
this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
|
|
1946
2021
|
}
|
|
@@ -1972,14 +2047,14 @@ ${typeCode}`;
|
|
|
1972
2047
|
mode: resolvedOptions.mode,
|
|
1973
2048
|
includeDescriptions: resolvedOptions.includeDescriptions,
|
|
1974
2049
|
useDescribe: resolvedOptions.useDescribe,
|
|
2050
|
+
defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
|
|
1975
2051
|
namingOptions: {
|
|
1976
2052
|
prefix: this.options.prefix,
|
|
1977
2053
|
suffix: this.options.suffix
|
|
1978
2054
|
},
|
|
1979
2055
|
stripSchemaPrefix: this.options.stripSchemaPrefix
|
|
1980
2056
|
});
|
|
1981
|
-
const
|
|
1982
|
-
const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, isAlias);
|
|
2057
|
+
const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, true);
|
|
1983
2058
|
const zodSchemaCode = `${jsdoc}export const ${schemaName} = ${zodSchema};`;
|
|
1984
2059
|
if (zodSchema.includes("z.discriminatedUnion(")) {
|
|
1985
2060
|
const match = zodSchema.match(/z\.discriminatedUnion\([^,]+,\s*\[([^\]]+)\]/);
|
|
@@ -1989,7 +2064,7 @@ ${typeCode}`;
|
|
|
1989
2064
|
const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
|
|
1990
2065
|
if (depMatch) {
|
|
1991
2066
|
const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
|
|
1992
|
-
(
|
|
2067
|
+
(_c = this.schemaDependencies.get(name)) == null ? void 0 : _c.add(depName);
|
|
1993
2068
|
}
|
|
1994
2069
|
}
|
|
1995
2070
|
}
|
|
@@ -2013,7 +2088,7 @@ ${typeCode}`;
|
|
|
2013
2088
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2014
2089
|
continue;
|
|
2015
2090
|
}
|
|
2016
|
-
if (!operation.
|
|
2091
|
+
if (!operation.parameters || !Array.isArray(operation.parameters)) {
|
|
2017
2092
|
continue;
|
|
2018
2093
|
}
|
|
2019
2094
|
const queryParams = operation.parameters.filter(
|
|
@@ -2022,7 +2097,13 @@ ${typeCode}`;
|
|
|
2022
2097
|
if (queryParams.length === 0) {
|
|
2023
2098
|
continue;
|
|
2024
2099
|
}
|
|
2025
|
-
|
|
2100
|
+
let pascalOperationId;
|
|
2101
|
+
if (operation.operationId) {
|
|
2102
|
+
pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
|
|
2103
|
+
} else {
|
|
2104
|
+
const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
|
|
2105
|
+
pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
|
|
2106
|
+
}
|
|
2026
2107
|
const schemaName = `${pascalOperationId}QueryParams`;
|
|
2027
2108
|
if (!this.schemaDependencies.has(schemaName)) {
|
|
2028
2109
|
this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
|
|
@@ -2070,8 +2151,9 @@ ${propsCode}
|
|
|
2070
2151
|
const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
|
|
2071
2152
|
const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
|
|
2072
2153
|
const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}QueryParamsSchema`;
|
|
2154
|
+
const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
|
|
2073
2155
|
const jsdoc = `/**
|
|
2074
|
-
* Query parameters for ${
|
|
2156
|
+
* Query parameters for ${jsdocOperationName}
|
|
2075
2157
|
*/
|
|
2076
2158
|
`;
|
|
2077
2159
|
const fullSchemaCode = `${jsdoc}export const ${camelCaseSchemaName} = ${schemaCode};`;
|
|
@@ -2080,6 +2162,35 @@ ${propsCode}
|
|
|
2080
2162
|
}
|
|
2081
2163
|
}
|
|
2082
2164
|
}
|
|
2165
|
+
/**
|
|
2166
|
+
* Generate a PascalCase method name from HTTP method and path
|
|
2167
|
+
* Used as fallback when operationId is not available
|
|
2168
|
+
* @internal
|
|
2169
|
+
*/
|
|
2170
|
+
generateMethodNameFromPath(method, path) {
|
|
2171
|
+
const segments = path.split("/").filter(Boolean).map((segment) => {
|
|
2172
|
+
if (segment.startsWith("{") && segment.endsWith("}")) {
|
|
2173
|
+
const paramName = segment.slice(1, -1);
|
|
2174
|
+
return `By${this.capitalizeSegment(paramName)}`;
|
|
2175
|
+
}
|
|
2176
|
+
return this.capitalizeSegment(segment);
|
|
2177
|
+
}).join("");
|
|
2178
|
+
const capitalizedMethod = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
|
|
2179
|
+
return `${capitalizedMethod}${segments}`;
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Capitalizes a path segment, handling special characters like dashes, underscores, and dots
|
|
2183
|
+
* @internal
|
|
2184
|
+
*/
|
|
2185
|
+
capitalizeSegment(str) {
|
|
2186
|
+
if (str.includes("-") || str.includes("_") || str.includes(".")) {
|
|
2187
|
+
return str.split(/[-_.]/).map((part) => {
|
|
2188
|
+
if (!part) return "";
|
|
2189
|
+
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
|
|
2190
|
+
}).join("");
|
|
2191
|
+
}
|
|
2192
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
2193
|
+
}
|
|
2083
2194
|
/**
|
|
2084
2195
|
* Check if a header should be ignored based on filter patterns
|
|
2085
2196
|
* @internal
|
|
@@ -2095,7 +2206,7 @@ ${propsCode}
|
|
|
2095
2206
|
const headerLower = headerName.toLowerCase();
|
|
2096
2207
|
return ignorePatterns.some((pattern) => {
|
|
2097
2208
|
const patternLower = pattern.toLowerCase();
|
|
2098
|
-
return (0,
|
|
2209
|
+
return (0, import_minimatch3.minimatch)(headerLower, patternLower);
|
|
2099
2210
|
});
|
|
2100
2211
|
}
|
|
2101
2212
|
/**
|
|
@@ -2116,7 +2227,7 @@ ${propsCode}
|
|
|
2116
2227
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2117
2228
|
continue;
|
|
2118
2229
|
}
|
|
2119
|
-
if (!operation.
|
|
2230
|
+
if (!operation.parameters || !Array.isArray(operation.parameters)) {
|
|
2120
2231
|
continue;
|
|
2121
2232
|
}
|
|
2122
2233
|
const headerParams = operation.parameters.filter(
|
|
@@ -2125,7 +2236,13 @@ ${propsCode}
|
|
|
2125
2236
|
if (headerParams.length === 0) {
|
|
2126
2237
|
continue;
|
|
2127
2238
|
}
|
|
2128
|
-
|
|
2239
|
+
let pascalOperationId;
|
|
2240
|
+
if (operation.operationId) {
|
|
2241
|
+
pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
|
|
2242
|
+
} else {
|
|
2243
|
+
const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
|
|
2244
|
+
pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
|
|
2245
|
+
}
|
|
2129
2246
|
const schemaName = `${pascalOperationId}HeaderParams`;
|
|
2130
2247
|
if (!this.schemaDependencies.has(schemaName)) {
|
|
2131
2248
|
this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
|
|
@@ -2162,8 +2279,9 @@ ${propsCode}
|
|
|
2162
2279
|
const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
|
|
2163
2280
|
const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
|
|
2164
2281
|
const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}HeaderParamsSchema`;
|
|
2282
|
+
const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
|
|
2165
2283
|
const jsdoc = `/**
|
|
2166
|
-
* Header parameters for ${
|
|
2284
|
+
* Header parameters for ${jsdocOperationName}
|
|
2167
2285
|
*/
|
|
2168
2286
|
`;
|
|
2169
2287
|
const fullSchemaCode = `${jsdoc}export const ${camelCaseSchemaName} = ${schemaCode};`;
|
|
@@ -2183,8 +2301,22 @@ ${propsCode}
|
|
|
2183
2301
|
return `${schemaName}Schema`;
|
|
2184
2302
|
}
|
|
2185
2303
|
if (schema.enum) {
|
|
2186
|
-
const
|
|
2187
|
-
|
|
2304
|
+
const allBooleans = schema.enum.every((v) => typeof v === "boolean");
|
|
2305
|
+
if (allBooleans) {
|
|
2306
|
+
return "z.boolean()";
|
|
2307
|
+
}
|
|
2308
|
+
const allStrings = schema.enum.every((v) => typeof v === "string");
|
|
2309
|
+
if (allStrings) {
|
|
2310
|
+
const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
|
|
2311
|
+
return `z.enum([${enumValues}])`;
|
|
2312
|
+
}
|
|
2313
|
+
const literalValues = schema.enum.map((v) => {
|
|
2314
|
+
if (typeof v === "string") {
|
|
2315
|
+
return `z.literal("${v}")`;
|
|
2316
|
+
}
|
|
2317
|
+
return `z.literal(${v})`;
|
|
2318
|
+
}).join(", ");
|
|
2319
|
+
return `z.union([${literalValues}])`;
|
|
2188
2320
|
}
|
|
2189
2321
|
const type = schema.type;
|
|
2190
2322
|
if (type === "string") {
|