zod-aot 0.13.0 → 0.14.1

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
@@ -7,467 +7,368 @@
7
7
  [![npm](https://img.shields.io/npm/v/zod-aot)](https://www.npmjs.com/package/zod-aot)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
9
9
 
10
- No code changes required — keep your existing Zod schemas and get **2-64x faster** validation.
10
+ Keep your existing Zod schemas. Get **2-64x faster** validation. No code changes required.
11
11
 
12
- ## Why
13
-
14
- Zod v4 is already fast, but runtime schema traversal still costs ~10x compared to ahead-of-time (AOT) compiled approaches. Existing AOT solutions like [Typia](https://typia.io/) require rewriting your schemas as TypeScript types. **zod-aot** bridges this gap — it takes your existing Zod schemas and generates optimized, plain JavaScript validation functions at build time.
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
- | | Zod AOT | Typia | AJV standalone | Zod v3 | Zod v4 |
17
- |---|---------------------|---|---|---|---|
18
- | **Input** | Zod schemas | TS types | JSON Schema | Zod schemas | Zod schemas |
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
- ## Benchmarks
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
- Measured with `vitest bench` on Node.js (Apple M-series). The benchmark suite compares **Zod v3**, **Zod v4**, **zod-aot**, **[ajv](https://ajv.js.org/)**, and **[typia](https://typia.io/)** across primitives, objects, collections, unions, recursive schemas, and real-world scenarios.
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
- Run benchmarks locally:
34
+ ## Install
28
35
 
29
36
  ```bash
30
- pnpm bench
37
+ npm install zod-aot zod@^4
31
38
  ```
32
39
 
33
- ### safeParse
40
+ | Runtime | Version |
41
+ |---------|---------|
42
+ | Node.js | 20+ |
43
+ | Bun | 1.3+ |
44
+ | Deno | 2.0+ |
34
45
 
35
- | Scenario | Zod v3 | Zod v4 | **Zod AOT** | Typia | AJV | vs Zod v4 |
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
- *ops/s, higher is better. "—" = not supported by the library. Measured with `vitest bench` on Apple M-series.*
48
+ There are three ways to use zod-aot. Choose the one that fits your project.
62
49
 
63
- Performance gains scale with schema complexity. The `discriminatedUnion` optimization uses an O(1) `switch` dispatch instead of Zod's sequential trial approach. Partial fallback schemas (containing `transform`/`refine`) still show 2-6x speedups by compiling the optimizable portions. Set/Map/BigInt are only benchmarked among Zod variants as AJV and Typia lack native support for these types.
50
+ ### 1. autoDiscover (Recommended)
64
51
 
65
- ## Runtime Support
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
- | Runtime | Version | Status |
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
- ## Install
56
+ ```typescript
57
+ import zodAot from "zod-aot/vite";
74
58
 
75
- ```bash
76
- npm install zod-aot
77
- # zod v4 is a peer dependency
78
- npm install zod@^4
59
+ export default defineConfig({
60
+ plugins: [zodAot({ autoDiscover: true })],
61
+ });
79
62
  ```
80
63
 
81
- ## Quick Start
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 UserSchema = z.object({
91
- name: z.string().min(3),
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
- role: z.enum(["admin", "user"]),
73
+ age: z.number().int().min(0).max(150),
74
+ role: z.enum(["admin", "editor", "viewer"]),
95
75
  });
96
76
 
97
- // compile() falls back to Zod in dev, uses generated functions after build
98
- export const validateUser = compile(UserSchema);
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
- ### 2. Use the compiled validator
88
+ **Use them as usual:**
102
89
 
103
90
  ```typescript
104
- // Same interface as Zod works in both dev and production
105
- const user = validateUser.parse(data); // throws on failure
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
- ### 3. Generate optimized code
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
- Choose one of these approaches:
103
+ ### 2. compile() (Explicit)
112
104
 
113
- **Option A: Build plugin (Vite / webpack / esbuild / Rollup / Rolldown / rspack)**
105
+ If you prefer explicit opt-in, wrap specific schemas with `compile()`:
114
106
 
115
107
  ```typescript
116
- // vite.config.ts
117
- import zodAot from "zod-aot/vite";
108
+ import { z } from "zod";
109
+ import { compile } from "zod-aot";
118
110
 
119
- export default defineConfig({
120
- plugins: [zodAot()],
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
- Also available: `zod-aot/webpack`, `zod-aot/esbuild`, `zod-aot/rollup`, `zod-aot/rolldown`, `zod-aot/rspack`, `zod-aot/bun`
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
- **Option B: CLI**
128
+ Generate optimized validation files from the command line:
127
129
 
128
130
  ```bash
129
- # Generate optimized validators
131
+ # Single file
130
132
  npx zod-aot generate src/schemas.ts -o src/schemas.compiled.ts
131
133
 
132
- # Generate from a directory
134
+ # Directory
133
135
  npx zod-aot generate src/ -o src/compiled/
134
136
 
135
- # Watch mode — regenerate on file changes
137
+ # Watch mode
136
138
  npx zod-aot generate src/ --watch
139
+ ```
137
140
 
138
- # Diagnose schemas — tree view, coverage, Fast Path, hints
139
- npx zod-aot check src/schemas.ts
141
+ ## Build Plugin
140
142
 
141
- # JSON output for CI integration
142
- npx zod-aot check src/schemas.ts --json
143
+ ### Supported Build Tools
143
144
 
144
- # Fail CI if coverage < 80%
145
- npx zod-aot check src/schemas.ts --json --fail-under 80
146
- ```
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"` |
147
154
 
148
- ## Build Plugin (unplugin)
155
+ ### Options
149
156
 
150
- The build plugin automatically replaces `compile()` calls with optimized inline validators during the build step. No code changes needed — your source files stay the same.
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 |
151
164
 
152
165
  ```typescript
153
- // vite.config.ts
154
- import zodAot from "zod-aot/vite";
155
- export default defineConfig({ plugins: [zodAot()] });
156
-
157
- // webpack.config.js
158
- const zodAot = require("zod-aot/webpack");
159
- module.exports = { plugins: [zodAot()] };
166
+ zodAot({
167
+ autoDiscover: true,
168
+ include: ["src/schemas"],
169
+ verbose: true,
170
+ })
160
171
  ```
161
172
 
162
- ### Options
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:
163
178
 
164
179
  ```typescript
165
180
  zodAot({
166
- include: ["src/schemas"], // only process files matching these substrings
167
- exclude: ["test", "mock"], // skip files matching these substrings
168
- verbose: true, // log per-schema compilation status and build summary
181
+ autoDiscover: true,
182
+ include: ["src/schemas", "src/validators"],
169
183
  })
170
184
  ```
171
185
 
172
- The plugin:
173
- - Runs at build time (`enforce: "pre"`)
174
- - Replaces `compile(Schema)` with optimized IIFE inline validators
175
- - Adds `/* @__PURE__ */` annotations for tree-shaking
176
- - Supports HMR in development
186
+ ### autoDiscover vs compile()
177
187
 
178
- ## Zod Ecosystem Compatibility
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 |
179
195
 
180
- `compile()` returns a full Zod schema (`T & CompiledSchema<T>`) — it preserves all original Zod methods and only replaces validation methods (`safeParse`, `parse`, etc.) with AOT-optimized versions. This means compiled schemas work with any library that accepts Zod schemas.
196
+ ## Framework Examples
181
197
 
182
- ### Hono
198
+ ### tRPC
183
199
 
184
200
  ```typescript
185
- import { Hono } from "hono";
186
- import { zValidator } from "@hono/zod-validator";
201
+ // src/schemas.ts
187
202
  import { z } from "zod";
188
- import { compile } from "zod-aot";
189
203
 
190
- const UserSchema = z.object({
191
- name: z.string().min(3),
192
- age: z.number().int().positive(),
204
+ export const CreateUserSchema = z.object({
205
+ name: z.string().min(1).max(100),
193
206
  email: z.email(),
207
+ age: z.number().int().min(0).max(150),
208
+ });
209
+
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)),
194
217
  });
218
+ ```
195
219
 
196
- // Still a Zod schema but safeParse is AOT-optimized
197
- const validateUser = compile(UserSchema);
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";
198
228
 
199
229
  const app = new Hono();
200
230
 
201
- app.post("/users", zValidator("json", validateUser), (c) => {
231
+ app.post("/users", zValidator("json", UserSchema), (c) => {
202
232
  const user = c.req.valid("json");
203
233
  return c.json(user);
204
234
  });
205
235
  ```
206
236
 
207
- `@hono/zod-validator` internally calls `schema.safeParse()` — with zod-aot, this call is replaced by the generated optimized validator at build time, giving you faster request validation with zero code changes.
208
-
209
- ## Schema Diagnostics (`check`)
210
-
211
- The `check` command analyzes schemas for compilation coverage, Fast Path eligibility, and actionable hints — without generating code.
237
+ ### React Hook Form
212
238
 
213
- ```bash
214
- npx zod-aot check src/schemas.ts
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
+ }
215
250
  ```
216
251
 
217
- **Output includes:**
218
-
219
- - **Tree view** — hierarchical visualization of schema structure with compile/fallback status per node
220
- - **Coverage** — percentage of schema nodes that are compiled (e.g. `85% compiled (17/20 nodes)`)
221
- - **Fast Path eligibility** — whether the schema qualifies for two-phase validation, with the specific blocker if ineligible
222
- - **Hints** — actionable suggestions (e.g. "Replace `.refine()` with built-in checks")
252
+ ### Any Standard Schema Consumer
223
253
 
224
- ### Options
254
+ zod-aot compiled schemas implement [Standard Schema](https://standardschema.dev) via prototype chain. Any library that accepts Standard Schema validators works automatically.
225
255
 
226
- | Flag | Description |
227
- |---|---|
228
- | `--json` | Output structured JSON (for CI/CD integration) |
229
- | `--fail-under <pct>` | Exit with code 1 if any schema's coverage is below the threshold |
230
- | `--no-color` | Disable colored output |
256
+ ## Schema Diagnostics
231
257
 
232
- ### JSON output
258
+ Analyze your schemas before compiling — check coverage, Fast Path eligibility, and get actionable hints:
233
259
 
234
260
  ```bash
235
- npx zod-aot check src/schemas.ts --json
236
- ```
237
-
238
- ```json
239
- [
240
- {
241
- "file": "src/schemas.ts",
242
- "schemas": [
243
- {
244
- "exportName": "validateUser",
245
- "coverage": { "total": 5, "compilable": 5, "percent": 100 },
246
- "fastPath": { "eligible": true },
247
- "fallbacks": []
248
- }
249
- ]
250
- }
251
- ]
261
+ npx zod-aot check src/schemas.ts
252
262
  ```
253
263
 
254
- ### CI gate
264
+ Output:
255
265
 
256
- ```bash
257
- npx zod-aot check src/schemas.ts --json --fail-under 80
258
266
  ```
267
+ src/schemas.ts
259
268
 
260
- Exits with code 1 if any schema's compilation coverage drops below 80%.
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
261
274
 
262
- ## How It Works
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
263
280
 
281
+ Summary: 2 schemas | 1 Fast Path, 1 Slow Path | 8/9 nodes (88.9%)
264
282
  ```
265
- Zod Schema
266
-
267
-
268
- ┌─────────────────────┐
269
- │ Extractor │ Traverse _zod.def recursively
270
- │ extractSchema() │ → produce JSON-serializable IR
271
- └─────────┬───────────┘
272
- │ SchemaIR
273
-
274
- ┌─────────────────────┐
275
- │ CodeGen │ IR → optimized JS with:
276
- │ generateValidator()│ • inline type checks
277
- └─────────┬───────────┘ • pre-compiled RegExps
278
- │ • Set-based enum lookups
279
- ▼ • early returns
280
- Optimized JS function
281
- (no runtime dependencies)
282
- ```
283
-
284
- ### Why Runtime Extraction (not static analysis)
285
-
286
- - Zod v4's `_zod.def` is JSON-serializable — perfect for IR extraction
287
- - Static AST analysis cannot handle dynamic schemas (variable references, function calls, spread operators)
288
- - `_zod.bag` contains aggregated metadata from checks (minimum, maximum, regex patterns, etc.)
289
- - Reliable detection of `transform`/`refine` for automatic fallback
290
-
291
- ### Generated Code Example
292
283
 
293
- **Input:**
284
+ ### CI Integration
294
285
 
295
- ```typescript
296
- z.object({
297
- name: z.string().min(3).max(50),
298
- role: z.enum(["admin", "user"]),
299
- })
300
- ```
286
+ ```bash
287
+ # JSON output
288
+ npx zod-aot check src/schemas.ts --json
301
289
 
302
- **Output:**
303
-
304
- ```javascript
305
- /* zod-aot */
306
- var __set_0 = new Set(["admin", "user"]);
307
-
308
- function safeParse_validate(input) {
309
- var __issues = [];
310
- if (typeof input !== "object" || input === null || Array.isArray(input)) {
311
- __issues.push({ code: "invalid_type", expected: "object", path: [] });
312
- } else {
313
- // name: string().min(3).max(50)
314
- if (typeof input["name"] !== "string") {
315
- __issues.push({ code: "invalid_type", expected: "string", path: ["name"] });
316
- } else {
317
- if (input["name"].length < 3)
318
- __issues.push({ code: "too_small", minimum: 3, path: ["name"] });
319
- if (input["name"].length > 50)
320
- __issues.push({ code: "too_big", maximum: 50, path: ["name"] });
321
- }
322
-
323
- // role: enum(["admin", "user"])
324
- if (!__set_0.has(input["role"])) {
325
- __issues.push({ code: "invalid_enum_value", path: ["role"] });
326
- }
327
- }
328
- if (__issues.length > 0) return { success: false, error: { issues: __issues } };
329
- return { success: true, data: input };
330
- }
290
+ # Fail if any schema below 80% coverage
291
+ npx zod-aot check src/schemas.ts --json --fail-under 80
331
292
  ```
332
293
 
333
- Key optimizations in the generated code:
334
-
335
- - **No schema traversal** all validation logic is inlined
336
- - **Pre-compiled RegExps** regex patterns are compiled once, reused across calls
337
- - **Set-based enum lookups** O(1) membership tests instead of array iteration
338
- - **Early type checks** — nested checks only run if the type is correct
339
- - **Minimal allocations** — issues array is only created once per call
340
-
341
- ## API Reference
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 |
342
299
 
343
- ### `compile<T>(zodSchema): CompiledSchema<T>`
300
+ ## What Gets Compiled
344
301
 
345
- Wraps a Zod schema for AOT compilation. In development, it falls back to Zod's built-in validation. After build (via CLI or unplugin), it uses the generated optimized validator.
302
+ ### Fully Compiled (3-64x faster)
346
303
 
347
- ```typescript
348
- import { z } from "zod";
349
- import { compile } from "zod-aot";
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)
350
305
 
351
- const validateUser = compile(z.object({
352
- name: z.string().min(3),
353
- age: z.number().int().positive(),
354
- }));
355
- ```
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.
356
307
 
357
- ### `CompiledSchema<T>`
308
+ ### Falls Back to Zod (Still Works, Not Faster)
358
309
 
359
- The interface returned by `compile()`:
310
+ These types contain JavaScript closures that cannot be compiled to static code:
360
311
 
361
- ```typescript
362
- interface CompiledSchema<T> {
363
- parse(input: unknown): T; // throws on failure
364
- safeParse(input: unknown): SafeParseResult<T>; // { success, data/error }
365
- schema: unknown; // reference to original Zod schema
366
- }
367
- ```
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 |
368
319
 
369
- ## Supported Types
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.
370
321
 
371
- | Type | Supported Checks |
372
- |---|---|
373
- | `string` | `min`, `max`, `length`, `email`, `url`, `uuid`, `regex`, `includes`, `startsWith`, `endsWith` |
374
- | `number` | `int`, `positive`, `negative`, `nonnegative`, `nonpositive`, `min`, `max`, `multipleOf`, `int32`, `uint32`, `float32`, `float64` |
375
- | `bigint` | `min`, `max`, `positive`, `negative`, `nonnegative`, `nonpositive`, `multipleOf` |
376
- | `boolean` | — |
377
- | `null` | — |
378
- | `undefined` | — |
379
- | `any` | — (always passes) |
380
- | `unknown` | — (always passes) |
381
- | `literal` | single value, multi-value |
382
- | `enum` | string enum values |
383
- | `date` | `min`, `max` (timestamp comparison) |
384
- | `object` | nested objects, mixed property types |
385
- | `array` | `min`, `max`, `length`, element validation |
386
- | `tuple` | per-element types, optional rest element |
387
- | `record` | key and value type validation |
388
- | `set` | `min`, `max` (size), element validation |
389
- | `map` | key and value type validation |
390
- | `union` | sequential trial of all options |
391
- | `discriminatedUnion` | O(1) `switch` dispatch on discriminator field |
392
- | `intersection` | validates both left and right schemas |
393
- | `pipe` (non-transform) | sequential in→out validation |
394
- | `optional` | wraps any supported type |
395
- | `nullable` | wraps any supported type |
396
- | `readonly` | validates inner type (TS-only concept) |
397
- | `default` | replaces `undefined` with default value, then validates inner |
398
- | `symbol` | — (typeof check) |
399
- | `void` | — (accepts `undefined`) |
400
- | `nan` | — (Number.isNaN check) |
401
- | `never` | — (always fails) |
402
- | `lazy` (self-recursive) | cycle detection → self-recursive codegen |
403
-
404
- ### Automatic Fallback to Zod
405
-
406
- 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`:
407
-
408
- - `transform` — runtime data transformation
409
- - `refine` / `superRefine` — custom validation with closures
410
- - `custom` — arbitrary validation logic
411
- - `preprocess` — input preprocessing
412
- - `lazy` (non-recursive) — deferred schema resolution where inner type cannot be resolved
413
-
414
- #### Partial Fallback
415
-
416
- 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.
417
-
418
- > **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.
419
-
420
- ## Development
322
+ **Tip:** Run `npx zod-aot check` to see exactly which parts of your schemas are compiled and which fall back.
421
323
 
422
- ```bash
423
- # Install dependencies
424
- pnpm install
324
+ ## Benchmarks
425
325
 
426
- # Run tests
427
- pnpm test
326
+ 5-way comparison: **Zod v3** vs **Zod v4** vs **Zod AOT** vs **[Typia](https://typia.io/)** vs **[AJV](https://ajv.js.org/)**
428
327
 
429
- # Run benchmarks (zod v3 vs zod v4 vs zod-aot vs ajv vs typia)
430
- pnpm bench
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 |
431
353
 
432
- # Lint (Biome)
433
- pnpm lint
354
+ *ops/s, higher is better. "—" = not supported by the library. Measured with `vitest bench` on Apple M-series.*
434
355
 
435
- # Type check
436
- pnpm -r typecheck
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.
437
357
 
438
- # Build
439
- pnpm -r build
358
+ ```bash
359
+ pnpm bench # run locally
440
360
  ```
441
361
 
442
- ### Project Structure
362
+ ### Performance Architecture
443
363
 
444
- ```
445
- zod-aot/
446
- ├── packages/zod-aot/ # Main npm package
447
- │ ├── src/
448
- │ │ ├── index.ts # Public API exports (zod-aot)
449
- │ │ ├── discovery.ts # Schema discovery (shared by CLI & unplugin)
450
- │ │ ├── loader.ts # Runtime-aware file loader
451
- │ │ ├── core/ # Pure logic (no CLI/unplugin deps)
452
- │ │ │ ├── types.ts # SchemaIR, CompiledSchema, CheckIR
453
- │ │ │ ├── compile.ts # compile() marker + isCompiledSchema()
454
- │ │ │ ├── runtime.ts # createFallback (dev-time)
455
- │ │ │ ├── extract/ # _zod.def → SchemaIR (extractors per type)
456
- │ │ │ └── codegen/ # SchemaIR → optimized JS
457
- │ │ ├── cli/ # CLI commands (generate, check, watch)
458
- │ │ └── unplugin/ # Build plugin (Vite/webpack/esbuild/Rollup/Rolldown/rspack/Bun)
459
- │ └── tests/
460
- ├── benchmarks/ # vitest bench (zod v3 vs v4 vs zod-aot vs ajv vs typia)
461
- └── .github/workflows/ # CI + release automation
462
- ```
364
+ For eligible schemas, zod-aot generates a **two-phase validator**:
463
365
 
464
- ## Contributing
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.
465
368
 
466
- Contributions are welcome! Please ensure your changes pass all checks before submitting a PR:
369
+ Additional optimizations: check ordering (cheap checks first), pre-compiled regex, Set-based enum lookups, small enum inlining (`===` for 1-3 values).
467
370
 
468
- ```bash
469
- pnpm lint && pnpm -r typecheck && pnpm test
470
- ```
371
+ Run `npx zod-aot check --json` to see which schemas qualify for Fast Path.
471
372
 
472
373
  ## License
473
374
 
@@ -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;AAUxD,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,sDAAoD,CAAC;AAEnF,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,4CAA4C,CAAC;AAE7E;;;;;;;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,CAyBR"}
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,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,sDAAoD,CAAC;AAEnF,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,4CAA4C,CAAC;AAU7E;;;;;;;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,CAyBR"}
package/dist/core/iife.js CHANGED
@@ -2,6 +2,10 @@
2
2
  * Shared CompiledSchema<T> IIFE generation.
3
3
  * Used by both CLI emitter and unplugin transform.
4
4
  */
5
+ /** Import statement required by generateIIFE output (references __zodAotConfig). */
6
+ export const ZOD_CONFIG_IMPORT = 'import { config as __zodAotConfig } from "zod";';
7
+ /** File-level __msg declaration (must appear once after ZOD_CONFIG_IMPORT). */
8
+ export const ZOD_MSG_DECLARATION = "var __msg=__zodAotConfig().localeError;";
5
9
  function extractFunctionName(functionDef) {
6
10
  const match = /^function\s+(\w+)\s*\(/.exec(functionDef);
7
11
  if (!match?.[1]) {
@@ -9,10 +13,6 @@ function extractFunctionName(functionDef) {
9
13
  }
10
14
  return match[1];
11
15
  }
12
- /** Import statement required by generateIIFE output (references __zodAotConfig). */
13
- export const ZOD_CONFIG_IMPORT = 'import { config as __zodAotConfig } from "zod";';
14
- /** File-level __msg declaration (must appear once after ZOD_CONFIG_IMPORT). */
15
- export const ZOD_MSG_DECLARATION = "var __msg=__zodAotConfig().localeError;";
16
16
  /**
17
17
  * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.
18
18
  *
@@ -1 +1 @@
1
- {"version":3,"file":"iife.js","sourceRoot":"","sources":["../../src/core/iife.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,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,oFAAoF;AACpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,iDAAiD,CAAC;AAEnF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,yCAAyC,CAAC;AAE7E;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,MAA0B,EAC1B,OAA6C;IAE7C,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC;IAClD,MAAM,MAAM,GAAG,mBAAmB,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,KAAK,KAAK,CAAC;IAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,UAAU,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAE/D,OAAO;QACL,0BAA0B;QAC1B,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC;YAC5B,CAAC,CAAC,CAAC,aAAa,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,UAAU,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAC3F,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,eAAe,CAAC;QACjE,GAAG,CAAC,aAAa,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAC3C,aAAa,CAAC,WAAW;QACzB,WAAW,IAAI,GAAG;QAClB,qCAAqC,MAAM,mGAAmG;QAC9I,iBAAiB,MAAM,GAAG;QAC1B,6DAA6D,MAAM,aAAa;QAChF,0CAA0C,MAAM,qIAAqI;QACrL,cAAc,UAAU,GAAG;QAC3B,aAAa;QACb,MAAM;KACP,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"iife.js","sourceRoot":"","sources":["../../src/core/iife.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,oFAAoF;AACpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,iDAAiD,CAAC;AAEnF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,yCAAyC,CAAC;AAE7E,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,eAAe,EAAE,GAAG,MAAM,CAAC;IAClD,MAAM,MAAM,GAAG,mBAAmB,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,KAAK,KAAK,CAAC;IAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,UAAU,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAE/D,OAAO;QACL,0BAA0B;QAC1B,GAAG,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC;YAC5B,CAAC,CAAC,CAAC,aAAa,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,UAAU,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAC3F,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,eAAe,CAAC;QACjE,GAAG,CAAC,aAAa,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAC3C,aAAa,CAAC,WAAW;QACzB,WAAW,IAAI,GAAG;QAClB,qCAAqC,MAAM,mGAAmG;QAC9I,iBAAiB,MAAM,GAAG;QAC1B,6DAA6D,MAAM,aAAa;QAChF,0CAA0C,MAAM,qIAAqI;QACrL,cAAc,UAAU,GAAG;QAC3B,aAAa;QACb,MAAM;KACP,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -1,8 +1,15 @@
1
1
  import type { DiscoveredSchema } from "#src/core/types.js";
2
2
  import type { LoadOptions } from "./loader.js";
3
+ export interface DiscoverOptions extends LoadOptions {
4
+ /** Auto-detect all exported Zod schemas without requiring compile() wrappers. */
5
+ autoDiscover?: boolean;
6
+ }
3
7
  /**
4
- * Discover all compile() calls in a source file by importing it and
5
- * scanning exports for CompiledSchema objects.
8
+ * Discover schemas in a source file by importing it and scanning exports.
9
+ *
10
+ * - Default mode: finds compile() calls via CompiledSchema marker.
11
+ * - autoDiscover mode: also finds plain Zod schema exports via _zod.def detection.
12
+ * compile() schemas take priority (isCompiledSchema checked first).
6
13
  */
7
- export declare function discoverSchemas(filePath: string, options?: LoadOptions): Promise<DiscoveredSchema[]>;
14
+ export declare function discoverSchemas(filePath: string, options?: DiscoverOptions): Promise<DiscoveredSchema[]>;
8
15
  //# sourceMappingURL=discovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C;;;GAGG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAoB7B"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,iFAAiF;IACjF,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAYD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAsB7B"}
package/dist/discovery.js CHANGED
@@ -1,8 +1,21 @@
1
1
  import { isCompiledSchema } from "#src/core/compile.js";
2
2
  import { loadSourceFile } from "./loader.js";
3
3
  /**
4
- * Discover all compile() calls in a source file by importing it and
5
- * scanning exports for CompiledSchema objects.
4
+ * Check if a value is a Zod schema by detecting the _zod.def structure.
5
+ * Used by autoDiscover to find plain Zod exports.
6
+ */
7
+ function isZodSchema(value) {
8
+ if (typeof value !== "object" || value === null || !("_zod" in value))
9
+ return false;
10
+ const zod = value["_zod"];
11
+ return typeof zod === "object" && zod !== null && "def" in zod;
12
+ }
13
+ /**
14
+ * Discover schemas in a source file by importing it and scanning exports.
15
+ *
16
+ * - Default mode: finds compile() calls via CompiledSchema marker.
17
+ * - autoDiscover mode: also finds plain Zod schema exports via _zod.def detection.
18
+ * compile() schemas take priority (isCompiledSchema checked first).
6
19
  */
7
20
  export async function discoverSchemas(filePath, options) {
8
21
  const mod = await loadSourceFile(filePath, options);
@@ -18,6 +31,9 @@ export async function discoverSchemas(filePath, options) {
18
31
  if (isCompiledSchema(value)) {
19
32
  schemas.push({ exportName, schema: value.schema });
20
33
  }
34
+ else if (options?.autoDiscover && isZodSchema(value)) {
35
+ schemas.push({ exportName, schema: value });
36
+ }
21
37
  }
22
38
  return schemas;
23
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,OAAqB;IAErB,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,OAAO,GAA4B,EAAE,GAAG,GAAG,EAAE,CAAC;IACpD,MAAM,aAAa,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IACrC,IACE,aAAa,IAAI,IAAI;QACrB,OAAO,aAAa,KAAK,QAAQ;QACjC,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAChC,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,aAAwC,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1D,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAO7C;;;GAGG;AACH,SAAS,WAAW,CAAC,KAAc;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpF,MAAM,GAAG,GAAI,KAAiC,CAAC,MAAM,CAAC,CAAC;IACvD,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,OAAyB;IAEzB,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,MAAM,OAAO,GAA4B,EAAE,GAAG,GAAG,EAAE,CAAC;IACpD,MAAM,aAAa,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IACrC,IACE,aAAa,IAAI,IAAI;QACrB,OAAO,aAAa,KAAK,QAAQ;QACjC,CAAC,gBAAgB,CAAC,aAAa,CAAC,EAChC,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,aAAwC,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1D,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,OAAO,EAAE,YAAY,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/unplugin/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,eAAO,MAAM,QAAQ,+EAyCnB,CAAC;AAEH,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/unplugin/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,eAAO,MAAM,QAAQ,+EA0CnB,CAAC;AAEH,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
@@ -13,6 +13,7 @@ export const unplugin = createUnplugin((options) => {
13
13
  const result = await transformCode(code, id, {
14
14
  zodCompat: options?.zodCompat,
15
15
  verbose,
16
+ autoDiscover: options?.autoDiscover,
16
17
  onBuildStats(s) {
17
18
  stats.files += s.files;
18
19
  stats.schemas += s.schemas;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/unplugin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGrE,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,OAA6B,EAAE,EAAE;IACvE,MAAM,KAAK,GAAe,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAE1C,OAAO;QACL,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAc;QAEvB,gBAAgB,CAAC,EAAU;YACzB,OAAO,eAAe,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,EAAU;YACtC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE;gBAC3C,SAAS,EAAE,OAAO,EAAE,SAAS;gBAC7B,OAAO;gBACP,YAAY,CAAC,CAAC;oBACZ,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;oBACvB,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC;oBAC3B,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC;oBAC/B,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;gBAC3B,CAAC;aACF,CAAC,CAAC;YACH,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACrC,CAAC;QAED,QAAQ;YACN,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC;gBAAE,OAAO;YAChC,GAAG,CACD,kBAAkB,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,6BAA6B,KAAK,CAAC,KAAK,UAAU;gBAClG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CACvD,CAAC;YACF,6BAA6B;YAC7B,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;YAChB,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;YAClB,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;YACpB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/unplugin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGrE,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,OAA6B,EAAE,EAAE;IACvE,MAAM,KAAK,GAAe,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAE1C,OAAO;QACL,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAc;QAEvB,gBAAgB,CAAC,EAAU;YACzB,OAAO,eAAe,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,EAAU;YACtC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,EAAE,EAAE;gBAC3C,SAAS,EAAE,OAAO,EAAE,SAAS;gBAC7B,OAAO;gBACP,YAAY,EAAE,OAAO,EAAE,YAAY;gBACnC,YAAY,CAAC,CAAC;oBACZ,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;oBACvB,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC;oBAC3B,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC;oBAC/B,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;gBAC3B,CAAC;aACF,CAAC,CAAC;YACH,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACrC,CAAC;QAED,QAAQ;YACN,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC;gBAAE,OAAO;YAChC,GAAG,CACD,kBAAkB,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,6BAA6B,KAAK,CAAC,KAAK,UAAU;gBAClG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CACvD,CAAC;YACF,6BAA6B;YAC7B,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;YAChB,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;YAClB,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;YACpB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -13,6 +13,7 @@ export interface BuildStats {
13
13
  interface TransformOptions {
14
14
  zodCompat?: boolean | undefined;
15
15
  verbose?: boolean | undefined;
16
+ autoDiscover?: boolean | undefined;
16
17
  onBuildStats?: (stats: BuildStats) => void;
17
18
  }
18
19
  export declare function log(msg: string): void;
@@ -27,6 +28,18 @@ export declare function transformCode(code: string, id: string, options?: Transf
27
28
  export declare function rewriteSource(code: string, schemas: CompiledSchemaInfo[], options?: {
28
29
  zodCompat?: boolean | undefined;
29
30
  }): string;
31
+ /**
32
+ * Find the end position of a JavaScript expression starting at `start` using acorn.
33
+ * Returns the end offset, or -1 if the expression cannot be parsed.
34
+ */
35
+ export declare function findExpressionEnd(code: string, start: number): number;
36
+ /**
37
+ * Rewrite source code by replacing plain Zod schema exports with IIFE-wrapped optimized validators.
38
+ * Used by autoDiscover mode (no compile() wrappers needed).
39
+ */
40
+ export declare function rewriteSourceAutoDiscover(code: string, schemas: CompiledSchemaInfo[], options?: {
41
+ zodCompat?: boolean | undefined;
42
+ }): string;
30
43
  /**
31
44
  * Remove the `compile` binding from `import { compile, ... } from "zod-aot"` statements.
32
45
  * If `compile` is the only import, the entire import line is removed.
@@ -1 +1 @@
1
- {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/unplugin/transform.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,kBAAkB,EAAkB,MAAM,uBAAuB,CAAC;AAGhF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAUlF;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAgB;IACxB,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAC5C;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGrC;AAOD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiDxB;AAmBD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GAC5C,MAAM,CA+BR;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAaxD"}
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../src/unplugin/transform.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,kBAAkB,EAAkB,MAAM,uBAAuB,CAAC;AAGhF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAKtD;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAUlF;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,gBAAgB;IACxB,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAC5C;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAGrC;AAOD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiGxB;AA6BD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GAC5C,MAAM,CA2BR;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAUrE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,kBAAkB,EAAE,EAC7B,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GAC5C,MAAM,CAuBR;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAaxD"}
@@ -1,6 +1,9 @@
1
+ import { parseExpressionAt } from "acorn";
1
2
  import { generateIIFE, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION } from "#src/core/iife.js";
2
3
  import { compileSchemas } from "#src/core/pipeline.js";
3
4
  import { discoverSchemas } from "#src/discovery.js";
5
+ /** Matches a runtime (non-type-only) import from "zod". */
6
+ const HAS_RUNTIME_ZOD_IMPORT = /import\s+(?!type\s)[^;]*from\s+["']zod["']/;
4
7
  /**
5
8
  * Check if a file should be transformed by the plugin.
6
9
  */
@@ -33,16 +36,34 @@ function warn(msg) {
33
36
  */
34
37
  export async function transformCode(code, id, options) {
35
38
  const verbose = options?.verbose === true;
36
- // Quick check: source must reference both "zod-aot" and "compile"
37
- if (!code.includes("zod-aot") || !code.includes("compile"))
38
- return null;
39
- // Discover compiled schemas by executing the file (with cache busting for HMR)
39
+ const autoDiscover = options?.autoDiscover === true;
40
+ // Quick bail-out check
41
+ if (autoDiscover) {
42
+ // autoDiscover: any file with a runtime Zod import is a candidate.
43
+ // Skip `import type` — these files have no runtime schemas.
44
+ if (!HAS_RUNTIME_ZOD_IMPORT.test(code))
45
+ return null;
46
+ }
47
+ else {
48
+ // Legacy mode: require compile() from zod-aot
49
+ if (!code.includes("zod-aot") || !code.includes("compile"))
50
+ return null;
51
+ }
52
+ // Discover schemas by executing the file (with cache busting for HMR)
40
53
  let schemas;
41
54
  try {
42
- schemas = await discoverSchemas(id, { cacheBust: true });
55
+ schemas = await discoverSchemas(id, { cacheBust: true, autoDiscover });
43
56
  }
44
57
  catch (e) {
45
58
  const msg = e instanceof Error ? e.message : String(e);
59
+ // In autoDiscover mode, files that can't be loaded (JSX components,
60
+ // unresolved path aliases, etc.) are expected — warn and skip.
61
+ if (autoDiscover) {
62
+ if (verbose) {
63
+ warn(`Skipping ${id}: ${msg}`);
64
+ }
65
+ return null;
66
+ }
46
67
  throw new Error(`[zod-aot] Failed to load schemas from ${id}: ${msg}`);
47
68
  }
48
69
  if (schemas.length === 0)
@@ -52,17 +73,20 @@ export async function transformCode(code, id, options) {
52
73
  const compiled = compileSchemas(schemas, {
53
74
  onError(exportName, error) {
54
75
  failedCount++;
55
- warn(`Failed to compile "${exportName}" in ${id}: ${error.message}. Keeping original compile() call.`);
76
+ warn(`Failed to compile "${exportName}" in ${id}: ${error.message}. Keeping original${autoDiscover ? "" : " compile()"} call.`);
56
77
  },
57
78
  });
58
79
  if (verbose) {
80
+ if (autoDiscover) {
81
+ log(`Auto-discovering: ${id} (${schemas.length} Zod export${schemas.length > 1 ? "s" : ""} found)`);
82
+ }
59
83
  for (const s of compiled) {
60
84
  const fbCount = s.fallbackEntries.length;
61
85
  const fbSuffix = fbCount > 0 ? ` (${fbCount} fallback${fbCount > 1 ? "s" : ""})` : "";
62
86
  log(` ✓ ${s.exportName}${fbSuffix}`);
63
87
  }
64
88
  if (failedCount > 0) {
65
- log(` ✗ ${failedCount} schema(s) failed — kept original compile() calls`);
89
+ log(` ✗ ${failedCount} schema(s) failed`);
66
90
  }
67
91
  }
68
92
  if (compiled.length === 0)
@@ -74,7 +98,43 @@ export async function transformCode(code, id, options) {
74
98
  optimized: compiled.length,
75
99
  failed: failedCount,
76
100
  });
77
- return rewriteSource(code, compiled, { zodCompat: options?.zodCompat });
101
+ // Two-pass rewrite: separate compile() schemas from autoDiscover schemas
102
+ if (autoDiscover) {
103
+ // Detect compile() schemas by checking source code patterns
104
+ const compileExportNames = new Set();
105
+ for (const s of compiled) {
106
+ const pattern = new RegExp(`\\b${s.exportName}\\s*=\\s*compile[\\s<(]`);
107
+ if (pattern.test(code)) {
108
+ compileExportNames.add(s.exportName);
109
+ }
110
+ }
111
+ const compileSchemaInfos = compiled.filter((s) => compileExportNames.has(s.exportName));
112
+ const autoDiscoverSchemaInfos = compiled.filter((s) => !compileExportNames.has(s.exportName));
113
+ let result = code;
114
+ // Pass 1: rewrite compile() schemas with existing function
115
+ if (compileSchemaInfos.length > 0) {
116
+ result = rewriteSource(result, compileSchemaInfos, { zodCompat: options?.zodCompat });
117
+ }
118
+ // Pass 2: rewrite autoDiscover schemas with new function
119
+ if (autoDiscoverSchemaInfos.length > 0) {
120
+ result = rewriteSourceAutoDiscover(result, autoDiscoverSchemaInfos, {
121
+ zodCompat: options?.zodCompat,
122
+ });
123
+ }
124
+ return injectZodConfigImport(result);
125
+ }
126
+ return injectZodConfigImport(rewriteSource(code, compiled, { zodCompat: options?.zodCompat }));
127
+ }
128
+ /**
129
+ * Add zod config import for __msg (localeError) if needed.
130
+ * Called once after all rewrite passes to avoid duplicate imports.
131
+ */
132
+ function injectZodConfigImport(code) {
133
+ if (!code.includes("__msg"))
134
+ return code;
135
+ if (code.includes("__zodAotConfig"))
136
+ return code;
137
+ return [ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, code].join("\n");
78
138
  }
79
139
  /**
80
140
  * Find the matching closing parenthesis for a compile() call,
@@ -119,11 +179,47 @@ export function rewriteSource(code, schemas, options) {
119
179
  const replacement = prefix + generateIIFE(schemaArgName, schema, options);
120
180
  result = result.replace(fullMatch, replacement);
121
181
  }
122
- result = removeCompileImport(result);
123
- // Add zod config import for __msg (localeError) used in IIFEs
124
- if (!result.includes("__msg"))
125
- return result;
126
- return [ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, result].join("\n");
182
+ return removeCompileImport(result);
183
+ }
184
+ /**
185
+ * Find the end position of a JavaScript expression starting at `start` using acorn.
186
+ * Returns the end offset, or -1 if the expression cannot be parsed.
187
+ */
188
+ export function findExpressionEnd(code, start) {
189
+ try {
190
+ const node = parseExpressionAt(code, start, {
191
+ ecmaVersion: "latest",
192
+ sourceType: "module",
193
+ });
194
+ return node.end;
195
+ }
196
+ catch {
197
+ return -1;
198
+ }
199
+ }
200
+ /**
201
+ * Rewrite source code by replacing plain Zod schema exports with IIFE-wrapped optimized validators.
202
+ * Used by autoDiscover mode (no compile() wrappers needed).
203
+ */
204
+ export function rewriteSourceAutoDiscover(code, schemas, options) {
205
+ let result = code;
206
+ for (const schema of schemas) {
207
+ const escapedName = schema.exportName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
208
+ // Match: export? (const|let|var) ExportName[: TypeAnnotation] = <expr>
209
+ const assignPattern = new RegExp(`((?:export\\s+)?(?:const|let|var)\\s+${escapedName}(?:\\s*:[^=]*)?\\s*=\\s*)`);
210
+ const match = assignPattern.exec(result);
211
+ if (!match)
212
+ continue;
213
+ const rhsStart = match.index + match[0].length;
214
+ const rhsEnd = findExpressionEnd(result, rhsStart);
215
+ if (rhsEnd === -1)
216
+ continue;
217
+ const originalExpr = result.slice(rhsStart, rhsEnd).trim();
218
+ const prefix = match[1] ?? "";
219
+ const iife = generateIIFE(originalExpr, schema, options);
220
+ result = result.slice(0, match.index) + prefix + iife + result.slice(rhsEnd);
221
+ }
222
+ return result;
127
223
  }
128
224
  /**
129
225
  * Remove the `compile` binding from `import { compile, ... } from "zod-aot"` statements.
@@ -1 +1 @@
1
- {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/unplugin/transform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/unplugin/transform.ts"],"names":[],"mappings":"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"}
@@ -17,5 +17,15 @@ export interface ZodAotPluginOptions {
17
17
  * @default false
18
18
  */
19
19
  verbose?: boolean | undefined;
20
+ /**
21
+ * Auto-detect all exported Zod schemas without requiring compile() wrappers.
22
+ * When enabled, the plugin scans exports for Zod schemas (via `_zod.def` detection)
23
+ * and compiles them at build time. No `import { compile } from "zod-aot"` needed.
24
+ *
25
+ * **Note:** Files with runtime Zod imports are executed at build time via `loadSourceFile()`.
26
+ * Use `include` to limit scope if your project has schema files with side effects.
27
+ * @default false
28
+ */
29
+ autoDiscover?: boolean | undefined;
20
30
  }
21
31
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/unplugin/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/unplugin/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-aot",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Compile Zod schemas into zero-overhead validation functions at build time",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -83,6 +83,7 @@
83
83
  }
84
84
  },
85
85
  "dependencies": {
86
+ "acorn": "^8.16.0",
86
87
  "jiti": "^2.6.1",
87
88
  "unplugin": "^3.0.0"
88
89
  },