zod-compiler 2.0.7 → 2.0.8

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.
Files changed (51) hide show
  1. package/README.md +4 -0
  2. package/dist/cli/emitter.d.ts.map +1 -1
  3. package/dist/cli/emitter.js +10 -4
  4. package/dist/cli/emitter.js.map +1 -1
  5. package/dist/core/codegen/context.d.ts +17 -1
  6. package/dist/core/codegen/context.d.ts.map +1 -1
  7. package/dist/core/codegen/context.js +17 -1
  8. package/dist/core/codegen/context.js.map +1 -1
  9. package/dist/core/codegen/index.d.ts +8 -0
  10. package/dist/core/codegen/index.d.ts.map +1 -1
  11. package/dist/core/codegen/index.js +11 -10
  12. package/dist/core/codegen/index.js.map +1 -1
  13. package/dist/core/compile.d.ts +4 -3
  14. package/dist/core/compile.d.ts.map +1 -1
  15. package/dist/core/compile.js +1 -0
  16. package/dist/core/compile.js.map +1 -1
  17. package/dist/core/extract/error-class.d.ts +32 -0
  18. package/dist/core/extract/error-class.d.ts.map +1 -0
  19. package/dist/core/extract/error-class.js +13 -0
  20. package/dist/core/extract/error-class.js.map +1 -0
  21. package/dist/core/iife.d.ts +41 -6
  22. package/dist/core/iife.d.ts.map +1 -1
  23. package/dist/core/iife.js +71 -8
  24. package/dist/core/iife.js.map +1 -1
  25. package/dist/core/pipeline.d.ts +1 -0
  26. package/dist/core/pipeline.d.ts.map +1 -1
  27. package/dist/core/pipeline.js +6 -1
  28. package/dist/core/pipeline.js.map +1 -1
  29. package/dist/core/types.d.ts +16 -5
  30. package/dist/core/types.d.ts.map +1 -1
  31. package/dist/is-zod-schema.d.ts +5 -3
  32. package/dist/is-zod-schema.d.ts.map +1 -1
  33. package/dist/is-zod-schema.js +3 -1
  34. package/dist/is-zod-schema.js.map +1 -1
  35. package/dist/jit.d.ts +5 -4
  36. package/dist/jit.d.ts.map +1 -1
  37. package/dist/jit.js +17 -3
  38. package/dist/jit.js.map +1 -1
  39. package/dist/register/index.js.map +1 -1
  40. package/dist/runtime.d.ts +2 -0
  41. package/dist/runtime.js +6 -2
  42. package/dist/unplugin/hoist-compile.d.ts.map +1 -1
  43. package/dist/unplugin/hoist-compile.js +5 -1
  44. package/dist/unplugin/hoist-compile.js.map +1 -1
  45. package/dist/unplugin/transform.d.ts.map +1 -1
  46. package/dist/unplugin/transform.js +10 -4
  47. package/dist/unplugin/transform.js.map +1 -1
  48. package/dist/unplugin/virtual.d.ts.map +1 -1
  49. package/dist/unplugin/virtual.js +6 -1
  50. package/dist/unplugin/virtual.js.map +1 -1
  51. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/codegen/index.ts"],"sourcesContent":["import type { SchemaIR } from \"../types.js\";\nimport type {\n CodeGenContext,\n CodeGenResult,\n CodegenMode,\n GeneratedConstant,\n RecTargetGen,\n} from \"./context.js\";\nimport {\n fastResultIsInput,\n generateBuild,\n nestedNeedsProtoScrub,\n rebuildsOutput,\n} from \"./build-path.js\";\nimport {\n declareFastTemps,\n emitRetainedMethod,\n emitRfDelegate,\n emitRuntimeHelper,\n hasMutation,\n needsProtoScrub,\n RETAINED_SCHEMA_VAR,\n} from \"./context.js\";\nimport type { SharedSchemaPlan } from \"./dedupe.js\";\nimport { ZC_PROTO_SCRUB_DECL } from \"./issue-decls.js\";\nimport { createFastGen, generateFast } from \"./fast-path.js\";\nimport { createSlowGen, generateSlow } from \"./slow-path.js\";\n\nexport type { CodeGenResult } from \"./context.js\";\n\nexport interface GenerateValidatorOptions {\n refCount?: number;\n /** Codegen output mode. Defaults to \"inline\". */\n mode?: CodegenMode;\n /**\n * File-level shared slow-walk plan (schema deduplication). Applied only to\n * mutation-free schemas, so shared walks stay on the deferred cold path.\n */\n sharedSchemas?: SharedSchemaPlan | undefined;\n /**\n * Compact mode (`output: \"compact\"`). Drop the compiled slow walk for\n * mutation-free schemas with a TOTAL fast path and delegate the cold error\n * path to the retained Zod schema (`__zcFinZ`). The fast (hot) path is\n * unchanged; only the bulky error-collecting walk — 64–77% of generated\n * bytes — is replaced by a few bytes of zod delegation. See\n * {@link CodeGenResult.usesRetainedSchema}.\n */\n compact?: boolean | undefined;\n /** Internal file-pipeline hook for pooling exact constant initializers across validators. */\n onConstant?: ((constant: GeneratedConstant) => void) | undefined;\n /** Internal exact-initializer plan used by the file pipeline's final generation pass. */\n sharedConstantNames?: ReadonlyMap<string, string> | undefined;\n}\n\n/**\n * Generate optimized validation code from SchemaIR.\n *\n * - `code`: preamble declarations (Sets, RegExps, etc.) — deterministic for the same IR\n * - `functionDef`: full function expression string referencing preamble vars via closure\n * - `usedHelpers`: helper names from \"virtual:zod-compiler/runtime\" referenced (lean mode only)\n *\n * Usage: `new Function(code + \"\\nreturn \" + functionDef + \";\")()`\n */\nexport function generateValidator(\n ir: SchemaIR,\n name: string,\n options?: GenerateValidatorOptions,\n): CodeGenResult {\n const fnName = `safeParse_${name}`;\n const mode: CodegenMode = options?.mode ?? \"inline\";\n const ctx: CodeGenContext = {\n preamble: [],\n counter: 0,\n fnName,\n regexCache: new Map(),\n mode,\n usedHelpers: new Set(),\n onConstant: options?.onConstant,\n sharedConstantNames: options?.sharedConstantNames,\n };\n\n // Slow-walk sharing. The plan already excludes any shape that would reach for\n // this export's `__rf[]`, and a shared walk returns its parsed value, so a\n // rewriting shape (a stripping object above all) delivers its result through\n // the call. Nothing left to gate on here.\n if (options?.sharedSchemas !== undefined) {\n ctx.sharedSchemas = options.sharedSchemas;\n }\n\n // Root-level fallback: the whole schema delegates to Zod, so zod's own\n // safeParse result IS the result. Returning it directly skips the issue\n // copy loop (which would force zod's eager ZodError construction), the\n // pointless [].concat(path) rewrites, and the __zcFin re-wrap. Delegation\n // goes through the pre-mutation capture (emitRfDelegate) — here __rf[0]\n // and the __zcMkv target are routinely the SAME object.\n if (ir.type === \"fallback\" && ir.refIndex !== undefined) {\n const delegate = emitRfDelegate(ctx, ir.refIndex);\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: `function ${fnName}(input){return ${delegate}(input);}`,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n };\n }\n\n // Recursion-target table. The root (refId 0) reuses the schema's own\n // `safeParse_<name>` / hosted fast-check, so it needs no separate helper and\n // its fast name is allocated lazily during the walk (recFastName). Non-root\n // targets — recursive sub-schemas nested in a larger root, multiple distinct\n // recursive shapes, mutual recursion — are each hosted as a standalone\n // `__rsp_N` (slow) / `__fcr_N` (fast) validator the cycle calls by name.\n // Common directly-self-recursive schemas have no non-root targets, so this\n // leaves their generated output byte-identical.\n const nonRootTargets = collectRecursionTargets(ir);\n ctx.recTargets = new Map<number, RecTargetGen>([[0, { isRoot: true, slowName: fnName }]]);\n for (const [refId, inner] of nonRootTargets) {\n ctx.recTargets.set(refId, {\n isRoot: false,\n inner,\n slowName: `__rsp_${ctx.counter++}`,\n fastName: `__fcr_${ctx.counter++}`,\n });\n }\n const hasNonRootTargets = nonRootTargets.size > 0;\n\n // Fast Path: generate a boolean expression for eligible schemas.\n //\n // generateFast mutates ctx as it walks (extracted __fo_ helpers + regex/effect\n // decls pushed to the preamble, a recursive __fcr_ name reserved, dedup caches\n // populated). The walk is all-or-nothing: a later fast-ineligible node makes it\n // return null AFTER those side effects already landed. Without a rollback the\n // discarded fast path leaves dead __fo_ helpers in the output — and, when one\n // referenced the recursive __fcr_ host that the `fastExpr !== null` branch below\n // never emits, a dangling reference to an undefined identifier. Snapshot the\n // mutable state and restore it on abort so the slow path re-declares from clean.\n const fastPreambleLen = ctx.preamble.length;\n const fastRegexCache = new Map(ctx.regexCache);\n const fastEffectCache = ctx.effectFnCache && new Map(ctx.effectFnCache);\n const fastValueCache = ctx.valueCache && new Map(ctx.valueCache);\n const fastRecName = ctx.recFastName;\n // A schema that rebuilds its output never takes a by-reference shortcut:\n // `fastResultIsInput` withholds `data: input` and the published `fc` alike,\n // so its root expression is only ever consumed as a VERDICT — by `.is()`. It\n // is therefore generated as an acceptance predicate (see FastGen.acceptance),\n // which differs from the by-reference form only at `.default()` nodes and is\n // what lets a defaulted schema keep a zero-allocation `.is()`.\n const acceptance = rebuildsOutput(ir);\n const fg = createFastGen(\"input\", ctx, false, undefined, undefined, acceptance);\n let fastExpr = generateFast(ir, fg);\n if (fastExpr !== null && hasNonRootTargets) {\n // Host each non-root recursion target as a boolean fast-check helper. A\n // single fast-ineligible target (e.g. one whose recursive shape contains a\n // fallback) disables the WHOLE fast path: the root expression already emits\n // calls to these names, so a missing body would dangle. The shared\n // rollback below then restores clean state for the slow-only path.\n for (const t of ctx.recTargets.values()) {\n if (t.isRoot) continue;\n const targetGen = createFastGen(\"input\", ctx, false, undefined, undefined, acceptance);\n const body = generateFast(t.inner as SchemaIR, targetGen);\n if (body === null) {\n fastExpr = null;\n break;\n }\n ctx.preamble.push(\n `function ${t.fastName}(input){${declareFastTemps(targetGen.scope)}return ${body};}`,\n );\n }\n }\n if (fastExpr === null) {\n // The build pass also invokes generateFast for passthrough subtrees. Its\n // recursive calls must decline once this rollback removes their hosts;\n // the pre-allocated names in recTargets alone do not prove they exist.\n ctx.fastRecursionDisabled = true;\n ctx.preamble.length = fastPreambleLen;\n ctx.regexCache = fastRegexCache;\n if (fastEffectCache === undefined) delete ctx.effectFnCache;\n else ctx.effectFnCache = fastEffectCache;\n // Value declarations the abandoned walk emitted are truncated above, so\n // their cache entries would name identifiers that no longer exist.\n if (fastValueCache === undefined) delete ctx.valueCache;\n else ctx.valueCache = fastValueCache;\n if (fastRecName === undefined) delete ctx.recFastName;\n else ctx.recFastName = fastRecName;\n }\n\n // Host the fast expression in a named boolean helper. Self-recursive\n // schemas need it so recursive refs can call it; every other eligible\n // schema benefits too: __zcMkv wires it into parse()/parseAsync(), whose\n // success paths then return the input directly — no intermediate\n // SafeParseResult allocation (the safeParse function body is far past\n // V8's inlining budget, so escape analysis never removes it).\n let fastFnName: string | null = null;\n if (fastExpr !== null && fastExpr !== \"true\") {\n fastFnName = ctx.recFastName ?? `__fc_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${fastFnName}(input){${declareFastTemps(fg.scope)}return ${fastExpr};}`,\n );\n fastExpr = `${fastFnName}(input)`;\n }\n\n // Build Path: one pass that validates and assembles rewritten output, bailing\n // on the first failure (see build-path). Null unless every mutation in the\n // schema is modelled — so this emits nothing for the mutation-free schemas\n // the compact branch takes.\n const buildFnName = generateBuild(ir, ctx);\n\n // A zodDelegate with a rebuilding inner exists only to accelerate that\n // build. If an unmodelled descendant made the all-or-nothing build decline,\n // preserve the old root-fallback shape instead of wrapping the same pristine\n // Zod call in an issues array/copy/finalizer. This keeps unsupported object\n // intersections neutral rather than making compilation slower than Zod.\n if (ir.type === \"zodDelegate\" && rebuildsOutput(ir.inner) && buildFnName === null) {\n ctx.preamble.length = 0;\n ctx.usedHelpers.clear();\n ctx.regexCache.clear();\n ctx.effectFnCache?.clear();\n ctx.valueCache?.clear();\n const delegate = emitRfDelegate(ctx, ir.refIndex);\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: `function ${fnName}(input){return ${delegate}(input);}`,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n };\n }\n\n // `.is()` for a build-path schema is the fast expression — stripping reshapes\n // the payload, never the verdict, and a `.default()` is covered too: the build\n // path is only ever taken by a rebuilding schema, whose expression was\n // generated in acceptance mode (`acceptance` above) and so accepts the absent\n // value the substitution stands in for.\n const buildIsFnName = fastFnName;\n\n const baseRefCount = options?.refCount ?? 0;\n\n // Compact mode: a mutation-free schema with a TOTAL fast path needs no\n // compiled slow walk — its only purpose is reproducing zod's issues on\n // failure, and the original zod schema (retained in `output: \"compact\"`) does\n // that exactly. Emit the fast check and, on failure, delegate to a fresh root\n // RefEntry (the schema itself) via the pristine safeParse method capture, then\n // wrap it in the lazy `__zcFinZ` failure. Drops 64–77% of generated bytes\n // with zero hot-path cost (fc and `.is()` are unchanged) and zod-identical\n // errors. Excluded: schemas with non-root recursion targets (mutual/nested\n // recursion still hosts standalone slow validators) and any non-total fast\n // path (mutation/default/catch/fallback) — those keep the compiled path.\n if (\n options?.compact === true &&\n fastExpr !== null &&\n fastExpr !== \"true\" &&\n !hasMutation(ir) &&\n // `data: input` verbatim, with no compiled walk to fall back on — so a\n // schema whose output needs an own `__proto__` removed cannot use it.\n !needsProtoScrub(ir) &&\n !nestedNeedsProtoScrub(ir) &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `if(${fastExpr}){return{success:true,data:input};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName,\n // Mutation-free total fast path: fc(input) ⟺ accepts(input), so `.is()`\n // installs fc directly (compact never weakens the guard).\n fastTotal: true,\n usesRetainedSchema: true,\n };\n }\n\n // Compact + Build Path: same bargain for a schema with modelled rewrites. The\n // build pass still has to run (it produces the payload, which zod's schema\n // would only reproduce by parsing again), but the compiled issue walk is what\n // compact drops, and delegating that to the retained zod schema costs a few\n // bytes.\n if (\n options?.compact === true &&\n buildFnName !== null &&\n ctx.buildFailName !== undefined &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n const built = `__bd_${ctx.counter++}`;\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n isFnName: buildIsFnName,\n usesRetainedSchema: true,\n };\n }\n\n // Host each non-root recursion target as a safeParse-shaped slow validator,\n // mirroring the root's eager body: collect issues, return success+data or a\n // deferred-error result. Always emitted (the slow path always exists); the\n // recursion call sites read `.success` / `.error.issues` / `.data`. Hoisted\n // function declarations, so their order relative to the root is irrelevant.\n if (hasNonRootTargets) {\n for (const t of ctx.recTargets.values()) {\n if (t.isRoot) continue;\n const body = generateSlow(t.inner as SchemaIR, createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx));\n ctx.usedHelpers.add(\"__zcFin\");\n ctx.preamble.push(\n `function ${t.slowName}(input){var _e=[];\\nvar _d=input;\\n${body}\\n` +\n `if(_e.length===0){return{success:true,data:_d};}\\nreturn __zcFin(_e,_d);}`,\n );\n }\n }\n\n const sg = createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx);\n // When the root schema's own shape is shared (it recurs as a sub-schema of\n // another export, or as a duplicate root), its slow walk delegates to the\n // shared function instead of emitting a second full copy. The fast path is\n // still generated inline above — only the cold walk is shared.\n const rootRef = ctx.sharedSchemas?.refFor(ir);\n const slowCode = rootRef !== undefined ? `_d=${rootRef.name}(_d,[],_e);` : generateSlow(ir, sg);\n\n const buildCode = (): string => [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\");\n\n const functionDefParts = [`function ${fnName}(input){`];\n\n // Build Path: every mutation is modelled, so one pass can validate and\n // assemble the output together and bail on the first failure, leaving the\n // issue-producing walk deferred behind `.error` (see build-path).\n // The fast check stays out of `safeParse` entirely — running it first would\n // read every property twice — but it is still an EXACT acceptance predicate\n // (stripping reshapes the output, never the verdict), so `.is()` installs it.\n if (buildFnName !== null && ctx.buildFailName !== undefined) {\n ctx.usedHelpers.add(\"__zcFinD\");\n const built = `__bd_${ctx.counter++}`;\n // A self-recursive walk calls this validator BY NAME (slowRecursiveRef),\n // and that binding exists only inside the named function expression — so\n // there the walk stays a per-call closure. Everything else hosts it in the\n // preamble, keeping safeParse to three statements. Mirrors the same split\n // in the mutation-free branch below.\n const recursive = slowCode.includes(fnName);\n let deferred: string;\n if (recursive) {\n deferred = `__zcFinD(function(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;},input)`;\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n deferred = `__zcFinD(${walkName},input)`;\n }\n return {\n code: buildCode(),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return ${deferred};`,\n `}`,\n ].join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // No by-reference shortcut: `data` is the freshly built object, so\n // parse() must go through safeParse rather than returning its input.\n fastFnName: null,\n // `fastTotal` qualifies `fastFnName`, which is null here; the predicate\n // travels in `isFnName` instead.\n fastTotal: false,\n isFnName: buildIsFnName,\n };\n }\n\n if (fastExpr === \"true\") {\n // Schema always succeeds (any/unknown) — skip slow path entirely\n functionDefParts.push(`return{success:true,data:input};`);\n functionDefParts.push(`}`);\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n // any/unknown always succeed; `.is()` derives `true` from the fn fallback.\n fastTotal: false,\n };\n }\n\n if (fastExpr !== null && !hasMutation(ir) && !nestedNeedsProtoScrub(ir)) {\n // The by-reference shortcut hands back the input verbatim, which a loose or\n // catchall object — or a record — must not do while it still carries an own\n // `__proto__` (see ZC_PROTO_SCRUB_DECL). The fast check itself stays a pure\n // predicate, so `fc(input) ⟺ zod accepts` still holds and the deferred error\n // path below is untouched; only the value handed back is filtered. The cost\n // is one `hasOwnProperty` per successful parse of those shapes.\n const fastData = needsProtoScrub(ir)\n ? `${emitRuntimeHelper(ctx, \"__zcPs\", ZC_PROTO_SCRUB_DECL)}(input)`\n : \"input\";\n // Mutation-free schemas with a fast path: a fast-check failure can never\n // become a slow-path success (both are generated from the same checks —\n // unlike default/catch schemas, whose partial fast path requires value\n // presence while the slow path SUCCEEDS by applying the fallback).\n // The slow path's only output is therefore the issues array, observable\n // solely through `.error` — defer the whole re-walk into the cached\n // accessor (__zcFinD): a failed safeParse whose `.error` is never read\n // costs the fast check alone.\n //\n // The walk is HOSTED as a named preamble function rather than a per-call\n // closure, for two measured reasons: (1) a failed safeParse no longer\n // allocates a closure environment + function object before the deferral\n // even starts; (2) the safeParse body shrinks to two statements, putting\n // it within V8's inlining budget — callers in hot loops get the\n // success-path result object escape-analyzed away entirely, which the\n // old shape (slow walk inlined into the body) made impossible.\n ctx.usedHelpers.add(\"__zcFinD\");\n if (slowCode.includes(fnName)) {\n // Self-recursive slow paths call the safeParse function by NAME\n // (slowRecursiveRef) — that binding exists only inside the named\n // function expression under the documented evaluation contract\n // (`new Function(code + \"return \" + functionDef)`), so the walk stays\n // a per-call closure for recursive schemas. Recursion is the rare\n // shape; everything else gets the hosted walk.\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return __zcFinD(function(input){`,\n `var _e=[];`,\n `var _d=input;`,\n slowCode,\n `return _e;`,\n `},input);`,\n `}`,\n );\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return __zcFinD(${walkName},input);`,\n `}`,\n );\n }\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // `fc` is a sound VERDICT here either way, but publishing it also promises\n // `parse()` may return the input — which a scrubbed output cannot (see\n // fastResultIsInput). `.is()` reads only the verdict, so it takes the\n // predicate through `isFnName` whether or not `fc` is withheld —\n // `fastTotal` below qualifies `fastFnName` alone.\n fastFnName: fastResultIsInput(ir) ? fastFnName : null,\n // Total predicate: mutation-free fast path, fc(input) ⟺ accepts(input).\n // generateIIFE installs fc directly as the zero-allocation `.is()`.\n fastTotal: true,\n isFnName: fastFnName,\n };\n }\n\n if (fastExpr !== null && fastResultIsInput(ir)) {\n // Partial fast path (default/catch/... present-value shortcut): the slow\n // path must run eagerly — it can succeed where the fast check failed.\n //\n // Withheld when the schema rebuilds its output: there the fast check is a\n // sound VERDICT but says nothing about the payload, and `data:input` would\n // hand back the unstripped input. Such schemas reach here only when the\n // build path declined them, so the eager walk produces the output instead.\n functionDefParts.push(`if(${fastExpr}){return{success:true,data:input};}`);\n }\n\n // Success branch inlined at the call site instead of inside __zcFin: the\n // eager path (mutation schemas — coerce/default/trim/transform) returns\n // here on EVERY parse, and the inline literal keeps the hot exit free of a\n // cross-function call; __zcFin is reached only on failure.\n functionDefParts.push(\n `var _e=[];`,\n `var _d=input;`,\n slowCode,\n `if(_e.length===0){return{success:true,data:_d};}`,\n `return __zcFin(_e,_d);`,\n `}`,\n );\n\n const functionDef = functionDefParts.join(\"\\n\");\n\n return {\n code: buildCode(),\n functionDef,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // `fc` carries a stronger contract than \"accepts\": `__zcMkv` returns the\n // INPUT from `parse()`/`parseAsync()`/`~standard` whenever it holds, so it\n // may only be published when a passing check implies `data === input`. A\n // rebuilding schema breaks that even though its safeParse is correct, and so\n // does a union whose options can rewrite — see `fastResultIsInput` for both.\n // Same guard as the `data: input` shortcut above, which is the other reader\n // of the same contract.\n fastFnName: fastResultIsInput(ir) ? fastFnName : null,\n // Partial fast path (default/catch) or none (including coercion): a false fc\n // result does not imply rejection, so `.is()` derives from\n // safeParse(input).success.\n fastTotal: false,\n };\n}\n\n/**\n * Find every non-root recursion target (a `recursionTarget` node, refId ≥ 1)\n * reachable from `root`, mapping refId → the inner IR to host as a standalone\n * validator. The root target (refId 0) is the schema's own function and is\n * never wrapped, so it never appears here. The same target may be wrapped at\n * several sites (a recursive schema reached from sibling positions); the first\n * inner wins — they are structurally identical extractions of one schema.\n */\nfunction collectRecursionTargets(root: SchemaIR): Map<number, SchemaIR> {\n const out = new Map<number, SchemaIR>();\n const seen = new Set<SchemaIR>();\n const walk = (ir: SchemaIR): void => {\n if (seen.has(ir)) return;\n seen.add(ir);\n if (ir.type === \"recursionTarget\" && !out.has(ir.refId)) {\n out.set(ir.refId, ir.inner);\n }\n for (const child of childIRs(ir)) walk(child);\n };\n walk(root);\n return out;\n}\n\n/** Direct child SchemaIR nodes, covering every node type (including the new wrapper). */\nfunction childIRs(ir: SchemaIR): readonly SchemaIR[] {\n switch (ir.type) {\n case \"object\":\n return Object.values(ir.properties);\n case \"array\":\n return [ir.element];\n case \"tuple\":\n return ir.rest === null ? ir.items : [...ir.items, ir.rest];\n case \"record\":\n case \"map\":\n return [ir.keyType, ir.valueType];\n case \"set\":\n return [ir.valueType];\n case \"union\":\n case \"discriminatedUnion\":\n return ir.options;\n case \"intersection\":\n return [ir.left, ir.right];\n case \"optional\":\n case \"nullable\":\n case \"readonly\":\n case \"default\":\n case \"catch\":\n case \"effect\":\n case \"recursionTarget\":\n case \"zodDelegate\":\n return [ir.inner];\n case \"pipe\":\n return [ir.in, ir.out];\n default:\n return [];\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/codegen/index.ts"],"sourcesContent":["import type { ZodErrorClass } from \"../extract/error-class.js\";\nimport type { SchemaIR } from \"../types.js\";\nimport type {\n CodeGenContext,\n CodeGenResult,\n CodegenMode,\n GeneratedConstant,\n RecTargetGen,\n} from \"./context.js\";\nimport {\n fastResultIsInput,\n generateBuild,\n nestedNeedsProtoScrub,\n rebuildsOutput,\n} from \"./build-path.js\";\nimport {\n declareFastTemps,\n emitRetainedMethod,\n emitRfDelegate,\n emitRuntimeHelper,\n FINALIZERS,\n hasMutation,\n needsProtoScrub,\n RETAINED_SCHEMA_VAR,\n} from \"./context.js\";\nimport type { SharedSchemaPlan } from \"./dedupe.js\";\nimport { ZC_PROTO_SCRUB_DECL } from \"./issue-decls.js\";\nimport { createFastGen, generateFast } from \"./fast-path.js\";\nimport { createSlowGen, generateSlow } from \"./slow-path.js\";\n\nexport type { CodeGenResult } from \"./context.js\";\n\nexport interface GenerateValidatorOptions {\n refCount?: number;\n /** Codegen output mode. Defaults to \"inline\". */\n mode?: CodegenMode;\n /**\n * File-level shared slow-walk plan (schema deduplication). Applied only to\n * mutation-free schemas, so shared walks stay on the deferred cold path.\n */\n sharedSchemas?: SharedSchemaPlan | undefined;\n /**\n * Compact mode (`output: \"compact\"`). Drop the compiled slow walk for\n * mutation-free schemas with a TOTAL fast path and delegate the cold error\n * path to the retained Zod schema (`__zcFinZ`). The fast (hot) path is\n * unchanged; only the bulky error-collecting walk — 64–77% of generated\n * bytes — is replaced by a few bytes of zod delegation. See\n * {@link CodeGenResult.usesRetainedSchema}.\n */\n compact?: boolean | undefined;\n /** Internal file-pipeline hook for pooling exact constant initializers across validators. */\n onConstant?: ((constant: GeneratedConstant) => void) | undefined;\n /** Internal exact-initializer plan used by the file pipeline's final generation pass. */\n sharedConstantNames?: ReadonlyMap<string, string> | undefined;\n /**\n * The error class the schema's own methods fail with (`zodErrorClassOf` on\n * the root schema): classic's `ZodError`, or core's `$ZodError` for\n * `zod/mini`. Picks the finalizers (see FINALIZERS), and so the class a\n * failed parse's `.error` is built with. Defaults to `\"ZodError\"`.\n */\n errorClass?: ZodErrorClass | undefined;\n}\n\n/**\n * Generate optimized validation code from SchemaIR.\n *\n * - `code`: preamble declarations (Sets, RegExps, etc.) — deterministic for the same IR\n * - `functionDef`: full function expression string referencing preamble vars via closure\n * - `usedHelpers`: helper names from \"virtual:zod-compiler/runtime\" referenced (lean mode only)\n *\n * Usage: `new Function(code + \"\\nreturn \" + functionDef + \";\")()`\n */\nexport function generateValidator(\n ir: SchemaIR,\n name: string,\n options?: GenerateValidatorOptions,\n): CodeGenResult {\n const fnName = `safeParse_${name}`;\n const mode: CodegenMode = options?.mode ?? \"inline\";\n // Every failure the compiled walk reports goes through one of these two, so\n // they decide the class `.error` is built with. (Compact and root-fallback\n // validators return zod's own result, built by the schema's own class.)\n const { eager: fin, deferred: finD } = FINALIZERS[options?.errorClass ?? \"ZodError\"];\n const ctx: CodeGenContext = {\n preamble: [],\n counter: 0,\n fnName,\n regexCache: new Map(),\n mode,\n usedHelpers: new Set(),\n onConstant: options?.onConstant,\n sharedConstantNames: options?.sharedConstantNames,\n };\n\n // Slow-walk sharing. The plan already excludes any shape that would reach for\n // this export's `__rf[]`, and a shared walk returns its parsed value, so a\n // rewriting shape (a stripping object above all) delivers its result through\n // the call. Nothing left to gate on here.\n if (options?.sharedSchemas !== undefined) {\n ctx.sharedSchemas = options.sharedSchemas;\n }\n\n // Root-level fallback: the whole schema delegates to Zod, so zod's own\n // safeParse result IS the result. Returning it directly skips the issue\n // copy loop (which would force zod's eager ZodError construction), the\n // pointless [].concat(path) rewrites, and the __zcFin re-wrap. Delegation\n // goes through the pre-mutation capture (emitRfDelegate) — here __rf[0]\n // and the __zcMkv target are routinely the SAME object.\n if (ir.type === \"fallback\" && ir.refIndex !== undefined) {\n const delegate = emitRfDelegate(ctx, ir.refIndex);\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: `function ${fnName}(input){return ${delegate}(input);}`,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n };\n }\n\n // Recursion-target table. The root (refId 0) reuses the schema's own\n // `safeParse_<name>` / hosted fast-check, so it needs no separate helper and\n // its fast name is allocated lazily during the walk (recFastName). Non-root\n // targets — recursive sub-schemas nested in a larger root, multiple distinct\n // recursive shapes, mutual recursion — are each hosted as a standalone\n // `__rsp_N` (slow) / `__fcr_N` (fast) validator the cycle calls by name.\n // Common directly-self-recursive schemas have no non-root targets, so this\n // leaves their generated output byte-identical.\n const nonRootTargets = collectRecursionTargets(ir);\n ctx.recTargets = new Map<number, RecTargetGen>([[0, { isRoot: true, slowName: fnName }]]);\n for (const [refId, inner] of nonRootTargets) {\n ctx.recTargets.set(refId, {\n isRoot: false,\n inner,\n slowName: `__rsp_${ctx.counter++}`,\n fastName: `__fcr_${ctx.counter++}`,\n });\n }\n const hasNonRootTargets = nonRootTargets.size > 0;\n\n // Fast Path: generate a boolean expression for eligible schemas.\n //\n // generateFast mutates ctx as it walks (extracted __fo_ helpers + regex/effect\n // decls pushed to the preamble, a recursive __fcr_ name reserved, dedup caches\n // populated). The walk is all-or-nothing: a later fast-ineligible node makes it\n // return null AFTER those side effects already landed. Without a rollback the\n // discarded fast path leaves dead __fo_ helpers in the output — and, when one\n // referenced the recursive __fcr_ host that the `fastExpr !== null` branch below\n // never emits, a dangling reference to an undefined identifier. Snapshot the\n // mutable state and restore it on abort so the slow path re-declares from clean.\n const fastPreambleLen = ctx.preamble.length;\n const fastRegexCache = new Map(ctx.regexCache);\n const fastEffectCache = ctx.effectFnCache && new Map(ctx.effectFnCache);\n const fastValueCache = ctx.valueCache && new Map(ctx.valueCache);\n const fastRecName = ctx.recFastName;\n // A schema that rebuilds its output never takes a by-reference shortcut:\n // `fastResultIsInput` withholds `data: input` and the published `fc` alike,\n // so its root expression is only ever consumed as a VERDICT — by `.is()`. It\n // is therefore generated as an acceptance predicate (see FastGen.acceptance),\n // which differs from the by-reference form only at `.default()` nodes and is\n // what lets a defaulted schema keep a zero-allocation `.is()`.\n const acceptance = rebuildsOutput(ir);\n const fg = createFastGen(\"input\", ctx, false, undefined, undefined, acceptance);\n let fastExpr = generateFast(ir, fg);\n if (fastExpr !== null && hasNonRootTargets) {\n // Host each non-root recursion target as a boolean fast-check helper. A\n // single fast-ineligible target (e.g. one whose recursive shape contains a\n // fallback) disables the WHOLE fast path: the root expression already emits\n // calls to these names, so a missing body would dangle. The shared\n // rollback below then restores clean state for the slow-only path.\n for (const t of ctx.recTargets.values()) {\n if (t.isRoot) continue;\n const targetGen = createFastGen(\"input\", ctx, false, undefined, undefined, acceptance);\n const body = generateFast(t.inner as SchemaIR, targetGen);\n if (body === null) {\n fastExpr = null;\n break;\n }\n ctx.preamble.push(\n `function ${t.fastName}(input){${declareFastTemps(targetGen.scope)}return ${body};}`,\n );\n }\n }\n if (fastExpr === null) {\n // The build pass also invokes generateFast for passthrough subtrees. Its\n // recursive calls must decline once this rollback removes their hosts;\n // the pre-allocated names in recTargets alone do not prove they exist.\n ctx.fastRecursionDisabled = true;\n ctx.preamble.length = fastPreambleLen;\n ctx.regexCache = fastRegexCache;\n if (fastEffectCache === undefined) delete ctx.effectFnCache;\n else ctx.effectFnCache = fastEffectCache;\n // Value declarations the abandoned walk emitted are truncated above, so\n // their cache entries would name identifiers that no longer exist.\n if (fastValueCache === undefined) delete ctx.valueCache;\n else ctx.valueCache = fastValueCache;\n if (fastRecName === undefined) delete ctx.recFastName;\n else ctx.recFastName = fastRecName;\n }\n\n // Host the fast expression in a named boolean helper. Self-recursive\n // schemas need it so recursive refs can call it; every other eligible\n // schema benefits too: __zcMkv wires it into parse()/parseAsync(), whose\n // success paths then return the input directly — no intermediate\n // SafeParseResult allocation (the safeParse function body is far past\n // V8's inlining budget, so escape analysis never removes it).\n let fastFnName: string | null = null;\n if (fastExpr !== null && fastExpr !== \"true\") {\n fastFnName = ctx.recFastName ?? `__fc_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${fastFnName}(input){${declareFastTemps(fg.scope)}return ${fastExpr};}`,\n );\n fastExpr = `${fastFnName}(input)`;\n }\n\n // Build Path: one pass that validates and assembles rewritten output, bailing\n // on the first failure (see build-path). Null unless every mutation in the\n // schema is modelled — so this emits nothing for the mutation-free schemas\n // the compact branch takes.\n const buildFnName = generateBuild(ir, ctx);\n\n // A zodDelegate with a rebuilding inner exists only to accelerate that\n // build. If an unmodelled descendant made the all-or-nothing build decline,\n // preserve the old root-fallback shape instead of wrapping the same pristine\n // Zod call in an issues array/copy/finalizer. This keeps unsupported object\n // intersections neutral rather than making compilation slower than Zod.\n if (ir.type === \"zodDelegate\" && rebuildsOutput(ir.inner) && buildFnName === null) {\n ctx.preamble.length = 0;\n ctx.usedHelpers.clear();\n ctx.regexCache.clear();\n ctx.effectFnCache?.clear();\n ctx.valueCache?.clear();\n const delegate = emitRfDelegate(ctx, ir.refIndex);\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: `function ${fnName}(input){return ${delegate}(input);}`,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n };\n }\n\n // `.is()` for a build-path schema is the fast expression — stripping reshapes\n // the payload, never the verdict, and a `.default()` is covered too: the build\n // path is only ever taken by a rebuilding schema, whose expression was\n // generated in acceptance mode (`acceptance` above) and so accepts the absent\n // value the substitution stands in for.\n const buildIsFnName = fastFnName;\n\n const baseRefCount = options?.refCount ?? 0;\n\n // Compact mode: a mutation-free schema with a TOTAL fast path needs no\n // compiled slow walk — its only purpose is reproducing zod's issues on\n // failure, and the original zod schema (retained in `output: \"compact\"`) does\n // that exactly. Emit the fast check and, on failure, delegate to a fresh root\n // RefEntry (the schema itself) via the pristine safeParse method capture, then\n // wrap it in the lazy `__zcFinZ` failure. Drops 64–77% of generated bytes\n // with zero hot-path cost (fc and `.is()` are unchanged) and zod-identical\n // errors. Excluded: schemas with non-root recursion targets (mutual/nested\n // recursion still hosts standalone slow validators) and any non-total fast\n // path (mutation/default/catch/fallback) — those keep the compiled path.\n if (\n options?.compact === true &&\n fastExpr !== null &&\n fastExpr !== \"true\" &&\n !hasMutation(ir) &&\n // `data: input` verbatim, with no compiled walk to fall back on — so a\n // schema whose output needs an own `__proto__` removed cannot use it.\n !needsProtoScrub(ir) &&\n !nestedNeedsProtoScrub(ir) &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `if(${fastExpr}){return{success:true,data:input};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName,\n // Mutation-free total fast path: fc(input) ⟺ accepts(input), so `.is()`\n // installs fc directly (compact never weakens the guard).\n fastTotal: true,\n usesRetainedSchema: true,\n };\n }\n\n // Compact + Build Path: same bargain for a schema with modelled rewrites. The\n // build pass still has to run (it produces the payload, which zod's schema\n // would only reproduce by parsing again), but the compiled issue walk is what\n // compact drops, and delegating that to the retained zod schema costs a few\n // bytes.\n if (\n options?.compact === true &&\n buildFnName !== null &&\n ctx.buildFailName !== undefined &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n const built = `__bd_${ctx.counter++}`;\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n isFnName: buildIsFnName,\n usesRetainedSchema: true,\n };\n }\n\n // Host each non-root recursion target as a safeParse-shaped slow validator,\n // mirroring the root's eager body: collect issues, return success+data or a\n // deferred-error result. Always emitted (the slow path always exists); the\n // recursion call sites read `.success` / `.error.issues` / `.data`. Hoisted\n // function declarations, so their order relative to the root is irrelevant.\n if (hasNonRootTargets) {\n for (const t of ctx.recTargets.values()) {\n if (t.isRoot) continue;\n const body = generateSlow(t.inner as SchemaIR, createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx));\n ctx.usedHelpers.add(fin);\n ctx.preamble.push(\n `function ${t.slowName}(input){var _e=[];\\nvar _d=input;\\n${body}\\n` +\n `if(_e.length===0){return{success:true,data:_d};}\\nreturn ${fin}(_e,_d);}`,\n );\n }\n }\n\n const sg = createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx);\n // When the root schema's own shape is shared (it recurs as a sub-schema of\n // another export, or as a duplicate root), its slow walk delegates to the\n // shared function instead of emitting a second full copy. The fast path is\n // still generated inline above — only the cold walk is shared.\n const rootRef = ctx.sharedSchemas?.refFor(ir);\n const slowCode = rootRef !== undefined ? `_d=${rootRef.name}(_d,[],_e);` : generateSlow(ir, sg);\n\n const buildCode = (): string => [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\");\n\n const functionDefParts = [`function ${fnName}(input){`];\n\n // Build Path: every mutation is modelled, so one pass can validate and\n // assemble the output together and bail on the first failure, leaving the\n // issue-producing walk deferred behind `.error` (see build-path).\n // The fast check stays out of `safeParse` entirely — running it first would\n // read every property twice — but it is still an EXACT acceptance predicate\n // (stripping reshapes the output, never the verdict), so `.is()` installs it.\n if (buildFnName !== null && ctx.buildFailName !== undefined) {\n ctx.usedHelpers.add(finD);\n const built = `__bd_${ctx.counter++}`;\n // A self-recursive walk calls this validator BY NAME (slowRecursiveRef),\n // and that binding exists only inside the named function expression — so\n // there the walk stays a per-call closure. Everything else hosts it in the\n // preamble, keeping safeParse to three statements. Mirrors the same split\n // in the mutation-free branch below.\n const recursive = slowCode.includes(fnName);\n let deferred: string;\n if (recursive) {\n deferred = `${finD}(function(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;},input)`;\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n deferred = `${finD}(${walkName},input)`;\n }\n return {\n code: buildCode(),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return ${deferred};`,\n `}`,\n ].join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // No by-reference shortcut: `data` is the freshly built object, so\n // parse() must go through safeParse rather than returning its input.\n fastFnName: null,\n // `fastTotal` qualifies `fastFnName`, which is null here; the predicate\n // travels in `isFnName` instead.\n fastTotal: false,\n isFnName: buildIsFnName,\n };\n }\n\n if (fastExpr === \"true\") {\n // Schema always succeeds (any/unknown) — skip slow path entirely\n functionDefParts.push(`return{success:true,data:input};`);\n functionDefParts.push(`}`);\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n // any/unknown always succeed; `.is()` derives `true` from the fn fallback.\n fastTotal: false,\n };\n }\n\n if (fastExpr !== null && !hasMutation(ir) && !nestedNeedsProtoScrub(ir)) {\n // The by-reference shortcut hands back the input verbatim, which a loose or\n // catchall object — or a record — must not do while it still carries an own\n // `__proto__` (see ZC_PROTO_SCRUB_DECL). The fast check itself stays a pure\n // predicate, so `fc(input) ⟺ zod accepts` still holds and the deferred error\n // path below is untouched; only the value handed back is filtered. The cost\n // is one `hasOwnProperty` per successful parse of those shapes.\n const fastData = needsProtoScrub(ir)\n ? `${emitRuntimeHelper(ctx, \"__zcPs\", ZC_PROTO_SCRUB_DECL)}(input)`\n : \"input\";\n // Mutation-free schemas with a fast path: a fast-check failure can never\n // become a slow-path success (both are generated from the same checks —\n // unlike default/catch schemas, whose partial fast path requires value\n // presence while the slow path SUCCEEDS by applying the fallback).\n // The slow path's only output is therefore the issues array, observable\n // solely through `.error` — defer the whole re-walk into the cached\n // accessor (__zcFinD): a failed safeParse whose `.error` is never read\n // costs the fast check alone.\n //\n // The walk is HOSTED as a named preamble function rather than a per-call\n // closure, for two measured reasons: (1) a failed safeParse no longer\n // allocates a closure environment + function object before the deferral\n // even starts; (2) the safeParse body shrinks to two statements, putting\n // it within V8's inlining budget — callers in hot loops get the\n // success-path result object escape-analyzed away entirely, which the\n // old shape (slow walk inlined into the body) made impossible.\n ctx.usedHelpers.add(finD);\n if (slowCode.includes(fnName)) {\n // Self-recursive slow paths call the safeParse function by NAME\n // (slowRecursiveRef) — that binding exists only inside the named\n // function expression under the documented evaluation contract\n // (`new Function(code + \"return \" + functionDef)`), so the walk stays\n // a per-call closure for recursive schemas. Recursion is the rare\n // shape; everything else gets the hosted walk.\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return ${finD}(function(input){`,\n `var _e=[];`,\n `var _d=input;`,\n slowCode,\n `return _e;`,\n `},input);`,\n `}`,\n );\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return ${finD}(${walkName},input);`,\n `}`,\n );\n }\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // `fc` is a sound VERDICT here either way, but publishing it also promises\n // `parse()` may return the input — which a scrubbed output cannot (see\n // fastResultIsInput). `.is()` reads only the verdict, so it takes the\n // predicate through `isFnName` whether or not `fc` is withheld —\n // `fastTotal` below qualifies `fastFnName` alone.\n fastFnName: fastResultIsInput(ir) ? fastFnName : null,\n // Total predicate: mutation-free fast path, fc(input) ⟺ accepts(input).\n // generateIIFE installs fc directly as the zero-allocation `.is()`.\n fastTotal: true,\n isFnName: fastFnName,\n };\n }\n\n if (fastExpr !== null && fastResultIsInput(ir)) {\n // Partial fast path (default/catch/... present-value shortcut): the slow\n // path must run eagerly — it can succeed where the fast check failed.\n //\n // Withheld when the schema rebuilds its output: there the fast check is a\n // sound VERDICT but says nothing about the payload, and `data:input` would\n // hand back the unstripped input. Such schemas reach here only when the\n // build path declined them, so the eager walk produces the output instead.\n functionDefParts.push(`if(${fastExpr}){return{success:true,data:input};}`);\n }\n\n // Success branch inlined at the call site instead of inside __zcFin: the\n // eager path (mutation schemas — coerce/default/trim/transform) returns\n // here on EVERY parse, and the inline literal keeps the hot exit free of a\n // cross-function call; __zcFin is reached only on failure.\n functionDefParts.push(\n `var _e=[];`,\n `var _d=input;`,\n slowCode,\n `if(_e.length===0){return{success:true,data:_d};}`,\n `return ${fin}(_e,_d);`,\n `}`,\n );\n\n const functionDef = functionDefParts.join(\"\\n\");\n\n return {\n code: buildCode(),\n functionDef,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // `fc` carries a stronger contract than \"accepts\": `__zcMkv` returns the\n // INPUT from `parse()`/`parseAsync()`/`~standard` whenever it holds, so it\n // may only be published when a passing check implies `data === input`. A\n // rebuilding schema breaks that even though its safeParse is correct, and so\n // does a union whose options can rewrite — see `fastResultIsInput` for both.\n // Same guard as the `data: input` shortcut above, which is the other reader\n // of the same contract.\n fastFnName: fastResultIsInput(ir) ? fastFnName : null,\n // Partial fast path (default/catch) or none (including coercion): a false fc\n // result does not imply rejection, so `.is()` derives from\n // safeParse(input).success.\n fastTotal: false,\n };\n}\n\n/**\n * Find every non-root recursion target (a `recursionTarget` node, refId ≥ 1)\n * reachable from `root`, mapping refId → the inner IR to host as a standalone\n * validator. The root target (refId 0) is the schema's own function and is\n * never wrapped, so it never appears here. The same target may be wrapped at\n * several sites (a recursive schema reached from sibling positions); the first\n * inner wins — they are structurally identical extractions of one schema.\n */\nfunction collectRecursionTargets(root: SchemaIR): Map<number, SchemaIR> {\n const out = new Map<number, SchemaIR>();\n const seen = new Set<SchemaIR>();\n const walk = (ir: SchemaIR): void => {\n if (seen.has(ir)) return;\n seen.add(ir);\n if (ir.type === \"recursionTarget\" && !out.has(ir.refId)) {\n out.set(ir.refId, ir.inner);\n }\n for (const child of childIRs(ir)) walk(child);\n };\n walk(root);\n return out;\n}\n\n/** Direct child SchemaIR nodes, covering every node type (including the new wrapper). */\nfunction childIRs(ir: SchemaIR): readonly SchemaIR[] {\n switch (ir.type) {\n case \"object\":\n return Object.values(ir.properties);\n case \"array\":\n return [ir.element];\n case \"tuple\":\n return ir.rest === null ? ir.items : [...ir.items, ir.rest];\n case \"record\":\n case \"map\":\n return [ir.keyType, ir.valueType];\n case \"set\":\n return [ir.valueType];\n case \"union\":\n case \"discriminatedUnion\":\n return ir.options;\n case \"intersection\":\n return [ir.left, ir.right];\n case \"optional\":\n case \"nullable\":\n case \"readonly\":\n case \"default\":\n case \"catch\":\n case \"effect\":\n case \"recursionTarget\":\n case \"zodDelegate\":\n return [ir.inner];\n case \"pipe\":\n return [ir.in, ir.out];\n default:\n return [];\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { CompiledSchema } from "./types.js";
2
- import { ZodType, output } from "zod";
1
+ import { CompilableSchema, CompiledSchema } from "./types.js";
2
+ import { output } from "zod";
3
3
  //#region src/core/compile.d.ts
4
4
  /**
5
5
  * Compile a Zod schema into an optimized validator.
@@ -9,10 +9,11 @@ import { ZodType, output } from "zod";
9
9
  * compiled marker so build-time discovery can find it.
10
10
  * After `npx zod-compiler generate`, import from the `.compiled.ts` file instead.
11
11
  *
12
+ * Accepts classic `zod` and `zod/mini` schemas alike (see {@link CompilableSchema}).
12
13
  * The return type is `T & CompiledSchema<output<T>>`, preserving the original
13
14
  * Zod schema type for compatibility with libraries like `@hono/zod-validator`.
14
15
  */
15
- declare function compile<T extends ZodType>(zodSchema: T): T & CompiledSchema<output<T>>;
16
+ declare function compile<T extends CompilableSchema>(zodSchema: T): T & CompiledSchema<output<T>>;
16
17
  /**
17
18
  * Check if a value is a CompiledSchema created by compile().
18
19
  * Used by the CLI to discover schemas in source files.
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","names":[],"sources":["../../src/core/compile.ts"],"mappings":";;;;;;;;;;;;;;iBA+CgB,QAAQ,UAAU,SAAS,WAAW,IAAI,IAAI,eAAe,OAAO;;;;;;;;;;iBAiBpE,iBAAiB,iBAAiB,SAAS"}
1
+ {"version":3,"file":"compile.d.ts","names":[],"sources":["../../src/core/compile.ts"],"mappings":";;;;;;;;;;;;;;;iBAgDgB,QAAQ,UAAU,kBAAkB,WAAW,IAAI,IAAI,eAAe,OAAO;;;;;;;;;;iBAiB7E,iBAAiB,iBAAiB,SAAS"}
@@ -33,6 +33,7 @@ function createFallback(zodSchema) {
33
33
  * compiled marker so build-time discovery can find it.
34
34
  * After `npx zod-compiler generate`, import from the `.compiled.ts` file instead.
35
35
  *
36
+ * Accepts classic `zod` and `zod/mini` schemas alike (see {@link CompilableSchema}).
36
37
  * The return type is `T & CompiledSchema<output<T>>`, preserving the original
37
38
  * Zod schema type for compatibility with libraries like `@hono/zod-validator`.
38
39
  */
@@ -1 +1 @@
1
- {"version":3,"file":"compile.js","names":[],"sources":["../../src/core/compile.ts"],"sourcesContent":["import type { output, ZodType } from \"zod\";\nimport type { CompiledSchema } from \"./types.js\";\n\nconst COMPILED_MARKER = Symbol.for(\"zod-compiler:compiled\");\n\n/**\n * Dev-time fallback: returns the ORIGINAL schema object, augmented with a\n * non-enumerable `schema` self-reference (CLI emitter discovery reads\n * `(__src_X as any).schema`) and the compiled marker.\n *\n * Identity preservation is load-bearing: zod v4 keys toJSONSchema's\n * processing context and globalRegistry/.meta() on schema object identity —\n * an Object.create facade crashes toJSONSchema the moment the compiled\n * schema is composed into another schema, and silently loses .meta()\n * metadata. parse/safeParse/... remain the schema's own zod methods.\n */\nfunction createFallback<T>(zodSchema: unknown): CompiledSchema<T> {\n const facade = zodSchema as CompiledSchema<T>;\n if (!(\"schema\" in (facade as object))) {\n Object.defineProperty(facade, \"schema\", { value: zodSchema, enumerable: false });\n }\n // Dev-time `.is`: delegates to zod's own safeParse so the boolean guard works\n // before `zod-compiler generate` runs. The build replaces this with the\n // compiled fast-check (zero-allocation) via __zcMkv. Non-enumerable to keep\n // the augmentation invisible on the identity-preserved schema object.\n if (!(\"is\" in (facade as object))) {\n Object.defineProperty(facade, \"is\", {\n value: (input: unknown): boolean => facade.safeParse(input).success,\n enumerable: false,\n configurable: true,\n writable: true,\n });\n }\n return facade;\n}\n\n/**\n * Compile a Zod schema into an optimized validator.\n *\n * At dev-time, falls back to Zod's runtime validation: the schema itself is\n * returned (identity-preserving for toJSONSchema/.meta()), tagged with the\n * compiled marker so build-time discovery can find it.\n * After `npx zod-compiler generate`, import from the `.compiled.ts` file instead.\n *\n * The return type is `T & CompiledSchema<output<T>>`, preserving the original\n * Zod schema type for compatibility with libraries like `@hono/zod-validator`.\n */\nexport function compile<T extends ZodType>(zodSchema: T): T & CompiledSchema<output<T>> {\n const result = createFallback<output<T>>(zodSchema);\n if (!(COMPILED_MARKER in (result as object))) {\n Object.defineProperty(result, COMPILED_MARKER, { value: true, enumerable: false });\n }\n return result as T & CompiledSchema<output<T>>;\n}\n\n/**\n * Check if a value is a CompiledSchema created by compile().\n * Used by the CLI to discover schemas in source files.\n *\n * Like {@link isZodSchema}, this probes values the caller does not control —\n * every export of every candidate file — and `COMPILED_MARKER in value` fires a\n * Proxy's `has` trap. A trap that throws (an ORM model, a strict test double)\n * must not fail the build over an export that was never a candidate.\n */\nexport function isCompiledSchema(value: unknown): value is CompiledSchema<unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n try {\n return COMPILED_MARKER in value;\n } catch {\n return false;\n }\n}\n"],"mappings":";AAGA,MAAM,kBAAkB,OAAO,IAAI,uBAAuB;;;;;;;;;;;;AAa1D,SAAS,eAAkB,WAAuC;CAChE,MAAM,SAAS;CACf,IAAI,EAAE,YAAa,SACjB,OAAO,eAAe,QAAQ,UAAU;EAAE,OAAO;EAAW,YAAY;CAAM,CAAC;CAMjF,IAAI,EAAE,QAAS,SACb,OAAO,eAAe,QAAQ,MAAM;EAClC,QAAQ,UAA4B,OAAO,UAAU,KAAK,CAAC,CAAC;EAC5D,YAAY;EACZ,cAAc;EACd,UAAU;CACZ,CAAC;CAEH,OAAO;AACT;;;;;;;;;;;;AAaA,SAAgB,QAA2B,WAA6C;CACtF,MAAM,SAAS,eAA0B,SAAS;CAClD,IAAI,EAAE,mBAAoB,SACxB,OAAO,eAAe,QAAQ,iBAAiB;EAAE,OAAO;EAAM,YAAY;CAAM,CAAC;CAEnF,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,iBAAiB,OAAkD;CACjF,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,IAAI;EACF,OAAO,mBAAmB;CAC5B,QAAQ;EACN,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"compile.js","names":[],"sources":["../../src/core/compile.ts"],"sourcesContent":["import type { output } from \"zod\";\nimport type { CompilableSchema, CompiledSchema } from \"./types.js\";\n\nconst COMPILED_MARKER = Symbol.for(\"zod-compiler:compiled\");\n\n/**\n * Dev-time fallback: returns the ORIGINAL schema object, augmented with a\n * non-enumerable `schema` self-reference (CLI emitter discovery reads\n * `(__src_X as any).schema`) and the compiled marker.\n *\n * Identity preservation is load-bearing: zod v4 keys toJSONSchema's\n * processing context and globalRegistry/.meta() on schema object identity —\n * an Object.create facade crashes toJSONSchema the moment the compiled\n * schema is composed into another schema, and silently loses .meta()\n * metadata. parse/safeParse/... remain the schema's own zod methods.\n */\nfunction createFallback<T>(zodSchema: unknown): CompiledSchema<T> {\n const facade = zodSchema as CompiledSchema<T>;\n if (!(\"schema\" in (facade as object))) {\n Object.defineProperty(facade, \"schema\", { value: zodSchema, enumerable: false });\n }\n // Dev-time `.is`: delegates to zod's own safeParse so the boolean guard works\n // before `zod-compiler generate` runs. The build replaces this with the\n // compiled fast-check (zero-allocation) via __zcMkv. Non-enumerable to keep\n // the augmentation invisible on the identity-preserved schema object.\n if (!(\"is\" in (facade as object))) {\n Object.defineProperty(facade, \"is\", {\n value: (input: unknown): boolean => facade.safeParse(input).success,\n enumerable: false,\n configurable: true,\n writable: true,\n });\n }\n return facade;\n}\n\n/**\n * Compile a Zod schema into an optimized validator.\n *\n * At dev-time, falls back to Zod's runtime validation: the schema itself is\n * returned (identity-preserving for toJSONSchema/.meta()), tagged with the\n * compiled marker so build-time discovery can find it.\n * After `npx zod-compiler generate`, import from the `.compiled.ts` file instead.\n *\n * Accepts classic `zod` and `zod/mini` schemas alike (see {@link CompilableSchema}).\n * The return type is `T & CompiledSchema<output<T>>`, preserving the original\n * Zod schema type for compatibility with libraries like `@hono/zod-validator`.\n */\nexport function compile<T extends CompilableSchema>(zodSchema: T): T & CompiledSchema<output<T>> {\n const result = createFallback<output<T>>(zodSchema);\n if (!(COMPILED_MARKER in (result as object))) {\n Object.defineProperty(result, COMPILED_MARKER, { value: true, enumerable: false });\n }\n return result as T & CompiledSchema<output<T>>;\n}\n\n/**\n * Check if a value is a CompiledSchema created by compile().\n * Used by the CLI to discover schemas in source files.\n *\n * Like {@link isZodSchema}, this probes values the caller does not control —\n * every export of every candidate file — and `COMPILED_MARKER in value` fires a\n * Proxy's `has` trap. A trap that throws (an ORM model, a strict test double)\n * must not fail the build over an export that was never a candidate.\n */\nexport function isCompiledSchema(value: unknown): value is CompiledSchema<unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n try {\n return COMPILED_MARKER in value;\n } catch {\n return false;\n }\n}\n"],"mappings":";AAGA,MAAM,kBAAkB,OAAO,IAAI,uBAAuB;;;;;;;;;;;;AAa1D,SAAS,eAAkB,WAAuC;CAChE,MAAM,SAAS;CACf,IAAI,EAAE,YAAa,SACjB,OAAO,eAAe,QAAQ,UAAU;EAAE,OAAO;EAAW,YAAY;CAAM,CAAC;CAMjF,IAAI,EAAE,QAAS,SACb,OAAO,eAAe,QAAQ,MAAM;EAClC,QAAQ,UAA4B,OAAO,UAAU,KAAK,CAAC,CAAC;EAC5D,YAAY;EACZ,cAAc;EACd,UAAU;CACZ,CAAC;CAEH,OAAO;AACT;;;;;;;;;;;;;AAcA,SAAgB,QAAoC,WAA6C;CAC/F,MAAM,SAAS,eAA0B,SAAS;CAClD,IAAI,EAAE,mBAAoB,SACxB,OAAO,eAAe,QAAQ,iBAAiB;EAAE,OAAO;EAAM,YAAY;CAAM,CAAC;CAEnF,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,iBAAiB,OAAkD;CACjF,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,IAAI;EACF,OAAO,mBAAmB;CAC5B,QAAQ;EACN,OAAO;CACT;AACF"}
@@ -0,0 +1,32 @@
1
+ //#region src/core/extract/error-class.d.ts
2
+ /**
3
+ * The error class a schema's own parse methods build, which a compiled
4
+ * validator installed on that schema has to build too.
5
+ *
6
+ * Classic `zod` and `zod/mini` share every internal the compiler reads
7
+ * (`_zod.def`, `_zod.bag`, the checks), so one IR and one validator serve both.
8
+ * The error a failed parse hands back is where they part. Classic methods build
9
+ * classic's `ZodError`: `name: "ZodError"`, `.format()` and `.flatten()`, and
10
+ * the `"ZodError"` trait that `instanceof z.ZodError` tests. Mini's methods
11
+ * call zod/v4/core's parse functions, which build core's `$ZodError`:
12
+ * `name: "$ZodError"`, none of those methods, and the `"$ZodError"` trait
13
+ * alone. The issues are the same either way, but the class is observable, and
14
+ * a compiled Mini schema used to answer with the classic one.
15
+ *
16
+ * Decided by the ROOT schema, whose methods the validator replaces. A Mini
17
+ * object holding a classic field still fails with Mini's error from its own
18
+ * `parse()`, so its compiled replacement does too.
19
+ *
20
+ * Read off the `"ZodType"` trait, which only classic's `ZodType` constructor
21
+ * adds (Mini's adds `"ZodMiniType"`). A schema built straight from
22
+ * `zod/v4/core` carries neither and has no parse methods of its own; core's
23
+ * `parse()` builds the core error for it, so that is the class it gets. A
24
+ * schema whose traits cannot be read keeps the classic class, which is what
25
+ * every schema got before the distinction existed.
26
+ */
27
+ /** The `name` zod gives the error class: classic's, or zod/v4/core's (Mini). */
28
+ type ZodErrorClass = "ZodError" | "$ZodError";
29
+ declare function zodErrorClassOf(schema: unknown): ZodErrorClass;
30
+ //#endregion
31
+ export { ZodErrorClass, zodErrorClassOf };
32
+ //# sourceMappingURL=error-class.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-class.d.ts","names":[],"sources":["../../../src/core/extract/error-class.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;KA2BY;iBAEI,gBAAgB,kBAAkB"}
@@ -0,0 +1,13 @@
1
+ //#region src/core/extract/error-class.ts
2
+ function zodErrorClassOf(schema) {
3
+ if (typeof schema !== "object" || schema === null) return "ZodError";
4
+ try {
5
+ const traits = schema._zod?.traits;
6
+ if (typeof traits?.has === "function" && !traits.has("ZodType")) return "$ZodError";
7
+ } catch {}
8
+ return "ZodError";
9
+ }
10
+ //#endregion
11
+ export { zodErrorClassOf };
12
+
13
+ //# sourceMappingURL=error-class.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-class.js","names":[],"sources":["../../../src/core/extract/error-class.ts"],"sourcesContent":["/**\n * The error class a schema's own parse methods build, which a compiled\n * validator installed on that schema has to build too.\n *\n * Classic `zod` and `zod/mini` share every internal the compiler reads\n * (`_zod.def`, `_zod.bag`, the checks), so one IR and one validator serve both.\n * The error a failed parse hands back is where they part. Classic methods build\n * classic's `ZodError`: `name: \"ZodError\"`, `.format()` and `.flatten()`, and\n * the `\"ZodError\"` trait that `instanceof z.ZodError` tests. Mini's methods\n * call zod/v4/core's parse functions, which build core's `$ZodError`:\n * `name: \"$ZodError\"`, none of those methods, and the `\"$ZodError\"` trait\n * alone. The issues are the same either way, but the class is observable, and\n * a compiled Mini schema used to answer with the classic one.\n *\n * Decided by the ROOT schema, whose methods the validator replaces. A Mini\n * object holding a classic field still fails with Mini's error from its own\n * `parse()`, so its compiled replacement does too.\n *\n * Read off the `\"ZodType\"` trait, which only classic's `ZodType` constructor\n * adds (Mini's adds `\"ZodMiniType\"`). A schema built straight from\n * `zod/v4/core` carries neither and has no parse methods of its own; core's\n * `parse()` builds the core error for it, so that is the class it gets. A\n * schema whose traits cannot be read keeps the classic class, which is what\n * every schema got before the distinction existed.\n */\n\n/** The `name` zod gives the error class: classic's, or zod/v4/core's (Mini). */\nexport type ZodErrorClass = \"ZodError\" | \"$ZodError\";\n\nexport function zodErrorClassOf(schema: unknown): ZodErrorClass {\n if (typeof schema !== \"object\" || schema === null) return \"ZodError\";\n try {\n const traits = (schema as { _zod?: { traits?: { has?: unknown } } })._zod?.traits;\n if (typeof traits?.has === \"function\" && !(traits as Set<string>).has(\"ZodType\")) {\n return \"$ZodError\";\n }\n } catch {\n // A Proxy trapping `get`: nothing zod built, so nothing to match.\n }\n return \"ZodError\";\n}\n"],"mappings":";AA6BA,SAAgB,gBAAgB,QAAgC;CAC9D,IAAI,OAAO,WAAW,YAAY,WAAW,MAAM,OAAO;CAC1D,IAAI;EACF,MAAM,SAAU,OAAqD,MAAM;EAC3E,IAAI,OAAO,QAAQ,QAAQ,cAAc,CAAE,OAAuB,IAAI,SAAS,GAC7E,OAAO;CAEX,QAAQ,CAER;CACA,OAAO;AACT"}
@@ -1,12 +1,21 @@
1
1
  import { CompiledSchemaInfo } from "./pipeline.js";
