zod-compiler 1.26.1 → 1.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/emitter.d.ts.map +1 -1
- package/dist/cli/emitter.js +3 -2
- package/dist/cli/emitter.js.map +1 -1
- package/dist/core/codegen/build-path.d.ts.map +1 -1
- package/dist/core/codegen/build-path.js +15 -6
- package/dist/core/codegen/build-path.js.map +1 -1
- package/dist/core/codegen/context.d.ts +72 -17
- package/dist/core/codegen/context.d.ts.map +1 -1
- package/dist/core/codegen/context.js +75 -16
- package/dist/core/codegen/context.js.map +1 -1
- package/dist/core/codegen/index.d.ts +5 -5
- package/dist/core/codegen/index.d.ts.map +1 -1
- package/dist/core/codegen/index.js +11 -11
- package/dist/core/codegen/index.js.map +1 -1
- package/dist/core/codegen/well-known-regex.d.ts.map +1 -1
- package/dist/core/codegen/well-known-regex.js +16 -0
- package/dist/core/codegen/well-known-regex.js.map +1 -1
- package/dist/core/iife.d.ts +31 -10
- package/dist/core/iife.d.ts.map +1 -1
- package/dist/core/iife.js +41 -13
- package/dist/core/iife.js.map +1 -1
- package/dist/core/pipeline.d.ts +5 -5
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +61 -35
- package/dist/core/pipeline.js.map +1 -1
- package/dist/jit.d.ts.map +1 -1
- package/dist/jit.js.map +1 -1
- package/dist/runtime.d.ts +6 -0
- package/dist/runtime.js +7 -1
- package/dist/unplugin/virtual.js +1 -1
- 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 GeneratedSetConstant,\n RecTargetGen,\n} from \"./context.js\";\nimport { fastResultIsInput, generateBuild, rebuildsOutput } from \"./build-path.js\";\nimport { declareFastTemps, emitRfDelegate, emitRfMethod, hasMutation } from \"./context.js\";\nimport type { SharedSchemaPlan } from \"./dedupe.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.rootDelegateRefIndex}.\n */\n compact?: boolean | undefined;\n /** Internal file-pipeline hook for sharing exact Set initializers across validators. */\n onSetConstant?: ((constant: GeneratedSetConstant) => void) | undefined;\n /** Internal exact-initializer plan used by the file pipeline's final generation pass. */\n sharedSetNames?: 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 onSetConstant: options?.onSetConstant,\n sharedSetNames: options?.sharedSetNames,\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 const fg = createFastGen(\"input\", ctx);\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);\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 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. A substituted `.default()` breaks that: the\n // fast check demands a present value where the schema accepts its absence, so\n // the predicate is partial and `.is()` falls back to safeParse().success\n // (which runs the build pass, so it is no slower than the eager walk was).\n const buildIsFnName = ctx.buildSubstitutesValue === true ? null : 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 !hasNonRootTargets\n ) {\n const delegate = emitRfMethod(ctx, baseRefCount);\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},__rf[${baseRefCount}],input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount + 1,\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 rootDelegateRefIndex: baseRefCount,\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 = emitRfMethod(ctx, baseRefCount);\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},__rf[${baseRefCount}],input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount + 1,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n isFnName: buildIsFnName,\n rootDelegateRefIndex: baseRefCount,\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)) {\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:input};}`,\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:input};}`,\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 fastFnName,\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 };\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 { SchemaIR } from \"../types.js\";\nimport type {\n CodeGenContext,\n CodeGenResult,\n CodegenMode,\n GeneratedConstant,\n RecTargetGen,\n} from \"./context.js\";\nimport { fastResultIsInput, generateBuild, rebuildsOutput } from \"./build-path.js\";\nimport {\n declareFastTemps,\n emitRetainedMethod,\n emitRfDelegate,\n hasMutation,\n RETAINED_SCHEMA_VAR,\n} from \"./context.js\";\nimport type { SharedSchemaPlan } from \"./dedupe.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 const fg = createFastGen(\"input\", ctx);\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);\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 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. A substituted `.default()` breaks that: the\n // fast check demands a present value where the schema accepts its absence, so\n // the predicate is partial and `.is()` falls back to safeParse().success\n // (which runs the build pass, so it is no slower than the eager walk was).\n const buildIsFnName = ctx.buildSubstitutesValue === true ? null : 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 !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)) {\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:input};}`,\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:input};}`,\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 fastFnName,\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 };\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"well-known-regex.d.ts","names":[],"sources":["../../../src/core/codegen/well-known-regex.ts"],"mappings":";;;;;;;;;;;;cAca;;;;;;;;;;;;;cAcA;;cAGA;UAGI;;EAEf;;EAEA;;;;;;EAMA;;cAGW,6BAA6B;;;;;
|
|
1
|
+
{"version":3,"file":"well-known-regex.d.ts","names":[],"sources":["../../../src/core/codegen/well-known-regex.ts"],"mappings":";;;;;;;;;;;;cAca;;;;;;;;;;;;;cAcA;;cAGA;UAGI;;EAEf;;EAEA;;;;;;EAMA;;cAGW,6BAA6B;;;;;iBAqE1B,qBAAqB;;;;;;;;;iBAYrB,sBAAsB;;;;;;;;;;;;;;;;iBAmBtB,eAAe;;;;;;;iBAWf,yBAAyB"}
|
|
@@ -84,6 +84,22 @@ const WELL_KNOWN_REGEXES = [
|
|
|
84
84
|
{
|
|
85
85
|
name: "__zcReGuid",
|
|
86
86
|
source: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "__zcReIsoDate",
|
|
90
|
+
source: "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "__zcReIsoTime",
|
|
94
|
+
source: "^(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?$"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "__zcReIsoDateTime",
|
|
98
|
+
source: "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "__zcReIsoDuration",
|
|
102
|
+
source: "^P(?:(\\d+W)|(?!.*W)(?=\\d|T\\d)(\\d+Y)?(\\d+M)?(\\d+D)?(T(?=\\d)(\\d+H)?(\\d+M)?(\\d+([.,]\\d+)?S)?)?)$"
|
|
87
103
|
}
|
|
88
104
|
];
|
|
89
105
|
const SOURCE_TO_NAME = new Map(WELL_KNOWN_REGEXES.map((r) => [r.source, r.name]));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"well-known-regex.js","names":[],"sources":["../../../src/core/codegen/well-known-regex.ts"],"sourcesContent":["/**\n * Well-known regex sources hosted in the virtual module \"virtual:zod-compiler/runtime\".\n *\n * In lean mode (unplugin), `g.regex()` consults this registry and emits a reference\n * like `__zcReEmail` instead of declaring `var __re_email_*=new RegExp(...)`.\n * The bundler then deduplicates the regex literal across all transformed files.\n *\n * Pattern sources are matched verbatim (string equality). Add new entries as Zod\n * exposes additional well-known formats and we want bundle-wide dedup.\n */\n\nimport { unrollRepeats } from \"./regex-unroll.js\";\n\n/** Zod v4's email regex source (string.ts uses this directly when format === \"email\"). */\nexport const EMAIL_REGEX_SOURCE = String.raw`^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$`;\n\n/**\n * Behavior-equivalent rewrite of EMAIL_REGEX_SOURCE that runs ~1.45x faster on V8.\n *\n * Zod's pattern fronts two lookaheads; `(?!.*\\.\\.)` re-scans the entire string\n * before matching starts. The rewrite encodes the same constraints structurally:\n * the local part is dot-separated runs of `[A-Za-z0-9_'+-]` (no leading dot, no\n * empty run ⇒ no `..`) ending in `[A-Za-z0-9_+-]`, and the domain grammar already\n * makes `..` impossible (every label starts with an alphanumeric).\n *\n * Equivalence is enforced by tests/core/codegen/email-fast-regex.test.ts\n * (exhaustive short-string sweep + structured cases + random fuzz).\n */\nexport const EMAIL_FAST_REGEX_SOURCE = String.raw`^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$`;\n\n/** Fallback UUID regex used when the extractor doesn't provide a pattern (e.g. in unit tests). */\nexport const UUID_REGEX_SOURCE =\n \"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$\";\n\nexport interface WellKnownRegex {\n /** Stable virtual-module export name. Always starts with \"__zcRe\". */\n name: string;\n /** Pattern source string (verbatim match against `g.regex()` 2nd argument). */\n source: string;\n /**\n * Behavior-equivalent faster pattern used for the actual `.test()` regex.\n * Issue reporting (`pattern:` field) always uses `source` so generated\n * issues stay byte-identical to zod's.\n */\n testSource?: string;\n}\n\nexport const WELL_KNOWN_REGEXES: readonly WellKnownRegex[] = [\n { name: \"__zcReEmail\", source: EMAIL_REGEX_SOURCE, testSource: EMAIL_FAST_REGEX_SOURCE },\n { name: \"__zcReUuid\", source: UUID_REGEX_SOURCE },\n { name: \"__zcReCuid\", source: \"^[cC][^\\\\s-]{8,}$\" },\n { name: \"__zcReCuid2\", source: \"^[0-9a-z]+$\" },\n { name: \"__zcReUlid\", source: \"^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$\" },\n { name: \"__zcReNanoid\", source: \"^[a-zA-Z0-9_-]{21}$\" },\n { name: \"__zcReXid\", source: \"^[0-9a-vA-V]{20}$\" },\n { name: \"__zcReKsuid\", source: \"^[A-Za-z0-9]{27}$\" },\n {\n name: \"__zcReIpv4\",\n source:\n \"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$\",\n },\n {\n name: \"__zcReIpv6\",\n source:\n \"^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$\",\n },\n {\n name: \"__zcReBase64\",\n source: \"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$\",\n },\n { name: \"__zcReBase64Url\", source: \"^[A-Za-z0-9_-]*$\" },\n { name: \"__zcReE164\", source: \"^\\\\+[1-9]\\\\d{6,14}$\" },\n {\n name: \"__zcReGuid\",\n source: \"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$\",\n },\n];\n\nconst SOURCE_TO_NAME: ReadonlyMap<string, string> = new Map(\n WELL_KNOWN_REGEXES.map((r) => [r.source, r.name]),\n);\n\nconst SOURCE_TO_TEST_SOURCE: ReadonlyMap<string, string> = new Map(\n WELL_KNOWN_REGEXES.filter((r) => r.testSource !== undefined).map((r) => [\n r.source,\n r.testSource as string,\n ]),\n);\n\n/**\n * Look up a well-known regex by its pattern source string.\n * Returns the virtual-module export name or null if the pattern is user-defined.\n */\nexport function lookupWellKnownRegex(source: string): string | null {\n return SOURCE_TO_NAME.get(source) ?? null;\n}\n\n/**\n * Look up the hand-written behavior-equivalent test pattern for a regex source.\n * Returns null when no rewrite is registered in {@link WELL_KNOWN_REGEXES}.\n *\n * This is the TABLE lookup only. Codegen calls {@link fastTestSource}, which\n * layers automatic repeat unrolling on top and also covers user-supplied\n * patterns that are in no table.\n */\nexport function lookupFastRegexSource(source: string): string | null {\n return SOURCE_TO_TEST_SOURCE.get(source) ?? null;\n}\n\n/**\n * The pattern a generated `.test()` should actually run for `source`, or null\n * when `source` is already the best form.\n *\n * Two behavior-preserving rewrites compose here: the hand-written table entry\n * above (currently just email), then {@link unrollRepeats}, which turns bounded\n * repeats of single-character atoms into explicit repetition — worth 1.3-3.4x\n * on the string formats everyday schemas use (uuid, guid, ulid, nanoid, xid,\n * ksuid, base64, e164, iso.date). Unrolling runs on the table rewrite when\n * there is one, so the two stack.\n *\n * Callers must apply this only to flag-less regexes (the flagged form would\n * need its flags carried into the reported pattern too) and must keep\n * reporting the ORIGINAL source in issues — see `emitRegexSourceString`.\n */\nexport function fastTestSource(source: string): string | null {\n const tableRewrite = SOURCE_TO_TEST_SOURCE.get(source) ?? null;\n return unrollRepeats(tableRewrite ?? source) ?? tableRewrite;\n}\n\n/**\n * Virtual-module export name for the ORIGINAL `/source/` pattern string of a\n * rewritten well-known regex (e.g. \"__zcReEmailSrc\"). Issue sites reference it\n * so the original pattern stays a single bundle-wide string even though the\n * runtime regex object is built from testSource.\n */\nexport function wellKnownRegexSourceName(source: string): string | null {\n const name = SOURCE_TO_NAME.get(source);\n if (name === undefined) return null;\n return fastTestSource(source) !== null ? `${name}Src` : null;\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,MAAa,qBAAqB,OAAO,GAAG;;;;;;;;;;;;;AAc5C,MAAa,0BAA0B,OAAO,GAAG;;AAGjD,MAAa,oBACX;AAeF,MAAa,qBAAgD;CAC3D;EAAE,MAAM;EAAe,QAAQ;EAAoB,YAAY;CAAwB;CACvF;EAAE,MAAM;EAAc,QAAQ;CAAkB;CAChD;EAAE,MAAM;EAAc,QAAQ;CAAoB;CAClD;EAAE,MAAM;EAAe,QAAQ;CAAc;CAC7C;EAAE,MAAM;EAAc,QAAQ;CAAwC;CACtE;EAAE,MAAM;EAAgB,QAAQ;CAAsB;CACtD;EAAE,MAAM;EAAa,QAAQ;CAAoB;CACjD;EAAE,MAAM;EAAe,QAAQ;CAAoB;CACnD;EACE,MAAM;EACN,QACE;CACJ;CACA;EACE,MAAM;EACN,QACE;CACJ;CACA;EACE,MAAM;EACN,QAAQ;CACV;CACA;EAAE,MAAM;EAAmB,QAAQ;CAAmB;CACtD;EAAE,MAAM;EAAc,QAAQ;CAAsB;CACpD;EACE,MAAM;EACN,QAAQ;CACV;AACF;AAEA,MAAM,iBAA8C,IAAI,IACtD,mBAAmB,KAAK,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAClD;AAEA,MAAM,wBAAqD,IAAI,IAC7D,mBAAmB,QAAQ,MAAM,EAAE,eAAe,KAAA,CAAS,CAAC,CAAC,KAAK,MAAM,CACtE,EAAE,QACF,EAAE,UACJ,CAAC,CACH;;;;;AAMA,SAAgB,qBAAqB,QAA+B;CAClE,OAAO,eAAe,IAAI,MAAM,KAAK;AACvC;;;;;;;;;AAUA,SAAgB,sBAAsB,QAA+B;CACnE,OAAO,sBAAsB,IAAI,MAAM,KAAK;AAC9C;;;;;;;;;;;;;;;;AAiBA,SAAgB,eAAe,QAA+B;CAC5D,MAAM,eAAe,sBAAsB,IAAI,MAAM,KAAK;CAC1D,OAAO,cAAc,gBAAgB,MAAM,KAAK;AAClD;;;;;;;AAQA,SAAgB,yBAAyB,QAA+B;CACtE,MAAM,OAAO,eAAe,IAAI,MAAM;CACtC,IAAI,SAAS,KAAA,GAAW,OAAO;CAC/B,OAAO,eAAe,MAAM,MAAM,OAAO,GAAG,KAAK,OAAO;AAC1D"}
|
|
1
|
+
{"version":3,"file":"well-known-regex.js","names":[],"sources":["../../../src/core/codegen/well-known-regex.ts"],"sourcesContent":["/**\n * Well-known regex sources hosted in the virtual module \"virtual:zod-compiler/runtime\".\n *\n * In lean mode (unplugin), `g.regex()` consults this registry and emits a reference\n * like `__zcReEmail` instead of declaring `var __re_email_*=new RegExp(...)`.\n * The bundler then deduplicates the regex literal across all transformed files.\n *\n * Pattern sources are matched verbatim (string equality). Add new entries as Zod\n * exposes additional well-known formats and we want bundle-wide dedup.\n */\n\nimport { unrollRepeats } from \"./regex-unroll.js\";\n\n/** Zod v4's email regex source (string.ts uses this directly when format === \"email\"). */\nexport const EMAIL_REGEX_SOURCE = String.raw`^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$`;\n\n/**\n * Behavior-equivalent rewrite of EMAIL_REGEX_SOURCE that runs ~1.45x faster on V8.\n *\n * Zod's pattern fronts two lookaheads; `(?!.*\\.\\.)` re-scans the entire string\n * before matching starts. The rewrite encodes the same constraints structurally:\n * the local part is dot-separated runs of `[A-Za-z0-9_'+-]` (no leading dot, no\n * empty run ⇒ no `..`) ending in `[A-Za-z0-9_+-]`, and the domain grammar already\n * makes `..` impossible (every label starts with an alphanumeric).\n *\n * Equivalence is enforced by tests/core/codegen/email-fast-regex.test.ts\n * (exhaustive short-string sweep + structured cases + random fuzz).\n */\nexport const EMAIL_FAST_REGEX_SOURCE = String.raw`^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$`;\n\n/** Fallback UUID regex used when the extractor doesn't provide a pattern (e.g. in unit tests). */\nexport const UUID_REGEX_SOURCE =\n \"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$\";\n\nexport interface WellKnownRegex {\n /** Stable virtual-module export name. Always starts with \"__zcRe\". */\n name: string;\n /** Pattern source string (verbatim match against `g.regex()` 2nd argument). */\n source: string;\n /**\n * Behavior-equivalent faster pattern used for the actual `.test()` regex.\n * Issue reporting (`pattern:` field) always uses `source` so generated\n * issues stay byte-identical to zod's.\n */\n testSource?: string;\n}\n\nexport const WELL_KNOWN_REGEXES: readonly WellKnownRegex[] = [\n { name: \"__zcReEmail\", source: EMAIL_REGEX_SOURCE, testSource: EMAIL_FAST_REGEX_SOURCE },\n { name: \"__zcReUuid\", source: UUID_REGEX_SOURCE },\n { name: \"__zcReCuid\", source: \"^[cC][^\\\\s-]{8,}$\" },\n { name: \"__zcReCuid2\", source: \"^[0-9a-z]+$\" },\n { name: \"__zcReUlid\", source: \"^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$\" },\n { name: \"__zcReNanoid\", source: \"^[a-zA-Z0-9_-]{21}$\" },\n { name: \"__zcReXid\", source: \"^[0-9a-vA-V]{20}$\" },\n { name: \"__zcReKsuid\", source: \"^[A-Za-z0-9]{27}$\" },\n {\n name: \"__zcReIpv4\",\n source:\n \"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$\",\n },\n {\n name: \"__zcReIpv6\",\n source:\n \"^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$\",\n },\n {\n name: \"__zcReBase64\",\n source: \"^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$\",\n },\n { name: \"__zcReBase64Url\", source: \"^[A-Za-z0-9_-]*$\" },\n { name: \"__zcReE164\", source: \"^\\\\+[1-9]\\\\d{6,14}$\" },\n {\n name: \"__zcReGuid\",\n source: \"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$\",\n },\n // The ISO family. Zod BUILDS these from the call's options, so only the\n // default spelling is a fixed string — `z.iso.datetime({ offset: true })` or\n // `{ precision: 3 }` produces a different source that simply misses this\n // exact-match table and keeps its per-IIFE declaration. Defaults are worth\n // listing anyway: `z.iso.datetime()` is everywhere in API schemas and its\n // pattern is ~330 characters, so a bundle that repeats it per validator pays\n // for it in bytes and in a RegExp construction per schema at module init.\n {\n name: \"__zcReIsoDate\",\n source:\n \"^(?:(?:\\\\d\\\\d[2468][048]|\\\\d\\\\d[13579][26]|\\\\d\\\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\\\d|30)|(?:02)-(?:0[1-9]|1\\\\d|2[0-8])))$\",\n },\n { name: \"__zcReIsoTime\", source: \"^(?:[01]\\\\d|2[0-3]):[0-5]\\\\d(?::[0-5]\\\\d(?:\\\\.\\\\d+)?)?$\" },\n {\n name: \"__zcReIsoDateTime\",\n source:\n \"^(?:(?:\\\\d\\\\d[2468][048]|\\\\d\\\\d[13579][26]|\\\\d\\\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\\\d|30)|(?:02)-(?:0[1-9]|1\\\\d|2[0-8])))T(?:(?:[01]\\\\d|2[0-3]):[0-5]\\\\d(?::[0-5]\\\\d(?:\\\\.\\\\d+)?)?(?:Z))$\",\n },\n {\n name: \"__zcReIsoDuration\",\n source:\n \"^P(?:(\\\\d+W)|(?!.*W)(?=\\\\d|T\\\\d)(\\\\d+Y)?(\\\\d+M)?(\\\\d+D)?(T(?=\\\\d)(\\\\d+H)?(\\\\d+M)?(\\\\d+([.,]\\\\d+)?S)?)?)$\",\n },\n];\n\nconst SOURCE_TO_NAME: ReadonlyMap<string, string> = new Map(\n WELL_KNOWN_REGEXES.map((r) => [r.source, r.name]),\n);\n\nconst SOURCE_TO_TEST_SOURCE: ReadonlyMap<string, string> = new Map(\n WELL_KNOWN_REGEXES.filter((r) => r.testSource !== undefined).map((r) => [\n r.source,\n r.testSource as string,\n ]),\n);\n\n/**\n * Look up a well-known regex by its pattern source string.\n * Returns the virtual-module export name or null if the pattern is user-defined.\n */\nexport function lookupWellKnownRegex(source: string): string | null {\n return SOURCE_TO_NAME.get(source) ?? null;\n}\n\n/**\n * Look up the hand-written behavior-equivalent test pattern for a regex source.\n * Returns null when no rewrite is registered in {@link WELL_KNOWN_REGEXES}.\n *\n * This is the TABLE lookup only. Codegen calls {@link fastTestSource}, which\n * layers automatic repeat unrolling on top and also covers user-supplied\n * patterns that are in no table.\n */\nexport function lookupFastRegexSource(source: string): string | null {\n return SOURCE_TO_TEST_SOURCE.get(source) ?? null;\n}\n\n/**\n * The pattern a generated `.test()` should actually run for `source`, or null\n * when `source` is already the best form.\n *\n * Two behavior-preserving rewrites compose here: the hand-written table entry\n * above (currently just email), then {@link unrollRepeats}, which turns bounded\n * repeats of single-character atoms into explicit repetition — worth 1.3-3.4x\n * on the string formats everyday schemas use (uuid, guid, ulid, nanoid, xid,\n * ksuid, base64, e164, iso.date). Unrolling runs on the table rewrite when\n * there is one, so the two stack.\n *\n * Callers must apply this only to flag-less regexes (the flagged form would\n * need its flags carried into the reported pattern too) and must keep\n * reporting the ORIGINAL source in issues — see `emitRegexSourceString`.\n */\nexport function fastTestSource(source: string): string | null {\n const tableRewrite = SOURCE_TO_TEST_SOURCE.get(source) ?? null;\n return unrollRepeats(tableRewrite ?? source) ?? tableRewrite;\n}\n\n/**\n * Virtual-module export name for the ORIGINAL `/source/` pattern string of a\n * rewritten well-known regex (e.g. \"__zcReEmailSrc\"). Issue sites reference it\n * so the original pattern stays a single bundle-wide string even though the\n * runtime regex object is built from testSource.\n */\nexport function wellKnownRegexSourceName(source: string): string | null {\n const name = SOURCE_TO_NAME.get(source);\n if (name === undefined) return null;\n return fastTestSource(source) !== null ? `${name}Src` : null;\n}\n"],"mappings":";;;;;;;;;;;;;AAcA,MAAa,qBAAqB,OAAO,GAAG;;;;;;;;;;;;;AAc5C,MAAa,0BAA0B,OAAO,GAAG;;AAGjD,MAAa,oBACX;AAeF,MAAa,qBAAgD;CAC3D;EAAE,MAAM;EAAe,QAAQ;EAAoB,YAAY;CAAwB;CACvF;EAAE,MAAM;EAAc,QAAQ;CAAkB;CAChD;EAAE,MAAM;EAAc,QAAQ;CAAoB;CAClD;EAAE,MAAM;EAAe,QAAQ;CAAc;CAC7C;EAAE,MAAM;EAAc,QAAQ;CAAwC;CACtE;EAAE,MAAM;EAAgB,QAAQ;CAAsB;CACtD;EAAE,MAAM;EAAa,QAAQ;CAAoB;CACjD;EAAE,MAAM;EAAe,QAAQ;CAAoB;CACnD;EACE,MAAM;EACN,QACE;CACJ;CACA;EACE,MAAM;EACN,QACE;CACJ;CACA;EACE,MAAM;EACN,QAAQ;CACV;CACA;EAAE,MAAM;EAAmB,QAAQ;CAAmB;CACtD;EAAE,MAAM;EAAc,QAAQ;CAAsB;CACpD;EACE,MAAM;EACN,QAAQ;CACV;CAQA;EACE,MAAM;EACN,QACE;CACJ;CACA;EAAE,MAAM;EAAiB,QAAQ;CAA0D;CAC3F;EACE,MAAM;EACN,QACE;CACJ;CACA;EACE,MAAM;EACN,QACE;CACJ;AACF;AAEA,MAAM,iBAA8C,IAAI,IACtD,mBAAmB,KAAK,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAClD;AAEA,MAAM,wBAAqD,IAAI,IAC7D,mBAAmB,QAAQ,MAAM,EAAE,eAAe,KAAA,CAAS,CAAC,CAAC,KAAK,MAAM,CACtE,EAAE,QACF,EAAE,UACJ,CAAC,CACH;;;;;AAMA,SAAgB,qBAAqB,QAA+B;CAClE,OAAO,eAAe,IAAI,MAAM,KAAK;AACvC;;;;;;;;;AAUA,SAAgB,sBAAsB,QAA+B;CACnE,OAAO,sBAAsB,IAAI,MAAM,KAAK;AAC9C;;;;;;;;;;;;;;;;AAiBA,SAAgB,eAAe,QAA+B;CAC5D,MAAM,eAAe,sBAAsB,IAAI,MAAM,KAAK;CAC1D,OAAO,cAAc,gBAAgB,MAAM,KAAK;AAClD;;;;;;;AAQA,SAAgB,yBAAyB,QAA+B;CACtE,MAAM,OAAO,eAAe,IAAI,MAAM;CACtC,IAAI,SAAS,KAAA,GAAW,OAAO;CAC/B,OAAO,eAAe,MAAM,MAAM,OAAO,GAAG,KAAK,OAAO;AAC1D"}
|
package/dist/core/iife.d.ts
CHANGED
|
@@ -101,11 +101,13 @@ declare const FIN_DEFERRED_DECL = "function __zcFinD(f,inp){return new __ZcFail(
|
|
|
101
101
|
* path is produced by the retained Zod schema itself (`zod` is the source of
|
|
102
102
|
* truth, so the issues are byte-identical — no second validation engine).
|
|
103
103
|
*
|
|
104
|
-
* `_z` is the schema's PRISTINE safeParse method
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
104
|
+
* `_z` is the schema's PRISTINE safeParse method, captured by
|
|
105
|
+
* emitRetainedMethod (see context.ts), and `_r` is its receiver — the `__zs`
|
|
106
|
+
* binding generateIIFE places above that capture. Both are read before the
|
|
107
|
+
* trailing `__zcMkv` call installs anything, so the method is zod's own
|
|
108
|
+
* implementation, never the compiled delegate, avoiding infinite recursion
|
|
109
|
+
* without allocating a bound function. The zod parse is deferred until `.error`
|
|
110
|
+
* is read and cached, so
|
|
109
111
|
* the common `safeParse(x).success`/`.is(x)` checks on invalid input cost only
|
|
110
112
|
* the fast check (zod never runs) — the same deferral boundary `__zcFinD`
|
|
111
113
|
* establishes for the compiled slow walk. Sound because compact mode is gated
|
|
@@ -180,12 +182,31 @@ declare const FINZ_DECL = "function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);
|
|
|
180
182
|
* 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema
|
|
181
183
|
* consumers (tRPC, Hono, TanStack) were getting plain Zod.
|
|
182
184
|
*
|
|
183
|
-
* Zod's own
|
|
184
|
-
*
|
|
185
|
+
* Zod's own `~standard` is never READ, only overwritten. Zod installs the slot
|
|
186
|
+
* with `util.defineLazy` — commented there as "avoid creating objects for every
|
|
187
|
+
* schema" — so it is an accessor that builds `{version, vendor, validate}` plus
|
|
188
|
+
* its closure on first touch. Reading it to capture a fallback fired that getter
|
|
189
|
+
* for every compiled schema while the module was still initializing.
|
|
190
|
+
*
|
|
191
|
+
* How much that costs depends on the entry point, and only one of them is free:
|
|
192
|
+
* classic `zod` forces the slot itself during `ZodType.init` (it does
|
|
193
|
+
* `Object.assign(inst["~standard"], { jsonSchema })`), so there the read hit an
|
|
194
|
+
* already-built object and cost only an accessor call. `zod/mini` and raw
|
|
195
|
+
* `zod/v4/core` never touch it, so for those the read built — and retained — an
|
|
196
|
+
* object and a closure per schema, purely to capture a fallback the schema will
|
|
197
|
+
* most likely never expose to a Standard Schema consumer.
|
|
198
|
+
*
|
|
199
|
+
* The throw path is rebuilt instead of captured. Zod's validate catches a
|
|
200
|
+
* synchronous throw and retries through `safeParseAsync` — that is how an async
|
|
185
201
|
* refinement resolves and how a throwing check surfaces as a rejected promise
|
|
186
|
-
* rather than a synchronous throw
|
|
187
|
-
*
|
|
188
|
-
*
|
|
202
|
+
* rather than a synchronous throw — so calling the already-captured `zspa` and
|
|
203
|
+
* mapping its result is the same route to the same result. `vendor` is likewise
|
|
204
|
+
* a constant: schema discovery only ever admits zod schemas, and classic, mini
|
|
205
|
+
* and core all hardcode `vendor: "zod"` themselves.
|
|
206
|
+
*
|
|
207
|
+
* Not carried over (unchanged by this, and pre-dating it): classic's
|
|
208
|
+
* `~standard.jsonSchema` extension, which the replacement object has never
|
|
209
|
+
* reproduced.
|
|
189
210
|
*
|
|
190
211
|
* Installed with defineProperty rather than assignment: Zod's lazy setter
|
|
191
212
|
* redefines the slot as non-writable, so a second `__zcMkv` on the same schema
|
package/dist/core/iife.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAca;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8CA;;;cAUA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6FA;;;;;;;;;iBAqBG,aACd,oBACA,QAAQ,oBACR;EAAY"}
|
package/dist/core/iife.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { RETAINED_SCHEMA_VAR } from "./codegen/context.js";
|
|
1
2
|
//#region src/core/iife.ts
|
|
2
3
|
/**
|
|
4
|
+
* Shared CompiledSchema<T> IIFE generation.
|
|
5
|
+
* Used by both CLI emitter and unplugin transform.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
3
8
|
* Import statement required by generateIIFE output (references
|
|
4
9
|
* __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and
|
|
5
10
|
* custom callbacks may only reveal that they are async through the promise
|
|
@@ -100,11 +105,13 @@ const FIN_DEFERRED_DECL = "function __zcFinD(f,inp){return new __ZcFail(null,f,i
|
|
|
100
105
|
* path is produced by the retained Zod schema itself (`zod` is the source of
|
|
101
106
|
* truth, so the issues are byte-identical — no second validation engine).
|
|
102
107
|
*
|
|
103
|
-
* `_z` is the schema's PRISTINE safeParse method
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
+
* `_z` is the schema's PRISTINE safeParse method, captured by
|
|
109
|
+
* emitRetainedMethod (see context.ts), and `_r` is its receiver — the `__zs`
|
|
110
|
+
* binding generateIIFE places above that capture. Both are read before the
|
|
111
|
+
* trailing `__zcMkv` call installs anything, so the method is zod's own
|
|
112
|
+
* implementation, never the compiled delegate, avoiding infinite recursion
|
|
113
|
+
* without allocating a bound function. The zod parse is deferred until `.error`
|
|
114
|
+
* is read and cached, so
|
|
108
115
|
* the common `safeParse(x).success`/`.is(x)` checks on invalid input cost only
|
|
109
116
|
* the fast check (zod never runs) — the same deferral boundary `__zcFinD`
|
|
110
117
|
* establishes for the compiled slow walk. Sound because compact mode is gated
|
|
@@ -179,18 +186,37 @@ const FINZ_DECL = "function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);}";
|
|
|
179
186
|
* 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema
|
|
180
187
|
* consumers (tRPC, Hono, TanStack) were getting plain Zod.
|
|
181
188
|
*
|
|
182
|
-
* Zod's own
|
|
183
|
-
*
|
|
189
|
+
* Zod's own `~standard` is never READ, only overwritten. Zod installs the slot
|
|
190
|
+
* with `util.defineLazy` — commented there as "avoid creating objects for every
|
|
191
|
+
* schema" — so it is an accessor that builds `{version, vendor, validate}` plus
|
|
192
|
+
* its closure on first touch. Reading it to capture a fallback fired that getter
|
|
193
|
+
* for every compiled schema while the module was still initializing.
|
|
194
|
+
*
|
|
195
|
+
* How much that costs depends on the entry point, and only one of them is free:
|
|
196
|
+
* classic `zod` forces the slot itself during `ZodType.init` (it does
|
|
197
|
+
* `Object.assign(inst["~standard"], { jsonSchema })`), so there the read hit an
|
|
198
|
+
* already-built object and cost only an accessor call. `zod/mini` and raw
|
|
199
|
+
* `zod/v4/core` never touch it, so for those the read built — and retained — an
|
|
200
|
+
* object and a closure per schema, purely to capture a fallback the schema will
|
|
201
|
+
* most likely never expose to a Standard Schema consumer.
|
|
202
|
+
*
|
|
203
|
+
* The throw path is rebuilt instead of captured. Zod's validate catches a
|
|
204
|
+
* synchronous throw and retries through `safeParseAsync` — that is how an async
|
|
184
205
|
* refinement resolves and how a throwing check surfaces as a rejected promise
|
|
185
|
-
* rather than a synchronous throw
|
|
186
|
-
*
|
|
187
|
-
*
|
|
206
|
+
* rather than a synchronous throw — so calling the already-captured `zspa` and
|
|
207
|
+
* mapping its result is the same route to the same result. `vendor` is likewise
|
|
208
|
+
* a constant: schema discovery only ever admits zod schemas, and classic, mini
|
|
209
|
+
* and core all hardcode `vendor: "zod"` themselves.
|
|
210
|
+
*
|
|
211
|
+
* Not carried over (unchanged by this, and pre-dating it): classic's
|
|
212
|
+
* `~standard.jsonSchema` extension, which the replacement object has never
|
|
213
|
+
* reproduced.
|
|
188
214
|
*
|
|
189
215
|
* Installed with defineProperty rather than assignment: Zod's lazy setter
|
|
190
216
|
* redefines the slot as non-writable, so a second `__zcMkv` on the same schema
|
|
191
217
|
* object — two exports aliasing one schema — would throw under ESM strict mode.
|
|
192
218
|
*/
|
|
193
|
-
const MK_VALIDATOR_DECL = "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;};
|
|
219
|
+
const MK_VALIDATOR_DECL = "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;};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};}}});return w;}";
|
|
194
220
|
function extractFunctionName(functionDef) {
|
|
195
221
|
const match = /^function\s+(\w+)\s*\(/.exec(functionDef);
|
|
196
222
|
if (!match?.[1]) throw new Error("Cannot extract function name from generated code");
|
|
@@ -208,13 +234,15 @@ function generateIIFE(schemaExpr, schema, options) {
|
|
|
208
234
|
const { codegenResult, refEntries } = schema;
|
|
209
235
|
const fnName = extractFunctionName(codegenResult.functionDef);
|
|
210
236
|
const zodCompat = options?.zodCompat !== false;
|
|
211
|
-
const
|
|
237
|
+
const bindsSchema = refEntries.length > 0 || codegenResult.usesRetainedSchema === true;
|
|
238
|
+
const retainedSchema = bindsSchema ? RETAINED_SCHEMA_VAR : schemaExpr;
|
|
212
239
|
const schemaArg = zodCompat ? retainedSchema : "null";
|
|
213
240
|
const fcArg = codegenResult.fastFnName ?? "null";
|
|
214
241
|
const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : "null");
|
|
215
242
|
return [
|
|
216
243
|
"/* @__PURE__ */ (() => {",
|
|
217
|
-
...
|
|
244
|
+
...bindsSchema ? [`var ${RETAINED_SCHEMA_VAR}=${schemaExpr};`] : [],
|
|
245
|
+
...refEntries.length > 0 ? [`var __rf=[${refEntries.map((fb) => `${retainedSchema}${fb.accessPath}`).join(",")}];`] : [],
|
|
218
246
|
...codegenResult.code.split("\n").filter((l) => l.trim() !== "" && l.trim() !== "/* zod-compiler */"),
|
|
219
247
|
codegenResult.functionDef,
|
|
220
248
|
`return __zcMkv(${fnName},${schemaArg},${fcArg},${isArg});`,
|
package/dist/core/iife.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iife.js","names":[],"sources":["../../src/core/iife.ts"],"sourcesContent":["/**\n * Shared CompiledSchema<T> IIFE generation.\n * Used by both CLI emitter and unplugin transform.\n */\n\nimport type { CompiledSchemaInfo } from \"./pipeline.js\";\n\n/**\n * Import statement required by generateIIFE output (references\n * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and\n * custom callbacks may only reveal that they are async through the promise\n * they return, at which point zod's own synchronous parse raises.\n */\nexport const ZOD_CONFIG_IMPORT =\n 'import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";';\n\n/**\n * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):\n * the message an issue gets when nothing was baked into it at build time.\n *\n * Resolves zod's tail of `finalizeIssue` — `config.customError` then\n * `config.localeError` then \"Invalid input\" — and does it PER CALL, because the\n * config is mutable: `z.config({ localeError })` in an entry point runs after\n * the schema modules it imports, so a value snapshotted at module init misses\n * it. Reading a captured `localeError` alone also dropped `customError`\n * outright, silently ignoring the global map most i18n setups install.\n *\n * The head of zod's chain — the schema's own `error` option — is baked into the\n * issue at build time and short-circuits this. The one link that cannot be\n * reproduced is a per-CALL `ctx.error`, which would have to travel through\n * `safeParse`; that entry point sits at V8's inlining budget, where even an\n * unused extra parameter measured ~12% on every parse.\n *\n * Only ever called while building an error, never on a successful parse.\n */\nexport const ZOD_MSG_DECLARATION =\n 'function __zcUw(m){return typeof m===\"string\"?m:(m===undefined||m===null?undefined:m.message);}' +\n \"var __zcMsg=function(iss){var c=__zodCompilerConfig(),m;\" +\n \"if(c.customError){m=__zcUw(c.customError(iss));if(m!==undefined&&m!==null)return m;}\" +\n \"if(c.localeError){m=__zcUw(c.localeError(iss));if(m!==undefined&&m!==null)return m;}\" +\n 'return \"Invalid input\";};';\n\n/**\n * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)\n * declares it once per compiled file; lean mode (all unplugin bundlers) declares\n * it once per bundle in the plugin-materialized runtime module (module-local —\n * generated code only ever references __zcFin/__zcFinD, never __ZcFail).\n *\n * Why a prototype getter and not `{success:false, get error(){...}}`: an object\n * literal with an inline accessor forces V8 down its slow accessor-defining\n * allocation path — ~110ns per failure, measured — which dominates the entire\n * invalid-input cost whenever callers never read `.error`. Hosting `error` on\n * the prototype turns each failure into a plain field-only instantiation (~2ns,\n * ~13x), with the lazy-cache semantics intact. (Trade-off: `error` is a\n * prototype accessor, so it no longer shows up in `Object.keys(result)` / spread\n * / JSON.stringify of the result wrapper — `.success`/`.error`/`.data` access,\n * destructuring, and `in` are unaffected.)\n *\n * One class serves both finalizers, so the instances share one hidden class:\n * __zcFin passes pre-collected issues in `_e` (with `_f===null`); __zcFinD\n * passes the hosted slow-walk in `_f` plus the input in `_i`, and the getter\n * runs the walk on first `.error` read. The whole finalization — locale fill\n * (__zcMsg applied ONLY when an issue carries no message, never overwriting a\n * baked-in custom/fallback message), input strip, and ZodError construction\n * (zod v4 JSON.stringifies every issue into `message` and captures a stack\n * trace) — stays deferred inside the cached accessor exactly as before, since\n * the issues array is observable solely through `.error`.\n *\n * `input` is `delete`d, not assigned `undefined`. Key PRESENCE is observable —\n * `\"input\" in issue`, `Object.keys(issue)`, object spread, `toStrictEqual`\n * against a zod issue — and zod's `util.finalizeIssue` does `delete full.input`\n * whenever `reportInput` is off, so assignment left every compiled issue one\n * enumerable key wider than zod's. The delete's dictionary-mode transition is\n * affordable precisely BECAUSE of the deferral above: it runs only after a\n * caller asks for `.error` on a failed parse, and is memoised in `_c`. Neither\n * a successful parse nor a `.success`/`.is()` check on a rejected one reaches\n * it — measured, the two are unchanged, while the `.error` read itself goes\n * ~3.95us -> ~4.19us per failure, i.e. ~6% of a path whose cost is already\n * dominated by the ZodError construction on the next line (stack capture plus a\n * JSON.stringify of every issue).\n */\nexport const FAIL_CLASS_DECL =\n \"function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){' +\n \"if(this._c)return this._c;\" +\n \"var e=this._f!==null?this._f(this._i):this._e;\" +\n 'for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);delete e[i].input;delete e[i].continue;}' +\n \"return this._c=new __zcZodError(e);}});\";\n\n/** Eager finalizer (mutation / partial-fast-path schemas): issues already\n * collected in `e`; success short-circuits to a plain result literal. */\nexport const FIN_DECL =\n \"function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}\";\n\n/**\n * Deferred-collection finalizer for Fast-Path-eligible schemas. When the\n * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is\n * pushed into the cached `.error` accessor instead of running eagerly:\n * fast-eligible schemas never mutate, so the walk's only output is the\n * issues array, which is observable solely through `.error` — one step\n * further along the same lazy boundary `__zcFin` already established (locale\n * fill, input strip, ZodError construction). A failed safeParse whose\n * `.error` is never read costs the fast check alone.\n *\n * Takes the schema's HOSTED slow-walk function plus the input — NOT a\n * per-call closure: `__zcFinD(__sw_N, input)` allocates only the result\n * object, where `__zcFinD(function(){...})` paid a closure environment and\n * function object per failure. Hosting the walk also shrinks safeParse to\n * two statements, within V8's inlining budget (the success-path result\n * literal becomes escape-analyzable at monomorphic call sites).\n *\n * The walk re-reads `input` at `.error`-read time; a caller that mutates\n * the input between safeParse and reading `.error` sees issues for the\n * mutated value (zod materializes at parse time). Same caveat class as the\n * documented __zcFin deferral.\n */\nexport const FIN_DEFERRED_DECL = \"function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}\";\n\n/**\n * Compact-mode failure class — a lazy failure that delegates error reporting to\n * the ORIGINAL Zod schema's `safeParse`. Used by `output: \"compact\"`, where the\n * compiled slow walk is dropped entirely: a mutation-free schema's fast check\n * is the only generated validation, and on a fast-check failure the cold error\n * path is produced by the retained Zod schema itself (`zod` is the source of\n * truth, so the issues are byte-identical — no second validation engine).\n *\n * `_z` is the schema's PRISTINE safeParse method and `_r` is its receiver. Both\n * are captured pre-`__zcMkv` by emitRfMethod — see context.ts — so the method is\n * zod's own implementation, never the compiled delegate, avoiding infinite\n * recursion without allocating a bound function. The zod parse is deferred\n * until `.error` 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 validate is captured first and kept as the throw path: it catches a\n * synchronous throw and retries through `safeParseAsync`, which is how an async\n * refinement resolves and how a throwing check surfaces as a rejected promise\n * rather than a synchronous throw. The compiled validator cannot reproduce that\n * (async schemas delegate to Zod anyway), so deferring to the original is both\n * simpler and exact.\n *\n * Installed with defineProperty rather than assignment: Zod's lazy setter\n * redefines the slot as non-writable, so a second `__zcMkv` on the same schema\n * object — two exports aliasing one schema — would throw under ESM strict mode.\n */\nexport const MK_VALIDATOR_DECL =\n \"function __zcMkv(fn,schema,fc,is){var w=schema||{};var zpa=w.parseAsync,zspa=w.safeParseAsync;w.parse=fc?function(input){if(fc(input))return input;var r=fn(input);if(r.success)return r.data;throw r.error;}:function(input){var r=fn(input);if(r.success)return r.data;throw r.error;};w.safeParse=fn;w.safeParseAsync=function(input){try{return Promise.resolve(fn(input));}catch(e){if(zspa)return zspa(input);throw e;}};w.parseAsync=fc?function(input){try{if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}}:function(input){try{var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}};w.is=is||function(input){return fn(input).success;};\" +\n 'var s=w[\"~standard\"],zv=s&&s.validate;' +\n 'Object.defineProperty(w,\"~standard\",{configurable:true,value:{version:1,vendor:(s&&s.vendor)||\"zod\",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zv)return zv(input);throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});' +\n \"return w;}\";\n\nfunction extractFunctionName(functionDef: string): string {\n const match = /^function\\s+(\\w+)\\s*\\(/.exec(functionDef);\n if (!match?.[1]) {\n throw new Error(\"Cannot extract function name from generated code\");\n }\n return match[1];\n}\n\n/**\n * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.\n *\n * @param schemaExpr - Expression resolving to the original Zod schema\n * (e.g. `\"UserSchema\"` in unplugin, `\"(__src_X as any).schema\"` in CLI)\n * @param schema\n * @param options\n */\nexport function generateIIFE(\n schemaExpr: string,\n schema: CompiledSchemaInfo,\n options?: { zodCompat?: boolean | undefined },\n): string {\n const { codegenResult, refEntries } = schema;\n const fnName = extractFunctionName(codegenResult.functionDef);\n const zodCompat = options?.zodCompat !== false;\n // Every fallback access starts from the same source schema. Capture it once\n // whenever refs exist so an inline initializer is not reconstructed for each\n // path and again for the identity-preserving __zcMkv target.\n const retainedSchema = refEntries.length > 0 ? \"__zs\" : schemaExpr;\n const schemaArg = zodCompat ? retainedSchema : \"null\";\n const fcArg = codegenResult.fastFnName ?? \"null\";\n // `.is()` gets the fast-check directly only when it is a total predicate;\n // partial/none falls back to safeParse().success inside __zcMkv. A rebuilding\n // schema has no by-reference `fc` but still names its predicate separately.\n const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : \"null\");\n\n return [\n \"/* @__PURE__ */ (() => {\",\n ...(refEntries.length > 0\n ? [\n `var __zs=${schemaExpr};`,\n `var __rf=[${refEntries.map((fb) => `${retainedSchema}${fb.accessPath}`).join(\",\")}];`,\n ]\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":";;;;;;;AAaA,MAAa,oBACX;;;;;;;;;;;;;;;;;;;;AAqBF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CF,MAAa,kBACX;;;AASF,MAAa,WACX;;;;;;;;;;;;;;;;;;;;;;;AAwBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;AAyBjC,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0EzB,MAAa,oBACX;AAKF,SAAS,oBAAoB,aAA6B;CACxD,MAAM,QAAQ,yBAAyB,KAAK,WAAW;CACvD,IAAI,CAAC,QAAQ,IACX,MAAM,IAAI,MAAM,kDAAkD;CAEpE,OAAO,MAAM;AACf;;;;;;;;;AAUA,SAAgB,aACd,YACA,QACA,SACQ;CACR,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,SAAS,oBAAoB,cAAc,WAAW;CAC5D,MAAM,YAAY,SAAS,cAAc;CAIzC,MAAM,iBAAiB,WAAW,SAAS,IAAI,SAAS;CACxD,MAAM,YAAY,YAAY,iBAAiB;CAC/C,MAAM,QAAQ,cAAc,cAAc;CAI1C,MAAM,QAAQ,cAAc,aAAa,cAAc,YAAY,QAAQ;CAE3E,OAAO;EACL;EACA,GAAI,WAAW,SAAS,IACpB,CACE,YAAY,WAAW,IACvB,aAAa,WAAW,KAAK,OAAO,GAAG,iBAAiB,GAAG,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GACrF,IACA,CAAC;EACL,GAAG,cAAc,KACd,MAAM,IAAI,CAAC,CACX,QAAQ,MAAM,EAAE,KAAK,MAAM,MAAM,EAAE,KAAK,MAAM,oBAAoB;EACrE,cAAc;EACd,kBAAkB,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM;EACxD;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}
|
|
1
|
+
{"version":3,"file":"iife.js","names":[],"sources":["../../src/core/iife.ts"],"sourcesContent":["/**\n * Shared CompiledSchema<T> IIFE generation.\n * Used by both CLI emitter and unplugin transform.\n */\n\nimport { RETAINED_SCHEMA_VAR } from \"./codegen/context.js\";\nimport type { CompiledSchemaInfo } from \"./pipeline.js\";\n\n/**\n * Import statement required by generateIIFE output (references\n * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and\n * custom callbacks may only reveal that they are async through the promise\n * they return, at which point zod's own synchronous parse raises.\n */\nexport const ZOD_CONFIG_IMPORT =\n 'import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";';\n\n/**\n * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):\n * the message an issue gets when nothing was baked into it at build time.\n *\n * Resolves zod's tail of `finalizeIssue` — `config.customError` then\n * `config.localeError` then \"Invalid input\" — and does it PER CALL, because the\n * config is mutable: `z.config({ localeError })` in an entry point runs after\n * the schema modules it imports, so a value snapshotted at module init misses\n * it. Reading a captured `localeError` alone also dropped `customError`\n * outright, silently ignoring the global map most i18n setups install.\n *\n * The head of zod's chain — the schema's own `error` option — is baked into the\n * issue at build time and short-circuits this. The one link that cannot be\n * reproduced is a per-CALL `ctx.error`, which would have to travel through\n * `safeParse`; that entry point sits at V8's inlining budget, where even an\n * unused extra parameter measured ~12% on every parse.\n *\n * Only ever called while building an error, never on a successful parse.\n */\nexport const ZOD_MSG_DECLARATION =\n 'function __zcUw(m){return typeof m===\"string\"?m:(m===undefined||m===null?undefined:m.message);}' +\n \"var __zcMsg=function(iss){var c=__zodCompilerConfig(),m;\" +\n \"if(c.customError){m=__zcUw(c.customError(iss));if(m!==undefined&&m!==null)return m;}\" +\n \"if(c.localeError){m=__zcUw(c.localeError(iss));if(m!==undefined&&m!==null)return m;}\" +\n 'return \"Invalid input\";};';\n\n/**\n * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)\n * declares it once per compiled file; lean mode (all unplugin bundlers) declares\n * it once per bundle in the plugin-materialized runtime module (module-local —\n * generated code only ever references __zcFin/__zcFinD, never __ZcFail).\n *\n * Why a prototype getter and not `{success:false, get error(){...}}`: an object\n * literal with an inline accessor forces V8 down its slow accessor-defining\n * allocation path — ~110ns per failure, measured — which dominates the entire\n * invalid-input cost whenever callers never read `.error`. Hosting `error` on\n * the prototype turns each failure into a plain field-only instantiation (~2ns,\n * ~13x), with the lazy-cache semantics intact. (Trade-off: `error` is a\n * prototype accessor, so it no longer shows up in `Object.keys(result)` / spread\n * / JSON.stringify of the result wrapper — `.success`/`.error`/`.data` access,\n * destructuring, and `in` are unaffected.)\n *\n * One class serves both finalizers, so the instances share one hidden class:\n * __zcFin passes pre-collected issues in `_e` (with `_f===null`); __zcFinD\n * passes the hosted slow-walk in `_f` plus the input in `_i`, and the getter\n * runs the walk on first `.error` read. The whole finalization — locale fill\n * (__zcMsg applied ONLY when an issue carries no message, never overwriting a\n * baked-in custom/fallback message), input strip, and ZodError construction\n * (zod v4 JSON.stringifies every issue into `message` and captures a stack\n * trace) — stays deferred inside the cached accessor exactly as before, since\n * the issues array is observable solely through `.error`.\n *\n * `input` is `delete`d, not assigned `undefined`. Key PRESENCE is observable —\n * `\"input\" in issue`, `Object.keys(issue)`, object spread, `toStrictEqual`\n * against a zod issue — and zod's `util.finalizeIssue` does `delete full.input`\n * whenever `reportInput` is off, so assignment left every compiled issue one\n * enumerable key wider than zod's. The delete's dictionary-mode transition is\n * affordable precisely BECAUSE of the deferral above: it runs only after a\n * caller asks for `.error` on a failed parse, and is memoised in `_c`. Neither\n * a successful parse nor a `.success`/`.is()` check on a rejected one reaches\n * it — measured, the two are unchanged, while the `.error` read itself goes\n * ~3.95us -> ~4.19us per failure, i.e. ~6% of a path whose cost is already\n * dominated by the ZodError construction on the next line (stack capture plus a\n * JSON.stringify of every issue).\n */\nexport const FAIL_CLASS_DECL =\n \"function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){' +\n \"if(this._c)return this._c;\" +\n \"var e=this._f!==null?this._f(this._i):this._e;\" +\n 'for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);delete e[i].input;delete e[i].continue;}' +\n \"return this._c=new __zcZodError(e);}});\";\n\n/** Eager finalizer (mutation / partial-fast-path schemas): issues already\n * collected in `e`; success short-circuits to a plain result literal. */\nexport const FIN_DECL =\n \"function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}\";\n\n/**\n * Deferred-collection finalizer for Fast-Path-eligible schemas. When the\n * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is\n * pushed into the cached `.error` accessor instead of running eagerly:\n * fast-eligible schemas never mutate, so the walk's only output is the\n * issues array, which is observable solely through `.error` — one step\n * further along the same lazy boundary `__zcFin` already established (locale\n * fill, input strip, ZodError construction). A failed safeParse whose\n * `.error` is never read costs the fast check alone.\n *\n * Takes the schema's HOSTED slow-walk function plus the input — NOT a\n * per-call closure: `__zcFinD(__sw_N, input)` allocates only the result\n * object, where `__zcFinD(function(){...})` paid a closure environment and\n * function object per failure. Hosting the walk also shrinks safeParse to\n * two statements, within V8's inlining budget (the success-path result\n * literal becomes escape-analyzable at monomorphic call sites).\n *\n * The walk re-reads `input` at `.error`-read time; a caller that mutates\n * the input between safeParse and reading `.error` sees issues for the\n * mutated value (zod materializes at parse time). Same caveat class as the\n * documented __zcFin deferral.\n */\nexport const FIN_DEFERRED_DECL = \"function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}\";\n\n/**\n * Compact-mode failure class — a lazy failure that delegates error reporting to\n * the ORIGINAL Zod schema's `safeParse`. Used by `output: \"compact\"`, where the\n * compiled slow walk is dropped entirely: a mutation-free schema's fast check\n * is the only generated validation, and on a fast-check failure the cold error\n * path is produced by the retained Zod schema itself (`zod` is the source of\n * truth, so the issues are byte-identical — no second validation engine).\n *\n * `_z` is the schema's PRISTINE safeParse method, captured by\n * emitRetainedMethod (see context.ts), and `_r` is its receiver — the `__zs`\n * binding generateIIFE places above that capture. Both are read before the\n * trailing `__zcMkv` call installs anything, so the method is zod's own\n * implementation, never the compiled delegate, avoiding infinite recursion\n * without allocating a bound function. The zod parse is deferred until `.error`\n * is read and cached, so\n * the common `safeParse(x).success`/`.is(x)` checks on invalid input cost only\n * the fast check (zod never runs) — the same deferral boundary `__zcFinD`\n * establishes for the compiled slow walk. Sound because compact mode is gated\n * on a TOTAL fast path: `fc(input) === false` ⟹ zod rejects, so `success:false`\n * holds without consulting zod.\n *\n * The getter returns zod's OWN ZodError verbatim (no locale fill / input strip /\n * re-wrap — zod already finalized it), so a delegated failure is exactly what\n * the unaltered schema would have produced.\n */\nexport const FAILZ_CLASS_DECL =\n \"function __ZcFailZ(z,r,i){this.success=false;this._z=z;this._r=r;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFailZ.prototype,\"error\",{configurable:true,get:function(){' +\n \"return this._c||(this._c=this._z.call(this._r,this._i).error);}});\";\n\n/** Compact-mode finalizer: retain a pristine safeParse, its receiver, and input lazily. */\nexport const FINZ_DECL = \"function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);}\";\n\n/**\n * Validator factory. Inline mode (CLI emitter) declares it once per compiled\n * file; lean mode (all unplugin bundlers) exports it once per bundle from the\n * plugin-materialized runtime module — generated code never imports it from\n * the zod-compiler package itself, so zod-compiler stays a devDependency and\n * the helper set is always version-locked to the codegen that calls it.\n * Wraps a safeParse function into the CompiledSchema interface.\n *\n * IDENTITY-PRESERVING: with zodCompat (schema != null) the compiled\n * parse/safeParse/parseAsync/safeParseAsync are installed as OWN properties\n * on the original schema object, which is returned as-is. zod v4 keys\n * several APIs on object identity — toJSONSchema's ctx.seen registers the\n * object it is handed while each processor closure captures the original\n * inst (a wrapper crashes `optionalProcessor` with \"Cannot set properties\n * of undefined (setting 'ref')\" the moment a compiled schema is composed\n * into another schema), and globalRegistry/.meta() is a WeakMap keyed by\n * the schema instance (a wrapper silently loses OpenAPI titles/ids). An\n * Object.create wrapper breaks both; mutating the original breaks neither\n * (zod's internal parsing flows through _zod.run, never the public\n * methods, and derived schemas — .optional(), .extend() — are fresh\n * instances that fall back to plain zod). schema=null (zodCompat: false)\n * still produces a plain method-bag object.\n *\n * fc is the schema's hosted fast-check boolean function (null when no Fast\n * Path exists). parse()/parseAsync() try it first and return the input\n * directly on success: fc is small enough for V8 to inline, so the hot parse\n * path runs with zero allocations — calling fn would allocate an intermediate\n * SafeParseResult that escape analysis cannot remove (fn never inlines).\n * Fast-path-eligible schemas never mutate, so fc(input) ⟹ data === input.\n *\n * is is the TOTAL fast-check predicate (fc when the fast path is total, else\n * null). Installed as `.is()` — a zero-allocation boolean type guard. When\n * null (partial fast path or none) `.is()` derives from fn(input).success: a\n * partial fc can pass-through valid input but its `false` does not imply\n * rejection (a default/catch may still succeed), so it would be unsound as a\n * standalone guard.\n *\n * parseAsync/safeParseAsync wrap the SYNC validator, which is right for every\n * schema the compiler can reproduce — none of them are async. It is wrong for\n * the ones it cannot: an `async` refinement or a `z.promise()` extracts to a\n * Zod delegate, and delegating means calling Zod's SYNCHRONOUS safeParse, which\n * raises `$ZodAsyncError` by design. Wrapping that gave the compiled schema an\n * async pair that rejected with `$ZodAsyncError` for EVERY input — including\n * valid ones — where Zod resolves normally, so `await UserSchema.parseAsync(x)`\n * stopped working the moment any part of the schema went async.\n *\n * So both are guarded: a synchronous throw hands off to the schema's ORIGINAL\n * async method, captured before these are installed — the same escape hatch\n * `~standard` already uses for its throw path, and for the same reason (the\n * compiled validator has no async mode to offer, and Zod's is exact). It also\n * fixes the smaller wart that a throwing `fn` made `parseAsync` throw\n * SYNCHRONOUSLY rather than return a rejected promise. With `zodCompat: false`\n * there is no schema to delegate to and the throw propagates as before.\n *\n * `~standard` is REPLACED, not merely preserved. Zod builds it lazily as\n * `validate: (v) => safeParse(inst, v)` — the core FUNCTION, which goes straight\n * to `inst._zod.run`. It never reads the schema's own `safeParse` property, so\n * installing the compiled one leaves this route entirely uncompiled: measured\n * 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema\n * consumers (tRPC, Hono, TanStack) were getting plain Zod.\n *\n * Zod's own `~standard` is never READ, only overwritten. Zod installs the slot\n * with `util.defineLazy` — commented there as \"avoid creating objects for every\n * schema\" — so it is an accessor that builds `{version, vendor, validate}` plus\n * its closure on first touch. Reading it to capture a fallback fired that getter\n * for every compiled schema while the module was still initializing.\n *\n * How much that costs depends on the entry point, and only one of them is free:\n * classic `zod` forces the slot itself during `ZodType.init` (it does\n * `Object.assign(inst[\"~standard\"], { jsonSchema })`), so there the read hit an\n * already-built object and cost only an accessor call. `zod/mini` and raw\n * `zod/v4/core` never touch it, so for those the read built — and retained — an\n * object and a closure per schema, purely to capture a fallback the schema will\n * most likely never expose to a Standard Schema consumer.\n *\n * The throw path is rebuilt instead of captured. Zod's validate catches a\n * synchronous throw and retries through `safeParseAsync` — that is how an async\n * refinement resolves and how a throwing check surfaces as a rejected promise\n * rather than a synchronous throw — so calling the already-captured `zspa` and\n * mapping its result is the same route to the same result. `vendor` is likewise\n * a constant: schema discovery only ever admits zod schemas, and classic, mini\n * and core all hardcode `vendor: \"zod\"` themselves.\n *\n * Not carried over (unchanged by this, and pre-dating it): classic's\n * `~standard.jsonSchema` extension, which the replacement object has never\n * reproduced.\n *\n * Installed with defineProperty rather than assignment: Zod's lazy setter\n * redefines the slot as non-writable, so a second `__zcMkv` on the same schema\n * object — two exports aliasing one schema — would throw under ESM strict mode.\n */\nexport const MK_VALIDATOR_DECL =\n \"function __zcMkv(fn,schema,fc,is){var w=schema||{};var zpa=w.parseAsync,zspa=w.safeParseAsync;w.parse=fc?function(input){if(fc(input))return input;var r=fn(input);if(r.success)return r.data;throw r.error;}:function(input){var r=fn(input);if(r.success)return r.data;throw r.error;};w.safeParse=fn;w.safeParseAsync=function(input){try{return Promise.resolve(fn(input));}catch(e){if(zspa)return zspa(input);throw e;}};w.parseAsync=fc?function(input){try{if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}}:function(input){try{var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}};w.is=is||function(input){return fn(input).success;};\" +\n 'Object.defineProperty(w,\"~standard\",{configurable:true,value:{version:1,vendor:\"zod\",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zspa)return zspa(input).then(function(q){return q.success?{value:q.data}:{issues:q.error.issues};});throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});' +\n \"return w;}\";\n\nfunction extractFunctionName(functionDef: string): string {\n const match = /^function\\s+(\\w+)\\s*\\(/.exec(functionDef);\n if (!match?.[1]) {\n throw new Error(\"Cannot extract function name from generated code\");\n }\n return match[1];\n}\n\n/**\n * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.\n *\n * @param schemaExpr - Expression resolving to the original Zod schema\n * (e.g. `\"UserSchema\"` in unplugin, `\"(__src_X as any).schema\"` in CLI)\n * @param schema\n * @param options\n */\nexport function generateIIFE(\n schemaExpr: string,\n schema: CompiledSchemaInfo,\n options?: { zodCompat?: boolean | undefined },\n): string {\n const { codegenResult, refEntries } = schema;\n const fnName = extractFunctionName(codegenResult.functionDef);\n const zodCompat = options?.zodCompat !== false;\n // Every fallback access starts from the same source schema, and compact\n // delegation names it outright. Capture it once whenever either needs it, so\n // an inline initializer is not reconstructed for each path and again for the\n // identity-preserving __zcMkv target.\n const bindsSchema = refEntries.length > 0 || codegenResult.usesRetainedSchema === true;\n const retainedSchema = bindsSchema ? RETAINED_SCHEMA_VAR : schemaExpr;\n const schemaArg = zodCompat ? retainedSchema : \"null\";\n const fcArg = codegenResult.fastFnName ?? \"null\";\n // `.is()` gets the fast-check directly only when it is a total predicate;\n // partial/none falls back to safeParse().success inside __zcMkv. A rebuilding\n // schema has no by-reference `fc` but still names its predicate separately.\n const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : \"null\");\n\n return [\n \"/* @__PURE__ */ (() => {\",\n ...(bindsSchema ? [`var ${RETAINED_SCHEMA_VAR}=${schemaExpr};`] : []),\n // Only fallback refs need the array; a compact validator with none of its\n // own reads `__zs` directly rather than allocating `[__zs]` to index into.\n ...(refEntries.length > 0\n ? [`var __rf=[${refEntries.map((fb) => `${retainedSchema}${fb.accessPath}`).join(\",\")}];`]\n : []),\n ...codegenResult.code\n .split(\"\\n\")\n .filter((l) => l.trim() !== \"\" && l.trim() !== \"/* zod-compiler */\"),\n codegenResult.functionDef,\n `return __zcMkv(${fnName},${schemaArg},${fcArg},${isArg});`,\n \"})()\",\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;AAcA,MAAa,oBACX;;;;;;;;;;;;;;;;;;;;AAqBF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CF,MAAa,kBACX;;;AASF,MAAa,WACX;;;;;;;;;;;;;;;;;;;;;;;AAwBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BjC,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6FzB,MAAa,oBACX;AAIF,SAAS,oBAAoB,aAA6B;CACxD,MAAM,QAAQ,yBAAyB,KAAK,WAAW;CACvD,IAAI,CAAC,QAAQ,IACX,MAAM,IAAI,MAAM,kDAAkD;CAEpE,OAAO,MAAM;AACf;;;;;;;;;AAUA,SAAgB,aACd,YACA,QACA,SACQ;CACR,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,SAAS,oBAAoB,cAAc,WAAW;CAC5D,MAAM,YAAY,SAAS,cAAc;CAKzC,MAAM,cAAc,WAAW,SAAS,KAAK,cAAc,uBAAuB;CAClF,MAAM,iBAAiB,cAAc,sBAAsB;CAC3D,MAAM,YAAY,YAAY,iBAAiB;CAC/C,MAAM,QAAQ,cAAc,cAAc;CAI1C,MAAM,QAAQ,cAAc,aAAa,cAAc,YAAY,QAAQ;CAE3E,OAAO;EACL;EACA,GAAI,cAAc,CAAC,OAAO,oBAAoB,GAAG,WAAW,EAAE,IAAI,CAAC;EAGnE,GAAI,WAAW,SAAS,IACpB,CAAC,aAAa,WAAW,KAAK,OAAO,GAAG,iBAAiB,GAAG,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG,IACvF,CAAC;EACL,GAAG,cAAc,KACd,MAAM,IAAI,CAAC,CACX,QAAQ,MAAM,EAAE,KAAK,MAAM,MAAM,EAAE,KAAK,MAAM,oBAAoB;EACrE,cAAc;EACd,kBAAkB,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM;EACxD;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}
|
package/dist/core/pipeline.d.ts
CHANGED
|
@@ -27,8 +27,8 @@ interface CompileSchemasOptions {
|
|
|
27
27
|
* Compact output (`output: "compact"`). Drop the compiled slow walk for
|
|
28
28
|
* mutation-free, total-fast-path schemas and delegate their cold error path
|
|
29
29
|
* to the retained Zod schema. Disables slow-walk sharing (delegated schemas
|
|
30
|
-
* never emit a walk to share)
|
|
31
|
-
*
|
|
30
|
+
* never emit a walk to share); delegated validators read the retained schema
|
|
31
|
+
* through the `__zs` binding rather than through `__rf[]`.
|
|
32
32
|
*/
|
|
33
33
|
compact?: boolean | undefined;
|
|
34
34
|
/** When provided, per-schema failures call this and continue. Otherwise the first error throws. */
|
|
@@ -40,9 +40,9 @@ interface CompileSchemasOptions {
|
|
|
40
40
|
*
|
|
41
41
|
* Pass 1 extracts every schema's IR and plans repeated slow walks. Pass 2
|
|
42
42
|
* generates each validator, calling shared `__zcSw_N` functions instead of
|
|
43
|
-
* re-inlining them. Exact
|
|
44
|
-
* pooled when at least two validators use them. Files with no repetition
|
|
45
|
-
* their original local declarations.
|
|
43
|
+
* re-inlining them. Exact constant initializers reported during generation are
|
|
44
|
+
* then pooled when at least two validators use them. Files with no repetition
|
|
45
|
+
* keep their original local declarations.
|
|
46
46
|
*/
|
|
47
47
|
declare function compileSchemas(schemas: DiscoveredSchema[], options: CompileSchemasOptions): CompileSchemasResult;
|
|
48
48
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","names":[],"sources":["../../src/core/pipeline.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","names":[],"sources":["../../src/core/pipeline.ts"],"mappings":";;;;;UAaiB;EACf;EACA,eAAe;EACf,YAAY;;;UAIG;;EAEf;;EAEA,aAAa;;;UAIE;EACf,SAAS;EACT,QAAQ;;UAGO;;EAEf,MAAM;;;;;;;;EAQN;;EAEA,WAAW,oBAAoB,OAAO;;;;;;;;;;;;iBA4FxB,eACd,SAAS,oBACT,SAAS,wBACR;;;;;iBAwHa,qBAAqB,SAAS,uBAAuB"}
|