@cerios/openapi-to-zod 1.1.1 → 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 +125 -0
- package/dist/cli.js +148 -22
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +149 -23
- 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 +112 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +112 -19
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.mts +23 -2
- package/dist/internal.d.ts +23 -2
- package/dist/internal.js +70 -1
- package/dist/internal.js.map +1 -1
- package/dist/internal.mjs +68 -1
- package/dist/internal.mjs.map +1 -1
- package/dist/{types-CI48CjiU.d.mts → types--r0d47sd.d.mts} +67 -0
- package/dist/{types-CI48CjiU.d.ts → types--r0d47sd.d.ts} +67 -0
- package/package.json +16 -4
package/dist/index.mjs
CHANGED
|
@@ -163,14 +163,17 @@ function escapeJSDoc(str) {
|
|
|
163
163
|
function wrapNullable(validation, isNullable2) {
|
|
164
164
|
return isNullable2 ? `${validation}.nullable()` : validation;
|
|
165
165
|
}
|
|
166
|
-
function isNullable(schema) {
|
|
166
|
+
function isNullable(schema, defaultNullable = false) {
|
|
167
167
|
if (schema.nullable === true) {
|
|
168
168
|
return true;
|
|
169
169
|
}
|
|
170
|
+
if (schema.nullable === false) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
170
173
|
if (Array.isArray(schema.type)) {
|
|
171
174
|
return schema.type.includes("null");
|
|
172
175
|
}
|
|
173
|
-
return
|
|
176
|
+
return defaultNullable;
|
|
174
177
|
}
|
|
175
178
|
function getPrimaryType(schema) {
|
|
176
179
|
if (Array.isArray(schema.type)) {
|
|
@@ -336,6 +339,22 @@ function stripPrefix(input, pattern, ensureLeadingChar) {
|
|
|
336
339
|
}
|
|
337
340
|
return input;
|
|
338
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
|
+
}
|
|
339
358
|
|
|
340
359
|
// src/validators/array-validator.ts
|
|
341
360
|
function generateArrayValidation(schema, context) {
|
|
@@ -861,7 +880,7 @@ function configurePatternCache(size) {
|
|
|
861
880
|
PATTERN_CACHE = new LRUCache(size);
|
|
862
881
|
}
|
|
863
882
|
}
|
|
864
|
-
var
|
|
883
|
+
var DEFAULT_FORMAT_MAP = {
|
|
865
884
|
uuid: "z.uuid()",
|
|
866
885
|
email: "z.email()",
|
|
867
886
|
uri: "z.url()",
|
|
@@ -871,7 +890,6 @@ var FORMAT_MAP = {
|
|
|
871
890
|
byte: "z.base64()",
|
|
872
891
|
binary: "z.string()",
|
|
873
892
|
date: "z.iso.date()",
|
|
874
|
-
"date-time": "z.iso.datetime()",
|
|
875
893
|
time: "z.iso.time()",
|
|
876
894
|
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" })',
|
|
877
895
|
ipv4: "z.ipv4()",
|
|
@@ -890,6 +908,30 @@ var FORMAT_MAP = {
|
|
|
890
908
|
"json-pointer": 'z.string().refine((val) => val === "" || /^(\\/([^~/]|~0|~1)+)+$/.test(val), { message: "Must be a valid JSON Pointer (RFC 6901)" })',
|
|
891
909
|
"relative-json-pointer": 'z.string().refine((val) => /^(0|[1-9]\\d*)(#|(\\/([^~/]|~0|~1)+)*)$/.test(val), { message: "Must be a valid relative JSON Pointer" })'
|
|
892
910
|
};
|
|
911
|
+
var FORMAT_MAP = {
|
|
912
|
+
...DEFAULT_FORMAT_MAP,
|
|
913
|
+
"date-time": "z.iso.datetime()"
|
|
914
|
+
};
|
|
915
|
+
function configureDateTimeFormat(pattern) {
|
|
916
|
+
if (!pattern) {
|
|
917
|
+
FORMAT_MAP["date-time"] = "z.iso.datetime()";
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
const patternStr = pattern instanceof RegExp ? pattern.source : pattern;
|
|
921
|
+
if (patternStr === "") {
|
|
922
|
+
FORMAT_MAP["date-time"] = "z.iso.datetime()";
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
try {
|
|
926
|
+
new RegExp(patternStr);
|
|
927
|
+
} catch (error) {
|
|
928
|
+
throw new Error(
|
|
929
|
+
`Invalid regular expression pattern for customDateTimeFormatRegex: ${patternStr}. ${error instanceof Error ? error.message : "Pattern is malformed"}`
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
const escapedPattern = escapePattern(patternStr);
|
|
933
|
+
FORMAT_MAP["date-time"] = `z.string().regex(/${escapedPattern}/)`;
|
|
934
|
+
}
|
|
893
935
|
function generateStringValidation(schema, useDescribe) {
|
|
894
936
|
let validation = FORMAT_MAP[schema.format || ""] || "z.string()";
|
|
895
937
|
if (schema.minLength !== void 0) {
|
|
@@ -1179,7 +1221,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
1179
1221
|
if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
|
|
1180
1222
|
schema = this.filterNestedProperties(schema);
|
|
1181
1223
|
}
|
|
1182
|
-
const
|
|
1224
|
+
const effectiveDefaultNullable = isTopLevel ? false : this.context.defaultNullable;
|
|
1225
|
+
const nullable = isNullable(schema, effectiveDefaultNullable);
|
|
1183
1226
|
if (hasMultipleTypes(schema)) {
|
|
1184
1227
|
const union = this.generateMultiTypeUnion(schema, currentSchema);
|
|
1185
1228
|
return wrapNullable(union, nullable);
|
|
@@ -1498,7 +1541,7 @@ var OpenApiGenerator = class {
|
|
|
1498
1541
|
this.schemaUsageMap = /* @__PURE__ */ new Map();
|
|
1499
1542
|
this.needsZodImport = true;
|
|
1500
1543
|
this.filterStats = createFilterStatistics();
|
|
1501
|
-
var _a, _b, _c, _d, _e;
|
|
1544
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1502
1545
|
if (!options.input) {
|
|
1503
1546
|
throw new ConfigurationError("Input path is required", { providedOptions: options });
|
|
1504
1547
|
}
|
|
@@ -1508,21 +1551,27 @@ var OpenApiGenerator = class {
|
|
|
1508
1551
|
output: options.output,
|
|
1509
1552
|
includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
|
|
1510
1553
|
useDescribe: (_b = options.useDescribe) != null ? _b : false,
|
|
1554
|
+
defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
|
|
1511
1555
|
schemaType: options.schemaType || "all",
|
|
1512
1556
|
prefix: options.prefix,
|
|
1513
1557
|
suffix: options.suffix,
|
|
1514
1558
|
stripSchemaPrefix: options.stripSchemaPrefix,
|
|
1515
|
-
|
|
1559
|
+
stripPathPrefix: options.stripPathPrefix,
|
|
1560
|
+
showStats: (_d = options.showStats) != null ? _d : true,
|
|
1516
1561
|
request: options.request,
|
|
1517
1562
|
response: options.response,
|
|
1518
1563
|
operationFilters: options.operationFilters,
|
|
1519
1564
|
ignoreHeaders: options.ignoreHeaders,
|
|
1520
|
-
cacheSize: (
|
|
1521
|
-
batchSize: (
|
|
1565
|
+
cacheSize: (_e = options.cacheSize) != null ? _e : 1e3,
|
|
1566
|
+
batchSize: (_f = options.batchSize) != null ? _f : 10,
|
|
1567
|
+
customDateTimeFormatRegex: options.customDateTimeFormatRegex
|
|
1522
1568
|
};
|
|
1523
1569
|
if (this.options.cacheSize) {
|
|
1524
1570
|
configurePatternCache(this.options.cacheSize);
|
|
1525
1571
|
}
|
|
1572
|
+
if (this.options.customDateTimeFormatRegex) {
|
|
1573
|
+
configureDateTimeFormat(this.options.customDateTimeFormatRegex);
|
|
1574
|
+
}
|
|
1526
1575
|
try {
|
|
1527
1576
|
const fs = __require("fs");
|
|
1528
1577
|
if (!fs.existsSync(this.options.input)) {
|
|
@@ -1585,6 +1634,7 @@ var OpenApiGenerator = class {
|
|
|
1585
1634
|
mode: this.requestOptions.mode,
|
|
1586
1635
|
includeDescriptions: this.requestOptions.includeDescriptions,
|
|
1587
1636
|
useDescribe: this.requestOptions.useDescribe,
|
|
1637
|
+
defaultNullable: (_g = this.options.defaultNullable) != null ? _g : false,
|
|
1588
1638
|
namingOptions: {
|
|
1589
1639
|
prefix: this.options.prefix,
|
|
1590
1640
|
suffix: this.options.suffix
|
|
@@ -1938,7 +1988,7 @@ var OpenApiGenerator = class {
|
|
|
1938
1988
|
* Generate schema for a component
|
|
1939
1989
|
*/
|
|
1940
1990
|
generateComponentSchema(name, schema) {
|
|
1941
|
-
var _a, _b;
|
|
1991
|
+
var _a, _b, _c;
|
|
1942
1992
|
if (!this.schemaDependencies.has(name)) {
|
|
1943
1993
|
this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
|
|
1944
1994
|
}
|
|
@@ -1970,14 +2020,14 @@ ${typeCode}`;
|
|
|
1970
2020
|
mode: resolvedOptions.mode,
|
|
1971
2021
|
includeDescriptions: resolvedOptions.includeDescriptions,
|
|
1972
2022
|
useDescribe: resolvedOptions.useDescribe,
|
|
2023
|
+
defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
|
|
1973
2024
|
namingOptions: {
|
|
1974
2025
|
prefix: this.options.prefix,
|
|
1975
2026
|
suffix: this.options.suffix
|
|
1976
2027
|
},
|
|
1977
2028
|
stripSchemaPrefix: this.options.stripSchemaPrefix
|
|
1978
2029
|
});
|
|
1979
|
-
const
|
|
1980
|
-
const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, isAlias);
|
|
2030
|
+
const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, true);
|
|
1981
2031
|
const zodSchemaCode = `${jsdoc}export const ${schemaName} = ${zodSchema};`;
|
|
1982
2032
|
if (zodSchema.includes("z.discriminatedUnion(")) {
|
|
1983
2033
|
const match = zodSchema.match(/z\.discriminatedUnion\([^,]+,\s*\[([^\]]+)\]/);
|
|
@@ -1987,7 +2037,7 @@ ${typeCode}`;
|
|
|
1987
2037
|
const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
|
|
1988
2038
|
if (depMatch) {
|
|
1989
2039
|
const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
|
|
1990
|
-
(
|
|
2040
|
+
(_c = this.schemaDependencies.get(name)) == null ? void 0 : _c.add(depName);
|
|
1991
2041
|
}
|
|
1992
2042
|
}
|
|
1993
2043
|
}
|
|
@@ -2011,7 +2061,7 @@ ${typeCode}`;
|
|
|
2011
2061
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2012
2062
|
continue;
|
|
2013
2063
|
}
|
|
2014
|
-
if (!operation.
|
|
2064
|
+
if (!operation.parameters || !Array.isArray(operation.parameters)) {
|
|
2015
2065
|
continue;
|
|
2016
2066
|
}
|
|
2017
2067
|
const queryParams = operation.parameters.filter(
|
|
@@ -2020,7 +2070,13 @@ ${typeCode}`;
|
|
|
2020
2070
|
if (queryParams.length === 0) {
|
|
2021
2071
|
continue;
|
|
2022
2072
|
}
|
|
2023
|
-
|
|
2073
|
+
let pascalOperationId;
|
|
2074
|
+
if (operation.operationId) {
|
|
2075
|
+
pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
|
|
2076
|
+
} else {
|
|
2077
|
+
const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
|
|
2078
|
+
pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
|
|
2079
|
+
}
|
|
2024
2080
|
const schemaName = `${pascalOperationId}QueryParams`;
|
|
2025
2081
|
if (!this.schemaDependencies.has(schemaName)) {
|
|
2026
2082
|
this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
|
|
@@ -2068,8 +2124,9 @@ ${propsCode}
|
|
|
2068
2124
|
const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
|
|
2069
2125
|
const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
|
|
2070
2126
|
const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}QueryParamsSchema`;
|
|
2127
|
+
const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
|
|
2071
2128
|
const jsdoc = `/**
|
|
2072
|
-
* Query parameters for ${
|
|
2129
|
+
* Query parameters for ${jsdocOperationName}
|
|
2073
2130
|
*/
|
|
2074
2131
|
`;
|
|
2075
2132
|
const fullSchemaCode = `${jsdoc}export const ${camelCaseSchemaName} = ${schemaCode};`;
|
|
@@ -2078,6 +2135,35 @@ ${propsCode}
|
|
|
2078
2135
|
}
|
|
2079
2136
|
}
|
|
2080
2137
|
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Generate a PascalCase method name from HTTP method and path
|
|
2140
|
+
* Used as fallback when operationId is not available
|
|
2141
|
+
* @internal
|
|
2142
|
+
*/
|
|
2143
|
+
generateMethodNameFromPath(method, path) {
|
|
2144
|
+
const segments = path.split("/").filter(Boolean).map((segment) => {
|
|
2145
|
+
if (segment.startsWith("{") && segment.endsWith("}")) {
|
|
2146
|
+
const paramName = segment.slice(1, -1);
|
|
2147
|
+
return `By${this.capitalizeSegment(paramName)}`;
|
|
2148
|
+
}
|
|
2149
|
+
return this.capitalizeSegment(segment);
|
|
2150
|
+
}).join("");
|
|
2151
|
+
const capitalizedMethod = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
|
|
2152
|
+
return `${capitalizedMethod}${segments}`;
|
|
2153
|
+
}
|
|
2154
|
+
/**
|
|
2155
|
+
* Capitalizes a path segment, handling special characters like dashes, underscores, and dots
|
|
2156
|
+
* @internal
|
|
2157
|
+
*/
|
|
2158
|
+
capitalizeSegment(str) {
|
|
2159
|
+
if (str.includes("-") || str.includes("_") || str.includes(".")) {
|
|
2160
|
+
return str.split(/[-_.]/).map((part) => {
|
|
2161
|
+
if (!part) return "";
|
|
2162
|
+
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
|
|
2163
|
+
}).join("");
|
|
2164
|
+
}
|
|
2165
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
2166
|
+
}
|
|
2081
2167
|
/**
|
|
2082
2168
|
* Check if a header should be ignored based on filter patterns
|
|
2083
2169
|
* @internal
|
|
@@ -2114,7 +2200,7 @@ ${propsCode}
|
|
|
2114
2200
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
2115
2201
|
continue;
|
|
2116
2202
|
}
|
|
2117
|
-
if (!operation.
|
|
2203
|
+
if (!operation.parameters || !Array.isArray(operation.parameters)) {
|
|
2118
2204
|
continue;
|
|
2119
2205
|
}
|
|
2120
2206
|
const headerParams = operation.parameters.filter(
|
|
@@ -2123,7 +2209,13 @@ ${propsCode}
|
|
|
2123
2209
|
if (headerParams.length === 0) {
|
|
2124
2210
|
continue;
|
|
2125
2211
|
}
|
|
2126
|
-
|
|
2212
|
+
let pascalOperationId;
|
|
2213
|
+
if (operation.operationId) {
|
|
2214
|
+
pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
|
|
2215
|
+
} else {
|
|
2216
|
+
const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
|
|
2217
|
+
pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
|
|
2218
|
+
}
|
|
2127
2219
|
const schemaName = `${pascalOperationId}HeaderParams`;
|
|
2128
2220
|
if (!this.schemaDependencies.has(schemaName)) {
|
|
2129
2221
|
this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
|
|
@@ -2160,8 +2252,9 @@ ${propsCode}
|
|
|
2160
2252
|
const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
|
|
2161
2253
|
const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
|
|
2162
2254
|
const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}HeaderParamsSchema`;
|
|
2255
|
+
const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
|
|
2163
2256
|
const jsdoc = `/**
|
|
2164
|
-
* Header parameters for ${
|
|
2257
|
+
* Header parameters for ${jsdocOperationName}
|
|
2165
2258
|
*/
|
|
2166
2259
|
`;
|
|
2167
2260
|
const fullSchemaCode = `${jsdoc}export const ${camelCaseSchemaName} = ${schemaCode};`;
|