2
2
  //#region src/core/iife.d.ts
3
3
  /**
4
- * Import statement required by generateIIFE output (references
4
+ * Import statements required by generateIIFE output (references
5
5
  * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and
6
6
  * custom callbacks may only reveal that they are async through the promise
7
- * they return, at which point zod's own synchronous parse raises.
7
+ * they return, at which point zod's own synchronous parse raises. It also
8
+ * supplies `$ZodRealError`, the error class `zod/mini` schemas fail with (see
9
+ * FAIL_CORE_CLASS_DECL); `ZodRealError` is classic's.
10
+ *
11
+ * `core` comes from `zod/v4/core` directly — the same module object classic
12
+ * re-exports as `core`, but reached as a namespace IMPORT, whose member reads a
13
+ * bundler can resolve one by one. Through classic's `export * as core`
14
+ * re-export, esbuild instead materializes the whole namespace, every locale
15
+ * included: a `zod/mini` bundle touching one `__zcCore` member measured 20 KB
16
+ * before that read and 398 KB after.
8
17
  */
9
- declare const ZOD_CONFIG_IMPORT = "import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";";
18
+ declare const ZOD_CONFIG_IMPORT: string;
10
19
  /**
11
20
  * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):
12
21
  * the message an issue gets when nothing was baked into it at build time.
@@ -66,9 +75,24 @@ declare const ZOD_MSG_DECLARATION: string;
66
75
  * after a caller asks for `.error` on a failed parse, and is memoised in `_c`.
67
76
  */
