zod-compiler 2.0.5 → 2.0.6
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 +97 -118
- package/dist/core/codegen/build-path.js +1 -1
- package/dist/core/codegen/context.d.ts +6 -5
- package/dist/core/codegen/context.d.ts.map +1 -1
- package/dist/core/codegen/context.js +10 -8
- package/dist/core/codegen/context.js.map +1 -1
- package/dist/core/codegen/index.js +1 -1
- package/dist/core/codegen/issue-decls.d.ts +18 -1
- package/dist/core/codegen/issue-decls.d.ts.map +1 -1
- package/dist/core/codegen/issue-decls.js +19 -1
- package/dist/core/codegen/issue-decls.js.map +1 -1
- package/dist/core/codegen/schemas/array.js +2 -2
- package/dist/core/codegen/schemas/array.js.map +1 -1
- package/dist/core/codegen/schemas/custom.js +1 -1
- package/dist/core/codegen/schemas/discriminated-union.js +1 -1
- package/dist/core/codegen/schemas/discriminated-union.js.map +1 -1
- package/dist/core/codegen/schemas/effect.js +2 -2
- package/dist/core/codegen/schemas/effect.js.map +1 -1
- package/dist/core/codegen/schemas/fallback.js +1 -1
- package/dist/core/codegen/schemas/map.js +1 -1
- package/dist/core/codegen/schemas/number.js +1 -1
- package/dist/core/codegen/schemas/object.js +3 -3
- package/dist/core/codegen/schemas/object.js.map +1 -1
- package/dist/core/codegen/schemas/record.js +2 -2
- package/dist/core/codegen/schemas/record.js.map +1 -1
- package/dist/core/codegen/schemas/sizeable.js +1 -1
- package/dist/core/codegen/schemas/string.js +1 -1
- package/dist/core/codegen/schemas/tuple.js +2 -2
- package/dist/core/codegen/schemas/tuple.js.map +1 -1
- package/dist/core/codegen/schemas/union.js +1 -1
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +1 -0
- package/dist/unplugin/virtual.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
**Compile Zod schemas into zero-overhead validation functions at build time.**
|
|
4
4
|
|
|
5
|
-
Keep your existing Zod schemas. Get **up to
|
|
5
|
+
Keep your existing Zod schemas. Get **up to 43x faster** validation, and up to **48x** on rejected
|
|
6
6
|
input. No code changes required.
|
|
7
7
|
|
|
8
|
-
Requires **Zod ≥ 4.5
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
and `jit()` warn once and leave the schemas as plain Zod) rather than compiled into validators that
|
|
12
|
-
disagree with it.
|
|
8
|
+
Requires **Zod ≥ 4.5**; compiled output reproduces 4.5's semantics exactly, so it does not match
|
|
9
|
+
earlier 4.x releases. Use zod-compiler 1.x for Zod 4.0–4.4. An older Zod is refused with an explicit
|
|
10
|
+
error; the build plugin and `jit()` warn once and leave schemas as plain Zod.
|
|
13
11
|
|
|
14
12
|
- [What Gets Compiled](#what-gets-compiled)
|
|
15
13
|
- [Schema Hoisting](#schema-hoisting)
|
|
@@ -28,16 +26,12 @@ loads pre-generated validators.
|
|
|
28
26
|
| | zod-compiler (build plugins / CLI) | Zod `z.compile()` |
|
|
29
27
|
| -------------------------------------- | -------------------------------------------- | --------------------------------------------- |
|
|
30
28
|
| Compilation | Build time (true AOT) | Runtime (`z.compile()` or the first parse) |
|
|
31
|
-
| Reported validation speedup | Up to
|
|
32
|
-
| Uses `new Function()` at runtime
|
|
29
|
+
| Reported validation speedup | Up to 43x; up to 48x on rejected input | ~9x in Zod's headline example |
|
|
30
|
+
| Uses `new Function()` at runtime | No | Yes |
|
|
33
31
|
| Cold start | Fast; the validator is already generated | Pays for code generation at startup/first use |
|
|
34
32
|
| Strict CSP without `'unsafe-eval'` | Supported | Compilation is unavailable |
|
|
35
33
|
| Compiler shipped in the runtime bundle | No; only validators and runtime helpers ship | Yes; about 7 KB gzipped according to Zod |
|
|
36
34
|
|
|
37
|
-
\*zod-compiler's optional [`jit()`](#4-runtime-compilation-no-build-step) and
|
|
38
|
-
[Node.js register hook](#5-nodejs-register-hook) use `new Function()` and have the same runtime
|
|
39
|
-
code-generation and CSP trade-offs as Zod's `z.compile()`.
|
|
40
|
-
|
|
41
35
|
## Usage
|
|
42
36
|
|
|
43
37
|
Five ways to use zod-compiler. Pick one:
|
|
@@ -135,8 +129,7 @@ Compilation is lazy, costing 0.1-0.3 ms on a schema's first parse. `{ eager: tru
|
|
|
135
129
|
and `jitAll(namespace)` takes a whole module.
|
|
136
130
|
|
|
137
131
|
The cost is the import: ~570 KB of codegen and `acorn`, **~10 ms of module load**. That suits a
|
|
138
|
-
long-lived process, not a CLI, a cold serverless handler or a browser.
|
|
139
|
-
have libraries ship plain Zod so the app can decide.
|
|
132
|
+
long-lived process, not a CLI, a cold serverless handler or a browser.
|
|
140
133
|
|
|
141
134
|
Needs `new Function`, as Zod's own object fast-path does. `z.config({ jitless: true })` and a CSP
|
|
142
135
|
that blocks eval both leave a working plain-Zod schema.
|
|
@@ -157,11 +150,9 @@ also chains with TypeScript runners:
|
|
|
157
150
|
node --import zod-compiler/register --import tsx src/server.ts
|
|
158
151
|
```
|
|
159
152
|
|
|
160
|
-
This is runtime JIT instrumentation, not
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
build plugin or the CLI when validator code must exist before Node starts, or when `new Function` is
|
|
164
|
-
unavailable at runtime.
|
|
153
|
+
This is runtime JIT instrumentation, not AOT source rewriting: the hook generates validators
|
|
154
|
+
in-process on first use. Use a build plugin or the CLI when validator code must exist before Node
|
|
155
|
+
starts, or when `new Function` is unavailable.
|
|
165
156
|
|
|
166
157
|
Optional settings come from `zod-compiler.json` in the working directory:
|
|
167
158
|
|
|
@@ -282,10 +273,9 @@ bundle. Schemas in a file that share a structurally identical sub-shape emit its
|
|
|
282
273
|
**19-28% raw / 10-18% gzipped** and scaling with how much the file repeats.
|
|
283
274
|
|
|
284
275
|
Build plugins serve that module from a resolve hook (`virtual:zod-compiler/runtime`, or
|
|
285
|
-
`__zod-compiler-runtime__` on webpack and rspack
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
import rather than leaving it external.
|
|
276
|
+
`__zod-compiler-runtime__` on webpack and rspack). [Turbopack](#nextjs-turbopack) has no such hook, so
|
|
277
|
+
it imports the real subpath `zod-compiler/runtime` instead, opt-in because it only pays off where the
|
|
278
|
+
host bundles that import.
|
|
289
279
|
|
|
290
280
|
**Transpile-only esbuild builds** (no `--bundle`) never fire the bundler's resolve hooks, so the
|
|
291
281
|
`virtual:` specifier would survive into `dist/` and fail at runtime. Set `codegenMode: "inline"` to emit
|
|
@@ -376,8 +366,7 @@ The step pays for itself: **Hermes ships no JIT and no `new Function`**, so Zod'
|
|
|
376
366
|
is unavailable on device and [`jit()`](#4-runtime-compilation-no-build-step) cannot run there at all.
|
|
377
367
|
|
|
378
368
|
Keep schema modules free of `react-native` and `expo-*` imports, transitively. Discovery executes each
|
|
379
|
-
file and its import graph in Node
|
|
380
|
-
silently.
|
|
369
|
+
file and its import graph in Node, and one that throws falls back to runtime Zod silently.
|
|
381
370
|
|
|
382
371
|
### Compact Output (`output: "compact"`)
|
|
383
372
|
|
|
@@ -391,14 +380,13 @@ zodCompiler({ output: "compact" });
|
|
|
391
380
|
|
|
392
381
|
### Workers and Serverless Startup
|
|
393
382
|
|
|
394
|
-
Workers construct every imported schema at module init, even when an isolate validates only a few
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
lazy.
|
|
383
|
+
Workers construct every imported schema at module init, even when an isolate validates only a few, so
|
|
384
|
+
compiling all of them trades bundle size and startup work for validation speed. Compact output trims
|
|
385
|
+
the generated error path but does not make construction lazy.
|
|
398
386
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
387
|
+
Narrow `include` or use `schemas: "explicit"` to skip intermediate exports. Use `output: "bag"` where
|
|
388
|
+
consumers need no Zod APIs (`.shape`, `.extend()`, `.meta()`, `z.toJSONSchema()`); it drops the
|
|
389
|
+
retained schema entirely.
|
|
402
390
|
|
|
403
391
|
Measure startup separately from validation throughput, on the target deployment and bundle.
|
|
404
392
|
|
|
@@ -439,10 +427,9 @@ never mention `zod` cost nothing.
|
|
|
439
427
|
|
|
440
428
|
### Parallel Transforms
|
|
441
429
|
|
|
442
|
-
Discovery runs one file at a time on the bundler's
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
same time sound.
|
|
430
|
+
Discovery runs one file at a time on the bundler's thread so concurrent transforms cannot
|
|
431
|
+
double-execute a shared dependency. `parallel` moves whole transforms onto worker threads, each with
|
|
432
|
+
its own loader and module cache.
|
|
446
433
|
|
|
447
434
|
```typescript
|
|
448
435
|
zodCompiler({ parallel: true }); // one worker per core, less one, capped at 4
|
|
@@ -459,18 +446,15 @@ win; files chained through each other can lose. Both rows below are 120 files of
|
|
|
459
446
|
| independent graphs | 3,633 ms | 2,263 ms | 1,508 ms | 1,786 ms | 2,119 ms |
|
|
460
447
|
| 120-deep import chain | 945 ms | 977 ms | 1,045 ms | 1,796 ms | 3,332 ms |
|
|
461
448
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
re-executes more graph
|
|
465
|
-
receiving thread has to deserialize.
|
|
449
|
+
Measure before adopting it: `ZOD_COMPILER_TIMING=1` prints the per-phase breakdown, and `discover` is
|
|
450
|
+
the line workers move. Throughput peaks around four workers and declines past it, as every extra
|
|
451
|
+
worker re-executes more graph and holds another copy in memory.
|
|
466
452
|
|
|
467
|
-
Emitted code, sourcemaps and cache entries are identical either way
|
|
468
|
-
cache key, so parallel and serial builds share one cache.
|
|
469
|
-
|
|
470
|
-
rather than failing the build.
|
|
453
|
+
Emitted code, sourcemaps and cache entries are identical either way, and `parallel` is not part of the
|
|
454
|
+
cache key, so parallel and serial builds share one cache. A worker that cannot start or dies mid-build
|
|
455
|
+
has its file retried in-process.
|
|
471
456
|
|
|
472
|
-
A **warm cache still beats parallelism** and costs no memory. Reach for `parallel` on
|
|
473
|
-
cache cannot help with.
|
|
457
|
+
A **warm cache still beats parallelism** and costs no memory. Reach for `parallel` on cold runs.
|
|
474
458
|
|
|
475
459
|
## Framework Examples
|
|
476
460
|
|
|
@@ -545,7 +529,7 @@ npx zod-compiler check src/schemas.ts --json --fail-under 80
|
|
|
545
529
|
|
|
546
530
|
## What Gets Compiled
|
|
547
531
|
|
|
548
|
-
### Fully Compiled (up to
|
|
532
|
+
### Fully Compiled (up to 43x faster)
|
|
549
533
|
|
|
550
534
|
Every Zod type except the fallbacks below: all primitives, `object` / `strictObject` / `looseObject`,
|
|
551
535
|
`array`, `tuple`, `record`, `set`, `map`, `union`, `discriminatedUnion`, `intersection`, `pipe`,
|
|
@@ -596,61 +580,63 @@ Schema-level `error` and `z.config()` maps are unaffected; for a per-call map us
|
|
|
596
580
|
|
|
597
581
|
| Scenario | Zod v3 | Zod v4 | **zod-compiler** | Typia | AJV | vs Zod v4 |
|
|
598
582
|
| ----------------------------------------------- | ------ | ------ | ---------------- | ----- | ----- | --------- |
|
|
599
|
-
| simple string | 12.
|
|
600
|
-
| string (min/max) | 12.
|
|
601
|
-
| number (int+positive) |
|
|
602
|
-
| enum |
|
|
603
|
-
| bigint (min/max) | 11.
|
|
604
|
-
| tuple [string, int, bool] | 5.
|
|
605
|
-
| record\<string, number\> | 3.
|
|
606
|
-
| set\<string\> (5 items) | 3.
|
|
607
|
-
| set\<string\> (20 items) | 1.3M |
|
|
608
|
-
| map\<string, number\> (5 entries) | 2.0M | 1.3M | **13.
|
|
609
|
-
| map\<string, number\> (20 entries) |
|
|
610
|
-
| pipe (non-transform) | 8.
|
|
611
|
-
| discriminatedUnion (3 variants) | 3.3M | 5.2M | **
|
|
612
|
-
| discriminatedUnion (8 variants, rotating) | 2.6M | 4.
|
|
613
|
-
| plain union of 8 tagged objects (auto-discrim.) |
|
|
614
|
-
| strict object (DB row) | 1.8M | 3.0M | **11.
|
|
615
|
-
| medium object (valid) |
|
|
616
|
-
| medium object (extra keys stripped) | 1.8M | 2.
|
|
617
|
-
| medium object (invalid) |
|
|
618
|
-
| large object (10 items) |
|
|
619
|
-
| large object (100 items) | 13K |
|
|
620
|
-
| readonly field (wrapper compiles away) | 3.
|
|
621
|
-
| readonly root object (rebuild + freeze) | 2.8M | 5.
|
|
583
|
+
| simple string | 12.7M | 15.1M | **16.5M** | 17.1M | 17.7M | 1.1x |
|
|
584
|
+
| string (min/max) | 12.5M | 7.3M | **16.7M** | 17.0M | 15.0M | 2.3x |
|
|
585
|
+
| number (int+positive) | 12.0M | 9.5M | **16.8M** | 17.0M | 18.0M | 1.8x |
|
|
586
|
+
| enum | 11.6M | 15.1M | **16.7M** | 17.3M | 17.5M | 1.1x |
|
|
587
|
+
| bigint (min/max) | 11.5M | 8.4M | **16.6M** | — | — | 2.0x |
|
|
588
|
+
| tuple [string, int, bool] | 5.7M | 7.6M | **17.5M** | 17.3M | 16.2M | 2.3x |
|
|
589
|
+
| record\<string, number\> | 3.2M | 2.6M | **12.6M** | 11.8M | 15.1M | 4.9x |
|
|
590
|
+
| set\<string\> (5 items) | 3.6M | 2.3M | **15.7M** | — | — | 7.0x |
|
|
591
|
+
| set\<string\> (20 items) | 1.3M | 679K | **12.3M** | — | — | **18x** |
|
|
592
|
+
| map\<string, number\> (5 entries) | 2.0M | 1.3M | **13.4M** | — | — | **10x** |
|
|
593
|
+
| map\<string, number\> (20 entries) | 658K | 348K | **8.7M** | — | — | **25x** |
|
|
594
|
+
| pipe (non-transform) | 8.9M | 4.7M | **17.6M** | — | — | 3.7x |
|
|
595
|
+
| discriminatedUnion (3 variants) | 3.3M | 5.2M | **16.3M** | 15.5M | 7.6M | 3.1x |
|
|
596
|
+
| discriminatedUnion (8 variants, rotating) | 2.6M | 4.6M | **10.1M** | — | — | 2.2x |
|
|
597
|
+
| plain union of 8 tagged objects (auto-discrim.) | 350K | 1.3M | **10.4M** | — | — | 7.8x |
|
|
598
|
+
| strict object (DB row) | 1.8M | 3.0M | **11.5M** | — | — | 3.9x |
|
|
599
|
+
| medium object (valid) | 2.0M | 2.3M | **9.8M** | 11.4M | 7.6M | 4.2x |
|
|
600
|
+
| medium object (extra keys stripped) | 1.8M | 2.1M | **9.6M** | — | — | 4.6x |
|
|
601
|
+
| medium object (invalid) | 464K | 370K | **16.0M** | 2.9M | 7.6M | **43x** |
|
|
602
|
+
| large object (10 items) | 119K | 169K | **5.2M** | 5.9M | 1.2M | **31x** |
|
|
603
|
+
| large object (100 items) | 13K | 18K | **763K** | 1.3M | 127K | **43x** |
|
|
604
|
+
| readonly field (wrapper compiles away) | 3.1M | 6.6M | **17.1M** | — | — | 2.6x |
|
|
605
|
+
| readonly root object (rebuild + freeze) | 2.8M | 5.6M | **13.0M** | — | — | 2.3x |
|
|
622
606
|
| readonly array (delegates to Zod) | 3.9M | 4.3M | **4.2M** | — | — | 1.0x |
|
|
623
|
-
| recursive tree (7 nodes) |
|
|
624
|
-
| recursive tree (121 nodes) |
|
|
625
|
-
| nested recursion (7 nodes) |
|
|
626
|
-
| nested recursion (121 nodes) | 24K |
|
|
627
|
-
| deeply nested object (243 leaves) | 11K | 27K | **
|
|
628
|
-
| event log (combined) |
|
|
629
|
-
|
|
|
630
|
-
|
|
|
631
|
-
|
|
|
632
|
-
| object with
|
|
633
|
-
|
|
|
634
|
-
|
|
|
635
|
-
|
|
|
636
|
-
|
|
|
637
|
-
|
|
|
638
|
-
|
|
|
639
|
-
|
|
|
640
|
-
|
|
|
641
|
-
|
|
|
642
|
-
|
|
|
643
|
-
|
|
|
644
|
-
|
|
|
607
|
+
| recursive tree (7 nodes) | 576K | 1.0M | **7.8M** | 11.9M | 4.8M | 7.8x |
|
|
608
|
+
| recursive tree (121 nodes) | 32K | 57K | **774K** | 1.9M | 371K | **13x** |
|
|
609
|
+
| nested recursion (7 nodes) | 388K | 677K | **7.7M** | 10.4M | 3.0M | **11x** |
|
|
610
|
+
| nested recursion (121 nodes) | 24K | 41K | **804K** | 1.6M | 210K | **20x** |
|
|
611
|
+
| deeply nested object (243 leaves) | 11K | 27K | **847K** | 1.0M | 122K | **31x** |
|
|
612
|
+
| event log (combined) | 370K | 786K | **7.7M** | — | — | 9.8x |
|
|
613
|
+
| catalog product with image URLs (valid) | 426K | 451K | **1.4M** | — | — | 3.1x |
|
|
614
|
+
| catalog product with image URLs (invalid) | 115K | 104K | **237K** | — | — | 2.3x |
|
|
615
|
+
| catalog page (20 products) | 21K | 23K | **74K** | — | — | 3.2x |
|
|
616
|
+
| object with transform (zero-capture) | 1.1M | 1.9M | **7.3M** | — | — | 3.9x |
|
|
617
|
+
| array 10 × transform (zero-capture) | 120K | 209K | **4.3M** | — | — | **21x** |
|
|
618
|
+
| array 50 × transform (zero-capture) | 25K | 43K | **1.0M** | — | — | **24x** |
|
|
619
|
+
| object with captured transform | 1.2M | 7.8M | **15.3M** | — | — | 2.0x |
|
|
620
|
+
| object with captured refine (cross-field) | 1.5M | 2.2M | **11.2M** | — | — | 5.1x |
|
|
621
|
+
| object with superRefine (cross-field) | 1.4M | 2.1M | **9.1M** | — | — | 4.3x |
|
|
622
|
+
| coerced query object (valid) | 1.8M | 2.9M | **5.4M** | — | — | 1.8x |
|
|
623
|
+
| coerced query object (invalid) | 1.0M | 843K | **10.2M** | — | — | **12x** |
|
|
624
|
+
| preprocessed query object (valid) | 430K | 1.7M | **5.3M** | — | — | 3.1x |
|
|
625
|
+
| preprocessed query object (invalid) | 382K | 780K | **12.3M** | — | — | **16x** |
|
|
626
|
+
| stringbool config object (valid) | — | 2.8M | **6.4M** | — | — | 2.2x |
|
|
627
|
+
| stringbool config object (invalid) | — | 688K | **12.6M** | — | — | **18x** |
|
|
628
|
+
| custom/instanceof request (valid) | 972K | 3.1M | **10.3M** | — | — | 3.3x |
|
|
629
|
+
| custom/instanceof request (invalid) | 776K | 945K | **13.5M** | — | — | **14x** |
|
|
630
|
+
| disjoint object intersection (valid) | 1.4M | 1.6M | **10.0M** | — | — | 6.1x |
|
|
631
|
+
| disjoint object intersection (invalid) | 482K | 333K | **16.0M** | — | — | **48x** |
|
|
645
632
|
|
|
646
633
|
_ops/s, higher is better. `vp test bench` on an Apple M4 Max (zod 4.5.2, zod v3 3.23.8, typia 12, ajv 8),
|
|
647
634
|
best of three runs. The harness costs ~60 ns per iteration, so the fastest rows sit at that floor and gaps
|
|
648
635
|
between the AOT columns there are noise, not real._
|
|
649
636
|
|
|
650
637
|
Nested objects, arrays and recursive types gain the most. Rejection is fast because a failed
|
|
651
|
-
`safeParse` defers building the error until `.error` is read. Zod 4.5 stopped capturing a stack trace
|
|
652
|
-
|
|
653
|
-
narrower than it was.
|
|
638
|
+
`safeParse` defers building the error until `.error` is read. Zod 4.5 stopped capturing a stack trace
|
|
639
|
+
there too, narrowing the gap on rejected input.
|
|
654
640
|
|
|
655
641
|
```bash
|
|
656
642
|
vp run benchmark # run locally
|
|
@@ -658,29 +644,22 @@ vp run benchmark # run locally
|
|
|
658
644
|
|
|
659
645
|
### Performance Architecture
|
|
660
646
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
`
|
|
676
|
-
|
|
677
|
-
same single pass over the merged shape, and `z.custom()` / `z.instanceof()` compile to a direct predicate
|
|
678
|
-
call.
|
|
679
|
-
|
|
680
|
-
Where success is cheaper to compile than failure, only the verdict and output are compiled.
|
|
681
|
-
Intersections and `custom` keep the original Zod schema to construct issues, so a rejection still
|
|
682
|
-
reports exactly what Zod would, an intersection's one-issue-per-side shape included, without slowing the
|
|
683
|
-
hot path.
|
|
647
|
+
A schema compiles to a **fast path** — one zero-allocation `&&` chain, shared by `.is()` and
|
|
648
|
+
`parse()` — plus a **slow path** that collects errors only on failure, deferred until `.error` is read.
|
|
649
|
+
Schemas that reshape their input (stripping objects, coercions, `stringbool`, defaults, transforms,
|
|
650
|
+
context-free preprocessors, disjoint-key intersections) instead validate and rebuild in a single pass
|
|
651
|
+
that bails on the first failure.
|
|
652
|
+
|
|
653
|
+
Other optimizations:
|
|
654
|
+
|
|
655
|
+
- Regexes pre-compiled, bounded repeats unrolled; `z.email()` is a linear scan, not a backtracking regex.
|
|
656
|
+
- Checks run cheapest-first, regardless of declaration order.
|
|
657
|
+
- Discriminated unions dispatch through a `switch`; plain tagged unions are auto-discriminated into one.
|
|
658
|
+
- `z.custom()` / `z.instanceof()` compile to a direct predicate call.
|
|
659
|
+
- Oversized check functions are split to stay within V8's optimizer budget.
|
|
660
|
+
|
|
661
|
+
Intersections and `custom` keep the original Zod schema to construct issues, so rejections match Zod
|
|
662
|
+
exactly without slowing the hot path.
|
|
684
663
|
|
|
685
664
|
## Development
|
|
686
665
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { declareFastTemps, emitEffectCallable, emitEffectFn, emitPooledConstant, emitRuntimeHelper, emitTemp, escapeString, hasMutation, keyMembershipTest, literalToJs, needsProtoScrub, outputAlwaysDefined, rejectsUndefined, tupleRewritesShortInput } from "./context.js";
|
|
2
1
|
import { ZC_ASYNC_DECL, ZC_HOP_DECL, ZC_PLAIN_DECL, ZC_PROTO_SCRUB_DECL } from "./issue-decls.js";
|
|
2
|
+
import { declareFastTemps, emitEffectCallable, emitEffectFn, emitPooledConstant, emitRuntimeHelper, emitTemp, escapeString, hasMutation, keyMembershipTest, literalToJs, needsProtoScrub, outputAlwaysDefined, rejectsUndefined, tupleRewritesShortInput } from "./context.js";
|
|
3
3
|
import { defaultValueExpr, needsPostInnerDefault } from "./schemas/default.js";
|
|
4
4
|
import { detectUnionDiscriminator } from "./schemas/discriminated-union.js";
|
|
5
5
|
import { estimateFastCost, orderByRuntimeCost, predictedInlineSize } from "./fast-size.js";
|
|
@@ -501,14 +501,15 @@ declare function emitRuntimeHelper(ctx: CodeGenContext, name: string, decl: stri
|
|
|
501
501
|
* `[]` root, so any path that looks like an array literal IS one — the new
|
|
502
502
|
* segment is spliced in to keep issue paths a single array allocation
|
|
503
503
|
* (`["data","items",__i_7]`) instead of an allocation per nesting level
|
|
504
|
-
* (`["data"].concat("items").concat(__i_7)`).
|
|
505
|
-
*
|
|
504
|
+
* (`["data"].concat("items").concat(__i_7)`). An opaque path — a shared walk's
|
|
505
|
+
* `path` parameter, or an extension of it — appends through `__zcPa` (see
|
|
506
|
+
* ZC_PATH_APPEND_DECL), not `.concat()`.
|
|
506
507
|
*/
|
|
507
|
-
declare function extendPath(parentPath: string, segExpr: string): string;
|
|
508
|
+
declare function extendPath(ctx: CodeGenContext, parentPath: string, segExpr: string): string;
|
|
508
509
|
/** Extend a path expression with a static string key. */
|
|
509
|
-
declare function extendStaticPath(parentPath: string, key: string): string;
|
|
510
|
+
declare function extendStaticPath(ctx: CodeGenContext, parentPath: string, key: string): string;
|
|
510
511
|
/** Extend a path expression with a numeric index. */
|
|
511
|
-
declare function extendStaticPathIndex(parentPath: string, index: number): string;
|
|
512
|
+
declare function extendStaticPathIndex(ctx: CodeGenContext, parentPath: string, index: number): string;
|
|
512
513
|
/**
|
|
513
514
|
* Slow-walk one member of a container — an array element, a tuple slot, a
|
|
514
515
|
* record value — without writing to the container while it is still the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","names":[],"sources":["../../../src/core/codegen/context.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"context.d.ts","names":[],"sources":["../../../src/core/codegen/context.ts"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ZC_PATH_APPEND_DECL } from "./issue-decls.js";
|
|
1
2
|
import { fastTestSource, lookupWellKnownRegex, wellKnownRegexSourceName } from "./well-known-regex.js";
|
|
2
3
|
//#region src/core/codegen/context.ts
|
|
3
4
|
/** `var a,b;` declaration for a scope's temps, or "" when it allocated none. */
|
|
@@ -392,21 +393,22 @@ function emitRuntimeHelper(ctx, name, decl) {
|
|
|
392
393
|
* `[]` root, so any path that looks like an array literal IS one — the new
|
|
393
394
|
* segment is spliced in to keep issue paths a single array allocation
|
|
394
395
|
* (`["data","items",__i_7]`) instead of an allocation per nesting level
|
|
395
|
-
* (`["data"].concat("items").concat(__i_7)`).
|
|
396
|
-
*
|
|
396
|
+
* (`["data"].concat("items").concat(__i_7)`). An opaque path — a shared walk's
|
|
397
|
+
* `path` parameter, or an extension of it — appends through `__zcPa` (see
|
|
398
|
+
* ZC_PATH_APPEND_DECL), not `.concat()`.
|
|
397
399
|
*/
|
|
398
|
-
function extendPath(parentPath, segExpr) {
|
|
400
|
+
function extendPath(ctx, parentPath, segExpr) {
|
|
399
401
|
if (parentPath === "[]") return `[${segExpr}]`;
|
|
400
402
|
if (parentPath.startsWith("[") && parentPath.endsWith("]")) return `${parentPath.slice(0, -1)},${segExpr}]`;
|
|
401
|
-
return `${
|
|
403
|
+
return `${emitRuntimeHelper(ctx, "__zcPa", ZC_PATH_APPEND_DECL)}(${parentPath},${segExpr})`;
|
|
402
404
|
}
|
|
403
405
|
/** Extend a path expression with a static string key. */
|
|
404
|
-
function extendStaticPath(parentPath, key) {
|
|
405
|
-
return extendPath(parentPath, escapeString(key));
|
|
406
|
+
function extendStaticPath(ctx, parentPath, key) {
|
|
407
|
+
return extendPath(ctx, parentPath, escapeString(key));
|
|
406
408
|
}
|
|
407
409
|
/** Extend a path expression with a numeric index. */
|
|
408
|
-
function extendStaticPathIndex(parentPath, index) {
|
|
409
|
-
return extendPath(parentPath, String(index));
|
|
410
|
+
function extendStaticPathIndex(ctx, parentPath, index) {
|
|
411
|
+
return extendPath(ctx, parentPath, String(index));
|
|
410
412
|
}
|
|
411
413
|
/**
|
|
412
414
|
* Slow-walk one member of a container — an array element, a tuple slot, a
|