zod-aot 0.12.0 → 0.14.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 +248 -287
- package/dist/cli/commands/check.d.ts +4 -2
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/commands/check.js +102 -113
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +8 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +136 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/index.js +43 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/logger.d.ts +10 -0
- package/dist/cli/logger.d.ts.map +1 -1
- package/dist/cli/logger.js +22 -9
- package/dist/cli/logger.js.map +1 -1
- package/dist/core/codegen/context.d.ts +3 -10
- package/dist/core/codegen/context.d.ts.map +1 -1
- package/dist/core/codegen/context.js +10 -31
- package/dist/core/codegen/context.js.map +1 -1
- package/dist/core/codegen/emit.d.ts +8 -0
- package/dist/core/codegen/emit.d.ts.map +1 -0
- package/dist/core/codegen/emit.js +16 -0
- package/dist/core/codegen/emit.js.map +1 -0
- package/dist/core/codegen/fast-check/array.d.ts +4 -0
- package/dist/core/codegen/fast-check/array.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/array.js +28 -0
- package/dist/core/codegen/fast-check/array.js.map +1 -0
- package/dist/core/codegen/fast-check/bigint.d.ts +3 -0
- package/dist/core/codegen/fast-check/bigint.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/bigint.js +19 -0
- package/dist/core/codegen/fast-check/bigint.js.map +1 -0
- package/dist/core/codegen/fast-check/discriminated-union.d.ts +4 -0
- package/dist/core/codegen/fast-check/discriminated-union.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/discriminated-union.js +13 -0
- package/dist/core/codegen/fast-check/discriminated-union.js.map +1 -0
- package/dist/core/codegen/fast-check/enum.d.ts +4 -0
- package/dist/core/codegen/fast-check/enum.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/enum.js +12 -0
- package/dist/core/codegen/fast-check/enum.js.map +1 -0
- package/dist/core/codegen/{fast-check.d.ts → fast-check/index.d.ts} +3 -3
- package/dist/core/codegen/fast-check/index.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/index.js +118 -0
- package/dist/core/codegen/fast-check/index.js.map +1 -0
- package/dist/core/codegen/fast-check/intersection.d.ts +4 -0
- package/dist/core/codegen/fast-check/intersection.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/intersection.js +10 -0
- package/dist/core/codegen/fast-check/intersection.js.map +1 -0
- package/dist/core/codegen/fast-check/literal.d.ts +3 -0
- package/dist/core/codegen/fast-check/literal.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/literal.js +8 -0
- package/dist/core/codegen/fast-check/literal.js.map +1 -0
- package/dist/core/codegen/fast-check/nullable.d.ts +4 -0
- package/dist/core/codegen/fast-check/nullable.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/nullable.js +7 -0
- package/dist/core/codegen/fast-check/nullable.js.map +1 -0
- package/dist/core/codegen/fast-check/number.d.ts +3 -0
- package/dist/core/codegen/fast-check/number.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/number.js +51 -0
- package/dist/core/codegen/fast-check/number.js.map +1 -0
- package/dist/core/codegen/fast-check/object.d.ts +4 -0
- package/dist/core/codegen/fast-check/object.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/object.js +13 -0
- package/dist/core/codegen/fast-check/object.js.map +1 -0
- package/dist/core/codegen/fast-check/optional.d.ts +4 -0
- package/dist/core/codegen/fast-check/optional.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/optional.js +7 -0
- package/dist/core/codegen/fast-check/optional.js.map +1 -0
- package/dist/core/codegen/fast-check/pipe.d.ts +4 -0
- package/dist/core/codegen/fast-check/pipe.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/pipe.js +14 -0
- package/dist/core/codegen/fast-check/pipe.js.map +1 -0
- package/dist/core/codegen/fast-check/readonly.d.ts +4 -0
- package/dist/core/codegen/fast-check/readonly.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/readonly.js +4 -0
- package/dist/core/codegen/fast-check/readonly.js.map +1 -0
- package/dist/core/codegen/fast-check/record.d.ts +4 -0
- package/dist/core/codegen/fast-check/record.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/record.js +18 -0
- package/dist/core/codegen/fast-check/record.js.map +1 -0
- package/dist/core/codegen/fast-check/string.d.ts +4 -0
- package/dist/core/codegen/fast-check/string.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/string.js +62 -0
- package/dist/core/codegen/fast-check/string.js.map +1 -0
- package/dist/core/codegen/fast-check/tuple.d.ts +4 -0
- package/dist/core/codegen/fast-check/tuple.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/tuple.js +32 -0
- package/dist/core/codegen/fast-check/tuple.js.map +1 -0
- package/dist/core/codegen/fast-check/union.d.ts +4 -0
- package/dist/core/codegen/fast-check/union.d.ts.map +1 -0
- package/dist/core/codegen/fast-check/union.js +12 -0
- package/dist/core/codegen/fast-check/union.js.map +1 -0
- package/dist/core/codegen/generators/array.js +1 -1
- package/dist/core/codegen/generators/array.js.map +1 -1
- package/dist/core/codegen/generators/bigint.d.ts.map +1 -1
- package/dist/core/codegen/generators/bigint.js +2 -1
- package/dist/core/codegen/generators/bigint.js.map +1 -1
- package/dist/core/codegen/generators/boolean.js +1 -1
- package/dist/core/codegen/generators/boolean.js.map +1 -1
- package/dist/core/codegen/generators/date.js +1 -1
- package/dist/core/codegen/generators/date.js.map +1 -1
- package/dist/core/codegen/generators/default.js +1 -1
- package/dist/core/codegen/generators/default.js.map +1 -1
- package/dist/core/codegen/generators/discriminated-union.d.ts.map +1 -1
- package/dist/core/codegen/generators/discriminated-union.js +2 -1
- package/dist/core/codegen/generators/discriminated-union.js.map +1 -1
- package/dist/core/codegen/generators/enum.d.ts.map +1 -1
- package/dist/core/codegen/generators/enum.js +3 -2
- package/dist/core/codegen/generators/enum.js.map +1 -1
- package/dist/core/codegen/generators/fallback.js +1 -1
- package/dist/core/codegen/generators/fallback.js.map +1 -1
- package/dist/core/codegen/generators/index.d.ts +3 -33
- package/dist/core/codegen/generators/index.d.ts.map +1 -1
- package/dist/core/codegen/generators/index.js +103 -33
- package/dist/core/codegen/generators/index.js.map +1 -1
- package/dist/core/codegen/generators/literal.d.ts.map +1 -1
- package/dist/core/codegen/generators/literal.js +2 -1
- package/dist/core/codegen/generators/literal.js.map +1 -1
- package/dist/core/codegen/generators/map.js +1 -1
- package/dist/core/codegen/generators/map.js.map +1 -1
- package/dist/core/codegen/generators/nan.js +1 -1
- package/dist/core/codegen/generators/nan.js.map +1 -1
- package/dist/core/codegen/generators/never.js +1 -1
- package/dist/core/codegen/generators/never.js.map +1 -1
- package/dist/core/codegen/generators/null.js +1 -1
- package/dist/core/codegen/generators/null.js.map +1 -1
- package/dist/core/codegen/generators/nullable.js +1 -1
- package/dist/core/codegen/generators/nullable.js.map +1 -1
- package/dist/core/codegen/generators/number.d.ts.map +1 -1
- package/dist/core/codegen/generators/number.js +2 -1
- package/dist/core/codegen/generators/number.js.map +1 -1
- package/dist/core/codegen/generators/object.d.ts.map +1 -1
- package/dist/core/codegen/generators/object.js +2 -1
- package/dist/core/codegen/generators/object.js.map +1 -1
- package/dist/core/codegen/generators/optional.js +1 -1
- package/dist/core/codegen/generators/optional.js.map +1 -1
- package/dist/core/codegen/generators/record.js +1 -1
- package/dist/core/codegen/generators/record.js.map +1 -1
- package/dist/core/codegen/generators/recursive-ref.js +1 -1
- package/dist/core/codegen/generators/recursive-ref.js.map +1 -1
- package/dist/core/codegen/generators/set.js +1 -1
- package/dist/core/codegen/generators/set.js.map +1 -1
- package/dist/core/codegen/generators/string.d.ts.map +1 -1
- package/dist/core/codegen/generators/string.js +2 -1
- package/dist/core/codegen/generators/string.js.map +1 -1
- package/dist/core/codegen/generators/symbol.js +1 -1
- package/dist/core/codegen/generators/symbol.js.map +1 -1
- package/dist/core/codegen/generators/template-literal.d.ts.map +1 -1
- package/dist/core/codegen/generators/template-literal.js +2 -1
- package/dist/core/codegen/generators/template-literal.js.map +1 -1
- package/dist/core/codegen/generators/tuple.js +1 -1
- package/dist/core/codegen/generators/tuple.js.map +1 -1
- package/dist/core/codegen/generators/undefined.js +1 -1
- package/dist/core/codegen/generators/undefined.js.map +1 -1
- package/dist/core/codegen/generators/union.js +1 -1
- package/dist/core/codegen/generators/union.js.map +1 -1
- package/dist/core/codegen/generators/void.js +1 -1
- package/dist/core/codegen/generators/void.js.map +1 -1
- package/dist/core/codegen/index.d.ts +1 -1
- package/dist/core/codegen/index.d.ts.map +1 -1
- package/dist/core/codegen/index.js +3 -73
- package/dist/core/codegen/index.js.map +1 -1
- package/dist/core/compile.d.ts.map +1 -1
- package/dist/core/compile.js +12 -1
- package/dist/core/compile.js.map +1 -1
- package/dist/core/diagnostic.d.ts +46 -0
- package/dist/core/diagnostic.d.ts.map +1 -0
- package/dist/core/diagnostic.js +168 -0
- package/dist/core/diagnostic.js.map +1 -0
- package/dist/core/iife.d.ts.map +1 -1
- package/dist/core/iife.js +7 -1
- package/dist/core/iife.js.map +1 -1
- package/dist/core/pipeline.d.ts +10 -4
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +21 -9
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/discovery.d.ts +10 -6
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +18 -2
- package/dist/discovery.js.map +1 -1
- package/dist/unplugin/index.d.ts.map +1 -1
- package/dist/unplugin/index.js +41 -17
- package/dist/unplugin/index.js.map +1 -1
- package/dist/unplugin/transform.d.ts +28 -4
- package/dist/unplugin/transform.d.ts.map +1 -1
- package/dist/unplugin/transform.js +134 -12
- package/dist/unplugin/transform.js.map +1 -1
- package/dist/unplugin/types.d.ts +16 -0
- package/dist/unplugin/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/core/codegen/fast-check.d.ts.map +0 -1
- package/dist/core/codegen/fast-check.js +0 -406
- package/dist/core/codegen/fast-check.js.map +0 -1
- package/dist/core/runtime.d.ts +0 -10
- package/dist/core/runtime.d.ts.map +0 -1
- package/dist/core/runtime.js +0 -14
- package/dist/core/runtime.js.map +0 -1
package/README.md
CHANGED
|
@@ -7,408 +7,369 @@
|
|
|
7
7
|
[](https://www.npmjs.com/package/zod-aot)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Keep your existing Zod schemas. Get **2-64x faster** validation. No code changes required.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
```typescript
|
|
13
|
+
// vite.config.ts — add one line
|
|
14
|
+
import zodAot from "zod-aot/vite";
|
|
15
|
+
export default defineConfig({
|
|
16
|
+
plugins: [zodAot({ autoDiscover: true })],
|
|
17
|
+
});
|
|
18
|
+
```
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
| **Existing code changes** | None | Full rewrite | Full rewrite | N/A | N/A |
|
|
20
|
-
| **Type inference** | Inherited from Zod | Native | External | Native | Native |
|
|
21
|
-
| **Runtime dependency** | None (generated code) | Typia runtime | AJV runtime | Zod | Zod |
|
|
20
|
+
```typescript
|
|
21
|
+
// src/schemas.ts — write plain Zod, nothing else
|
|
22
|
+
import { z } from "zod";
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
export const UserSchema = z.object({
|
|
25
|
+
name: z.string().min(3),
|
|
26
|
+
email: z.email(),
|
|
27
|
+
age: z.number().int().positive(),
|
|
28
|
+
});
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
// Use it anywhere — tRPC, Hono, React Hook Form, etc.
|
|
31
|
+
// At build time, zod-aot compiles it to a 3-64x faster validator.
|
|
32
|
+
```
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
## Install
|
|
28
35
|
|
|
29
36
|
```bash
|
|
30
|
-
|
|
37
|
+
npm install zod-aot zod@^4
|
|
31
38
|
```
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
| Runtime | Version |
|
|
41
|
+
|---------|---------|
|
|
42
|
+
| Node.js | 20+ |
|
|
43
|
+
| Bun | 1.3+ |
|
|
44
|
+
| Deno | 2.0+ |
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
|---|---|---|---|---|---|---|
|
|
37
|
-
| simple string | 8.7M | 10.0M | **11.0M** | 11.0M | 11.1M | 1.1x |
|
|
38
|
-
| string (min/max) | 8.3M | 6.0M | **11.1M** | 11.3M | 9.5M | 1.8x |
|
|
39
|
-
| number (int+positive) | 8.2M | 5.8M | **10.9M** | 10.7M | 10.9M | 1.9x |
|
|
40
|
-
| enum | 8.0M | 9.5M | **10.6M** | 10.6M | 10.5M | 1.1x |
|
|
41
|
-
| bigint (min/max) | 8.0M | 6.0M | **10.9M** | — | — | 1.8x |
|
|
42
|
-
| tuple [string, int, bool] | 4.0M | 4.4M | **10.5M** | 10.8M | 10.5M | 2.4x |
|
|
43
|
-
| record\<string, number\> | 2.3M | 1.9M | **5.4M** | 7.5M | 9.4M | 2.8x |
|
|
44
|
-
| set\<string\> (5 items) | 2.7M | 1.6M | **9.8M** | — | — | 6.3x |
|
|
45
|
-
| set\<string\> (20 items) | 1.0M | 475K | **7.7M** | — | — | **16x** |
|
|
46
|
-
| map\<string, number\> (5 entries) | 1.5M | 946K | **8.5M** | — | — | 9.0x |
|
|
47
|
-
| map\<string, number\> (20 entries) | 490K | 238K | **5.2M** | — | — | **22x** |
|
|
48
|
-
| pipe (non-transform) | 6.3M | 3.8M | **10.8M** | — | — | 2.8x |
|
|
49
|
-
| discriminatedUnion (3 variants) | 2.3M | 2.9M | **9.8M** | 10.4M | 5.6M | 3.4x |
|
|
50
|
-
| medium object (valid) | 1.3M | 1.7M | **5.4M** | 7.3M | 5.0M | 3.1x |
|
|
51
|
-
| medium object (invalid) | 351K | 65K | **471K** | 2.1M | 5.6M | 7.3x |
|
|
52
|
-
| large object (10 items) | 82K | 111K | **4.0M** | 4.1M | 834K | **36x** |
|
|
53
|
-
| large object (100 items) | 9.0K | 11.6K | **676K** | 808K | 89K | **58x** |
|
|
54
|
-
| recursive tree (7 nodes) | 424K | 1.5M | **6.4M** | 8.1M | 3.1M | 4.1x |
|
|
55
|
-
| recursive tree (121 nodes) | 24K | 101K | **741K** | 1.4M | 250K | 7.4x |
|
|
56
|
-
| event log (combined) | 260K | 479K | **4.5M** | — | — | 9.4x |
|
|
57
|
-
| partial fallback obj (transform) | 817K | 1.4M | **3.3M** | — | — | 2.3x |
|
|
58
|
-
| partial fallback arr 10 (transform) | 88K | 139K | **841K** | — | — | 6.1x |
|
|
59
|
-
| partial fallback arr 50 (transform) | 18K | 28K | **175K** | — | — | 6.3x |
|
|
46
|
+
## Usage
|
|
60
47
|
|
|
61
|
-
|
|
48
|
+
There are three ways to use zod-aot. Choose the one that fits your project.
|
|
62
49
|
|
|
63
|
-
|
|
50
|
+
### 1. autoDiscover (Recommended)
|
|
64
51
|
|
|
65
|
-
|
|
52
|
+
The plugin automatically detects and compiles all exported Zod schemas at build time. No wrappers, no imports from `zod-aot` in your source code.
|
|
66
53
|
|
|
67
|
-
|
|
68
|
-
|---------|---------|--------|
|
|
69
|
-
| Node.js | 20+ | Fully supported |
|
|
70
|
-
| Bun | 1.3+ | Fully supported |
|
|
71
|
-
| Deno | 2.0+ | Fully supported |
|
|
54
|
+
**vite.config.ts:**
|
|
72
55
|
|
|
73
|
-
|
|
56
|
+
```typescript
|
|
57
|
+
import zodAot from "zod-aot/vite";
|
|
74
58
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
npm install zod@^4
|
|
59
|
+
export default defineConfig({
|
|
60
|
+
plugins: [zodAot({ autoDiscover: true })],
|
|
61
|
+
});
|
|
79
62
|
```
|
|
80
63
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
### 1. Define schemas with `compile()`
|
|
64
|
+
**Your schema file stays pure Zod:**
|
|
84
65
|
|
|
85
66
|
```typescript
|
|
86
67
|
// src/schemas.ts
|
|
87
68
|
import { z } from "zod";
|
|
88
|
-
import { compile } from "zod-aot";
|
|
89
69
|
|
|
90
|
-
const
|
|
91
|
-
name: z.string().min(
|
|
92
|
-
age: z.number().int().positive(),
|
|
70
|
+
export const CreateUserSchema = z.object({
|
|
71
|
+
name: z.string().min(1).max(100),
|
|
93
72
|
email: z.email(),
|
|
94
|
-
|
|
73
|
+
age: z.number().int().min(0).max(150),
|
|
74
|
+
role: z.enum(["admin", "editor", "viewer"]),
|
|
95
75
|
});
|
|
96
76
|
|
|
97
|
-
|
|
98
|
-
|
|
77
|
+
export const UpdateUserSchema = z.object({
|
|
78
|
+
name: z.string().min(1).max(100).optional(),
|
|
79
|
+
email: z.email().optional(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export const ListUsersSchema = z.object({
|
|
83
|
+
page: z.number().int().min(1).optional().default(1),
|
|
84
|
+
limit: z.number().int().min(1).max(100).optional().default(20),
|
|
85
|
+
});
|
|
99
86
|
```
|
|
100
87
|
|
|
101
|
-
|
|
88
|
+
**Use them as usual:**
|
|
102
89
|
|
|
103
90
|
```typescript
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
const result = validateUser.safeParse(data); // { success, data/error }
|
|
91
|
+
const user = CreateUserSchema.parse(data); // throws on failure
|
|
92
|
+
const result = CreateUserSchema.safeParse(data); // { success, data/error }
|
|
107
93
|
```
|
|
108
94
|
|
|
109
|
-
|
|
95
|
+
At build time, the plugin:
|
|
96
|
+
1. Finds every file with `import ... from "zod"` (skips type-only imports)
|
|
97
|
+
2. Executes the file and detects exported Zod schemas
|
|
98
|
+
3. Compiles each schema into an optimized validator
|
|
99
|
+
4. Replaces the export with a tree-shakeable IIFE that preserves the full Zod API
|
|
100
|
+
|
|
101
|
+
**What "preserves the full Zod API" means:** The compiled schema inherits from the original Zod schema via `Object.create()`. So `._zod`, `.shape`, Standard Schema (`~standard`), `instanceof` checks — all still work. Libraries that accept Zod schemas (tRPC, Hono, React Hook Form) work without changes.
|
|
110
102
|
|
|
111
|
-
|
|
103
|
+
### 2. compile() (Explicit)
|
|
112
104
|
|
|
113
|
-
|
|
105
|
+
If you prefer explicit opt-in, wrap specific schemas with `compile()`:
|
|
114
106
|
|
|
115
107
|
```typescript
|
|
116
|
-
|
|
117
|
-
import
|
|
108
|
+
import { z } from "zod";
|
|
109
|
+
import { compile } from "zod-aot";
|
|
118
110
|
|
|
119
|
-
|
|
120
|
-
|
|
111
|
+
const UserSchema = z.object({
|
|
112
|
+
name: z.string().min(3),
|
|
113
|
+
email: z.email(),
|
|
121
114
|
});
|
|
115
|
+
|
|
116
|
+
export const validateUser = compile(UserSchema);
|
|
117
|
+
|
|
118
|
+
// In dev: falls back to Zod's runtime validation
|
|
119
|
+
// After build: uses AOT-compiled optimized code
|
|
120
|
+
validateUser.parse(data);
|
|
121
|
+
validateUser.safeParse(data);
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
`compile()` and `autoDiscover` coexist — `compile()` schemas are detected first, then `autoDiscover` picks up remaining plain Zod exports.
|
|
125
|
+
|
|
126
|
+
### 3. CLI (No Bundler)
|
|
125
127
|
|
|
126
|
-
|
|
128
|
+
Generate optimized validation files from the command line:
|
|
127
129
|
|
|
128
130
|
```bash
|
|
129
|
-
#
|
|
131
|
+
# Single file
|
|
130
132
|
npx zod-aot generate src/schemas.ts -o src/schemas.compiled.ts
|
|
131
133
|
|
|
132
|
-
#
|
|
134
|
+
# Directory
|
|
133
135
|
npx zod-aot generate src/ -o src/compiled/
|
|
134
136
|
|
|
135
|
-
# Watch mode
|
|
137
|
+
# Watch mode
|
|
136
138
|
npx zod-aot generate src/ --watch
|
|
137
|
-
|
|
138
|
-
# Check if schemas are compilable (without generating)
|
|
139
|
-
npx zod-aot check src/schemas.ts
|
|
140
139
|
```
|
|
141
140
|
|
|
142
|
-
## Build Plugin
|
|
141
|
+
## Build Plugin
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
### Supported Build Tools
|
|
145
144
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
import zodAot from "zod-aot/vite"
|
|
149
|
-
|
|
145
|
+
| Build Tool | Import |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Vite | `import zodAot from "zod-aot/vite"` |
|
|
148
|
+
| webpack | `import zodAot from "zod-aot/webpack"` |
|
|
149
|
+
| esbuild | `import zodAot from "zod-aot/esbuild"` |
|
|
150
|
+
| Rollup | `import zodAot from "zod-aot/rollup"` |
|
|
151
|
+
| Rolldown | `import zodAot from "zod-aot/rolldown"` |
|
|
152
|
+
| rspack | `import zodAot from "zod-aot/rspack"` |
|
|
153
|
+
| Bun | `import zodAot from "zod-aot/bun"` |
|
|
154
|
+
|
|
155
|
+
### Options
|
|
150
156
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
| Option | Type | Default | Description |
|
|
158
|
+
|---|---|---|---|
|
|
159
|
+
| `autoDiscover` | `boolean` | `false` | Auto-detect all exported Zod schemas without `compile()` |
|
|
160
|
+
| `include` | `string[]` | — | Only process files matching these substrings |
|
|
161
|
+
| `exclude` | `string[]` | — | Skip files matching these substrings |
|
|
162
|
+
| `zodCompat` | `boolean` | `true` | Preserve Zod API via `Object.create()`. Set `false` for smaller output |
|
|
163
|
+
| `verbose` | `boolean` | `false` | Log per-schema compilation status during build |
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
zodAot({
|
|
167
|
+
autoDiscover: true,
|
|
168
|
+
include: ["src/schemas"],
|
|
169
|
+
verbose: true,
|
|
170
|
+
})
|
|
154
171
|
```
|
|
155
172
|
|
|
156
|
-
###
|
|
173
|
+
### autoDiscover: Side Effects Warning
|
|
174
|
+
|
|
175
|
+
With `autoDiscover`, the plugin executes files to inspect their exports. If a file imports Zod AND has side effects (starts a server, connects to a database), those side effects run at build time.
|
|
176
|
+
|
|
177
|
+
**Fix:** Use `include` to limit which files are scanned:
|
|
157
178
|
|
|
158
179
|
```typescript
|
|
159
180
|
zodAot({
|
|
160
|
-
|
|
161
|
-
|
|
181
|
+
autoDiscover: true,
|
|
182
|
+
include: ["src/schemas", "src/validators"],
|
|
162
183
|
})
|
|
163
184
|
```
|
|
164
185
|
|
|
165
|
-
|
|
166
|
-
- Runs at build time (`enforce: "pre"`)
|
|
167
|
-
- Replaces `compile(Schema)` with optimized IIFE inline validators
|
|
168
|
-
- Adds `/* @__PURE__ */` annotations for tree-shaking
|
|
169
|
-
- Supports HMR in development
|
|
186
|
+
### autoDiscover vs compile()
|
|
170
187
|
|
|
171
|
-
|
|
188
|
+
| | autoDiscover | compile() |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| Source code changes | None | Wrap each schema |
|
|
191
|
+
| `zod-aot` import needed | No | Yes |
|
|
192
|
+
| What gets compiled | All exported Zod schemas | Only wrapped schemas |
|
|
193
|
+
| Build-time file execution | Files with `import ... from "zod"` | Files with `import ... from "zod-aot"` |
|
|
194
|
+
| Best for | New projects, framework integration | Gradual adoption, selective optimization |
|
|
172
195
|
|
|
173
|
-
|
|
196
|
+
## Framework Examples
|
|
174
197
|
|
|
175
|
-
###
|
|
198
|
+
### tRPC
|
|
176
199
|
|
|
177
200
|
```typescript
|
|
178
|
-
|
|
179
|
-
import { zValidator } from "@hono/zod-validator";
|
|
201
|
+
// src/schemas.ts
|
|
180
202
|
import { z } from "zod";
|
|
181
|
-
import { compile } from "zod-aot";
|
|
182
203
|
|
|
183
|
-
const
|
|
184
|
-
name: z.string().min(
|
|
185
|
-
age: z.number().int().positive(),
|
|
204
|
+
export const CreateUserSchema = z.object({
|
|
205
|
+
name: z.string().min(1).max(100),
|
|
186
206
|
email: z.email(),
|
|
207
|
+
age: z.number().int().min(0).max(150),
|
|
187
208
|
});
|
|
188
209
|
|
|
189
|
-
//
|
|
190
|
-
|
|
210
|
+
// src/router.ts
|
|
211
|
+
import { CreateUserSchema } from "./schemas";
|
|
212
|
+
|
|
213
|
+
export const appRouter = t.router({
|
|
214
|
+
createUser: t.procedure
|
|
215
|
+
.input(CreateUserSchema)
|
|
216
|
+
.mutation(({ input }) => createUser(input)),
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
With `autoDiscover: true`, `CreateUserSchema` is compiled at build time. The tRPC router uses the optimized version automatically. No `.input(compile(CreateUserSchema))` needed.
|
|
221
|
+
|
|
222
|
+
### Hono
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { Hono } from "hono";
|
|
226
|
+
import { zValidator } from "@hono/zod-validator";
|
|
227
|
+
import { UserSchema } from "./schemas";
|
|
191
228
|
|
|
192
229
|
const app = new Hono();
|
|
193
230
|
|
|
194
|
-
app.post("/users", zValidator("json",
|
|
231
|
+
app.post("/users", zValidator("json", UserSchema), (c) => {
|
|
195
232
|
const user = c.req.valid("json");
|
|
196
233
|
return c.json(user);
|
|
197
234
|
});
|
|
198
235
|
```
|
|
199
236
|
|
|
200
|
-
|
|
237
|
+
### React Hook Form
|
|
201
238
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
▼
|
|
214
|
-
┌─────────────────────┐
|
|
215
|
-
│ CodeGen │ IR → optimized JS with:
|
|
216
|
-
│ generateValidator()│ • inline type checks
|
|
217
|
-
└─────────┬───────────┘ • pre-compiled RegExps
|
|
218
|
-
│ • Set-based enum lookups
|
|
219
|
-
▼ • early returns
|
|
220
|
-
Optimized JS function
|
|
221
|
-
(no runtime dependencies)
|
|
239
|
+
```typescript
|
|
240
|
+
import { useForm } from "react-hook-form";
|
|
241
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
242
|
+
import { UserSchema } from "./schemas";
|
|
243
|
+
|
|
244
|
+
function UserForm() {
|
|
245
|
+
const form = useForm({
|
|
246
|
+
resolver: zodResolver(UserSchema),
|
|
247
|
+
});
|
|
248
|
+
// ...
|
|
249
|
+
}
|
|
222
250
|
```
|
|
223
251
|
|
|
224
|
-
###
|
|
252
|
+
### Any Standard Schema Consumer
|
|
225
253
|
|
|
226
|
-
-
|
|
227
|
-
- Static AST analysis cannot handle dynamic schemas (variable references, function calls, spread operators)
|
|
228
|
-
- `_zod.bag` contains aggregated metadata from checks (minimum, maximum, regex patterns, etc.)
|
|
229
|
-
- Reliable detection of `transform`/`refine` for automatic fallback
|
|
254
|
+
zod-aot compiled schemas implement [Standard Schema](https://standardschema.dev) via prototype chain. Any library that accepts Standard Schema validators works automatically.
|
|
230
255
|
|
|
231
|
-
|
|
256
|
+
## Schema Diagnostics
|
|
232
257
|
|
|
233
|
-
|
|
258
|
+
Analyze your schemas before compiling — check coverage, Fast Path eligibility, and get actionable hints:
|
|
234
259
|
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
name: z.string().min(3).max(50),
|
|
238
|
-
role: z.enum(["admin", "user"]),
|
|
239
|
-
})
|
|
260
|
+
```bash
|
|
261
|
+
npx zod-aot check src/schemas.ts
|
|
240
262
|
```
|
|
241
263
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
```javascript
|
|
245
|
-
/* zod-aot */
|
|
246
|
-
var __set_0 = new Set(["admin", "user"]);
|
|
247
|
-
|
|
248
|
-
function safeParse_validate(input) {
|
|
249
|
-
var __issues = [];
|
|
250
|
-
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
251
|
-
__issues.push({ code: "invalid_type", expected: "object", path: [] });
|
|
252
|
-
} else {
|
|
253
|
-
// name: string().min(3).max(50)
|
|
254
|
-
if (typeof input["name"] !== "string") {
|
|
255
|
-
__issues.push({ code: "invalid_type", expected: "string", path: ["name"] });
|
|
256
|
-
} else {
|
|
257
|
-
if (input["name"].length < 3)
|
|
258
|
-
__issues.push({ code: "too_small", minimum: 3, path: ["name"] });
|
|
259
|
-
if (input["name"].length > 50)
|
|
260
|
-
__issues.push({ code: "too_big", maximum: 50, path: ["name"] });
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// role: enum(["admin", "user"])
|
|
264
|
-
if (!__set_0.has(input["role"])) {
|
|
265
|
-
__issues.push({ code: "invalid_enum_value", path: ["role"] });
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
if (__issues.length > 0) return { success: false, error: { issues: __issues } };
|
|
269
|
-
return { success: true, data: input };
|
|
270
|
-
}
|
|
271
|
-
```
|
|
264
|
+
Output:
|
|
272
265
|
|
|
273
|
-
|
|
266
|
+
```
|
|
267
|
+
src/schemas.ts
|
|
274
268
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
269
|
+
CreateUserSchema [Fast Path] 100% compiled (5 checks)
|
|
270
|
+
├─ name: string (min_length, max_length)
|
|
271
|
+
├─ email: string (string_format[email])
|
|
272
|
+
├─ age: number (number_format[safeint], greater_than)
|
|
273
|
+
└─ role: enum
|
|
280
274
|
|
|
281
|
-
|
|
275
|
+
OrderSchema [Slow Path] 85% compiled (3 checks)
|
|
276
|
+
├─ id: string (string_format[uuid])
|
|
277
|
+
└─ metadata: object
|
|
278
|
+
└─ audit: fallback(transform)
|
|
279
|
+
Hint: Consider z.pipe() to keep inner schema compilable
|
|
282
280
|
|
|
283
|
-
|
|
281
|
+
Summary: 2 schemas | 1 Fast Path, 1 Slow Path | 8/9 nodes (88.9%)
|
|
282
|
+
```
|
|
284
283
|
|
|
285
|
-
|
|
284
|
+
### CI Integration
|
|
286
285
|
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
|
|
286
|
+
```bash
|
|
287
|
+
# JSON output
|
|
288
|
+
npx zod-aot check src/schemas.ts --json
|
|
290
289
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
age: z.number().int().positive(),
|
|
294
|
-
}));
|
|
290
|
+
# Fail if any schema below 80% coverage
|
|
291
|
+
npx zod-aot check src/schemas.ts --json --fail-under 80
|
|
295
292
|
```
|
|
296
293
|
|
|
297
|
-
|
|
294
|
+
| Flag | Description |
|
|
295
|
+
|---|---|
|
|
296
|
+
| `--json` | Structured JSON output |
|
|
297
|
+
| `--fail-under <pct>` | Exit code 1 if coverage below threshold |
|
|
298
|
+
| `--no-color` | Disable colored output |
|
|
298
299
|
|
|
299
|
-
|
|
300
|
+
## What Gets Compiled
|
|
300
301
|
|
|
301
|
-
|
|
302
|
-
interface CompiledSchema<T> {
|
|
303
|
-
parse(input: unknown): T; // throws on failure
|
|
304
|
-
safeParse(input: unknown): SafeParseResult<T>; // { success, data/error }
|
|
305
|
-
schema: unknown; // reference to original Zod schema
|
|
306
|
-
}
|
|
307
|
-
```
|
|
302
|
+
### Fully Compiled (3-64x faster)
|
|
308
303
|
|
|
309
|
-
|
|
304
|
+
`string`, `number`, `bigint`, `boolean`, `null`, `undefined`, `any`, `unknown`, `literal`, `enum`, `date`, `object`, `array`, `tuple`, `record`, `set`, `map`, `union`, `discriminatedUnion`, `intersection`, `pipe` (non-transform), `optional`, `nullable`, `readonly`, `default`, `catch`, `coerce`, `templateLiteral`, `symbol`, `void`, `nan`, `never`, `lazy` (self-recursive)
|
|
310
305
|
|
|
311
|
-
|
|
312
|
-
|---|---|
|
|
313
|
-
| `string` | `min`, `max`, `length`, `email`, `url`, `uuid`, `regex`, `includes`, `startsWith`, `endsWith` |
|
|
314
|
-
| `number` | `int`, `positive`, `negative`, `nonnegative`, `nonpositive`, `min`, `max`, `multipleOf`, `int32`, `uint32`, `float32`, `float64` |
|
|
315
|
-
| `bigint` | `min`, `max`, `positive`, `negative`, `nonnegative`, `nonpositive`, `multipleOf` |
|
|
316
|
-
| `boolean` | — |
|
|
317
|
-
| `null` | — |
|
|
318
|
-
| `undefined` | — |
|
|
319
|
-
| `any` | — (always passes) |
|
|
320
|
-
| `unknown` | — (always passes) |
|
|
321
|
-
| `literal` | single value, multi-value |
|
|
322
|
-
| `enum` | string enum values |
|
|
323
|
-
| `date` | `min`, `max` (timestamp comparison) |
|
|
324
|
-
| `object` | nested objects, mixed property types |
|
|
325
|
-
| `array` | `min`, `max`, `length`, element validation |
|
|
326
|
-
| `tuple` | per-element types, optional rest element |
|
|
327
|
-
| `record` | key and value type validation |
|
|
328
|
-
| `set` | `min`, `max` (size), element validation |
|
|
329
|
-
| `map` | key and value type validation |
|
|
330
|
-
| `union` | sequential trial of all options |
|
|
331
|
-
| `discriminatedUnion` | O(1) `switch` dispatch on discriminator field |
|
|
332
|
-
| `intersection` | validates both left and right schemas |
|
|
333
|
-
| `pipe` (non-transform) | sequential in→out validation |
|
|
334
|
-
| `optional` | wraps any supported type |
|
|
335
|
-
| `nullable` | wraps any supported type |
|
|
336
|
-
| `readonly` | validates inner type (TS-only concept) |
|
|
337
|
-
| `default` | replaces `undefined` with default value, then validates inner |
|
|
338
|
-
| `symbol` | — (typeof check) |
|
|
339
|
-
| `void` | — (accepts `undefined`) |
|
|
340
|
-
| `nan` | — (Number.isNaN check) |
|
|
341
|
-
| `never` | — (always fails) |
|
|
342
|
-
| `lazy` (self-recursive) | cycle detection → self-recursive codegen |
|
|
343
|
-
|
|
344
|
-
### Automatic Fallback to Zod
|
|
345
|
-
|
|
346
|
-
These schema types contain JavaScript closures or runtime-dependent logic that cannot be compiled to static code. They are detected during extraction and produce a `FallbackIR`:
|
|
347
|
-
|
|
348
|
-
- `transform` — runtime data transformation
|
|
349
|
-
- `refine` / `superRefine` — custom validation with closures
|
|
350
|
-
- `custom` — arbitrary validation logic
|
|
351
|
-
- `preprocess` — input preprocessing
|
|
352
|
-
- `lazy` (non-recursive) — deferred schema resolution where inner type cannot be resolved
|
|
353
|
-
|
|
354
|
-
#### Partial Fallback
|
|
355
|
-
|
|
356
|
-
When a schema contains a mix of compilable and non-compilable parts (e.g., an object where some properties use `transform`/`refine`), zod-aot compiles the optimizable parts and delegates only the non-compilable properties to Zod at runtime.
|
|
357
|
-
|
|
358
|
-
> **Note:** If a schema heavily relies on `transform`, `refine`, or other non-compilable features, the performance benefit from partial fallback will be minimal — most of the validation work is still delegated to Zod. Partial fallback is most effective when only a small portion of the schema uses these features.
|
|
359
|
-
|
|
360
|
-
## Development
|
|
306
|
+
All standard Zod checks are supported: `min`, `max`, `length`, `email`, `url`, `uuid`, `regex`, `int`, `positive`, `negative`, `multipleOf`, `int32`, `uint32`, `float32`, `float64`, `includes`, `startsWith`, `endsWith`, and more.
|
|
361
307
|
|
|
362
|
-
|
|
363
|
-
# Install dependencies
|
|
364
|
-
pnpm install
|
|
308
|
+
### Falls Back to Zod (Still Works, Not Faster)
|
|
365
309
|
|
|
366
|
-
|
|
367
|
-
pnpm test
|
|
310
|
+
These types contain JavaScript closures that cannot be compiled to static code:
|
|
368
311
|
|
|
369
|
-
|
|
370
|
-
|
|
312
|
+
| Type | Why | Alternative |
|
|
313
|
+
|---|---|---|
|
|
314
|
+
| `transform` | Runtime data transformation function | Use `z.pipe()` when possible |
|
|
315
|
+
| `refine` / `superRefine` | Custom validation closures | Use built-in checks when possible |
|
|
316
|
+
| `custom` | Arbitrary validation logic | — |
|
|
317
|
+
| `preprocess` | Input preprocessing function | Use `z.coerce` when possible |
|
|
318
|
+
| `lazy` (non-recursive) | Cannot resolve inner type | Use self-referencing lazy for recursion |
|
|
371
319
|
|
|
372
|
-
|
|
373
|
-
pnpm lint
|
|
320
|
+
**Partial fallback:** If an object has 10 properties and 1 uses `transform`, the other 9 are still compiled. Only the `transform` property falls back to Zod.
|
|
374
321
|
|
|
375
|
-
|
|
376
|
-
pnpm -r typecheck
|
|
322
|
+
**Tip:** Run `npx zod-aot check` to see exactly which parts of your schemas are compiled and which fall back.
|
|
377
323
|
|
|
378
|
-
|
|
379
|
-
pnpm -r build
|
|
380
|
-
```
|
|
324
|
+
## Benchmarks
|
|
381
325
|
|
|
382
|
-
|
|
326
|
+
5-way comparison: **Zod v3** vs **Zod v4** vs **Zod AOT** vs **[Typia](https://typia.io/)** vs **[AJV](https://ajv.js.org/)**
|
|
383
327
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
328
|
+
| Scenario | Zod v3 | Zod v4 | **Zod AOT** | Typia | AJV | vs Zod v4 |
|
|
329
|
+
|---|---|---|---|---|---|---|
|
|
330
|
+
| simple string | 8.7M | 10.0M | **11.0M** | 11.0M | 11.1M | 1.1x |
|
|
331
|
+
| string (min/max) | 8.3M | 6.0M | **11.1M** | 11.3M | 9.5M | 1.8x |
|
|
332
|
+
| number (int+positive) | 8.2M | 5.8M | **10.9M** | 10.7M | 10.9M | 1.9x |
|
|
333
|
+
| enum | 8.0M | 9.5M | **10.6M** | 10.6M | 10.5M | 1.1x |
|
|
334
|
+
| bigint (min/max) | 8.0M | 6.0M | **10.9M** | — | — | 1.8x |
|
|
335
|
+
| tuple [string, int, bool] | 4.0M | 4.4M | **10.5M** | 10.8M | 10.5M | 2.4x |
|
|
336
|
+
| record\<string, number\> | 2.3M | 1.9M | **5.4M** | 7.5M | 9.4M | 2.8x |
|
|
337
|
+
| set\<string\> (5 items) | 2.7M | 1.6M | **9.8M** | — | — | 6.3x |
|
|
338
|
+
| set\<string\> (20 items) | 1.0M | 475K | **7.7M** | — | — | **16x** |
|
|
339
|
+
| map\<string, number\> (5 entries) | 1.5M | 946K | **8.5M** | — | — | 9.0x |
|
|
340
|
+
| map\<string, number\> (20 entries) | 490K | 238K | **5.2M** | — | — | **22x** |
|
|
341
|
+
| pipe (non-transform) | 6.3M | 3.8M | **10.8M** | — | — | 2.8x |
|
|
342
|
+
| discriminatedUnion (3 variants) | 2.3M | 2.9M | **9.8M** | 10.4M | 5.6M | 3.4x |
|
|
343
|
+
| medium object (valid) | 1.3M | 1.7M | **5.4M** | 7.3M | 5.0M | 3.1x |
|
|
344
|
+
| medium object (invalid) | 351K | 65K | **471K** | 2.1M | 5.6M | 7.3x |
|
|
345
|
+
| large object (10 items) | 82K | 111K | **4.0M** | 4.1M | 834K | **36x** |
|
|
346
|
+
| large object (100 items) | 9.0K | 11.6K | **676K** | 808K | 89K | **58x** |
|
|
347
|
+
| recursive tree (7 nodes) | 424K | 1.5M | **6.4M** | 8.1M | 3.1M | 4.1x |
|
|
348
|
+
| recursive tree (121 nodes) | 24K | 101K | **741K** | 1.4M | 250K | 7.4x |
|
|
349
|
+
| event log (combined) | 260K | 479K | **4.5M** | — | — | 9.4x |
|
|
350
|
+
| partial fallback obj (transform) | 817K | 1.4M | **3.3M** | — | — | 2.3x |
|
|
351
|
+
| partial fallback arr 10 (transform) | 88K | 139K | **841K** | — | — | 6.1x |
|
|
352
|
+
| partial fallback arr 50 (transform) | 18K | 28K | **175K** | — | — | 6.3x |
|
|
403
353
|
|
|
404
|
-
|
|
354
|
+
*ops/s, higher is better. "—" = not supported by the library. Measured with `vitest bench` on Apple M-series.*
|
|
405
355
|
|
|
406
|
-
|
|
356
|
+
Performance scales with schema complexity. Nested objects and arrays see the biggest gains because zod-aot eliminates per-node traversal overhead. `discriminatedUnion` uses O(1) `switch` dispatch instead of Zod's sequential trial. Partial fallback schemas (containing `transform`/`refine`) still show 2-6x speedups.
|
|
407
357
|
|
|
408
358
|
```bash
|
|
409
|
-
pnpm
|
|
359
|
+
pnpm bench # run locally
|
|
410
360
|
```
|
|
411
361
|
|
|
362
|
+
### Performance Architecture
|
|
363
|
+
|
|
364
|
+
For eligible schemas, zod-aot generates a **two-phase validator**:
|
|
365
|
+
|
|
366
|
+
1. **Fast Path** — A single `&&` expression chain that validates the entire input with zero allocations. Valid input returns immediately.
|
|
367
|
+
2. **Slow Path** — Error-collecting validation that only runs when the Fast Path fails.
|
|
368
|
+
|
|
369
|
+
Additional optimizations: check ordering (cheap checks first), pre-compiled regex, Set-based enum lookups, small enum inlining (`===` for 1-3 values).
|
|
370
|
+
|
|
371
|
+
Run `npx zod-aot check --json` to see which schemas qualify for Fast Path.
|
|
372
|
+
|
|
412
373
|
## License
|
|
413
374
|
|
|
414
375
|
[MIT](LICENSE)
|