68
77
  declare const FAIL_CLASS_DECL: string;
78
+ /**
79
+ * {@link FAIL_CLASS_DECL} for a schema that fails with zod/v4/core's
80
+ * `$ZodError` instead of classic's `ZodError`: `zod/mini`, whose methods call
81
+ * core's parse functions, and raw core (see zodErrorClassOf). The finalization
82
+ * is identical; only the class constructed at the end differs, and with it
83
+ * everything the class carries (`name`, the trait `instanceof` tests,
84
+ * classic's `.format()`/`.flatten()`).
85
+ *
86
+ * A class of its own, with its own finalizers, rather than a constructor
87
+ * picked per failure: generated code names the pair its schema needs, so a
88
+ * bundle keeps only the class its validators construct (see failClassDecl).
89
+ */
90
+ declare const FAIL_CORE_CLASS_DECL: string;
69
91
  /** Eager finalizer (mutation / partial-fast-path schemas): issues already
70
92
  * collected in `e`; success short-circuits to a plain result literal. */
71
- declare const FIN_DECL = "function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}";
93
+ declare const FIN_DECL: string;
94
+ /** {@link FIN_DECL} for schemas failing with core's `$ZodError` (see {@link FAIL_CORE_CLASS_DECL}). */
95
+ declare const FIN_CORE_DECL: string;
72
96
  /**
73
97
  * Deferred-collection finalizer for Fast-Path-eligible schemas. When the
74
98
  * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is
@@ -91,7 +115,18 @@ declare const FIN_DECL = "function __zcFin(e,d){if(!e.length)return{success:true
91
115
  * mutated value (zod materializes at parse time). Same caveat class as the
92
116
  * documented __zcFin deferral.
93
117
  */
