@zod-utils/core 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@zod-utils/core.svg)](https://www.npmjs.com/package/@zod-utils/core)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@zod-utils/core.svg)](https://www.npmjs.com/package/@zod-utils/core)
5
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@zod-utils/core)](https://bundlephobia.com/package/@zod-utils/core)
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)
7
8
  [![CI](https://github.com/thu-san/zod-utils/workflows/CI/badge.svg)](https://github.com/thu-san/zod-utils/actions)
9
+ [![codecov](https://codecov.io/gh/thu-san/zod-utils/branch/main/graph/badge.svg?flag=core)](https://codecov.io/gh/thu-san/zod-utils)
8
10
 
9
11
  Pure TypeScript utilities for Zod schema manipulation and default extraction. No React dependencies.
10
12
 
@@ -14,10 +16,14 @@ Pure TypeScript utilities for Zod schema manipulation and default extraction. No
14
16
  npm install @zod-utils/core zod
15
17
  ```
16
18
 
19
+ ## Related Packages
20
+
21
+ - **[@zod-utils/react-hook-form](https://www.npmjs.com/package/@zod-utils/react-hook-form)** - React Hook Form integration with automatic type transformation. Uses this package internally and re-exports all utilities for convenience.
22
+
17
23
  ## Features
18
24
 
19
25
  - 🎯 **Extract defaults** - Get default values from Zod schemas
20
- - ✅ **Check required fields** - Determine if fields are required
26
+ - ✅ **Check validation requirements** - Determine if fields will error on empty input
21
27
  - 🔧 **Schema utilities** - Unwrap and manipulate schema types
22
28
  - 📦 **Zero dependencies** - Only requires Zod as a peer dependency
23
29
  - 🌐 **Universal** - Works in Node.js, browsers, and any TypeScript project
@@ -26,20 +32,22 @@ npm install @zod-utils/core zod
26
32
 
27
33
  ### `getSchemaDefaults(schema)`
28
34
 
29
- Extract all default values from a Zod object schema. Recursively handles nested objects.
35
+ Extract all default values from a Zod object schema. Only extracts fields that explicitly have `.default()` on them.
30
36
 
31
37
  ```typescript
32
- import { getSchemaDefaults } from '@zod-utils/core';
33
- import { z } from 'zod';
38
+ import { getSchemaDefaults } from "@zod-utils/core";
39
+ import { z } from "zod";
34
40
 
35
41
  const schema = z.object({
36
- name: z.string().default('John Doe'),
42
+ name: z.string().default("John Doe"),
37
43
  age: z.number().default(25),
38
44
  email: z.string().email(), // no default - skipped
39
- settings: z.object({
40
- theme: z.string().default('light'),
41
- notifications: z.boolean().default(true),
42
- }),
45
+ settings: z
46
+ .object({
47
+ theme: z.string().default("light"),
48
+ notifications: z.boolean().default(true),
49
+ })
50
+ .default({}), // must have explicit .default() to be extracted
43
51
  tags: z.array(z.string()).default([]),
44
52
  });
45
53
 
@@ -47,53 +55,101 @@ const defaults = getSchemaDefaults(schema);
47
55
  // {
48
56
  // name: 'John Doe',
49
57
  // age: 25,
50
- // settings: { theme: 'light', notifications: true },
58
+ // settings: {},
51
59
  // tags: []
52
60
  // }
53
61
  ```
54
62
 
63
+ **Important:** Only fields with explicit `.default()` are extracted. Nested object fields without an explicit default on the parent field are not extracted, even if they contain defaults internally.
64
+
55
65
  **Handles:**
56
- - Nested objects at any depth
66
+
57
67
  - Optional fields with defaults: `.optional().default(value)`
68
+ - Nullable fields with defaults: `.nullable().default(value)`
58
69
  - Arrays with defaults: `.array().default([])`
59
- - Skips fields without defaults
70
+ - Objects with defaults: `.object({...}).default({})`
71
+ - Skips fields without explicit defaults
60
72
 
61
73
  ---
62
74
 
63
- ### `checkIfFieldIsRequired(field)`
75
+ ### `requiresValidInput(field)`
76
+
77
+ Determines if a field will show validation errors when the user submits empty or invalid input. Useful for form UIs to show which fields need valid user input (asterisks, validation indicators).
64
78
 
65
- Check if a Zod field is required (not optional/nullable and doesn't accept empty values).
79
+ **Key insight:** Defaults are just initial values - they don't prevent validation errors if the user clears the field.
80
+
81
+ **Real-world example:**
66
82
 
67
83
  ```typescript
68
- import { checkIfFieldIsRequired } from '@zod-utils/core';
69
- import { z } from 'zod';
84
+ // Marital status with default but validation rules
85
+ const maritalStatus = z.string().min(1).default('single');
86
+
87
+ // What happens in the form:
88
+ // 1. Initial: field shows "single" (from default)
89
+ // 2. User deletes the value → empty string
90
+ // 3. User submits form → validation fails (.min(1) rejects empty)
91
+ // 4. requiresValidInput(maritalStatus) → true (show *, show error)
92
+ ```
93
+
94
+ **How it works:**
70
95
 
71
- const requiredField = z.string();
72
- const optionalField = z.string().optional();
73
- const emptyStringAllowed = z.string().min(0);
96
+ 1. Removes `.default()` wrappers (defaults ≠ validation rules)
97
+ 2. Tests if underlying schema accepts empty/invalid input:
98
+ - `undefined` (via `.optional()`)
99
+ - `null` (via `.nullable()`)
100
+ - Empty string (plain `z.string()`)
101
+ - Empty array (plain `z.array()`)
102
+ 3. Returns `true` if validation will fail on empty input
74
103
 
75
- checkIfFieldIsRequired(requiredField); // true
76
- checkIfFieldIsRequired(optionalField); // false
77
- checkIfFieldIsRequired(emptyStringAllowed); // false
104
+ **Examples:**
105
+
106
+ ```typescript
107
+ import { requiresValidInput } from "@zod-utils/core";
108
+ import { z } from "zod";
109
+
110
+ // User name - required, no default
111
+ const userName = z.string().min(1);
112
+ requiresValidInput(userName); // true - will error if empty
113
+
114
+ // Marital status - required WITH default
115
+ const maritalStatus = z.string().min(1).default('single');
116
+ requiresValidInput(maritalStatus); // true - will error if user clears it
117
+
118
+ // Age with default - requires valid input
119
+ const age = z.number().default(0);
120
+ requiresValidInput(age); // true - numbers reject empty strings
121
+
122
+ // Optional bio - doesn't require input
123
+ const bio = z.string().optional();
124
+ requiresValidInput(bio); // false - user can leave empty
125
+
126
+ // Notes with default but NO validation
127
+ const notes = z.string().default('N/A');
128
+ requiresValidInput(notes); // false - plain z.string() accepts empty
129
+
130
+ // Nullable middle name
131
+ const middleName = z.string().nullable();
132
+ requiresValidInput(middleName); // false - user can leave null
78
133
  ```
79
134
 
80
135
  ---
81
136
 
82
- ### `getPrimitiveType(field, options?)`
137
+ ### `getPrimitiveType(field)`
83
138
 
84
139
  Get the primitive type of a Zod field by unwrapping optional/nullable wrappers.
140
+ Stops at arrays without unwrapping them.
85
141
 
86
142
  ```typescript
87
- import { getPrimitiveType } from '@zod-utils/core';
88
- import { z } from 'zod';
143
+ import { getPrimitiveType } from "@zod-utils/core";
144
+ import { z } from "zod";
89
145
 
90
146
  const field = z.string().optional().nullable();
91
147
  const primitive = getPrimitiveType(field);
92
148
  // Returns the underlying string schema
93
149
 
94
- // Options
95
- getPrimitiveType(z.array(z.string()), { unwrapArrays: false }); // Stops at array
96
- getPrimitiveType(z.array(z.string()), { unwrapArrays: true }); // Continues unwrapping
150
+ const arrayField = z.array(z.string()).optional();
151
+ const arrayPrimitive = getPrimitiveType(arrayField);
152
+ // Returns the ZodArray (stops at arrays)
97
153
  ```
98
154
 
99
155
  ---
@@ -103,14 +159,14 @@ getPrimitiveType(z.array(z.string()), { unwrapArrays: true }); // Continues unw
103
159
  Remove default values from a Zod field.
104
160
 
105
161
  ```typescript
106
- import { removeDefault } from '@zod-utils/core';
107
- import { z } from 'zod';
162
+ import { removeDefault } from "@zod-utils/core";
163
+ import { z } from "zod";
108
164
 
109
- const withDefault = z.string().default('hello');
165
+ const withDefault = z.string().default("hello");
110
166
  const withoutDefault = removeDefault(withDefault);
111
167
 
112
- withDefault.parse(undefined); // 'hello'
113
- withoutDefault.parse(undefined); // throws error
168
+ withDefault.parse(undefined); // 'hello'
169
+ withoutDefault.parse(undefined); // throws error
114
170
  ```
115
171
 
116
172
  ---
@@ -120,10 +176,10 @@ withoutDefault.parse(undefined); // throws error
120
176
  Extract the default value from a Zod field (recursively unwraps optional/nullable).
121
177
 
122
178
  ```typescript
123
- import { extractDefault } from '@zod-utils/core';
124
- import { z } from 'zod';
179
+ import { extractDefault } from "@zod-utils/core";
180
+ import { z } from "zod";
125
181
 
126
- const field = z.string().optional().default('hello');
182
+ const field = z.string().optional().default("hello");
127
183
  extractDefault(field); // 'hello'
128
184
 
129
185
  const noDefault = z.string();
@@ -132,63 +188,20 @@ extractDefault(noDefault); // undefined
132
188
 
133
189
  ---
134
190
 
135
- ### `getUnwrappedType(field)`
136
-
137
- Get the unwrapped type without going through defaults. Useful for detecting nested objects/arrays.
138
-
139
- ```typescript
140
- import { getUnwrappedType } from '@zod-utils/core';
141
- import { z } from 'zod';
142
-
143
- const field = z.object({ name: z.string() }).optional().default({});
144
- const unwrapped = getUnwrappedType(field);
145
- // Returns the ZodObject (preserves the default wrapper)
146
- ```
147
-
148
- ---
149
-
150
191
  ## Type Utilities
151
192
 
152
- ### `MakeOptionalAndNullable<T>`
153
-
154
- Make all properties optional and nullable. Useful for form input types.
155
-
156
- ```typescript
157
- import type { MakeOptionalAndNullable } from '@zod-utils/core';
158
-
159
- type User = {
160
- name: string;
161
- age: number;
162
- };
163
-
164
- type FormInput = MakeOptionalAndNullable<User>;
165
- // { name?: string | null; age?: number | null; }
166
- ```
167
-
168
193
  ### `Simplify<T>`
169
194
 
170
195
  Simplify complex types for better IDE hints.
171
196
 
172
197
  ```typescript
173
- import type { Simplify } from '@zod-utils/core';
198
+ import type { Simplify } from "@zod-utils/core";
174
199
 
175
200
  type Complex = { a: string } & { b: number };
176
201
  type Simple = Simplify<Complex>;
177
202
  // { a: string; b: number }
178
203
  ```
179
204
 
180
- ### `PickArrayObject<T>`
181
-
182
- Extract the element type from an array.
183
-
184
- ```typescript
185
- import type { PickArrayObject } from '@zod-utils/core';
186
-
187
- type Users = Array<{ name: string }>;
188
- type User = PickArrayObject<Users>;
189
- // { name: string }
190
- ```
191
-
192
205
  ---
193
206
 
194
207
  ## License