@zod-utils/core 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -1
- package/dist/index.d.mts +113 -3
- package/dist/index.d.ts +113 -3
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ npm install @zod-utils/core zod
|
|
|
24
24
|
|
|
25
25
|
- 🎯 **Extract defaults** - Get default values from Zod schemas
|
|
26
26
|
- ✅ **Check validation requirements** - Determine if fields will error on empty input
|
|
27
|
+
- 🔍 **Extract validation checks** - Get all validation constraints (min/max, formats, patterns, etc.)
|
|
27
28
|
- 🔧 **Schema utilities** - Unwrap and manipulate schema types
|
|
28
29
|
- 📦 **Zero dependencies** - Only requires Zod as a peer dependency
|
|
29
30
|
- 🌐 **Universal** - Works in Node.js, browsers, and any TypeScript project
|
|
@@ -173,17 +174,100 @@ withoutDefault.parse(undefined); // throws error
|
|
|
173
174
|
|
|
174
175
|
### `extractDefault(field)`
|
|
175
176
|
|
|
176
|
-
Extract the default value from a Zod field (recursively unwraps optional/nullable).
|
|
177
|
+
Extract the default value from a Zod field (recursively unwraps optional/nullable/union layers).
|
|
178
|
+
|
|
179
|
+
**Union handling:** For union types, extracts the default from the first option. If the first option has no default, returns `undefined` (defaults in other union options are not checked).
|
|
177
180
|
|
|
178
181
|
```typescript
|
|
179
182
|
import { extractDefault } from "@zod-utils/core";
|
|
180
183
|
import { z } from "zod";
|
|
181
184
|
|
|
185
|
+
// Basic usage
|
|
182
186
|
const field = z.string().optional().default("hello");
|
|
183
187
|
extractDefault(field); // 'hello'
|
|
184
188
|
|
|
185
189
|
const noDefault = z.string();
|
|
186
190
|
extractDefault(noDefault); // undefined
|
|
191
|
+
|
|
192
|
+
// Union with default in first option
|
|
193
|
+
const unionField = z.union([z.string().default('hello'), z.number()]);
|
|
194
|
+
extractDefault(unionField); // 'hello'
|
|
195
|
+
|
|
196
|
+
// Union with default in second option (only checks first)
|
|
197
|
+
const unionField2 = z.union([z.string(), z.number().default(42)]);
|
|
198
|
+
extractDefault(unionField2); // undefined
|
|
199
|
+
|
|
200
|
+
// Union wrapped in optional
|
|
201
|
+
const wrappedUnion = z.union([z.string().default('test'), z.number()]).optional();
|
|
202
|
+
extractDefault(wrappedUnion); // 'test'
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### `getFieldChecks(field)`
|
|
208
|
+
|
|
209
|
+
Extract all validation check definitions from a Zod schema field. Returns Zod's raw check definition objects directly, including all properties like `check`, `minimum`, `maximum`, `value`, `inclusive`, `format`, `pattern`, etc.
|
|
210
|
+
|
|
211
|
+
**Automatically unwraps:** optional, nullable, and default layers. For unions, checks only the first option.
|
|
212
|
+
|
|
213
|
+
**Supported check types:** Returns any of 21 check types:
|
|
214
|
+
- **Length checks**: `min_length`, `max_length`, `length_equals` (strings, arrays)
|
|
215
|
+
- **Size checks**: `min_size`, `max_size`, `size_equals` (files, sets, maps)
|
|
216
|
+
- **Numeric checks**: `greater_than`, `less_than`, `multiple_of`
|
|
217
|
+
- **Format checks**: `number_format`, `bigint_format`, `string_format` (email, url, uuid, etc.)
|
|
218
|
+
- **String pattern checks**: `regex`, `lowercase`, `uppercase`, `includes`, `starts_with`, `ends_with`
|
|
219
|
+
- **Other checks**: `property`, `mime_type`, `overwrite`
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { getFieldChecks } from "@zod-utils/core";
|
|
223
|
+
import { z } from "zod";
|
|
224
|
+
|
|
225
|
+
// String with length constraints
|
|
226
|
+
const username = z.string().min(3).max(20);
|
|
227
|
+
const checks = getFieldChecks(username);
|
|
228
|
+
// [
|
|
229
|
+
// { check: 'min_length', minimum: 3, when: [Function], ... },
|
|
230
|
+
// { check: 'max_length', maximum: 20, when: [Function], ... }
|
|
231
|
+
// ]
|
|
232
|
+
|
|
233
|
+
// Number with range constraints
|
|
234
|
+
const age = z.number().min(18).max(120);
|
|
235
|
+
const checks = getFieldChecks(age);
|
|
236
|
+
// [
|
|
237
|
+
// { check: 'greater_than', value: 18, inclusive: true, ... },
|
|
238
|
+
// { check: 'less_than', value: 120, inclusive: true, ... }
|
|
239
|
+
// ]
|
|
240
|
+
|
|
241
|
+
// Array with item count constraints
|
|
242
|
+
const tags = z.array(z.string()).min(1).max(5);
|
|
243
|
+
const checks = getFieldChecks(tags);
|
|
244
|
+
// [
|
|
245
|
+
// { check: 'min_length', minimum: 1, ... },
|
|
246
|
+
// { check: 'max_length', maximum: 5, ... }
|
|
247
|
+
// ]
|
|
248
|
+
|
|
249
|
+
// String with format validation
|
|
250
|
+
const email = z.string().email();
|
|
251
|
+
const checks = getFieldChecks(email);
|
|
252
|
+
// [{ check: 'string_format', format: 'email', ... }]
|
|
253
|
+
|
|
254
|
+
// Unwrapping optional/nullable/default layers
|
|
255
|
+
const bio = z.string().min(10).max(500).optional();
|
|
256
|
+
const checks = getFieldChecks(bio);
|
|
257
|
+
// [
|
|
258
|
+
// { check: 'min_length', minimum: 10, ... },
|
|
259
|
+
// { check: 'max_length', maximum: 500, ... }
|
|
260
|
+
// ]
|
|
261
|
+
|
|
262
|
+
// No checks
|
|
263
|
+
const plainString = z.string();
|
|
264
|
+
getFieldChecks(plainString); // []
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Type:** The return type is `ZodUnionCheck[]`, a union of all 21 Zod check definition types. You can also import the `ZodUnionCheck` type:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import { getFieldChecks, type ZodUnionCheck } from "@zod-utils/core";
|
|
187
271
|
```
|
|
188
272
|
|
|
189
273
|
---
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
+
import { $ZodCheckLessThanDef, $ZodCheckGreaterThanDef, $ZodCheckMultipleOfDef, $ZodCheckNumberFormatDef, $ZodCheckBigIntFormatDef, $ZodCheckMaxSizeDef, $ZodCheckMinSizeDef, $ZodCheckSizeEqualsDef, $ZodCheckMaxLengthDef, $ZodCheckMinLengthDef, $ZodCheckLengthEqualsDef, $ZodCheckStringFormatDef, $ZodCheckRegexDef, $ZodCheckLowerCaseDef, $ZodCheckUpperCaseDef, $ZodCheckIncludesDef, $ZodCheckStartsWithDef, $ZodCheckEndsWithDef, $ZodCheckPropertyDef, $ZodCheckMimeTypeDef, $ZodCheckOverwriteDef } from 'zod/v4/core';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Simplifies complex TypeScript types for better IDE hover tooltips and error messages.
|
|
@@ -45,11 +46,14 @@ type Simplify<T> = {
|
|
|
45
46
|
} & {};
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
|
-
* Extracts the default value from a Zod field, recursively unwrapping optional and
|
|
49
|
+
* Extracts the default value from a Zod field, recursively unwrapping optional, nullable, and union layers.
|
|
49
50
|
*
|
|
50
|
-
* This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`) to find
|
|
51
|
+
* This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`, `ZodUnion`) to find
|
|
51
52
|
* the underlying `ZodDefault` and returns its default value. If no default is found, returns `undefined`.
|
|
52
53
|
*
|
|
54
|
+
* **Union handling:** For union types, extracts the default from the first option. If the first option
|
|
55
|
+
* has no default, returns `undefined` (defaults in other union options are not checked).
|
|
56
|
+
*
|
|
53
57
|
* @template T - The Zod type to extract default from
|
|
54
58
|
* @param field - The Zod field to extract default from
|
|
55
59
|
* @returns The default value if present, undefined otherwise
|
|
@@ -71,6 +75,22 @@ type Simplify<T> = {
|
|
|
71
75
|
* ```
|
|
72
76
|
*
|
|
73
77
|
* @example
|
|
78
|
+
* Union with default in first option
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const field = z.union([z.string().default('hello'), z.number()]);
|
|
81
|
+
* const defaultValue = extractDefault(field);
|
|
82
|
+
* // Result: 'hello' (extracts from first union option)
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* Union with default in second option
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const field = z.union([z.string(), z.number().default(42)]);
|
|
89
|
+
* const defaultValue = extractDefault(field);
|
|
90
|
+
* // Result: undefined (only checks first option)
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
74
94
|
* Field without default
|
|
75
95
|
* ```typescript
|
|
76
96
|
* const field = z.string().optional();
|
|
@@ -397,5 +417,95 @@ declare function removeDefault<T extends z.ZodType>(field: T): StripZodDefault<T
|
|
|
397
417
|
* @since 0.1.0
|
|
398
418
|
*/
|
|
399
419
|
declare const requiresValidInput: <T extends z.ZodType>(field: T) => boolean;
|
|
420
|
+
/**
|
|
421
|
+
* Union type of all Zod check definition types.
|
|
422
|
+
*
|
|
423
|
+
* Includes all validation check types supported by Zod v4:
|
|
424
|
+
* - **Length checks**: `min_length`, `max_length`, `length_equals` (strings, arrays)
|
|
425
|
+
* - **Size checks**: `min_size`, `max_size`, `size_equals` (files, sets, maps)
|
|
426
|
+
* - **Numeric checks**: `greater_than`, `less_than`, `multiple_of`
|
|
427
|
+
* - **Format checks**: `number_format` (int32, float64, etc.), `bigint_format`, `string_format` (email, url, uuid, etc.)
|
|
428
|
+
* - **String pattern checks**: `regex`, `lowercase`, `uppercase`, `includes`, `starts_with`, `ends_with`
|
|
429
|
+
* - **Other checks**: `property`, `mime_type`, `overwrite`
|
|
430
|
+
*
|
|
431
|
+
* @since 0.4.0
|
|
432
|
+
*/
|
|
433
|
+
type ZodUnionCheck = $ZodCheckLessThanDef | $ZodCheckGreaterThanDef | $ZodCheckMultipleOfDef | $ZodCheckNumberFormatDef | $ZodCheckBigIntFormatDef | $ZodCheckMaxSizeDef | $ZodCheckMinSizeDef | $ZodCheckSizeEqualsDef | $ZodCheckMaxLengthDef | $ZodCheckMinLengthDef | $ZodCheckLengthEqualsDef | $ZodCheckStringFormatDef | $ZodCheckRegexDef | $ZodCheckLowerCaseDef | $ZodCheckUpperCaseDef | $ZodCheckIncludesDef | $ZodCheckStartsWithDef | $ZodCheckEndsWithDef | $ZodCheckPropertyDef | $ZodCheckMimeTypeDef | $ZodCheckOverwriteDef;
|
|
434
|
+
/**
|
|
435
|
+
* Extracts all validation check definitions from a Zod schema field.
|
|
436
|
+
*
|
|
437
|
+
* This function analyzes a Zod field and returns all check definitions as defined
|
|
438
|
+
* by Zod's internal structure. Returns Zod's raw check definition objects directly,
|
|
439
|
+
* including all properties like `check`, `minimum`, `maximum`, `value`, `inclusive`,
|
|
440
|
+
* `format`, `pattern`, etc.
|
|
441
|
+
*
|
|
442
|
+
* **Unwrapping behavior:** Automatically unwraps optional, nullable, and default layers.
|
|
443
|
+
* For unions, checks only the first option (same as other schema utilities).
|
|
444
|
+
*
|
|
445
|
+
* **Supported check types:** Returns any of the 21 check types defined in {@link ZodUnionCheck},
|
|
446
|
+
* including length, size, numeric range, format validation, string patterns, and more.
|
|
447
|
+
*
|
|
448
|
+
* @template T - The Zod type to extract checks from
|
|
449
|
+
* @param field - The Zod field to analyze
|
|
450
|
+
* @returns Array of Zod check definition objects (see {@link ZodUnionCheck})
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* String with length constraints
|
|
454
|
+
* ```typescript
|
|
455
|
+
* const username = z.string().min(3).max(20);
|
|
456
|
+
* const checks = getFieldChecks(username);
|
|
457
|
+
* // [
|
|
458
|
+
* // { check: 'min_length', minimum: 3, when: [Function], ... },
|
|
459
|
+
* // { check: 'max_length', maximum: 20, when: [Function], ... }
|
|
460
|
+
* // ]
|
|
461
|
+
* ```
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* Number with range constraints
|
|
465
|
+
* ```typescript
|
|
466
|
+
* const age = z.number().min(18).max(120);
|
|
467
|
+
* const checks = getFieldChecks(age);
|
|
468
|
+
* // [
|
|
469
|
+
* // { check: 'greater_than', value: 18, inclusive: true, when: [Function], ... },
|
|
470
|
+
* // { check: 'less_than', value: 120, inclusive: true, when: [Function], ... }
|
|
471
|
+
* // ]
|
|
472
|
+
* ```
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* Array with item count constraints
|
|
476
|
+
* ```typescript
|
|
477
|
+
* const tags = z.array(z.string()).min(1).max(5);
|
|
478
|
+
* const checks = getFieldChecks(tags);
|
|
479
|
+
* // [
|
|
480
|
+
* // { check: 'min_length', minimum: 1, ... },
|
|
481
|
+
* // { check: 'max_length', maximum: 5, ... }
|
|
482
|
+
* // ]
|
|
483
|
+
* ```
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* String with format validation
|
|
487
|
+
* ```typescript
|
|
488
|
+
* const email = z.string().email();
|
|
489
|
+
* const checks = getFieldChecks(email);
|
|
490
|
+
* // [
|
|
491
|
+
* // { check: 'string_format', format: 'email', ... }
|
|
492
|
+
* // ]
|
|
493
|
+
* ```
|
|
494
|
+
*
|
|
495
|
+
* @example
|
|
496
|
+
* Unwrapping optional/nullable/default layers
|
|
497
|
+
* ```typescript
|
|
498
|
+
* const bio = z.string().min(10).max(500).optional();
|
|
499
|
+
* const checks = getFieldChecks(bio);
|
|
500
|
+
* // [
|
|
501
|
+
* // { check: 'min_length', minimum: 10, ... },
|
|
502
|
+
* // { check: 'max_length', maximum: 500, ... }
|
|
503
|
+
* // ]
|
|
504
|
+
* ```
|
|
505
|
+
*
|
|
506
|
+
* @see {@link ZodUnionCheck} for all supported check types
|
|
507
|
+
* @since 0.4.0
|
|
508
|
+
*/
|
|
509
|
+
declare function getFieldChecks<T extends z.ZodTypeAny>(field: T): Array<ZodUnionCheck>;
|
|
400
510
|
|
|
401
|
-
export { type Simplify, canUnwrap, extractDefault, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, unwrapUnion };
|
|
511
|
+
export { type Simplify, type ZodUnionCheck, canUnwrap, extractDefault, getFieldChecks, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, unwrapUnion };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
+
import { $ZodCheckLessThanDef, $ZodCheckGreaterThanDef, $ZodCheckMultipleOfDef, $ZodCheckNumberFormatDef, $ZodCheckBigIntFormatDef, $ZodCheckMaxSizeDef, $ZodCheckMinSizeDef, $ZodCheckSizeEqualsDef, $ZodCheckMaxLengthDef, $ZodCheckMinLengthDef, $ZodCheckLengthEqualsDef, $ZodCheckStringFormatDef, $ZodCheckRegexDef, $ZodCheckLowerCaseDef, $ZodCheckUpperCaseDef, $ZodCheckIncludesDef, $ZodCheckStartsWithDef, $ZodCheckEndsWithDef, $ZodCheckPropertyDef, $ZodCheckMimeTypeDef, $ZodCheckOverwriteDef } from 'zod/v4/core';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Simplifies complex TypeScript types for better IDE hover tooltips and error messages.
|
|
@@ -45,11 +46,14 @@ type Simplify<T> = {
|
|
|
45
46
|
} & {};
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
|
-
* Extracts the default value from a Zod field, recursively unwrapping optional and
|
|
49
|
+
* Extracts the default value from a Zod field, recursively unwrapping optional, nullable, and union layers.
|
|
49
50
|
*
|
|
50
|
-
* This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`) to find
|
|
51
|
+
* This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`, `ZodUnion`) to find
|
|
51
52
|
* the underlying `ZodDefault` and returns its default value. If no default is found, returns `undefined`.
|
|
52
53
|
*
|
|
54
|
+
* **Union handling:** For union types, extracts the default from the first option. If the first option
|
|
55
|
+
* has no default, returns `undefined` (defaults in other union options are not checked).
|
|
56
|
+
*
|
|
53
57
|
* @template T - The Zod type to extract default from
|
|
54
58
|
* @param field - The Zod field to extract default from
|
|
55
59
|
* @returns The default value if present, undefined otherwise
|
|
@@ -71,6 +75,22 @@ type Simplify<T> = {
|
|
|
71
75
|
* ```
|
|
72
76
|
*
|
|
73
77
|
* @example
|
|
78
|
+
* Union with default in first option
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const field = z.union([z.string().default('hello'), z.number()]);
|
|
81
|
+
* const defaultValue = extractDefault(field);
|
|
82
|
+
* // Result: 'hello' (extracts from first union option)
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* Union with default in second option
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const field = z.union([z.string(), z.number().default(42)]);
|
|
89
|
+
* const defaultValue = extractDefault(field);
|
|
90
|
+
* // Result: undefined (only checks first option)
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
74
94
|
* Field without default
|
|
75
95
|
* ```typescript
|
|
76
96
|
* const field = z.string().optional();
|
|
@@ -397,5 +417,95 @@ declare function removeDefault<T extends z.ZodType>(field: T): StripZodDefault<T
|
|
|
397
417
|
* @since 0.1.0
|
|
398
418
|
*/
|
|
399
419
|
declare const requiresValidInput: <T extends z.ZodType>(field: T) => boolean;
|
|
420
|
+
/**
|
|
421
|
+
* Union type of all Zod check definition types.
|
|
422
|
+
*
|
|
423
|
+
* Includes all validation check types supported by Zod v4:
|
|
424
|
+
* - **Length checks**: `min_length`, `max_length`, `length_equals` (strings, arrays)
|
|
425
|
+
* - **Size checks**: `min_size`, `max_size`, `size_equals` (files, sets, maps)
|
|
426
|
+
* - **Numeric checks**: `greater_than`, `less_than`, `multiple_of`
|
|
427
|
+
* - **Format checks**: `number_format` (int32, float64, etc.), `bigint_format`, `string_format` (email, url, uuid, etc.)
|
|
428
|
+
* - **String pattern checks**: `regex`, `lowercase`, `uppercase`, `includes`, `starts_with`, `ends_with`
|
|
429
|
+
* - **Other checks**: `property`, `mime_type`, `overwrite`
|
|
430
|
+
*
|
|
431
|
+
* @since 0.4.0
|
|
432
|
+
*/
|
|
433
|
+
type ZodUnionCheck = $ZodCheckLessThanDef | $ZodCheckGreaterThanDef | $ZodCheckMultipleOfDef | $ZodCheckNumberFormatDef | $ZodCheckBigIntFormatDef | $ZodCheckMaxSizeDef | $ZodCheckMinSizeDef | $ZodCheckSizeEqualsDef | $ZodCheckMaxLengthDef | $ZodCheckMinLengthDef | $ZodCheckLengthEqualsDef | $ZodCheckStringFormatDef | $ZodCheckRegexDef | $ZodCheckLowerCaseDef | $ZodCheckUpperCaseDef | $ZodCheckIncludesDef | $ZodCheckStartsWithDef | $ZodCheckEndsWithDef | $ZodCheckPropertyDef | $ZodCheckMimeTypeDef | $ZodCheckOverwriteDef;
|
|
434
|
+
/**
|
|
435
|
+
* Extracts all validation check definitions from a Zod schema field.
|
|
436
|
+
*
|
|
437
|
+
* This function analyzes a Zod field and returns all check definitions as defined
|
|
438
|
+
* by Zod's internal structure. Returns Zod's raw check definition objects directly,
|
|
439
|
+
* including all properties like `check`, `minimum`, `maximum`, `value`, `inclusive`,
|
|
440
|
+
* `format`, `pattern`, etc.
|
|
441
|
+
*
|
|
442
|
+
* **Unwrapping behavior:** Automatically unwraps optional, nullable, and default layers.
|
|
443
|
+
* For unions, checks only the first option (same as other schema utilities).
|
|
444
|
+
*
|
|
445
|
+
* **Supported check types:** Returns any of the 21 check types defined in {@link ZodUnionCheck},
|
|
446
|
+
* including length, size, numeric range, format validation, string patterns, and more.
|
|
447
|
+
*
|
|
448
|
+
* @template T - The Zod type to extract checks from
|
|
449
|
+
* @param field - The Zod field to analyze
|
|
450
|
+
* @returns Array of Zod check definition objects (see {@link ZodUnionCheck})
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* String with length constraints
|
|
454
|
+
* ```typescript
|
|
455
|
+
* const username = z.string().min(3).max(20);
|
|
456
|
+
* const checks = getFieldChecks(username);
|
|
457
|
+
* // [
|
|
458
|
+
* // { check: 'min_length', minimum: 3, when: [Function], ... },
|
|
459
|
+
* // { check: 'max_length', maximum: 20, when: [Function], ... }
|
|
460
|
+
* // ]
|
|
461
|
+
* ```
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* Number with range constraints
|
|
465
|
+
* ```typescript
|
|
466
|
+
* const age = z.number().min(18).max(120);
|
|
467
|
+
* const checks = getFieldChecks(age);
|
|
468
|
+
* // [
|
|
469
|
+
* // { check: 'greater_than', value: 18, inclusive: true, when: [Function], ... },
|
|
470
|
+
* // { check: 'less_than', value: 120, inclusive: true, when: [Function], ... }
|
|
471
|
+
* // ]
|
|
472
|
+
* ```
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* Array with item count constraints
|
|
476
|
+
* ```typescript
|
|
477
|
+
* const tags = z.array(z.string()).min(1).max(5);
|
|
478
|
+
* const checks = getFieldChecks(tags);
|
|
479
|
+
* // [
|
|
480
|
+
* // { check: 'min_length', minimum: 1, ... },
|
|
481
|
+
* // { check: 'max_length', maximum: 5, ... }
|
|
482
|
+
* // ]
|
|
483
|
+
* ```
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* String with format validation
|
|
487
|
+
* ```typescript
|
|
488
|
+
* const email = z.string().email();
|
|
489
|
+
* const checks = getFieldChecks(email);
|
|
490
|
+
* // [
|
|
491
|
+
* // { check: 'string_format', format: 'email', ... }
|
|
492
|
+
* // ]
|
|
493
|
+
* ```
|
|
494
|
+
*
|
|
495
|
+
* @example
|
|
496
|
+
* Unwrapping optional/nullable/default layers
|
|
497
|
+
* ```typescript
|
|
498
|
+
* const bio = z.string().min(10).max(500).optional();
|
|
499
|
+
* const checks = getFieldChecks(bio);
|
|
500
|
+
* // [
|
|
501
|
+
* // { check: 'min_length', minimum: 10, ... },
|
|
502
|
+
* // { check: 'max_length', maximum: 500, ... }
|
|
503
|
+
* // ]
|
|
504
|
+
* ```
|
|
505
|
+
*
|
|
506
|
+
* @see {@link ZodUnionCheck} for all supported check types
|
|
507
|
+
* @since 0.4.0
|
|
508
|
+
*/
|
|
509
|
+
declare function getFieldChecks<T extends z.ZodTypeAny>(field: T): Array<ZodUnionCheck>;
|
|
400
510
|
|
|
401
|
-
export { type Simplify, canUnwrap, extractDefault, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, unwrapUnion };
|
|
511
|
+
export { type Simplify, type ZodUnionCheck, canUnwrap, extractDefault, getFieldChecks, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, unwrapUnion };
|
package/dist/index.js
CHANGED
|
@@ -82,6 +82,11 @@ var requiresValidInput = (field) => {
|
|
|
82
82
|
const emptyArrayResult = primitiveType.type === "array" && defaultRemovedField.safeParse([]).success;
|
|
83
83
|
return !undefinedResult && !nullResult && !emptyStringResult && !emptyArrayResult;
|
|
84
84
|
};
|
|
85
|
+
function getFieldChecks(field) {
|
|
86
|
+
var _a;
|
|
87
|
+
const primitiveType = getPrimitiveType(field);
|
|
88
|
+
return ((_a = primitiveType.def.checks) == null ? void 0 : _a.map((check) => check._zod.def)) || [];
|
|
89
|
+
}
|
|
85
90
|
|
|
86
91
|
// src/defaults.ts
|
|
87
92
|
function extractDefault(field) {
|
|
@@ -91,6 +96,9 @@ function extractDefault(field) {
|
|
|
91
96
|
if (canUnwrap(field)) {
|
|
92
97
|
return extractDefault(field.unwrap());
|
|
93
98
|
}
|
|
99
|
+
if (field instanceof z__namespace.ZodUnion) {
|
|
100
|
+
return extractDefault(unwrapUnion(field).field);
|
|
101
|
+
}
|
|
94
102
|
return void 0;
|
|
95
103
|
}
|
|
96
104
|
function getSchemaDefaults(schema) {
|
|
@@ -108,6 +116,7 @@ function getSchemaDefaults(schema) {
|
|
|
108
116
|
|
|
109
117
|
exports.canUnwrap = canUnwrap;
|
|
110
118
|
exports.extractDefault = extractDefault;
|
|
119
|
+
exports.getFieldChecks = getFieldChecks;
|
|
111
120
|
exports.getPrimitiveType = getPrimitiveType;
|
|
112
121
|
exports.getSchemaDefaults = getSchemaDefaults;
|
|
113
122
|
exports.removeDefault = removeDefault;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema.ts","../src/defaults.ts"],"names":["z","z2"],"mappings":"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","file":"index.js","sourcesContent":["import * as z from 'zod';\n\n/**\n * Type representing a Zod type that has an unwrap method\n */\ntype Unwrappable = { unwrap: () => z.ZodTypeAny };\n\n/**\n * Type guard to check if a Zod field can be unwrapped (has wrapper types like optional, nullable, default).\n *\n * This checks whether a Zod type has an `unwrap()` method, which is present on wrapper types\n * like `ZodOptional`, `ZodNullable`, `ZodDefault`, and others.\n *\n * @param field - The Zod field to check\n * @returns True if the field has an unwrap method, false otherwise\n *\n * @example\n * ```typescript\n * const optionalField = z.string().optional();\n * console.log(canUnwrap(optionalField)); // true\n *\n * const plainField = z.string();\n * console.log(canUnwrap(plainField)); // false\n * ```\n *\n * @since 0.1.0\n */\nexport function canUnwrap(\n field: z.ZodTypeAny,\n): field is z.ZodTypeAny & Unwrappable {\n return 'unwrap' in field && typeof field.unwrap === 'function';\n}\n\n/**\n * Unwraps a ZodUnion type and returns the first field and all union options.\n *\n * This function extracts the individual type options from a union type.\n * By default, it filters out `ZodNull` and `ZodUndefined` types, returning only\n * the meaningful type options. You can disable this filtering to get all options.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field (union or single type)\n * @param options - Configuration options\n * @param options.filterNullish - Whether to filter out null and undefined types (default: true)\n * @returns Object with `field` (first option) and `union` (all options array)\n *\n * @example\n * Basic union unwrapping\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string(), z.number()] }\n * ```\n *\n * @example\n * Union with null (filtered by default)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Union with null (keep all options)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field, { filterNullish: false });\n * // Result: { field: z.string(), union: [z.string(), z.null()] }\n * ```\n *\n * @example\n * Non-union type (returns single field)\n * ```typescript\n * const field = z.string();\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Nullable as union\n * ```typescript\n * const field = z.string().nullable(); // This is z.union([z.string(), z.null()])\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] } (null filtered out)\n * ```\n *\n * @example\n * Using the first field for type checking\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const { field: firstField, union } = unwrapUnion(field);\n * if (firstField instanceof z.ZodString) {\n * console.log('First type is string');\n * }\n * ```\n *\n * @see {@link getPrimitiveType} for unwrapping wrapper types\n * @since 0.1.0\n */\nexport function unwrapUnion<T extends z.ZodTypeAny>(\n field: T,\n options: { filterNullish?: boolean } = {},\n): { field: z.ZodTypeAny; union: z.ZodTypeAny[] } {\n const { filterNullish = true } = options;\n\n if (field instanceof z.ZodUnion) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n const unionOptions = [...field.def.options] as z.ZodTypeAny[];\n\n const filteredOptions = filterNullish\n ? unionOptions.filter(\n (option) =>\n !(option instanceof z.ZodNull) &&\n !(option instanceof z.ZodUndefined),\n )\n : unionOptions;\n\n return {\n field: filteredOptions[0] || field,\n union: filteredOptions,\n };\n }\n\n // If it's not a union, return the field itself\n return {\n field,\n union: [field],\n };\n}\n\n/**\n * Gets the underlying primitive type of a Zod field by recursively unwrapping wrapper types.\n *\n * This function removes wrapper layers (optional, nullable, default) to reveal the base type.\n * **Important:** It stops at array types without unwrapping them, treating arrays as primitives.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field to unwrap\n * @returns The unwrapped primitive Zod type\n *\n * @example\n * Unwrapping to string primitive\n * ```typescript\n * const field = z.string().optional().nullable();\n * const primitive = getPrimitiveType(field);\n * // Result: z.string() (unwrapped all wrappers)\n * ```\n *\n * @example\n * Stopping at array type\n * ```typescript\n * const field = z.array(z.string()).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.array(z.string()) (stops at array, doesn't unwrap it)\n * ```\n *\n * @example\n * Unwrapping defaults\n * ```typescript\n * const field = z.number().default(0).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.number()\n * ```\n *\n * @see {@link canUnwrap} for checking if a field can be unwrapped\n * @since 0.1.0\n */\nexport const getPrimitiveType = <T extends z.ZodType>(\n field: T,\n): z.ZodTypeAny => {\n // Stop at arrays - don't unwrap them\n if (field instanceof z.ZodArray) {\n return field;\n }\n\n if (canUnwrap(field)) {\n return getPrimitiveType(field.unwrap());\n }\n\n if (field instanceof z.ZodUnion) {\n return getPrimitiveType(unwrapUnion(field).field);\n }\n\n return field;\n};\n\ntype StripZodDefault<T> = T extends z.ZodDefault<infer Inner>\n ? StripZodDefault<Inner>\n : T extends z.ZodOptional<infer Inner>\n ? z.ZodOptional<StripZodDefault<Inner>>\n : T extends z.ZodNullable<infer Inner>\n ? z.ZodNullable<StripZodDefault<Inner>>\n : T;\n\n/**\n * Removes default values from a Zod field while preserving other wrapper types.\n *\n * This function recursively removes `ZodDefault` wrappers from a field, while maintaining\n * `optional()` and `nullable()` wrappers. Useful for scenarios where you want to check\n * field requirements without considering default values.\n *\n * @template T - The Zod type to process\n * @param field - The Zod field to remove defaults from\n * @returns The field without defaults but with optional/nullable preserved\n *\n * @example\n * Removing simple default\n * ```typescript\n * const field = z.string().default('hello');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string()\n * ```\n *\n * @example\n * Preserving optional wrapper\n * ```typescript\n * const field = z.string().default('hello').optional();\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().optional()\n * ```\n *\n * @example\n * Nested defaults\n * ```typescript\n * const field = z.string().default('inner').nullable().default('outer');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().nullable()\n * ```\n *\n * @see {@link requiresValidInput} for usage with requirement checking\n * @since 0.1.0\n */\nexport function removeDefault<T extends z.ZodType>(\n field: T,\n): StripZodDefault<T> {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.unwrap() as StripZodDefault<T>;\n }\n\n if ('innerType' in field.def && field.def.innerType instanceof z.ZodType) {\n const inner = removeDefault(field.def.innerType);\n // Reconstruct the wrapper with the modified inner type\n if (field instanceof z.ZodOptional) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.optional() as unknown as StripZodDefault<T>;\n }\n if (field instanceof z.ZodNullable) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.nullable() as unknown as StripZodDefault<T>;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field as StripZodDefault<T>;\n}\n\n/**\n * Determines if a field will show validation errors when the user submits empty or invalid input.\n *\n * This is useful for form UIs to indicate which fields require valid user input (e.g., showing\n * asterisks, validation states). The key insight: **defaults are just initial values** - they\n * don't prevent validation errors if the user clears the field.\n *\n * **Real-world example:**\n * ```typescript\n * // Marital status field with default but validation rules\n * const maritalStatus = z.string().min(1).default('single');\n *\n * // Initial: field shows \"single\" (from default)\n * // User deletes the value → field is now empty string\n * // User submits form → validation fails because .min(1) rejects empty strings\n * // requiresValidInput(maritalStatus) → true (shows * indicator, validation error)\n * ```\n *\n * **How it works:**\n * 1. Removes `.default()` wrappers (defaults are initial values, not validation rules)\n * 2. Tests if the underlying schema accepts empty/invalid input:\n * - `undefined` (via `.optional()`)\n * - `null` (via `.nullable()`)\n * - Empty string (plain `z.string()` without `.min(1)` or `.nonempty()`)\n * - Empty array (plain `z.array()` without `.min(1)` or `.nonempty()`)\n * 3. Returns `true` if validation will fail, `false` if empty input is accepted\n *\n * @template T - The Zod type to check\n * @param field - The Zod field to check\n * @returns True if the field will show validation errors on empty/invalid input, false otherwise\n *\n * @example\n * User name field - required, no default\n * ```typescript\n * const userName = z.string().min(1);\n * requiresValidInput(userName); // true - will error if user submits empty\n * ```\n *\n * @example\n * Marital status - required WITH default\n * ```typescript\n * const maritalStatus = z.string().min(1).default('single');\n * requiresValidInput(maritalStatus); // true - will error if user clears and submits\n * ```\n *\n * @example\n * Age with default - requires valid input\n * ```typescript\n * const age = z.number().default(0);\n * requiresValidInput(age); // true - numbers reject empty strings\n * ```\n *\n * @example\n * Optional bio field - doesn't require input\n * ```typescript\n * const bio = z.string().optional();\n * requiresValidInput(bio); // false - user can leave empty\n * ```\n *\n * @example\n * String with default but NO validation - doesn't require input\n * ```typescript\n * const notes = z.string().default('N/A');\n * requiresValidInput(notes); // false - plain z.string() accepts empty strings\n * ```\n *\n * @example\n * Nullable field - doesn't require input\n * ```typescript\n * const middleName = z.string().nullable();\n * requiresValidInput(middleName); // false - user can leave null\n * ```\n *\n * @see {@link removeDefault} for understanding how defaults are handled\n * @see {@link getPrimitiveType} for understanding type unwrapping\n * @since 0.1.0\n */\nexport const requiresValidInput = <T extends z.ZodType>(field: T) => {\n const defaultRemovedField = removeDefault(field);\n if (!(defaultRemovedField instanceof z.ZodType)) {\n return false;\n }\n\n const undefinedResult = defaultRemovedField.safeParse(undefined).success;\n\n // Check if field accepts null (nullable)\n const nullResult = defaultRemovedField.safeParse(null).success;\n\n const primitiveType = getPrimitiveType(defaultRemovedField);\n\n const emptyStringResult =\n primitiveType.type === 'string' &&\n defaultRemovedField.safeParse('').success;\n\n const emptyArrayResult =\n primitiveType.type === 'array' && defaultRemovedField.safeParse([]).success;\n\n return (\n !undefinedResult && !nullResult && !emptyStringResult && !emptyArrayResult\n );\n};\n","import * as z from 'zod';\nimport { canUnwrap } from './schema';\nimport type { Simplify } from './types';\n\n/**\n * Extracts the default value from a Zod field, recursively unwrapping optional and nullable layers.\n *\n * This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`) to find\n * the underlying `ZodDefault` and returns its default value. If no default is found, returns `undefined`.\n *\n * @template T - The Zod type to extract default from\n * @param field - The Zod field to extract default from\n * @returns The default value if present, undefined otherwise\n *\n * @example\n * Basic usage with default value\n * ```typescript\n * const field = z.string().default('hello');\n * const defaultValue = extractDefault(field);\n * // Result: 'hello'\n * ```\n *\n * @example\n * Unwrapping optional/nullable layers\n * ```typescript\n * const field = z.string().default('world').optional();\n * const defaultValue = extractDefault(field);\n * // Result: 'world' (unwraps optional to find default)\n * ```\n *\n * @example\n * Field without default\n * ```typescript\n * const field = z.string().optional();\n * const defaultValue = extractDefault(field);\n * // Result: undefined\n * ```\n *\n * @see {@link getSchemaDefaults} for extracting defaults from entire schemas\n * @since 0.1.0\n */\nexport function extractDefault<T extends z.ZodTypeAny>(\n field: T,\n): z.infer<T> | undefined {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.def.defaultValue as z.infer<T>;\n }\n\n if (canUnwrap(field)) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return extractDefault(field.unwrap()) as z.infer<T>;\n }\n\n return undefined;\n}\n\n/**\n * Extracts default values from a Zod object schema while skipping fields without defaults.\n *\n * This function recursively traverses the schema and collects all fields that have\n * explicit default values defined. Fields without defaults are excluded from the result.\n *\n * **Important:** Nested defaults are NOT extracted unless the parent object also has\n * an explicit `.default()`. This is by design to match Zod's default value behavior.\n *\n * @template T - The Zod object schema type\n * @param schema - The Zod object schema to extract defaults from\n * @returns A partial object containing only fields with default values\n *\n * @example\n * Basic usage\n * ```typescript\n * const schema = z.object({\n * name: z.string().default('John'),\n * age: z.number(), // no default - will be skipped\n * email: z.string().email().optional(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { name: 'John' }\n * ```\n *\n * @example\n * Nested objects with defaults\n * ```typescript\n * const schema = z.object({\n * user: z.object({\n * name: z.string().default('Guest')\n * }).default({ name: 'Guest' }), // ✅ Extracted because parent has .default()\n *\n * settings: z.object({\n * theme: z.string().default('light')\n * }), // ❌ NOT extracted - parent has no .default()\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { user: { name: 'Guest' } }\n * ```\n *\n * @example\n * Unwrapping optional/nullable fields\n * ```typescript\n * const schema = z.object({\n * title: z.string().default('Untitled').optional(),\n * count: z.number().default(0).nullable(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { title: 'Untitled', count: 0 }\n * ```\n *\n * @see {@link extractDefault} for extracting defaults from individual fields\n * @since 0.1.0\n */\nexport function getSchemaDefaults<T extends z.ZodObject>(\n schema: T,\n): Simplify<Partial<z.infer<T>>> {\n const defaults: Record<string, unknown> = {};\n\n for (const key in schema.shape) {\n const field = schema.shape[key];\n if (!field) continue;\n\n // Check if this field has an explicit default value\n const defaultValue = extractDefault(field);\n if (defaultValue !== undefined) {\n defaults[key] = defaultValue;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return defaults as Partial<z.infer<T>>;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/defaults.ts"],"names":["z","z2"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAkDO,SAAS,UACd,KAAA,EACqC;AACrC,EAAA,OAAO,QAAA,IAAY,KAAA,IAAS,OAAO,KAAA,CAAM,MAAA,KAAW,UAAA;AACtD;AAoEO,SAAS,WAAA,CACd,KAAA,EACA,OAAA,GAAuC,EAAC,EACQ;AAChD,EAAA,MAAM,EAAE,aAAA,GAAgB,IAAA,EAAK,GAAI,OAAA;AAEjC,EAAA,IAAI,iBAAmBA,YAAA,CAAA,QAAA,EAAU;AAE/B,IAAA,MAAM,YAAA,GAAe,CAAC,GAAG,KAAA,CAAM,IAAI,OAAO,CAAA;AAE1C,IAAA,MAAM,eAAA,GAAkB,gBACpB,YAAA,CAAa,MAAA;AAAA,MACX,CAAC,MAAA,KACC,EAAE,MAAA,YAAoBA,YAAA,CAAA,OAAA,CAAA,IACtB,EAAE,MAAA,YAAoBA,YAAA,CAAA,YAAA;AAAA,KAC1B,GACA,YAAA;AAEJ,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,eAAA,CAAgB,CAAC,CAAA,IAAK,KAAA;AAAA,MAC7B,KAAA,EAAO;AAAA,KACT;AAAA,EACF;AAGA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,KAAA,EAAO,CAAC,KAAK;AAAA,GACf;AACF;AAuCO,IAAM,gBAAA,GAAmB,CAC9B,KAAA,KACiB;AAEjB,EAAA,IAAI,iBAAmBA,YAAA,CAAA,QAAA,EAAU;AAC/B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,SAAA,CAAU,KAAK,CAAA,EAAG;AACpB,IAAA,OAAO,gBAAA,CAAiB,KAAA,CAAM,MAAA,EAAQ,CAAA;AAAA,EACxC;AAEA,EAAA,IAAI,iBAAmBA,YAAA,CAAA,QAAA,EAAU;AAC/B,IAAA,OAAO,gBAAA,CAAiB,WAAA,CAAY,KAAK,CAAA,CAAE,KAAK,CAAA;AAAA,EAClD;AAEA,EAAA,OAAO,KAAA;AACT;AAgDO,SAAS,cACd,KAAA,EACoB;AACpB,EAAA,IAAI,iBAAmBA,YAAA,CAAA,UAAA,EAAY;AAEjC,IAAA,OAAO,MAAM,MAAA,EAAO;AAAA,EACtB;AAEA,EAAA,IAAI,eAAe,KAAA,CAAM,GAAA,IAAO,KAAA,CAAM,GAAA,CAAI,qBAAuBA,YAAA,CAAA,OAAA,EAAS;AACxE,IAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,KAAA,CAAM,GAAA,CAAI,SAAS,CAAA;AAE/C,IAAA,IAAI,iBAAmBA,YAAA,CAAA,WAAA,EAAa;AAElC,MAAA,OAAO,MAAM,QAAA,EAAS;AAAA,IACxB;AACA,IAAA,IAAI,iBAAmBA,YAAA,CAAA,WAAA,EAAa;AAElC,MAAA,OAAO,MAAM,QAAA,EAAS;AAAA,IACxB;AAAA,EACF;AAGA,EAAA,OAAO,KAAA;AACT;AA+EO,IAAM,kBAAA,GAAqB,CAAsB,KAAA,KAAa;AACnE,EAAA,MAAM,mBAAA,GAAsB,cAAc,KAAK,CAAA;AAC/C,EAAA,IAAI,EAAE,+BAAiCA,YAAA,CAAA,OAAA,CAAA,EAAU;AAC/C,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,eAAA,GAAkB,mBAAA,CAAoB,SAAA,CAAU,MAAS,CAAA,CAAE,OAAA;AAGjE,EAAA,MAAM,UAAA,GAAa,mBAAA,CAAoB,SAAA,CAAU,IAAI,CAAA,CAAE,OAAA;AAEvD,EAAA,MAAM,aAAA,GAAgB,iBAAiB,mBAAmB,CAAA;AAE1D,EAAA,MAAM,oBACJ,aAAA,CAAc,IAAA,KAAS,YACvB,mBAAA,CAAoB,SAAA,CAAU,EAAE,CAAA,CAAE,OAAA;AAEpC,EAAA,MAAM,gBAAA,GACJ,cAAc,IAAA,KAAS,OAAA,IAAW,oBAAoB,SAAA,CAAU,EAAE,CAAA,CAAE,OAAA;AAEtE,EAAA,OACE,CAAC,eAAA,IAAmB,CAAC,UAAA,IAAc,CAAC,qBAAqB,CAAC,gBAAA;AAE9D;AAiHO,SAAS,eACd,KAAA,EACsB;AA/exB,EAAA,IAAA,EAAA;AAgfE,EAAA,MAAM,aAAA,GAAgB,iBAAiB,KAAK,CAAA;AAE5C,EAAA,OAAA,CAAA,CAAQ,EAAA,GAAA,aAAA,CAAc,GAAA,CAAI,MAAA,KAAlB,IAAA,GAAA,MAAA,GAAA,EAAA,CAA0B,GAAA,CAAI,CAAC,KAAA,KAAU,KAAA,CAAM,IAAA,CAAK,GAAA,CAAA,KAC1D,EAAC;AACL;;;ACxbO,SAAS,eACd,KAAA,EACwB;AACxB,EAAA,IAAI,iBAAmBC,YAAA,CAAA,UAAA,EAAY;AAEjC,IAAA,OAAO,MAAM,GAAA,CAAI,YAAA;AAAA,EACnB;AAEA,EAAA,IAAI,SAAA,CAAU,KAAK,CAAA,EAAG;AAEpB,IAAA,OAAO,cAAA,CAAe,KAAA,CAAM,MAAA,EAAQ,CAAA;AAAA,EACtC;AAEA,EAAA,IAAI,iBAAmBA,YAAA,CAAA,QAAA,EAAU;AAE/B,IAAA,OAAO,cAAA,CAAe,WAAA,CAAY,KAAK,CAAA,CAAE,KAAK,CAAA;AAAA,EAChD;AAEA,EAAA,OAAO,MAAA;AACT;AA4DO,SAAS,kBACd,MAAA,EAC+B;AAC/B,EAAA,MAAM,WAAoC,EAAC;AAE3C,EAAA,KAAA,MAAW,GAAA,IAAO,OAAO,KAAA,EAAO;AAC9B,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAC9B,IAAA,IAAI,CAAC,KAAA,EAAO;AAGZ,IAAA,MAAM,YAAA,GAAe,eAAe,KAAK,CAAA;AACzC,IAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,MAAA,QAAA,CAAS,GAAG,CAAA,GAAI,YAAA;AAAA,IAClB;AAAA,EACF;AAGA,EAAA,OAAO,QAAA;AACT","file":"index.js","sourcesContent":["import * as z from 'zod';\nimport type {\n $ZodCheckBigIntFormatDef,\n $ZodCheckEndsWithDef,\n $ZodCheckGreaterThanDef,\n $ZodCheckIncludesDef,\n $ZodCheckLengthEqualsDef,\n $ZodCheckLessThanDef,\n $ZodCheckLowerCaseDef,\n $ZodCheckMaxLengthDef,\n $ZodCheckMaxSizeDef,\n $ZodCheckMimeTypeDef,\n $ZodCheckMinLengthDef,\n $ZodCheckMinSizeDef,\n $ZodCheckMultipleOfDef,\n $ZodCheckNumberFormatDef,\n $ZodCheckOverwriteDef,\n $ZodCheckPropertyDef,\n $ZodCheckRegexDef,\n $ZodCheckSizeEqualsDef,\n $ZodCheckStartsWithDef,\n $ZodCheckStringFormatDef,\n $ZodCheckUpperCaseDef,\n} from 'zod/v4/core';\n\n/**\n * Type representing a Zod type that has an unwrap method\n */\ntype Unwrappable = { unwrap: () => z.ZodTypeAny };\n\n/**\n * Type guard to check if a Zod field can be unwrapped (has wrapper types like optional, nullable, default).\n *\n * This checks whether a Zod type has an `unwrap()` method, which is present on wrapper types\n * like `ZodOptional`, `ZodNullable`, `ZodDefault`, and others.\n *\n * @param field - The Zod field to check\n * @returns True if the field has an unwrap method, false otherwise\n *\n * @example\n * ```typescript\n * const optionalField = z.string().optional();\n * console.log(canUnwrap(optionalField)); // true\n *\n * const plainField = z.string();\n * console.log(canUnwrap(plainField)); // false\n * ```\n *\n * @since 0.1.0\n */\nexport function canUnwrap(\n field: z.ZodTypeAny,\n): field is z.ZodTypeAny & Unwrappable {\n return 'unwrap' in field && typeof field.unwrap === 'function';\n}\n\n/**\n * Unwraps a ZodUnion type and returns the first field and all union options.\n *\n * This function extracts the individual type options from a union type.\n * By default, it filters out `ZodNull` and `ZodUndefined` types, returning only\n * the meaningful type options. You can disable this filtering to get all options.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field (union or single type)\n * @param options - Configuration options\n * @param options.filterNullish - Whether to filter out null and undefined types (default: true)\n * @returns Object with `field` (first option) and `union` (all options array)\n *\n * @example\n * Basic union unwrapping\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string(), z.number()] }\n * ```\n *\n * @example\n * Union with null (filtered by default)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Union with null (keep all options)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field, { filterNullish: false });\n * // Result: { field: z.string(), union: [z.string(), z.null()] }\n * ```\n *\n * @example\n * Non-union type (returns single field)\n * ```typescript\n * const field = z.string();\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Nullable as union\n * ```typescript\n * const field = z.string().nullable(); // This is z.union([z.string(), z.null()])\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] } (null filtered out)\n * ```\n *\n * @example\n * Using the first field for type checking\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const { field: firstField, union } = unwrapUnion(field);\n * if (firstField instanceof z.ZodString) {\n * console.log('First type is string');\n * }\n * ```\n *\n * @see {@link getPrimitiveType} for unwrapping wrapper types\n * @since 0.1.0\n */\nexport function unwrapUnion<T extends z.ZodTypeAny>(\n field: T,\n options: { filterNullish?: boolean } = {},\n): { field: z.ZodTypeAny; union: z.ZodTypeAny[] } {\n const { filterNullish = true } = options;\n\n if (field instanceof z.ZodUnion) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n const unionOptions = [...field.def.options] as z.ZodTypeAny[];\n\n const filteredOptions = filterNullish\n ? unionOptions.filter(\n (option) =>\n !(option instanceof z.ZodNull) &&\n !(option instanceof z.ZodUndefined),\n )\n : unionOptions;\n\n return {\n field: filteredOptions[0] || field,\n union: filteredOptions,\n };\n }\n\n // If it's not a union, return the field itself\n return {\n field,\n union: [field],\n };\n}\n\n/**\n * Gets the underlying primitive type of a Zod field by recursively unwrapping wrapper types.\n *\n * This function removes wrapper layers (optional, nullable, default) to reveal the base type.\n * **Important:** It stops at array types without unwrapping them, treating arrays as primitives.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field to unwrap\n * @returns The unwrapped primitive Zod type\n *\n * @example\n * Unwrapping to string primitive\n * ```typescript\n * const field = z.string().optional().nullable();\n * const primitive = getPrimitiveType(field);\n * // Result: z.string() (unwrapped all wrappers)\n * ```\n *\n * @example\n * Stopping at array type\n * ```typescript\n * const field = z.array(z.string()).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.array(z.string()) (stops at array, doesn't unwrap it)\n * ```\n *\n * @example\n * Unwrapping defaults\n * ```typescript\n * const field = z.number().default(0).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.number()\n * ```\n *\n * @see {@link canUnwrap} for checking if a field can be unwrapped\n * @since 0.1.0\n */\nexport const getPrimitiveType = <T extends z.ZodType>(\n field: T,\n): z.ZodTypeAny => {\n // Stop at arrays - don't unwrap them\n if (field instanceof z.ZodArray) {\n return field;\n }\n\n if (canUnwrap(field)) {\n return getPrimitiveType(field.unwrap());\n }\n\n if (field instanceof z.ZodUnion) {\n return getPrimitiveType(unwrapUnion(field).field);\n }\n\n return field;\n};\n\ntype StripZodDefault<T> = T extends z.ZodDefault<infer Inner>\n ? StripZodDefault<Inner>\n : T extends z.ZodOptional<infer Inner>\n ? z.ZodOptional<StripZodDefault<Inner>>\n : T extends z.ZodNullable<infer Inner>\n ? z.ZodNullable<StripZodDefault<Inner>>\n : T;\n\n/**\n * Removes default values from a Zod field while preserving other wrapper types.\n *\n * This function recursively removes `ZodDefault` wrappers from a field, while maintaining\n * `optional()` and `nullable()` wrappers. Useful for scenarios where you want to check\n * field requirements without considering default values.\n *\n * @template T - The Zod type to process\n * @param field - The Zod field to remove defaults from\n * @returns The field without defaults but with optional/nullable preserved\n *\n * @example\n * Removing simple default\n * ```typescript\n * const field = z.string().default('hello');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string()\n * ```\n *\n * @example\n * Preserving optional wrapper\n * ```typescript\n * const field = z.string().default('hello').optional();\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().optional()\n * ```\n *\n * @example\n * Nested defaults\n * ```typescript\n * const field = z.string().default('inner').nullable().default('outer');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().nullable()\n * ```\n *\n * @see {@link requiresValidInput} for usage with requirement checking\n * @since 0.1.0\n */\nexport function removeDefault<T extends z.ZodType>(\n field: T,\n): StripZodDefault<T> {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.unwrap() as StripZodDefault<T>;\n }\n\n if ('innerType' in field.def && field.def.innerType instanceof z.ZodType) {\n const inner = removeDefault(field.def.innerType);\n // Reconstruct the wrapper with the modified inner type\n if (field instanceof z.ZodOptional) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.optional() as unknown as StripZodDefault<T>;\n }\n if (field instanceof z.ZodNullable) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.nullable() as unknown as StripZodDefault<T>;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field as StripZodDefault<T>;\n}\n\n/**\n * Determines if a field will show validation errors when the user submits empty or invalid input.\n *\n * This is useful for form UIs to indicate which fields require valid user input (e.g., showing\n * asterisks, validation states). The key insight: **defaults are just initial values** - they\n * don't prevent validation errors if the user clears the field.\n *\n * **Real-world example:**\n * ```typescript\n * // Marital status field with default but validation rules\n * const maritalStatus = z.string().min(1).default('single');\n *\n * // Initial: field shows \"single\" (from default)\n * // User deletes the value → field is now empty string\n * // User submits form → validation fails because .min(1) rejects empty strings\n * // requiresValidInput(maritalStatus) → true (shows * indicator, validation error)\n * ```\n *\n * **How it works:**\n * 1. Removes `.default()` wrappers (defaults are initial values, not validation rules)\n * 2. Tests if the underlying schema accepts empty/invalid input:\n * - `undefined` (via `.optional()`)\n * - `null` (via `.nullable()`)\n * - Empty string (plain `z.string()` without `.min(1)` or `.nonempty()`)\n * - Empty array (plain `z.array()` without `.min(1)` or `.nonempty()`)\n * 3. Returns `true` if validation will fail, `false` if empty input is accepted\n *\n * @template T - The Zod type to check\n * @param field - The Zod field to check\n * @returns True if the field will show validation errors on empty/invalid input, false otherwise\n *\n * @example\n * User name field - required, no default\n * ```typescript\n * const userName = z.string().min(1);\n * requiresValidInput(userName); // true - will error if user submits empty\n * ```\n *\n * @example\n * Marital status - required WITH default\n * ```typescript\n * const maritalStatus = z.string().min(1).default('single');\n * requiresValidInput(maritalStatus); // true - will error if user clears and submits\n * ```\n *\n * @example\n * Age with default - requires valid input\n * ```typescript\n * const age = z.number().default(0);\n * requiresValidInput(age); // true - numbers reject empty strings\n * ```\n *\n * @example\n * Optional bio field - doesn't require input\n * ```typescript\n * const bio = z.string().optional();\n * requiresValidInput(bio); // false - user can leave empty\n * ```\n *\n * @example\n * String with default but NO validation - doesn't require input\n * ```typescript\n * const notes = z.string().default('N/A');\n * requiresValidInput(notes); // false - plain z.string() accepts empty strings\n * ```\n *\n * @example\n * Nullable field - doesn't require input\n * ```typescript\n * const middleName = z.string().nullable();\n * requiresValidInput(middleName); // false - user can leave null\n * ```\n *\n * @see {@link removeDefault} for understanding how defaults are handled\n * @see {@link getPrimitiveType} for understanding type unwrapping\n * @since 0.1.0\n */\nexport const requiresValidInput = <T extends z.ZodType>(field: T) => {\n const defaultRemovedField = removeDefault(field);\n if (!(defaultRemovedField instanceof z.ZodType)) {\n return false;\n }\n\n const undefinedResult = defaultRemovedField.safeParse(undefined).success;\n\n // Check if field accepts null (nullable)\n const nullResult = defaultRemovedField.safeParse(null).success;\n\n const primitiveType = getPrimitiveType(defaultRemovedField);\n\n const emptyStringResult =\n primitiveType.type === 'string' &&\n defaultRemovedField.safeParse('').success;\n\n const emptyArrayResult =\n primitiveType.type === 'array' && defaultRemovedField.safeParse([]).success;\n\n return (\n !undefinedResult && !nullResult && !emptyStringResult && !emptyArrayResult\n );\n};\n\n/**\n * Union type of all Zod check definition types.\n *\n * Includes all validation check types supported by Zod v4:\n * - **Length checks**: `min_length`, `max_length`, `length_equals` (strings, arrays)\n * - **Size checks**: `min_size`, `max_size`, `size_equals` (files, sets, maps)\n * - **Numeric checks**: `greater_than`, `less_than`, `multiple_of`\n * - **Format checks**: `number_format` (int32, float64, etc.), `bigint_format`, `string_format` (email, url, uuid, etc.)\n * - **String pattern checks**: `regex`, `lowercase`, `uppercase`, `includes`, `starts_with`, `ends_with`\n * - **Other checks**: `property`, `mime_type`, `overwrite`\n *\n * @since 0.4.0\n */\nexport type ZodUnionCheck =\n | $ZodCheckLessThanDef\n | $ZodCheckGreaterThanDef\n | $ZodCheckMultipleOfDef\n | $ZodCheckNumberFormatDef\n | $ZodCheckBigIntFormatDef\n | $ZodCheckMaxSizeDef\n | $ZodCheckMinSizeDef\n | $ZodCheckSizeEqualsDef\n | $ZodCheckMaxLengthDef\n | $ZodCheckMinLengthDef\n | $ZodCheckLengthEqualsDef\n | $ZodCheckStringFormatDef\n | $ZodCheckRegexDef\n | $ZodCheckLowerCaseDef\n | $ZodCheckUpperCaseDef\n | $ZodCheckIncludesDef\n | $ZodCheckStartsWithDef\n | $ZodCheckEndsWithDef\n | $ZodCheckPropertyDef\n | $ZodCheckMimeTypeDef\n | $ZodCheckOverwriteDef;\n\n/**\n * Extracts all validation check definitions from a Zod schema field.\n *\n * This function analyzes a Zod field and returns all check definitions as defined\n * by Zod's internal structure. Returns Zod's raw check definition objects directly,\n * including all properties like `check`, `minimum`, `maximum`, `value`, `inclusive`,\n * `format`, `pattern`, etc.\n *\n * **Unwrapping behavior:** Automatically unwraps optional, nullable, and default layers.\n * For unions, checks only the first option (same as other schema utilities).\n *\n * **Supported check types:** Returns any of the 21 check types defined in {@link ZodUnionCheck},\n * including length, size, numeric range, format validation, string patterns, and more.\n *\n * @template T - The Zod type to extract checks from\n * @param field - The Zod field to analyze\n * @returns Array of Zod check definition objects (see {@link ZodUnionCheck})\n *\n * @example\n * String with length constraints\n * ```typescript\n * const username = z.string().min(3).max(20);\n * const checks = getFieldChecks(username);\n * // [\n * // { check: 'min_length', minimum: 3, when: [Function], ... },\n * // { check: 'max_length', maximum: 20, when: [Function], ... }\n * // ]\n * ```\n *\n * @example\n * Number with range constraints\n * ```typescript\n * const age = z.number().min(18).max(120);\n * const checks = getFieldChecks(age);\n * // [\n * // { check: 'greater_than', value: 18, inclusive: true, when: [Function], ... },\n * // { check: 'less_than', value: 120, inclusive: true, when: [Function], ... }\n * // ]\n * ```\n *\n * @example\n * Array with item count constraints\n * ```typescript\n * const tags = z.array(z.string()).min(1).max(5);\n * const checks = getFieldChecks(tags);\n * // [\n * // { check: 'min_length', minimum: 1, ... },\n * // { check: 'max_length', maximum: 5, ... }\n * // ]\n * ```\n *\n * @example\n * String with format validation\n * ```typescript\n * const email = z.string().email();\n * const checks = getFieldChecks(email);\n * // [\n * // { check: 'string_format', format: 'email', ... }\n * // ]\n * ```\n *\n * @example\n * Unwrapping optional/nullable/default layers\n * ```typescript\n * const bio = z.string().min(10).max(500).optional();\n * const checks = getFieldChecks(bio);\n * // [\n * // { check: 'min_length', minimum: 10, ... },\n * // { check: 'max_length', maximum: 500, ... }\n * // ]\n * ```\n *\n * @see {@link ZodUnionCheck} for all supported check types\n * @since 0.4.0\n */\nexport function getFieldChecks<T extends z.ZodTypeAny>(\n field: T,\n): Array<ZodUnionCheck> {\n const primitiveType = getPrimitiveType(field);\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return (primitiveType.def.checks?.map((check) => check._zod.def) ||\n []) as Array<ZodUnionCheck>;\n}\n","import * as z from 'zod';\nimport { canUnwrap, unwrapUnion } from './schema';\nimport type { Simplify } from './types';\n\n/**\n * Extracts the default value from a Zod field, recursively unwrapping optional, nullable, and union layers.\n *\n * This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`, `ZodUnion`) to find\n * the underlying `ZodDefault` and returns its default value. If no default is found, returns `undefined`.\n *\n * **Union handling:** For union types, extracts the default from the first option. If the first option\n * has no default, returns `undefined` (defaults in other union options are not checked).\n *\n * @template T - The Zod type to extract default from\n * @param field - The Zod field to extract default from\n * @returns The default value if present, undefined otherwise\n *\n * @example\n * Basic usage with default value\n * ```typescript\n * const field = z.string().default('hello');\n * const defaultValue = extractDefault(field);\n * // Result: 'hello'\n * ```\n *\n * @example\n * Unwrapping optional/nullable layers\n * ```typescript\n * const field = z.string().default('world').optional();\n * const defaultValue = extractDefault(field);\n * // Result: 'world' (unwraps optional to find default)\n * ```\n *\n * @example\n * Union with default in first option\n * ```typescript\n * const field = z.union([z.string().default('hello'), z.number()]);\n * const defaultValue = extractDefault(field);\n * // Result: 'hello' (extracts from first union option)\n * ```\n *\n * @example\n * Union with default in second option\n * ```typescript\n * const field = z.union([z.string(), z.number().default(42)]);\n * const defaultValue = extractDefault(field);\n * // Result: undefined (only checks first option)\n * ```\n *\n * @example\n * Field without default\n * ```typescript\n * const field = z.string().optional();\n * const defaultValue = extractDefault(field);\n * // Result: undefined\n * ```\n *\n * @see {@link getSchemaDefaults} for extracting defaults from entire schemas\n * @since 0.1.0\n */\nexport function extractDefault<T extends z.ZodTypeAny>(\n field: T,\n): z.infer<T> | undefined {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.def.defaultValue as z.infer<T>;\n }\n\n if (canUnwrap(field)) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return extractDefault(field.unwrap()) as z.infer<T>;\n }\n\n if (field instanceof z.ZodUnion) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return extractDefault(unwrapUnion(field).field) as z.infer<T>;\n }\n\n return undefined;\n}\n\n/**\n * Extracts default values from a Zod object schema while skipping fields without defaults.\n *\n * This function recursively traverses the schema and collects all fields that have\n * explicit default values defined. Fields without defaults are excluded from the result.\n *\n * **Important:** Nested defaults are NOT extracted unless the parent object also has\n * an explicit `.default()`. This is by design to match Zod's default value behavior.\n *\n * @template T - The Zod object schema type\n * @param schema - The Zod object schema to extract defaults from\n * @returns A partial object containing only fields with default values\n *\n * @example\n * Basic usage\n * ```typescript\n * const schema = z.object({\n * name: z.string().default('John'),\n * age: z.number(), // no default - will be skipped\n * email: z.string().email().optional(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { name: 'John' }\n * ```\n *\n * @example\n * Nested objects with defaults\n * ```typescript\n * const schema = z.object({\n * user: z.object({\n * name: z.string().default('Guest')\n * }).default({ name: 'Guest' }), // ✅ Extracted because parent has .default()\n *\n * settings: z.object({\n * theme: z.string().default('light')\n * }), // ❌ NOT extracted - parent has no .default()\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { user: { name: 'Guest' } }\n * ```\n *\n * @example\n * Unwrapping optional/nullable fields\n * ```typescript\n * const schema = z.object({\n * title: z.string().default('Untitled').optional(),\n * count: z.number().default(0).nullable(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { title: 'Untitled', count: 0 }\n * ```\n *\n * @see {@link extractDefault} for extracting defaults from individual fields\n * @since 0.1.0\n */\nexport function getSchemaDefaults<T extends z.ZodObject>(\n schema: T,\n): Simplify<Partial<z.infer<T>>> {\n const defaults: Record<string, unknown> = {};\n\n for (const key in schema.shape) {\n const field = schema.shape[key];\n if (!field) continue;\n\n // Check if this field has an explicit default value\n const defaultValue = extractDefault(field);\n if (defaultValue !== undefined) {\n defaults[key] = defaultValue;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return defaults as Partial<z.infer<T>>;\n}\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -60,6 +60,11 @@ var requiresValidInput = (field) => {
|
|
|
60
60
|
const emptyArrayResult = primitiveType.type === "array" && defaultRemovedField.safeParse([]).success;
|
|
61
61
|
return !undefinedResult && !nullResult && !emptyStringResult && !emptyArrayResult;
|
|
62
62
|
};
|
|
63
|
+
function getFieldChecks(field) {
|
|
64
|
+
var _a;
|
|
65
|
+
const primitiveType = getPrimitiveType(field);
|
|
66
|
+
return ((_a = primitiveType.def.checks) == null ? void 0 : _a.map((check) => check._zod.def)) || [];
|
|
67
|
+
}
|
|
63
68
|
|
|
64
69
|
// src/defaults.ts
|
|
65
70
|
function extractDefault(field) {
|
|
@@ -69,6 +74,9 @@ function extractDefault(field) {
|
|
|
69
74
|
if (canUnwrap(field)) {
|
|
70
75
|
return extractDefault(field.unwrap());
|
|
71
76
|
}
|
|
77
|
+
if (field instanceof z.ZodUnion) {
|
|
78
|
+
return extractDefault(unwrapUnion(field).field);
|
|
79
|
+
}
|
|
72
80
|
return void 0;
|
|
73
81
|
}
|
|
74
82
|
function getSchemaDefaults(schema) {
|
|
@@ -84,6 +92,6 @@ function getSchemaDefaults(schema) {
|
|
|
84
92
|
return defaults;
|
|
85
93
|
}
|
|
86
94
|
|
|
87
|
-
export { canUnwrap, extractDefault, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, unwrapUnion };
|
|
95
|
+
export { canUnwrap, extractDefault, getFieldChecks, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, unwrapUnion };
|
|
88
96
|
//# sourceMappingURL=index.mjs.map
|
|
89
97
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema.ts","../src/defaults.ts"],"names":["z2"],"mappings":"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","file":"index.mjs","sourcesContent":["import * as z from 'zod';\n\n/**\n * Type representing a Zod type that has an unwrap method\n */\ntype Unwrappable = { unwrap: () => z.ZodTypeAny };\n\n/**\n * Type guard to check if a Zod field can be unwrapped (has wrapper types like optional, nullable, default).\n *\n * This checks whether a Zod type has an `unwrap()` method, which is present on wrapper types\n * like `ZodOptional`, `ZodNullable`, `ZodDefault`, and others.\n *\n * @param field - The Zod field to check\n * @returns True if the field has an unwrap method, false otherwise\n *\n * @example\n * ```typescript\n * const optionalField = z.string().optional();\n * console.log(canUnwrap(optionalField)); // true\n *\n * const plainField = z.string();\n * console.log(canUnwrap(plainField)); // false\n * ```\n *\n * @since 0.1.0\n */\nexport function canUnwrap(\n field: z.ZodTypeAny,\n): field is z.ZodTypeAny & Unwrappable {\n return 'unwrap' in field && typeof field.unwrap === 'function';\n}\n\n/**\n * Unwraps a ZodUnion type and returns the first field and all union options.\n *\n * This function extracts the individual type options from a union type.\n * By default, it filters out `ZodNull` and `ZodUndefined` types, returning only\n * the meaningful type options. You can disable this filtering to get all options.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field (union or single type)\n * @param options - Configuration options\n * @param options.filterNullish - Whether to filter out null and undefined types (default: true)\n * @returns Object with `field` (first option) and `union` (all options array)\n *\n * @example\n * Basic union unwrapping\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string(), z.number()] }\n * ```\n *\n * @example\n * Union with null (filtered by default)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Union with null (keep all options)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field, { filterNullish: false });\n * // Result: { field: z.string(), union: [z.string(), z.null()] }\n * ```\n *\n * @example\n * Non-union type (returns single field)\n * ```typescript\n * const field = z.string();\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Nullable as union\n * ```typescript\n * const field = z.string().nullable(); // This is z.union([z.string(), z.null()])\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] } (null filtered out)\n * ```\n *\n * @example\n * Using the first field for type checking\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const { field: firstField, union } = unwrapUnion(field);\n * if (firstField instanceof z.ZodString) {\n * console.log('First type is string');\n * }\n * ```\n *\n * @see {@link getPrimitiveType} for unwrapping wrapper types\n * @since 0.1.0\n */\nexport function unwrapUnion<T extends z.ZodTypeAny>(\n field: T,\n options: { filterNullish?: boolean } = {},\n): { field: z.ZodTypeAny; union: z.ZodTypeAny[] } {\n const { filterNullish = true } = options;\n\n if (field instanceof z.ZodUnion) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n const unionOptions = [...field.def.options] as z.ZodTypeAny[];\n\n const filteredOptions = filterNullish\n ? unionOptions.filter(\n (option) =>\n !(option instanceof z.ZodNull) &&\n !(option instanceof z.ZodUndefined),\n )\n : unionOptions;\n\n return {\n field: filteredOptions[0] || field,\n union: filteredOptions,\n };\n }\n\n // If it's not a union, return the field itself\n return {\n field,\n union: [field],\n };\n}\n\n/**\n * Gets the underlying primitive type of a Zod field by recursively unwrapping wrapper types.\n *\n * This function removes wrapper layers (optional, nullable, default) to reveal the base type.\n * **Important:** It stops at array types without unwrapping them, treating arrays as primitives.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field to unwrap\n * @returns The unwrapped primitive Zod type\n *\n * @example\n * Unwrapping to string primitive\n * ```typescript\n * const field = z.string().optional().nullable();\n * const primitive = getPrimitiveType(field);\n * // Result: z.string() (unwrapped all wrappers)\n * ```\n *\n * @example\n * Stopping at array type\n * ```typescript\n * const field = z.array(z.string()).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.array(z.string()) (stops at array, doesn't unwrap it)\n * ```\n *\n * @example\n * Unwrapping defaults\n * ```typescript\n * const field = z.number().default(0).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.number()\n * ```\n *\n * @see {@link canUnwrap} for checking if a field can be unwrapped\n * @since 0.1.0\n */\nexport const getPrimitiveType = <T extends z.ZodType>(\n field: T,\n): z.ZodTypeAny => {\n // Stop at arrays - don't unwrap them\n if (field instanceof z.ZodArray) {\n return field;\n }\n\n if (canUnwrap(field)) {\n return getPrimitiveType(field.unwrap());\n }\n\n if (field instanceof z.ZodUnion) {\n return getPrimitiveType(unwrapUnion(field).field);\n }\n\n return field;\n};\n\ntype StripZodDefault<T> = T extends z.ZodDefault<infer Inner>\n ? StripZodDefault<Inner>\n : T extends z.ZodOptional<infer Inner>\n ? z.ZodOptional<StripZodDefault<Inner>>\n : T extends z.ZodNullable<infer Inner>\n ? z.ZodNullable<StripZodDefault<Inner>>\n : T;\n\n/**\n * Removes default values from a Zod field while preserving other wrapper types.\n *\n * This function recursively removes `ZodDefault` wrappers from a field, while maintaining\n * `optional()` and `nullable()` wrappers. Useful for scenarios where you want to check\n * field requirements without considering default values.\n *\n * @template T - The Zod type to process\n * @param field - The Zod field to remove defaults from\n * @returns The field without defaults but with optional/nullable preserved\n *\n * @example\n * Removing simple default\n * ```typescript\n * const field = z.string().default('hello');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string()\n * ```\n *\n * @example\n * Preserving optional wrapper\n * ```typescript\n * const field = z.string().default('hello').optional();\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().optional()\n * ```\n *\n * @example\n * Nested defaults\n * ```typescript\n * const field = z.string().default('inner').nullable().default('outer');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().nullable()\n * ```\n *\n * @see {@link requiresValidInput} for usage with requirement checking\n * @since 0.1.0\n */\nexport function removeDefault<T extends z.ZodType>(\n field: T,\n): StripZodDefault<T> {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.unwrap() as StripZodDefault<T>;\n }\n\n if ('innerType' in field.def && field.def.innerType instanceof z.ZodType) {\n const inner = removeDefault(field.def.innerType);\n // Reconstruct the wrapper with the modified inner type\n if (field instanceof z.ZodOptional) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.optional() as unknown as StripZodDefault<T>;\n }\n if (field instanceof z.ZodNullable) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.nullable() as unknown as StripZodDefault<T>;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field as StripZodDefault<T>;\n}\n\n/**\n * Determines if a field will show validation errors when the user submits empty or invalid input.\n *\n * This is useful for form UIs to indicate which fields require valid user input (e.g., showing\n * asterisks, validation states). The key insight: **defaults are just initial values** - they\n * don't prevent validation errors if the user clears the field.\n *\n * **Real-world example:**\n * ```typescript\n * // Marital status field with default but validation rules\n * const maritalStatus = z.string().min(1).default('single');\n *\n * // Initial: field shows \"single\" (from default)\n * // User deletes the value → field is now empty string\n * // User submits form → validation fails because .min(1) rejects empty strings\n * // requiresValidInput(maritalStatus) → true (shows * indicator, validation error)\n * ```\n *\n * **How it works:**\n * 1. Removes `.default()` wrappers (defaults are initial values, not validation rules)\n * 2. Tests if the underlying schema accepts empty/invalid input:\n * - `undefined` (via `.optional()`)\n * - `null` (via `.nullable()`)\n * - Empty string (plain `z.string()` without `.min(1)` or `.nonempty()`)\n * - Empty array (plain `z.array()` without `.min(1)` or `.nonempty()`)\n * 3. Returns `true` if validation will fail, `false` if empty input is accepted\n *\n * @template T - The Zod type to check\n * @param field - The Zod field to check\n * @returns True if the field will show validation errors on empty/invalid input, false otherwise\n *\n * @example\n * User name field - required, no default\n * ```typescript\n * const userName = z.string().min(1);\n * requiresValidInput(userName); // true - will error if user submits empty\n * ```\n *\n * @example\n * Marital status - required WITH default\n * ```typescript\n * const maritalStatus = z.string().min(1).default('single');\n * requiresValidInput(maritalStatus); // true - will error if user clears and submits\n * ```\n *\n * @example\n * Age with default - requires valid input\n * ```typescript\n * const age = z.number().default(0);\n * requiresValidInput(age); // true - numbers reject empty strings\n * ```\n *\n * @example\n * Optional bio field - doesn't require input\n * ```typescript\n * const bio = z.string().optional();\n * requiresValidInput(bio); // false - user can leave empty\n * ```\n *\n * @example\n * String with default but NO validation - doesn't require input\n * ```typescript\n * const notes = z.string().default('N/A');\n * requiresValidInput(notes); // false - plain z.string() accepts empty strings\n * ```\n *\n * @example\n * Nullable field - doesn't require input\n * ```typescript\n * const middleName = z.string().nullable();\n * requiresValidInput(middleName); // false - user can leave null\n * ```\n *\n * @see {@link removeDefault} for understanding how defaults are handled\n * @see {@link getPrimitiveType} for understanding type unwrapping\n * @since 0.1.0\n */\nexport const requiresValidInput = <T extends z.ZodType>(field: T) => {\n const defaultRemovedField = removeDefault(field);\n if (!(defaultRemovedField instanceof z.ZodType)) {\n return false;\n }\n\n const undefinedResult = defaultRemovedField.safeParse(undefined).success;\n\n // Check if field accepts null (nullable)\n const nullResult = defaultRemovedField.safeParse(null).success;\n\n const primitiveType = getPrimitiveType(defaultRemovedField);\n\n const emptyStringResult =\n primitiveType.type === 'string' &&\n defaultRemovedField.safeParse('').success;\n\n const emptyArrayResult =\n primitiveType.type === 'array' && defaultRemovedField.safeParse([]).success;\n\n return (\n !undefinedResult && !nullResult && !emptyStringResult && !emptyArrayResult\n );\n};\n","import * as z from 'zod';\nimport { canUnwrap } from './schema';\nimport type { Simplify } from './types';\n\n/**\n * Extracts the default value from a Zod field, recursively unwrapping optional and nullable layers.\n *\n * This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`) to find\n * the underlying `ZodDefault` and returns its default value. If no default is found, returns `undefined`.\n *\n * @template T - The Zod type to extract default from\n * @param field - The Zod field to extract default from\n * @returns The default value if present, undefined otherwise\n *\n * @example\n * Basic usage with default value\n * ```typescript\n * const field = z.string().default('hello');\n * const defaultValue = extractDefault(field);\n * // Result: 'hello'\n * ```\n *\n * @example\n * Unwrapping optional/nullable layers\n * ```typescript\n * const field = z.string().default('world').optional();\n * const defaultValue = extractDefault(field);\n * // Result: 'world' (unwraps optional to find default)\n * ```\n *\n * @example\n * Field without default\n * ```typescript\n * const field = z.string().optional();\n * const defaultValue = extractDefault(field);\n * // Result: undefined\n * ```\n *\n * @see {@link getSchemaDefaults} for extracting defaults from entire schemas\n * @since 0.1.0\n */\nexport function extractDefault<T extends z.ZodTypeAny>(\n field: T,\n): z.infer<T> | undefined {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.def.defaultValue as z.infer<T>;\n }\n\n if (canUnwrap(field)) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return extractDefault(field.unwrap()) as z.infer<T>;\n }\n\n return undefined;\n}\n\n/**\n * Extracts default values from a Zod object schema while skipping fields without defaults.\n *\n * This function recursively traverses the schema and collects all fields that have\n * explicit default values defined. Fields without defaults are excluded from the result.\n *\n * **Important:** Nested defaults are NOT extracted unless the parent object also has\n * an explicit `.default()`. This is by design to match Zod's default value behavior.\n *\n * @template T - The Zod object schema type\n * @param schema - The Zod object schema to extract defaults from\n * @returns A partial object containing only fields with default values\n *\n * @example\n * Basic usage\n * ```typescript\n * const schema = z.object({\n * name: z.string().default('John'),\n * age: z.number(), // no default - will be skipped\n * email: z.string().email().optional(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { name: 'John' }\n * ```\n *\n * @example\n * Nested objects with defaults\n * ```typescript\n * const schema = z.object({\n * user: z.object({\n * name: z.string().default('Guest')\n * }).default({ name: 'Guest' }), // ✅ Extracted because parent has .default()\n *\n * settings: z.object({\n * theme: z.string().default('light')\n * }), // ❌ NOT extracted - parent has no .default()\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { user: { name: 'Guest' } }\n * ```\n *\n * @example\n * Unwrapping optional/nullable fields\n * ```typescript\n * const schema = z.object({\n * title: z.string().default('Untitled').optional(),\n * count: z.number().default(0).nullable(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { title: 'Untitled', count: 0 }\n * ```\n *\n * @see {@link extractDefault} for extracting defaults from individual fields\n * @since 0.1.0\n */\nexport function getSchemaDefaults<T extends z.ZodObject>(\n schema: T,\n): Simplify<Partial<z.infer<T>>> {\n const defaults: Record<string, unknown> = {};\n\n for (const key in schema.shape) {\n const field = schema.shape[key];\n if (!field) continue;\n\n // Check if this field has an explicit default value\n const defaultValue = extractDefault(field);\n if (defaultValue !== undefined) {\n defaults[key] = defaultValue;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return defaults as Partial<z.infer<T>>;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/defaults.ts"],"names":["z2"],"mappings":"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","file":"index.mjs","sourcesContent":["import * as z from 'zod';\nimport type {\n $ZodCheckBigIntFormatDef,\n $ZodCheckEndsWithDef,\n $ZodCheckGreaterThanDef,\n $ZodCheckIncludesDef,\n $ZodCheckLengthEqualsDef,\n $ZodCheckLessThanDef,\n $ZodCheckLowerCaseDef,\n $ZodCheckMaxLengthDef,\n $ZodCheckMaxSizeDef,\n $ZodCheckMimeTypeDef,\n $ZodCheckMinLengthDef,\n $ZodCheckMinSizeDef,\n $ZodCheckMultipleOfDef,\n $ZodCheckNumberFormatDef,\n $ZodCheckOverwriteDef,\n $ZodCheckPropertyDef,\n $ZodCheckRegexDef,\n $ZodCheckSizeEqualsDef,\n $ZodCheckStartsWithDef,\n $ZodCheckStringFormatDef,\n $ZodCheckUpperCaseDef,\n} from 'zod/v4/core';\n\n/**\n * Type representing a Zod type that has an unwrap method\n */\ntype Unwrappable = { unwrap: () => z.ZodTypeAny };\n\n/**\n * Type guard to check if a Zod field can be unwrapped (has wrapper types like optional, nullable, default).\n *\n * This checks whether a Zod type has an `unwrap()` method, which is present on wrapper types\n * like `ZodOptional`, `ZodNullable`, `ZodDefault`, and others.\n *\n * @param field - The Zod field to check\n * @returns True if the field has an unwrap method, false otherwise\n *\n * @example\n * ```typescript\n * const optionalField = z.string().optional();\n * console.log(canUnwrap(optionalField)); // true\n *\n * const plainField = z.string();\n * console.log(canUnwrap(plainField)); // false\n * ```\n *\n * @since 0.1.0\n */\nexport function canUnwrap(\n field: z.ZodTypeAny,\n): field is z.ZodTypeAny & Unwrappable {\n return 'unwrap' in field && typeof field.unwrap === 'function';\n}\n\n/**\n * Unwraps a ZodUnion type and returns the first field and all union options.\n *\n * This function extracts the individual type options from a union type.\n * By default, it filters out `ZodNull` and `ZodUndefined` types, returning only\n * the meaningful type options. You can disable this filtering to get all options.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field (union or single type)\n * @param options - Configuration options\n * @param options.filterNullish - Whether to filter out null and undefined types (default: true)\n * @returns Object with `field` (first option) and `union` (all options array)\n *\n * @example\n * Basic union unwrapping\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string(), z.number()] }\n * ```\n *\n * @example\n * Union with null (filtered by default)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Union with null (keep all options)\n * ```typescript\n * const field = z.union([z.string(), z.null()]);\n * const result = unwrapUnion(field, { filterNullish: false });\n * // Result: { field: z.string(), union: [z.string(), z.null()] }\n * ```\n *\n * @example\n * Non-union type (returns single field)\n * ```typescript\n * const field = z.string();\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] }\n * ```\n *\n * @example\n * Nullable as union\n * ```typescript\n * const field = z.string().nullable(); // This is z.union([z.string(), z.null()])\n * const result = unwrapUnion(field);\n * // Result: { field: z.string(), union: [z.string()] } (null filtered out)\n * ```\n *\n * @example\n * Using the first field for type checking\n * ```typescript\n * const field = z.union([z.string(), z.number()]);\n * const { field: firstField, union } = unwrapUnion(field);\n * if (firstField instanceof z.ZodString) {\n * console.log('First type is string');\n * }\n * ```\n *\n * @see {@link getPrimitiveType} for unwrapping wrapper types\n * @since 0.1.0\n */\nexport function unwrapUnion<T extends z.ZodTypeAny>(\n field: T,\n options: { filterNullish?: boolean } = {},\n): { field: z.ZodTypeAny; union: z.ZodTypeAny[] } {\n const { filterNullish = true } = options;\n\n if (field instanceof z.ZodUnion) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n const unionOptions = [...field.def.options] as z.ZodTypeAny[];\n\n const filteredOptions = filterNullish\n ? unionOptions.filter(\n (option) =>\n !(option instanceof z.ZodNull) &&\n !(option instanceof z.ZodUndefined),\n )\n : unionOptions;\n\n return {\n field: filteredOptions[0] || field,\n union: filteredOptions,\n };\n }\n\n // If it's not a union, return the field itself\n return {\n field,\n union: [field],\n };\n}\n\n/**\n * Gets the underlying primitive type of a Zod field by recursively unwrapping wrapper types.\n *\n * This function removes wrapper layers (optional, nullable, default) to reveal the base type.\n * **Important:** It stops at array types without unwrapping them, treating arrays as primitives.\n *\n * @template T - The Zod type to unwrap\n * @param field - The Zod field to unwrap\n * @returns The unwrapped primitive Zod type\n *\n * @example\n * Unwrapping to string primitive\n * ```typescript\n * const field = z.string().optional().nullable();\n * const primitive = getPrimitiveType(field);\n * // Result: z.string() (unwrapped all wrappers)\n * ```\n *\n * @example\n * Stopping at array type\n * ```typescript\n * const field = z.array(z.string()).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.array(z.string()) (stops at array, doesn't unwrap it)\n * ```\n *\n * @example\n * Unwrapping defaults\n * ```typescript\n * const field = z.number().default(0).optional();\n * const primitive = getPrimitiveType(field);\n * // Result: z.number()\n * ```\n *\n * @see {@link canUnwrap} for checking if a field can be unwrapped\n * @since 0.1.0\n */\nexport const getPrimitiveType = <T extends z.ZodType>(\n field: T,\n): z.ZodTypeAny => {\n // Stop at arrays - don't unwrap them\n if (field instanceof z.ZodArray) {\n return field;\n }\n\n if (canUnwrap(field)) {\n return getPrimitiveType(field.unwrap());\n }\n\n if (field instanceof z.ZodUnion) {\n return getPrimitiveType(unwrapUnion(field).field);\n }\n\n return field;\n};\n\ntype StripZodDefault<T> = T extends z.ZodDefault<infer Inner>\n ? StripZodDefault<Inner>\n : T extends z.ZodOptional<infer Inner>\n ? z.ZodOptional<StripZodDefault<Inner>>\n : T extends z.ZodNullable<infer Inner>\n ? z.ZodNullable<StripZodDefault<Inner>>\n : T;\n\n/**\n * Removes default values from a Zod field while preserving other wrapper types.\n *\n * This function recursively removes `ZodDefault` wrappers from a field, while maintaining\n * `optional()` and `nullable()` wrappers. Useful for scenarios where you want to check\n * field requirements without considering default values.\n *\n * @template T - The Zod type to process\n * @param field - The Zod field to remove defaults from\n * @returns The field without defaults but with optional/nullable preserved\n *\n * @example\n * Removing simple default\n * ```typescript\n * const field = z.string().default('hello');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string()\n * ```\n *\n * @example\n * Preserving optional wrapper\n * ```typescript\n * const field = z.string().default('hello').optional();\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().optional()\n * ```\n *\n * @example\n * Nested defaults\n * ```typescript\n * const field = z.string().default('inner').nullable().default('outer');\n * const withoutDefault = removeDefault(field);\n * // Result: z.string().nullable()\n * ```\n *\n * @see {@link requiresValidInput} for usage with requirement checking\n * @since 0.1.0\n */\nexport function removeDefault<T extends z.ZodType>(\n field: T,\n): StripZodDefault<T> {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.unwrap() as StripZodDefault<T>;\n }\n\n if ('innerType' in field.def && field.def.innerType instanceof z.ZodType) {\n const inner = removeDefault(field.def.innerType);\n // Reconstruct the wrapper with the modified inner type\n if (field instanceof z.ZodOptional) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.optional() as unknown as StripZodDefault<T>;\n }\n if (field instanceof z.ZodNullable) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return inner.nullable() as unknown as StripZodDefault<T>;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field as StripZodDefault<T>;\n}\n\n/**\n * Determines if a field will show validation errors when the user submits empty or invalid input.\n *\n * This is useful for form UIs to indicate which fields require valid user input (e.g., showing\n * asterisks, validation states). The key insight: **defaults are just initial values** - they\n * don't prevent validation errors if the user clears the field.\n *\n * **Real-world example:**\n * ```typescript\n * // Marital status field with default but validation rules\n * const maritalStatus = z.string().min(1).default('single');\n *\n * // Initial: field shows \"single\" (from default)\n * // User deletes the value → field is now empty string\n * // User submits form → validation fails because .min(1) rejects empty strings\n * // requiresValidInput(maritalStatus) → true (shows * indicator, validation error)\n * ```\n *\n * **How it works:**\n * 1. Removes `.default()` wrappers (defaults are initial values, not validation rules)\n * 2. Tests if the underlying schema accepts empty/invalid input:\n * - `undefined` (via `.optional()`)\n * - `null` (via `.nullable()`)\n * - Empty string (plain `z.string()` without `.min(1)` or `.nonempty()`)\n * - Empty array (plain `z.array()` without `.min(1)` or `.nonempty()`)\n * 3. Returns `true` if validation will fail, `false` if empty input is accepted\n *\n * @template T - The Zod type to check\n * @param field - The Zod field to check\n * @returns True if the field will show validation errors on empty/invalid input, false otherwise\n *\n * @example\n * User name field - required, no default\n * ```typescript\n * const userName = z.string().min(1);\n * requiresValidInput(userName); // true - will error if user submits empty\n * ```\n *\n * @example\n * Marital status - required WITH default\n * ```typescript\n * const maritalStatus = z.string().min(1).default('single');\n * requiresValidInput(maritalStatus); // true - will error if user clears and submits\n * ```\n *\n * @example\n * Age with default - requires valid input\n * ```typescript\n * const age = z.number().default(0);\n * requiresValidInput(age); // true - numbers reject empty strings\n * ```\n *\n * @example\n * Optional bio field - doesn't require input\n * ```typescript\n * const bio = z.string().optional();\n * requiresValidInput(bio); // false - user can leave empty\n * ```\n *\n * @example\n * String with default but NO validation - doesn't require input\n * ```typescript\n * const notes = z.string().default('N/A');\n * requiresValidInput(notes); // false - plain z.string() accepts empty strings\n * ```\n *\n * @example\n * Nullable field - doesn't require input\n * ```typescript\n * const middleName = z.string().nullable();\n * requiresValidInput(middleName); // false - user can leave null\n * ```\n *\n * @see {@link removeDefault} for understanding how defaults are handled\n * @see {@link getPrimitiveType} for understanding type unwrapping\n * @since 0.1.0\n */\nexport const requiresValidInput = <T extends z.ZodType>(field: T) => {\n const defaultRemovedField = removeDefault(field);\n if (!(defaultRemovedField instanceof z.ZodType)) {\n return false;\n }\n\n const undefinedResult = defaultRemovedField.safeParse(undefined).success;\n\n // Check if field accepts null (nullable)\n const nullResult = defaultRemovedField.safeParse(null).success;\n\n const primitiveType = getPrimitiveType(defaultRemovedField);\n\n const emptyStringResult =\n primitiveType.type === 'string' &&\n defaultRemovedField.safeParse('').success;\n\n const emptyArrayResult =\n primitiveType.type === 'array' && defaultRemovedField.safeParse([]).success;\n\n return (\n !undefinedResult && !nullResult && !emptyStringResult && !emptyArrayResult\n );\n};\n\n/**\n * Union type of all Zod check definition types.\n *\n * Includes all validation check types supported by Zod v4:\n * - **Length checks**: `min_length`, `max_length`, `length_equals` (strings, arrays)\n * - **Size checks**: `min_size`, `max_size`, `size_equals` (files, sets, maps)\n * - **Numeric checks**: `greater_than`, `less_than`, `multiple_of`\n * - **Format checks**: `number_format` (int32, float64, etc.), `bigint_format`, `string_format` (email, url, uuid, etc.)\n * - **String pattern checks**: `regex`, `lowercase`, `uppercase`, `includes`, `starts_with`, `ends_with`\n * - **Other checks**: `property`, `mime_type`, `overwrite`\n *\n * @since 0.4.0\n */\nexport type ZodUnionCheck =\n | $ZodCheckLessThanDef\n | $ZodCheckGreaterThanDef\n | $ZodCheckMultipleOfDef\n | $ZodCheckNumberFormatDef\n | $ZodCheckBigIntFormatDef\n | $ZodCheckMaxSizeDef\n | $ZodCheckMinSizeDef\n | $ZodCheckSizeEqualsDef\n | $ZodCheckMaxLengthDef\n | $ZodCheckMinLengthDef\n | $ZodCheckLengthEqualsDef\n | $ZodCheckStringFormatDef\n | $ZodCheckRegexDef\n | $ZodCheckLowerCaseDef\n | $ZodCheckUpperCaseDef\n | $ZodCheckIncludesDef\n | $ZodCheckStartsWithDef\n | $ZodCheckEndsWithDef\n | $ZodCheckPropertyDef\n | $ZodCheckMimeTypeDef\n | $ZodCheckOverwriteDef;\n\n/**\n * Extracts all validation check definitions from a Zod schema field.\n *\n * This function analyzes a Zod field and returns all check definitions as defined\n * by Zod's internal structure. Returns Zod's raw check definition objects directly,\n * including all properties like `check`, `minimum`, `maximum`, `value`, `inclusive`,\n * `format`, `pattern`, etc.\n *\n * **Unwrapping behavior:** Automatically unwraps optional, nullable, and default layers.\n * For unions, checks only the first option (same as other schema utilities).\n *\n * **Supported check types:** Returns any of the 21 check types defined in {@link ZodUnionCheck},\n * including length, size, numeric range, format validation, string patterns, and more.\n *\n * @template T - The Zod type to extract checks from\n * @param field - The Zod field to analyze\n * @returns Array of Zod check definition objects (see {@link ZodUnionCheck})\n *\n * @example\n * String with length constraints\n * ```typescript\n * const username = z.string().min(3).max(20);\n * const checks = getFieldChecks(username);\n * // [\n * // { check: 'min_length', minimum: 3, when: [Function], ... },\n * // { check: 'max_length', maximum: 20, when: [Function], ... }\n * // ]\n * ```\n *\n * @example\n * Number with range constraints\n * ```typescript\n * const age = z.number().min(18).max(120);\n * const checks = getFieldChecks(age);\n * // [\n * // { check: 'greater_than', value: 18, inclusive: true, when: [Function], ... },\n * // { check: 'less_than', value: 120, inclusive: true, when: [Function], ... }\n * // ]\n * ```\n *\n * @example\n * Array with item count constraints\n * ```typescript\n * const tags = z.array(z.string()).min(1).max(5);\n * const checks = getFieldChecks(tags);\n * // [\n * // { check: 'min_length', minimum: 1, ... },\n * // { check: 'max_length', maximum: 5, ... }\n * // ]\n * ```\n *\n * @example\n * String with format validation\n * ```typescript\n * const email = z.string().email();\n * const checks = getFieldChecks(email);\n * // [\n * // { check: 'string_format', format: 'email', ... }\n * // ]\n * ```\n *\n * @example\n * Unwrapping optional/nullable/default layers\n * ```typescript\n * const bio = z.string().min(10).max(500).optional();\n * const checks = getFieldChecks(bio);\n * // [\n * // { check: 'min_length', minimum: 10, ... },\n * // { check: 'max_length', maximum: 500, ... }\n * // ]\n * ```\n *\n * @see {@link ZodUnionCheck} for all supported check types\n * @since 0.4.0\n */\nexport function getFieldChecks<T extends z.ZodTypeAny>(\n field: T,\n): Array<ZodUnionCheck> {\n const primitiveType = getPrimitiveType(field);\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return (primitiveType.def.checks?.map((check) => check._zod.def) ||\n []) as Array<ZodUnionCheck>;\n}\n","import * as z from 'zod';\nimport { canUnwrap, unwrapUnion } from './schema';\nimport type { Simplify } from './types';\n\n/**\n * Extracts the default value from a Zod field, recursively unwrapping optional, nullable, and union layers.\n *\n * This function traverses through wrapper types (like `ZodOptional`, `ZodNullable`, `ZodUnion`) to find\n * the underlying `ZodDefault` and returns its default value. If no default is found, returns `undefined`.\n *\n * **Union handling:** For union types, extracts the default from the first option. If the first option\n * has no default, returns `undefined` (defaults in other union options are not checked).\n *\n * @template T - The Zod type to extract default from\n * @param field - The Zod field to extract default from\n * @returns The default value if present, undefined otherwise\n *\n * @example\n * Basic usage with default value\n * ```typescript\n * const field = z.string().default('hello');\n * const defaultValue = extractDefault(field);\n * // Result: 'hello'\n * ```\n *\n * @example\n * Unwrapping optional/nullable layers\n * ```typescript\n * const field = z.string().default('world').optional();\n * const defaultValue = extractDefault(field);\n * // Result: 'world' (unwraps optional to find default)\n * ```\n *\n * @example\n * Union with default in first option\n * ```typescript\n * const field = z.union([z.string().default('hello'), z.number()]);\n * const defaultValue = extractDefault(field);\n * // Result: 'hello' (extracts from first union option)\n * ```\n *\n * @example\n * Union with default in second option\n * ```typescript\n * const field = z.union([z.string(), z.number().default(42)]);\n * const defaultValue = extractDefault(field);\n * // Result: undefined (only checks first option)\n * ```\n *\n * @example\n * Field without default\n * ```typescript\n * const field = z.string().optional();\n * const defaultValue = extractDefault(field);\n * // Result: undefined\n * ```\n *\n * @see {@link getSchemaDefaults} for extracting defaults from entire schemas\n * @since 0.1.0\n */\nexport function extractDefault<T extends z.ZodTypeAny>(\n field: T,\n): z.infer<T> | undefined {\n if (field instanceof z.ZodDefault) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return field.def.defaultValue as z.infer<T>;\n }\n\n if (canUnwrap(field)) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return extractDefault(field.unwrap()) as z.infer<T>;\n }\n\n if (field instanceof z.ZodUnion) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return extractDefault(unwrapUnion(field).field) as z.infer<T>;\n }\n\n return undefined;\n}\n\n/**\n * Extracts default values from a Zod object schema while skipping fields without defaults.\n *\n * This function recursively traverses the schema and collects all fields that have\n * explicit default values defined. Fields without defaults are excluded from the result.\n *\n * **Important:** Nested defaults are NOT extracted unless the parent object also has\n * an explicit `.default()`. This is by design to match Zod's default value behavior.\n *\n * @template T - The Zod object schema type\n * @param schema - The Zod object schema to extract defaults from\n * @returns A partial object containing only fields with default values\n *\n * @example\n * Basic usage\n * ```typescript\n * const schema = z.object({\n * name: z.string().default('John'),\n * age: z.number(), // no default - will be skipped\n * email: z.string().email().optional(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { name: 'John' }\n * ```\n *\n * @example\n * Nested objects with defaults\n * ```typescript\n * const schema = z.object({\n * user: z.object({\n * name: z.string().default('Guest')\n * }).default({ name: 'Guest' }), // ✅ Extracted because parent has .default()\n *\n * settings: z.object({\n * theme: z.string().default('light')\n * }), // ❌ NOT extracted - parent has no .default()\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { user: { name: 'Guest' } }\n * ```\n *\n * @example\n * Unwrapping optional/nullable fields\n * ```typescript\n * const schema = z.object({\n * title: z.string().default('Untitled').optional(),\n * count: z.number().default(0).nullable(),\n * });\n *\n * const defaults = getSchemaDefaults(schema);\n * // Result: { title: 'Untitled', count: 0 }\n * ```\n *\n * @see {@link extractDefault} for extracting defaults from individual fields\n * @since 0.1.0\n */\nexport function getSchemaDefaults<T extends z.ZodObject>(\n schema: T,\n): Simplify<Partial<z.infer<T>>> {\n const defaults: Record<string, unknown> = {};\n\n for (const key in schema.shape) {\n const field = schema.shape[key];\n if (!field) continue;\n\n // Check if this field has an explicit default value\n const defaultValue = extractDefault(field);\n if (defaultValue !== undefined) {\n defaults[key] = defaultValue;\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n return defaults as Partial<z.infer<T>>;\n}\n"]}
|