94
- declare const FIN_DEFERRED_DECL = "function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}";
118
+ declare const FIN_DEFERRED_DECL: string;
119
+ /** {@link FIN_DEFERRED_DECL} for schemas failing with core's `$ZodError` (see {@link FAIL_CORE_CLASS_DECL}). */
120
+ declare const FIN_DEFERRED_CORE_DECL: string;
121
+ /**
122
+ * Whether generated code that uses `helpers` builds core `$ZodError`s.
123
+ *
124
+ * Every emitter has always supplied the classic `__zcFin` whether or not any
125
+ * validator calls it. A file whose validators fail with core errors skips that
126
+ * default (a validator that does call it names it anyway): there it would be
127
+ * dead code that reaches for classic zod's error class.
128
+ */
129
+ declare function usesCoreErrors(helpers: ReadonlySet<string>): boolean;
95
130
  /**
96
131
  * Compact-mode failure class — a lazy failure that delegates error reporting to
97
132
  * the ORIGINAL Zod schema's `safeParse`. Used by `output: "compact"`, where the
@@ -254,5 +289,5 @@ declare function generateIIFE(schemaExpr: string, schema: CompiledSchemaInfo, op
254
289
  pure?: boolean | undefined;
255
290
  }): string;
256
291
  //#endregion
257
- 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 };
292
+ export { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FAIL_CORE_CLASS_DECL, FINZ_DECL, FIN_CORE_DECL, FIN_DECL, FIN_DEFERRED_CORE_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE, iifeDerefsSchema, usesCoreErrors };
258
293
  //# sourceMappingURL=iife.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAca;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6CA;;;cAWA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqGA;;;;;;;;;;;;;;;;;iBA6BG,iBAAiB,QAAQ;;;;;;;;;;;;;iBAgBzB,aACd,oBACA,QAAQ,oBACR;EAAY;EAAiC"}
1
+ {"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;;;;;;;;;;cAuBa;;;;;;;;;;;;;;;;;;;;cAuBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6CA;;;;;;;;;;;;;cAcA;;;cAmCA;;cAGA;;;;;;;;;;;;;;;;;;;;;;;cA4BA;;cAGA;;;;;;;;;iBAcG,eAAe,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;cA6B3B;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqGA;;;;;;;;;;;;;;;;;iBA6BG,iBAAiB,QAAQ;;;;;;;;;;;;;iBAgBzB,aACd,oBACA,QAAQ,oBACR;EAAY;EAAiC"}
package/dist/core/iife.js CHANGED
@@ -1,16 +1,25 @@
1
- import { RETAINED_SCHEMA_VAR } from "./codegen/context.js";
1
+ import { FINALIZERS, RETAINED_SCHEMA_VAR } from "./codegen/context.js";
2
2
  //#region src/core/iife.ts
3
3
  /**
4
4
  * Shared CompiledSchema<T> IIFE generation.
5
5
  * Used by both CLI emitter and unplugin transform.
6
6
  */
