@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 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 false;
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 FORMAT_MAP = {
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 nullable = isNullable(schema);
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
- showStats: (_c = options.showStats) != null ? _c : true,
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: (_d = options.cacheSize) != null ? _d : 1e3,
6605
- batchSize: (_e = options.batchSize) != null ? _e : 10
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 isAlias = !!(schema.$ref && !schema.properties && !schema.allOf && !schema.oneOf && !schema.anyOf);
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
- (_b = this.schemaDependencies.get(name)) == null ? void 0 : _b.add(depName);
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.operationId || !operation.parameters || !Array.isArray(operation.parameters)) {
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
- const pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
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 ${operation.operationId}
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.operationId || !operation.parameters || !Array.isArray(operation.parameters)) {
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
- const pascalOperationId = operation.operationId.includes("-") ? toPascalCase(operation.operationId) : operation.operationId.charAt(0).toUpperCase() + operation.operationId.slice(1);
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 ${operation.operationId}
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
  };