@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/README.md
CHANGED
|
@@ -184,6 +184,7 @@ Examples:
|
|
|
184
184
|
| `mode` | `"strict"` \| `"normal"` \| `"loose"` | Validation mode |
|
|
185
185
|
| `includeDescriptions` | `boolean` | Include JSDoc comments |
|
|
186
186
|
| `useDescribe` | `boolean` | Add `.describe()` calls |
|
|
187
|
+
| `defaultNullable` | `boolean` | Treat properties as nullable by default when not explicitly specified (default: `false`) |
|
|
187
188
|
| `schemaType` | `"all"` \| `"request"` \| `"response"` | Schema filtering |
|
|
188
189
|
| `prefix` | `string` | Prefix for schema names |
|
|
189
190
|
| `suffix` | `string` | Suffix for schema names |
|
|
@@ -410,6 +411,68 @@ The generator supports all OpenAPI string formats with Zod v4:
|
|
|
410
411
|
| `cidrv4` | `z.cidrv4()` |
|
|
411
412
|
| `cidrv6` | `z.cidrv6()` |
|
|
412
413
|
|
|
414
|
+
### Custom Date-Time Format
|
|
415
|
+
|
|
416
|
+
By default, the generator uses `z.iso.datetime()` for `date-time` format fields, which requires an ISO 8601 datetime string with a timezone suffix (e.g., `2026-01-07T14:30:00Z`).
|
|
417
|
+
|
|
418
|
+
If your API returns date-times **without the `Z` suffix** (e.g., `2026-01-07T14:30:00`), you can override this with a custom regex pattern:
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
import { defineConfig } from '@cerios/openapi-to-zod';
|
|
422
|
+
|
|
423
|
+
export default defineConfig({
|
|
424
|
+
defaults: {
|
|
425
|
+
// For date-times without Z suffix
|
|
426
|
+
customDateTimeFormatRegex: '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$',
|
|
427
|
+
},
|
|
428
|
+
specs: [
|
|
429
|
+
{
|
|
430
|
+
input: 'openapi.yaml',
|
|
431
|
+
output: 'src/schemas.ts',
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
});
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**TypeScript Config - RegExp Literals:**
|
|
438
|
+
|
|
439
|
+
In TypeScript config files, you can also use RegExp literals (which don't require double-escaping):
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
export default defineConfig({
|
|
443
|
+
defaults: {
|
|
444
|
+
// Use RegExp literal (single escaping)
|
|
445
|
+
customDateTimeFormatRegex: /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/,
|
|
446
|
+
},
|
|
447
|
+
specs: [
|
|
448
|
+
{
|
|
449
|
+
input: 'openapi.yaml',
|
|
450
|
+
output: 'src/schemas.ts',
|
|
451
|
+
},
|
|
452
|
+
],
|
|
453
|
+
});
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Common Custom Formats:**
|
|
457
|
+
|
|
458
|
+
| Use Case | String Pattern (JSON/YAML) | RegExp Literal (TypeScript) |
|
|
459
|
+
|----------|----------------------------|----------------------------|
|
|
460
|
+
| No timezone suffix<br>`2026-01-07T14:30:00` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/` |
|
|
461
|
+
| With milliseconds, no Z<br>`2026-01-07T14:30:00.123` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}$/` |
|
|
462
|
+
| Optional Z suffix<br>`2026-01-07T14:30:00` or<br>`2026-01-07T14:30:00Z` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z?$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z?$/` |
|
|
463
|
+
| With milliseconds + optional Z<br>`2026-01-07T14:30:00.123Z` | `'^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z?$'` | `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z?$/` |
|
|
464
|
+
|
|
465
|
+
**Generated Output:**
|
|
466
|
+
|
|
467
|
+
When using a custom regex, the generator will produce:
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
// Instead of: z.iso.datetime()
|
|
471
|
+
// You get: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**Note:** This option only affects `date-time` format fields. Other formats (like `date`, `email`, `uuid`) remain unchanged.
|
|
475
|
+
|
|
413
476
|
## Advanced Features
|
|
414
477
|
|
|
415
478
|
### Operation Filtering
|
|
@@ -563,6 +626,68 @@ export const userSchema = z.object({
|
|
|
563
626
|
|
|
564
627
|
OpenAPI's `nullable: true` is converted to `.nullable()`
|
|
565
628
|
|
|
629
|
+
#### Default Nullable Behavior
|
|
630
|
+
|
|
631
|
+
By default, properties are only nullable when explicitly marked with `nullable: true` (OpenAPI 3.0) or `type: ["string", "null"]` (OpenAPI 3.1).
|
|
632
|
+
|
|
633
|
+
However, many teams follow the industry de facto standard for OpenAPI 3.0.x where properties are assumed nullable unless explicitly constrained. You can enable this behavior with the `defaultNullable` option:
|
|
634
|
+
|
|
635
|
+
```typescript
|
|
636
|
+
export default defineConfig({
|
|
637
|
+
specs: [{
|
|
638
|
+
input: 'openapi.yaml',
|
|
639
|
+
output: 'schemas.ts',
|
|
640
|
+
defaultNullable: true, // Treat unspecified properties as nullable
|
|
641
|
+
}]
|
|
642
|
+
});
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
**Behavior comparison:**
|
|
646
|
+
|
|
647
|
+
| Schema Property | `defaultNullable: false` (default) | `defaultNullable: true` |
|
|
648
|
+
|-----------------|-------------------------------------|-------------------------|
|
|
649
|
+
| `nullable: true` | `.nullable()` | `.nullable()` |
|
|
650
|
+
| `nullable: false` | No `.nullable()` | No `.nullable()` |
|
|
651
|
+
| No `nullable` specified | No `.nullable()` | `.nullable()` |
|
|
652
|
+
|
|
653
|
+
**Example:**
|
|
654
|
+
|
|
655
|
+
```yaml
|
|
656
|
+
User:
|
|
657
|
+
type: object
|
|
658
|
+
properties:
|
|
659
|
+
id:
|
|
660
|
+
type: integer
|
|
661
|
+
name:
|
|
662
|
+
type: string
|
|
663
|
+
email:
|
|
664
|
+
type: string
|
|
665
|
+
nullable: true
|
|
666
|
+
phone:
|
|
667
|
+
type: string
|
|
668
|
+
nullable: false
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
**With `defaultNullable: false` (default):**
|
|
672
|
+
```typescript
|
|
673
|
+
export const userSchema = z.object({
|
|
674
|
+
id: z.number().int(),
|
|
675
|
+
name: z.string(), // Not nullable (no annotation)
|
|
676
|
+
email: z.string().nullable(), // Explicitly nullable
|
|
677
|
+
phone: z.string(), // Explicitly not nullable
|
|
678
|
+
});
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
**With `defaultNullable: true`:**
|
|
682
|
+
```typescript
|
|
683
|
+
export const userSchema = z.object({
|
|
684
|
+
id: z.number().int().nullable(), // Nullable by default
|
|
685
|
+
name: z.string().nullable(), // Nullable by default
|
|
686
|
+
email: z.string().nullable(), // Explicitly nullable
|
|
687
|
+
phone: z.string(), // Explicitly NOT nullable (respected)
|
|
688
|
+
});
|
|
689
|
+
```
|
|
690
|
+
|
|
566
691
|
### Schema Composition
|
|
567
692
|
|
|
568
693
|
- `allOf` → `.merge()` for objects, `.and()` for primitives
|
package/dist/cli.js
CHANGED
|
@@ -5233,14 +5233,17 @@ function escapeJSDoc(str) {
|
|
|
5233
5233
|
function wrapNullable(validation, isNullable2) {
|
|
5234
5234
|
return isNullable2 ? `${validation}.nullable()` : validation;
|
|
5235
5235
|
}
|
|
5236
|
-
function isNullable(schema) {
|
|
5236
|
+
function isNullable(schema, defaultNullable = false) {
|
|
5237
5237
|
if (schema.nullable === true) {
|
|
5238
5238
|
return true;
|
|
5239
5239
|
}
|
|
5240
|
+
if (schema.nullable === false) {
|
|
5241
|
+
return false;
|
|
5242
|
+
}
|
|
5240
5243
|
if (Array.isArray(schema.type)) {
|
|
5241
5244
|
return schema.type.includes("null");
|
|
5242
5245
|
}
|
|
5243
|
-
return
|
|
5246
|
+
return defaultNullable;
|
|
5244
5247
|
}
|
|
5245
5248
|
function getPrimaryType(schema) {
|
|
5246
5249
|
if (Array.isArray(schema.type)) {
|
|
@@ -5411,6 +5414,22 @@ function stripPrefix(input, pattern, ensureLeadingChar) {
|
|
|
5411
5414
|
}
|
|
5412
5415
|
return input;
|
|
5413
5416
|
}
|
|
5417
|
+
function stripPathPrefix(path, pattern) {
|
|
5418
|
+
if (!pattern) {
|
|
5419
|
+
return path;
|
|
5420
|
+
}
|
|
5421
|
+
if (!isGlobPattern(pattern)) {
|
|
5422
|
+
let normalizedPattern = pattern.trim();
|
|
5423
|
+
if (!normalizedPattern.startsWith("/")) {
|
|
5424
|
+
normalizedPattern = `/${normalizedPattern}`;
|
|
5425
|
+
}
|
|
5426
|
+
if (normalizedPattern.endsWith("/") && normalizedPattern !== "/") {
|
|
5427
|
+
normalizedPattern = normalizedPattern.slice(0, -1);
|
|
5428
|
+
}
|
|
5429
|
+
return stripPrefix(path, normalizedPattern, "/");
|
|
5430
|
+
}
|
|
5431
|
+
return stripPrefix(path, pattern, "/");
|
|
5432
|
+
}
|
|
5414
5433
|
|
|
5415
5434
|
// src/validators/array-validator.ts
|
|
5416
5435
|
init_cjs_shims();
|
|
@@ -5944,7 +5963,7 @@ function configurePatternCache(size) {
|
|
|
5944
5963
|
PATTERN_CACHE = new LRUCache(size);
|
|
5945
5964
|
}
|
|
5946
5965
|
}
|
|
5947
|
-
var
|
|
5966
|
+
var DEFAULT_FORMAT_MAP = {
|
|
5948
5967
|
uuid: "z.uuid()",
|
|
5949
5968
|
email: "z.email()",
|
|
5950
5969
|
uri: "z.url()",
|
|
@@ -5954,7 +5973,6 @@ var FORMAT_MAP = {
|
|
|
5954
5973
|
byte: "z.base64()",
|
|
5955
5974
|
binary: "z.string()",
|
|
5956
5975
|
date: "z.iso.date()",
|
|
5957
|
-
"date-time": "z.iso.datetime()",
|
|
5958
5976
|
time: "z.iso.time()",
|
|
5959
5977
|
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" })',
|
|
5960
5978
|
ipv4: "z.ipv4()",
|
|
@@ -5973,6 +5991,30 @@ var FORMAT_MAP = {
|
|
|
5973
5991
|
"json-pointer": 'z.string().refine((val) => val === "" || /^(\\/([^~/]|~0|~1)+)+$/.test(val), { message: "Must be a valid JSON Pointer (RFC 6901)" })',
|
|
5974
5992
|
"relative-json-pointer": 'z.string().refine((val) => /^(0|[1-9]\\d*)(#|(\\/([^~/]|~0|~1)+)*)$/.test(val), { message: "Must be a valid relative JSON Pointer" })'
|
|
5975
5993
|
};
|
|
5994
|
+
var FORMAT_MAP = {
|
|
5995
|
+
...DEFAULT_FORMAT_MAP,
|
|
5996
|
+
"date-time": "z.iso.datetime()"
|
|
5997
|
+
};
|
|
5998
|
+
function configureDateTimeFormat(pattern) {
|
|
5999
|
+
if (!pattern) {
|
|
6000
|
+
FORMAT_MAP["date-time"] = "z.iso.datetime()";
|
|
6001
|
+
return;
|
|
6002
|
+
}
|
|
6003
|
+
const patternStr = pattern instanceof RegExp ? pattern.source : pattern;
|
|
6004
|
+
if (patternStr === "") {
|
|
6005
|
+
FORMAT_MAP["date-time"] = "z.iso.datetime()";
|
|
6006
|
+
return;
|
|
6007
|
+
}
|
|
6008
|
+
try {
|
|
6009
|
+
new RegExp(patternStr);
|
|
6010
|
+
} catch (error) {
|
|
6011
|
+
throw new Error(
|
|
6012
|
+
`Invalid regular expression pattern for customDateTimeFormatRegex: ${patternStr}. ${error instanceof Error ? error.message : "Pattern is malformed"}`
|
|
6013
|
+
);
|
|
6014
|
+
}
|
|
6015
|
+
const escapedPattern = escapePattern(patternStr);
|
|
6016
|
+
FORMAT_MAP["date-time"] = `z.string().regex(/${escapedPattern}/)`;
|
|
6017
|
+
}
|
|
5976
6018
|
function generateStringValidation(schema, useDescribe) {
|
|
5977
6019
|
let validation = FORMAT_MAP[schema.format || ""] || "z.string()";
|
|
5978
6020
|
if (schema.minLength !== void 0) {
|
|
@@ -6262,7 +6304,8 @@ var _PropertyGenerator = class _PropertyGenerator {
|
|
|
6262
6304
|
if ((this.context.schemaType === "request" || this.context.schemaType === "response") && schema.properties) {
|
|
6263
6305
|
schema = this.filterNestedProperties(schema);
|
|
6264
6306
|
}
|
|
6265
|
-
const
|
|
6307
|
+
const effectiveDefaultNullable = isTopLevel ? false : this.context.defaultNullable;
|
|
6308
|
+
const nullable = isNullable(schema, effectiveDefaultNullable);
|
|
6266
6309
|
if (hasMultipleTypes(schema)) {
|
|
6267
6310
|
const union = this.generateMultiTypeUnion(schema, currentSchema);
|
|
6268
6311
|
return wrapNullable(union, nullable);
|
|
@@ -6582,7 +6625,7 @@ var OpenApiGenerator = class {
|
|
|
6582
6625
|
this.schemaUsageMap = /* @__PURE__ */ new Map();
|
|
6583
6626
|
this.needsZodImport = true;
|
|
6584
6627
|
this.filterStats = createFilterStatistics();
|
|
6585
|
-
var _a, _b, _c, _d, _e;
|
|
6628
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6586
6629
|
if (!options.input) {
|
|
6587
6630
|
throw new ConfigurationError("Input path is required", { providedOptions: options });
|
|
6588
6631
|
}
|
|
@@ -6592,21 +6635,27 @@ var OpenApiGenerator = class {
|
|
|
6592
6635
|
output: options.output,
|
|
6593
6636
|
includeDescriptions: (_a = options.includeDescriptions) != null ? _a : true,
|
|
6594
6637
|
useDescribe: (_b = options.useDescribe) != null ? _b : false,
|
|
6638
|
+
defaultNullable: (_c = options.defaultNullable) != null ? _c : false,
|
|
6595
6639
|
schemaType: options.schemaType || "all",
|
|
6596
6640
|
prefix: options.prefix,
|
|
6597
6641
|
suffix: options.suffix,
|
|
6598
6642
|
stripSchemaPrefix: options.stripSchemaPrefix,
|
|
6599
|
-
|
|
6643
|
+
stripPathPrefix: options.stripPathPrefix,
|
|
6644
|
+
showStats: (_d = options.showStats) != null ? _d : true,
|
|
6600
6645
|
request: options.request,
|
|
6601
6646
|
response: options.response,
|
|
6602
6647
|
operationFilters: options.operationFilters,
|
|
6603
6648
|
ignoreHeaders: options.ignoreHeaders,
|
|
6604
|
-
cacheSize: (
|
|
6605
|
-
batchSize: (
|
|
6649
|
+
cacheSize: (_e = options.cacheSize) != null ? _e : 1e3,
|
|
6650
|
+
batchSize: (_f = options.batchSize) != null ? _f : 10,
|
|
6651
|
+
customDateTimeFormatRegex: options.customDateTimeFormatRegex
|
|
6606
6652
|
};
|
|
6607
6653
|
if (this.options.cacheSize) {
|
|
6608
6654
|
configurePatternCache(this.options.cacheSize);
|
|
6609
6655
|
}
|
|
6656
|
+
if (this.options.customDateTimeFormatRegex) {
|
|
6657
|
+
configureDateTimeFormat(this.options.customDateTimeFormatRegex);
|
|
6658
|
+
}
|
|
6610
6659
|
try {
|
|
6611
6660
|
const fs = require("fs");
|
|
6612
6661
|
if (!fs.existsSync(this.options.input)) {
|
|
@@ -6669,6 +6718,7 @@ var OpenApiGenerator = class {
|
|
|
6669
6718
|
mode: this.requestOptions.mode,
|
|
6670
6719
|
includeDescriptions: this.requestOptions.includeDescriptions,
|
|
6671
6720
|
useDescribe: this.requestOptions.useDescribe,
|
|
6721
|
+
defaultNullable: (_g = this.options.defaultNullable) != null ? _g : false,
|
|
6672
6722
|
namingOptions: {
|
|
6673
6723
|
prefix: this.options.prefix,
|
|
6674
6724
|
suffix: this.options.suffix
|
|
@@ -7022,7 +7072,7 @@ var OpenApiGenerator = class {
|
|
|
7022
7072
|
* Generate schema for a component
|
|
7023
7073
|
*/
|
|
7024
7074
|
generateComponentSchema(name, schema) {
|
|
7025
|
-
var _a, _b;
|
|
7075
|
+
var _a, _b, _c;
|
|
7026
7076
|
if (!this.schemaDependencies.has(name)) {
|
|
7027
7077
|
this.schemaDependencies.set(name, /* @__PURE__ */ new Set());
|
|
7028
7078
|
}
|
|
@@ -7054,14 +7104,14 @@ ${typeCode}`;
|
|
|
7054
7104
|
mode: resolvedOptions.mode,
|
|
7055
7105
|
includeDescriptions: resolvedOptions.includeDescriptions,
|
|
7056
7106
|
useDescribe: resolvedOptions.useDescribe,
|
|
7107
|
+
defaultNullable: (_b = this.options.defaultNullable) != null ? _b : false,
|
|
7057
7108
|
namingOptions: {
|
|
7058
7109
|
prefix: this.options.prefix,
|
|
7059
7110
|
suffix: this.options.suffix
|
|
7060
7111
|
},
|
|
7061
7112
|
stripSchemaPrefix: this.options.stripSchemaPrefix
|
|
7062
7113
|
});
|
|
7063
|
-
const
|
|
7064
|
-
const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, isAlias);
|
|
7114
|
+
const zodSchema = this.propertyGenerator.generatePropertySchema(schema, name, true);
|
|
7065
7115
|
const zodSchemaCode = `${jsdoc}export const ${schemaName} = ${zodSchema};`;
|
|
7066
7116
|
if (zodSchema.includes("z.discriminatedUnion(")) {
|
|
7067
7117
|
const match = zodSchema.match(/z\.discriminatedUnion\([^,]+,\s*\[([^\]]+)\]/);
|
|
@@ -7071,7 +7121,7 @@ ${typeCode}`;
|
|
|
7071
7121
|
const depMatch = ref.match(/^([a-z][a-zA-Z0-9]*?)Schema$/);
|
|
7072
7122
|
if (depMatch) {
|
|
7073
7123
|
const depName = depMatch[1].charAt(0).toUpperCase() + depMatch[1].slice(1);
|
|
7074
|
-
(
|
|
7124
|
+
(_c = this.schemaDependencies.get(name)) == null ? void 0 : _c.add(depName);
|
|
7075
7125
|
}
|
|
7076
7126
|
}
|
|
7077
7127
|
}
|
|
@@ -7095,7 +7145,7 @@ ${typeCode}`;
|
|
|
7095
7145
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
7096
7146
|
continue;
|
|
7097
7147
|
}
|
|
7098
|
-
if (!operation.
|
|
7148
|
+
if (!operation.parameters || !Array.isArray(operation.parameters)) {
|
|
7099
7149
|
continue;
|
|
7100
7150
|
}
|
|
7101
7151
|
const queryParams = operation.parameters.filter(
|
|
@@ -7104,7 +7154,13 @@ ${typeCode}`;
|
|
|
7104
7154
|
if (queryParams.length === 0) {
|
|
7105
7155
|
continue;
|
|
7106
7156
|
}
|
|
7107
|
-
|
|
7157
|
+
let pascalOperationId;
|
|
7158
|
+
if (operation.operationId) {
|
|
7159
|
+
pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
|
|
7160
|
+
} else {
|
|
7161
|
+
const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
|
|
7162
|
+
pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
|
|
7163
|
+
}
|
|
7108
7164
|
const schemaName = `${pascalOperationId}QueryParams`;
|
|
7109
7165
|
if (!this.schemaDependencies.has(schemaName)) {
|
|
7110
7166
|
this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
|
|
@@ -7152,8 +7208,9 @@ ${propsCode}
|
|
|
7152
7208
|
const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
|
|
7153
7209
|
const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
|
|
7154
7210
|
const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}QueryParamsSchema`;
|
|
7211
|
+
const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
|
|
7155
7212
|
const jsdoc = `/**
|
|
7156
|
-
* Query parameters for ${
|
|
7213
|
+
* Query parameters for ${jsdocOperationName}
|
|
7157
7214
|
*/
|
|
7158
7215
|
`;
|
|
7159
7216
|
const fullSchemaCode = `${jsdoc}export const ${camelCaseSchemaName} = ${schemaCode};`;
|
|
@@ -7162,6 +7219,35 @@ ${propsCode}
|
|
|
7162
7219
|
}
|
|
7163
7220
|
}
|
|
7164
7221
|
}
|
|
7222
|
+
/**
|
|
7223
|
+
* Generate a PascalCase method name from HTTP method and path
|
|
7224
|
+
* Used as fallback when operationId is not available
|
|
7225
|
+
* @internal
|
|
7226
|
+
*/
|
|
7227
|
+
generateMethodNameFromPath(method, path) {
|
|
7228
|
+
const segments = path.split("/").filter(Boolean).map((segment) => {
|
|
7229
|
+
if (segment.startsWith("{") && segment.endsWith("}")) {
|
|
7230
|
+
const paramName = segment.slice(1, -1);
|
|
7231
|
+
return `By${this.capitalizeSegment(paramName)}`;
|
|
7232
|
+
}
|
|
7233
|
+
return this.capitalizeSegment(segment);
|
|
7234
|
+
}).join("");
|
|
7235
|
+
const capitalizedMethod = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
|
|
7236
|
+
return `${capitalizedMethod}${segments}`;
|
|
7237
|
+
}
|
|
7238
|
+
/**
|
|
7239
|
+
* Capitalizes a path segment, handling special characters like dashes, underscores, and dots
|
|
7240
|
+
* @internal
|
|
7241
|
+
*/
|
|
7242
|
+
capitalizeSegment(str) {
|
|
7243
|
+
if (str.includes("-") || str.includes("_") || str.includes(".")) {
|
|
7244
|
+
return str.split(/[-_.]/).map((part) => {
|
|
7245
|
+
if (!part) return "";
|
|
7246
|
+
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
|
|
7247
|
+
}).join("");
|
|
7248
|
+
}
|
|
7249
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
7250
|
+
}
|
|
7165
7251
|
/**
|
|
7166
7252
|
* Check if a header should be ignored based on filter patterns
|
|
7167
7253
|
* @internal
|
|
@@ -7198,7 +7284,7 @@ ${propsCode}
|
|
|
7198
7284
|
if (!shouldIncludeOperation(operation, path, method, this.options.operationFilters)) {
|
|
7199
7285
|
continue;
|
|
7200
7286
|
}
|
|
7201
|
-
if (!operation.
|
|
7287
|
+
if (!operation.parameters || !Array.isArray(operation.parameters)) {
|
|
7202
7288
|
continue;
|
|
7203
7289
|
}
|
|
7204
7290
|
const headerParams = operation.parameters.filter(
|
|
@@ -7207,7 +7293,13 @@ ${propsCode}
|
|
|
7207
7293
|
if (headerParams.length === 0) {
|
|
7208
7294
|
continue;
|
|
7209
7295
|
}
|
|
7210
|
-
|
|
7296
|
+
let pascalOperationId;
|
|
7297
|
+
if (operation.operationId) {
|
|
7298
|
+
pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
|
|
7299
|
+
} else {
|
|
7300
|
+
const strippedPath = stripPathPrefix(path, this.options.stripPathPrefix);
|
|
7301
|
+
pascalOperationId = this.generateMethodNameFromPath(method, strippedPath);
|
|
7302
|
+
}
|
|
7211
7303
|
const schemaName = `${pascalOperationId}HeaderParams`;
|
|
7212
7304
|
if (!this.schemaDependencies.has(schemaName)) {
|
|
7213
7305
|
this.schemaDependencies.set(schemaName, /* @__PURE__ */ new Set());
|
|
@@ -7244,8 +7336,9 @@ ${propsCode}
|
|
|
7244
7336
|
const prefixedName = this.options.prefix ? `${toPascalCase(this.options.prefix)}${operationName}` : operationName;
|
|
7245
7337
|
const suffixedName = this.options.suffix ? `${prefixedName}${toPascalCase(this.options.suffix)}` : prefixedName;
|
|
7246
7338
|
const camelCaseSchemaName = `${suffixedName.charAt(0).toLowerCase() + suffixedName.slice(1)}HeaderParamsSchema`;
|
|
7339
|
+
const jsdocOperationName = operation.operationId || `${method.toUpperCase()} ${path}`;
|
|
7247
7340
|
const jsdoc = `/**
|
|
7248
|
-
* Header parameters for ${
|
|
7341
|
+
* Header parameters for ${jsdocOperationName}
|
|
7249
7342
|
*/
|
|
7250
7343
|
`;
|
|
7251
7344
|
const fullSchemaCode = `${jsdoc}export const ${camelCaseSchemaName} = ${schemaCode};`;
|
|
@@ -7425,7 +7518,8 @@ var import_zod = require("zod");
|
|
|
7425
7518
|
var RequestResponseOptionsSchema = import_zod.z.strictObject({
|
|
7426
7519
|
mode: import_zod.z.enum(["strict", "normal", "loose"]).optional(),
|
|
7427
7520
|
useDescribe: import_zod.z.boolean().optional(),
|
|
7428
|
-
includeDescriptions: import_zod.z.boolean().optional()
|
|
7521
|
+
includeDescriptions: import_zod.z.boolean().optional(),
|
|
7522
|
+
defaultNullable: import_zod.z.boolean().optional()
|
|
7429
7523
|
});
|
|
7430
7524
|
var OperationFiltersSchema = import_zod.z.strictObject({
|
|
7431
7525
|
includeTags: import_zod.z.array(import_zod.z.string()).optional(),
|
|
@@ -7508,6 +7602,7 @@ var OpenApiGeneratorOptionsSchema = import_zod2.z.strictObject({
|
|
|
7508
7602
|
output: import_zod2.z.string(),
|
|
7509
7603
|
includeDescriptions: import_zod2.z.boolean().optional(),
|
|
7510
7604
|
useDescribe: import_zod2.z.boolean().optional(),
|
|
7605
|
+
defaultNullable: import_zod2.z.boolean().optional(),
|
|
7511
7606
|
schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
|
|
7512
7607
|
prefix: import_zod2.z.string().optional(),
|
|
7513
7608
|
suffix: import_zod2.z.string().optional(),
|
|
@@ -7518,13 +7613,28 @@ var OpenApiGeneratorOptionsSchema = import_zod2.z.strictObject({
|
|
|
7518
7613
|
name: import_zod2.z.string().optional(),
|
|
7519
7614
|
operationFilters: OperationFiltersSchema.optional(),
|
|
7520
7615
|
cacheSize: import_zod2.z.number().positive().optional(),
|
|
7521
|
-
batchSize: import_zod2.z.number().positive().optional()
|
|
7616
|
+
batchSize: import_zod2.z.number().positive().optional(),
|
|
7617
|
+
customDateTimeFormatRegex: import_zod2.z.union([
|
|
7618
|
+
import_zod2.z.string().refine(
|
|
7619
|
+
(pattern) => {
|
|
7620
|
+
try {
|
|
7621
|
+
new RegExp(pattern);
|
|
7622
|
+
return true;
|
|
7623
|
+
} catch {
|
|
7624
|
+
return false;
|
|
7625
|
+
}
|
|
7626
|
+
},
|
|
7627
|
+
{ message: "Must be a valid regular expression pattern" }
|
|
7628
|
+
),
|
|
7629
|
+
import_zod2.z.instanceof(RegExp)
|
|
7630
|
+
]).optional()
|
|
7522
7631
|
});
|
|
7523
7632
|
var ConfigFileSchema = import_zod2.z.strictObject({
|
|
7524
7633
|
defaults: import_zod2.z.strictObject({
|
|
7525
7634
|
mode: import_zod2.z.enum(["strict", "normal", "loose"]).optional(),
|
|
7526
7635
|
includeDescriptions: import_zod2.z.boolean().optional(),
|
|
7527
7636
|
useDescribe: import_zod2.z.boolean().optional(),
|
|
7637
|
+
defaultNullable: import_zod2.z.boolean().optional(),
|
|
7528
7638
|
schemaType: import_zod2.z.enum(["all", "request", "response"]).optional(),
|
|
7529
7639
|
prefix: import_zod2.z.string().optional(),
|
|
7530
7640
|
suffix: import_zod2.z.string().optional(),
|
|
@@ -7534,7 +7644,21 @@ var ConfigFileSchema = import_zod2.z.strictObject({
|
|
|
7534
7644
|
response: RequestResponseOptionsSchema.optional(),
|
|
7535
7645
|
operationFilters: OperationFiltersSchema.optional(),
|
|
7536
7646
|
cacheSize: import_zod2.z.number().positive().optional(),
|
|
7537
|
-
batchSize: import_zod2.z.number().positive().optional()
|
|
7647
|
+
batchSize: import_zod2.z.number().positive().optional(),
|
|
7648
|
+
customDateTimeFormatRegex: import_zod2.z.union([
|
|
7649
|
+
import_zod2.z.string().refine(
|
|
7650
|
+
(pattern) => {
|
|
7651
|
+
try {
|
|
7652
|
+
new RegExp(pattern);
|
|
7653
|
+
return true;
|
|
7654
|
+
} catch {
|
|
7655
|
+
return false;
|
|
7656
|
+
}
|
|
7657
|
+
},
|
|
7658
|
+
{ message: "Must be a valid regular expression pattern" }
|
|
7659
|
+
),
|
|
7660
|
+
import_zod2.z.instanceof(RegExp)
|
|
7661
|
+
]).optional()
|
|
7538
7662
|
}).optional(),
|
|
7539
7663
|
specs: import_zod2.z.array(OpenApiGeneratorOptionsSchema).min(1, {
|
|
7540
7664
|
message: "Configuration must include at least one specification. Each specification should have 'input' and 'output' paths."
|
|
@@ -7583,10 +7707,12 @@ function mergeConfigWithDefaults(config) {
|
|
|
7583
7707
|
mode: defaults.mode,
|
|
7584
7708
|
includeDescriptions: defaults.includeDescriptions,
|
|
7585
7709
|
useDescribe: defaults.useDescribe,
|
|
7710
|
+
defaultNullable: defaults.defaultNullable,
|
|
7586
7711
|
schemaType: defaults.schemaType,
|
|
7587
7712
|
prefix: defaults.prefix,
|
|
7588
7713
|
suffix: defaults.suffix,
|
|
7589
7714
|
showStats: defaults.showStats,
|
|
7715
|
+
customDateTimeFormatRegex: defaults.customDateTimeFormatRegex,
|
|
7590
7716
|
// Override with spec-specific values (including required input/output)
|
|
7591
7717
|
...spec
|
|
7592
7718
|
};
|