7
7
  /**
8
- * Import statement required by generateIIFE output (references
8
+ * Import statements required by generateIIFE output (references
9
9
  * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and
10
10
  * custom callbacks may only reveal that they are async through the promise
11
- * they return, at which point zod's own synchronous parse raises.
11
+ * they return, at which point zod's own synchronous parse raises. It also
12
+ * supplies `$ZodRealError`, the error class `zod/mini` schemas fail with (see
13
+ * FAIL_CORE_CLASS_DECL); `ZodRealError` is classic's.
14
+ *
15
+ * `core` comes from `zod/v4/core` directly — the same module object classic
16
+ * re-exports as `core`, but reached as a namespace IMPORT, whose member reads a
17
+ * bundler can resolve one by one. Through classic's `export * as core`
18
+ * re-export, esbuild instead materializes the whole namespace, every locale
19
+ * included: a `zod/mini` bundle touching one `__zcCore` member measured 20 KB
20
+ * before that read and 398 KB after.
12
21
  */
13
- const ZOD_CONFIG_IMPORT = "import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";";
22
+ const ZOD_CONFIG_IMPORT = "import { config as __zodCompilerConfig, ZodRealError as __zcZodError } from \"zod\";\nimport * as __zcCore from \"zod/v4/core\";";
14
23
  /**
15
24
  * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):
16
25
  * the message an issue gets when nothing was baked into it at build time.
@@ -69,10 +78,48 @@ const ZOD_MSG_DECLARATION = "function __zcUw(m){return typeof m===\"string\"?m:(
69
78
  * `Object.prototype` stays out, as it does from zod's spread. All of it runs only
70
79
  * after a caller asks for `.error` on a failed parse, and is memoised in `_c`.
71
80
  */
