zod-compiler 1.26.2 → 1.26.3
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/dist/core/iife.d.ts +23 -2
- package/dist/core/iife.d.ts.map +1 -1
- package/dist/core/iife.js +25 -3
- package/dist/core/iife.js.map +1 -1
- package/dist/unplugin/transform.d.ts.map +1 -1
- package/dist/unplugin/transform.js +29 -1
- package/dist/unplugin/transform.js.map +1 -1
- package/package.json +1 -1
package/dist/core/iife.d.ts
CHANGED
|
@@ -213,17 +213,38 @@ declare const FINZ_DECL = "function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);
|
|
|
213
213
|
* object — two exports aliasing one schema — would throw under ESM strict mode.
|
|
214
214
|
*/
|
|
215
215
|
declare const MK_VALIDATOR_DECL: string;
|
|
216
|
+
/**
|
|
217
|
+
* Does the IIFE's preamble DEREFERENCE the retained schema at evaluation time?
|
|
218
|
+
*
|
|
219
|
+
* Only `__rf` does: every entry is `__zs<accessPath>`, and an access path walks
|
|
220
|
+
* the schema's structure — `._zod.innerType` fires a `z.lazy()` getter,
|
|
221
|
+
* `.shape` materializes a `z.object()` shape (zod v4 reads every property
|
|
222
|
+
* descriptor, so ONE `.shape` read fires ALL of an object's recursion getters).
|
|
223
|
+
* Binding `__zs` itself does not: constructing the schema leaves deferred
|
|
224
|
+
* callbacks unforced, and `usesRetainedSchema`'s only read is `__zs.safeParse`,
|
|
225
|
+
* an own property zod assigns during `ZodType.init`.
|
|
226
|
+
*
|
|
227
|
+
* The distinction decides whether the IIFE may be evaluated inside the
|
|
228
|
+
* INITIALIZER of the binding the schema's own deferred callbacks close over —
|
|
229
|
+
* see the self-referential path in the unplugin's autoDiscover rewrite.
|
|
230
|
+
*/
|
|
231
|
+
declare function iifeDerefsSchema(schema: CompiledSchemaInfo): boolean;
|
|
216
232
|
/**
|
|
217
233
|
* Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.
|
|
218
234
|
*
|
|
219
235
|
* @param schemaExpr - Expression resolving to the original Zod schema
|
|
220
236
|
* (e.g. `"UserSchema"` in unplugin, `"(__src_X as any).schema"` in CLI)
|
|
221
237
|
* @param schema
|
|
222
|
-
* @param options
|
|
238
|
+
* @param options - `pure: false` drops the `/* @__PURE__ * /` annotation, for
|
|
239
|
+
* the one caller that emits the IIFE as a STATEMENT following the
|
|
240
|
+
* declaration rather than as its initializer: there the call's whole point is
|
|
241
|
+
* its side effect (`__zcMkv` installing the compiled methods on the schema),
|
|
242
|
+
* and a bundler that believed it pure would drop the compilation outright.
|
|
223
243
|
*/
|
|
224
244
|
declare function generateIIFE(schemaExpr: string, schema: CompiledSchemaInfo, options?: {
|
|
225
245
|
zodCompat?: boolean | undefined;
|
|
246
|
+
pure?: boolean | undefined;
|
|
226
247
|
}): string;
|
|
227
248
|
//#endregion
|
|
228
|
-
export { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FINZ_DECL, FIN_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE };
|
|
249
|
+
export { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FINZ_DECL, FIN_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE, iifeDerefsSchema };
|
|
229
250
|
//# sourceMappingURL=iife.d.ts.map
|
package/dist/core/iife.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAca;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8CA;;;cAUA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6FA
|
|
1
|
+
{"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAca;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8CA;;;cAUA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6FA;;;;;;;;;;;;;;;;iBA4BG,iBAAiB,QAAQ;;;;;;;;;;;;;iBAgBzB,aACd,oBACA,QAAQ,oBACR;EAAY;EAAiC"}
|
package/dist/core/iife.js
CHANGED
|
@@ -223,12 +223,34 @@ function extractFunctionName(functionDef) {
|
|
|
223
223
|
return match[1];
|
|
224
224
|
}
|
|
225
225
|
/**
|
|
226
|
+
* Does the IIFE's preamble DEREFERENCE the retained schema at evaluation time?
|
|
227
|
+
*
|
|
228
|
+
* Only `__rf` does: every entry is `__zs<accessPath>`, and an access path walks
|
|
229
|
+
* the schema's structure — `._zod.innerType` fires a `z.lazy()` getter,
|
|
230
|
+
* `.shape` materializes a `z.object()` shape (zod v4 reads every property
|
|
231
|
+
* descriptor, so ONE `.shape` read fires ALL of an object's recursion getters).
|
|
232
|
+
* Binding `__zs` itself does not: constructing the schema leaves deferred
|
|
233
|
+
* callbacks unforced, and `usesRetainedSchema`'s only read is `__zs.safeParse`,
|
|
234
|
+
* an own property zod assigns during `ZodType.init`.
|
|
235
|
+
*
|
|
236
|
+
* The distinction decides whether the IIFE may be evaluated inside the
|
|
237
|
+
* INITIALIZER of the binding the schema's own deferred callbacks close over —
|
|
238
|
+
* see the self-referential path in the unplugin's autoDiscover rewrite.
|
|
239
|
+
*/
|
|
240
|
+
function iifeDerefsSchema(schema) {
|
|
241
|
+
return schema.refEntries.length > 0;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
226
244
|
* Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.
|
|
227
245
|
*
|
|
228
246
|
* @param schemaExpr - Expression resolving to the original Zod schema
|
|
229
247
|
* (e.g. `"UserSchema"` in unplugin, `"(__src_X as any).schema"` in CLI)
|
|
230
248
|
* @param schema
|
|
231
|
-
* @param options
|
|
249
|
+
* @param options - `pure: false` drops the `/* @__PURE__ * /` annotation, for
|
|
250
|
+
* the one caller that emits the IIFE as a STATEMENT following the
|
|
251
|
+
* declaration rather than as its initializer: there the call's whole point is
|
|
252
|
+
* its side effect (`__zcMkv` installing the compiled methods on the schema),
|
|
253
|
+
* and a bundler that believed it pure would drop the compilation outright.
|
|
232
254
|
*/
|
|
233
255
|
function generateIIFE(schemaExpr, schema, options) {
|
|
234
256
|
const { codegenResult, refEntries } = schema;
|
|
@@ -240,7 +262,7 @@ function generateIIFE(schemaExpr, schema, options) {
|
|
|
240
262
|
const fcArg = codegenResult.fastFnName ?? "null";
|
|
241
263
|
const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : "null");
|
|
242
264
|
return [
|
|
243
|
-
"/* @__PURE__ */ (() => {",
|
|
265
|
+
options?.pure === false ? "(() => {" : "/* @__PURE__ */ (() => {",
|
|
244
266
|
...bindsSchema ? [`var ${RETAINED_SCHEMA_VAR}=${schemaExpr};`] : [],
|
|
245
267
|
...refEntries.length > 0 ? [`var __rf=[${refEntries.map((fb) => `${retainedSchema}${fb.accessPath}`).join(",")}];`] : [],
|
|
246
268
|
...codegenResult.code.split("\n").filter((l) => l.trim() !== "" && l.trim() !== "/* zod-compiler */"),
|
|
@@ -250,6 +272,6 @@ function generateIIFE(schemaExpr, schema, options) {
|
|
|
250
272
|
].join("\n");
|
|
251
273
|
}
|
|
252
274
|
//#endregion
|
|
253
|
-
export { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FINZ_DECL, FIN_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE };
|
|
275
|
+
export { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FINZ_DECL, FIN_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE, iifeDerefsSchema };
|
|
254
276
|
|
|
255
277
|
//# sourceMappingURL=iife.js.map
|
package/dist/core/iife.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iife.js","names":[],"sources":["../../src/core/iife.ts"],"sourcesContent":["/**\n * Shared CompiledSchema<T> IIFE generation.\n * Used by both CLI emitter and unplugin transform.\n */\n\nimport { RETAINED_SCHEMA_VAR } from \"./codegen/context.js\";\nimport type { CompiledSchemaInfo } from \"./pipeline.js\";\n\n/**\n * Import statement required by generateIIFE output (references\n * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and\n * custom callbacks may only reveal that they are async through the promise\n * they return, at which point zod's own synchronous parse raises.\n */\nexport const ZOD_CONFIG_IMPORT =\n 'import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";';\n\n/**\n * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):\n * the message an issue gets when nothing was baked into it at build time.\n *\n * Resolves zod's tail of `finalizeIssue` — `config.customError` then\n * `config.localeError` then \"Invalid input\" — and does it PER CALL, because the\n * config is mutable: `z.config({ localeError })` in an entry point runs after\n * the schema modules it imports, so a value snapshotted at module init misses\n * it. Reading a captured `localeError` alone also dropped `customError`\n * outright, silently ignoring the global map most i18n setups install.\n *\n * The head of zod's chain — the schema's own `error` option — is baked into the\n * issue at build time and short-circuits this. The one link that cannot be\n * reproduced is a per-CALL `ctx.error`, which would have to travel through\n * `safeParse`; that entry point sits at V8's inlining budget, where even an\n * unused extra parameter measured ~12% on every parse.\n *\n * Only ever called while building an error, never on a successful parse.\n */\nexport const ZOD_MSG_DECLARATION =\n 'function __zcUw(m){return typeof m===\"string\"?m:(m===undefined||m===null?undefined:m.message);}' +\n \"var __zcMsg=function(iss){var c=__zodCompilerConfig(),m;\" +\n \"if(c.customError){m=__zcUw(c.customError(iss));if(m!==undefined&&m!==null)return m;}\" +\n \"if(c.localeError){m=__zcUw(c.localeError(iss));if(m!==undefined&&m!==null)return m;}\" +\n 'return \"Invalid input\";};';\n\n/**\n * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)\n * declares it once per compiled file; lean mode (all unplugin bundlers) declares\n * it once per bundle in the plugin-materialized runtime module (module-local —\n * generated code only ever references __zcFin/__zcFinD, never __ZcFail).\n *\n * Why a prototype getter and not `{success:false, get error(){...}}`: an object\n * literal with an inline accessor forces V8 down its slow accessor-defining\n * allocation path — ~110ns per failure, measured — which dominates the entire\n * invalid-input cost whenever callers never read `.error`. Hosting `error` on\n * the prototype turns each failure into a plain field-only instantiation (~2ns,\n * ~13x), with the lazy-cache semantics intact. (Trade-off: `error` is a\n * prototype accessor, so it no longer shows up in `Object.keys(result)` / spread\n * / JSON.stringify of the result wrapper — `.success`/`.error`/`.data` access,\n * destructuring, and `in` are unaffected.)\n *\n * One class serves both finalizers, so the instances share one hidden class:\n * __zcFin passes pre-collected issues in `_e` (with `_f===null`); __zcFinD\n * passes the hosted slow-walk in `_f` plus the input in `_i`, and the getter\n * runs the walk on first `.error` read. The whole finalization — locale fill\n * (__zcMsg applied ONLY when an issue carries no message, never overwriting a\n * baked-in custom/fallback message), input strip, and ZodError construction\n * (zod v4 JSON.stringifies every issue into `message` and captures a stack\n * trace) — stays deferred inside the cached accessor exactly as before, since\n * the issues array is observable solely through `.error`.\n *\n * `input` is `delete`d, not assigned `undefined`. Key PRESENCE is observable —\n * `\"input\" in issue`, `Object.keys(issue)`, object spread, `toStrictEqual`\n * against a zod issue — and zod's `util.finalizeIssue` does `delete full.input`\n * whenever `reportInput` is off, so assignment left every compiled issue one\n * enumerable key wider than zod's. The delete's dictionary-mode transition is\n * affordable precisely BECAUSE of the deferral above: it runs only after a\n * caller asks for `.error` on a failed parse, and is memoised in `_c`. Neither\n * a successful parse nor a `.success`/`.is()` check on a rejected one reaches\n * it — measured, the two are unchanged, while the `.error` read itself goes\n * ~3.95us -> ~4.19us per failure, i.e. ~6% of a path whose cost is already\n * dominated by the ZodError construction on the next line (stack capture plus a\n * JSON.stringify of every issue).\n */\nexport const FAIL_CLASS_DECL =\n \"function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){' +\n \"if(this._c)return this._c;\" +\n \"var e=this._f!==null?this._f(this._i):this._e;\" +\n 'for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);delete e[i].input;delete e[i].continue;}' +\n \"return this._c=new __zcZodError(e);}});\";\n\n/** Eager finalizer (mutation / partial-fast-path schemas): issues already\n * collected in `e`; success short-circuits to a plain result literal. */\nexport const FIN_DECL =\n \"function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}\";\n\n/**\n * Deferred-collection finalizer for Fast-Path-eligible schemas. When the\n * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is\n * pushed into the cached `.error` accessor instead of running eagerly:\n * fast-eligible schemas never mutate, so the walk's only output is the\n * issues array, which is observable solely through `.error` — one step\n * further along the same lazy boundary `__zcFin` already established (locale\n * fill, input strip, ZodError construction). A failed safeParse whose\n * `.error` is never read costs the fast check alone.\n *\n * Takes the schema's HOSTED slow-walk function plus the input — NOT a\n * per-call closure: `__zcFinD(__sw_N, input)` allocates only the result\n * object, where `__zcFinD(function(){...})` paid a closure environment and\n * function object per failure. Hosting the walk also shrinks safeParse to\n * two statements, within V8's inlining budget (the success-path result\n * literal becomes escape-analyzable at monomorphic call sites).\n *\n * The walk re-reads `input` at `.error`-read time; a caller that mutates\n * the input between safeParse and reading `.error` sees issues for the\n * mutated value (zod materializes at parse time). Same caveat class as the\n * documented __zcFin deferral.\n */\nexport const FIN_DEFERRED_DECL = \"function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}\";\n\n/**\n * Compact-mode failure class — a lazy failure that delegates error reporting to\n * the ORIGINAL Zod schema's `safeParse`. Used by `output: \"compact\"`, where the\n * compiled slow walk is dropped entirely: a mutation-free schema's fast check\n * is the only generated validation, and on a fast-check failure the cold error\n * path is produced by the retained Zod schema itself (`zod` is the source of\n * truth, so the issues are byte-identical — no second validation engine).\n *\n * `_z` is the schema's PRISTINE safeParse method, captured by\n * emitRetainedMethod (see context.ts), and `_r` is its receiver — the `__zs`\n * binding generateIIFE places above that capture. Both are read before the\n * trailing `__zcMkv` call installs anything, so the method is zod's own\n * implementation, never the compiled delegate, avoiding infinite recursion\n * without allocating a bound function. The zod parse is deferred until `.error`\n * is read and cached, so\n * the common `safeParse(x).success`/`.is(x)` checks on invalid input cost only\n * the fast check (zod never runs) — the same deferral boundary `__zcFinD`\n * establishes for the compiled slow walk. Sound because compact mode is gated\n * on a TOTAL fast path: `fc(input) === false` ⟹ zod rejects, so `success:false`\n * holds without consulting zod.\n *\n * The getter returns zod's OWN ZodError verbatim (no locale fill / input strip /\n * re-wrap — zod already finalized it), so a delegated failure is exactly what\n * the unaltered schema would have produced.\n */\nexport const FAILZ_CLASS_DECL =\n \"function __ZcFailZ(z,r,i){this.success=false;this._z=z;this._r=r;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFailZ.prototype,\"error\",{configurable:true,get:function(){' +\n \"return this._c||(this._c=this._z.call(this._r,this._i).error);}});\";\n\n/** Compact-mode finalizer: retain a pristine safeParse, its receiver, and input lazily. */\nexport const FINZ_DECL = \"function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);}\";\n\n/**\n * Validator factory. Inline mode (CLI emitter) declares it once per compiled\n * file; lean mode (all unplugin bundlers) exports it once per bundle from the\n * plugin-materialized runtime module — generated code never imports it from\n * the zod-compiler package itself, so zod-compiler stays a devDependency and\n * the helper set is always version-locked to the codegen that calls it.\n * Wraps a safeParse function into the CompiledSchema interface.\n *\n * IDENTITY-PRESERVING: with zodCompat (schema != null) the compiled\n * parse/safeParse/parseAsync/safeParseAsync are installed as OWN properties\n * on the original schema object, which is returned as-is. zod v4 keys\n * several APIs on object identity — toJSONSchema's ctx.seen registers the\n * object it is handed while each processor closure captures the original\n * inst (a wrapper crashes `optionalProcessor` with \"Cannot set properties\n * of undefined (setting 'ref')\" the moment a compiled schema is composed\n * into another schema), and globalRegistry/.meta() is a WeakMap keyed by\n * the schema instance (a wrapper silently loses OpenAPI titles/ids). An\n * Object.create wrapper breaks both; mutating the original breaks neither\n * (zod's internal parsing flows through _zod.run, never the public\n * methods, and derived schemas — .optional(), .extend() — are fresh\n * instances that fall back to plain zod). schema=null (zodCompat: false)\n * still produces a plain method-bag object.\n *\n * fc is the schema's hosted fast-check boolean function (null when no Fast\n * Path exists). parse()/parseAsync() try it first and return the input\n * directly on success: fc is small enough for V8 to inline, so the hot parse\n * path runs with zero allocations — calling fn would allocate an intermediate\n * SafeParseResult that escape analysis cannot remove (fn never inlines).\n * Fast-path-eligible schemas never mutate, so fc(input) ⟹ data === input.\n *\n * is is the TOTAL fast-check predicate (fc when the fast path is total, else\n * null). Installed as `.is()` — a zero-allocation boolean type guard. When\n * null (partial fast path or none) `.is()` derives from fn(input).success: a\n * partial fc can pass-through valid input but its `false` does not imply\n * rejection (a default/catch may still succeed), so it would be unsound as a\n * standalone guard.\n *\n * parseAsync/safeParseAsync wrap the SYNC validator, which is right for every\n * schema the compiler can reproduce — none of them are async. It is wrong for\n * the ones it cannot: an `async` refinement or a `z.promise()` extracts to a\n * Zod delegate, and delegating means calling Zod's SYNCHRONOUS safeParse, which\n * raises `$ZodAsyncError` by design. Wrapping that gave the compiled schema an\n * async pair that rejected with `$ZodAsyncError` for EVERY input — including\n * valid ones — where Zod resolves normally, so `await UserSchema.parseAsync(x)`\n * stopped working the moment any part of the schema went async.\n *\n * So both are guarded: a synchronous throw hands off to the schema's ORIGINAL\n * async method, captured before these are installed — the same escape hatch\n * `~standard` already uses for its throw path, and for the same reason (the\n * compiled validator has no async mode to offer, and Zod's is exact). It also\n * fixes the smaller wart that a throwing `fn` made `parseAsync` throw\n * SYNCHRONOUSLY rather than return a rejected promise. With `zodCompat: false`\n * there is no schema to delegate to and the throw propagates as before.\n *\n * `~standard` is REPLACED, not merely preserved. Zod builds it lazily as\n * `validate: (v) => safeParse(inst, v)` — the core FUNCTION, which goes straight\n * to `inst._zod.run`. It never reads the schema's own `safeParse` property, so\n * installing the compiled one leaves this route entirely uncompiled: measured\n * 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema\n * consumers (tRPC, Hono, TanStack) were getting plain Zod.\n *\n * Zod's own `~standard` is never READ, only overwritten. Zod installs the slot\n * with `util.defineLazy` — commented there as \"avoid creating objects for every\n * schema\" — so it is an accessor that builds `{version, vendor, validate}` plus\n * its closure on first touch. Reading it to capture a fallback fired that getter\n * for every compiled schema while the module was still initializing.\n *\n * How much that costs depends on the entry point, and only one of them is free:\n * classic `zod` forces the slot itself during `ZodType.init` (it does\n * `Object.assign(inst[\"~standard\"], { jsonSchema })`), so there the read hit an\n * already-built object and cost only an accessor call. `zod/mini` and raw\n * `zod/v4/core` never touch it, so for those the read built — and retained — an\n * object and a closure per schema, purely to capture a fallback the schema will\n * most likely never expose to a Standard Schema consumer.\n *\n * The throw path is rebuilt instead of captured. Zod's validate catches a\n * synchronous throw and retries through `safeParseAsync` — that is how an async\n * refinement resolves and how a throwing check surfaces as a rejected promise\n * rather than a synchronous throw — so calling the already-captured `zspa` and\n * mapping its result is the same route to the same result. `vendor` is likewise\n * a constant: schema discovery only ever admits zod schemas, and classic, mini\n * and core all hardcode `vendor: \"zod\"` themselves.\n *\n * Not carried over (unchanged by this, and pre-dating it): classic's\n * `~standard.jsonSchema` extension, which the replacement object has never\n * reproduced.\n *\n * Installed with defineProperty rather than assignment: Zod's lazy setter\n * redefines the slot as non-writable, so a second `__zcMkv` on the same schema\n * object — two exports aliasing one schema — would throw under ESM strict mode.\n */\nexport const MK_VALIDATOR_DECL =\n \"function __zcMkv(fn,schema,fc,is){var w=schema||{};var zpa=w.parseAsync,zspa=w.safeParseAsync;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){try{return Promise.resolve(fn(input));}catch(e){if(zspa)return zspa(input);throw e;}};w.parseAsync=fc?function(input){try{if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}}:function(input){try{var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}};w.is=is||function(input){return fn(input).success;};\" +\n 'Object.defineProperty(w,\"~standard\",{configurable:true,value:{version:1,vendor:\"zod\",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zspa)return zspa(input).then(function(q){return q.success?{value:q.data}:{issues:q.error.issues};});throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});' +\n \"return w;}\";\n\nfunction extractFunctionName(functionDef: string): string {\n const match = /^function\\s+(\\w+)\\s*\\(/.exec(functionDef);\n if (!match?.[1]) {\n throw new Error(\"Cannot extract function name from generated code\");\n }\n return match[1];\n}\n\n/**\n * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.\n *\n * @param schemaExpr - Expression resolving to the original Zod schema\n * (e.g. `\"UserSchema\"` in unplugin, `\"(__src_X as any).schema\"` in CLI)\n * @param schema\n * @param options\n */\nexport function generateIIFE(\n schemaExpr: string,\n schema: CompiledSchemaInfo,\n options?: { zodCompat?: boolean | undefined },\n): string {\n const { codegenResult, refEntries } = schema;\n const fnName = extractFunctionName(codegenResult.functionDef);\n const zodCompat = options?.zodCompat !== false;\n // Every fallback access starts from the same source schema, and compact\n // delegation names it outright. Capture it once whenever either needs it, so\n // an inline initializer is not reconstructed for each path and again for the\n // identity-preserving __zcMkv target.\n const bindsSchema = refEntries.length > 0 || codegenResult.usesRetainedSchema === true;\n const retainedSchema = bindsSchema ? RETAINED_SCHEMA_VAR : schemaExpr;\n const schemaArg = zodCompat ? retainedSchema : \"null\";\n const fcArg = codegenResult.fastFnName ?? \"null\";\n // `.is()` gets the fast-check directly only when it is a total predicate;\n // partial/none falls back to safeParse().success inside __zcMkv. A rebuilding\n // schema has no by-reference `fc` but still names its predicate separately.\n const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : \"null\");\n\n return [\n \"/* @__PURE__ */ (() => {\",\n ...(bindsSchema ? [`var ${RETAINED_SCHEMA_VAR}=${schemaExpr};`] : []),\n // Only fallback refs need the array; a compact validator with none of its\n // own reads `__zs` directly rather than allocating `[__zs]` to index into.\n ...(refEntries.length > 0\n ? [`var __rf=[${refEntries.map((fb) => `${retainedSchema}${fb.accessPath}`).join(\",\")}];`]\n : []),\n ...codegenResult.code\n .split(\"\\n\")\n .filter((l) => l.trim() !== \"\" && l.trim() !== \"/* zod-compiler */\"),\n codegenResult.functionDef,\n `return __zcMkv(${fnName},${schemaArg},${fcArg},${isArg});`,\n \"})()\",\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,oBACX;;;;;;;;;;;;;;;;;;;;AAqBF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CF,MAAa,kBACX;;;AASF,MAAa,WACX;;;;;;;;;;;;;;;;;;;;;;;AAwBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BjC,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6FzB,MAAa,oBACX;AAIF,SAAS,oBAAoB,aAA6B;CACxD,MAAM,QAAQ,yBAAyB,KAAK,WAAW;CACvD,IAAI,CAAC,QAAQ,IACX,MAAM,IAAI,MAAM,kDAAkD;CAEpE,OAAO,MAAM;AACf;;;;;;;;;AAUA,SAAgB,aACd,YACA,QACA,SACQ;CACR,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,SAAS,oBAAoB,cAAc,WAAW;CAC5D,MAAM,YAAY,SAAS,cAAc;CAKzC,MAAM,cAAc,WAAW,SAAS,KAAK,cAAc,uBAAuB;CAClF,MAAM,iBAAiB,cAAc,sBAAsB;CAC3D,MAAM,YAAY,YAAY,iBAAiB;CAC/C,MAAM,QAAQ,cAAc,cAAc;CAI1C,MAAM,QAAQ,cAAc,aAAa,cAAc,YAAY,QAAQ;CAE3E,OAAO;EACL;EACA,GAAI,cAAc,CAAC,OAAO,oBAAoB,GAAG,WAAW,EAAE,IAAI,CAAC;EAGnE,GAAI,WAAW,SAAS,IACpB,CAAC,aAAa,WAAW,KAAK,OAAO,GAAG,iBAAiB,GAAG,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG,IACvF,CAAC;EACL,GAAG,cAAc,KACd,MAAM,IAAI,CAAC,CACX,QAAQ,MAAM,EAAE,KAAK,MAAM,MAAM,EAAE,KAAK,MAAM,oBAAoB;EACrE,cAAc;EACd,kBAAkB,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM;EACxD;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}
|
|
1
|
+
{"version":3,"file":"iife.js","names":[],"sources":["../../src/core/iife.ts"],"sourcesContent":["/**\n * Shared CompiledSchema<T> IIFE generation.\n * Used by both CLI emitter and unplugin transform.\n */\n\nimport { RETAINED_SCHEMA_VAR } from \"./codegen/context.js\";\nimport type { CompiledSchemaInfo } from \"./pipeline.js\";\n\n/**\n * Import statement required by generateIIFE output (references\n * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and\n * custom callbacks may only reveal that they are async through the promise\n * they return, at which point zod's own synchronous parse raises.\n */\nexport const ZOD_CONFIG_IMPORT =\n 'import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";';\n\n/**\n * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):\n * the message an issue gets when nothing was baked into it at build time.\n *\n * Resolves zod's tail of `finalizeIssue` — `config.customError` then\n * `config.localeError` then \"Invalid input\" — and does it PER CALL, because the\n * config is mutable: `z.config({ localeError })` in an entry point runs after\n * the schema modules it imports, so a value snapshotted at module init misses\n * it. Reading a captured `localeError` alone also dropped `customError`\n * outright, silently ignoring the global map most i18n setups install.\n *\n * The head of zod's chain — the schema's own `error` option — is baked into the\n * issue at build time and short-circuits this. The one link that cannot be\n * reproduced is a per-CALL `ctx.error`, which would have to travel through\n * `safeParse`; that entry point sits at V8's inlining budget, where even an\n * unused extra parameter measured ~12% on every parse.\n *\n * Only ever called while building an error, never on a successful parse.\n */\nexport const ZOD_MSG_DECLARATION =\n 'function __zcUw(m){return typeof m===\"string\"?m:(m===undefined||m===null?undefined:m.message);}' +\n \"var __zcMsg=function(iss){var c=__zodCompilerConfig(),m;\" +\n \"if(c.customError){m=__zcUw(c.customError(iss));if(m!==undefined&&m!==null)return m;}\" +\n \"if(c.localeError){m=__zcUw(c.localeError(iss));if(m!==undefined&&m!==null)return m;}\" +\n 'return \"Invalid input\";};';\n\n/**\n * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)\n * declares it once per compiled file; lean mode (all unplugin bundlers) declares\n * it once per bundle in the plugin-materialized runtime module (module-local —\n * generated code only ever references __zcFin/__zcFinD, never __ZcFail).\n *\n * Why a prototype getter and not `{success:false, get error(){...}}`: an object\n * literal with an inline accessor forces V8 down its slow accessor-defining\n * allocation path — ~110ns per failure, measured — which dominates the entire\n * invalid-input cost whenever callers never read `.error`. Hosting `error` on\n * the prototype turns each failure into a plain field-only instantiation (~2ns,\n * ~13x), with the lazy-cache semantics intact. (Trade-off: `error` is a\n * prototype accessor, so it no longer shows up in `Object.keys(result)` / spread\n * / JSON.stringify of the result wrapper — `.success`/`.error`/`.data` access,\n * destructuring, and `in` are unaffected.)\n *\n * One class serves both finalizers, so the instances share one hidden class:\n * __zcFin passes pre-collected issues in `_e` (with `_f===null`); __zcFinD\n * passes the hosted slow-walk in `_f` plus the input in `_i`, and the getter\n * runs the walk on first `.error` read. The whole finalization — locale fill\n * (__zcMsg applied ONLY when an issue carries no message, never overwriting a\n * baked-in custom/fallback message), input strip, and ZodError construction\n * (zod v4 JSON.stringifies every issue into `message` and captures a stack\n * trace) — stays deferred inside the cached accessor exactly as before, since\n * the issues array is observable solely through `.error`.\n *\n * `input` is `delete`d, not assigned `undefined`. Key PRESENCE is observable —\n * `\"input\" in issue`, `Object.keys(issue)`, object spread, `toStrictEqual`\n * against a zod issue — and zod's `util.finalizeIssue` does `delete full.input`\n * whenever `reportInput` is off, so assignment left every compiled issue one\n * enumerable key wider than zod's. The delete's dictionary-mode transition is\n * affordable precisely BECAUSE of the deferral above: it runs only after a\n * caller asks for `.error` on a failed parse, and is memoised in `_c`. Neither\n * a successful parse nor a `.success`/`.is()` check on a rejected one reaches\n * it — measured, the two are unchanged, while the `.error` read itself goes\n * ~3.95us -> ~4.19us per failure, i.e. ~6% of a path whose cost is already\n * dominated by the ZodError construction on the next line (stack capture plus a\n * JSON.stringify of every issue).\n */\nexport const FAIL_CLASS_DECL =\n \"function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){' +\n \"if(this._c)return this._c;\" +\n \"var e=this._f!==null?this._f(this._i):this._e;\" +\n 'for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);delete e[i].input;delete e[i].continue;}' +\n \"return this._c=new __zcZodError(e);}});\";\n\n/** Eager finalizer (mutation / partial-fast-path schemas): issues already\n * collected in `e`; success short-circuits to a plain result literal. */\nexport const FIN_DECL =\n \"function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}\";\n\n/**\n * Deferred-collection finalizer for Fast-Path-eligible schemas. When the\n * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is\n * pushed into the cached `.error` accessor instead of running eagerly:\n * fast-eligible schemas never mutate, so the walk's only output is the\n * issues array, which is observable solely through `.error` — one step\n * further along the same lazy boundary `__zcFin` already established (locale\n * fill, input strip, ZodError construction). A failed safeParse whose\n * `.error` is never read costs the fast check alone.\n *\n * Takes the schema's HOSTED slow-walk function plus the input — NOT a\n * per-call closure: `__zcFinD(__sw_N, input)` allocates only the result\n * object, where `__zcFinD(function(){...})` paid a closure environment and\n * function object per failure. Hosting the walk also shrinks safeParse to\n * two statements, within V8's inlining budget (the success-path result\n * literal becomes escape-analyzable at monomorphic call sites).\n *\n * The walk re-reads `input` at `.error`-read time; a caller that mutates\n * the input between safeParse and reading `.error` sees issues for the\n * mutated value (zod materializes at parse time). Same caveat class as the\n * documented __zcFin deferral.\n */\nexport const FIN_DEFERRED_DECL = \"function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}\";\n\n/**\n * Compact-mode failure class — a lazy failure that delegates error reporting to\n * the ORIGINAL Zod schema's `safeParse`. Used by `output: \"compact\"`, where the\n * compiled slow walk is dropped entirely: a mutation-free schema's fast check\n * is the only generated validation, and on a fast-check failure the cold error\n * path is produced by the retained Zod schema itself (`zod` is the source of\n * truth, so the issues are byte-identical — no second validation engine).\n *\n * `_z` is the schema's PRISTINE safeParse method, captured by\n * emitRetainedMethod (see context.ts), and `_r` is its receiver — the `__zs`\n * binding generateIIFE places above that capture. Both are read before the\n * trailing `__zcMkv` call installs anything, so the method is zod's own\n * implementation, never the compiled delegate, avoiding infinite recursion\n * without allocating a bound function. The zod parse is deferred until `.error`\n * is read and cached, so\n * the common `safeParse(x).success`/`.is(x)` checks on invalid input cost only\n * the fast check (zod never runs) — the same deferral boundary `__zcFinD`\n * establishes for the compiled slow walk. Sound because compact mode is gated\n * on a TOTAL fast path: `fc(input) === false` ⟹ zod rejects, so `success:false`\n * holds without consulting zod.\n *\n * The getter returns zod's OWN ZodError verbatim (no locale fill / input strip /\n * re-wrap — zod already finalized it), so a delegated failure is exactly what\n * the unaltered schema would have produced.\n */\nexport const FAILZ_CLASS_DECL =\n \"function __ZcFailZ(z,r,i){this.success=false;this._z=z;this._r=r;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFailZ.prototype,\"error\",{configurable:true,get:function(){' +\n \"return this._c||(this._c=this._z.call(this._r,this._i).error);}});\";\n\n/** Compact-mode finalizer: retain a pristine safeParse, its receiver, and input lazily. */\nexport const FINZ_DECL = \"function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);}\";\n\n/**\n * Validator factory. Inline mode (CLI emitter) declares it once per compiled\n * file; lean mode (all unplugin bundlers) exports it once per bundle from the\n * plugin-materialized runtime module — generated code never imports it from\n * the zod-compiler package itself, so zod-compiler stays a devDependency and\n * the helper set is always version-locked to the codegen that calls it.\n * Wraps a safeParse function into the CompiledSchema interface.\n *\n * IDENTITY-PRESERVING: with zodCompat (schema != null) the compiled\n * parse/safeParse/parseAsync/safeParseAsync are installed as OWN properties\n * on the original schema object, which is returned as-is. zod v4 keys\n * several APIs on object identity — toJSONSchema's ctx.seen registers the\n * object it is handed while each processor closure captures the original\n * inst (a wrapper crashes `optionalProcessor` with \"Cannot set properties\n * of undefined (setting 'ref')\" the moment a compiled schema is composed\n * into another schema), and globalRegistry/.meta() is a WeakMap keyed by\n * the schema instance (a wrapper silently loses OpenAPI titles/ids). An\n * Object.create wrapper breaks both; mutating the original breaks neither\n * (zod's internal parsing flows through _zod.run, never the public\n * methods, and derived schemas — .optional(), .extend() — are fresh\n * instances that fall back to plain zod). schema=null (zodCompat: false)\n * still produces a plain method-bag object.\n *\n * fc is the schema's hosted fast-check boolean function (null when no Fast\n * Path exists). parse()/parseAsync() try it first and return the input\n * directly on success: fc is small enough for V8 to inline, so the hot parse\n * path runs with zero allocations — calling fn would allocate an intermediate\n * SafeParseResult that escape analysis cannot remove (fn never inlines).\n * Fast-path-eligible schemas never mutate, so fc(input) ⟹ data === input.\n *\n * is is the TOTAL fast-check predicate (fc when the fast path is total, else\n * null). Installed as `.is()` — a zero-allocation boolean type guard. When\n * null (partial fast path or none) `.is()` derives from fn(input).success: a\n * partial fc can pass-through valid input but its `false` does not imply\n * rejection (a default/catch may still succeed), so it would be unsound as a\n * standalone guard.\n *\n * parseAsync/safeParseAsync wrap the SYNC validator, which is right for every\n * schema the compiler can reproduce — none of them are async. It is wrong for\n * the ones it cannot: an `async` refinement or a `z.promise()` extracts to a\n * Zod delegate, and delegating means calling Zod's SYNCHRONOUS safeParse, which\n * raises `$ZodAsyncError` by design. Wrapping that gave the compiled schema an\n * async pair that rejected with `$ZodAsyncError` for EVERY input — including\n * valid ones — where Zod resolves normally, so `await UserSchema.parseAsync(x)`\n * stopped working the moment any part of the schema went async.\n *\n * So both are guarded: a synchronous throw hands off to the schema's ORIGINAL\n * async method, captured before these are installed — the same escape hatch\n * `~standard` already uses for its throw path, and for the same reason (the\n * compiled validator has no async mode to offer, and Zod's is exact). It also\n * fixes the smaller wart that a throwing `fn` made `parseAsync` throw\n * SYNCHRONOUSLY rather than return a rejected promise. With `zodCompat: false`\n * there is no schema to delegate to and the throw propagates as before.\n *\n * `~standard` is REPLACED, not merely preserved. Zod builds it lazily as\n * `validate: (v) => safeParse(inst, v)` — the core FUNCTION, which goes straight\n * to `inst._zod.run`. It never reads the schema's own `safeParse` property, so\n * installing the compiled one leaves this route entirely uncompiled: measured\n * 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema\n * consumers (tRPC, Hono, TanStack) were getting plain Zod.\n *\n * Zod's own `~standard` is never READ, only overwritten. Zod installs the slot\n * with `util.defineLazy` — commented there as \"avoid creating objects for every\n * schema\" — so it is an accessor that builds `{version, vendor, validate}` plus\n * its closure on first touch. Reading it to capture a fallback fired that getter\n * for every compiled schema while the module was still initializing.\n *\n * How much that costs depends on the entry point, and only one of them is free:\n * classic `zod` forces the slot itself during `ZodType.init` (it does\n * `Object.assign(inst[\"~standard\"], { jsonSchema })`), so there the read hit an\n * already-built object and cost only an accessor call. `zod/mini` and raw\n * `zod/v4/core` never touch it, so for those the read built — and retained — an\n * object and a closure per schema, purely to capture a fallback the schema will\n * most likely never expose to a Standard Schema consumer.\n *\n * The throw path is rebuilt instead of captured. Zod's validate catches a\n * synchronous throw and retries through `safeParseAsync` — that is how an async\n * refinement resolves and how a throwing check surfaces as a rejected promise\n * rather than a synchronous throw — so calling the already-captured `zspa` and\n * mapping its result is the same route to the same result. `vendor` is likewise\n * a constant: schema discovery only ever admits zod schemas, and classic, mini\n * and core all hardcode `vendor: \"zod\"` themselves.\n *\n * Not carried over (unchanged by this, and pre-dating it): classic's\n * `~standard.jsonSchema` extension, which the replacement object has never\n * reproduced.\n *\n * Installed with defineProperty rather than assignment: Zod's lazy setter\n * redefines the slot as non-writable, so a second `__zcMkv` on the same schema\n * object — two exports aliasing one schema — would throw under ESM strict mode.\n */\nexport const MK_VALIDATOR_DECL =\n \"function __zcMkv(fn,schema,fc,is){var w=schema||{};var zpa=w.parseAsync,zspa=w.safeParseAsync;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){try{return Promise.resolve(fn(input));}catch(e){if(zspa)return zspa(input);throw e;}};w.parseAsync=fc?function(input){try{if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}}:function(input){try{var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}};w.is=is||function(input){return fn(input).success;};\" +\n 'Object.defineProperty(w,\"~standard\",{configurable:true,value:{version:1,vendor:\"zod\",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zspa)return zspa(input).then(function(q){return q.success?{value:q.data}:{issues:q.error.issues};});throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});' +\n \"return w;}\";\n\nfunction extractFunctionName(functionDef: string): string {\n const match = /^function\\s+(\\w+)\\s*\\(/.exec(functionDef);\n if (!match?.[1]) {\n throw new Error(\"Cannot extract function name from generated code\");\n }\n return match[1];\n}\n\n/**\n * Does the IIFE's preamble DEREFERENCE the retained schema at evaluation time?\n *\n * Only `__rf` does: every entry is `__zs<accessPath>`, and an access path walks\n * the schema's structure — `._zod.innerType` fires a `z.lazy()` getter,\n * `.shape` materializes a `z.object()` shape (zod v4 reads every property\n * descriptor, so ONE `.shape` read fires ALL of an object's recursion getters).\n * Binding `__zs` itself does not: constructing the schema leaves deferred\n * callbacks unforced, and `usesRetainedSchema`'s only read is `__zs.safeParse`,\n * an own property zod assigns during `ZodType.init`.\n *\n * The distinction decides whether the IIFE may be evaluated inside the\n * INITIALIZER of the binding the schema's own deferred callbacks close over —\n * see the self-referential path in the unplugin's autoDiscover rewrite.\n */\nexport function iifeDerefsSchema(schema: CompiledSchemaInfo): boolean {\n return schema.refEntries.length > 0;\n}\n\n/**\n * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.\n *\n * @param schemaExpr - Expression resolving to the original Zod schema\n * (e.g. `\"UserSchema\"` in unplugin, `\"(__src_X as any).schema\"` in CLI)\n * @param schema\n * @param options - `pure: false` drops the `/* @__PURE__ * /` annotation, for\n * the one caller that emits the IIFE as a STATEMENT following the\n * declaration rather than as its initializer: there the call's whole point is\n * its side effect (`__zcMkv` installing the compiled methods on the schema),\n * and a bundler that believed it pure would drop the compilation outright.\n */\nexport function generateIIFE(\n schemaExpr: string,\n schema: CompiledSchemaInfo,\n options?: { zodCompat?: boolean | undefined; pure?: boolean | undefined },\n): string {\n const { codegenResult, refEntries } = schema;\n const fnName = extractFunctionName(codegenResult.functionDef);\n const zodCompat = options?.zodCompat !== false;\n // Every fallback access starts from the same source schema, and compact\n // delegation names it outright. Capture it once whenever either needs it, so\n // an inline initializer is not reconstructed for each path and again for the\n // identity-preserving __zcMkv target.\n const bindsSchema = refEntries.length > 0 || codegenResult.usesRetainedSchema === true;\n const retainedSchema = bindsSchema ? RETAINED_SCHEMA_VAR : schemaExpr;\n const schemaArg = zodCompat ? retainedSchema : \"null\";\n const fcArg = codegenResult.fastFnName ?? \"null\";\n // `.is()` gets the fast-check directly only when it is a total predicate;\n // partial/none falls back to safeParse().success inside __zcMkv. A rebuilding\n // schema has no by-reference `fc` but still names its predicate separately.\n const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : \"null\");\n\n return [\n options?.pure === false ? \"(() => {\" : \"/* @__PURE__ */ (() => {\",\n ...(bindsSchema ? [`var ${RETAINED_SCHEMA_VAR}=${schemaExpr};`] : []),\n // Only fallback refs need the array; a compact validator with none of its\n // own reads `__zs` directly rather than allocating `[__zs]` to index into.\n ...(refEntries.length > 0\n ? [`var __rf=[${refEntries.map((fb) => `${retainedSchema}${fb.accessPath}`).join(\",\")}];`]\n : []),\n ...codegenResult.code\n .split(\"\\n\")\n .filter((l) => l.trim() !== \"\" && l.trim() !== \"/* zod-compiler */\"),\n codegenResult.functionDef,\n `return __zcMkv(${fnName},${schemaArg},${fcArg},${isArg});`,\n \"})()\",\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,oBACX;;;;;;;;;;;;;;;;;;;;AAqBF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CF,MAAa,kBACX;;;AASF,MAAa,WACX;;;;;;;;;;;;;;;;;;;;;;;AAwBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BjC,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6FzB,MAAa,oBACX;AAIF,SAAS,oBAAoB,aAA6B;CACxD,MAAM,QAAQ,yBAAyB,KAAK,WAAW;CACvD,IAAI,CAAC,QAAQ,IACX,MAAM,IAAI,MAAM,kDAAkD;CAEpE,OAAO,MAAM;AACf;;;;;;;;;;;;;;;;AAiBA,SAAgB,iBAAiB,QAAqC;CACpE,OAAO,OAAO,WAAW,SAAS;AACpC;;;;;;;;;;;;;AAcA,SAAgB,aACd,YACA,QACA,SACQ;CACR,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,SAAS,oBAAoB,cAAc,WAAW;CAC5D,MAAM,YAAY,SAAS,cAAc;CAKzC,MAAM,cAAc,WAAW,SAAS,KAAK,cAAc,uBAAuB;CAClF,MAAM,iBAAiB,cAAc,sBAAsB;CAC3D,MAAM,YAAY,YAAY,iBAAiB;CAC/C,MAAM,QAAQ,cAAc,cAAc;CAI1C,MAAM,QAAQ,cAAc,aAAa,cAAc,YAAY,QAAQ;CAE3E,OAAO;EACL,SAAS,SAAS,QAAQ,aAAa;EACvC,GAAI,cAAc,CAAC,OAAO,oBAAoB,GAAG,WAAW,EAAE,IAAI,CAAC;EAGnE,GAAI,WAAW,SAAS,IACpB,CAAC,aAAa,WAAW,KAAK,OAAO,GAAG,iBAAiB,GAAG,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG,IACvF,CAAC;EACL,GAAG,cAAc,KACd,MAAM,IAAI,CAAC,CACX,QAAQ,MAAM,EAAE,KAAK,MAAM,MAAM,EAAE,KAAK,MAAM,oBAAoB;EACrE,cAAc;EACd,kBAAkB,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM;EACxD;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","names":[],"sources":["../../src/unplugin/transform.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"transform.d.ts","names":[],"sources":["../../src/unplugin/transform.ts"],"mappings":";;;;UA8BiB;EACf;EACA;EACA;EACA;EACA;EACA;;;;;;;;;;cAsHW,wBAAsB;;;;iBAgDnB,gBAAgB,YAAY,UAAU;;;;;;;;;;;;;cA6BzC;EAAuB,SAAS;EAAU,SAAS;;;;;;;;iBAgChD,oBAAoB,UAAU,2BAA2B;iBAOzD,IAAI;UAUH;EACf;EACA,KAAK;;;;;;;iBAQe,cACpB,cACA,YACA,SAAS,mBACR;;;;;;iBAUmB,qBACpB,cACA,YACA,SAAS,mBACR,QAAQ;;;;iBAqXK,cACd,cACA,SAAS,sBACT;EAAY;;;;;;iBAiDE,kBAAkB,cAAc;;;;;iBAgBhC,0BACd,cACA,SAAS,sBACT;EAAY;;;;;;iBAgGE,oBAAoB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProcessExitDuringLoadError } from "../loader.js";
|
|
2
2
|
import { discoverSchemas } from "../discovery.js";
|
|
3
|
-
import { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FINZ_DECL, FIN_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE } from "../core/iife.js";
|
|
3
|
+
import { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FINZ_DECL, FIN_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE, iifeDerefsSchema } from "../core/iife.js";
|
|
4
4
|
import "../core/codegen/dedupe.js";
|
|
5
5
|
import { aggregateUsedHelpers, compileSchemas } from "../core/pipeline.js";
|
|
6
6
|
import { mayExportSchemas } from "../static-filter.js";
|
|
@@ -461,6 +461,19 @@ function findExpressionEnd(code, start) {
|
|
|
461
461
|
function rewriteSourceAutoDiscover(code, schemas, options) {
|
|
462
462
|
return applyEdits(code, collectAutoDiscoverEdits(code, schemas, options));
|
|
463
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Does `expr` mention `name` as an identifier?
|
|
466
|
+
*
|
|
467
|
+
* Deliberately lexical, and deliberately biased toward YES. A false positive
|
|
468
|
+
* costs one export its `@__PURE__` annotation; a false negative emits an IIFE
|
|
469
|
+
* that dereferences a binding still under initialization. The expression text
|
|
470
|
+
* is often TypeScript (`z.custom<T>(...)`), which no JS parser here can be
|
|
471
|
+
* trusted to walk, so a word-boundary scan — which cannot miss a real
|
|
472
|
+
* identifier reference — is the sound direction to be wrong in.
|
|
473
|
+
*/
|
|
474
|
+
function mentionsIdentifier(expr, name) {
|
|
475
|
+
return new RegExp(`\\b${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`).test(expr);
|
|
476
|
+
}
|
|
464
477
|
/** Edits for rewriteSourceAutoDiscover, collected against pristine `code`. */
|
|
465
478
|
function collectAutoDiscoverEdits(code, schemas, options) {
|
|
466
479
|
const edits = [];
|
|
@@ -472,6 +485,21 @@ function collectAutoDiscoverEdits(code, schemas, options) {
|
|
|
472
485
|
const rhsEnd = findExpressionEnd(code, rhsStart);
|
|
473
486
|
if (rhsEnd === -1) continue;
|
|
474
487
|
const originalExpr = code.slice(rhsStart, rhsEnd).trim();
|
|
488
|
+
if (iifeDerefsSchema(schema) && mentionsIdentifier(originalExpr, schema.exportName)) {
|
|
489
|
+
if (options?.zodCompat === false) {
|
|
490
|
+
warn(`Skipping self-referential export "${schema.exportName}": output "bag" cannot preserve its recursive reference. Keeping the original schema.`);
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
edits.push({
|
|
494
|
+
start: rhsStart,
|
|
495
|
+
end: rhsEnd,
|
|
496
|
+
text: `${originalExpr};\n${generateIIFE(schema.exportName, schema, {
|
|
497
|
+
...options,
|
|
498
|
+
pure: false
|
|
499
|
+
})};`
|
|
500
|
+
});
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
475
503
|
edits.push({
|
|
476
504
|
start: rhsStart,
|
|
477
505
|
end: rhsEnd,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","names":[],"sources":["../../src/unplugin/transform.ts"],"sourcesContent":["import remapping from \"@jridgewell/remapping\";\nimport { parseExpressionAt } from \"acorn\";\nimport MagicString from \"magic-string\";\nimport picomatch from \"picomatch\";\nimport type { CodegenMode } from \"../core/codegen/context.js\";\nimport { SHARED_BLOCK_MARKER } from \"../core/codegen/dedupe.js\";\nimport {\n FAIL_CLASS_DECL,\n FAILZ_CLASS_DECL,\n FIN_DECL,\n FIN_DEFERRED_DECL,\n FINZ_DECL,\n generateIIFE,\n MK_VALIDATOR_DECL,\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n} from \"../core/iife.js\";\nimport { aggregateUsedHelpers, type CompiledSchemaInfo, compileSchemas } from \"../core/pipeline.js\";\nimport type { DiscoveredSchema } from \"../core/types.js\";\nimport { discoverSchemas } from \"../discovery.js\";\nimport { ProcessExitDuringLoadError } from \"../loader.js\";\nimport { mayExportSchemas } from \"../static-filter.js\";\nimport { applyEdits, type Edit, type Insertion, moduleHeadOffset } from \"./edits.js\";\nimport { hoistZodSchemasMeta } from \"./hoist.js\";\nimport { compileHoistedSchemas } from \"./hoist-compile.js\";\nimport type { TransformOptions, ZodCompilerPluginOptions } from \"./types.js\";\nimport { VIRTUAL_RUNTIME_ID } from \"./virtual.js\";\n\n/** JSON shape of the composed sourcemap returned alongside transformed code. */\nexport interface TransformSourceMap {\n version: number;\n sources: (string | null)[];\n sourcesContent?: (string | null)[];\n names: string[];\n mappings: string;\n file?: string | null;\n}\n\n/**\n * The transform pipeline as a chain of edit batches. Each batch is applied\n * to the CURRENT text through a MagicString (one stage map per batch); the\n * final original→output map is the remapping-composed chain. Deriving the\n * output string and the map from the same edit list makes divergence\n * impossible.\n */\nclass StagedTransform {\n current: string;\n private readonly source: string;\n private readonly maps: unknown[] = [];\n\n constructor(original: string, source: string) {\n this.current = original;\n this.source = source;\n }\n\n apply(edits: readonly Edit[], insert?: Insertion): void {\n this.stage(edits, (s) => {\n if (insert === undefined) return false;\n s.appendLeft(insert.offset, insert.text);\n return true;\n });\n }\n\n /**\n * Apply `edits`, then prepend `deferred`'s text to the module head — both\n * inside ONE stage.\n *\n * The head injection (runtime import + shared dedup block) has to be decided\n * from the REWRITTEN source, because `computeRuntimePrefix` probes it for\n * already-present markers. Staging it separately made a whole second\n * `generateMap` over the full generated output — for what is only a prepend at\n * the module head — and then forced `remapping` to compose the two. Together\n * those were the dominant cost of a transform: on a 320-schema project they ran\n * to 64% of total wall time, more than discovery and codegen combined. Deferring\n * the insertion into the same MagicString buys byte-identical output and an\n * equivalent map for one generation and no composition — 1.6x (small schemas)\n * to 3.4x (large ones) on the transform, scaling with how much code a file\n * emits, since that is what both costs are proportional to.\n *\n * `deferred` returns TEXT, not an `Insertion`: `appendLeft` resolves offsets\n * against the PRE-edit text while `deferred` is shown the POST-edit text, so a\n * callback-supplied offset would be in the wrong coordinate system. Deriving it\n * here from `this.current` keeps the two in step by construction.\n */\n applyThen(edits: readonly Edit[], deferred?: (rewritten: string) => string | undefined): void {\n this.stage(edits, (s, rewritten) => {\n // `?.()` short-circuits its arguments, so a stage with no deferred step\n // never materializes the rewritten text.\n const head = deferred?.(rewritten());\n if (head === undefined) return false;\n s.appendLeft(moduleHeadOffset(this.current), head);\n return true;\n });\n }\n\n /**\n * One stage: apply `edits` to a fresh MagicString, let `inject` add at most\n * one insertion, then commit the text and its map. `inject` reports whether\n * it inserted, so a no-op stage can be skipped entirely.\n *\n * `rewritten` is a thunk, not a string: materializing it costs a full\n * `toString()` over generated-code-sized input, and the injectors that do not\n * read it (every `apply()` call) must not pay for it.\n */\n private stage(\n edits: readonly Edit[],\n inject: (s: MagicString, rewritten: () => string) => boolean,\n ): void {\n const s = new MagicString(this.current);\n for (const e of edits) {\n if (e.start === e.end) {\n s.appendLeft(e.start, e.text);\n } else {\n s.overwrite(e.start, e.end, e.text);\n }\n }\n // `toString()` is the only way to show the deferred step what the rewrite\n // produced; it measured well under 1% of a transform.\n const inserted = inject(s, () => (edits.length === 0 ? this.current : s.toString()));\n if (edits.length === 0 && !inserted) return;\n this.current = s.toString();\n // `hires: \"boundary\"` is load-bearing, not a tuning knob: without it every\n // mapping collapses to column 0, so a stack frame or debugger breakpoint in\n // untouched user code below a compiled schema lands at the start of its line\n // instead of the right column (tests/unplugin/sourcemap.test.ts pins it). It\n // is also the most expensive thing here, which is why the stage COUNT is\n // what to economize on.\n this.maps.push(s.generateMap({ source: this.source, hires: \"boundary\", includeContent: true }));\n }\n\n /** Composed original→current map, or null when nothing was applied. */\n map(): TransformSourceMap | null {\n if (this.maps.length === 0) return null;\n // A single stage needs no composition: `remapping` over a one-map chain\n // reproduces that map, and it is expensive on generated-code-sized input.\n const [only] = this.maps;\n if (this.maps.length === 1) return only as TransformSourceMap;\n const chain = [...this.maps].reverse();\n return remapping(\n chain as Parameters<typeof remapping>[0],\n () => null,\n ) as unknown as TransformSourceMap;\n }\n}\n\n/**\n * Matches a runtime (non-type-only) import from \"zod\".\n *\n * One of the three triggers ZOD_MENTION (the transform hook's `code` filter)\n * must remain a superset of — widening this to a specifier that does not\n * contain \"zod\" silently strips those files from every bundler with native\n * hook filters. `describe(\"code filter soundness\")` fails if it drifts.\n */\nexport const HAS_RUNTIME_ZOD_IMPORT =\n /import\\s+(?!type\\s)[^;]*from\\s+[\"']zod(?:\\/v\\d+)?(?:[/-]mini)?[\"']/;\n\n/**\n * Opt-in phase timing (ZOD_COMPILER_TIMING=1): accumulates per-phase wall time\n * across all transform calls and prints a summary on process exit. Used to\n * attribute plugin overhead in real builds/test runs.\n */\nconst TIMING = process.env[\"ZOD_COMPILER_TIMING\"] === \"1\";\n\n/** A single file's discovery exceeding this is worth an actionable warning. */\nconst SLOW_DISCOVERY_WARN_MS = 5_000;\nconst phaseTotals = new Map<string, { ms: number; calls: number }>();\nlet timingHookInstalled = false;\n\n/** Dedupes the process.exit-during-discovery warning to one per process. */\nlet warnedProcessExit = false;\n\nfunction timePhase<T>(phase: string, fn: () => T): T {\n if (!TIMING) return fn();\n const t0 = performance.now();\n const done = (): void => {\n const dt = performance.now() - t0;\n const agg = phaseTotals.get(phase) ?? { ms: 0, calls: 0 };\n agg.ms += dt;\n agg.calls++;\n phaseTotals.set(phase, agg);\n };\n if (!timingHookInstalled) {\n timingHookInstalled = true;\n process.on(\"exit\", () => {\n const rows = [...phaseTotals.entries()].sort((a, b) => b[1].ms - a[1].ms);\n for (const [name, { ms, calls }] of rows) {\n log(`timing ${name}: ${ms.toFixed(1)}ms over ${calls} call(s)`);\n }\n });\n }\n const r = fn();\n if (r instanceof Promise) {\n return r.finally(done) as T;\n }\n done();\n return r;\n}\n\n/**\n * Check if a file should be transformed by the plugin.\n */\nexport function shouldTransform(id: string, options?: ZodCompilerPluginOptions): boolean {\n if (!/\\.[cm]?[jt]sx?$/.test(id)) return false;\n if (id.includes(\"node_modules\")) return false;\n if (id.endsWith(\".d.ts\")) return false;\n if (id.endsWith(\".compiled.ts\") || id.endsWith(\".compiled.js\")) return false;\n\n if (options?.exclude?.some((pattern) => picomatch.isMatch(id, pattern, { contains: true })))\n return false;\n if (\n options?.include &&\n !options.include.some((pattern) => picomatch.isMatch(id, pattern, { contains: true }))\n )\n return false;\n\n return true;\n}\n\n/**\n * `id` half of the transform hook filter: the option-independent checks of\n * shouldTransform(), restated as patterns the bundler can evaluate itself.\n * Rolldown, Vite and Rollup 4.40+ apply hook filters natively, so a rejected\n * module never crosses into JS; unplugin applies the same patterns in JS for\n * the rest (webpack/rspack skip installing the transform loader entirely).\n *\n * The `include`/`exclude` options stay out of the filter on purpose: they are\n * matched with picomatch's `contains: true` semantics, which the native glob\n * support (patterns resolved against cwd, matched whole) would silently\n * narrow — shouldTransform() keeps applying them inside the handler.\n */\nexport const TRANSFORM_ID_FILTER: { exclude: RegExp[]; include: RegExp[] } = {\n exclude: [/node_modules/, /\\.d\\.ts$/, /\\.compiled\\.[jt]s$/],\n include: [/\\.[cm]?[jt]sx?$/],\n};\n\n/**\n * Every transform path that can change a file needs the substring \"zod\" (or\n * \"Zod\") somewhere in the source. There are exactly three triggers, and each\n * one is pinned by `describe(\"code filter soundness\")` in the transform tests:\n *\n * 1. auto-discovery — HAS_RUNTIME_ZOD_IMPORT (above), which only matches\n * specifiers spelled \"zod…\";\n * 2. `schemas: \"explicit\"` — an import from \"zod-compiler\" (the package name);\n * 3. hoisting — a root imported from ZOD_MODULES or an identifier matching\n * SCHEMA_NAME_PATTERN (both in hoist.ts; a *custom* pattern drops this\n * filter entirely, see transformCodeFilter).\n *\n * Adding a fourth trigger that can fire without a \"zod\" mention MUST widen\n * this pattern, or those files are silently skipped on every bundler with\n * native hook filters — no error, schemas just quietly stay uncompiled.\n *\n * Spelled as a character class rather than an `i` flag: native filters\n * recompile these patterns outside JS, where flag support is narrower.\n */\nconst ZOD_MENTION = /[Zz]od/;\n\n/**\n * `code` half of the transform hook filter, or undefined when no sound filter\n * exists. A custom `hoist.schemaNamePattern` promotes arbitrary imported\n * identifiers to schema roots (`UserModel`), so nothing in such a file is\n * guaranteed to mention zod — those setups keep the unfiltered behavior.\n */\nexport function transformCodeFilter(options?: ZodCompilerPluginOptions): RegExp | undefined {\n const namePattern = typeof options?.hoist === \"object\" ? options.hoist.schemaNamePattern : null;\n // `null` disables name matching and `undefined` keeps the default\n // /ZodSchema$/ — both leave a \"zod\" mention as the only way in.\n return namePattern === null || namePattern === undefined ? ZOD_MENTION : undefined;\n}\n\nexport function log(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.log(`[zod-compiler] ${msg}`);\n}\n\nfunction warn(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.warn(`[zod-compiler] ${msg}`);\n}\n\nexport interface TransformOutput {\n code: string;\n map: TransformSourceMap | null;\n}\n\n/**\n * Transform source code by replacing compile() calls with optimized validators.\n * Returns the transformed code or null if no transformation was needed.\n * Compatibility wrapper over transformCodeWithMap() — discards the map.\n */\nexport async function transformCode(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<string | null> {\n const result = await transformCodeWithMap(code, id, options);\n return result === null ? null : result.code;\n}\n\n/**\n * transformCode + a composed sourcemap (original → output). Stack traces in\n * transformed files shift by prepended declarations and expanded IIFEs\n * without it — a vitest assertion can be reported dozens of lines off.\n */\nexport async function transformCodeWithMap(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<TransformOutput | null> {\n const verbose = options.verbose === true;\n const autoDiscover = options.autoDiscover === true;\n const mode = options.mode;\n const staged = new StagedTransform(code, id);\n\n // Hoist Zod schema construction out of function bodies to module scope\n // (babel-plugin-zod-hoist equivalent). Mode-independent: inline schemas\n // live exactly in the files that export none. hoistZodSchemasMeta() bails\n // in microseconds when no eligible imports exist.\n let hoistedSchemas: ReturnType<typeof hoistZodSchemasMeta> = null;\n if (options.hoist !== false && code.includes(\"import\")) {\n hoistedSchemas = timePhase(\"hoist\", () =>\n hoistZodSchemasMeta(code, {\n ...(typeof options.hoist === \"object\" ? options.hoist : undefined),\n onScan: options.onSubstantialWork,\n }),\n );\n if (hoistedSchemas !== null) {\n staged.apply(hoistedSchemas.edits, hoistedSchemas.insert);\n if (verbose) {\n log(`Hoisted inline Zod schemas in ${id}`);\n }\n }\n }\n\n // Compile the hoisted schemas (autoDiscover only — compiling anonymous\n // schemas is auto-discovery of unexported module-scope schemas). Each\n // hoisted `const _zh_x = z.object({...});` whose construction is\n // deterministic (eager refs are zod bindings only) is evaluated at build\n // time and its initializer replaced with the compiled validator IIFE;\n // anything ineligible stays a plain hoist.\n const hoistHelpers = new Set<string>();\n let hoistCompiledCount = 0;\n if (autoDiscover && hoistedSchemas !== null && hoistedSchemas.schemas.length > 0) {\n const hoistCompiled = await timePhase(\"hoist-compile\", () =>\n compileHoistedSchemas(hoistedSchemas.schemas, code, id, mode),\n );\n const spliceEdits: Edit[] = [];\n for (const h of hoistCompiled) {\n const decl = `const ${h.name} = ${h.text};`;\n const at = staged.current.indexOf(decl);\n if (at === -1) continue;\n const iife = generateIIFE(h.text, h.info, { zodCompat: options.zodCompat });\n spliceEdits.push({ start: at, end: at + decl.length, text: `const ${h.name} = ${iife};` });\n hoistCompiledCount++;\n for (const helper of h.info.codegenResult.usedHelpers) {\n hoistHelpers.add(helper);\n }\n if (verbose) {\n log(` ✓ ${h.name} (hoisted schema compiled)`);\n }\n }\n staged.apply(spliceEdits);\n if (hoistCompiledCount > 0) {\n hoistHelpers.add(\"__zcMkv\");\n hoistHelpers.add(\"__zcFin\");\n }\n }\n\n // When only hoisting (± hoisted-schema compilation) changed the file, that\n // is still a transform result — with runtime helpers injected if any\n // hoisted schema compiled.\n const finishHoistOnly = (): TransformOutput | null => {\n if (staged.current === code) return null;\n if (hoistCompiledCount > 0) {\n options.onBuildStats?.({\n files: 1,\n schemas: hoistedSchemas?.schemas.length ?? 0,\n optimized: hoistCompiledCount,\n failed: 0,\n });\n const prefix = computeRuntimePrefix(staged.current, hoistHelpers, mode, options.runtimeId);\n if (prefix !== null) {\n staged.applyThen([], () => prefix);\n }\n }\n return { code: staged.current, map: staged.map() };\n };\n\n // Quick bail-out check. Both gates are also encoded in the transform hook's\n // `code` filter (ZOD_MENTION) so bundlers can skip the hook call entirely —\n // relaxing either one here without widening that pattern makes the bundler\n // drop those files before this code ever runs.\n if (autoDiscover) {\n // autoDiscover: any file with a runtime Zod import is a candidate.\n // Skip `import type` — these files have no runtime schemas.\n if (!HAS_RUNTIME_ZOD_IMPORT.test(staged.current)) return finishHoistOnly();\n } else {\n // Legacy mode: require compile() from zod-compiler. The word-boundary\n // check matters: the package name itself contains the substring\n // \"compile\", so a plain includes(\"compile\") would match every import of\n // \"zod-compiler\" — \\bcompile\\b does not match inside \"zod-compiler\"\n // (no boundary between \"e\" and \"r\") but matches compile( / { compile }.\n if (!staged.current.includes(\"zod-compiler\") || !/\\bcompile\\b/.test(staged.current))\n return finishHoistOnly();\n }\n\n // Static pre-filter: skip files whose exports provably cannot be schemas\n // (functions, components, constants, type-only modules) without executing\n // them. Conservative — anything ambiguous stays a candidate. The filter\n // transpiles + parses the file, so its outcome is worth persisting even\n // when the eventual result is null.\n options.onSubstantialWork?.();\n if (!(await timePhase(\"static-filter\", () => mayExportSchemas(staged.current, id))))\n return finishHoistOnly();\n\n // Discover schemas by executing the file. Module executions are cached in\n // the shared loader; watch/HMR changes invalidate via invalidateModuleCache().\n options.onDiscovery?.();\n let schemas: DiscoveredSchema[];\n const discoverStart = performance.now();\n try {\n schemas = await timePhase(\"discover\", () => discoverSchemas(id, { autoDiscover }));\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n // A module in the import graph called process.exit() during discovery —\n // typically an env-validation guard in a CI build where secrets are\n // intentionally absent. The loader converts that exit into a catchable\n // error so the build survives; the affected files just fall back to\n // runtime Zod. Handle it in both modes (never crash on a build-time exit)\n // and surface the cooperative remedy once.\n if (e instanceof ProcessExitDuringLoadError) {\n // The result reflects missing secrets, not file content — never persist\n // it to the content-hashed disk cache (a later secret-ful build would be\n // served this stale \"nothing compiled\" entry).\n options.onUncacheableResult?.();\n if (!warnedProcessExit) {\n warnedProcessExit = true;\n warn(\n `${id} (or a module it imports) called process.exit during build-time schema ` +\n `discovery — those files fall back to runtime Zod instead of crashing the build. ` +\n `This is usually an env-validation guard; wrap it in ` +\n `\\`if (!process.env.ZOD_COMPILER) { ... }\\` to keep these schemas compiled, or set ` +\n `schemas:\"explicit\" / use include to scope discovery.`,\n );\n }\n return finishHoistOnly();\n }\n // In autoDiscover mode, files that can't be loaded (JSX components,\n // unresolved path aliases, etc.) are expected — warn and skip.\n if (autoDiscover) {\n if (verbose) {\n warn(`Skipping ${id}: ${msg}`);\n }\n return finishHoistOnly();\n }\n throw new Error(`[zod-compiler] Failed to load schemas from ${id}: ${msg}`);\n }\n const discoverMs = performance.now() - discoverStart;\n if (discoverMs >= SLOW_DISCOVERY_WARN_MS) {\n // Discovery executes the file's whole first-party import graph inside\n // the bundler's single-threaded process — on saturated CI hosts a large\n // graph can stall the event loop long enough to trip test timeouts.\n // Surface the cost with the two effective remedies.\n warn(\n `Discovery of ${id} took ${(discoverMs / 1000).toFixed(1)}s executing its import graph ` +\n `in the bundler process. Persist node_modules/.cache/zod-compiler across CI runs to pay ` +\n `this once, or narrow autoDiscover/include for test runs (see README \"Large projects ` +\n `and CI\"). ZOD_COMPILER_TIMING=1 prints a per-phase breakdown.`,\n );\n }\n if (schemas.length === 0) return finishHoistOnly();\n\n // Lean mode (every bundler in VIRTUAL_MODULE_FRAMEWORKS — Vite/Rollup/webpack/rspack/etc.)\n // imports shared helpers from a runtime module for cross-file dedup: virtual:zod-compiler/runtime\n // on virtual-friendly bundlers, the __zod-compiler-runtime__ bare specifier on webpack/rspack.\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS) emits self-contained\n // file-level helpers.\n let failedCount = 0;\n const { schemas: compiled, shared } = timePhase(\"compile\", () =>\n compileSchemas(schemas, {\n mode,\n compact: options.compact,\n onError(exportName, error) {\n failedCount++;\n warn(\n `Failed to compile \"${exportName}\" in ${id}: ${error.message}. Keeping original${autoDiscover ? \"\" : \" compile()\"} call.`,\n );\n },\n }),\n );\n\n if (verbose) {\n if (autoDiscover) {\n log(\n `Auto-discovering: ${id} (${schemas.length} Zod export${schemas.length > 1 ? \"s\" : \"\"} found)`,\n );\n }\n for (const s of compiled) {\n const rfCount = s.refEntries.length;\n const rfSuffix = rfCount > 0 ? ` (${rfCount} ref${rfCount > 1 ? \"s\" : \"\"})` : \"\";\n log(` ✓ ${s.exportName}${rfSuffix}`);\n }\n if (failedCount > 0) {\n log(` ✗ ${failedCount} schema(s) failed`);\n }\n }\n\n if (compiled.length === 0) return finishHoistOnly();\n\n // Report build stats only when at least one schema was compiled\n // (hoisted-schema compiles count alongside export schemas).\n options.onBuildStats?.({\n files: 1,\n schemas: schemas.length + (hoistedSchemas?.schemas.length ?? 0),\n optimized: compiled.length + hoistCompiledCount,\n failed: failedCount,\n });\n\n // __zcMkv and __zcFin are always needed (they wrap every IIFE). Helpers used\n // by compiled hoisted schemas ride along in the same injection.\n const usedHelpers = aggregateUsedHelpers(compiled);\n usedHelpers.add(\"__zcMkv\");\n usedHelpers.add(\"__zcFin\");\n for (const helper of hoistHelpers) {\n usedHelpers.add(helper);\n }\n // Shared dedup validators ride the same runtime import.\n for (const helper of shared.usedHelpers) {\n usedHelpers.add(helper);\n }\n\n // Two-pass rewrite: separate compile() schemas from autoDiscover schemas.\n // Both passes collect edits against the same pristine stage input — their\n // target regions are disjoint (compile() assignments vs plain exported\n // declarations of OTHER names), so one batched application is equivalent\n // to the historical sequential rewrites.\n let rewriteEdits: readonly Edit[];\n if (autoDiscover) {\n // Detect compile() schemas by checking source code patterns\n const compileExportNames = new Set<string>();\n for (const s of compiled) {\n const pattern = new RegExp(`\\\\b${s.exportName}\\\\s*=\\\\s*compile[\\\\s<(]`);\n if (pattern.test(staged.current)) {\n compileExportNames.add(s.exportName);\n }\n }\n const compileSchemaInfos = compiled.filter((s) => compileExportNames.has(s.exportName));\n const autoDiscoverSchemaInfos = compiled.filter((s) => !compileExportNames.has(s.exportName));\n\n const edits: Edit[] = [];\n // Pass 1: compile() schemas (includes compile-import removal — only when\n // compile() schemas were actually rewritten, mirroring the historical\n // conditional rewriteSource call)\n if (compileSchemaInfos.length > 0) {\n edits.push(\n ...collectCompileRewriteEdits(staged.current, compileSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n // Pass 2: plain exported schemas\n if (autoDiscoverSchemaInfos.length > 0) {\n edits.push(\n ...collectAutoDiscoverEdits(staged.current, autoDiscoverSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n rewriteEdits = edits;\n } else {\n rewriteEdits = collectCompileRewriteEdits(staged.current, compiled, {\n zodCompat: options.zodCompat,\n });\n }\n\n // Head = runtime helpers/import, then the file-level shared dedup block, then\n // the rewritten source. Shared constants and `__zcSw_N` functions live at\n // module scope so every IIFE closes over them; they must follow the runtime\n // import (lean) and the helper decls (inline) that they reference. Guard against\n // double-injection on watch/HMR re-runs the same way computeRuntimePrefix\n // does — a second copy would redeclare every `__zcSw_N`.\n //\n // Deferred into the rewrite's own stage rather than staged after it: both\n // decisions read the REWRITTEN text, and giving a bare prepend its own stage\n // doubled the sourcemap work and added a composition pass (see applyThen).\n staged.applyThen(rewriteEdits, (rewritten) => {\n const prefix = computeRuntimePrefix(rewritten, usedHelpers, mode, options.runtimeId);\n const needsShared = shared.code !== \"\" && !rewritten.includes(SHARED_BLOCK_MARKER);\n const head = (prefix ?? \"\") + (needsShared ? `${shared.code}\\n` : \"\");\n return head === \"\" ? undefined : head;\n });\n return { code: staged.current, map: staged.map() };\n}\n\n/**\n * Prepend the runtime helpers required by the rewritten source.\n *\n * Lean mode emits a single `import { ... } from \"<runtimeId>\";` line —\n * bundlers whose resolveId hook intercepts the specifier dedup helpers across\n * every transformed file into one shared virtual module.\n *\n * Inline mode prepends file-level `function __zcMkv` / `function __zcFin`\n * declarations directly so the file is self-contained.\n *\n * Idempotent: if the file already contains the relevant marker (re-run during\n * watch/HMR), we skip re-injection.\n */\n/** The runtime-helper text to prepend, or null when nothing is needed. */\nfunction computeRuntimePrefix(\n code: string,\n usedHelpers: Set<string>,\n mode: CodegenMode,\n runtimeId: string = VIRTUAL_RUNTIME_ID,\n): string | null {\n if (mode === \"lean\") {\n if (usedHelpers.size === 0) return null;\n // Match the import STATEMENT, not the bare id. `zod-compiler/runtime` is a\n // plain package specifier and a substring of `virtual:zod-compiler/runtime`,\n // so a file merely mentioning either — a comment, a docs snippet — would\n // suppress the import while codegen still emits calls to the helpers.\n if (code.includes(`from \"${runtimeId}\"`)) return null;\n const names = [...usedHelpers].sort().join(\", \");\n return `import { ${names} } from \"${runtimeId}\";\\n`;\n }\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS):\n // ship file-level helper declarations instead of a virtual import.\n // Codegen emits per-IIFE issue literals + per-IIFE `__re_*` decls,\n // so we only need __zcMkv / __zcFin (plus __zcMsg via the zod config import).\n if (!code.includes(\"__zcMkv\")) return null;\n const prefix: string[] = [];\n if (!code.includes(\"__zodCompilerConfig\")) {\n prefix.push(ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION);\n }\n if (!code.includes(\"function __zcMkv(\")) {\n prefix.push(MK_VALIDATOR_DECL);\n }\n // __zcFin and __zcFinD both construct __ZcFail; declare it once before either,\n // guarding against a header already shipped earlier in the same module.\n const needsFin = !code.includes(\"function __zcFin(\");\n const needsFinD = code.includes(\"__zcFinD(\") && !code.includes(\"function __zcFinD(\");\n if ((needsFin || needsFinD) && !code.includes(\"function __ZcFail(\")) {\n prefix.push(FAIL_CLASS_DECL);\n }\n if (needsFin) {\n prefix.push(FIN_DECL);\n }\n if (needsFinD) {\n prefix.push(FIN_DEFERRED_DECL);\n }\n // Compact mode (output: \"compact\") delegates cold errors to zod via __zcFinZ,\n // which constructs its own __ZcFailZ (distinct from __ZcFail).\n const needsFinZ = code.includes(\"__zcFinZ(\") && !code.includes(\"function __zcFinZ(\");\n if (needsFinZ && !code.includes(\"function __ZcFailZ(\")) {\n prefix.push(FAILZ_CLASS_DECL);\n }\n if (needsFinZ) {\n prefix.push(FINZ_DECL);\n }\n return prefix.length > 0 ? `${prefix.join(\"\\n\")}\\n` : null;\n}\n\n/**\n * Find the matching closing parenthesis for a compile() call,\n * handling nested parentheses like compile(z.object({...})).\n * Returns the index of the closing ')' or -1 if not found.\n */\nfunction findMatchingParen(code: string, openIndex: number): number {\n let depth = 1;\n for (let i = openIndex + 1; i < code.length; i++) {\n if (code[i] === \"(\") depth++;\n else if (code[i] === \")\") {\n depth--;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\n/**\n * Rewrite source code by replacing compile() calls with IIFE-wrapped optimized validators.\n */\nexport function rewriteSource(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectCompileRewriteEdits(code, schemas, options));\n}\n\n/**\n * Edits for rewriteSource (compile() call replacements + compile-import\n * removal), collected against pristine `code`. Each schema's declaration is\n * a distinct region and the import statement is distinct from all of them,\n * so the batch is non-overlapping and order-independent.\n */\nfunction collectCompileRewriteEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n // Match: <exportName> = compile<...>( with word boundary to prevent substring matches\n const prefixPattern = new RegExp(\n `(\\\\b${schema.exportName}\\\\s*=\\\\s*)compile\\\\s*(?:<[^>]*(?:<[^>]*>[^>]*)?>)?\\\\s*\\\\(`,\n );\n const match = prefixPattern.exec(code);\n if (!match) continue;\n\n // Find the matching closing paren (handles nested parens)\n const openParenIndex = match.index + match[0].length - 1;\n const closeParenIndex = findMatchingParen(code, openParenIndex);\n if (closeParenIndex === -1) continue;\n\n const schemaArgName = code\n .slice(openParenIndex + 1, closeParenIndex)\n .trim()\n .replace(/,\\s*$/, \"\");\n const prefix = match[1] ?? \"\";\n edits.push({\n start: match.index,\n end: closeParenIndex + 1,\n text: prefix + generateIIFE(schemaArgName, schema, options),\n });\n }\n edits.push(...collectRemoveCompileImportEdits(code));\n return edits;\n}\n\n/**\n * Find the end position of a JavaScript expression starting at `start` using acorn.\n * Returns the end offset, or -1 if the expression cannot be parsed.\n */\nexport function findExpressionEnd(code: string, start: number): number {\n try {\n const node = parseExpressionAt(code, start, {\n ecmaVersion: \"latest\",\n sourceType: \"module\",\n });\n return node.end;\n } catch {\n return -1;\n }\n}\n\n/**\n * Rewrite source code by replacing plain Zod schema exports with IIFE-wrapped optimized validators.\n * Used by autoDiscover mode (no compile() wrappers needed).\n */\nexport function rewriteSourceAutoDiscover(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectAutoDiscoverEdits(code, schemas, options));\n}\n\n/** Edits for rewriteSourceAutoDiscover, collected against pristine `code`. */\nfunction collectAutoDiscoverEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n const escapedName = schema.exportName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // Match: export? (const|let|var) ExportName[: TypeAnnotation] = <expr>\n const assignPattern = new RegExp(\n `((?:export\\\\s+)?(?:const|let|var)\\\\s+${escapedName}(?:\\\\s*:[^=]*)?\\\\s*=\\\\s*)`,\n );\n const match = assignPattern.exec(code);\n if (!match) continue;\n\n const rhsStart = match.index + match[0].length;\n const rhsEnd = findExpressionEnd(code, rhsStart);\n if (rhsEnd === -1) continue;\n\n const originalExpr = code.slice(rhsStart, rhsEnd).trim();\n edits.push({\n start: rhsStart,\n end: rhsEnd,\n text: generateIIFE(originalExpr, schema, options),\n });\n }\n return edits;\n}\n\n/**\n * Remove the `compile` binding from `import { compile, ... } from \"zod-compiler\"` statements.\n * If `compile` is the only import, the entire import line is removed.\n */\nexport function removeCompileImport(code: string): string {\n return applyEdits(code, collectRemoveCompileImportEdits(code));\n}\n\n/** Edits stripping the `compile` binding from zod-compiler import statements. */\nfunction collectRemoveCompileImportEdits(code: string): Edit[] {\n // Match: import { ... } from \"zod-compiler\" or 'zod-compiler'\n const importPattern = /import\\s*\\{([^}]*)\\}\\s*from\\s*[\"']zod-compiler[\"'];?/g;\n const edits: Edit[] = [];\n for (const match of code.matchAll(importPattern)) {\n const imports = match[1] ?? \"\";\n const names = imports\n .split(\",\")\n .map((n) => n.trim())\n .filter(Boolean);\n const remaining = names.filter((n) => n !== \"compile\");\n const text =\n remaining.length === 0 ? \"\" : `import { ${remaining.join(\", \")} } from \"zod-compiler\";`;\n if (text !== match[0]) {\n edits.push({ start: match.index, end: match.index + match[0].length, text });\n }\n }\n return edits;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transform.js","names":[],"sources":["../../src/unplugin/transform.ts"],"sourcesContent":["import remapping from \"@jridgewell/remapping\";\nimport { parseExpressionAt } from \"acorn\";\nimport MagicString from \"magic-string\";\nimport picomatch from \"picomatch\";\nimport type { CodegenMode } from \"../core/codegen/context.js\";\nimport { SHARED_BLOCK_MARKER } from \"../core/codegen/dedupe.js\";\nimport {\n FAIL_CLASS_DECL,\n FAILZ_CLASS_DECL,\n FIN_DECL,\n FIN_DEFERRED_DECL,\n FINZ_DECL,\n generateIIFE,\n iifeDerefsSchema,\n MK_VALIDATOR_DECL,\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n} from \"../core/iife.js\";\nimport { aggregateUsedHelpers, type CompiledSchemaInfo, compileSchemas } from \"../core/pipeline.js\";\nimport type { DiscoveredSchema } from \"../core/types.js\";\nimport { discoverSchemas } from \"../discovery.js\";\nimport { ProcessExitDuringLoadError } from \"../loader.js\";\nimport { mayExportSchemas } from \"../static-filter.js\";\nimport { applyEdits, type Edit, type Insertion, moduleHeadOffset } from \"./edits.js\";\nimport { hoistZodSchemasMeta } from \"./hoist.js\";\nimport { compileHoistedSchemas } from \"./hoist-compile.js\";\nimport type { TransformOptions, ZodCompilerPluginOptions } from \"./types.js\";\nimport { VIRTUAL_RUNTIME_ID } from \"./virtual.js\";\n\n/** JSON shape of the composed sourcemap returned alongside transformed code. */\nexport interface TransformSourceMap {\n version: number;\n sources: (string | null)[];\n sourcesContent?: (string | null)[];\n names: string[];\n mappings: string;\n file?: string | null;\n}\n\n/**\n * The transform pipeline as a chain of edit batches. Each batch is applied\n * to the CURRENT text through a MagicString (one stage map per batch); the\n * final original→output map is the remapping-composed chain. Deriving the\n * output string and the map from the same edit list makes divergence\n * impossible.\n */\nclass StagedTransform {\n current: string;\n private readonly source: string;\n private readonly maps: unknown[] = [];\n\n constructor(original: string, source: string) {\n this.current = original;\n this.source = source;\n }\n\n apply(edits: readonly Edit[], insert?: Insertion): void {\n this.stage(edits, (s) => {\n if (insert === undefined) return false;\n s.appendLeft(insert.offset, insert.text);\n return true;\n });\n }\n\n /**\n * Apply `edits`, then prepend `deferred`'s text to the module head — both\n * inside ONE stage.\n *\n * The head injection (runtime import + shared dedup block) has to be decided\n * from the REWRITTEN source, because `computeRuntimePrefix` probes it for\n * already-present markers. Staging it separately made a whole second\n * `generateMap` over the full generated output — for what is only a prepend at\n * the module head — and then forced `remapping` to compose the two. Together\n * those were the dominant cost of a transform: on a 320-schema project they ran\n * to 64% of total wall time, more than discovery and codegen combined. Deferring\n * the insertion into the same MagicString buys byte-identical output and an\n * equivalent map for one generation and no composition — 1.6x (small schemas)\n * to 3.4x (large ones) on the transform, scaling with how much code a file\n * emits, since that is what both costs are proportional to.\n *\n * `deferred` returns TEXT, not an `Insertion`: `appendLeft` resolves offsets\n * against the PRE-edit text while `deferred` is shown the POST-edit text, so a\n * callback-supplied offset would be in the wrong coordinate system. Deriving it\n * here from `this.current` keeps the two in step by construction.\n */\n applyThen(edits: readonly Edit[], deferred?: (rewritten: string) => string | undefined): void {\n this.stage(edits, (s, rewritten) => {\n // `?.()` short-circuits its arguments, so a stage with no deferred step\n // never materializes the rewritten text.\n const head = deferred?.(rewritten());\n if (head === undefined) return false;\n s.appendLeft(moduleHeadOffset(this.current), head);\n return true;\n });\n }\n\n /**\n * One stage: apply `edits` to a fresh MagicString, let `inject` add at most\n * one insertion, then commit the text and its map. `inject` reports whether\n * it inserted, so a no-op stage can be skipped entirely.\n *\n * `rewritten` is a thunk, not a string: materializing it costs a full\n * `toString()` over generated-code-sized input, and the injectors that do not\n * read it (every `apply()` call) must not pay for it.\n */\n private stage(\n edits: readonly Edit[],\n inject: (s: MagicString, rewritten: () => string) => boolean,\n ): void {\n const s = new MagicString(this.current);\n for (const e of edits) {\n if (e.start === e.end) {\n s.appendLeft(e.start, e.text);\n } else {\n s.overwrite(e.start, e.end, e.text);\n }\n }\n // `toString()` is the only way to show the deferred step what the rewrite\n // produced; it measured well under 1% of a transform.\n const inserted = inject(s, () => (edits.length === 0 ? this.current : s.toString()));\n if (edits.length === 0 && !inserted) return;\n this.current = s.toString();\n // `hires: \"boundary\"` is load-bearing, not a tuning knob: without it every\n // mapping collapses to column 0, so a stack frame or debugger breakpoint in\n // untouched user code below a compiled schema lands at the start of its line\n // instead of the right column (tests/unplugin/sourcemap.test.ts pins it). It\n // is also the most expensive thing here, which is why the stage COUNT is\n // what to economize on.\n this.maps.push(s.generateMap({ source: this.source, hires: \"boundary\", includeContent: true }));\n }\n\n /** Composed original→current map, or null when nothing was applied. */\n map(): TransformSourceMap | null {\n if (this.maps.length === 0) return null;\n // A single stage needs no composition: `remapping` over a one-map chain\n // reproduces that map, and it is expensive on generated-code-sized input.\n const [only] = this.maps;\n if (this.maps.length === 1) return only as TransformSourceMap;\n const chain = [...this.maps].reverse();\n return remapping(\n chain as Parameters<typeof remapping>[0],\n () => null,\n ) as unknown as TransformSourceMap;\n }\n}\n\n/**\n * Matches a runtime (non-type-only) import from \"zod\".\n *\n * One of the three triggers ZOD_MENTION (the transform hook's `code` filter)\n * must remain a superset of — widening this to a specifier that does not\n * contain \"zod\" silently strips those files from every bundler with native\n * hook filters. `describe(\"code filter soundness\")` fails if it drifts.\n */\nexport const HAS_RUNTIME_ZOD_IMPORT =\n /import\\s+(?!type\\s)[^;]*from\\s+[\"']zod(?:\\/v\\d+)?(?:[/-]mini)?[\"']/;\n\n/**\n * Opt-in phase timing (ZOD_COMPILER_TIMING=1): accumulates per-phase wall time\n * across all transform calls and prints a summary on process exit. Used to\n * attribute plugin overhead in real builds/test runs.\n */\nconst TIMING = process.env[\"ZOD_COMPILER_TIMING\"] === \"1\";\n\n/** A single file's discovery exceeding this is worth an actionable warning. */\nconst SLOW_DISCOVERY_WARN_MS = 5_000;\nconst phaseTotals = new Map<string, { ms: number; calls: number }>();\nlet timingHookInstalled = false;\n\n/** Dedupes the process.exit-during-discovery warning to one per process. */\nlet warnedProcessExit = false;\n\nfunction timePhase<T>(phase: string, fn: () => T): T {\n if (!TIMING) return fn();\n const t0 = performance.now();\n const done = (): void => {\n const dt = performance.now() - t0;\n const agg = phaseTotals.get(phase) ?? { ms: 0, calls: 0 };\n agg.ms += dt;\n agg.calls++;\n phaseTotals.set(phase, agg);\n };\n if (!timingHookInstalled) {\n timingHookInstalled = true;\n process.on(\"exit\", () => {\n const rows = [...phaseTotals.entries()].sort((a, b) => b[1].ms - a[1].ms);\n for (const [name, { ms, calls }] of rows) {\n log(`timing ${name}: ${ms.toFixed(1)}ms over ${calls} call(s)`);\n }\n });\n }\n const r = fn();\n if (r instanceof Promise) {\n return r.finally(done) as T;\n }\n done();\n return r;\n}\n\n/**\n * Check if a file should be transformed by the plugin.\n */\nexport function shouldTransform(id: string, options?: ZodCompilerPluginOptions): boolean {\n if (!/\\.[cm]?[jt]sx?$/.test(id)) return false;\n if (id.includes(\"node_modules\")) return false;\n if (id.endsWith(\".d.ts\")) return false;\n if (id.endsWith(\".compiled.ts\") || id.endsWith(\".compiled.js\")) return false;\n\n if (options?.exclude?.some((pattern) => picomatch.isMatch(id, pattern, { contains: true })))\n return false;\n if (\n options?.include &&\n !options.include.some((pattern) => picomatch.isMatch(id, pattern, { contains: true }))\n )\n return false;\n\n return true;\n}\n\n/**\n * `id` half of the transform hook filter: the option-independent checks of\n * shouldTransform(), restated as patterns the bundler can evaluate itself.\n * Rolldown, Vite and Rollup 4.40+ apply hook filters natively, so a rejected\n * module never crosses into JS; unplugin applies the same patterns in JS for\n * the rest (webpack/rspack skip installing the transform loader entirely).\n *\n * The `include`/`exclude` options stay out of the filter on purpose: they are\n * matched with picomatch's `contains: true` semantics, which the native glob\n * support (patterns resolved against cwd, matched whole) would silently\n * narrow — shouldTransform() keeps applying them inside the handler.\n */\nexport const TRANSFORM_ID_FILTER: { exclude: RegExp[]; include: RegExp[] } = {\n exclude: [/node_modules/, /\\.d\\.ts$/, /\\.compiled\\.[jt]s$/],\n include: [/\\.[cm]?[jt]sx?$/],\n};\n\n/**\n * Every transform path that can change a file needs the substring \"zod\" (or\n * \"Zod\") somewhere in the source. There are exactly three triggers, and each\n * one is pinned by `describe(\"code filter soundness\")` in the transform tests:\n *\n * 1. auto-discovery — HAS_RUNTIME_ZOD_IMPORT (above), which only matches\n * specifiers spelled \"zod…\";\n * 2. `schemas: \"explicit\"` — an import from \"zod-compiler\" (the package name);\n * 3. hoisting — a root imported from ZOD_MODULES or an identifier matching\n * SCHEMA_NAME_PATTERN (both in hoist.ts; a *custom* pattern drops this\n * filter entirely, see transformCodeFilter).\n *\n * Adding a fourth trigger that can fire without a \"zod\" mention MUST widen\n * this pattern, or those files are silently skipped on every bundler with\n * native hook filters — no error, schemas just quietly stay uncompiled.\n *\n * Spelled as a character class rather than an `i` flag: native filters\n * recompile these patterns outside JS, where flag support is narrower.\n */\nconst ZOD_MENTION = /[Zz]od/;\n\n/**\n * `code` half of the transform hook filter, or undefined when no sound filter\n * exists. A custom `hoist.schemaNamePattern` promotes arbitrary imported\n * identifiers to schema roots (`UserModel`), so nothing in such a file is\n * guaranteed to mention zod — those setups keep the unfiltered behavior.\n */\nexport function transformCodeFilter(options?: ZodCompilerPluginOptions): RegExp | undefined {\n const namePattern = typeof options?.hoist === \"object\" ? options.hoist.schemaNamePattern : null;\n // `null` disables name matching and `undefined` keeps the default\n // /ZodSchema$/ — both leave a \"zod\" mention as the only way in.\n return namePattern === null || namePattern === undefined ? ZOD_MENTION : undefined;\n}\n\nexport function log(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.log(`[zod-compiler] ${msg}`);\n}\n\nfunction warn(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.warn(`[zod-compiler] ${msg}`);\n}\n\nexport interface TransformOutput {\n code: string;\n map: TransformSourceMap | null;\n}\n\n/**\n * Transform source code by replacing compile() calls with optimized validators.\n * Returns the transformed code or null if no transformation was needed.\n * Compatibility wrapper over transformCodeWithMap() — discards the map.\n */\nexport async function transformCode(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<string | null> {\n const result = await transformCodeWithMap(code, id, options);\n return result === null ? null : result.code;\n}\n\n/**\n * transformCode + a composed sourcemap (original → output). Stack traces in\n * transformed files shift by prepended declarations and expanded IIFEs\n * without it — a vitest assertion can be reported dozens of lines off.\n */\nexport async function transformCodeWithMap(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<TransformOutput | null> {\n const verbose = options.verbose === true;\n const autoDiscover = options.autoDiscover === true;\n const mode = options.mode;\n const staged = new StagedTransform(code, id);\n\n // Hoist Zod schema construction out of function bodies to module scope\n // (babel-plugin-zod-hoist equivalent). Mode-independent: inline schemas\n // live exactly in the files that export none. hoistZodSchemasMeta() bails\n // in microseconds when no eligible imports exist.\n let hoistedSchemas: ReturnType<typeof hoistZodSchemasMeta> = null;\n if (options.hoist !== false && code.includes(\"import\")) {\n hoistedSchemas = timePhase(\"hoist\", () =>\n hoistZodSchemasMeta(code, {\n ...(typeof options.hoist === \"object\" ? options.hoist : undefined),\n onScan: options.onSubstantialWork,\n }),\n );\n if (hoistedSchemas !== null) {\n staged.apply(hoistedSchemas.edits, hoistedSchemas.insert);\n if (verbose) {\n log(`Hoisted inline Zod schemas in ${id}`);\n }\n }\n }\n\n // Compile the hoisted schemas (autoDiscover only — compiling anonymous\n // schemas is auto-discovery of unexported module-scope schemas). Each\n // hoisted `const _zh_x = z.object({...});` whose construction is\n // deterministic (eager refs are zod bindings only) is evaluated at build\n // time and its initializer replaced with the compiled validator IIFE;\n // anything ineligible stays a plain hoist.\n const hoistHelpers = new Set<string>();\n let hoistCompiledCount = 0;\n if (autoDiscover && hoistedSchemas !== null && hoistedSchemas.schemas.length > 0) {\n const hoistCompiled = await timePhase(\"hoist-compile\", () =>\n compileHoistedSchemas(hoistedSchemas.schemas, code, id, mode),\n );\n const spliceEdits: Edit[] = [];\n for (const h of hoistCompiled) {\n const decl = `const ${h.name} = ${h.text};`;\n const at = staged.current.indexOf(decl);\n if (at === -1) continue;\n const iife = generateIIFE(h.text, h.info, { zodCompat: options.zodCompat });\n spliceEdits.push({ start: at, end: at + decl.length, text: `const ${h.name} = ${iife};` });\n hoistCompiledCount++;\n for (const helper of h.info.codegenResult.usedHelpers) {\n hoistHelpers.add(helper);\n }\n if (verbose) {\n log(` ✓ ${h.name} (hoisted schema compiled)`);\n }\n }\n staged.apply(spliceEdits);\n if (hoistCompiledCount > 0) {\n hoistHelpers.add(\"__zcMkv\");\n hoistHelpers.add(\"__zcFin\");\n }\n }\n\n // When only hoisting (± hoisted-schema compilation) changed the file, that\n // is still a transform result — with runtime helpers injected if any\n // hoisted schema compiled.\n const finishHoistOnly = (): TransformOutput | null => {\n if (staged.current === code) return null;\n if (hoistCompiledCount > 0) {\n options.onBuildStats?.({\n files: 1,\n schemas: hoistedSchemas?.schemas.length ?? 0,\n optimized: hoistCompiledCount,\n failed: 0,\n });\n const prefix = computeRuntimePrefix(staged.current, hoistHelpers, mode, options.runtimeId);\n if (prefix !== null) {\n staged.applyThen([], () => prefix);\n }\n }\n return { code: staged.current, map: staged.map() };\n };\n\n // Quick bail-out check. Both gates are also encoded in the transform hook's\n // `code` filter (ZOD_MENTION) so bundlers can skip the hook call entirely —\n // relaxing either one here without widening that pattern makes the bundler\n // drop those files before this code ever runs.\n if (autoDiscover) {\n // autoDiscover: any file with a runtime Zod import is a candidate.\n // Skip `import type` — these files have no runtime schemas.\n if (!HAS_RUNTIME_ZOD_IMPORT.test(staged.current)) return finishHoistOnly();\n } else {\n // Legacy mode: require compile() from zod-compiler. The word-boundary\n // check matters: the package name itself contains the substring\n // \"compile\", so a plain includes(\"compile\") would match every import of\n // \"zod-compiler\" — \\bcompile\\b does not match inside \"zod-compiler\"\n // (no boundary between \"e\" and \"r\") but matches compile( / { compile }.\n if (!staged.current.includes(\"zod-compiler\") || !/\\bcompile\\b/.test(staged.current))\n return finishHoistOnly();\n }\n\n // Static pre-filter: skip files whose exports provably cannot be schemas\n // (functions, components, constants, type-only modules) without executing\n // them. Conservative — anything ambiguous stays a candidate. The filter\n // transpiles + parses the file, so its outcome is worth persisting even\n // when the eventual result is null.\n options.onSubstantialWork?.();\n if (!(await timePhase(\"static-filter\", () => mayExportSchemas(staged.current, id))))\n return finishHoistOnly();\n\n // Discover schemas by executing the file. Module executions are cached in\n // the shared loader; watch/HMR changes invalidate via invalidateModuleCache().\n options.onDiscovery?.();\n let schemas: DiscoveredSchema[];\n const discoverStart = performance.now();\n try {\n schemas = await timePhase(\"discover\", () => discoverSchemas(id, { autoDiscover }));\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n // A module in the import graph called process.exit() during discovery —\n // typically an env-validation guard in a CI build where secrets are\n // intentionally absent. The loader converts that exit into a catchable\n // error so the build survives; the affected files just fall back to\n // runtime Zod. Handle it in both modes (never crash on a build-time exit)\n // and surface the cooperative remedy once.\n if (e instanceof ProcessExitDuringLoadError) {\n // The result reflects missing secrets, not file content — never persist\n // it to the content-hashed disk cache (a later secret-ful build would be\n // served this stale \"nothing compiled\" entry).\n options.onUncacheableResult?.();\n if (!warnedProcessExit) {\n warnedProcessExit = true;\n warn(\n `${id} (or a module it imports) called process.exit during build-time schema ` +\n `discovery — those files fall back to runtime Zod instead of crashing the build. ` +\n `This is usually an env-validation guard; wrap it in ` +\n `\\`if (!process.env.ZOD_COMPILER) { ... }\\` to keep these schemas compiled, or set ` +\n `schemas:\"explicit\" / use include to scope discovery.`,\n );\n }\n return finishHoistOnly();\n }\n // In autoDiscover mode, files that can't be loaded (JSX components,\n // unresolved path aliases, etc.) are expected — warn and skip.\n if (autoDiscover) {\n if (verbose) {\n warn(`Skipping ${id}: ${msg}`);\n }\n return finishHoistOnly();\n }\n throw new Error(`[zod-compiler] Failed to load schemas from ${id}: ${msg}`);\n }\n const discoverMs = performance.now() - discoverStart;\n if (discoverMs >= SLOW_DISCOVERY_WARN_MS) {\n // Discovery executes the file's whole first-party import graph inside\n // the bundler's single-threaded process — on saturated CI hosts a large\n // graph can stall the event loop long enough to trip test timeouts.\n // Surface the cost with the two effective remedies.\n warn(\n `Discovery of ${id} took ${(discoverMs / 1000).toFixed(1)}s executing its import graph ` +\n `in the bundler process. Persist node_modules/.cache/zod-compiler across CI runs to pay ` +\n `this once, or narrow autoDiscover/include for test runs (see README \"Large projects ` +\n `and CI\"). ZOD_COMPILER_TIMING=1 prints a per-phase breakdown.`,\n );\n }\n if (schemas.length === 0) return finishHoistOnly();\n\n // Lean mode (every bundler in VIRTUAL_MODULE_FRAMEWORKS — Vite/Rollup/webpack/rspack/etc.)\n // imports shared helpers from a runtime module for cross-file dedup: virtual:zod-compiler/runtime\n // on virtual-friendly bundlers, the __zod-compiler-runtime__ bare specifier on webpack/rspack.\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS) emits self-contained\n // file-level helpers.\n let failedCount = 0;\n const { schemas: compiled, shared } = timePhase(\"compile\", () =>\n compileSchemas(schemas, {\n mode,\n compact: options.compact,\n onError(exportName, error) {\n failedCount++;\n warn(\n `Failed to compile \"${exportName}\" in ${id}: ${error.message}. Keeping original${autoDiscover ? \"\" : \" compile()\"} call.`,\n );\n },\n }),\n );\n\n if (verbose) {\n if (autoDiscover) {\n log(\n `Auto-discovering: ${id} (${schemas.length} Zod export${schemas.length > 1 ? \"s\" : \"\"} found)`,\n );\n }\n for (const s of compiled) {\n const rfCount = s.refEntries.length;\n const rfSuffix = rfCount > 0 ? ` (${rfCount} ref${rfCount > 1 ? \"s\" : \"\"})` : \"\";\n log(` ✓ ${s.exportName}${rfSuffix}`);\n }\n if (failedCount > 0) {\n log(` ✗ ${failedCount} schema(s) failed`);\n }\n }\n\n if (compiled.length === 0) return finishHoistOnly();\n\n // Report build stats only when at least one schema was compiled\n // (hoisted-schema compiles count alongside export schemas).\n options.onBuildStats?.({\n files: 1,\n schemas: schemas.length + (hoistedSchemas?.schemas.length ?? 0),\n optimized: compiled.length + hoistCompiledCount,\n failed: failedCount,\n });\n\n // __zcMkv and __zcFin are always needed (they wrap every IIFE). Helpers used\n // by compiled hoisted schemas ride along in the same injection.\n const usedHelpers = aggregateUsedHelpers(compiled);\n usedHelpers.add(\"__zcMkv\");\n usedHelpers.add(\"__zcFin\");\n for (const helper of hoistHelpers) {\n usedHelpers.add(helper);\n }\n // Shared dedup validators ride the same runtime import.\n for (const helper of shared.usedHelpers) {\n usedHelpers.add(helper);\n }\n\n // Two-pass rewrite: separate compile() schemas from autoDiscover schemas.\n // Both passes collect edits against the same pristine stage input — their\n // target regions are disjoint (compile() assignments vs plain exported\n // declarations of OTHER names), so one batched application is equivalent\n // to the historical sequential rewrites.\n let rewriteEdits: readonly Edit[];\n if (autoDiscover) {\n // Detect compile() schemas by checking source code patterns\n const compileExportNames = new Set<string>();\n for (const s of compiled) {\n const pattern = new RegExp(`\\\\b${s.exportName}\\\\s*=\\\\s*compile[\\\\s<(]`);\n if (pattern.test(staged.current)) {\n compileExportNames.add(s.exportName);\n }\n }\n const compileSchemaInfos = compiled.filter((s) => compileExportNames.has(s.exportName));\n const autoDiscoverSchemaInfos = compiled.filter((s) => !compileExportNames.has(s.exportName));\n\n const edits: Edit[] = [];\n // Pass 1: compile() schemas (includes compile-import removal — only when\n // compile() schemas were actually rewritten, mirroring the historical\n // conditional rewriteSource call)\n if (compileSchemaInfos.length > 0) {\n edits.push(\n ...collectCompileRewriteEdits(staged.current, compileSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n // Pass 2: plain exported schemas\n if (autoDiscoverSchemaInfos.length > 0) {\n edits.push(\n ...collectAutoDiscoverEdits(staged.current, autoDiscoverSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n rewriteEdits = edits;\n } else {\n rewriteEdits = collectCompileRewriteEdits(staged.current, compiled, {\n zodCompat: options.zodCompat,\n });\n }\n\n // Head = runtime helpers/import, then the file-level shared dedup block, then\n // the rewritten source. Shared constants and `__zcSw_N` functions live at\n // module scope so every IIFE closes over them; they must follow the runtime\n // import (lean) and the helper decls (inline) that they reference. Guard against\n // double-injection on watch/HMR re-runs the same way computeRuntimePrefix\n // does — a second copy would redeclare every `__zcSw_N`.\n //\n // Deferred into the rewrite's own stage rather than staged after it: both\n // decisions read the REWRITTEN text, and giving a bare prepend its own stage\n // doubled the sourcemap work and added a composition pass (see applyThen).\n staged.applyThen(rewriteEdits, (rewritten) => {\n const prefix = computeRuntimePrefix(rewritten, usedHelpers, mode, options.runtimeId);\n const needsShared = shared.code !== \"\" && !rewritten.includes(SHARED_BLOCK_MARKER);\n const head = (prefix ?? \"\") + (needsShared ? `${shared.code}\\n` : \"\");\n return head === \"\" ? undefined : head;\n });\n return { code: staged.current, map: staged.map() };\n}\n\n/**\n * Prepend the runtime helpers required by the rewritten source.\n *\n * Lean mode emits a single `import { ... } from \"<runtimeId>\";` line —\n * bundlers whose resolveId hook intercepts the specifier dedup helpers across\n * every transformed file into one shared virtual module.\n *\n * Inline mode prepends file-level `function __zcMkv` / `function __zcFin`\n * declarations directly so the file is self-contained.\n *\n * Idempotent: if the file already contains the relevant marker (re-run during\n * watch/HMR), we skip re-injection.\n */\n/** The runtime-helper text to prepend, or null when nothing is needed. */\nfunction computeRuntimePrefix(\n code: string,\n usedHelpers: Set<string>,\n mode: CodegenMode,\n runtimeId: string = VIRTUAL_RUNTIME_ID,\n): string | null {\n if (mode === \"lean\") {\n if (usedHelpers.size === 0) return null;\n // Match the import STATEMENT, not the bare id. `zod-compiler/runtime` is a\n // plain package specifier and a substring of `virtual:zod-compiler/runtime`,\n // so a file merely mentioning either — a comment, a docs snippet — would\n // suppress the import while codegen still emits calls to the helpers.\n if (code.includes(`from \"${runtimeId}\"`)) return null;\n const names = [...usedHelpers].sort().join(\", \");\n return `import { ${names} } from \"${runtimeId}\";\\n`;\n }\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS):\n // ship file-level helper declarations instead of a virtual import.\n // Codegen emits per-IIFE issue literals + per-IIFE `__re_*` decls,\n // so we only need __zcMkv / __zcFin (plus __zcMsg via the zod config import).\n if (!code.includes(\"__zcMkv\")) return null;\n const prefix: string[] = [];\n if (!code.includes(\"__zodCompilerConfig\")) {\n prefix.push(ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION);\n }\n if (!code.includes(\"function __zcMkv(\")) {\n prefix.push(MK_VALIDATOR_DECL);\n }\n // __zcFin and __zcFinD both construct __ZcFail; declare it once before either,\n // guarding against a header already shipped earlier in the same module.\n const needsFin = !code.includes(\"function __zcFin(\");\n const needsFinD = code.includes(\"__zcFinD(\") && !code.includes(\"function __zcFinD(\");\n if ((needsFin || needsFinD) && !code.includes(\"function __ZcFail(\")) {\n prefix.push(FAIL_CLASS_DECL);\n }\n if (needsFin) {\n prefix.push(FIN_DECL);\n }\n if (needsFinD) {\n prefix.push(FIN_DEFERRED_DECL);\n }\n // Compact mode (output: \"compact\") delegates cold errors to zod via __zcFinZ,\n // which constructs its own __ZcFailZ (distinct from __ZcFail).\n const needsFinZ = code.includes(\"__zcFinZ(\") && !code.includes(\"function __zcFinZ(\");\n if (needsFinZ && !code.includes(\"function __ZcFailZ(\")) {\n prefix.push(FAILZ_CLASS_DECL);\n }\n if (needsFinZ) {\n prefix.push(FINZ_DECL);\n }\n return prefix.length > 0 ? `${prefix.join(\"\\n\")}\\n` : null;\n}\n\n/**\n * Find the matching closing parenthesis for a compile() call,\n * handling nested parentheses like compile(z.object({...})).\n * Returns the index of the closing ')' or -1 if not found.\n */\nfunction findMatchingParen(code: string, openIndex: number): number {\n let depth = 1;\n for (let i = openIndex + 1; i < code.length; i++) {\n if (code[i] === \"(\") depth++;\n else if (code[i] === \")\") {\n depth--;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\n/**\n * Rewrite source code by replacing compile() calls with IIFE-wrapped optimized validators.\n */\nexport function rewriteSource(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectCompileRewriteEdits(code, schemas, options));\n}\n\n/**\n * Edits for rewriteSource (compile() call replacements + compile-import\n * removal), collected against pristine `code`. Each schema's declaration is\n * a distinct region and the import statement is distinct from all of them,\n * so the batch is non-overlapping and order-independent.\n */\nfunction collectCompileRewriteEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n // Match: <exportName> = compile<...>( with word boundary to prevent substring matches\n const prefixPattern = new RegExp(\n `(\\\\b${schema.exportName}\\\\s*=\\\\s*)compile\\\\s*(?:<[^>]*(?:<[^>]*>[^>]*)?>)?\\\\s*\\\\(`,\n );\n const match = prefixPattern.exec(code);\n if (!match) continue;\n\n // Find the matching closing paren (handles nested parens)\n const openParenIndex = match.index + match[0].length - 1;\n const closeParenIndex = findMatchingParen(code, openParenIndex);\n if (closeParenIndex === -1) continue;\n\n const schemaArgName = code\n .slice(openParenIndex + 1, closeParenIndex)\n .trim()\n .replace(/,\\s*$/, \"\");\n const prefix = match[1] ?? \"\";\n edits.push({\n start: match.index,\n end: closeParenIndex + 1,\n text: prefix + generateIIFE(schemaArgName, schema, options),\n });\n }\n edits.push(...collectRemoveCompileImportEdits(code));\n return edits;\n}\n\n/**\n * Find the end position of a JavaScript expression starting at `start` using acorn.\n * Returns the end offset, or -1 if the expression cannot be parsed.\n */\nexport function findExpressionEnd(code: string, start: number): number {\n try {\n const node = parseExpressionAt(code, start, {\n ecmaVersion: \"latest\",\n sourceType: \"module\",\n });\n return node.end;\n } catch {\n return -1;\n }\n}\n\n/**\n * Rewrite source code by replacing plain Zod schema exports with IIFE-wrapped optimized validators.\n * Used by autoDiscover mode (no compile() wrappers needed).\n */\nexport function rewriteSourceAutoDiscover(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectAutoDiscoverEdits(code, schemas, options));\n}\n\n/**\n * Does `expr` mention `name` as an identifier?\n *\n * Deliberately lexical, and deliberately biased toward YES. A false positive\n * costs one export its `@__PURE__` annotation; a false negative emits an IIFE\n * that dereferences a binding still under initialization. The expression text\n * is often TypeScript (`z.custom<T>(...)`), which no JS parser here can be\n * trusted to walk, so a word-boundary scan — which cannot miss a real\n * identifier reference — is the sound direction to be wrong in.\n */\nfunction mentionsIdentifier(expr: string, name: string): boolean {\n return new RegExp(`\\\\b${name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}\\\\b`).test(expr);\n}\n\n/** Edits for rewriteSourceAutoDiscover, collected against pristine `code`. */\nfunction collectAutoDiscoverEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n const escapedName = schema.exportName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // Match: export? (const|let|var) ExportName[: TypeAnnotation] = <expr>\n const assignPattern = new RegExp(\n `((?:export\\\\s+)?(?:const|let|var)\\\\s+${escapedName}(?:\\\\s*:[^=]*)?\\\\s*=\\\\s*)`,\n );\n const match = assignPattern.exec(code);\n if (!match) continue;\n\n const rhsStart = match.index + match[0].length;\n const rhsEnd = findExpressionEnd(code, rhsStart);\n if (rhsEnd === -1) continue;\n\n const originalExpr = code.slice(rhsStart, rhsEnd).trim();\n\n // A RECURSIVE schema defers its self-reference through a callback —\n // `z.lazy(() => z.array(Node))`, or zod v4's getter form\n // `get children() { return z.array(Node) }` — and that callback closes over\n // the module binding declared here. Replacing the initializer puts the\n // IIFE's `var __rf=[__zs._zod.innerType...]` preamble INSIDE that binding's\n // own initializer, so forcing the callback re-enters a binding that is not\n // yet assigned: a TDZ ReferenceError at module init, or — once a bundler\n // lowers the top-level `const` to `var`, as esbuild does — a silent\n // `undefined` that zod's `defineLazy` then CACHES, permanently poisoning\n // the schema for every consumer (`z.array(undefined)`).\n //\n // So the deref moves out of the initializer: the declaration keeps its\n // original expression and the IIFE follows it as a statement, mutating the\n // now-assigned schema in place. `__zcMkv` returns its argument (identity is\n // preserved by design), so the export is the same object either way, and\n // `__rfp_N`'s pristine-`safeParse` capture still happens before the\n // trailing `__zcMkv` installs anything. The cost is this export's\n // `@__PURE__` annotation — a self-referential schema is no longer\n // droppable when unused.\n if (iifeDerefsSchema(schema) && mentionsIdentifier(originalExpr, schema.exportName)) {\n // `output: \"bag\"` replaces the export with a method bag rather than\n // mutating the schema, so there is nothing to mutate in place — and the\n // user's own recursive reference would resolve to the bag regardless.\n if (options?.zodCompat === false) {\n warn(\n `Skipping self-referential export \"${schema.exportName}\": output \"bag\" cannot preserve its recursive reference. Keeping the original schema.`,\n );\n continue;\n }\n // Re-emitting `originalExpr` verbatim is what makes splitting the\n // declaration safe for `const Schema = <expr>, other = 1;`:\n // findExpressionEnd parses an Expression, and the comma operator makes\n // that span the whole declarator list, so the siblings are inside the\n // text being written back rather than after the statement terminator.\n edits.push({\n start: rhsStart,\n end: rhsEnd,\n text: `${originalExpr};\\n${generateIIFE(schema.exportName, schema, { ...options, pure: false })};`,\n });\n continue;\n }\n\n edits.push({\n start: rhsStart,\n end: rhsEnd,\n text: generateIIFE(originalExpr, schema, options),\n });\n }\n return edits;\n}\n\n/**\n * Remove the `compile` binding from `import { compile, ... } from \"zod-compiler\"` statements.\n * If `compile` is the only import, the entire import line is removed.\n */\nexport function removeCompileImport(code: string): string {\n return applyEdits(code, collectRemoveCompileImportEdits(code));\n}\n\n/** Edits stripping the `compile` binding from zod-compiler import statements. */\nfunction collectRemoveCompileImportEdits(code: string): Edit[] {\n // Match: import { ... } from \"zod-compiler\" or 'zod-compiler'\n const importPattern = /import\\s*\\{([^}]*)\\}\\s*from\\s*[\"']zod-compiler[\"'];?/g;\n const edits: Edit[] = [];\n for (const match of code.matchAll(importPattern)) {\n const imports = match[1] ?? \"\";\n const names = imports\n .split(\",\")\n .map((n) => n.trim())\n .filter(Boolean);\n const remaining = names.filter((n) => n !== \"compile\");\n const text =\n remaining.length === 0 ? \"\" : `import { ${remaining.join(\", \")} } from \"zod-compiler\";`;\n if (text !== match[0]) {\n edits.push({ start: match.index, end: match.index + match[0].length, text });\n }\n }\n return edits;\n}\n"],"mappings":"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"}
|