zod-compiler 1.22.4 → 1.22.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Compile Zod schemas into zero-overhead validation functions at build time.**
4
4
 
5
- Keep your existing Zod schemas. Get **2-45x faster** validation. No code changes required.
5
+ Keep your existing Zod schemas. Get **2-43x faster** validation. No code changes required.
6
6
 
7
7
  - [What Gets Compiled](#what-gets-compiled)
8
8
  - [Schema Hoisting](#schema-hoisting)
@@ -13,11 +13,11 @@ Keep your existing Zod schemas. Get **2-45x faster** validation. No code changes
13
13
 
14
14
  ## Usage
15
15
 
16
- There are three ways to use zod-compiler. Choose the one that fits your project.
16
+ Three ways to use zod-compiler pick one:
17
17
 
18
18
  ### 1. Automatic Mode (Default)
19
19
 
20
- The plugin automatically detects and compiles all exported Zod schemas at build time. No wrappers, no imports from `zod-compiler` in your source code.
20
+ The plugin detects and compiles every exported Zod schema at build time. No wrappers, no imports from `zod-compiler` in your source.
21
21
 
22
22
  **vite.config.ts:**
23
23
 
@@ -42,11 +42,11 @@ export const CreateUserSchema = z.object({
42
42
  });
43
43
  ```
44
44
 
45
- Use them as usual. Compiled methods are installed on the original schema object, so `.shape`, `._zod`,
46
- Standard Schema, `instanceof` and `z.toJSONSchema()` keep working and consumers need no changes.
45
+ Use them as usual. Methods are installed on the original schema object, so `.shape`, `._zod`, Standard
46
+ Schema, `instanceof` and `z.toJSONSchema()` keep working.
47
47
 
48
- Compiled schemas also expose **`.is(input): input is T`** — the compiled check itself, allocating
49
- nothing. A drop-in replacement for `safeParse(x).success`.
48
+ Compiled schemas also expose **`.is(input): input is T`** — a zero-allocation drop-in for
49
+ `safeParse(x).success`.
50
50
 
51
51
  ### 2. compile() (Explicit)
52
52
 
@@ -69,7 +69,7 @@ validateUser.parse(data);
69
69
  validateUser.safeParse(data);
70
70
  ```
71
71
 
72
- `compile()` and auto mode coexist `compile()` schemas are detected first, then every remaining plain Zod export is picked up. To make `compile()` the _only_ path (no automatic detection, no build-time execution of plain schema files), pair it with `schemas: "explicit"` in the plugin options.
72
+ `compile()` and auto mode coexist. Pair with `schemas: "explicit"` to make `compile()` the _only_ path no automatic detection, no build-time execution of plain schema files.
73
73
 
74
74
  ### 3. CLI (No Bundler)
75
75
 
@@ -148,8 +148,7 @@ export default defineConfig({
148
148
 
149
149
  ### Bun
150
150
 
151
- zod-compiler is a build-time tool, so on Bun it applies wherever your code passes through a build step.
152
- Requires **Bun ≥ 1.2.22**.
151
+ Applies wherever your code passes through a build step. Requires **Bun ≥ 1.2.22**.
153
152
 
154
153
  ```typescript
155
154
  import zodCompiler from "zod-compiler/bun";
@@ -179,16 +178,14 @@ Only expressions built from imported bindings and literals move; anything touchi
179
178
  `new Date()` stays put. Combinator chains on imported schemas qualify via `schemaNamePattern`
180
179
  (default `/ZodSchema$/`).
181
180
 
182
- In auto mode hoisted schemas also **compile** which rescues the schema that never leaves a function
183
- (a slonik query, a tRPC input), invisible to export scanning. Measured on that pattern: ~16,700 ns →
184
- ~14 ns per call.
181
+ In auto mode hoisted schemas also **compile**, rescuing the schema that never leaves a function (a
182
+ slonik query, a tRPC input) and so is invisible to export scanning: ~16,700 ns → ~14 ns per call.
185
183
 
186
184
  ### Bundle Size & Cross-File Dedup
187
185
 
188
186
  Validators share a runtime helper layer imported from one module, so each helper appears once per
189
- bundle. Schemas in a file sharing a structurally identical sub-shape emit its error walk once, which
190
- scales with how much a file repeats: **19% raw / 10% gzipped** for two exports reusing one nested
191
- shape, **28% / 18%** for four exports reusing two.
187
+ bundle. Schemas in a file sharing a structurally identical sub-shape emit its error walk once
188
+ **19-28% raw / 10-18% gzipped**, scaling with how much the file repeats.
192
189
 
193
190
  **Transpile-only esbuild builds** (no `--bundle`) never fire the bundler's resolve hooks, so the
194
191
  `virtual:` specifier would survive into `dist/` and fail at runtime. Set `codegenMode: "inline"` to emit
@@ -202,8 +199,8 @@ Set `output: "bag"` to also drop the retained Zod schema when you don't need `.s
202
199
 
203
200
  ### SWC
204
201
 
205
- `zod-compiler/swc` is a programmatic `@swc/core` bridge, not a `.swcrc` WASM plugin — discovery needs
206
- Node.js, so it wraps `transform()`. Install `@swc/core`, then:
202
+ A programmatic `@swc/core` bridge wrapping `transform()`, not a `.swcrc` plugin. Install
203
+ `@swc/core`, then:
207
204
 
208
205
  ```typescript
209
206
  import { transform } from "zod-compiler/swc";
@@ -220,13 +217,9 @@ Defaults `codegenMode` to `"inline"` (SWC has no virtual-module hook); pass
220
217
 
221
218
  ### Compact Output (`output: "compact"`)
222
219
 
223
- The error-collecting walk is 64–77% of the generated bytes, and it only reproduces Zod's issues on
224
- failure which the retained Zod schema already does. `output: "compact"` (CLI: `--emit compact`)
225
- compiles the fast path and delegates the cold error path to it.
226
-
227
- On 50 distinct schemas, output drops **~73% raw / ~71% gzipped**. The hot path is unchanged, errors are
228
- Zod's own, and `safeParse(x).success` / `.is(x)` never invoke Zod — only reading `.error` does. Mutation
229
- schemas keep the compiled path. Mutually exclusive with `output: "bag"`.
220
+ Compiles the fast path and delegates the cold error path to the retained Zod schema, dropping
221
+ **~73% raw / ~71% gzipped** on 50 distinct schemas. The hot path is unchanged and errors are Zod's own;
222
+ only reading `.error` invokes Zod. Mutually exclusive with `output: "bag"`.
230
223
 
231
224
  ### Auto Mode: Side Effects Warning
232
225
 
@@ -245,16 +238,6 @@ if (!process.env.ZOD_COMPILER) {
245
238
 
246
239
  With `@t3-oss/env-*`, pass `skipValidation: !!process.env.ZOD_COMPILER`.
247
240
 
248
- ### schemas: "auto" vs "explicit"
249
-
250
- | | `"auto"` (default) | `"explicit"` + compile() |
251
- | ---------------------------- | ---------------------------------------------------------- | ------------------------------------------- |
252
- | Source code changes | None | Wrap each schema |
253
- | `zod-compiler` import needed | No | Yes |
254
- | What gets compiled | All exported Zod schemas | Only wrapped schemas |
255
- | Build-time file execution | Zod-importing files that may export schemas (pre-filtered) | Files with `import ... from "zod-compiler"` |
256
- | Best for | New projects, framework integration | Gradual adoption, selective optimization |
257
-
258
241
  ### Large projects and CI
259
242
 
260
243
  Discovery executes each schema file inside the bundler's process, so the **first cold run** is the
@@ -267,14 +250,13 @@ expensive one — later runs hit the persistent cache.
267
250
  key: zod-compiler-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
268
251
  ```
269
252
 
270
- Cache entries self-validate against dependency hashes, so a stale cache can only cause recompiles.
271
- Scope discovery with `include`; set `ZOD_COMPILER_TIMING=1` to see per-phase wall time. Files that never
272
- mention `zod` cost nothing.
253
+ Scope discovery with `include`; set `ZOD_COMPILER_TIMING=1` for a per-phase breakdown. Files that
254
+ never mention `zod` cost nothing.
273
255
 
274
256
  ## Framework Examples
275
257
 
276
- Nothing framework-specific is needed. In auto mode your exported schemas are compiled in place, so
277
- anything that accepts a Zod schema keeps working and picks up the compiled version:
258
+ Nothing framework-specific is needed exported schemas are compiled in place, so anything accepting
259
+ a Zod schema picks up the compiled version:
278
260
 
279
261
  ```typescript
280
262
  // tRPC — no .input(compile(...)) needed
@@ -287,12 +269,15 @@ app.post("/users", zValidator("json", UserSchema), (c) => c.json(c.req.valid("js
287
269
  useForm({ resolver: zodResolver(SignupSchema) });
288
270
  ```
289
271
 
290
- The same applies to any [Standard Schema](https://standardschema.dev) consumer — `~standard` is
291
- preserved and routes through the compiled validator.
272
+ The same applies to any [Standard Schema](https://standardschema.dev) consumer — `~standard.validate`
273
+ routes through the compiled validator.
274
+
275
+ Compiled methods live on the schema object, so Zod's functional API (`z.safeParse(Schema, x)`) and a
276
+ compiled schema composed into an uncompiled parent stay on plain Zod.
292
277
 
293
278
  ## Schema Diagnostics
294
279
 
295
- Analyze your schemas before compiling — check coverage, Fast Path eligibility, and get actionable hints:
280
+ Check coverage and Fast Path eligibility before compiling:
296
281
 
297
282
  ```bash
298
283
  npx zod-compiler check src/schemas.ts
@@ -341,7 +326,7 @@ npx zod-compiler check src/schemas.ts --json --fail-under 80
341
326
 
342
327
  ## What Gets Compiled
343
328
 
344
- ### Fully Compiled (2-45x faster)
329
+ ### Fully Compiled (2-43x faster)
345
330
 
346
331
  Every Zod type except the fallbacks below — all primitives, `object` / `strictObject` / `looseObject`,
347
332
  `array`, `tuple`, `record`, `set`, `map`, `union`, `discriminatedUnion`, `intersection`, `pipe`,
@@ -372,16 +357,18 @@ see what compiled.
372
357
  ### Behavioral Differences from Zod
373
358
 
374
359
  Compiled validators match Zod on verdicts, output data and error messages, including issue ordering.
375
- Two things differ by design, both from the zero-allocation fast path:
360
+ Three things differ by design:
361
+
362
+ | Behavior | Zod | zod-compiler |
363
+ | ------------------------- | ----------------------------------------------- | ------------------------------------------------------- |
364
+ | Record key iteration | All own keys (`Reflect.ownKeys`) | Own enumerable **string** keys only |
365
+ | Container output identity | A fresh array / set / map / object | The input container, by reference (array holes survive) |
366
+ | Per-call parse params | `safeParse(x, { error, reportInput })` honoured | Ignored; global `z.config()` maps still apply |
376
367
 
377
- | Behavior | Zod | zod-compiler |
378
- | ------------------------- | ---------------------------------- | ------------------------------------------------------- |
379
- | Record key iteration | All own keys (`Reflect.ownKeys`) | Own enumerable **string** keys only |
380
- | Container output identity | A fresh array / set / map / object | The input container, by reference (array holes survive) |
368
+ Schema-level `error` and `z.config()` maps are unaffected; for a per-call map use
369
+ `z.safeParse(Schema, x, params)`.
381
370
 
382
- A container whose contents need no rewriting is validated in place and handed back, where Zod always
383
- rebuilds it. `z.object()` is the exception — it strips unknown keys exactly as Zod does, so its output
384
- is always a fresh object.
371
+ `z.object()` strips unknown keys exactly as Zod does, so its output is always a fresh object.
385
372
 
386
373
  ## Benchmark
387
374
 
@@ -389,42 +376,42 @@ is always a fresh object.
389
376
 
390
377
  | Scenario | Zod v3 | Zod v4 | **zod-compiler** | Typia | AJV | vs Zod v4 |
391
378
  | ----------------------------------------------- | ------ | ------ | ---------------- | ----- | ----- | --------- |
392
- | simple string | 12.9M | 14.5M | **16.9M** | 17.2M | 17.5M | 1.2x |
393
- | string (min/max) | 12.1M | 7.6M | **16.3M** | 17.6M | 14.9M | 2.1x |
394
- | number (int+positive) | 11.5M | 7.7M | **16.5M** | 16.8M | 17.7M | 2.1x |
395
- | enum | 11.8M | 12.2M | **16.8M** | 17.1M | 17.2M | 1.4x |
396
- | bigint (min/max) | 11.4M | 7.6M | **15.9M** | — | — | 2.1x |
397
- | tuple [string, int, bool] | 5.5M | 6.3M | **15.9M** | 16.8M | 15.3M | 2.5x |
398
- | record\<string, number\> | 3.2M | 2.7M | **15.5M** | 12.3M | 15.3M | 5.7x |
399
- | set\<string\> (5 items) | 3.6M | 2.3M | **15.0M** | — | — | 6.6x |
400
- | set\<string\> (20 items) | 1.3M | 695K | **11.9M** | — | — | **17x** |
401
- | map\<string, number\> (5 entries) | 2.0M | 1.3M | **12.4M** | — | — | 9.5x |
402
- | map\<string, number\> (20 entries) | 613K | 352K | **8.3M** | — | — | **24x** |
403
- | pipe (non-transform) | 8.7M | 5.6M | **16.8M** | — | — | 3.0x |
404
- | discriminatedUnion (3 variants) | 3.4M | 4.0M | **16.7M** | 16.0M | 7.9M | 4.1x |
405
- | discriminatedUnion (8 variants, rotating) | 2.7M | 3.5M | **9.8M** | — | — | 2.8x |
406
- | plain union of 8 tagged objects (auto-discrim.) | 358K | 646K | **9.5M** | — | — | **15x** |
407
- | strict object (DB row) | 1.8M | 3.1M | **11.0M** | — | — | 3.6x |
408
- | medium object (valid) | 1.5M | 2.3M | **9.4M** | 10.9M | 7.4M | 4.0x |
409
- | medium object (extra keys stripped) | 1.8M | 2.2M | **9.4M** | — | — | 4.3x |
410
- | medium object (invalid) | 536K | 79K | **14.2M** | 3.0M | 7.7M | **180x** |
411
- | large object (10 items) | 118K | 162K | **5.2M** | 5.8M | 1.2M | **32x** |
412
- | large object (100 items) | 13K | 18K | **811K** | 1.4M | 125K | **45x** |
413
- | recursive tree (7 nodes) | 589K | 2.1M | **8.1M** | 11.9M | 4.9M | 3.8x |
414
- | recursive tree (121 nodes) | 32K | 128K | **803K** | 1.9M | 386K | 6.3x |
415
- | nested recursion (7 nodes) | 395K | 1.0M | **7.1M** | 8.8M | 2.5M | 7.0x |
416
- | nested recursion (121 nodes) | 23K | 61K | **804K** | 1.4M | 184K | **13x** |
417
- | deeply nested object (243 leaves) | 11K | 20K | **832K** | 1.0M | 124K | **42x** |
418
- | event log (combined) | 377K | 623K | **7.3M** | — | — | **12x** |
419
- | object with transform (zero-capture) | 1.1M | 2.0M | **6.0M** | — | — | 3.0x |
420
- | array 10 × transform (zero-capture) | 120K | 204K | **3.7M** | — | — | **18x** |
421
- | array 50 × transform (zero-capture) | 25K | 41K | **963K** | — | — | **24x** |
422
- | object with captured transform | 1.3M | 6.1M | **15.2M** | — | — | 2.5x |
423
- | object with captured refine (cross-field) | 1.6M | 2.5M | **13.7M** | — | — | 5.5x |
424
- | object with superRefine (cross-field) | 1.5M | 2.3M | **11.7M** | — | — | 5.0x |
379
+ | simple string | 12.6M | 14.3M | **16.5M** | 17.8M | 17.6M | 1.2x |
380
+ | string (min/max) | 12.5M | 7.5M | **15.9M** | 17.0M | 15.2M | 2.1x |
381
+ | number (int+positive) | 12.3M | 7.8M | **16.6M** | 16.8M | 17.3M | 2.1x |
382
+ | enum | 11.7M | 12.1M | **16.2M** | 17.7M | 17.3M | 1.3x |
383
+ | bigint (min/max) | 12.0M | 7.7M | **15.9M** | — | — | 2.1x |
384
+ | tuple [string, int, bool] | 5.8M | 6.5M | **15.7M** | 17.1M | 16.3M | 2.4x |
385
+ | record\<string, number\> | 3.2M | 2.8M | **15.2M** | 12.1M | 15.2M | 5.5x |
386
+ | set\<string\> (5 items) | 3.7M | 2.3M | **14.7M** | — | — | 6.4x |
387
+ | set\<string\> (20 items) | 1.3M | 683K | **12.0M** | — | — | **18x** |
388
+ | map\<string, number\> (5 entries) | 2.1M | 1.4M | **13.1M** | — | — | 9.6x |
389
+ | map\<string, number\> (20 entries) | 635K | 362K | **8.3M** | — | — | **23x** |
390
+ | pipe (non-transform) | 8.6M | 5.6M | **15.9M** | — | — | 2.8x |
391
+ | discriminatedUnion (3 variants) | 3.3M | 4.0M | **15.8M** | 15.5M | 7.7M | 4.0x |
392
+ | discriminatedUnion (8 variants, rotating) | 2.7M | 3.4M | **9.2M** | — | — | 2.7x |
393
+ | plain union of 8 tagged objects (auto-discrim.) | 363K | 632K | **9.1M** | — | — | **14x** |
394
+ | strict object (DB row) | 1.8M | 3.1M | **10.9M** | — | — | 3.5x |
395
+ | medium object (valid) | 1.9M | 2.4M | **9.7M** | 11.2M | 7.7M | 4.1x |
396
+ | medium object (extra keys stripped) | 1.8M | 2.3M | **9.4M** | — | — | 4.2x |
397
+ | medium object (invalid) | 504K | 80K | **14.7M** | 2.9M | 7.7M | **184x** |
398
+ | large object (10 items) | 122K | 166K | **5.3M** | 5.9M | 1.2M | **32x** |
399
+ | large object (100 items) | 13K | 18K | **781K** | 1.3M | 125K | **43x** |
400
+ | recursive tree (7 nodes) | 569K | 2.1M | **8.2M** | 11.6M | 4.8M | 3.9x |
401
+ | recursive tree (121 nodes) | 32K | 135K | **800K** | 1.9M | 372K | 5.9x |
402
+ | nested recursion (7 nodes) | 391K | 1.0M | **7.9M** | 11.1M | 3.1M | 7.8x |
403
+ | nested recursion (121 nodes) | 24K | 62K | **818K** | 1.6M | 218K | **13x** |
404
+ | deeply nested object (243 leaves) | 11K | 20K | **828K** | 1.1M | 117K | **42x** |
405
+ | event log (combined) | 368K | 609K | **8.2M** | — | — | **13x** |
406
+ | object with transform (zero-capture) | 1.2M | 1.9M | **6.5M** | — | — | 3.4x |
407
+ | array 10 × transform (zero-capture) | 121K | 214K | **4.2M** | — | — | **20x** |
408
+ | array 50 × transform (zero-capture) | 25K | 44K | **1.0M** | — | — | **24x** |
409
+ | object with captured transform | 1.4M | 6.3M | **15.1M** | — | — | 2.4x |
410
+ | object with captured refine (cross-field) | 1.6M | 2.4M | **15.3M** | — | — | 6.3x |
411
+ | object with superRefine (cross-field) | 1.6M | 2.3M | **11.6M** | — | — | 5.0x |
425
412
 
426
413
  _ops/s, higher is better. `vitest bench` on an Apple M4 Max (zod 4.3.6, zod v3 3.23.8, typia 12, ajv 8),
427
- best of two runs. The harness costs ~55 ns per iteration, so the fastest rows sit at that floor and gaps
414
+ best of three runs. The harness costs ~55 ns per iteration, so the fastest rows sit at that floor and gaps
428
415
  between the AOT columns there are noise, not real._
429
416
 
430
417
  Nested objects, arrays and recursive types gain the most. Rejection is fast because a failed
@@ -439,9 +426,8 @@ pnpm benchmark # run locally
439
426
  An eligible schema compiles to a **fast path** — one `&&` chain validating the whole input with zero
440
427
  allocations, reused by `.is()` and `parse()` — plus a **slow path** that collects errors, run only on
441
428
  failure and deferred until `.error` is read. A `z.object()` strips, so it instead compiles to a single
442
- pass that validates and rebuilds together, bailing on the first failure. That pass also covers the
443
- idioms that reshape a value — array size checks, `.refine()`, `.default()`, `.trim()`, `.transform()`
444
- so one of them in a schema no longer costs it the whole single-pass parse.
429
+ pass that validates and rebuilds together, bailing on the first failure including the reshaping
430
+ idioms (array size checks, `.refine()`, `.default()`, `.trim()`, `.transform()`).
445
431
 
446
432
  Regexes are pre-compiled with bounded repeats unrolled, checks run cheapest-first, discriminated unions
447
433
  dispatch through a jump table (plain tagged unions are auto-discriminated into it), and oversized check
@@ -11,8 +11,26 @@ import type { CompiledSchemaInfo } from "./pipeline.js";
11
11
  * parse raises (see ZC_SR_DECL).
12
12
  */
13
13
  export declare const ZOD_CONFIG_IMPORT = "import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";";
14
- /** File-level __zcMsg declaration (must appear once after ZOD_CONFIG_IMPORT). */
15
- export declare const ZOD_MSG_DECLARATION = "var __zcMsg=__zodCompilerConfig().localeError;";
14
+ /**
15
+ * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):
16
+ * the message an issue gets when nothing was baked into it at build time.
17
+ *
18
+ * Resolves zod's tail of `finalizeIssue` — `config.customError` then
19
+ * `config.localeError` then "Invalid input" — and does it PER CALL, because the
20
+ * config is mutable: `z.config({ localeError })` in an entry point runs after
21
+ * the schema modules it imports, so a value snapshotted at module init misses
22
+ * it. Reading a captured `localeError` alone also dropped `customError`
23
+ * outright, silently ignoring the global map most i18n setups install.
24
+ *
25
+ * The head of zod's chain — the schema's own `error` option — is baked into the
26
+ * issue at build time and short-circuits this. The one link that cannot be
27
+ * reproduced is a per-CALL `ctx.error`, which would have to travel through
28
+ * `safeParse`; that entry point sits at V8's inlining budget, where even an
29
+ * unused extra parameter measured ~12% on every parse.
30
+ *
31
+ * Only ever called while building an error, never on a successful parse.
32
+ */
33
+ export declare const ZOD_MSG_DECLARATION: string;
16
34
  /**
17
35
  * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)
18
36
  * declares it once per compiled file; lean mode (all unplugin bundlers) declares
@@ -127,8 +145,26 @@ export declare const FINZ_DECL = "function __zcFinZ(z,i){return new __ZcFailZ(z,
127
145
  * partial fc can pass-through valid input but its `false` does not imply
128
146
  * rejection (a default/catch may still succeed), so it would be unsound as a
129
147
  * standalone guard.
148
+ *
149
+ * `~standard` is REPLACED, not merely preserved. Zod builds it lazily as
150
+ * `validate: (v) => safeParse(inst, v)` — the core FUNCTION, which goes straight
151
+ * to `inst._zod.run`. It never reads the schema's own `safeParse` property, so
152
+ * installing the compiled one leaves this route entirely uncompiled: measured
153
+ * 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema
154
+ * consumers (tRPC, Hono, TanStack) were getting plain Zod.
155
+ *
156
+ * Zod's own validate is captured first and kept as the throw path: it catches a
157
+ * synchronous throw and retries through `safeParseAsync`, which is how an async
158
+ * refinement resolves and how a throwing check surfaces as a rejected promise
159
+ * rather than a synchronous throw. The compiled validator cannot reproduce that
160
+ * (async schemas delegate to Zod anyway), so deferring to the original is both
161
+ * simpler and exact.
162
+ *
163
+ * Installed with defineProperty rather than assignment: Zod's lazy setter
164
+ * redefines the slot as non-writable, so a second `__zcMkv` on the same schema
165
+ * object — two exports aliasing one schema — would throw under ESM strict mode.
130
166
  */
131
- export declare const MK_VALIDATOR_DECL = "function __zcMkv(fn,schema,fc,is){var w=schema||{};w.parse=fc?function(input){if(fc(input))return input;var r=fn(input);if(r.success)return r.data;throw r.error;}:function(input){var r=fn(input);if(r.success)return r.data;throw r.error;};w.safeParse=fn;w.safeParseAsync=function(input){return Promise.resolve(fn(input));};w.parseAsync=fc?function(input){if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}:function(input){var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);};w.is=is||function(input){return fn(input).success;};return w;}";
167
+ export declare const MK_VALIDATOR_DECL: string;
132
168
  /**
133
169
  * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.
134
170
  *
@@ -1 +1 @@
1
- {"version":3,"file":"iife.d.ts","sourceRoot":"","sources":["../../src/core/iife.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,2GAC0E,CAAC;AAEzG,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,mDAAmD,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,QAMe,CAAC;AAE5C;yEACyE;AACzE,eAAO,MAAM,QAAQ,sGACgF,CAAC;AAEtG;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB,+DAA+D,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,gBAAgB,QAG4B,CAAC;AAE1D,qGAAqG;AACrG,eAAO,MAAM,SAAS,uDAAuD,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,iBAAiB,0pBAC2nB,CAAC;AAU1pB;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GAC5C,MAAM,CAuBR"}
1
+ {"version":3,"file":"iife.d.ts","sourceRoot":"","sources":["../../src/core/iife.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,2GAC0E,CAAC;AAEzG;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,mBAAmB,QAKH,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,QAMe,CAAC;AAE5C;yEACyE;AACzE,eAAO,MAAM,QAAQ,sGACgF,CAAC;AAEtG;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB,+DAA+D,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,gBAAgB,QAG4B,CAAC;AAE1D,qGAAqG;AACrG,eAAO,MAAM,SAAS,uDAAuD,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,eAAO,MAAM,iBAAiB,QAIhB,CAAC;AAUf;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GAC5C,MAAM,CAuBR"}
package/dist/core/iife.js CHANGED
@@ -10,8 +10,30 @@
10
10
  * parse raises (see ZC_SR_DECL).
11
11
  */
12
12
  export const ZOD_CONFIG_IMPORT = 'import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from "zod";';
13
- /** File-level __zcMsg declaration (must appear once after ZOD_CONFIG_IMPORT). */
14
- export const ZOD_MSG_DECLARATION = "var __zcMsg=__zodCompilerConfig().localeError;";
13
+ /**
14
+ * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):
15
+ * the message an issue gets when nothing was baked into it at build time.
16
+ *
17
+ * Resolves zod's tail of `finalizeIssue` — `config.customError` then
18
+ * `config.localeError` then "Invalid input" — and does it PER CALL, because the
19
+ * config is mutable: `z.config({ localeError })` in an entry point runs after
20
+ * the schema modules it imports, so a value snapshotted at module init misses
21
+ * it. Reading a captured `localeError` alone also dropped `customError`
22
+ * outright, silently ignoring the global map most i18n setups install.
23
+ *
24
+ * The head of zod's chain — the schema's own `error` option — is baked into the
25
+ * issue at build time and short-circuits this. The one link that cannot be
26
+ * reproduced is a per-CALL `ctx.error`, which would have to travel through
27
+ * `safeParse`; that entry point sits at V8's inlining budget, where even an
28
+ * unused extra parameter measured ~12% on every parse.
29
+ *
30
+ * Only ever called while building an error, never on a successful parse.
31
+ */
32
+ export const ZOD_MSG_DECLARATION = 'function __zcUw(m){return typeof m==="string"?m:(m===undefined||m===null?undefined:m.message);}' +
33
+ "var __zcMsg=function(iss){var c=__zodCompilerConfig(),m;" +
34
+ "if(c.customError){m=__zcUw(c.customError(iss));if(m!==undefined&&m!==null)return m;}" +
35
+ "if(c.localeError){m=__zcUw(c.localeError(iss));if(m!==undefined&&m!==null)return m;}" +
36
+ 'return "Invalid input";};';
15
37
  /**
16
38
  * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)
17
39
  * declares it once per compiled file; lean mode (all unplugin bundlers) declares
@@ -133,8 +155,29 @@ export const FINZ_DECL = "function __zcFinZ(z,i){return new __ZcFailZ(z,i);}";
133
155
  * partial fc can pass-through valid input but its `false` does not imply
134
156
  * rejection (a default/catch may still succeed), so it would be unsound as a
135
157
  * standalone guard.
158
+ *
159
+ * `~standard` is REPLACED, not merely preserved. Zod builds it lazily as
160
+ * `validate: (v) => safeParse(inst, v)` — the core FUNCTION, which goes straight
161
+ * to `inst._zod.run`. It never reads the schema's own `safeParse` property, so
162
+ * installing the compiled one leaves this route entirely uncompiled: measured
163
+ * 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema
164
+ * consumers (tRPC, Hono, TanStack) were getting plain Zod.
165
+ *
166
+ * Zod's own validate is captured first and kept as the throw path: it catches a
167
+ * synchronous throw and retries through `safeParseAsync`, which is how an async
168
+ * refinement resolves and how a throwing check surfaces as a rejected promise
169
+ * rather than a synchronous throw. The compiled validator cannot reproduce that
170
+ * (async schemas delegate to Zod anyway), so deferring to the original is both
171
+ * simpler and exact.
172
+ *
173
+ * Installed with defineProperty rather than assignment: Zod's lazy setter
174
+ * redefines the slot as non-writable, so a second `__zcMkv` on the same schema
175
+ * object — two exports aliasing one schema — would throw under ESM strict mode.
136
176
  */
137
- export const MK_VALIDATOR_DECL = "function __zcMkv(fn,schema,fc,is){var w=schema||{};w.parse=fc?function(input){if(fc(input))return input;var r=fn(input);if(r.success)return r.data;throw r.error;}:function(input){var r=fn(input);if(r.success)return r.data;throw r.error;};w.safeParse=fn;w.safeParseAsync=function(input){return Promise.resolve(fn(input));};w.parseAsync=fc?function(input){if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}:function(input){var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);};w.is=is||function(input){return fn(input).success;};return w;}";
177
+ export const MK_VALIDATOR_DECL = "function __zcMkv(fn,schema,fc,is){var w=schema||{};w.parse=fc?function(input){if(fc(input))return input;var r=fn(input);if(r.success)return r.data;throw r.error;}:function(input){var r=fn(input);if(r.success)return r.data;throw r.error;};w.safeParse=fn;w.safeParseAsync=function(input){return Promise.resolve(fn(input));};w.parseAsync=fc?function(input){if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}:function(input){var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);};w.is=is||function(input){return fn(input).success;};" +
178
+ 'var s=w["~standard"],zv=s&&s.validate;' +
179
+ 'Object.defineProperty(w,"~standard",{configurable:true,value:{version:1,vendor:(s&&s.vendor)||"zod",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zv)return zv(input);throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});' +
180
+ "return w;}";
138
181
  function extractFunctionName(functionDef) {
139
182
  const match = /^function\s+(\w+)\s*\(/.exec(functionDef);
140
183
  if (!match?.[1]) {
@@ -1 +1 @@
1
- {"version":3,"file":"iife.js","sourceRoot":"","sources":["../../src/core/iife.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAC5B,sGAAsG,CAAC;AAEzG,iFAAiF;AACjF,MAAM,CAAC,MAAM,mBAAmB,GAAG,gDAAgD,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,MAAM,eAAe,GAC1B,+FAA+F;IAC/F,qFAAqF;IACrF,4BAA4B;IAC5B,gDAAgD;IAChD,wIAAwI;IACxI,yCAAyC,CAAC;AAE5C;yEACyE;AACzE,MAAM,CAAC,MAAM,QAAQ,GACnB,mGAAmG,CAAC;AAEtG;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,4DAA4D,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B,oFAAoF;IACpF,sFAAsF;IACtF,uDAAuD,CAAC;AAE1D,qGAAqG;AACrG,MAAM,CAAC,MAAM,SAAS,GAAG,oDAAoD,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAC5B,upBAAupB,CAAC;AAE1pB,SAAS,mBAAmB,CAAC,WAAmB;IAC9C,MAAM,KAAK,GAAG,wBAAwB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACzD,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,MAA0B,EAC1B,OAA6C;IAE7C,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;IAC7C,MAAM,MAAM,GAAG,mBAAmB,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,KAAK,KAAK,CAAC;IAC/C,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC;IAClD,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,IAAI,MAAM,CAAC;IACjD,0EAA0E;IAC1E,8EAA8E;IAC9E,4EAA4E;IAC5E,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAEnF,OAAO;QACL,0BAA0B;QAC1B,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;YACvB,CAAC,CAAC,CAAC,aAAa,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,UAAU,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YACtF,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,aAAa,CAAC,IAAI;aAClB,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,oBAAoB,CAAC;QACtE,aAAa,CAAC,WAAW;QACzB,kBAAkB,MAAM,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,IAAI;QAC3D,MAAM;KACP,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"iife.js","sourceRoot":"","sources":["../../src/core/iife.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-compiler",
3
- "version": "1.22.4",
3
+ "version": "1.22.6",
4
4
  "description": "Compile Zod schemas into zero-overhead validation functions",
5
5
  "keywords": [
6
6
  "aot",