72
- const FAIL_CLASS_DECL = "function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){if(this._c)return this._c;var e=this._f!==null?this._f(this._i):this._e;for(var i=0;i<e.length;i++){var s=e[i],o={},k;if(s.message===undefined&&typeof __zcMsg===\"function\")s.message=__zcMsg(s);for(k in s){if(k!==\"input\"&&k!==\"continue\"&&Object.prototype.hasOwnProperty.call(s,k))o[k]=s[k];}e[i]=o;}return this._c=new __zcZodError(e);}});";
81
+ const FAIL_CLASS_DECL = failClassDecl("__ZcFail", "__zcZodError");
82
+ /**
83
+ * {@link FAIL_CLASS_DECL} for a schema that fails with zod/v4/core's
84
+ * `$ZodError` instead of classic's `ZodError`: `zod/mini`, whose methods call
85
+ * core's parse functions, and raw core (see zodErrorClassOf). The finalization
86
+ * is identical; only the class constructed at the end differs, and with it
87
+ * everything the class carries (`name`, the trait `instanceof` tests,
88
+ * classic's `.format()`/`.flatten()`).
89
+ *
90
+ * A class of its own, with its own finalizers, rather than a constructor
91
+ * picked per failure: generated code names the pair its schema needs, so a
92
+ * bundle keeps only the class its validators construct (see failClassDecl).
93
+ */
94
+ const FAIL_CORE_CLASS_DECL = failClassDecl("__ZcFailC", "__zcCore.$ZodRealError");
95
+ /**
96
+ * The failure class, for either error flavor; `errorClass` is the constructor
97
+ * expression.
98
+ *
99
+ * Wrapped in a `@__PURE__` IIFE so a bundle drops whichever class its
100
+ * validators never construct. A bare declaration is kept by every bundler
101
+ * for the `Object.defineProperty` that installs the getter (rolldown and
102
+ * esbuild both measured): the core class would cost every classic bundle
103
+ * ~500 B, and the classic class cost every `zod/mini` bundle 2.3-3.1 KB, since
104
+ * it carries classic zod's error class in with it. The wrapper itself costs a
105
+ * classic bundle 26-64 B.
106
+ *
107
+ * The binding is a `var`, not a hoisted function, so it must be initialized
108
+ * before a validator fails. Every emitter declares it at the head of the module
109
+ * (or of the evaluated body, under `jit()`), ahead of the finalizers and of
110
+ * every statement that could run a validator.
111
+ */
112
+ function failClassDecl(name, errorClass) {
113
+ return `var ${name}=/* @__PURE__ */(function(){function ${name}(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}Object.defineProperty(${name}.prototype,"error",{configurable:true,get:function(){if(this._c)return this._c;var e=this._f!==null?this._f(this._i):this._e;for(var i=0;i<e.length;i++){var s=e[i],o={},k;if(s.message===undefined&&typeof __zcMsg==="function")s.message=__zcMsg(s);for(k in s){if(k!=="input"&&k!=="continue"&&Object.prototype.hasOwnProperty.call(s,k))o[k]=s[k];}e[i]=o;}return this._c=new ${errorClass}(e);}});return ${name};})();`;
114
+ }
73
115
  /** Eager finalizer (mutation / partial-fast-path schemas): issues already
74
116
  * collected in `e`; success short-circuits to a plain result literal. */
