zod-compiler 2.0.0 → 2.0.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/README.md +175 -151
- package/dist/core/codegen/build-path.d.ts.map +1 -1
- package/dist/core/codegen/build-path.js +144 -34
- package/dist/core/codegen/build-path.js.map +1 -1
- package/dist/core/codegen/context.d.ts +11 -10
- package/dist/core/codegen/context.d.ts.map +1 -1
- package/dist/core/codegen/context.js.map +1 -1
- package/dist/core/codegen/fast-path.d.ts +3 -1
- package/dist/core/codegen/fast-path.d.ts.map +1 -1
- package/dist/core/codegen/fast-path.js +7 -4
- package/dist/core/codegen/fast-path.js.map +1 -1
- package/dist/core/codegen/index.js +4 -3
- package/dist/core/codegen/index.js.map +1 -1
- package/dist/core/codegen/issue-decls.d.ts +43 -1
- package/dist/core/codegen/issue-decls.d.ts.map +1 -1
- package/dist/core/codegen/issue-decls.js +45 -2
- package/dist/core/codegen/issue-decls.js.map +1 -1
- package/dist/core/codegen/schemas/default.d.ts +10 -0
- package/dist/core/codegen/schemas/default.d.ts.map +1 -1
- package/dist/core/codegen/schemas/default.js +11 -0
- package/dist/core/codegen/schemas/default.js.map +1 -1
- package/dist/core/codegen/schemas/discriminated-union.d.ts +6 -2
- package/dist/core/codegen/schemas/discriminated-union.d.ts.map +1 -1
- package/dist/core/codegen/schemas/discriminated-union.js +14 -55
- package/dist/core/codegen/schemas/discriminated-union.js.map +1 -1
- package/dist/core/codegen/schemas/string-bool.d.ts +12 -1
- package/dist/core/codegen/schemas/string-bool.d.ts.map +1 -1
- package/dist/core/codegen/schemas/string-bool.js +19 -4
- package/dist/core/codegen/schemas/string-bool.js.map +1 -1
- package/dist/core/codegen/schemas/string.d.ts.map +1 -1
- package/dist/core/codegen/schemas/string.js +15 -10
- package/dist/core/codegen/schemas/string.js.map +1 -1
- package/dist/core/codegen/well-known-regex.d.ts +19 -1
- package/dist/core/codegen/well-known-regex.d.ts.map +1 -1
- package/dist/core/codegen/well-known-regex.js +21 -1
- package/dist/core/codegen/well-known-regex.js.map +1 -1
- package/dist/core/iife.d.ts +8 -0
- package/dist/core/iife.d.ts.map +1 -1
- package/dist/core/iife.js +8 -0
- package/dist/core/iife.js.map +1 -1
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +2 -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 GeneratedConstant,\n RecTargetGen,\n} from \"./context.js\";\nimport {\n fastResultIsInput,\n generateBuild,\n nestedNeedsProtoScrub,\n rebuildsOutput,\n} from \"./build-path.js\";\nimport {\n declareFastTemps,\n emitRetainedMethod,\n emitRfDelegate,\n emitRuntimeHelper,\n hasMutation,\n needsProtoScrub,\n RETAINED_SCHEMA_VAR,\n} from \"./context.js\";\nimport type { SharedSchemaPlan } from \"./dedupe.js\";\nimport { ZC_PROTO_SCRUB_DECL } from \"./issue-decls.js\";\nimport { createFastGen, generateFast } from \"./fast-path.js\";\nimport { createSlowGen, generateSlow } from \"./slow-path.js\";\n\nexport type { CodeGenResult } from \"./context.js\";\n\nexport interface GenerateValidatorOptions {\n refCount?: number;\n /** Codegen output mode. Defaults to \"inline\". */\n mode?: CodegenMode;\n /**\n * File-level shared slow-walk plan (schema deduplication). Applied only to\n * mutation-free schemas, so shared walks stay on the deferred cold path.\n */\n sharedSchemas?: SharedSchemaPlan | undefined;\n /**\n * Compact mode (`output: \"compact\"`). Drop the compiled slow walk for\n * mutation-free schemas with a TOTAL fast path and delegate the cold error\n * path to the retained Zod schema (`__zcFinZ`). The fast (hot) path is\n * unchanged; only the bulky error-collecting walk — 64–77% of generated\n * bytes — is replaced by a few bytes of zod delegation. See\n * {@link CodeGenResult.usesRetainedSchema}.\n */\n compact?: boolean | undefined;\n /** Internal file-pipeline hook for pooling exact constant initializers across validators. */\n onConstant?: ((constant: GeneratedConstant) => void) | undefined;\n /** Internal exact-initializer plan used by the file pipeline's final generation pass. */\n sharedConstantNames?: ReadonlyMap<string, string> | undefined;\n}\n\n/**\n * Generate optimized validation code from SchemaIR.\n *\n * - `code`: preamble declarations (Sets, RegExps, etc.) — deterministic for the same IR\n * - `functionDef`: full function expression string referencing preamble vars via closure\n * - `usedHelpers`: helper names from \"virtual:zod-compiler/runtime\" referenced (lean mode only)\n *\n * Usage: `new Function(code + \"\\nreturn \" + functionDef + \";\")()`\n */\nexport function generateValidator(\n ir: SchemaIR,\n name: string,\n options?: GenerateValidatorOptions,\n): CodeGenResult {\n const fnName = `safeParse_${name}`;\n const mode: CodegenMode = options?.mode ?? \"inline\";\n const ctx: CodeGenContext = {\n preamble: [],\n counter: 0,\n fnName,\n regexCache: new Map(),\n mode,\n usedHelpers: new Set(),\n onConstant: options?.onConstant,\n sharedConstantNames: options?.sharedConstantNames,\n };\n\n // Slow-walk sharing. The plan already excludes any shape that would reach for\n // this export's `__rf[]`, and a shared walk returns its parsed value, so a\n // rewriting shape (a stripping object above all) delivers its result through\n // the call. Nothing left to gate on here.\n if (options?.sharedSchemas !== undefined) {\n ctx.sharedSchemas = options.sharedSchemas;\n }\n\n // Root-level fallback: the whole schema delegates to Zod, so zod's own\n // safeParse result IS the result. Returning it directly skips the issue\n // copy loop (which would force zod's eager ZodError construction), the\n // pointless [].concat(path) rewrites, and the __zcFin re-wrap. Delegation\n // goes through the pre-mutation capture (emitRfDelegate) — here __rf[0]\n // and the __zcMkv target are routinely the SAME object.\n if (ir.type === \"fallback\" && ir.refIndex !== undefined) {\n const delegate = emitRfDelegate(ctx, ir.refIndex);\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: `function ${fnName}(input){return ${delegate}(input);}`,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n };\n }\n\n // Recursion-target table. The root (refId 0) reuses the schema's own\n // `safeParse_<name>` / hosted fast-check, so it needs no separate helper and\n // its fast name is allocated lazily during the walk (recFastName). Non-root\n // targets — recursive sub-schemas nested in a larger root, multiple distinct\n // recursive shapes, mutual recursion — are each hosted as a standalone\n // `__rsp_N` (slow) / `__fcr_N` (fast) validator the cycle calls by name.\n // Common directly-self-recursive schemas have no non-root targets, so this\n // leaves their generated output byte-identical.\n const nonRootTargets = collectRecursionTargets(ir);\n ctx.recTargets = new Map<number, RecTargetGen>([[0, { isRoot: true, slowName: fnName }]]);\n for (const [refId, inner] of nonRootTargets) {\n ctx.recTargets.set(refId, {\n isRoot: false,\n inner,\n slowName: `__rsp_${ctx.counter++}`,\n fastName: `__fcr_${ctx.counter++}`,\n });\n }\n const hasNonRootTargets = nonRootTargets.size > 0;\n\n // Fast Path: generate a boolean expression for eligible schemas.\n //\n // generateFast mutates ctx as it walks (extracted __fo_ helpers + regex/effect\n // decls pushed to the preamble, a recursive __fcr_ name reserved, dedup caches\n // populated). The walk is all-or-nothing: a later fast-ineligible node makes it\n // return null AFTER those side effects already landed. Without a rollback the\n // discarded fast path leaves dead __fo_ helpers in the output — and, when one\n // referenced the recursive __fcr_ host that the `fastExpr !== null` branch below\n // never emits, a dangling reference to an undefined identifier. Snapshot the\n // mutable state and restore it on abort so the slow path re-declares from clean.\n const fastPreambleLen = ctx.preamble.length;\n const fastRegexCache = new Map(ctx.regexCache);\n const fastEffectCache = ctx.effectFnCache && new Map(ctx.effectFnCache);\n const fastValueCache = ctx.valueCache && new Map(ctx.valueCache);\n const fastRecName = ctx.recFastName;\n 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 // `data: input` verbatim, with no compiled walk to fall back on — so a\n // schema whose output needs an own `__proto__` removed cannot use it.\n !needsProtoScrub(ir) &&\n !nestedNeedsProtoScrub(ir) &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `if(${fastExpr}){return{success:true,data:input};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName,\n // Mutation-free total fast path: fc(input) ⟺ accepts(input), so `.is()`\n // installs fc directly (compact never weakens the guard).\n fastTotal: true,\n usesRetainedSchema: true,\n };\n }\n\n // Compact + Build Path: same bargain for a schema with modelled rewrites. The\n // build pass still has to run (it produces the payload, which zod's schema\n // would only reproduce by parsing again), but the compiled issue walk is what\n // compact drops, and delegating that to the retained zod schema costs a few\n // bytes.\n if (\n options?.compact === true &&\n buildFnName !== null &&\n ctx.buildFailName !== undefined &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n const built = `__bd_${ctx.counter++}`;\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n isFnName: buildIsFnName,\n usesRetainedSchema: true,\n };\n }\n\n // Host each non-root recursion target as a safeParse-shaped slow validator,\n // mirroring the root's eager body: collect issues, return success+data or a\n // deferred-error result. Always emitted (the slow path always exists); the\n // recursion call sites read `.success` / `.error.issues` / `.data`. Hoisted\n // function declarations, so their order relative to the root is irrelevant.\n if (hasNonRootTargets) {\n for (const t of ctx.recTargets.values()) {\n if (t.isRoot) continue;\n const body = generateSlow(t.inner as SchemaIR, createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx));\n ctx.usedHelpers.add(\"__zcFin\");\n ctx.preamble.push(\n `function ${t.slowName}(input){var _e=[];\\nvar _d=input;\\n${body}\\n` +\n `if(_e.length===0){return{success:true,data:_d};}\\nreturn __zcFin(_e,_d);}`,\n );\n }\n }\n\n const sg = createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx);\n // When the root schema's own shape is shared (it recurs as a sub-schema of\n // another export, or as a duplicate root), its slow walk delegates to the\n // shared function instead of emitting a second full copy. The fast path is\n // still generated inline above — only the cold walk is shared.\n const rootRef = ctx.sharedSchemas?.refFor(ir);\n const slowCode = rootRef !== undefined ? `_d=${rootRef.name}(_d,[],_e);` : generateSlow(ir, sg);\n\n const buildCode = (): string => [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\");\n\n const functionDefParts = [`function ${fnName}(input){`];\n\n // Build Path: every mutation is modelled, so one pass can validate and\n // assemble the output together and bail on the first failure, leaving the\n // issue-producing walk deferred behind `.error` (see build-path).\n // The fast check stays out of `safeParse` entirely — running it first would\n // read every property twice — but it is still an EXACT acceptance predicate\n // (stripping reshapes the output, never the verdict), so `.is()` installs it.\n if (buildFnName !== null && ctx.buildFailName !== undefined) {\n ctx.usedHelpers.add(\"__zcFinD\");\n const built = `__bd_${ctx.counter++}`;\n // A self-recursive walk calls this validator BY NAME (slowRecursiveRef),\n // and that binding exists only inside the named function expression — so\n // there the walk stays a per-call closure. Everything else hosts it in the\n // preamble, keeping safeParse to three statements. Mirrors the same split\n // in the mutation-free branch below.\n const recursive = slowCode.includes(fnName);\n let deferred: string;\n if (recursive) {\n deferred = `__zcFinD(function(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;},input)`;\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n deferred = `__zcFinD(${walkName},input)`;\n }\n return {\n code: buildCode(),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return ${deferred};`,\n `}`,\n ].join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // No by-reference shortcut: `data` is the freshly built object, so\n // parse() must go through safeParse rather than returning its input.\n fastFnName: null,\n // `fastTotal` qualifies `fastFnName`, which is null here; the predicate\n // travels in `isFnName` instead.\n fastTotal: false,\n isFnName: buildIsFnName,\n };\n }\n\n if (fastExpr === \"true\") {\n // Schema always succeeds (any/unknown) — skip slow path entirely\n functionDefParts.push(`return{success:true,data:input};`);\n functionDefParts.push(`}`);\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n // any/unknown always succeed; `.is()` derives `true` from the fn fallback.\n fastTotal: false,\n };\n }\n\n if (fastExpr !== null && !hasMutation(ir) && !nestedNeedsProtoScrub(ir)) {\n // The by-reference shortcut hands back the input verbatim, which a loose or\n // catchall object — or a record — must not do while it still carries an own\n // `__proto__` (see ZC_PROTO_SCRUB_DECL). The fast check itself stays a pure\n // predicate, so `fc(input) ⟺ zod accepts` still holds and the deferred error\n // path below is untouched; only the value handed back is filtered. The cost\n // is one `hasOwnProperty` per successful parse of those shapes.\n const fastData = needsProtoScrub(ir)\n ? `${emitRuntimeHelper(ctx, \"__zcPs\", ZC_PROTO_SCRUB_DECL)}(input)`\n : \"input\";\n // Mutation-free schemas with a fast path: a fast-check failure can never\n // become a slow-path success (both are generated from the same checks —\n // unlike default/catch schemas, whose partial fast path requires value\n // presence while the slow path SUCCEEDS by applying the fallback).\n // The slow path's only output is therefore the issues array, observable\n // solely through `.error` — defer the whole re-walk into the cached\n // accessor (__zcFinD): a failed safeParse whose `.error` is never read\n // costs the fast check alone.\n //\n // The walk is HOSTED as a named preamble function rather than a per-call\n // closure, for two measured reasons: (1) a failed safeParse no longer\n // allocates a closure environment + function object before the deferral\n // even starts; (2) the safeParse body shrinks to two statements, putting\n // it within V8's inlining budget — callers in hot loops get the\n // success-path result object escape-analyzed away entirely, which the\n // old shape (slow walk inlined into the body) made impossible.\n ctx.usedHelpers.add(\"__zcFinD\");\n if (slowCode.includes(fnName)) {\n // Self-recursive slow paths call the safeParse function by NAME\n // (slowRecursiveRef) — that binding exists only inside the named\n // function expression under the documented evaluation contract\n // (`new Function(code + \"return \" + functionDef)`), so the walk stays\n // a per-call closure for recursive schemas. Recursion is the rare\n // shape; everything else gets the hosted walk.\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return __zcFinD(function(input){`,\n `var _e=[];`,\n `var _d=input;`,\n slowCode,\n `return _e;`,\n `},input);`,\n `}`,\n );\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return __zcFinD(${walkName},input);`,\n `}`,\n );\n }\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // `fc` is a sound VERDICT here either way, but publishing it also promises\n // `parse()` may return the input — which a scrubbed output cannot (see\n // fastResultIsInput). `.is()` still gets the predicate through fastTotal.\n fastFnName: fastResultIsInput(ir) ? fastFnName : null,\n // Total predicate: mutation-free fast path, fc(input) ⟺ accepts(input).\n // generateIIFE installs fc directly as the zero-allocation `.is()`.\n fastTotal: true,\n };\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 {\n fastResultIsInput,\n generateBuild,\n nestedNeedsProtoScrub,\n rebuildsOutput,\n} from \"./build-path.js\";\nimport {\n declareFastTemps,\n emitRetainedMethod,\n emitRfDelegate,\n emitRuntimeHelper,\n hasMutation,\n needsProtoScrub,\n RETAINED_SCHEMA_VAR,\n} from \"./context.js\";\nimport type { SharedSchemaPlan } from \"./dedupe.js\";\nimport { ZC_PROTO_SCRUB_DECL } from \"./issue-decls.js\";\nimport { createFastGen, generateFast } from \"./fast-path.js\";\nimport { createSlowGen, generateSlow } from \"./slow-path.js\";\n\nexport type { CodeGenResult } from \"./context.js\";\n\nexport interface GenerateValidatorOptions {\n refCount?: number;\n /** Codegen output mode. Defaults to \"inline\". */\n mode?: CodegenMode;\n /**\n * File-level shared slow-walk plan (schema deduplication). Applied only to\n * mutation-free schemas, so shared walks stay on the deferred cold path.\n */\n sharedSchemas?: SharedSchemaPlan | undefined;\n /**\n * Compact mode (`output: \"compact\"`). Drop the compiled slow walk for\n * mutation-free schemas with a TOTAL fast path and delegate the cold error\n * path to the retained Zod schema (`__zcFinZ`). The fast (hot) path is\n * unchanged; only the bulky error-collecting walk — 64–77% of generated\n * bytes — is replaced by a few bytes of zod delegation. See\n * {@link CodeGenResult.usesRetainedSchema}.\n */\n compact?: boolean | undefined;\n /** Internal file-pipeline hook for pooling exact constant initializers across validators. */\n onConstant?: ((constant: GeneratedConstant) => void) | undefined;\n /** Internal exact-initializer plan used by the file pipeline's final generation pass. */\n sharedConstantNames?: ReadonlyMap<string, string> | undefined;\n}\n\n/**\n * Generate optimized validation code from SchemaIR.\n *\n * - `code`: preamble declarations (Sets, RegExps, etc.) — deterministic for the same IR\n * - `functionDef`: full function expression string referencing preamble vars via closure\n * - `usedHelpers`: helper names from \"virtual:zod-compiler/runtime\" referenced (lean mode only)\n *\n * Usage: `new Function(code + \"\\nreturn \" + functionDef + \";\")()`\n */\nexport function generateValidator(\n ir: SchemaIR,\n name: string,\n options?: GenerateValidatorOptions,\n): CodeGenResult {\n const fnName = `safeParse_${name}`;\n const mode: CodegenMode = options?.mode ?? \"inline\";\n const ctx: CodeGenContext = {\n preamble: [],\n counter: 0,\n fnName,\n regexCache: new Map(),\n mode,\n usedHelpers: new Set(),\n onConstant: options?.onConstant,\n sharedConstantNames: options?.sharedConstantNames,\n };\n\n // Slow-walk sharing. The plan already excludes any shape that would reach for\n // this export's `__rf[]`, and a shared walk returns its parsed value, so a\n // rewriting shape (a stripping object above all) delivers its result through\n // the call. Nothing left to gate on here.\n if (options?.sharedSchemas !== undefined) {\n ctx.sharedSchemas = options.sharedSchemas;\n }\n\n // Root-level fallback: the whole schema delegates to Zod, so zod's own\n // safeParse result IS the result. Returning it directly skips the issue\n // copy loop (which would force zod's eager ZodError construction), the\n // pointless [].concat(path) rewrites, and the __zcFin re-wrap. Delegation\n // goes through the pre-mutation capture (emitRfDelegate) — here __rf[0]\n // and the __zcMkv target are routinely the SAME object.\n if (ir.type === \"fallback\" && ir.refIndex !== undefined) {\n const delegate = emitRfDelegate(ctx, ir.refIndex);\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: `function ${fnName}(input){return ${delegate}(input);}`,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n };\n }\n\n // Recursion-target table. The root (refId 0) reuses the schema's own\n // `safeParse_<name>` / hosted fast-check, so it needs no separate helper and\n // its fast name is allocated lazily during the walk (recFastName). Non-root\n // targets — recursive sub-schemas nested in a larger root, multiple distinct\n // recursive shapes, mutual recursion — are each hosted as a standalone\n // `__rsp_N` (slow) / `__fcr_N` (fast) validator the cycle calls by name.\n // Common directly-self-recursive schemas have no non-root targets, so this\n // leaves their generated output byte-identical.\n const nonRootTargets = collectRecursionTargets(ir);\n ctx.recTargets = new Map<number, RecTargetGen>([[0, { isRoot: true, slowName: fnName }]]);\n for (const [refId, inner] of nonRootTargets) {\n ctx.recTargets.set(refId, {\n isRoot: false,\n inner,\n slowName: `__rsp_${ctx.counter++}`,\n fastName: `__fcr_${ctx.counter++}`,\n });\n }\n const hasNonRootTargets = nonRootTargets.size > 0;\n\n // Fast Path: generate a boolean expression for eligible schemas.\n //\n // generateFast mutates ctx as it walks (extracted __fo_ helpers + regex/effect\n // decls pushed to the preamble, a recursive __fcr_ name reserved, dedup caches\n // populated). The walk is all-or-nothing: a later fast-ineligible node makes it\n // return null AFTER those side effects already landed. Without a rollback the\n // discarded fast path leaves dead __fo_ helpers in the output — and, when one\n // referenced the recursive __fcr_ host that the `fastExpr !== null` branch below\n // never emits, a dangling reference to an undefined identifier. Snapshot the\n // mutable state and restore it on abort so the slow path re-declares from clean.\n const fastPreambleLen = ctx.preamble.length;\n const fastRegexCache = new Map(ctx.regexCache);\n const fastEffectCache = ctx.effectFnCache && new Map(ctx.effectFnCache);\n const fastValueCache = ctx.valueCache && new Map(ctx.valueCache);\n const fastRecName = ctx.recFastName;\n // A schema that rebuilds its output never takes a by-reference shortcut:\n // `fastResultIsInput` withholds `data: input` and the published `fc` alike,\n // so its root expression is only ever consumed as a VERDICT — by `.is()`. It\n // is therefore generated as an acceptance predicate (see FastGen.acceptance),\n // which differs from the by-reference form only at `.default()` nodes and is\n // what lets a defaulted schema keep a zero-allocation `.is()`.\n const acceptance = rebuildsOutput(ir);\n const fg = createFastGen(\"input\", ctx, false, undefined, undefined, acceptance);\n let fastExpr = generateFast(ir, fg);\n if (fastExpr !== null && hasNonRootTargets) {\n // Host each non-root recursion target as a boolean fast-check helper. A\n // single fast-ineligible target (e.g. one whose recursive shape contains a\n // fallback) disables the WHOLE fast path: the root expression already emits\n // calls to these names, so a missing body would dangle. The shared\n // rollback below then restores clean state for the slow-only path.\n for (const t of ctx.recTargets.values()) {\n if (t.isRoot) continue;\n const targetGen = createFastGen(\"input\", ctx, false, undefined, undefined, acceptance);\n const body = generateFast(t.inner as SchemaIR, targetGen);\n if (body === null) {\n fastExpr = null;\n break;\n }\n ctx.preamble.push(\n `function ${t.fastName}(input){${declareFastTemps(targetGen.scope)}return ${body};}`,\n );\n }\n }\n if (fastExpr === null) {\n ctx.preamble.length = fastPreambleLen;\n ctx.regexCache = fastRegexCache;\n if (fastEffectCache === undefined) delete ctx.effectFnCache;\n else ctx.effectFnCache = fastEffectCache;\n // Value declarations the abandoned walk emitted are truncated above, so\n // their cache entries would name identifiers that no longer exist.\n if (fastValueCache === undefined) delete ctx.valueCache;\n else ctx.valueCache = fastValueCache;\n if (fastRecName === undefined) delete ctx.recFastName;\n else ctx.recFastName = fastRecName;\n }\n\n // Host the fast expression in a named boolean helper. Self-recursive\n // schemas need it so recursive refs can call it; every other eligible\n // schema benefits too: __zcMkv wires it into parse()/parseAsync(), whose\n // success paths then return the input directly — no intermediate\n // SafeParseResult allocation (the safeParse function body is far past\n // V8's inlining budget, so escape analysis never removes it).\n let fastFnName: string | null = null;\n if (fastExpr !== null && fastExpr !== \"true\") {\n fastFnName = ctx.recFastName ?? `__fc_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${fastFnName}(input){${declareFastTemps(fg.scope)}return ${fastExpr};}`,\n );\n fastExpr = `${fastFnName}(input)`;\n }\n\n // Build Path: one pass that validates and assembles rewritten output, bailing\n // on the first failure (see build-path). Null unless every mutation in the\n // schema is modelled — so this emits nothing for the mutation-free schemas\n // the compact branch takes.\n const buildFnName = generateBuild(ir, ctx);\n\n // A zodDelegate with a rebuilding inner exists only to accelerate that\n // build. If an unmodelled descendant made the all-or-nothing build decline,\n // preserve the old root-fallback shape instead of wrapping the same pristine\n // Zod call in an issues array/copy/finalizer. This keeps unsupported object\n // intersections neutral rather than making compilation slower than Zod.\n if (ir.type === \"zodDelegate\" && rebuildsOutput(ir.inner) && buildFnName === null) {\n ctx.preamble.length = 0;\n ctx.usedHelpers.clear();\n ctx.regexCache.clear();\n ctx.effectFnCache?.clear();\n ctx.valueCache?.clear();\n const delegate = emitRfDelegate(ctx, ir.refIndex);\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: `function ${fnName}(input){return ${delegate}(input);}`,\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n };\n }\n\n // `.is()` for a build-path schema is the fast expression — stripping reshapes\n // the payload, never the verdict, and a `.default()` is covered too: the build\n // path is only ever taken by a rebuilding schema, whose expression was\n // generated in acceptance mode (`acceptance` above) and so accepts the absent\n // value the substitution stands in for.\n const buildIsFnName = fastFnName;\n\n const baseRefCount = options?.refCount ?? 0;\n\n // Compact mode: a mutation-free schema with a TOTAL fast path needs no\n // compiled slow walk — its only purpose is reproducing zod's issues on\n // failure, and the original zod schema (retained in `output: \"compact\"`) does\n // that exactly. Emit the fast check and, on failure, delegate to a fresh root\n // RefEntry (the schema itself) via the pristine safeParse method capture, then\n // wrap it in the lazy `__zcFinZ` failure. Drops 64–77% of generated bytes\n // with zero hot-path cost (fc and `.is()` are unchanged) and zod-identical\n // errors. Excluded: schemas with non-root recursion targets (mutual/nested\n // recursion still hosts standalone slow validators) and any non-total fast\n // path (mutation/default/catch/fallback) — those keep the compiled path.\n if (\n options?.compact === true &&\n fastExpr !== null &&\n fastExpr !== \"true\" &&\n !hasMutation(ir) &&\n // `data: input` verbatim, with no compiled walk to fall back on — so a\n // schema whose output needs an own `__proto__` removed cannot use it.\n !needsProtoScrub(ir) &&\n !nestedNeedsProtoScrub(ir) &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `if(${fastExpr}){return{success:true,data:input};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName,\n // Mutation-free total fast path: fc(input) ⟺ accepts(input), so `.is()`\n // installs fc directly (compact never weakens the guard).\n fastTotal: true,\n usesRetainedSchema: true,\n };\n }\n\n // Compact + Build Path: same bargain for a schema with modelled rewrites. The\n // build pass still has to run (it produces the payload, which zod's schema\n // would only reproduce by parsing again), but the compiled issue walk is what\n // compact drops, and delegating that to the retained zod schema costs a few\n // bytes.\n if (\n options?.compact === true &&\n buildFnName !== null &&\n ctx.buildFailName !== undefined &&\n !hasNonRootTargets\n ) {\n const delegate = emitRetainedMethod(ctx);\n ctx.usedHelpers.add(\"__zcFinZ\");\n const built = `__bd_${ctx.counter++}`;\n return {\n code: [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\"),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return __zcFinZ(${delegate},${RETAINED_SCHEMA_VAR},input);`,\n `}`,\n ].join(\"\\n\"),\n refCount: baseRefCount,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n fastTotal: false,\n isFnName: buildIsFnName,\n usesRetainedSchema: true,\n };\n }\n\n // Host each non-root recursion target as a safeParse-shaped slow validator,\n // mirroring the root's eager body: collect issues, return success+data or a\n // deferred-error result. Always emitted (the slow path always exists); the\n // recursion call sites read `.success` / `.error.issues` / `.data`. Hoisted\n // function declarations, so their order relative to the root is irrelevant.\n if (hasNonRootTargets) {\n for (const t of ctx.recTargets.values()) {\n if (t.isRoot) continue;\n const body = generateSlow(t.inner as SchemaIR, createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx));\n ctx.usedHelpers.add(\"__zcFin\");\n ctx.preamble.push(\n `function ${t.slowName}(input){var _e=[];\\nvar _d=input;\\n${body}\\n` +\n `if(_e.length===0){return{success:true,data:_d};}\\nreturn __zcFin(_e,_d);}`,\n );\n }\n }\n\n const sg = createSlowGen(\"_d\", \"_d\", \"[]\", \"_e\", ctx);\n // When the root schema's own shape is shared (it recurs as a sub-schema of\n // another export, or as a duplicate root), its slow walk delegates to the\n // shared function instead of emitting a second full copy. The fast path is\n // still generated inline above — only the cold walk is shared.\n const rootRef = ctx.sharedSchemas?.refFor(ir);\n const slowCode = rootRef !== undefined ? `_d=${rootRef.name}(_d,[],_e);` : generateSlow(ir, sg);\n\n const buildCode = (): string => [\"/* zod-compiler */\", ...ctx.preamble].join(\"\\n\");\n\n const functionDefParts = [`function ${fnName}(input){`];\n\n // Build Path: every mutation is modelled, so one pass can validate and\n // assemble the output together and bail on the first failure, leaving the\n // issue-producing walk deferred behind `.error` (see build-path).\n // The fast check stays out of `safeParse` entirely — running it first would\n // read every property twice — but it is still an EXACT acceptance predicate\n // (stripping reshapes the output, never the verdict), so `.is()` installs it.\n if (buildFnName !== null && ctx.buildFailName !== undefined) {\n ctx.usedHelpers.add(\"__zcFinD\");\n const built = `__bd_${ctx.counter++}`;\n // A self-recursive walk calls this validator BY NAME (slowRecursiveRef),\n // and that binding exists only inside the named function expression — so\n // there the walk stays a per-call closure. Everything else hosts it in the\n // preamble, keeping safeParse to three statements. Mirrors the same split\n // in the mutation-free branch below.\n const recursive = slowCode.includes(fnName);\n let deferred: string;\n if (recursive) {\n deferred = `__zcFinD(function(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;},input)`;\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n deferred = `__zcFinD(${walkName},input)`;\n }\n return {\n code: buildCode(),\n functionDef: [\n `function ${fnName}(input){`,\n `var ${built}=${buildFnName}(input);`,\n `if(${built}!==${ctx.buildFailName}){return{success:true,data:${built}};}`,\n `return ${deferred};`,\n `}`,\n ].join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // No by-reference shortcut: `data` is the freshly built object, so\n // parse() must go through safeParse rather than returning its input.\n fastFnName: null,\n // `fastTotal` qualifies `fastFnName`, which is null here; the predicate\n // travels in `isFnName` instead.\n fastTotal: false,\n isFnName: buildIsFnName,\n };\n }\n\n if (fastExpr === \"true\") {\n // Schema always succeeds (any/unknown) — skip slow path entirely\n functionDefParts.push(`return{success:true,data:input};`);\n functionDefParts.push(`}`);\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n fastFnName: null,\n // any/unknown always succeed; `.is()` derives `true` from the fn fallback.\n fastTotal: false,\n };\n }\n\n if (fastExpr !== null && !hasMutation(ir) && !nestedNeedsProtoScrub(ir)) {\n // The by-reference shortcut hands back the input verbatim, which a loose or\n // catchall object — or a record — must not do while it still carries an own\n // `__proto__` (see ZC_PROTO_SCRUB_DECL). The fast check itself stays a pure\n // predicate, so `fc(input) ⟺ zod accepts` still holds and the deferred error\n // path below is untouched; only the value handed back is filtered. The cost\n // is one `hasOwnProperty` per successful parse of those shapes.\n const fastData = needsProtoScrub(ir)\n ? `${emitRuntimeHelper(ctx, \"__zcPs\", ZC_PROTO_SCRUB_DECL)}(input)`\n : \"input\";\n // Mutation-free schemas with a fast path: a fast-check failure can never\n // become a slow-path success (both are generated from the same checks —\n // unlike default/catch schemas, whose partial fast path requires value\n // presence while the slow path SUCCEEDS by applying the fallback).\n // The slow path's only output is therefore the issues array, observable\n // solely through `.error` — defer the whole re-walk into the cached\n // accessor (__zcFinD): a failed safeParse whose `.error` is never read\n // costs the fast check alone.\n //\n // The walk is HOSTED as a named preamble function rather than a per-call\n // closure, for two measured reasons: (1) a failed safeParse no longer\n // allocates a closure environment + function object before the deferral\n // even starts; (2) the safeParse body shrinks to two statements, putting\n // it within V8's inlining budget — callers in hot loops get the\n // success-path result object escape-analyzed away entirely, which the\n // old shape (slow walk inlined into the body) made impossible.\n ctx.usedHelpers.add(\"__zcFinD\");\n if (slowCode.includes(fnName)) {\n // Self-recursive slow paths call the safeParse function by NAME\n // (slowRecursiveRef) — that binding exists only inside the named\n // function expression under the documented evaluation contract\n // (`new Function(code + \"return \" + functionDef)`), so the walk stays\n // a per-call closure for recursive schemas. Recursion is the rare\n // shape; everything else gets the hosted walk.\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return __zcFinD(function(input){`,\n `var _e=[];`,\n `var _d=input;`,\n slowCode,\n `return _e;`,\n `},input);`,\n `}`,\n );\n } else {\n const walkName = `__sw_${ctx.counter++}`;\n ctx.preamble.push(\n `function ${walkName}(input){var _e=[];\\nvar _d=input;\\n${slowCode}\\nreturn _e;}`,\n );\n functionDefParts.push(\n `if(${fastExpr}){return{success:true,data:${fastData}};}`,\n `return __zcFinD(${walkName},input);`,\n `}`,\n );\n }\n return {\n code: buildCode(),\n functionDef: functionDefParts.join(\"\\n\"),\n refCount: options?.refCount ?? 0,\n usedHelpers: ctx.usedHelpers,\n // `fc` is a sound VERDICT here either way, but publishing it also promises\n // `parse()` may return the input — which a scrubbed output cannot (see\n // fastResultIsInput). `.is()` still gets the predicate through fastTotal.\n fastFnName: fastResultIsInput(ir) ? fastFnName : null,\n // Total predicate: mutation-free fast path, fc(input) ⟺ accepts(input).\n // generateIIFE installs fc directly as the zero-allocation `.is()`.\n fastTotal: true,\n };\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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"}
|
|
@@ -78,12 +78,54 @@ declare const ZC_HOP_DECL = "const __zcHop=Object.prototype.hasOwnProperty;";
|
|
|
78
78
|
* than `Object.getPrototypeOf(o) === Object.prototype` is what lets a plain
|
|
79
79
|
* object from another realm (a vm context, an iframe) still count as plain.
|
|
80
80
|
*
|
|
81
|
+
* `c===Object` is a short-cut, not a fourth rule: it is exactly the case where
|
|
82
|
+
* zod's remaining steps are foregone — `Object.prototype` is an object and has
|
|
83
|
+
* its own `isPrototypeOf` — so the answer is `true` either way. It is also the
|
|
84
|
+
* case every ordinary record takes (an object literal, `JSON.parse` output, a
|
|
85
|
+
* `Map`-free DTO), and taking it saves the `prototype` load and the
|
|
86
|
+
* `hasOwnProperty` call: measured 9.6 → 5.7 ns on a monomorphic record and
|
|
87
|
+
* 15.7 → 9.2 ns across 16 shapes, i.e. 22% of a five-key record's whole parse.
|
|
88
|
+
* A plain object from another realm has a different `Object` and simply takes
|
|
89
|
+
* the long road to the same verdict, as before.
|
|
90
|
+
*
|
|
81
91
|
* Self-contained (`Object.prototype.hasOwnProperty` spelled out rather than
|
|
82
92
|
* reusing `__zcHop`) so inline mode can emit this decl alone: `emitRuntimeHelper`
|
|
83
93
|
* pushes only the decl it is asked for, and a helper that closed over another
|
|
84
94
|
* name would dangle wherever that one was not also emitted.
|
|
85
95
|
*/
|
|
86
96
|
declare const ZC_PLAIN_DECL: string;
|
|
97
|
+
/**
|
|
98
|
+
* `z.email()`'s default validator, `regexes.email`, as a single linear scan.
|
|
99
|
+
*
|
|
100
|
+
* Zod's pattern is
|
|
101
|
+
* `^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$`,
|
|
102
|
+
* and even its lookahead-free rewrite (EMAIL_FAST_REGEX_SOURCE) backtracks at
|
|
103
|
+
* every dot it fails to find: `(?:[X]+\.)*` re-tries the run one character
|
|
104
|
+
* shorter each time, and the domain's `(?:label\.)+` does the same over the
|
|
105
|
+
* TLD. Written as a scanner the language is:
|
|
106
|
+
*
|
|
107
|
+
* local — `[A-Za-z0-9_'+.-]+`, no leading `.`, no `..`, and the character
|
|
108
|
+
* before `@` is neither `.` nor `'` (that last is the `[A-Za-z0-9_+-]`
|
|
109
|
+
* the pattern demands there);
|
|
110
|
+
* domain — one or more labels `[A-Za-z0-9][A-Za-z0-9-]*` each ending in `.`,
|
|
111
|
+
* then a TLD of two or more letters running to the end.
|
|
112
|
+
*
|
|
113
|
+
* A trailing `\n` is not accepted: the pattern has no `m` flag, so its `$`
|
|
114
|
+
* matches only at the end of input, and the scan reads to `length`.
|
|
115
|
+
*
|
|
116
|
+
* Measured against the fast regex on V8: 32 → 16 ns for `alice@example.com`,
|
|
117
|
+
* 48 → 40 for `bob_smith-99@mail-server.io`, 39 → 20 for a non-address, and a
|
|
118
|
+
* tie from ~35 characters up (the regex's per-character work is cheaper than a
|
|
119
|
+
* `charCodeAt` loop's; its fixed dispatch cost is what the scanner avoids). A
|
|
120
|
+
* lookbehind rewrite runs about as fast but needs ES2018 regex support, which
|
|
121
|
+
* the CLI's React Native / Hermes and older-Safari consumers cannot assume.
|
|
122
|
+
*
|
|
123
|
+
* Equivalence to zod's regex — every string, both verdicts — is pinned by
|
|
124
|
+
* tests/core/codegen/email-scanner.test.ts. Reached only behind a `typeof`
|
|
125
|
+
* string guard, like the `.test()` it replaces; issue sites keep reporting
|
|
126
|
+
* zod's own pattern string (see `emitRegexSourceString`).
|
|
127
|
+
*/
|
|
128
|
+
declare const ZC_EMAIL_DECL: string;
|
|
87
129
|
/**
|
|
88
130
|
* Ports of `util.getLengthableOrigin` / `util.getSizableOrigin` — the `origin` a
|
|
89
131
|
* length/size check puts on its issue, computed from the RUNTIME INPUT rather
|
|
@@ -229,5 +271,5 @@ declare const ZC_SR_DECL: string;
|
|
|
229
271
|
/** Non-issue runtime helper declarations hosted in the virtual module. */
|
|
230
272
|
declare const RUNTIME_HELPER_DECLS: Readonly<Record<string, string>>;
|
|
231
273
|
//#endregion
|
|
232
|
-
export { ISSUE_DECLS, RUNTIME_HELPER_DECLS, ZC_AB_DECL, ZC_CPL_DECL, ZC_CUSTOM_OK_DECL, ZC_FSR_DECL, ZC_FZ_DECL, ZC_HOP_DECL, ZC_LENGTH_ORIGIN_DECL, ZC_PFX_DECL, ZC_PLAIN_DECL, ZC_PROTO_SCRUB_DECL, ZC_SIZE_ORIGIN_DECL, ZC_SR_DECL, ZC_SR_OK_DECL, ZC_SR_RUN_DECL, abortingCodeTest, propertyKeyTest };
|
|
274
|
+
export { ISSUE_DECLS, RUNTIME_HELPER_DECLS, ZC_AB_DECL, ZC_CPL_DECL, ZC_CUSTOM_OK_DECL, ZC_EMAIL_DECL, ZC_FSR_DECL, ZC_FZ_DECL, ZC_HOP_DECL, ZC_LENGTH_ORIGIN_DECL, ZC_PFX_DECL, ZC_PLAIN_DECL, ZC_PROTO_SCRUB_DECL, ZC_SIZE_ORIGIN_DECL, ZC_SR_DECL, ZC_SR_OK_DECL, ZC_SR_RUN_DECL, abortingCodeTest, propertyKeyTest };
|
|
233
275
|
//# sourceMappingURL=issue-decls.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-decls.d.ts","names":[],"sources":["../../../src/core/codegen/issue-decls.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkGa,aAAa,SAAS;;;;;;;;;;;;;cA0BtB;;;;;;;;;;cAcA
|
|
1
|
+
{"version":3,"file":"issue-decls.d.ts","names":[],"sources":["../../../src/core/codegen/issue-decls.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkGa,aAAa,SAAS;;;;;;;;;;;;;cA0BtB;;;;;;;;;;cAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqCA;;;;;;;;;;;;;;;;;;cAkCA;;;;;;;;;;;;;;;;;cAmBA;;;;;;;;cAWA;cAGA;;iBA+BG,iBAAiB;;;;;;;;;;;;;;;cAkBpB;;;;;;;;;;;;;;;;;cAkBA;;;;;;;;;cAaA;;iBAIG,gBAAgB;;;;;;;;;;;;;;;;cAmBnB;;;;;;;;;;;;;cAgBA;;;;;;cASA;;;;;;;;;;;;;;;;;;cAqBA;;cASA,sBAAsB,SAAS"}
|
|
@@ -58,12 +58,54 @@ const ZC_HOP_DECL = "const __zcHop=Object.prototype.hasOwnProperty;";
|
|
|
58
58
|
* than `Object.getPrototypeOf(o) === Object.prototype` is what lets a plain
|
|
59
59
|
* object from another realm (a vm context, an iframe) still count as plain.
|
|
60
60
|
*
|
|
61
|
+
* `c===Object` is a short-cut, not a fourth rule: it is exactly the case where
|
|
62
|
+
* zod's remaining steps are foregone — `Object.prototype` is an object and has
|
|
63
|
+
* its own `isPrototypeOf` — so the answer is `true` either way. It is also the
|
|
64
|
+
* case every ordinary record takes (an object literal, `JSON.parse` output, a
|
|
65
|
+
* `Map`-free DTO), and taking it saves the `prototype` load and the
|
|
66
|
+
* `hasOwnProperty` call: measured 9.6 → 5.7 ns on a monomorphic record and
|
|
67
|
+
* 15.7 → 9.2 ns across 16 shapes, i.e. 22% of a five-key record's whole parse.
|
|
68
|
+
* A plain object from another realm has a different `Object` and simply takes
|
|
69
|
+
* the long road to the same verdict, as before.
|
|
70
|
+
*
|
|
61
71
|
* Self-contained (`Object.prototype.hasOwnProperty` spelled out rather than
|
|
62
72
|
* reusing `__zcHop`) so inline mode can emit this decl alone: `emitRuntimeHelper`
|
|
63
73
|
* pushes only the decl it is asked for, and a helper that closed over another
|
|
64
74
|
* name would dangle wherever that one was not also emitted.
|
|
65
75
|
*/
|
|
66
|
-
const ZC_PLAIN_DECL = "function __zcPlain(o){if(typeof o!==\"object\"||o===null||Array.isArray(o))return false;var c=o.constructor;if(c===undefined||typeof c!==\"function\")return true;var p=c.prototype;if(typeof p!==\"object\"||p===null||Array.isArray(p))return false;return Object.prototype.hasOwnProperty.call(p,\"isPrototypeOf\");}";
|
|
76
|
+
const ZC_PLAIN_DECL = "function __zcPlain(o){if(typeof o!==\"object\"||o===null||Array.isArray(o))return false;var c=o.constructor;if(c===Object||c===undefined||typeof c!==\"function\")return true;var p=c.prototype;if(typeof p!==\"object\"||p===null||Array.isArray(p))return false;return Object.prototype.hasOwnProperty.call(p,\"isPrototypeOf\");}";
|
|
77
|
+
/**
|
|
78
|
+
* `z.email()`'s default validator, `regexes.email`, as a single linear scan.
|
|
79
|
+
*
|
|
80
|
+
* Zod's pattern is
|
|
81
|
+
* `^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$`,
|
|
82
|
+
* and even its lookahead-free rewrite (EMAIL_FAST_REGEX_SOURCE) backtracks at
|
|
83
|
+
* every dot it fails to find: `(?:[X]+\.)*` re-tries the run one character
|
|
84
|
+
* shorter each time, and the domain's `(?:label\.)+` does the same over the
|
|
85
|
+
* TLD. Written as a scanner the language is:
|
|
86
|
+
*
|
|
87
|
+
* local — `[A-Za-z0-9_'+.-]+`, no leading `.`, no `..`, and the character
|
|
88
|
+
* before `@` is neither `.` nor `'` (that last is the `[A-Za-z0-9_+-]`
|
|
89
|
+
* the pattern demands there);
|
|
90
|
+
* domain — one or more labels `[A-Za-z0-9][A-Za-z0-9-]*` each ending in `.`,
|
|
91
|
+
* then a TLD of two or more letters running to the end.
|
|
92
|
+
*
|
|
93
|
+
* A trailing `\n` is not accepted: the pattern has no `m` flag, so its `$`
|
|
94
|
+
* matches only at the end of input, and the scan reads to `length`.
|
|
95
|
+
*
|
|
96
|
+
* Measured against the fast regex on V8: 32 → 16 ns for `alice@example.com`,
|
|
97
|
+
* 48 → 40 for `bob_smith-99@mail-server.io`, 39 → 20 for a non-address, and a
|
|
98
|
+
* tie from ~35 characters up (the regex's per-character work is cheaper than a
|
|
99
|
+
* `charCodeAt` loop's; its fixed dispatch cost is what the scanner avoids). A
|
|
100
|
+
* lookbehind rewrite runs about as fast but needs ES2018 regex support, which
|
|
101
|
+
* the CLI's React Native / Hermes and older-Safari consumers cannot assume.
|
|
102
|
+
*
|
|
103
|
+
* Equivalence to zod's regex — every string, both verdicts — is pinned by
|
|
104
|
+
* tests/core/codegen/email-scanner.test.ts. Reached only behind a `typeof`
|
|
105
|
+
* string guard, like the `.test()` it replaces; issue sites keep reporting
|
|
106
|
+
* zod's own pattern string (see `emitRegexSourceString`).
|
|
107
|
+
*/
|
|
108
|
+
const ZC_EMAIL_DECL = "function __zcEmail(s){var n=s.length,i=0,c,p=46;for(;;){if(i===n)return false;c=s.charCodeAt(i);if(c===64)break;if(c===46){if(p===46)return false;}else if(!((c>=97&&c<=122)||(c>=65&&c<=90)||(c>=48&&c<=57)||c===95||c===39||c===43||c===45))return false;p=c;i++;}if(p===46||p===39)return false;var l=++i,d=0,t=true;for(;i<n;i++){c=s.charCodeAt(i);if((c>=97&&c<=122)||(c>=65&&c<=90))continue;if(c===46){if(i===l)return false;d++;l=i+1;t=true;continue;}if((c>=48&&c<=57)||c===45){if(c===45&&i===l)return false;t=false;continue;}return false;}return d>0&&t&&n-l>=2;}";
|
|
67
109
|
/**
|
|
68
110
|
* Ports of `util.getLengthableOrigin` / `util.getSizableOrigin` — the `origin` a
|
|
69
111
|
* length/size check puts on its issue, computed from the RUNTIME INPUT rather
|
|
@@ -244,6 +286,7 @@ const RUNTIME_HELPER_DECLS = {
|
|
|
244
286
|
__zcLo: ZC_LENGTH_ORIGIN_DECL,
|
|
245
287
|
__zcSo: ZC_SIZE_ORIGIN_DECL,
|
|
246
288
|
__zcCpl: ZC_CPL_DECL,
|
|
289
|
+
__zcEmail: ZC_EMAIL_DECL,
|
|
247
290
|
__zcPs: ZC_PROTO_SCRUB_DECL,
|
|
248
291
|
__zcPlain: ZC_PLAIN_DECL,
|
|
249
292
|
__zcPfx: ZC_PFX_DECL,
|
|
@@ -252,6 +295,6 @@ const RUNTIME_HELPER_DECLS = {
|
|
|
252
295
|
__zcSrOk: ZC_SR_OK_DECL
|
|
253
296
|
};
|
|
254
297
|
//#endregion
|
|
255
|
-
export { ISSUE_DECLS, RUNTIME_HELPER_DECLS, ZC_AB_DECL, ZC_CPL_DECL, ZC_CUSTOM_OK_DECL, ZC_FSR_DECL, ZC_FZ_DECL, ZC_HOP_DECL, ZC_LENGTH_ORIGIN_DECL, ZC_PFX_DECL, ZC_PLAIN_DECL, ZC_PROTO_SCRUB_DECL, ZC_SIZE_ORIGIN_DECL, ZC_SR_DECL, ZC_SR_OK_DECL, ZC_SR_RUN_DECL, abortingCodeTest, propertyKeyTest };
|
|
298
|
+
export { ISSUE_DECLS, RUNTIME_HELPER_DECLS, ZC_AB_DECL, ZC_CPL_DECL, ZC_CUSTOM_OK_DECL, ZC_EMAIL_DECL, ZC_FSR_DECL, ZC_FZ_DECL, ZC_HOP_DECL, ZC_LENGTH_ORIGIN_DECL, ZC_PFX_DECL, ZC_PLAIN_DECL, ZC_PROTO_SCRUB_DECL, ZC_SIZE_ORIGIN_DECL, ZC_SR_DECL, ZC_SR_OK_DECL, ZC_SR_RUN_DECL, abortingCodeTest, propertyKeyTest };
|
|
256
299
|
|
|
257
300
|
//# sourceMappingURL=issue-decls.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-decls.js","names":[],"sources":["../../../src/core/codegen/issue-decls.ts"],"sourcesContent":["/**\n * Issue factory function bodies (statement form).\n *\n * These functions produce the same `{code, ...}` shapes that lean-mode\n * generated code would otherwise inline at every check site.\n * Hosted in \"virtual:zod-compiler/runtime\" and called as `__zcTS(...)` etc.\n *\n * Argument convention (positional, kept short to minimize call-site bytes):\n * __zcTS(minimum, origin, inclusive, input, path, msg?) — too_small\n * __zcTSt(minimum, origin, input, path, msg?) — too_small, tuple key order\n * __zcTBt(maximum, origin, input, path, msg?) — too_big, tuple key order\n * __zcTB(maximum, origin, inclusive, input, path, msg?) — too_big\n * __zcIT(expected, input, path, msg?) — invalid_type\n * __zcITc(expected, input, path, msg?) — invalid_type, `code` first\n * __zcIF(origin, format, input, path, extra?, msg?) — invalid_format (extra merged into result)\n * __zcIV(values, input, path, extra?, msg?) — invalid_value (extra merged into result)\n * __zcUK(keys, input, path, msg?) — unrecognized_keys\n *\n * The trailing msg argument carries a static custom error message; when\n * absent, the __zcFin finalizer applies the configured locale default.\n *\n * KEY ORDER IS PART OF THE CONTRACT. `ZodError.message` is\n * `JSON.stringify(issues, …, 2)`, so the order these factories insert keys in is\n * printed verbatim in the message every consumer logs, snapshots or serializes.\n * Each literal below therefore reproduces the order of the corresponding\n * `payload.issues.push({…})` in zod, which is irregular by type — `too_small`\n * from a check leads with `origin` while the same code from a tuple's length\n * branch leads with `code` — and every factory writes `message` LAST, because\n * zod's `finalizeIssue` assigns it after the fact (`full.message = …`) even for\n * a custom message baked into the check's error map.\n */\n\nconst ZC_TS_DECL =\n 'function __zcTS(m,o,i,inp,p,msg){var r={origin:o,code:\"too_small\",minimum:m,inclusive:i,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * too_small in the TUPLE under-length key order. $ZodTuple pushes\n * `{ code, minimum, inclusive: true, input, inst, origin }`, so its `origin`\n * trails `inclusive` where every check-created size issue leads with it. Its\n * over-length sibling is __zcTBt.\n */\nconst ZC_TS_TUPLE_DECL =\n 'function __zcTSt(m,o,inp,p,msg){var r={code:\"too_small\",minimum:m,inclusive:true,origin:o,input:inp,path:p,continue:false};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_TS_EXACT_DECL =\n 'function __zcTSx(m,o,inp,p,msg){var r={origin:o,code:\"too_small\",minimum:m,inclusive:true,exact:true,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_TB_DECL =\n 'function __zcTB(m,o,i,inp,p,msg){var r={origin:o,code:\"too_big\",maximum:m,inclusive:i,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * too_big in the TUPLE over-length key order. $ZodTuple spreads\n * `{ code, maximum, inclusive }` and appends `origin` after `input`/`inst`, so\n * its `origin` trails `inclusive` where every check-created size issue leads\n * with it. Its under-length sibling is __zcTSt.\n */\nconst ZC_TB_TUPLE_DECL =\n 'function __zcTBt(m,o,inp,p,msg){var r={code:\"too_big\",maximum:m,inclusive:true,origin:o,input:inp,path:p,continue:false};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_TB_EXACT_DECL =\n 'function __zcTBx(m,o,inp,p,msg){var r={origin:o,code:\"too_big\",maximum:m,inclusive:true,exact:true,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_IT_DECL =\n 'function __zcIT(e,inp,p,msg){var r={expected:e,code:\"invalid_type\",input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * invalid_type with `code` ahead of `expected`. Every schema in zod spells this\n * issue `{ expected, code }` — except `$ZodDiscriminatedUnion`, whose\n * non-object guard writes `{ code, expected }`. One literal, one key order, and\n * it shows up in `ZodError.message`.\n */\nconst ZC_IT_CODE_FIRST_DECL =\n 'function __zcITc(e,inp,p,msg){var r={code:\"invalid_type\",expected:e,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * `o` is the leading `origin`, present only for the formats whose issue carries\n * one: `$ZodCheckStringFormat`'s default pattern check and the regex /\n * includes / starts_with / ends_with checks all lead with `origin: \"string\"`,\n * while `z.url()`'s own pushes and every `$ZodCustomStringFormat` omit it\n * entirely. `extra` holds the per-format tail (`pattern`, `includes`, `prefix`,\n * `suffix`, `note`) and is merged BEFORE input/path so it lands where zod\n * writes it.\n */\nconst ZC_IF_DECL =\n 'function __zcIF(o,f,inp,p,extra,msg){var r=o===undefined?{code:\"invalid_format\",format:f}:{origin:o,code:\"invalid_format\",format:f};if(extra)Object.assign(r,extra);r.input=inp;r.path=p;if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * `extra` carries the per-producer fields: enum and literal push `values` only,\n * while z.stringbool()'s codec transform also pushes `expected: \"stringbool\"`.\n * Merged the same way __zcIF merges its own.\n */\nconst ZC_IV_DECL =\n 'function __zcIV(values,inp,p,extra,msg){var r={code:\"invalid_value\"};if(extra)Object.assign(r,extra);r.values=values;r.input=inp;r.path=p;if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_UK_DECL =\n 'function __zcUK(k,inp,p,msg){var r={code:\"unrecognized_keys\",keys:k,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/** All issue factory declarations indexed by helper name. */\nexport const ISSUE_DECLS: Readonly<Record<string, string>> = {\n __zcTS: ZC_TS_DECL,\n __zcTSt: ZC_TS_TUPLE_DECL,\n __zcTSx: ZC_TS_EXACT_DECL,\n __zcTB: ZC_TB_DECL,\n __zcTBt: ZC_TB_TUPLE_DECL,\n __zcTBx: ZC_TB_EXACT_DECL,\n __zcIT: ZC_IT_DECL,\n __zcITc: ZC_IT_CODE_FIRST_DECL,\n __zcIF: ZC_IF_DECL,\n __zcIV: ZC_IV_DECL,\n __zcUK: ZC_UK_DECL,\n};\n\n/**\n * Float-safe remainder — byte-for-byte port of zod's util.floatSafeRemainder.\n * Raw `%` mis-rejects valid multiples of decimal steps (0.3 % 0.1 !== 0).\n *\n * zod 4.5 REPLACED the decimal-scaling implementation this once mirrored with a\n * ratio-and-tolerance one, and the two disagree in both directions: the old form\n * accepted `1e-7` as a multiple of 3 (its `toFixed` scaling collapsed the value\n * to 0) and rejected `1e21` (where `toFixed` yields exponential notation and\n * `parseInt` then reads 1). The tolerance is 4x epsilon because `val` and `step`\n * each round to a double before the division rounds again, so a true decimal\n * multiple's quotient can sit up to 1.5 scaled epsilons from the integer.\n */\nexport const ZC_FSR_DECL =\n \"function __zcFsr(v,s){var r=v/s;var q=Math.round(r);\" +\n \"var t=4*Number.EPSILON*Math.max(Math.abs(r),1);\" +\n \"return Math.abs(r-q)<t?0:r-q;}\";\n\n/**\n * Hoisted `Object.prototype.hasOwnProperty` reference. Record fast/slow paths\n * iterate keys with `for(k in o)` (no `Object.keys` array allocation) and guard\n * each key with `__zcHop.call(o,k)` to skip inherited enumerable properties —\n * yielding the exact own-enumerable string-key set `Object.keys` would, so\n * fast/slow stay in agreement and parity with zod's own-key record semantics is\n * preserved. The hoisted reference inlines in V8; reading the prototype property\n * per call would not.\n */\nexport const ZC_HOP_DECL = \"const __zcHop=Object.prototype.hasOwnProperty;\";\n\n/**\n * Port of zod's `util.isPlainObject` — the guard `$ZodRecord` applies to its\n * input, and a STRICTLY narrower test than the `util.isObject` (`typeof\n * \"object\"`, not null, not an array) that `$ZodObject` uses.\n *\n * The distinction is load-bearing and was a validation hole while records shared\n * the object guard: `z.record(z.string(), z.string())` accepted a `Date`, a\n * `Map`, a `RegExp`, an `Error`, a `File` and any class instance — every one of\n * which zod rejects with `invalid_type`/`expected: \"record\"`, and none of which\n * has own enumerable string keys for the value schema to catch. Compiled output\n * therefore said \"valid\" to inputs zod refuses, which is the one direction a\n * validator must never diverge in.\n *\n * The algorithm is zod's, step for step, because the answer is observable and\n * the edge cases are deliberate:\n * - `constructor === undefined` (a null-prototype object) is PLAIN;\n * - a non-function own `constructor` (`{ constructor: 1 }`) is PLAIN;\n * - otherwise the constructor's `prototype` must be an object carrying its OWN\n * `isPrototypeOf` — which `Object.prototype` does and `Date.prototype`,\n * `Map.prototype` and every user class prototype do not. Testing that rather\n * than `Object.getPrototypeOf(o) === Object.prototype` is what lets a plain\n * object from another realm (a vm context, an iframe) still count as plain.\n *\n * Self-contained (`Object.prototype.hasOwnProperty` spelled out rather than\n * reusing `__zcHop`) so inline mode can emit this decl alone: `emitRuntimeHelper`\n * pushes only the decl it is asked for, and a helper that closed over another\n * name would dangle wherever that one was not also emitted.\n */\nexport const ZC_PLAIN_DECL =\n 'function __zcPlain(o){if(typeof o!==\"object\"||o===null||Array.isArray(o))return false;' +\n 'var c=o.constructor;if(c===undefined||typeof c!==\"function\")return true;' +\n 'var p=c.prototype;if(typeof p!==\"object\"||p===null||Array.isArray(p))return false;' +\n 'return Object.prototype.hasOwnProperty.call(p,\"isPrototypeOf\");}';\n\n/**\n * Ports of `util.getLengthableOrigin` / `util.getSizableOrigin` — the `origin` a\n * length/size check puts on its issue, computed from the RUNTIME INPUT rather\n * than from the schema.\n *\n * They only matter because those checks declare a `when` predicate\n * (`!nullish(value) && value.length/size !== undefined`), which bypasses zod's\n * abort gate: `z.string().min(2)` handed `[]` reports the `invalid_type` AND a\n * `too_small` whose origin is `\"array\"`, because the empty array satisfies the\n * `when`. Inside the matching type branch the origin is statically known and\n * these are not used; they exist for the type-MISMATCH branch, where the input\n * can be anything with a `.length` or a `.size`.\n *\n * `File` is probed through `typeof` first: zod tests `input instanceof File`\n * unguarded, which throws where the global is absent — an environment zod does\n * not run in, and not one worth reproducing a crash for.\n */\nexport const ZC_LENGTH_ORIGIN_DECL =\n 'function __zcLo(v){return Array.isArray(v)?\"array\":typeof v===\"string\"?\"string\":\"unknown\";}';\n\n/**\n * Drop an own `__proto__` from a container the parse hands back BY REFERENCE.\n *\n * zod never lets the key into an output: `$ZodObject`'s shape loop strips a\n * declared one, `handleCatchall` skips an undeclared one, and `$ZodRecord` skips\n * it while copying — all so the assignment into their fresh `{}` cannot replace\n * the result's prototype. A compiled loose/catchall object or record IS its\n * input, so the key has to be removed here instead; leaving it made\n * `Object.assign({}, parsed)` a prototype-pollution sink, since [[Set]] runs the\n * inherited setter the spread that built the value did not.\n *\n * Copies rather than editing in place: the divergence note promises the caller\n * its own container back, not one with a key silently deleted from it. The\n * common object has no such key and is returned untouched, so the cost is one\n * `hasOwnProperty` call.\n */\nexport const ZC_PROTO_SCRUB_DECL =\n 'function __zcPs(o){if(!Object.prototype.hasOwnProperty.call(o,\"__proto__\"))return o;' +\n 'var c={...o};delete c[\"__proto__\"];return c;}';\n\n/**\n * Code points in a string — zod's `util.codePointLength`, verbatim. A surrogate\n * pair counts once and a lone surrogate as itself. The regex probe is the fast\n * exit for a string with no astral characters, and the hand-rolled loop avoids\n * the allocating string iterator. Only reached from a length check whose\n * UTF-16 count leaves the verdict in doubt (see stringLengthTests).\n */\nexport const ZC_CPL_DECL =\n \"function __zcCpl(s){var n=s.length;if(!/[\\\\uD800-\\\\uDBFF]/.test(s))return n;var c=n;for(var i=0;i<n-1;i++){if((s.charCodeAt(i)&0xfc00)===0xd800&&(s.charCodeAt(i+1)&0xfc00)===0xdc00){c--;i++;}}return c;}\";\n\nexport const ZC_SIZE_ORIGIN_DECL =\n 'function __zcSo(v){return v instanceof Set?\"set\":v instanceof Map?\"map\":' +\n '(typeof File!==\"undefined\"&&v instanceof File)?\"file\":\"unknown\";}';\n\n/**\n * Issue codes zod raises from a schema's `_zod.parse` rather than from a check,\n * and which therefore carry `continue !== true` — what `util.aborted` looks for.\n *\n * Everything a CHECK produces (`too_small`, `too_big`, `invalid_format`,\n * `not_multiple_of`, a refine's `custom`) is continuable, because `$ZodCheck`\n * sets `continue: !def.abort` and an `abort: true` check costs the schema its\n * compiled path anyway — so classifying by code alone is exact for generated\n * issues.\n *\n * `unrecognized_keys` is the one parse-level issue zod pushes WITH\n * `continue: true`: it describes the shape of the input rather than the\n * validity of the parsed value, so the parse still fails but the object's own\n * refines run first and a union does not count the option as aborted.\n *\n * Read by {@link ZC_AB_DECL} and by the union's option-pruning loop, which\n * applies the same rule inline over a per-option issue array.\n */\nconst ABORTING_ISSUE_CODES: readonly string[] = [\n \"invalid_type\",\n \"invalid_value\",\n \"invalid_union\",\n \"invalid_key\",\n \"invalid_element\",\n];\n\n/** `c===\"invalid_type\"||c===\"invalid_value\"||…` over the code held in `codeExpr`. */\nexport function abortingCodeTest(codeExpr: string): string {\n return ABORTING_ISSUE_CODES.map((code) => `${codeExpr}===${JSON.stringify(code)}`).join(\"||\");\n}\n\n/**\n * Port of zod's `util.aborted(payload, startIndex)`: has anything since\n * `startIndex` produced a NON-continuable issue?\n *\n * zod gates a schema's check chain on this (`runChecks`: `else if (isAborted)\n * continue`), which is what makes a container's `.refine()` still run after a\n * property or element failed its own `min`/`max`/format check, and stop running\n * once one failed to parse at all. The `startIndex` is the issue count when the\n * node was entered, mirroring the fresh payload zod hands each sub-schema.\n *\n * Size/length checks are exempt in zod — they declare a `when` predicate, which\n * bypasses the abort gate — so generated code leaves those ungated and only\n * wraps the refine/superRefine effects.\n */\nexport const ZC_AB_DECL = `function __zcAb(e,i){for(;i<e.length;i++){var s=e[i];if(s.continue===false)return true;var c=s.code;if(${abortingCodeTest(\"c\")})return true;}return false;}`;\n\n/**\n * Port of zod's `util.finalizeIssue` for issues NESTED inside an\n * `invalid_key` / `invalid_element` wrapper. Those never reach the top-level\n * finalization loop (which walks only the outer array), so zod finalizes them\n * where it builds the wrapper: locale message applied when none was baked in,\n * `input` cleared. Their `path` stays RELATIVE to the key or value schema — zod\n * ran it on a fresh payload — so nothing rewrites it.\n *\n * `input` is `delete`d rather than assigned `undefined`, matching zod's own\n * `delete full.input` and the top-level finalizer: the key's PRESENCE is\n * observable (`\"input\" in issue`, `Object.keys`, spread, a strict deep-equal\n * against a zod issue), so assigning left a nested issue one key wider than\n * zod's. Only reached while an error is being built — never on a successful\n * parse — so the dictionary-mode transition it costs is confined to the path\n * that then constructs a ZodError anyway.\n */\nexport const ZC_FZ_DECL =\n \"function __zcFz(e){for(var i=0;i<e.length;i++){var s=e[i];\" +\n 'if(s.message===undefined&&typeof __zcMsg===\"function\")s.message=__zcMsg(s);' +\n \"delete s.input;delete s.continue;}return e;}\";\n\n/**\n * Port of zod's `util.prefixIssues(key, issues)` for a map entry whose key is a\n * property-key type: each issue's RELATIVE path is spliced onto the map's own\n * path plus the key, and the issue moves into the parent's array.\n *\n * `b.concat(k,x.path)` flattens `x.path` one level, giving exactly\n * `[...base, key, ...relative]`.\n */\nexport const ZC_PFX_DECL =\n \"function __zcPfx(d,s,b,k){for(var i=0;i<s.length;i++){var x=s[i];x.path=b.concat(k,x.path);d.push(x);}}\";\n\n/** Does `keyExpr` hold one of zod's `util.propertyKeyTypes` (string|number|symbol)? */\nexport function propertyKeyTest(keyExpr: string): string {\n return `typeof ${keyExpr}===\"string\"||typeof ${keyExpr}===\"number\"||typeof ${keyExpr}===\"symbol\"`;\n}\n\n/**\n * superRefine fast-check: run the payload callback on a throwaway payload and\n * report whether it both added nothing AND left the value alone. zod's own\n * wrapper (the referenced function) installs `addIssue` and normalizes what the\n * user adds, so the verdict is zod's; the issues themselves are re-collected by\n * the slow walk.\n *\n * The `p.value===v` half is what lets a superRefine node keep a fast path at\n * all. `value` is writable public API ($RefinementCtx extends ParsePayload), so\n * a callback may rewrite it, and the fast path's caller returns the ORIGINAL\n * input on success — which would then be stale. Reporting false when the value\n * moved routes those parses into the slow walk, which propagates the new value\n * (see ZC_SR_DECL). Callbacks that only validate — effectively all of them —\n * still take the fast exit.\n */\nexport const ZC_SR_OK_DECL =\n \"function __zcSrOk(f,v){var p={value:v,issues:[]};__zcSrRun(f,p);\" +\n \"return p.issues.length===0&&p.value===v;}\";\n\n/**\n * Module-local (never imported by generated code) — __zcSr/__zcSrOk call it.\n * Lean mode declares it in the runtime module beside them; inline mode pushes it\n * into the preamble alongside whichever of the two is used.\n *\n * Invoke the referenced wrapper, reproducing zod's synchronous-parse contract:\n * a callback that returns a promise makes zod raise $ZodAsyncError rather than\n * silently accepting. Because the ref points at zod's superRefine WRAPPER, not\n * the user's function, an async callback cannot be detected while extracting —\n * the returned thenable is the only evidence, so the test lives here. Sync\n * callbacks return undefined, so the guard short-circuits on the first operand.\n */\nexport const ZC_SR_RUN_DECL =\n \"function __zcSrRun(f,p){var r=f(p);\" +\n 'if(r&&typeof r.then===\"function\"){throw new __zcCore.$ZodAsyncError();}}';\n\n/**\n * z.custom()/z.instanceof() fast verdict. Zod treats truthy predicate returns\n * as success and raises $ZodAsyncError when a synchronous parse encounters a\n * thenable, including a non-async function that happens to return a Promise.\n */\nexport const ZC_CUSTOM_OK_DECL =\n \"function __zcCu(f,v){var r=f(v);\" +\n 'if(r&&typeof r.then===\"function\"){throw new __zcCore.$ZodAsyncError();}return !!r;}';\n\n/**\n * superRefine slow-path merge: run the callback, then move its issues onto the\n * validator's list the way zod's finalizeIssue does — the node's path prefixed\n * onto any path the user supplied, the internal `inst`/`continue` fields\n * dropped (they are zod bookkeeping, deleted before the issue is user-visible),\n * and the owning schema's static message `m` applied to an issue that carries\n * none of its own, since zod stamps the owner onto every issue a check raises.\n *\n * Returns the payload, so the caller can write `.value` back (the callback may\n * have rewritten it) and read `.aborted`. Aborted is set when any issue aborts\n * in zod's sense (`continue !== true`, which covers `fatal: true` and the string\n * shorthand, whose issue carries no `continue` at all) — or when the callback\n * set it directly, also public payload API. A union option uses it to mark\n * itself aborted, matching how zod prunes option errors; without it an option\n * failing only through superRefine would be surfaced directly instead of inside\n * `invalid_union`.\n */\nexport const ZC_SR_DECL =\n \"function __zcSr(f,v,p,e,m){var q={value:v,issues:[]};__zcSrRun(f,q);\" +\n \"for(var i=0;i<q.issues.length;i++){var s=q.issues[i],t={};\" +\n 'for(var k in s){if(k!==\"inst\"&&k!==\"continue\")t[k]=s[k];}' +\n \"if(s.continue!==true)q.aborted=true;\" +\n \"t.path=s.path&&s.path.length?p.concat(s.path):p;\" +\n \"if(t.message===undefined&&m!==undefined)t.message=m;e.push(t);}return q;}\";\n\n/** Non-issue runtime helper declarations hosted in the virtual module. */\nexport const RUNTIME_HELPER_DECLS: Readonly<Record<string, string>> = {\n __zcAb: ZC_AB_DECL,\n __zcFsr: ZC_FSR_DECL,\n __zcFz: ZC_FZ_DECL,\n __zcHop: ZC_HOP_DECL,\n __zcLo: ZC_LENGTH_ORIGIN_DECL,\n __zcSo: ZC_SIZE_ORIGIN_DECL,\n __zcCpl: ZC_CPL_DECL,\n __zcPs: ZC_PROTO_SCRUB_DECL,\n __zcPlain: ZC_PLAIN_DECL,\n __zcPfx: ZC_PFX_DECL,\n __zcCu: ZC_CUSTOM_OK_DECL,\n __zcSr: ZC_SR_DECL,\n __zcSrOk: ZC_SR_OK_DECL,\n};\n"],"mappings":";AAkGA,MAAa,cAAgD;CAC3D,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;AACV;;;;;;;;;;;;;AAcA,MAAa,cACX;;;;;;;;;;AAaF,MAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B3B,MAAa,gBACX;;;;;;;;;;;;;;;;;;AAsBF,MAAa,wBACX;;;;;;;;;;;;;;;;;AAkBF,MAAa,sBACX;;;;;;;;AAUF,MAAa,cACX;AAEF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;AAqBF,MAAM,uBAA0C;CAC9C;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAgB,iBAAiB,UAA0B;CACzD,OAAO,qBAAqB,KAAK,SAAS,GAAG,SAAS,KAAK,KAAK,UAAU,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI;AAC9F;;;;;;;;;;;;;;;AAgBA,MAAa,aAAa,0GAA0G,iBAAiB,GAAG,EAAE;;;;;;;;;;;;;;;;;AAkB1J,MAAa,aACX;;;;;;;;;AAYF,MAAa,cACX;;AAGF,SAAgB,gBAAgB,SAAyB;CACvD,OAAO,UAAU,QAAQ,sBAAsB,QAAQ,sBAAsB,QAAQ;AACvF;;;;;;;;;;;;;;;;AAiBA,MAAa,gBACX;;;;;;;;;;;;;AAeF,MAAa,iBACX;;;;;;AAQF,MAAa,oBACX;;;;;;;;;;;;;;;;;;AAoBF,MAAa,aACX;;AAQF,MAAa,uBAAyD;CACpE,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,WAAW;CACX,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,UAAU;AACZ"}
|
|
1
|
+
{"version":3,"file":"issue-decls.js","names":[],"sources":["../../../src/core/codegen/issue-decls.ts"],"sourcesContent":["/**\n * Issue factory function bodies (statement form).\n *\n * These functions produce the same `{code, ...}` shapes that lean-mode\n * generated code would otherwise inline at every check site.\n * Hosted in \"virtual:zod-compiler/runtime\" and called as `__zcTS(...)` etc.\n *\n * Argument convention (positional, kept short to minimize call-site bytes):\n * __zcTS(minimum, origin, inclusive, input, path, msg?) — too_small\n * __zcTSt(minimum, origin, input, path, msg?) — too_small, tuple key order\n * __zcTBt(maximum, origin, input, path, msg?) — too_big, tuple key order\n * __zcTB(maximum, origin, inclusive, input, path, msg?) — too_big\n * __zcIT(expected, input, path, msg?) — invalid_type\n * __zcITc(expected, input, path, msg?) — invalid_type, `code` first\n * __zcIF(origin, format, input, path, extra?, msg?) — invalid_format (extra merged into result)\n * __zcIV(values, input, path, extra?, msg?) — invalid_value (extra merged into result)\n * __zcUK(keys, input, path, msg?) — unrecognized_keys\n *\n * The trailing msg argument carries a static custom error message; when\n * absent, the __zcFin finalizer applies the configured locale default.\n *\n * KEY ORDER IS PART OF THE CONTRACT. `ZodError.message` is\n * `JSON.stringify(issues, …, 2)`, so the order these factories insert keys in is\n * printed verbatim in the message every consumer logs, snapshots or serializes.\n * Each literal below therefore reproduces the order of the corresponding\n * `payload.issues.push({…})` in zod, which is irregular by type — `too_small`\n * from a check leads with `origin` while the same code from a tuple's length\n * branch leads with `code` — and every factory writes `message` LAST, because\n * zod's `finalizeIssue` assigns it after the fact (`full.message = …`) even for\n * a custom message baked into the check's error map.\n */\n\nconst ZC_TS_DECL =\n 'function __zcTS(m,o,i,inp,p,msg){var r={origin:o,code:\"too_small\",minimum:m,inclusive:i,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * too_small in the TUPLE under-length key order. $ZodTuple pushes\n * `{ code, minimum, inclusive: true, input, inst, origin }`, so its `origin`\n * trails `inclusive` where every check-created size issue leads with it. Its\n * over-length sibling is __zcTBt.\n */\nconst ZC_TS_TUPLE_DECL =\n 'function __zcTSt(m,o,inp,p,msg){var r={code:\"too_small\",minimum:m,inclusive:true,origin:o,input:inp,path:p,continue:false};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_TS_EXACT_DECL =\n 'function __zcTSx(m,o,inp,p,msg){var r={origin:o,code:\"too_small\",minimum:m,inclusive:true,exact:true,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_TB_DECL =\n 'function __zcTB(m,o,i,inp,p,msg){var r={origin:o,code:\"too_big\",maximum:m,inclusive:i,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * too_big in the TUPLE over-length key order. $ZodTuple spreads\n * `{ code, maximum, inclusive }` and appends `origin` after `input`/`inst`, so\n * its `origin` trails `inclusive` where every check-created size issue leads\n * with it. Its under-length sibling is __zcTSt.\n */\nconst ZC_TB_TUPLE_DECL =\n 'function __zcTBt(m,o,inp,p,msg){var r={code:\"too_big\",maximum:m,inclusive:true,origin:o,input:inp,path:p,continue:false};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_TB_EXACT_DECL =\n 'function __zcTBx(m,o,inp,p,msg){var r={origin:o,code:\"too_big\",maximum:m,inclusive:true,exact:true,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_IT_DECL =\n 'function __zcIT(e,inp,p,msg){var r={expected:e,code:\"invalid_type\",input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * invalid_type with `code` ahead of `expected`. Every schema in zod spells this\n * issue `{ expected, code }` — except `$ZodDiscriminatedUnion`, whose\n * non-object guard writes `{ code, expected }`. One literal, one key order, and\n * it shows up in `ZodError.message`.\n */\nconst ZC_IT_CODE_FIRST_DECL =\n 'function __zcITc(e,inp,p,msg){var r={code:\"invalid_type\",expected:e,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * `o` is the leading `origin`, present only for the formats whose issue carries\n * one: `$ZodCheckStringFormat`'s default pattern check and the regex /\n * includes / starts_with / ends_with checks all lead with `origin: \"string\"`,\n * while `z.url()`'s own pushes and every `$ZodCustomStringFormat` omit it\n * entirely. `extra` holds the per-format tail (`pattern`, `includes`, `prefix`,\n * `suffix`, `note`) and is merged BEFORE input/path so it lands where zod\n * writes it.\n */\nconst ZC_IF_DECL =\n 'function __zcIF(o,f,inp,p,extra,msg){var r=o===undefined?{code:\"invalid_format\",format:f}:{origin:o,code:\"invalid_format\",format:f};if(extra)Object.assign(r,extra);r.input=inp;r.path=p;if(msg!==undefined)r.message=msg;return r;}';\n\n/**\n * `extra` carries the per-producer fields: enum and literal push `values` only,\n * while z.stringbool()'s codec transform also pushes `expected: \"stringbool\"`.\n * Merged the same way __zcIF merges its own.\n */\nconst ZC_IV_DECL =\n 'function __zcIV(values,inp,p,extra,msg){var r={code:\"invalid_value\"};if(extra)Object.assign(r,extra);r.values=values;r.input=inp;r.path=p;if(msg!==undefined)r.message=msg;return r;}';\n\nconst ZC_UK_DECL =\n 'function __zcUK(k,inp,p,msg){var r={code:\"unrecognized_keys\",keys:k,input:inp,path:p};if(msg!==undefined)r.message=msg;return r;}';\n\n/** All issue factory declarations indexed by helper name. */\nexport const ISSUE_DECLS: Readonly<Record<string, string>> = {\n __zcTS: ZC_TS_DECL,\n __zcTSt: ZC_TS_TUPLE_DECL,\n __zcTSx: ZC_TS_EXACT_DECL,\n __zcTB: ZC_TB_DECL,\n __zcTBt: ZC_TB_TUPLE_DECL,\n __zcTBx: ZC_TB_EXACT_DECL,\n __zcIT: ZC_IT_DECL,\n __zcITc: ZC_IT_CODE_FIRST_DECL,\n __zcIF: ZC_IF_DECL,\n __zcIV: ZC_IV_DECL,\n __zcUK: ZC_UK_DECL,\n};\n\n/**\n * Float-safe remainder — byte-for-byte port of zod's util.floatSafeRemainder.\n * Raw `%` mis-rejects valid multiples of decimal steps (0.3 % 0.1 !== 0).\n *\n * zod 4.5 REPLACED the decimal-scaling implementation this once mirrored with a\n * ratio-and-tolerance one, and the two disagree in both directions: the old form\n * accepted `1e-7` as a multiple of 3 (its `toFixed` scaling collapsed the value\n * to 0) and rejected `1e21` (where `toFixed` yields exponential notation and\n * `parseInt` then reads 1). The tolerance is 4x epsilon because `val` and `step`\n * each round to a double before the division rounds again, so a true decimal\n * multiple's quotient can sit up to 1.5 scaled epsilons from the integer.\n */\nexport const ZC_FSR_DECL =\n \"function __zcFsr(v,s){var r=v/s;var q=Math.round(r);\" +\n \"var t=4*Number.EPSILON*Math.max(Math.abs(r),1);\" +\n \"return Math.abs(r-q)<t?0:r-q;}\";\n\n/**\n * Hoisted `Object.prototype.hasOwnProperty` reference. Record fast/slow paths\n * iterate keys with `for(k in o)` (no `Object.keys` array allocation) and guard\n * each key with `__zcHop.call(o,k)` to skip inherited enumerable properties —\n * yielding the exact own-enumerable string-key set `Object.keys` would, so\n * fast/slow stay in agreement and parity with zod's own-key record semantics is\n * preserved. The hoisted reference inlines in V8; reading the prototype property\n * per call would not.\n */\nexport const ZC_HOP_DECL = \"const __zcHop=Object.prototype.hasOwnProperty;\";\n\n/**\n * Port of zod's `util.isPlainObject` — the guard `$ZodRecord` applies to its\n * input, and a STRICTLY narrower test than the `util.isObject` (`typeof\n * \"object\"`, not null, not an array) that `$ZodObject` uses.\n *\n * The distinction is load-bearing and was a validation hole while records shared\n * the object guard: `z.record(z.string(), z.string())` accepted a `Date`, a\n * `Map`, a `RegExp`, an `Error`, a `File` and any class instance — every one of\n * which zod rejects with `invalid_type`/`expected: \"record\"`, and none of which\n * has own enumerable string keys for the value schema to catch. Compiled output\n * therefore said \"valid\" to inputs zod refuses, which is the one direction a\n * validator must never diverge in.\n *\n * The algorithm is zod's, step for step, because the answer is observable and\n * the edge cases are deliberate:\n * - `constructor === undefined` (a null-prototype object) is PLAIN;\n * - a non-function own `constructor` (`{ constructor: 1 }`) is PLAIN;\n * - otherwise the constructor's `prototype` must be an object carrying its OWN\n * `isPrototypeOf` — which `Object.prototype` does and `Date.prototype`,\n * `Map.prototype` and every user class prototype do not. Testing that rather\n * than `Object.getPrototypeOf(o) === Object.prototype` is what lets a plain\n * object from another realm (a vm context, an iframe) still count as plain.\n *\n * `c===Object` is a short-cut, not a fourth rule: it is exactly the case where\n * zod's remaining steps are foregone — `Object.prototype` is an object and has\n * its own `isPrototypeOf` — so the answer is `true` either way. It is also the\n * case every ordinary record takes (an object literal, `JSON.parse` output, a\n * `Map`-free DTO), and taking it saves the `prototype` load and the\n * `hasOwnProperty` call: measured 9.6 → 5.7 ns on a monomorphic record and\n * 15.7 → 9.2 ns across 16 shapes, i.e. 22% of a five-key record's whole parse.\n * A plain object from another realm has a different `Object` and simply takes\n * the long road to the same verdict, as before.\n *\n * Self-contained (`Object.prototype.hasOwnProperty` spelled out rather than\n * reusing `__zcHop`) so inline mode can emit this decl alone: `emitRuntimeHelper`\n * pushes only the decl it is asked for, and a helper that closed over another\n * name would dangle wherever that one was not also emitted.\n */\nexport const ZC_PLAIN_DECL =\n 'function __zcPlain(o){if(typeof o!==\"object\"||o===null||Array.isArray(o))return false;' +\n 'var c=o.constructor;if(c===Object||c===undefined||typeof c!==\"function\")return true;' +\n 'var p=c.prototype;if(typeof p!==\"object\"||p===null||Array.isArray(p))return false;' +\n 'return Object.prototype.hasOwnProperty.call(p,\"isPrototypeOf\");}';\n\n/**\n * `z.email()`'s default validator, `regexes.email`, as a single linear scan.\n *\n * Zod's pattern is\n * `^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$`,\n * and even its lookahead-free rewrite (EMAIL_FAST_REGEX_SOURCE) backtracks at\n * every dot it fails to find: `(?:[X]+\\.)*` re-tries the run one character\n * shorter each time, and the domain's `(?:label\\.)+` does the same over the\n * TLD. Written as a scanner the language is:\n *\n * local — `[A-Za-z0-9_'+.-]+`, no leading `.`, no `..`, and the character\n * before `@` is neither `.` nor `'` (that last is the `[A-Za-z0-9_+-]`\n * the pattern demands there);\n * domain — one or more labels `[A-Za-z0-9][A-Za-z0-9-]*` each ending in `.`,\n * then a TLD of two or more letters running to the end.\n *\n * A trailing `\\n` is not accepted: the pattern has no `m` flag, so its `$`\n * matches only at the end of input, and the scan reads to `length`.\n *\n * Measured against the fast regex on V8: 32 → 16 ns for `alice@example.com`,\n * 48 → 40 for `bob_smith-99@mail-server.io`, 39 → 20 for a non-address, and a\n * tie from ~35 characters up (the regex's per-character work is cheaper than a\n * `charCodeAt` loop's; its fixed dispatch cost is what the scanner avoids). A\n * lookbehind rewrite runs about as fast but needs ES2018 regex support, which\n * the CLI's React Native / Hermes and older-Safari consumers cannot assume.\n *\n * Equivalence to zod's regex — every string, both verdicts — is pinned by\n * tests/core/codegen/email-scanner.test.ts. Reached only behind a `typeof`\n * string guard, like the `.test()` it replaces; issue sites keep reporting\n * zod's own pattern string (see `emitRegexSourceString`).\n */\nexport const ZC_EMAIL_DECL =\n \"function __zcEmail(s){var n=s.length,i=0,c,p=46;\" +\n // Local part. `p` starts as `.` so a leading dot trips the `..` rule.\n \"for(;;){if(i===n)return false;c=s.charCodeAt(i);if(c===64)break;\" +\n \"if(c===46){if(p===46)return false;}\" +\n \"else if(!((c>=97&&c<=122)||(c>=65&&c<=90)||(c>=48&&c<=57)||c===95||c===39||c===43||c===45))return false;\" +\n \"p=c;i++;}\" +\n \"if(p===46||p===39)return false;\" +\n // Domain. `l` is the current label's start, `t` whether it is letters-only.\n \"var l=++i,d=0,t=true;\" +\n \"for(;i<n;i++){c=s.charCodeAt(i);\" +\n \"if((c>=97&&c<=122)||(c>=65&&c<=90))continue;\" +\n \"if(c===46){if(i===l)return false;d++;l=i+1;t=true;continue;}\" +\n \"if((c>=48&&c<=57)||c===45){if(c===45&&i===l)return false;t=false;continue;}\" +\n \"return false;}\" +\n \"return d>0&&t&&n-l>=2;}\";\n\n/**\n * Ports of `util.getLengthableOrigin` / `util.getSizableOrigin` — the `origin` a\n * length/size check puts on its issue, computed from the RUNTIME INPUT rather\n * than from the schema.\n *\n * They only matter because those checks declare a `when` predicate\n * (`!nullish(value) && value.length/size !== undefined`), which bypasses zod's\n * abort gate: `z.string().min(2)` handed `[]` reports the `invalid_type` AND a\n * `too_small` whose origin is `\"array\"`, because the empty array satisfies the\n * `when`. Inside the matching type branch the origin is statically known and\n * these are not used; they exist for the type-MISMATCH branch, where the input\n * can be anything with a `.length` or a `.size`.\n *\n * `File` is probed through `typeof` first: zod tests `input instanceof File`\n * unguarded, which throws where the global is absent — an environment zod does\n * not run in, and not one worth reproducing a crash for.\n */\nexport const ZC_LENGTH_ORIGIN_DECL =\n 'function __zcLo(v){return Array.isArray(v)?\"array\":typeof v===\"string\"?\"string\":\"unknown\";}';\n\n/**\n * Drop an own `__proto__` from a container the parse hands back BY REFERENCE.\n *\n * zod never lets the key into an output: `$ZodObject`'s shape loop strips a\n * declared one, `handleCatchall` skips an undeclared one, and `$ZodRecord` skips\n * it while copying — all so the assignment into their fresh `{}` cannot replace\n * the result's prototype. A compiled loose/catchall object or record IS its\n * input, so the key has to be removed here instead; leaving it made\n * `Object.assign({}, parsed)` a prototype-pollution sink, since [[Set]] runs the\n * inherited setter the spread that built the value did not.\n *\n * Copies rather than editing in place: the divergence note promises the caller\n * its own container back, not one with a key silently deleted from it. The\n * common object has no such key and is returned untouched, so the cost is one\n * `hasOwnProperty` call.\n */\nexport const ZC_PROTO_SCRUB_DECL =\n 'function __zcPs(o){if(!Object.prototype.hasOwnProperty.call(o,\"__proto__\"))return o;' +\n 'var c={...o};delete c[\"__proto__\"];return c;}';\n\n/**\n * Code points in a string — zod's `util.codePointLength`, verbatim. A surrogate\n * pair counts once and a lone surrogate as itself. The regex probe is the fast\n * exit for a string with no astral characters, and the hand-rolled loop avoids\n * the allocating string iterator. Only reached from a length check whose\n * UTF-16 count leaves the verdict in doubt (see stringLengthTests).\n */\nexport const ZC_CPL_DECL =\n \"function __zcCpl(s){var n=s.length;if(!/[\\\\uD800-\\\\uDBFF]/.test(s))return n;var c=n;for(var i=0;i<n-1;i++){if((s.charCodeAt(i)&0xfc00)===0xd800&&(s.charCodeAt(i+1)&0xfc00)===0xdc00){c--;i++;}}return c;}\";\n\nexport const ZC_SIZE_ORIGIN_DECL =\n 'function __zcSo(v){return v instanceof Set?\"set\":v instanceof Map?\"map\":' +\n '(typeof File!==\"undefined\"&&v instanceof File)?\"file\":\"unknown\";}';\n\n/**\n * Issue codes zod raises from a schema's `_zod.parse` rather than from a check,\n * and which therefore carry `continue !== true` — what `util.aborted` looks for.\n *\n * Everything a CHECK produces (`too_small`, `too_big`, `invalid_format`,\n * `not_multiple_of`, a refine's `custom`) is continuable, because `$ZodCheck`\n * sets `continue: !def.abort` and an `abort: true` check costs the schema its\n * compiled path anyway — so classifying by code alone is exact for generated\n * issues.\n *\n * `unrecognized_keys` is the one parse-level issue zod pushes WITH\n * `continue: true`: it describes the shape of the input rather than the\n * validity of the parsed value, so the parse still fails but the object's own\n * refines run first and a union does not count the option as aborted.\n *\n * Read by {@link ZC_AB_DECL} and by the union's option-pruning loop, which\n * applies the same rule inline over a per-option issue array.\n */\nconst ABORTING_ISSUE_CODES: readonly string[] = [\n \"invalid_type\",\n \"invalid_value\",\n \"invalid_union\",\n \"invalid_key\",\n \"invalid_element\",\n];\n\n/** `c===\"invalid_type\"||c===\"invalid_value\"||…` over the code held in `codeExpr`. */\nexport function abortingCodeTest(codeExpr: string): string {\n return ABORTING_ISSUE_CODES.map((code) => `${codeExpr}===${JSON.stringify(code)}`).join(\"||\");\n}\n\n/**\n * Port of zod's `util.aborted(payload, startIndex)`: has anything since\n * `startIndex` produced a NON-continuable issue?\n *\n * zod gates a schema's check chain on this (`runChecks`: `else if (isAborted)\n * continue`), which is what makes a container's `.refine()` still run after a\n * property or element failed its own `min`/`max`/format check, and stop running\n * once one failed to parse at all. The `startIndex` is the issue count when the\n * node was entered, mirroring the fresh payload zod hands each sub-schema.\n *\n * Size/length checks are exempt in zod — they declare a `when` predicate, which\n * bypasses the abort gate — so generated code leaves those ungated and only\n * wraps the refine/superRefine effects.\n */\nexport const ZC_AB_DECL = `function __zcAb(e,i){for(;i<e.length;i++){var s=e[i];if(s.continue===false)return true;var c=s.code;if(${abortingCodeTest(\"c\")})return true;}return false;}`;\n\n/**\n * Port of zod's `util.finalizeIssue` for issues NESTED inside an\n * `invalid_key` / `invalid_element` wrapper. Those never reach the top-level\n * finalization loop (which walks only the outer array), so zod finalizes them\n * where it builds the wrapper: locale message applied when none was baked in,\n * `input` cleared. Their `path` stays RELATIVE to the key or value schema — zod\n * ran it on a fresh payload — so nothing rewrites it.\n *\n * `input` is `delete`d rather than assigned `undefined`, matching zod's own\n * `delete full.input` and the top-level finalizer: the key's PRESENCE is\n * observable (`\"input\" in issue`, `Object.keys`, spread, a strict deep-equal\n * against a zod issue), so assigning left a nested issue one key wider than\n * zod's. Only reached while an error is being built — never on a successful\n * parse — so the dictionary-mode transition it costs is confined to the path\n * that then constructs a ZodError anyway.\n */\nexport const ZC_FZ_DECL =\n \"function __zcFz(e){for(var i=0;i<e.length;i++){var s=e[i];\" +\n 'if(s.message===undefined&&typeof __zcMsg===\"function\")s.message=__zcMsg(s);' +\n \"delete s.input;delete s.continue;}return e;}\";\n\n/**\n * Port of zod's `util.prefixIssues(key, issues)` for a map entry whose key is a\n * property-key type: each issue's RELATIVE path is spliced onto the map's own\n * path plus the key, and the issue moves into the parent's array.\n *\n * `b.concat(k,x.path)` flattens `x.path` one level, giving exactly\n * `[...base, key, ...relative]`.\n */\nexport const ZC_PFX_DECL =\n \"function __zcPfx(d,s,b,k){for(var i=0;i<s.length;i++){var x=s[i];x.path=b.concat(k,x.path);d.push(x);}}\";\n\n/** Does `keyExpr` hold one of zod's `util.propertyKeyTypes` (string|number|symbol)? */\nexport function propertyKeyTest(keyExpr: string): string {\n return `typeof ${keyExpr}===\"string\"||typeof ${keyExpr}===\"number\"||typeof ${keyExpr}===\"symbol\"`;\n}\n\n/**\n * superRefine fast-check: run the payload callback on a throwaway payload and\n * report whether it both added nothing AND left the value alone. zod's own\n * wrapper (the referenced function) installs `addIssue` and normalizes what the\n * user adds, so the verdict is zod's; the issues themselves are re-collected by\n * the slow walk.\n *\n * The `p.value===v` half is what lets a superRefine node keep a fast path at\n * all. `value` is writable public API ($RefinementCtx extends ParsePayload), so\n * a callback may rewrite it, and the fast path's caller returns the ORIGINAL\n * input on success — which would then be stale. Reporting false when the value\n * moved routes those parses into the slow walk, which propagates the new value\n * (see ZC_SR_DECL). Callbacks that only validate — effectively all of them —\n * still take the fast exit.\n */\nexport const ZC_SR_OK_DECL =\n \"function __zcSrOk(f,v){var p={value:v,issues:[]};__zcSrRun(f,p);\" +\n \"return p.issues.length===0&&p.value===v;}\";\n\n/**\n * Module-local (never imported by generated code) — __zcSr/__zcSrOk call it.\n * Lean mode declares it in the runtime module beside them; inline mode pushes it\n * into the preamble alongside whichever of the two is used.\n *\n * Invoke the referenced wrapper, reproducing zod's synchronous-parse contract:\n * a callback that returns a promise makes zod raise $ZodAsyncError rather than\n * silently accepting. Because the ref points at zod's superRefine WRAPPER, not\n * the user's function, an async callback cannot be detected while extracting —\n * the returned thenable is the only evidence, so the test lives here. Sync\n * callbacks return undefined, so the guard short-circuits on the first operand.\n */\nexport const ZC_SR_RUN_DECL =\n \"function __zcSrRun(f,p){var r=f(p);\" +\n 'if(r&&typeof r.then===\"function\"){throw new __zcCore.$ZodAsyncError();}}';\n\n/**\n * z.custom()/z.instanceof() fast verdict. Zod treats truthy predicate returns\n * as success and raises $ZodAsyncError when a synchronous parse encounters a\n * thenable, including a non-async function that happens to return a Promise.\n */\nexport const ZC_CUSTOM_OK_DECL =\n \"function __zcCu(f,v){var r=f(v);\" +\n 'if(r&&typeof r.then===\"function\"){throw new __zcCore.$ZodAsyncError();}return !!r;}';\n\n/**\n * superRefine slow-path merge: run the callback, then move its issues onto the\n * validator's list the way zod's finalizeIssue does — the node's path prefixed\n * onto any path the user supplied, the internal `inst`/`continue` fields\n * dropped (they are zod bookkeeping, deleted before the issue is user-visible),\n * and the owning schema's static message `m` applied to an issue that carries\n * none of its own, since zod stamps the owner onto every issue a check raises.\n *\n * Returns the payload, so the caller can write `.value` back (the callback may\n * have rewritten it) and read `.aborted`. Aborted is set when any issue aborts\n * in zod's sense (`continue !== true`, which covers `fatal: true` and the string\n * shorthand, whose issue carries no `continue` at all) — or when the callback\n * set it directly, also public payload API. A union option uses it to mark\n * itself aborted, matching how zod prunes option errors; without it an option\n * failing only through superRefine would be surfaced directly instead of inside\n * `invalid_union`.\n */\nexport const ZC_SR_DECL =\n \"function __zcSr(f,v,p,e,m){var q={value:v,issues:[]};__zcSrRun(f,q);\" +\n \"for(var i=0;i<q.issues.length;i++){var s=q.issues[i],t={};\" +\n 'for(var k in s){if(k!==\"inst\"&&k!==\"continue\")t[k]=s[k];}' +\n \"if(s.continue!==true)q.aborted=true;\" +\n \"t.path=s.path&&s.path.length?p.concat(s.path):p;\" +\n \"if(t.message===undefined&&m!==undefined)t.message=m;e.push(t);}return q;}\";\n\n/** Non-issue runtime helper declarations hosted in the virtual module. */\nexport const RUNTIME_HELPER_DECLS: Readonly<Record<string, string>> = {\n __zcAb: ZC_AB_DECL,\n __zcFsr: ZC_FSR_DECL,\n __zcFz: ZC_FZ_DECL,\n __zcHop: ZC_HOP_DECL,\n __zcLo: ZC_LENGTH_ORIGIN_DECL,\n __zcSo: ZC_SIZE_ORIGIN_DECL,\n __zcCpl: ZC_CPL_DECL,\n __zcEmail: ZC_EMAIL_DECL,\n __zcPs: ZC_PROTO_SCRUB_DECL,\n __zcPlain: ZC_PLAIN_DECL,\n __zcPfx: ZC_PFX_DECL,\n __zcCu: ZC_CUSTOM_OK_DECL,\n __zcSr: ZC_SR_DECL,\n __zcSrOk: ZC_SR_OK_DECL,\n};\n"],"mappings":";AAkGA,MAAa,cAAgD;CAC3D,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;AACV;;;;;;;;;;;;;AAcA,MAAa,cACX;;;;;;;;;;AAaF,MAAa,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwC3B,MAAa,gBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCF,MAAa,gBACX;;;;;;;;;;;;;;;;;;AAiCF,MAAa,wBACX;;;;;;;;;;;;;;;;;AAkBF,MAAa,sBACX;;;;;;;;AAUF,MAAa,cACX;AAEF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;AAqBF,MAAM,uBAA0C;CAC9C;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAgB,iBAAiB,UAA0B;CACzD,OAAO,qBAAqB,KAAK,SAAS,GAAG,SAAS,KAAK,KAAK,UAAU,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI;AAC9F;;;;;;;;;;;;;;;AAgBA,MAAa,aAAa,0GAA0G,iBAAiB,GAAG,EAAE;;;;;;;;;;;;;;;;;AAkB1J,MAAa,aACX;;;;;;;;;AAYF,MAAa,cACX;;AAGF,SAAgB,gBAAgB,SAAyB;CACvD,OAAO,UAAU,QAAQ,sBAAsB,QAAQ,sBAAsB,QAAQ;AACvF;;;;;;;;;;;;;;;;AAiBA,MAAa,gBACX;;;;;;;;;;;;;AAeF,MAAa,iBACX;;;;;;AAQF,MAAa,oBACX;;;;;;;;;;;;;;;;;;AAoBF,MAAa,aACX;;AAQF,MAAa,uBAAyD;CACpE,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,WAAW;CACX,QAAQ;CACR,WAAW;CACX,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,UAAU;AACZ"}
|
|
@@ -17,6 +17,16 @@ declare function defaultValueExpr(ir: DefaultIR): string;
|
|
|
17
17
|
*/
|
|
18
18
|
declare function needsPostInnerDefault(ir: DefaultIR): boolean;
|
|
19
19
|
declare function slowDefault(ir: DefaultIR, g: SlowGen): string;
|
|
20
|
+
/**
|
|
21
|
+
* By-reference form: a present value that the inner accepts. `undefined` is
|
|
22
|
+
* refused even though the schema takes it, because the fast path's caller hands
|
|
23
|
+
* back the INPUT on success and the schema's answer there is the default.
|
|
24
|
+
*
|
|
25
|
+
* Acceptance form (see FastGen.acceptance): `undefined` accepted, as zod does —
|
|
26
|
+
* the default fires, and the schema succeeds. Only a verdict is read from this
|
|
27
|
+
* form, so no payload can go wrong; it is what makes `.is()` on a defaulted
|
|
28
|
+
* schema a total, zero-allocation predicate.
|
|
29
|
+
*/
|
|
20
30
|
declare function fastDefault(ir: DefaultIR, g: FastGen): string | null;
|
|
21
31
|
//#endregion
|
|
22
32
|
export { defaultValueExpr, fastDefault, needsPostInnerDefault, slowDefault };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/default.ts"],"mappings":";;;;;;;iBASgB,iBAAiB,IAAI;;;;;;;;;;iBAarB,sBAAsB,IAAI;iBAI1B,YAAY,IAAI,WAAW,GAAG
|
|
1
|
+
{"version":3,"file":"default.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/default.ts"],"mappings":";;;;;;;iBASgB,iBAAiB,IAAI;;;;;;;;;;iBAarB,sBAAsB,IAAI;iBAI1B,YAAY,IAAI,WAAW,GAAG;;;;;;;;;;;iBA4B9B,YAAY,IAAI,WAAW,GAAG"}
|
|
@@ -35,7 +35,18 @@ function slowDefault(ir, g) {
|
|
|
35
35
|
}
|
|
36
36
|
`;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* By-reference form: a present value that the inner accepts. `undefined` is
|
|
40
|
+
* refused even though the schema takes it, because the fast path's caller hands
|
|
41
|
+
* back the INPUT on success and the schema's answer there is the default.
|
|
42
|
+
*
|
|
43
|
+
* Acceptance form (see FastGen.acceptance): `undefined` accepted, as zod does —
|
|
44
|
+
* the default fires, and the schema succeeds. Only a verdict is read from this
|
|
45
|
+
* form, so no payload can go wrong; it is what makes `.is()` on a defaulted
|
|
46
|
+
* schema a total, zero-allocation predicate.
|
|
47
|
+
*/
|
|
38
48
|
function fastDefault(ir, g) {
|
|
49
|
+
if (g.acceptance === true) return fastSentinelWrapper(g, ir.inner, "===undefined", "||");
|
|
39
50
|
return fastSentinelWrapper(g, ir.inner, "!==undefined", "&&");
|
|
40
51
|
}
|
|
41
52
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default.js","names":[],"sources":["../../../../src/core/codegen/schemas/default.ts"],"sourcesContent":["import type { DefaultIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { fastSentinelWrapper, rejectsUndefined } from \"../context.js\";\nimport { emit } from \"../emit.js\";\n\n/**\n * Expression for the declared default value, read off the retained schema so a\n * reference-typed default keeps zod's identity (one shared object, not a copy).\n */\nexport function defaultValueExpr(ir: DefaultIR): string {\n return `__rf[${ir.refIndex}]._zod.def.defaultValue`;\n}\n\n/**\n * Zod's `handleDefaultResult`: after the inner schema runs on a DEFINED input,\n * an `undefined` result gets the default applied too — so\n * `z.string().transform(() => undefined).default(\"d\")` yields \"d\", not undefined.\n *\n * Emitted only when the inner can actually yield `undefined`, which is what\n * `rejectsUndefined` decides; the overwhelmingly common\n * `z.number().default(1)` shape therefore pays nothing for it.\n */\nexport function needsPostInnerDefault(ir: DefaultIR): boolean {\n return !rejectsUndefined(ir.inner);\n}\n\nexport function slowDefault(ir: DefaultIR, g: SlowGen): string {\n // For a defined value, zod runs the inner schema and returns its payload\n // unchanged — so forward the union abort flag like the other pass-throughs\n // (a pipe inner whose `in` fails must abort this option). The default-value\n // branch produces no issues, so it never aborts.\n const reapply = needsPostInnerDefault(ir)\n ? `if(${g.output}===undefined){${g.output}=${defaultValueExpr(ir)};}`\n : \"\";\n return emit`\n if(${g.input}===undefined){\n ${g.output}=${defaultValueExpr(ir)};\n }else{\n ${g.visit(ir.inner, { input: g.output, output: g.output, aborted: g.aborted })}\n ${reapply}\n }\n `;\n}\n\nexport function fastDefault(ir: DefaultIR, g: FastGen): string | null {\n return fastSentinelWrapper(g, ir.inner, \"!==undefined\", \"&&\");\n}\n"],"mappings":";;;;;;;AASA,SAAgB,iBAAiB,IAAuB;CACtD,OAAO,QAAQ,GAAG,SAAS;AAC7B;;;;;;;;;;AAWA,SAAgB,sBAAsB,IAAwB;CAC5D,OAAO,CAAC,iBAAiB,GAAG,KAAK;AACnC;AAEA,SAAgB,YAAY,IAAe,GAAoB;CAK7D,MAAM,UAAU,sBAAsB,EAAE,IACpC,MAAM,EAAE,OAAO,gBAAgB,EAAE,OAAO,GAAG,iBAAiB,EAAE,EAAE,MAChE;CACJ,OAAO,IAAI;SACJ,EAAE,MAAM;QACT,EAAE,OAAO,GAAG,iBAAiB,EAAE,EAAE;;QAEjC,EAAE,MAAM,GAAG,OAAO;EAAE,OAAO,EAAE;EAAQ,QAAQ,EAAE;EAAQ,SAAS,EAAE;CAAQ,CAAC,EAAE;QAC7E,QAAQ;;;AAGhB
|
|
1
|
+
{"version":3,"file":"default.js","names":[],"sources":["../../../../src/core/codegen/schemas/default.ts"],"sourcesContent":["import type { DefaultIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { fastSentinelWrapper, rejectsUndefined } from \"../context.js\";\nimport { emit } from \"../emit.js\";\n\n/**\n * Expression for the declared default value, read off the retained schema so a\n * reference-typed default keeps zod's identity (one shared object, not a copy).\n */\nexport function defaultValueExpr(ir: DefaultIR): string {\n return `__rf[${ir.refIndex}]._zod.def.defaultValue`;\n}\n\n/**\n * Zod's `handleDefaultResult`: after the inner schema runs on a DEFINED input,\n * an `undefined` result gets the default applied too — so\n * `z.string().transform(() => undefined).default(\"d\")` yields \"d\", not undefined.\n *\n * Emitted only when the inner can actually yield `undefined`, which is what\n * `rejectsUndefined` decides; the overwhelmingly common\n * `z.number().default(1)` shape therefore pays nothing for it.\n */\nexport function needsPostInnerDefault(ir: DefaultIR): boolean {\n return !rejectsUndefined(ir.inner);\n}\n\nexport function slowDefault(ir: DefaultIR, g: SlowGen): string {\n // For a defined value, zod runs the inner schema and returns its payload\n // unchanged — so forward the union abort flag like the other pass-throughs\n // (a pipe inner whose `in` fails must abort this option). The default-value\n // branch produces no issues, so it never aborts.\n const reapply = needsPostInnerDefault(ir)\n ? `if(${g.output}===undefined){${g.output}=${defaultValueExpr(ir)};}`\n : \"\";\n return emit`\n if(${g.input}===undefined){\n ${g.output}=${defaultValueExpr(ir)};\n }else{\n ${g.visit(ir.inner, { input: g.output, output: g.output, aborted: g.aborted })}\n ${reapply}\n }\n `;\n}\n\n/**\n * By-reference form: a present value that the inner accepts. `undefined` is\n * refused even though the schema takes it, because the fast path's caller hands\n * back the INPUT on success and the schema's answer there is the default.\n *\n * Acceptance form (see FastGen.acceptance): `undefined` accepted, as zod does —\n * the default fires, and the schema succeeds. Only a verdict is read from this\n * form, so no payload can go wrong; it is what makes `.is()` on a defaulted\n * schema a total, zero-allocation predicate.\n */\nexport function fastDefault(ir: DefaultIR, g: FastGen): string | null {\n if (g.acceptance === true) return fastSentinelWrapper(g, ir.inner, \"===undefined\", \"||\");\n return fastSentinelWrapper(g, ir.inner, \"!==undefined\", \"&&\");\n}\n"],"mappings":";;;;;;;AASA,SAAgB,iBAAiB,IAAuB;CACtD,OAAO,QAAQ,GAAG,SAAS;AAC7B;;;;;;;;;;AAWA,SAAgB,sBAAsB,IAAwB;CAC5D,OAAO,CAAC,iBAAiB,GAAG,KAAK;AACnC;AAEA,SAAgB,YAAY,IAAe,GAAoB;CAK7D,MAAM,UAAU,sBAAsB,EAAE,IACpC,MAAM,EAAE,OAAO,gBAAgB,EAAE,OAAO,GAAG,iBAAiB,EAAE,EAAE,MAChE;CACJ,OAAO,IAAI;SACJ,EAAE,MAAM;QACT,EAAE,OAAO,GAAG,iBAAiB,EAAE,EAAE;;QAEjC,EAAE,MAAM,GAAG,OAAO;EAAE,OAAO,EAAE;EAAQ,QAAQ,EAAE;EAAQ,SAAS,EAAE;CAAQ,CAAC,EAAE;QAC7E,QAAQ;;;AAGhB;;;;;;;;;;;AAYA,SAAgB,YAAY,IAAe,GAA2B;CACpE,IAAI,EAAE,eAAe,MAAM,OAAO,oBAAoB,GAAG,GAAG,OAAO,gBAAgB,IAAI;CACvF,OAAO,oBAAoB,GAAG,GAAG,OAAO,gBAAgB,IAAI;AAC9D"}
|
|
@@ -40,10 +40,14 @@ declare function fastDiscriminatedUnion(ir: DiscriminatedUnionIR, g: FastGen): s
|
|
|
40
40
|
* options (ambiguous), a non-switchable value (`undefined`/`NaN`), or a
|
|
41
41
|
* non-object option makes detection bail to the safe `||`-chain.
|
|
42
42
|
*
|
|
43
|
-
*
|
|
43
|
+
* The slow path is untouched: it keeps `z.union`'s sequential trial and its
|
|
44
44
|
* `invalid_union` error shape, so failure output stays byte-identical to Zod.
|
|
45
|
+
* The fast path and the build path both dispatch on the result — the build
|
|
46
|
+
* path from two options up (`minOptions`), since its options are hosted calls
|
|
47
|
+
* either way and a switch only ever replaces probes with one call; see
|
|
48
|
+
* `buildUnion`.
|
|
45
49
|
*/
|
|
46
|
-
declare function detectUnionDiscriminator(options: readonly SchemaIR[]): {
|
|
50
|
+
declare function detectUnionDiscriminator(options: readonly SchemaIR[], minOptions?: number): {
|
|
47
51
|
discriminator: string;
|
|
48
52
|
cases: DiscriminatorCase[];
|
|
49
53
|
} | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discriminated-union.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"discriminated-union.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"mappings":";;;;KAaK,oBAAoB;iBAET,uBACd,IAAI;EAAa;GACjB,GAAG;;;;;;;;;;;;;;;;;;iBAoEW,4BACd,GAAG,SACH,uBACA,gBAAgB,qBAChB,kBAAkB;iBAmCJ,uBAAuB,IAAI,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;iBAyDpD,yBACd,kBAAkB,YAClB;EACG;EAAuB,OAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { declareFastTemps,
|
|
1
|
+
import { declareFastTemps, escapeString, extendPath, hasMutation, literalToJs } from "../context.js";
|
|
2
2
|
import { emit } from "../emit.js";
|
|
3
3
|
import { invalidType } from "../emit-issue.js";
|
|
4
4
|
//#region src/core/codegen/schemas/discriminated-union.ts
|
|
@@ -53,60 +53,15 @@ function emitFastDiscriminatedSwitch(g, discriminator, cases, options) {
|
|
|
53
53
|
const helperName = g.temp("du");
|
|
54
54
|
const helperParam = g.temp("dx");
|
|
55
55
|
const body = g.scoped(helperParam);
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (check === null) return null;
|
|
62
|
-
caseStrs.push(`case ${literalToJs(value)}:return ${check};`);
|
|
63
|
-
}
|
|
64
|
-
g.ctx.preamble.push(`function ${helperName}(${helperParam}){${declareFastTemps(body.scope)}switch(${helperParam}[${discKey}]){${caseStrs.join("")}default:return false;}}`);
|
|
65
|
-
} else {
|
|
66
|
-
const caseStrs = [];
|
|
67
|
-
for (const [optionIndex, ordinal] of table.ordinals) {
|
|
68
|
-
const check = body.visit(options[optionIndex], { discSkipKey: discriminator });
|
|
69
|
-
if (check === null) return null;
|
|
70
|
-
caseStrs.push(`case ${ordinal}:return ${check};`);
|
|
71
|
-
}
|
|
72
|
-
const tableVar = emitConstant(g.ctx, "dt", table.initializer);
|
|
73
|
-
const t = g.temp("dv");
|
|
74
|
-
g.ctx.preamble.push(`function ${helperName}(${helperParam}){${declareFastTemps(body.scope)}var ${t}=${helperParam}[${discKey}];switch(typeof ${t}==="string"?${tableVar}[${t}]:0){${caseStrs.join("")}default:return false;}}`);
|
|
56
|
+
const caseStrs = [];
|
|
57
|
+
for (const { value, option: index } of cases) {
|
|
58
|
+
const check = body.visit(options[index], { discSkipKey: discriminator });
|
|
59
|
+
if (check === null) return null;
|
|
60
|
+
caseStrs.push(`case ${literalToJs(value)}:return ${check};`);
|
|
75
61
|
}
|
|
62
|
+
g.ctx.preamble.push(`function ${helperName}(${helperParam}){${declareFastTemps(body.scope)}switch(${helperParam}[${discKey}]){${caseStrs.join("")}default:return false;}}`);
|
|
76
63
|
return `typeof ${x}==="object"&&${x}!==null&&!Array.isArray(${x})&&${helperName}(${x})`;
|
|
77
64
|
}
|
|
78
|
-
/**
|
|
79
|
-
* Minimum case count for ordinal dispatch. Measured crossover is 3: at 2 cases
|
|
80
|
-
* the string switch is one comparison and beats the extra table lookup
|
|
81
|
-
* (4.1 ns vs 4.5), at 3 the table already wins (6.1 vs 4.6).
|
|
82
|
-
*/
|
|
83
|
-
const MIN_TABLE_DISPATCH = 3;
|
|
84
|
-
/**
|
|
85
|
-
* Build the `{value: ordinal}` dispatch table for a set of cases, or null when
|
|
86
|
-
* the plain string switch should be kept. Requires every discriminator value to
|
|
87
|
-
* be a string — mixed types would collide once coerced to property keys (`5`
|
|
88
|
-
* and `"5"`) — and excludes `__proto__`, which an object literal cannot hold as
|
|
89
|
-
* an own key. Values that select the SAME option share one ordinal, so a
|
|
90
|
-
* multi-value literal emits its check once instead of per value.
|
|
91
|
-
*/
|
|
92
|
-
function stringDispatchTable(cases) {
|
|
93
|
-
if (cases.length < MIN_TABLE_DISPATCH) return null;
|
|
94
|
-
if (!cases.every((c) => typeof c.value === "string" && c.value !== "__proto__")) return null;
|
|
95
|
-
const ordinals = /* @__PURE__ */ new Map();
|
|
96
|
-
const entries = [];
|
|
97
|
-
for (const { value, option } of cases) {
|
|
98
|
-
let ordinal = ordinals.get(option);
|
|
99
|
-
if (ordinal === void 0) {
|
|
100
|
-
ordinal = ordinals.size + 1;
|
|
101
|
-
ordinals.set(option, ordinal);
|
|
102
|
-
}
|
|
103
|
-
entries.push(`${escapeString(value)}:${ordinal}`);
|
|
104
|
-
}
|
|
105
|
-
return {
|
|
106
|
-
initializer: `{${entries.join(",")}}`,
|
|
107
|
-
ordinals
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
65
|
function fastDiscriminatedUnion(ir, g) {
|
|
111
66
|
return emitFastDiscriminatedSwitch(g, ir.discriminator, ir.cases, ir.options);
|
|
112
67
|
}
|
|
@@ -148,11 +103,15 @@ function isSwitchableDiscriminant(v) {
|
|
|
148
103
|
* options (ambiguous), a non-switchable value (`undefined`/`NaN`), or a
|
|
149
104
|
* non-object option makes detection bail to the safe `||`-chain.
|
|
150
105
|
*
|
|
151
|
-
*
|
|
106
|
+
* The slow path is untouched: it keeps `z.union`'s sequential trial and its
|
|
152
107
|
* `invalid_union` error shape, so failure output stays byte-identical to Zod.
|
|
108
|
+
* The fast path and the build path both dispatch on the result — the build
|
|
109
|
+
* path from two options up (`minOptions`), since its options are hosted calls
|
|
110
|
+
* either way and a switch only ever replaces probes with one call; see
|
|
111
|
+
* `buildUnion`.
|
|
153
112
|
*/
|
|
154
|
-
function detectUnionDiscriminator(options) {
|
|
155
|
-
if (options.length <
|
|
113
|
+
function detectUnionDiscriminator(options, minOptions = MIN_AUTO_DISCRIMINATE_OPTIONS) {
|
|
114
|
+
if (options.length < minOptions) return null;
|
|
156
115
|
const objects = [];
|
|
157
116
|
for (const option of options) {
|
|
158
117
|
if (option.type !== "object") return null;
|