75
- const FIN_DECL = "function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}";
117
+ const FIN_DECL = finDecl(FINALIZERS.ZodError.eager, "__ZcFail");
118
+ /** {@link FIN_DECL} for schemas failing with core's `$ZodError` (see {@link FAIL_CORE_CLASS_DECL}). */
119
+ const FIN_CORE_DECL = finDecl(FINALIZERS.$ZodError.eager, "__ZcFailC");
120
+ function finDecl(name, failClass) {
121
+ return `function ${name}(e,d){if(!e.length)return{success:true,data:d};return new ${failClass}(e,null,null);}`;
122
+ }
76
123
  /**
77
124
  * Deferred-collection finalizer for Fast-Path-eligible schemas. When the
78
125
  * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is
@@ -95,7 +142,23 @@ const FIN_DECL = "function __zcFin(e,d){if(!e.length)return{success:true,data:d}
95
142
  * mutated value (zod materializes at parse time). Same caveat class as the
96
143
  * documented __zcFin deferral.
97
144
  */
98
- const FIN_DEFERRED_DECL = "function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}";
145
+ const FIN_DEFERRED_DECL = finDeferredDecl(FINALIZERS.ZodError.deferred, "__ZcFail");
146
+ /** {@link FIN_DEFERRED_DECL} for schemas failing with core's `$ZodError` (see {@link FAIL_CORE_CLASS_DECL}). */
147
+ const FIN_DEFERRED_CORE_DECL = finDeferredDecl(FINALIZERS.$ZodError.deferred, "__ZcFailC");
148
+ function finDeferredDecl(name, failClass) {
149
+ return `function ${name}(f,inp){return new ${failClass}(null,f,inp);}`;
150
+ }
151
+ /**
152
+ * Whether generated code that uses `helpers` builds core `$ZodError`s.
153
+ *
154
+ * Every emitter has always supplied the classic `__zcFin` whether or not any
155
+ * validator calls it. A file whose validators fail with core errors skips that
156
+ * default (a validator that does call it names it anyway): there it would be
157
+ * dead code that reaches for classic zod's error class.
158
+ */
159
+ function usesCoreErrors(helpers) {
160
+ return helpers.has(FINALIZERS.$ZodError.eager) || helpers.has(FINALIZERS.$ZodError.deferred);
161
+ }
99
162
  /**
100
163
  * Compact-mode failure class — a lazy failure that delegates error reporting to
101
164
  * the ORIGINAL Zod schema's `safeParse`. Used by `output: "compact"`, where the
@@ -280,6 +343,6 @@ function generateIIFE(schemaExpr, schema, options) {
280
343
  ].join("\n");
281
344
  }
282
345
  //#endregion
283
- 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 };
346
+ export { FAILZ_CLASS_DECL, FAIL_CLASS_DECL, FAIL_CORE_CLASS_DECL, FINZ_DECL, FIN_CORE_DECL, FIN_DECL, FIN_DEFERRED_CORE_DECL, FIN_DEFERRED_DECL, MK_VALIDATOR_DECL, ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION, generateIIFE, iifeDerefsSchema, usesCoreErrors };
284
347
 
285
348
  //# sourceMappingURL=iife.js.map
@@ -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` and `continue` are left OUT, not assigned `undefined`. Key PRESENCE is\n * observable — `\"input\" in issue`, `Object.keys(issue)`, object spread,\n * `toStrictEqual` against a zod issue — and zod's `util.finalizeIssue` deletes\n * `continue`, and `input` whenever `reportInput` is off, so assignment left every\n * compiled issue one enumerable key wider than zod's. Each issue is COPIED\n * without them rather than `delete`d from: removing a key that is not the last\n * one added drops the object into V8's dictionary mode, ~70 ns an issue. `.error`\n * over six issues went 1.49 -> 1.06 us, over one 653 -> 608 ns. The copy keeps\n * key order and takes own keys only, so an enumerable key added to\n * `Object.prototype` stays out, as it does from zod's spread. All of it runs only\n * after a caller asks for `.error` on a failed parse, and is memoised in `_c`.\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++){var s=e[i],o={},k;if(s.message===undefined&&typeof __zcMsg===\"function\")s.message=__zcMsg(s);' +\n 'for(k in s){if(k!==\"input\"&&k!==\"continue\"&&Object.prototype.hasOwnProperty.call(s,k))o[k]=s[k];}e[i]=o;}' +\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 *\n * A rebuilding schema (no `fc`) reaches `parse()` through `fn`, i.e. through a\n * SafeParseResult unwrapped a line later. Handing the build function over so\n * `parse()` could call it directly was measured and declined: the wrapper is a\n * young-generation bump allocation that V8 elides outright where `fn` inlines,\n * and even across eight schemas sharing this closure — where it cannot — the\n * direct call came out level (41.5 vs 41.8 ns), for a wider signature on every\n * bundle.\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 * a prototype getter that binds the method and installs the bound copy on the\n * instance without touching the schema's structure.\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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CF,MAAa,kBACX;;;AAUF,MAAa,WACX;;;;;;;;;;;;;;;;;;;;;;;AAwBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BjC,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqGzB,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;;;;;;;;;;;;;;;;;AAkBA,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
+ {"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 { FINALIZERS, RETAINED_SCHEMA_VAR } from \"./codegen/context.js\";\nimport type { CompiledSchemaInfo } from \"./pipeline.js\";\n\n/**\n * Import statements 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. It also\n * supplies `$ZodRealError`, the error class `zod/mini` schemas fail with (see\n * FAIL_CORE_CLASS_DECL); `ZodRealError` is classic's.\n *\n * `core` comes from `zod/v4/core` directly — the same module object classic\n * re-exports as `core`, but reached as a namespace IMPORT, whose member reads a\n * bundler can resolve one by one. Through classic's `export * as core`\n * re-export, esbuild instead materializes the whole namespace, every locale\n * included: a `zod/mini` bundle touching one `__zcCore` member measured 20 KB\n * before that read and 398 KB after.\n */\nexport const ZOD_CONFIG_IMPORT =\n 'import { config as __zodCompilerConfig, ZodRealError as __zcZodError } from \"zod\";\\n' +\n 'import * as __zcCore from \"zod/v4/core\";';\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` and `continue` are left OUT, not assigned `undefined`. Key PRESENCE is\n * observable — `\"input\" in issue`, `Object.keys(issue)`, object spread,\n * `toStrictEqual` against a zod issue — and zod's `util.finalizeIssue` deletes\n * `continue`, and `input` whenever `reportInput` is off, so assignment left every\n * compiled issue one enumerable key wider than zod's. Each issue is COPIED\n * without them rather than `delete`d from: removing a key that is not the last\n * one added drops the object into V8's dictionary mode, ~70 ns an issue. `.error`\n * over six issues went 1.49 -> 1.06 us, over one 653 -> 608 ns. The copy keeps\n * key order and takes own keys only, so an enumerable key added to\n * `Object.prototype` stays out, as it does from zod's spread. All of it runs only\n * after a caller asks for `.error` on a failed parse, and is memoised in `_c`.\n */\nexport const FAIL_CLASS_DECL = failClassDecl(\"__ZcFail\", \"__zcZodError\");\n\n/**\n * {@link FAIL_CLASS_DECL} for a schema that fails with zod/v4/core's\n * `$ZodError` instead of classic's `ZodError`: `zod/mini`, whose methods call\n * core's parse functions, and raw core (see zodErrorClassOf). The finalization\n * is identical; only the class constructed at the end differs, and with it\n * everything the class carries (`name`, the trait `instanceof` tests,\n * classic's `.format()`/`.flatten()`).\n *\n * A class of its own, with its own finalizers, rather than a constructor\n * picked per failure: generated code names the pair its schema needs, so a\n * bundle keeps only the class its validators construct (see failClassDecl).\n */\nexport const FAIL_CORE_CLASS_DECL = failClassDecl(\"__ZcFailC\", \"__zcCore.$ZodRealError\");\n\n/**\n * The failure class, for either error flavor; `errorClass` is the constructor\n * expression.\n *\n * Wrapped in a `@__PURE__` IIFE so a bundle drops whichever class its\n * validators never construct. A bare declaration is kept by every bundler\n * for the `Object.defineProperty` that installs the getter (rolldown and\n * esbuild both measured): the core class would cost every classic bundle\n * ~500 B, and the classic class cost every `zod/mini` bundle 2.3-3.1 KB, since\n * it carries classic zod's error class in with it. The wrapper itself costs a\n * classic bundle 26-64 B.\n *\n * The binding is a `var`, not a hoisted function, so it must be initialized\n * before a validator fails. Every emitter declares it at the head of the module\n * (or of the evaluated body, under `jit()`), ahead of the finalizers and of\n * every statement that could run a validator.\n */\nfunction failClassDecl(name: string, errorClass: string): string {\n return (\n `var ${name}=/* @__PURE__ */(function(){` +\n `function ${name}(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}` +\n `Object.defineProperty(${name}.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++){var s=e[i],o={},k;if(s.message===undefined&&typeof __zcMsg===\"function\")s.message=__zcMsg(s);' +\n 'for(k in s){if(k!==\"input\"&&k!==\"continue\"&&Object.prototype.hasOwnProperty.call(s,k))o[k]=s[k];}e[i]=o;}' +\n `return this._c=new ${errorClass}(e);}});` +\n `return ${name};})();`\n );\n}\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 = finDecl(FINALIZERS.ZodError.eager, \"__ZcFail\");\n\n/** {@link FIN_DECL} for schemas failing with core's `$ZodError` (see {@link FAIL_CORE_CLASS_DECL}). */\nexport const FIN_CORE_DECL = finDecl(FINALIZERS.$ZodError.eager, \"__ZcFailC\");\n\nfunction finDecl(name: string, failClass: string): string {\n return `function ${name}(e,d){if(!e.length)return{success:true,data:d};return new ${failClass}(e,null,null);}`;\n}\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 = finDeferredDecl(FINALIZERS.ZodError.deferred, \"__ZcFail\");\n\n/** {@link FIN_DEFERRED_DECL} for schemas failing with core's `$ZodError` (see {@link FAIL_CORE_CLASS_DECL}). */\nexport const FIN_DEFERRED_CORE_DECL = finDeferredDecl(FINALIZERS.$ZodError.deferred, \"__ZcFailC\");\n\nfunction finDeferredDecl(name: string, failClass: string): string {\n return `function ${name}(f,inp){return new ${failClass}(null,f,inp);}`;\n}\n\n/**\n * Whether generated code that uses `helpers` builds core `$ZodError`s.\n *\n * Every emitter has always supplied the classic `__zcFin` whether or not any\n * validator calls it. A file whose validators fail with core errors skips that\n * default (a validator that does call it names it anyway): there it would be\n * dead code that reaches for classic zod's error class.\n */\nexport function usesCoreErrors(helpers: ReadonlySet<string>): boolean {\n return helpers.has(FINALIZERS.$ZodError.eager) || helpers.has(FINALIZERS.$ZodError.deferred);\n}\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 *\n * A rebuilding schema (no `fc`) reaches `parse()` through `fn`, i.e. through a\n * SafeParseResult unwrapped a line later. Handing the build function over so\n * `parse()` could call it directly was measured and declined: the wrapper is a\n * young-generation bump allocation that V8 elides outright where `fn` inlines,\n * and even across eight schemas sharing this closure — where it cannot — the\n * direct call came out level (41.5 vs 41.8 ns), for a wider signature on every\n * bundle.\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 * a prototype getter that binds the method and installs the bound copy on the\n * instance without touching the schema's structure.\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":";;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,oBACX;;;;;;;;;;;;;;;;;;;;AAsBF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CF,MAAa,kBAAkB,cAAc,YAAY,cAAc;;;;;;;;;;;;;AAcvE,MAAa,uBAAuB,cAAc,aAAa,wBAAwB;;;;;;;;;;;;;;;;;;AAmBvF,SAAS,cAAc,MAAc,YAA4B;CAC/D,OACE,OAAO,KAAK,uCACA,KAAK,oGACQ,KAAK,oXAKR,WAAW,iBACvB,KAAK;AAEnB;;;AAIA,MAAa,WAAW,QAAQ,WAAW,SAAS,OAAO,UAAU;;AAGrE,MAAa,gBAAgB,QAAQ,WAAW,UAAU,OAAO,WAAW;AAE5E,SAAS,QAAQ,MAAc,WAA2B;CACxD,OAAO,YAAY,KAAK,4DAA4D,UAAU;AAChG;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,oBAAoB,gBAAgB,WAAW,SAAS,UAAU,UAAU;;AAGzF,MAAa,yBAAyB,gBAAgB,WAAW,UAAU,UAAU,WAAW;AAEhG,SAAS,gBAAgB,MAAc,WAA2B;CAChE,OAAO,YAAY,KAAK,qBAAqB,UAAU;AACzD;;;;;;;;;AAUA,SAAgB,eAAe,SAAuC;CACpE,OAAO,QAAQ,IAAI,WAAW,UAAU,KAAK,KAAK,QAAQ,IAAI,WAAW,UAAU,QAAQ;AAC7F;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqGzB,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;;;;;;;;;;;;;;;;;AAkBA,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"}