zod-compiler 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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"}
@@ -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
- * Fast-path only: the slow path keeps `z.union`'s sequential trial and its
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":";;;;KAcK,oBAAoB;iBAET,uBACd,IAAI;EAAa;GACjB,GAAG;;;;;;;;;;;;;;;;;;iBAoEW,4BACd,GAAG,SACH,uBACA,gBAAgB,qBAChB,kBAAkB;iBAsFJ,uBAAuB,IAAI,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;iBAqDpD,yBACd,kBAAkB;EACf;EAAuB,OAAO"}
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, emitConstant, escapeString, extendPath, hasMutation, literalToJs } from "../context.js";
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 table = stringDispatchTable(cases);
57
- if (table === null) {
58
- const caseStrs = [];
59
- for (const { value, option: index } of cases) {
60
- const check = body.visit(options[index], { discSkipKey: discriminator });
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
- * Fast-path only: the slow path keeps `z.union`'s sequential trial and its
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 < MIN_AUTO_DISCRIMINATE_OPTIONS) return null;
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;
@@ -1 +1 @@
1
- {"version":3,"file":"discriminated-union.js","names":[],"sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"sourcesContent":["import type { DiscriminatedUnionIR, LiteralValue, ObjectIR, SchemaIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport {\n declareFastTemps,\n emitConstant,\n escapeString,\n extendPath,\n hasMutation,\n literalToJs,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType } from \"../emit-issue.js\";\n\n/** One `discriminator value → option index` dispatch entry. */\ntype DiscriminatorCase = DiscriminatedUnionIR[\"cases\"][number];\n\nexport function slowDiscriminatedUnion(\n ir: SchemaIR & { type: \"discriminatedUnion\" },\n g: SlowGen,\n): string {\n const discKey = escapeString(ir.discriminator);\n\n let code = emit`\n if(typeof ${g.input}!==\"object\"||${g.input}===null||Array.isArray(${g.input})){\n ${invalidType(g, \"object\", { codeFirst: true })}\n }else{`;\n\n const objVar = g.temp(\"du\");\n code += `var ${objVar}=${g.input};switch(${objVar}[${discKey}]){`;\n\n for (const { value, option: index } of ir.cases) {\n const option = ir.options[index] as SchemaIR;\n code += emit`\n case ${literalToJs(value)}:\n ${g.visit(option, { input: objVar, output: objVar })}\n break;`;\n }\n\n const msgProp = g.typeMsg === undefined ? \"\" : `,message:${JSON.stringify(g.typeMsg)}`;\n // Field for field what $ZodDiscriminatedUnion pushes when no option matches:\n // `{ code, errors: [], note: \"No matching discriminator\", discriminator,\n // options, input, path: [def.discriminator] }`. `options` is\n // `Array.from(disc.value.keys())` — every dispatch value in map insertion\n // order, which is exactly `ir.cases` (option order, then each option's\n // `propValues[discriminator]` in ITS order, so an omittable discriminator\n // lists `undefined` right after its own values). The locale reads the list\n // for \"Invalid discriminator value. Expected 'a' | 'b'\". A fresh array\n // literal per push, as zod allocates one, so consumers never share or\n // mutate a hoisted table.\n const optionsList = ir.cases.map(({ value }) => literalToJs(value)).join(\",\");\n code += emit`\n default:\n ${g.issues}.push({code:\"invalid_union\",errors:[],note:\"No matching discriminator\",discriminator:${discKey},options:[${optionsList}],input:${g.input},path:${extendPath(g.path, discKey)}${msgProp}});\n }`;\n // Propagate option-applied mutations (defaults, coercions, transforms,\n // overwrite checks, stringbool) back to the output location. Each option is\n // visited with output:objVar — a fresh local — so a mutating option's clone is\n // reassigned into objVar and stranded there; without this write-back the caller\n // returns the ORIGINAL input by reference and the mutation is silently lost.\n // Gated on mutation so a pure-validation union stays a zero-write pass-through\n // (objVar still aliases the input). On the no-match/failure paths objVar equals\n // the input, so the write is a harmless self-assignment.\n if (ir.options.some(hasMutation)) {\n code += `${g.output}=${objVar};`;\n }\n code += `}`;\n return `${code}\\n`;\n}\n\n/**\n * Emit an O(1) switch-dispatch fast-check for a discriminated union — real\n * (`z.discriminatedUnion`) or one detected inside a plain `z.union`\n * (see {@link detectUnionDiscriminator}). Both share this so the detected case\n * inherits the size-gating and the per-case guard strip.\n *\n * `discSkipKey` tells each object option to drop its own type-guard and\n * discriminator re-check: the caller's guard (`typeof x===\"object\"&&…` below)\n * already proved object-ness, and the matched switch case has fixed the\n * discriminator value, so re-emitting either is pure redundancy the optimizer\n * only removes when it inlines this helper — which a union large enough to\n * matter won't. Routed through the normal `visit` so size-gated extraction\n * still bounds the switch (the strip survives into any hoisted helper);\n * non-object options ignore the hint and keep their own guard.\n *\n * Returns null if any option is fast-path-ineligible.\n */\nexport function emitFastDiscriminatedSwitch(\n g: FastGen,\n discriminator: string,\n cases: readonly DiscriminatorCase[],\n options: readonly SchemaIR[],\n): string | null {\n const x = g.input;\n const discKey = escapeString(discriminator);\n const helperName = g.temp(\"du\");\n const helperParam = g.temp(\"dx\");\n\n // The switch body is its own function: size-gate the options against the cap\n // in a fresh scope, otherwise many small options accumulate into the caller's\n // scope while this helper itself grows unbounded past the TurboFan budget.\n const body = g.scoped(helperParam);\n const table = stringDispatchTable(cases);\n\n if (table === null) {\n const caseStrs: string[] = [];\n for (const { value, option: index } of cases) {\n const check = body.visit(options[index] as SchemaIR, { discSkipKey: discriminator });\n if (check === null) return null;\n caseStrs.push(`case ${literalToJs(value)}:return ${check};`);\n }\n g.ctx.preamble.push(\n `function ${helperName}(${helperParam}){${declareFastTemps(body.scope)}switch(${helperParam}[${discKey}]){${caseStrs.join(\"\")}default:return false;}}`,\n );\n } else {\n // Dispatch through a string→ordinal table, then switch on the ordinal. V8\n // compiles a switch over STRING labels as sequential `===` comparisons, so\n // the plain form costs ~0.5 ns per preceding case: measured 4.1 ns (2\n // variants), 11.4 (8), 52.1 (80). A dense integer switch becomes a jump\n // table, leaving the lookup flat — 5.9 ns (8) and 15.1 (80), i.e. 1.9x to\n // 3.5x, for a table that adds ~1.3% to a union's generated bytes.\n //\n // `typeof t===\"string\"` is load-bearing: property access would coerce a\n // non-string discriminator (an object's toString, a number) into a key that\n // could hit a case whose own discriminator check the switch has stripped.\n // Strict equality never matched those, so the guard keeps the verdict.\n const caseStrs: string[] = [];\n for (const [optionIndex, ordinal] of table.ordinals) {\n const check = body.visit(options[optionIndex] as SchemaIR, { discSkipKey: discriminator });\n if (check === null) return null;\n caseStrs.push(`case ${ordinal}:return ${check};`);\n }\n const tableVar = emitConstant(g.ctx, \"dt\", table.initializer);\n const t = g.temp(\"dv\");\n g.ctx.preamble.push(\n `function ${helperName}(${helperParam}){${declareFastTemps(body.scope)}var ${t}=${helperParam}[${discKey}];` +\n `switch(typeof ${t}===\"string\"?${tableVar}[${t}]:0){${caseStrs.join(\"\")}default:return false;}}`,\n );\n }\n\n return `typeof ${x}===\"object\"&&${x}!==null&&!Array.isArray(${x})&&${helperName}(${x})`;\n}\n\n/**\n * Minimum case count for ordinal dispatch. Measured crossover is 3: at 2 cases\n * the string switch is one comparison and beats the extra table lookup\n * (4.1 ns vs 4.5), at 3 the table already wins (6.1 vs 4.6).\n */\nconst MIN_TABLE_DISPATCH = 3;\n\n/**\n * Build the `{value: ordinal}` dispatch table for a set of cases, or null when\n * the plain string switch should be kept. Requires every discriminator value to\n * be a string — mixed types would collide once coerced to property keys (`5`\n * and `\"5\"`) — and excludes `__proto__`, which an object literal cannot hold as\n * an own key. Values that select the SAME option share one ordinal, so a\n * multi-value literal emits its check once instead of per value.\n */\nfunction stringDispatchTable(\n cases: readonly DiscriminatorCase[],\n): { initializer: string; ordinals: Map<number, number> } | null {\n if (cases.length < MIN_TABLE_DISPATCH) return null;\n if (!cases.every((c) => typeof c.value === \"string\" && c.value !== \"__proto__\")) return null;\n\n const ordinals = new Map<number, number>();\n const entries: string[] = [];\n for (const { value, option } of cases) {\n let ordinal = ordinals.get(option);\n if (ordinal === undefined) {\n ordinal = ordinals.size + 1;\n ordinals.set(option, ordinal);\n }\n entries.push(`${escapeString(value as string)}:${ordinal}`);\n }\n return { initializer: `{${entries.join(\",\")}}`, ordinals };\n}\n\nexport function fastDiscriminatedUnion(ir: DiscriminatedUnionIR, g: FastGen): string | null {\n return emitFastDiscriminatedSwitch(g, ir.discriminator, ir.cases, ir.options);\n}\n\n/**\n * Minimum option count for rewriting a plain `z.union` to switch dispatch. Below\n * this the switch helper's fixed call overhead loses to a fully-inlined\n * `||`-chain that V8 keeps flat: measured crossover is ~4 options (n=3 can hit\n * 0.6x — a regression — while n=5 is 1.27x and n=32 is 2.34x), so 5 captures the\n * stable wins with margin and never regresses a small union. Real\n * `z.discriminatedUnion` is unaffected — it dispatches via switch by construction\n * regardless of size.\n */\nconst MIN_AUTO_DISCRIMINATE_OPTIONS = 5;\n\n/**\n * Values that switch correctly under `===` (excludes `undefined` and `NaN`).\n *\n * Also excludes a SYMBOL — now that `LiteralIR.values` admits one, this is the\n * guard that keeps it out. A symbol discriminant has no source form, so there\n * is no `case` label to emit for it (`literalToJs` refuses it by type), and the\n * ordinal-table variant is string-keyed besides. Detection bails to the\n * `||`-chain, where the option's own literal check does the right thing by\n * reading the value list off the retained schema.\n */\nfunction isSwitchableDiscriminant(v: LiteralValue): v is string | number | boolean | bigint | null {\n return (\n v === null ||\n typeof v === \"string\" ||\n typeof v === \"boolean\" ||\n typeof v === \"bigint\" ||\n (typeof v === \"number\" && !Number.isNaN(v))\n );\n}\n\n/**\n * Detect whether a plain (untagged) `z.union` is *structurally* a discriminated\n * union, so its fast path can use O(1) switch dispatch instead of probing every\n * arm. Returns the discriminator + dispatch table, or null to keep the\n * `||`-chain.\n *\n * Requires (proving the switch accepts exactly what the `||`-chain would): every\n * option is a plain object that pins one shared key to a REQUIRED literal\n * (`prop.type === \"literal\"` — an optional/non-literal key is rejected), and the\n * literal values are pairwise DISJOINT across options. Disjointness is the crux:\n * it guarantees at most one option can accept any given input, so dispatching to\n * that single option is equivalent to trying them all. Any value shared by two\n * options (ambiguous), a non-switchable value (`undefined`/`NaN`), or a\n * non-object option makes detection bail to the safe `||`-chain.\n *\n * Fast-path only: the slow path keeps `z.union`'s sequential trial and its\n * `invalid_union` error shape, so failure output stays byte-identical to Zod.\n */\nexport function detectUnionDiscriminator(\n options: readonly SchemaIR[],\n): { discriminator: string; cases: DiscriminatorCase[] } | null {\n if (options.length < MIN_AUTO_DISCRIMINATE_OPTIONS) return null;\n const objects: ObjectIR[] = [];\n for (const option of options) {\n if (option.type !== \"object\") return null;\n objects.push(option);\n }\n const first = objects[0];\n if (first === undefined) return null; // unreachable (length checked above)\n\n // Only keys present in the first option can be shared by all; try each.\n candidate: for (const key of Object.keys(first.properties)) {\n const seen = new Set<string | number | boolean | bigint | null>();\n const cases: DiscriminatorCase[] = [];\n for (const [i, object] of objects.entries()) {\n const prop = object.properties[key];\n if (prop === undefined || prop.type !== \"literal\") continue candidate;\n for (const value of prop.values) {\n if (!isSwitchableDiscriminant(value)) continue candidate;\n if (seen.has(value)) continue candidate; // shared value → ambiguous dispatch\n seen.add(value);\n cases.push({ value, option: i });\n }\n }\n return { discriminator: key, cases };\n }\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"discriminated-union.js","names":[],"sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"sourcesContent":["import type { DiscriminatedUnionIR, LiteralValue, ObjectIR, SchemaIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport {\n declareFastTemps,\n escapeString,\n extendPath,\n hasMutation,\n literalToJs,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType } from \"../emit-issue.js\";\n\n/** One `discriminator value → option index` dispatch entry. */\ntype DiscriminatorCase = DiscriminatedUnionIR[\"cases\"][number];\n\nexport function slowDiscriminatedUnion(\n ir: SchemaIR & { type: \"discriminatedUnion\" },\n g: SlowGen,\n): string {\n const discKey = escapeString(ir.discriminator);\n\n let code = emit`\n if(typeof ${g.input}!==\"object\"||${g.input}===null||Array.isArray(${g.input})){\n ${invalidType(g, \"object\", { codeFirst: true })}\n }else{`;\n\n const objVar = g.temp(\"du\");\n code += `var ${objVar}=${g.input};switch(${objVar}[${discKey}]){`;\n\n for (const { value, option: index } of ir.cases) {\n const option = ir.options[index] as SchemaIR;\n code += emit`\n case ${literalToJs(value)}:\n ${g.visit(option, { input: objVar, output: objVar })}\n break;`;\n }\n\n const msgProp = g.typeMsg === undefined ? \"\" : `,message:${JSON.stringify(g.typeMsg)}`;\n // Field for field what $ZodDiscriminatedUnion pushes when no option matches:\n // `{ code, errors: [], note: \"No matching discriminator\", discriminator,\n // options, input, path: [def.discriminator] }`. `options` is\n // `Array.from(disc.value.keys())` — every dispatch value in map insertion\n // order, which is exactly `ir.cases` (option order, then each option's\n // `propValues[discriminator]` in ITS order, so an omittable discriminator\n // lists `undefined` right after its own values). The locale reads the list\n // for \"Invalid discriminator value. Expected 'a' | 'b'\". A fresh array\n // literal per push, as zod allocates one, so consumers never share or\n // mutate a hoisted table.\n const optionsList = ir.cases.map(({ value }) => literalToJs(value)).join(\",\");\n code += emit`\n default:\n ${g.issues}.push({code:\"invalid_union\",errors:[],note:\"No matching discriminator\",discriminator:${discKey},options:[${optionsList}],input:${g.input},path:${extendPath(g.path, discKey)}${msgProp}});\n }`;\n // Propagate option-applied mutations (defaults, coercions, transforms,\n // overwrite checks, stringbool) back to the output location. Each option is\n // visited with output:objVar — a fresh local — so a mutating option's clone is\n // reassigned into objVar and stranded there; without this write-back the caller\n // returns the ORIGINAL input by reference and the mutation is silently lost.\n // Gated on mutation so a pure-validation union stays a zero-write pass-through\n // (objVar still aliases the input). On the no-match/failure paths objVar equals\n // the input, so the write is a harmless self-assignment.\n if (ir.options.some(hasMutation)) {\n code += `${g.output}=${objVar};`;\n }\n code += `}`;\n return `${code}\\n`;\n}\n\n/**\n * Emit an O(1) switch-dispatch fast-check for a discriminated union — real\n * (`z.discriminatedUnion`) or one detected inside a plain `z.union`\n * (see {@link detectUnionDiscriminator}). Both share this so the detected case\n * inherits the size-gating and the per-case guard strip.\n *\n * `discSkipKey` tells each object option to drop its own type-guard and\n * discriminator re-check: the caller's guard (`typeof x===\"object\"&&…` below)\n * already proved object-ness, and the matched switch case has fixed the\n * discriminator value, so re-emitting either is pure redundancy the optimizer\n * only removes when it inlines this helper — which a union large enough to\n * matter won't. Routed through the normal `visit` so size-gated extraction\n * still bounds the switch (the strip survives into any hoisted helper);\n * non-object options ignore the hint and keep their own guard.\n *\n * Returns null if any option is fast-path-ineligible.\n */\nexport function emitFastDiscriminatedSwitch(\n g: FastGen,\n discriminator: string,\n cases: readonly DiscriminatorCase[],\n options: readonly SchemaIR[],\n): string | null {\n const x = g.input;\n const discKey = escapeString(discriminator);\n const helperName = g.temp(\"du\");\n const helperParam = g.temp(\"dx\");\n\n // The switch body is its own function: size-gate the options against the cap\n // in a fresh scope, otherwise many small options accumulate into the caller's\n // scope while this helper itself grows unbounded past the TurboFan budget.\n //\n // The switch is over the literal labels themselves. An earlier revision\n // routed three or more string labels through a `{value: ordinal}` table and\n // switched on the ordinal, on the theory that V8 compiles a string switch as\n // sequential comparisons and a dense integer one as a jump table. Measured on\n // V8 13.x (node 24) that is a loss at every size: the table's `t[v]` is a\n // keyed load whose key varies per parse, which goes megamorphic the moment\n // the input rotates through the options, while the string switch stays\n // nearly flat (8.6 ns at 8 cases, 10.1 at 32, 17.3 at 80, rotating input)\n // against the table's 12.9, 15.8 and 20.8. The build path switches the same\n // way (see `buildDispatch`).\n const body = g.scoped(helperParam);\n const caseStrs: string[] = [];\n for (const { value, option: index } of cases) {\n const check = body.visit(options[index] as SchemaIR, { discSkipKey: discriminator });\n if (check === null) return null;\n caseStrs.push(`case ${literalToJs(value)}:return ${check};`);\n }\n g.ctx.preamble.push(\n `function ${helperName}(${helperParam}){${declareFastTemps(body.scope)}switch(${helperParam}[${discKey}]){${caseStrs.join(\"\")}default:return false;}}`,\n );\n\n return `typeof ${x}===\"object\"&&${x}!==null&&!Array.isArray(${x})&&${helperName}(${x})`;\n}\n\nexport function fastDiscriminatedUnion(ir: DiscriminatedUnionIR, g: FastGen): string | null {\n return emitFastDiscriminatedSwitch(g, ir.discriminator, ir.cases, ir.options);\n}\n\n/**\n * Minimum option count for rewriting a plain `z.union` to switch dispatch. Below\n * this the switch helper's fixed call overhead loses to a fully-inlined\n * `||`-chain that V8 keeps flat: measured crossover is ~4 options (n=3 can hit\n * 0.6x — a regression — while n=5 is 1.27x and n=32 is 2.34x), so 5 captures the\n * stable wins with margin and never regresses a small union. Real\n * `z.discriminatedUnion` is unaffected — it dispatches via switch by construction\n * regardless of size.\n */\nconst MIN_AUTO_DISCRIMINATE_OPTIONS = 5;\n\n/**\n * Values that switch correctly under `===` (excludes `undefined` and `NaN`).\n *\n * Also excludes a SYMBOL — now that `LiteralIR.values` admits one, this is the\n * guard that keeps it out. A symbol discriminant has no source form, so there\n * is no `case` label to emit for it (`literalToJs` refuses it by type), and the\n * ordinal-table variant is string-keyed besides. Detection bails to the\n * `||`-chain, where the option's own literal check does the right thing by\n * reading the value list off the retained schema.\n */\nfunction isSwitchableDiscriminant(v: LiteralValue): v is string | number | boolean | bigint | null {\n return (\n v === null ||\n typeof v === \"string\" ||\n typeof v === \"boolean\" ||\n typeof v === \"bigint\" ||\n (typeof v === \"number\" && !Number.isNaN(v))\n );\n}\n\n/**\n * Detect whether a plain (untagged) `z.union` is *structurally* a discriminated\n * union, so its fast path can use O(1) switch dispatch instead of probing every\n * arm. Returns the discriminator + dispatch table, or null to keep the\n * `||`-chain.\n *\n * Requires (proving the switch accepts exactly what the `||`-chain would): every\n * option is a plain object that pins one shared key to a REQUIRED literal\n * (`prop.type === \"literal\"` — an optional/non-literal key is rejected), and the\n * literal values are pairwise DISJOINT across options. Disjointness is the crux:\n * it guarantees at most one option can accept any given input, so dispatching to\n * that single option is equivalent to trying them all. Any value shared by two\n * options (ambiguous), a non-switchable value (`undefined`/`NaN`), or a\n * non-object option makes detection bail to the safe `||`-chain.\n *\n * The slow path is untouched: it keeps `z.union`'s sequential trial and its\n * `invalid_union` error shape, so failure output stays byte-identical to Zod.\n * The fast path and the build path both dispatch on the result — the build\n * path from two options up (`minOptions`), since its options are hosted calls\n * either way and a switch only ever replaces probes with one call; see\n * `buildUnion`.\n */\nexport function detectUnionDiscriminator(\n options: readonly SchemaIR[],\n minOptions: number = MIN_AUTO_DISCRIMINATE_OPTIONS,\n): { discriminator: string; cases: DiscriminatorCase[] } | null {\n if (options.length < minOptions) return null;\n const objects: ObjectIR[] = [];\n for (const option of options) {\n if (option.type !== \"object\") return null;\n objects.push(option);\n }\n const first = objects[0];\n if (first === undefined) return null; // unreachable (length checked above)\n\n // Only keys present in the first option can be shared by all; try each.\n candidate: for (const key of Object.keys(first.properties)) {\n const seen = new Set<string | number | boolean | bigint | null>();\n const cases: DiscriminatorCase[] = [];\n for (const [i, object] of objects.entries()) {\n const prop = object.properties[key];\n if (prop === undefined || prop.type !== \"literal\") continue candidate;\n for (const value of prop.values) {\n if (!isSwitchableDiscriminant(value)) continue candidate;\n if (seen.has(value)) continue candidate; // shared value → ambiguous dispatch\n seen.add(value);\n cases.push({ value, option: i });\n }\n }\n return { discriminator: key, cases };\n }\n return null;\n}\n"],"mappings":";;;;AAeA,SAAgB,uBACd,IACA,GACQ;CACR,MAAM,UAAU,aAAa,GAAG,aAAa;CAE7C,IAAI,OAAO,IAAI;gBACD,EAAE,MAAM,eAAe,EAAE,MAAM,yBAAyB,EAAE,MAAM;QACxE,YAAY,GAAG,UAAU,EAAE,WAAW,KAAK,CAAC,EAAE;;CAGpD,MAAM,SAAS,EAAE,KAAK,IAAI;CAC1B,QAAQ,OAAO,OAAO,GAAG,EAAE,MAAM,UAAU,OAAO,GAAG,QAAQ;CAE7D,KAAK,MAAM,EAAE,OAAO,QAAQ,WAAW,GAAG,OAAO;EAC/C,MAAM,SAAS,GAAG,QAAQ;EAC1B,QAAQ,IAAI;aACH,YAAY,KAAK,EAAE;UACtB,EAAE,MAAM,QAAQ;GAAE,OAAO;GAAQ,QAAQ;EAAO,CAAC,EAAE;;CAE3D;CAEA,MAAM,UAAU,EAAE,YAAY,KAAA,IAAY,KAAK,YAAY,KAAK,UAAU,EAAE,OAAO;CAWnF,MAAM,cAAc,GAAG,MAAM,KAAK,EAAE,YAAY,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG;CAC5E,QAAQ,IAAI;;QAEN,EAAE,OAAO,uFAAuF,QAAQ,YAAY,YAAY,UAAU,EAAE,MAAM,QAAQ,WAAW,EAAE,MAAM,OAAO,IAAI,QAAQ;;CAUtM,IAAI,GAAG,QAAQ,KAAK,WAAW,GAC7B,QAAQ,GAAG,EAAE,OAAO,GAAG,OAAO;CAEhC,QAAQ;CACR,OAAO,GAAG,KAAK;AACjB;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,4BACd,GACA,eACA,OACA,SACe;CACf,MAAM,IAAI,EAAE;CACZ,MAAM,UAAU,aAAa,aAAa;CAC1C,MAAM,aAAa,EAAE,KAAK,IAAI;CAC9B,MAAM,cAAc,EAAE,KAAK,IAAI;CAgB/B,MAAM,OAAO,EAAE,OAAO,WAAW;CACjC,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,EAAE,OAAO,QAAQ,WAAW,OAAO;EAC5C,MAAM,QAAQ,KAAK,MAAM,QAAQ,QAAoB,EAAE,aAAa,cAAc,CAAC;EACnF,IAAI,UAAU,MAAM,OAAO;EAC3B,SAAS,KAAK,QAAQ,YAAY,KAAK,EAAE,UAAU,MAAM,EAAE;CAC7D;CACA,EAAE,IAAI,SAAS,KACb,YAAY,WAAW,GAAG,YAAY,IAAI,iBAAiB,KAAK,KAAK,EAAE,SAAS,YAAY,GAAG,QAAQ,KAAK,SAAS,KAAK,EAAE,EAAE,wBAChI;CAEA,OAAO,UAAU,EAAE,eAAe,EAAE,0BAA0B,EAAE,KAAK,WAAW,GAAG,EAAE;AACvF;AAEA,SAAgB,uBAAuB,IAA0B,GAA2B;CAC1F,OAAO,4BAA4B,GAAG,GAAG,eAAe,GAAG,OAAO,GAAG,OAAO;AAC9E;;;;;;;;;;AAWA,MAAM,gCAAgC;;;;;;;;;;;AAYtC,SAAS,yBAAyB,GAAiE;CACjG,OACE,MAAM,QACN,OAAO,MAAM,YACb,OAAO,MAAM,aACb,OAAO,MAAM,YACZ,OAAO,MAAM,YAAY,CAAC,OAAO,MAAM,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,yBACd,SACA,aAAqB,+BACyC;CAC9D,IAAI,QAAQ,SAAS,YAAY,OAAO;CACxC,MAAM,UAAsB,CAAC;CAC7B,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,OAAO,SAAS,UAAU,OAAO;EACrC,QAAQ,KAAK,MAAM;CACrB;CACA,MAAM,QAAQ,QAAQ;CACtB,IAAI,UAAU,KAAA,GAAW,OAAO;CAGhC,WAAW,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,UAAU,GAAG;EAC1D,MAAM,uBAAO,IAAI,IAA+C;EAChE,MAAM,QAA6B,CAAC;EACpC,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GAAG;GAC3C,MAAM,OAAO,OAAO,WAAW;GAC/B,IAAI,SAAS,KAAA,KAAa,KAAK,SAAS,WAAW,SAAS;GAC5D,KAAK,MAAM,SAAS,KAAK,QAAQ;IAC/B,IAAI,CAAC,yBAAyB,KAAK,GAAG,SAAS;IAC/C,IAAI,KAAK,IAAI,KAAK,GAAG,SAAS;IAC9B,KAAK,IAAI,KAAK;IACd,MAAM,KAAK;KAAE;KAAO,QAAQ;IAAE,CAAC;GACjC;EACF;EACA,OAAO;GAAE,eAAe;GAAK;EAAM;CACrC;CACA,OAAO;AACT"}
@@ -3,8 +3,19 @@ import { CodeGenContext, SlowGen } from "../context.js";
3
3
  //#region src/core/codegen/schemas/string-bool.d.ts
4
4
  declare function slowStringBool(ir: StringBoolIR, g: SlowGen): string;
5
5
  declare function stringBoolUsesInline(ir: StringBoolIR): boolean;
6
+ /**
7
+ * Boolean expression: is `input` verbatim one of an INLINE codec's spellings?
8
+ *
9
+ * The accepted lists come from probing the schema with lowercase candidates
10
+ * (see extractStringBool), so for a case-insensitive codec an exact hit is
11
+ * exactly what `input.toLowerCase()` would have produced — and a handful of
12
+ * `===` on internalized strings is cheaper than the `toLowerCase()` call. The
13
+ * hashed form has no use for this: there the verbatim `Map.get` IS the lookup,
14
+ * retried on the lowercased string only when it misses.
15
+ */
16
+ declare function stringBoolInlineHit(ir: StringBoolIR, input: string): string;
6
17
  /** One lookup distinguishes true, false and absent; shared by hot and issue walks. */
7
18
  declare function emitStringBoolMap(ir: StringBoolIR, ctx: CodeGenContext): string;
8
19
  //#endregion
9
- export { emitStringBoolMap, slowStringBool, stringBoolUsesInline };
20
+ export { emitStringBoolMap, slowStringBool, stringBoolInlineHit, stringBoolUsesInline };
10
21
  //# sourceMappingURL=string-bool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"string-bool.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/string-bool.ts"],"mappings":";;;iBAMgB,eAAe,IAAI,cAAc,GAAG;iBA+CpC,qBAAqB,IAAI;;iBAKzB,kBAAkB,IAAI,cAAc,KAAK"}
1
+ {"version":3,"file":"string-bool.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/string-bool.ts"],"mappings":";;;iBAMgB,eAAe,IAAI,cAAc,GAAG;iBAyDpC,qBAAqB,IAAI;;;;;;;;;;;iBAczB,oBAAoB,IAAI,cAAc;;iBAKtC,kBAAkB,IAAI,cAAc,KAAK"}
@@ -9,12 +9,12 @@ function slowStringBool(ir, g) {
9
9
  ${invalidType(g, "string")}
10
10
  }else{
11
11
  `;
12
- const normalized = ir.caseSensitive ? g.input : g.temp("sbn");
13
- if (!ir.caseSensitive) code += `var ${normalized}=${g.input}.toLowerCase();`;
14
12
  const allValues = [...ir.truthy, ...ir.falsy];
15
13
  const valuesExpr = JSON.stringify(allValues);
16
14
  const expectedExtra = "expected:\"stringbool\"";
17
15
  if (stringBoolUsesInline(ir)) {
16
+ const normalized = ir.caseSensitive ? g.input : g.temp("sbn");
17
+ if (!ir.caseSensitive) code += `var ${normalized}=${stringBoolInlineHit(ir, g.input)}?${g.input}:${g.input}.toLowerCase();`;
18
18
  const truthyCondition = ir.truthy.map((v) => `${normalized}===${escapeString(v)}`).join("||");
19
19
  const falsyCondition = ir.falsy.map((v) => `${normalized}===${escapeString(v)}`).join("||");
20
20
  code += emit`
@@ -25,8 +25,10 @@ function slowStringBool(ir, g) {
25
25
  } else {
26
26
  const value = g.temp("sbv");
27
27
  const lookup = emitStringBoolMap(ir, g.ctx);
28
+ const lowered = g.temp("sbn");
29
+ const retry = ir.caseSensitive ? "" : `if(${value}===undefined){var ${lowered}=${g.input}.toLowerCase();if(${lowered}!==${g.input}){${value}=${lookup}.get(${lowered});}}`;
28
30
  code += emit`
29
- var ${value}=${lookup}.get(${normalized});
31
+ var ${value}=${lookup}.get(${g.input});${retry}
30
32
  if(${value}===undefined){${invalidValue(g, valuesExpr, { extra: expectedExtra })}}
31
33
  else{${g.output}=${value};}
32
34
  `;
@@ -37,12 +39,25 @@ function slowStringBool(ir, g) {
37
39
  function stringBoolUsesInline(ir) {
38
40
  return ir.truthy.length <= 5 && ir.falsy.length <= 5;
39
41
  }
42
+ /**
43
+ * Boolean expression: is `input` verbatim one of an INLINE codec's spellings?
44
+ *
45
+ * The accepted lists come from probing the schema with lowercase candidates
46
+ * (see extractStringBool), so for a case-insensitive codec an exact hit is
47
+ * exactly what `input.toLowerCase()` would have produced — and a handful of
48
+ * `===` on internalized strings is cheaper than the `toLowerCase()` call. The
49
+ * hashed form has no use for this: there the verbatim `Map.get` IS the lookup,
50
+ * retried on the lowercased string only when it misses.
51
+ */
52
+ function stringBoolInlineHit(ir, input) {
53
+ return [...ir.truthy, ...ir.falsy].map((v) => `${input}===${escapeString(v)}`).join("||");
54
+ }
40
55
  /** One lookup distinguishes true, false and absent; shared by hot and issue walks. */
41
56
  function emitStringBoolMap(ir, ctx) {
42
57
  const pairs = [...ir.truthy.map((value) => [value, true]), ...ir.falsy.map((value) => [value, false])];
43
58
  return emitConstant(ctx, "map_sb", `new Map(${JSON.stringify(pairs)})`);
44
59
  }
45
60
  //#endregion
46
- export { emitStringBoolMap, slowStringBool, stringBoolUsesInline };
61
+ export { emitStringBoolMap, slowStringBool, stringBoolInlineHit, stringBoolUsesInline };
47
62
 
48
63
  //# sourceMappingURL=string-bool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"string-bool.js","names":[],"sources":["../../../../src/core/codegen/schemas/string-bool.ts"],"sourcesContent":["import type { StringBoolIR } from \"../../types.js\";\nimport type { CodeGenContext, SlowGen } from \"../context.js\";\nimport { ENUM_INLINE_THRESHOLD, emitConstant, escapeString } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, invalidValue } from \"../emit-issue.js\";\n\nexport function slowStringBool(ir: StringBoolIR, g: SlowGen): string {\n let code = \"\";\n\n // Type check: input must be a string\n code += emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n }else{\n `;\n\n // Normalize input for case-insensitive matching\n const normalized = ir.caseSensitive ? g.input : g.temp(\"sbn\");\n if (!ir.caseSensitive) code += `var ${normalized}=${g.input}.toLowerCase();`;\n const allValues = [...ir.truthy, ...ir.falsy];\n const valuesExpr = JSON.stringify(allValues);\n // z.stringbool() is a Codec whose transform pushes\n // `{ code: \"invalid_value\", expected: \"stringbool\", values: [...] }` — the\n // only invalid_value producer that carries an `expected` (enum and literal\n // push `values` alone), and zod's locale keys off it. Both emitted lookups\n // below share this so the two code paths cannot drift apart.\n const expectedExtra = 'expected:\"stringbool\"';\n\n // Compare per-side counts against threshold (not the combined total)\n const useInline = stringBoolUsesInline(ir);\n\n if (useInline) {\n const truthyCondition = ir.truthy.map((v) => `${normalized}===${escapeString(v)}`).join(\"||\");\n const falsyCondition = ir.falsy.map((v) => `${normalized}===${escapeString(v)}`).join(\"||\");\n code += emit`\n if(${truthyCondition}){${g.output}=true;}\n else if(${falsyCondition}){${g.output}=false;}\n else{${invalidValue(g, valuesExpr, { extra: expectedExtra })}}\n `;\n } else {\n const value = g.temp(\"sbv\");\n const lookup = emitStringBoolMap(ir, g.ctx);\n code += emit`\n var ${value}=${lookup}.get(${normalized});\n if(${value}===undefined){${invalidValue(g, valuesExpr, { extra: expectedExtra })}}\n else{${g.output}=${value};}\n `;\n }\n\n code += emit`}`;\n return `${code}\\n`;\n}\n\nexport function stringBoolUsesInline(ir: StringBoolIR): boolean {\n return ir.truthy.length <= ENUM_INLINE_THRESHOLD && ir.falsy.length <= ENUM_INLINE_THRESHOLD;\n}\n\n/** One lookup distinguishes true, false and absent; shared by hot and issue walks. */\nexport function emitStringBoolMap(ir: StringBoolIR, ctx: CodeGenContext): string {\n const pairs = [\n ...ir.truthy.map((value) => [value, true]),\n ...ir.falsy.map((value) => [value, false]),\n ];\n return emitConstant(ctx, \"map_sb\", `new Map(${JSON.stringify(pairs)})`);\n}\n"],"mappings":";;;;AAMA,SAAgB,eAAe,IAAkB,GAAoB;CACnE,IAAI,OAAO;CAGX,QAAQ,IAAI;gBACE,EAAE,MAAM;QAChB,YAAY,GAAG,QAAQ,EAAE;;;CAK/B,MAAM,aAAa,GAAG,gBAAgB,EAAE,QAAQ,EAAE,KAAK,KAAK;CAC5D,IAAI,CAAC,GAAG,eAAe,QAAQ,OAAO,WAAW,GAAG,EAAE,MAAM;CAC5D,MAAM,YAAY,CAAC,GAAG,GAAG,QAAQ,GAAG,GAAG,KAAK;CAC5C,MAAM,aAAa,KAAK,UAAU,SAAS;CAM3C,MAAM,gBAAgB;CAKtB,IAFkB,qBAAqB,EAE3B,GAAG;EACb,MAAM,kBAAkB,GAAG,OAAO,KAAK,MAAM,GAAG,WAAW,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;EAC5F,MAAM,iBAAiB,GAAG,MAAM,KAAK,MAAM,GAAG,WAAW,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;EAC1F,QAAQ,IAAI;WACL,gBAAgB,IAAI,EAAE,OAAO;gBACxB,eAAe,IAAI,EAAE,OAAO;aAC/B,aAAa,GAAG,YAAY,EAAE,OAAO,cAAc,CAAC,EAAE;;CAEjE,OAAO;EACL,MAAM,QAAQ,EAAE,KAAK,KAAK;EAC1B,MAAM,SAAS,kBAAkB,IAAI,EAAE,GAAG;EAC1C,QAAQ,IAAI;YACJ,MAAM,GAAG,OAAO,OAAO,WAAW;WACnC,MAAM,gBAAgB,aAAa,GAAG,YAAY,EAAE,OAAO,cAAc,CAAC,EAAE;aAC1E,EAAE,OAAO,GAAG,MAAM;;CAE7B;CAEA,QAAQ,IAAI;CACZ,OAAO,GAAG,KAAK;AACjB;AAEA,SAAgB,qBAAqB,IAA2B;CAC9D,OAAO,GAAG,OAAO,UAAA,KAAmC,GAAG,MAAM,UAAA;AAC/D;;AAGA,SAAgB,kBAAkB,IAAkB,KAA6B;CAC/E,MAAM,QAAQ,CACZ,GAAG,GAAG,OAAO,KAAK,UAAU,CAAC,OAAO,IAAI,CAAC,GACzC,GAAG,GAAG,MAAM,KAAK,UAAU,CAAC,OAAO,KAAK,CAAC,CAC3C;CACA,OAAO,aAAa,KAAK,UAAU,WAAW,KAAK,UAAU,KAAK,EAAE,EAAE;AACxE"}
1
+ {"version":3,"file":"string-bool.js","names":[],"sources":["../../../../src/core/codegen/schemas/string-bool.ts"],"sourcesContent":["import type { StringBoolIR } from \"../../types.js\";\nimport type { CodeGenContext, SlowGen } from \"../context.js\";\nimport { ENUM_INLINE_THRESHOLD, emitConstant, escapeString } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, invalidValue } from \"../emit-issue.js\";\n\nexport function slowStringBool(ir: StringBoolIR, g: SlowGen): string {\n let code = \"\";\n\n // Type check: input must be a string\n code += emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n }else{\n `;\n\n const allValues = [...ir.truthy, ...ir.falsy];\n const valuesExpr = JSON.stringify(allValues);\n // z.stringbool() is a Codec whose transform pushes\n // `{ code: \"invalid_value\", expected: \"stringbool\", values: [...] }` — the\n // only invalid_value producer that carries an `expected` (enum and literal\n // push `values` alone), and zod's locale keys off it. Both emitted lookups\n // below share this so the two code paths cannot drift apart.\n const expectedExtra = 'expected:\"stringbool\"';\n\n // Compare per-side counts against threshold (not the combined total)\n const useInline = stringBoolUsesInline(ir);\n\n // Case-insensitive matching tries the input VERBATIM before lowercasing it:\n // the accepted spellings are all lowercase, so an exact hit and the\n // lowercased hit are the same string. See buildStringBool for the measured\n // trade; this is the same shape on the eager walk.\n if (useInline) {\n const normalized = ir.caseSensitive ? g.input : g.temp(\"sbn\");\n if (!ir.caseSensitive) {\n code += `var ${normalized}=${stringBoolInlineHit(ir, g.input)}?${g.input}:${g.input}.toLowerCase();`;\n }\n const truthyCondition = ir.truthy.map((v) => `${normalized}===${escapeString(v)}`).join(\"||\");\n const falsyCondition = ir.falsy.map((v) => `${normalized}===${escapeString(v)}`).join(\"||\");\n code += emit`\n if(${truthyCondition}){${g.output}=true;}\n else if(${falsyCondition}){${g.output}=false;}\n else{${invalidValue(g, valuesExpr, { extra: expectedExtra })}}\n `;\n } else {\n const value = g.temp(\"sbv\");\n const lookup = emitStringBoolMap(ir, g.ctx);\n const lowered = g.temp(\"sbn\");\n const retry = ir.caseSensitive\n ? \"\"\n : `if(${value}===undefined){var ${lowered}=${g.input}.toLowerCase();` +\n `if(${lowered}!==${g.input}){${value}=${lookup}.get(${lowered});}}`;\n code += emit`\n var ${value}=${lookup}.get(${g.input});${retry}\n if(${value}===undefined){${invalidValue(g, valuesExpr, { extra: expectedExtra })}}\n else{${g.output}=${value};}\n `;\n }\n\n code += emit`}`;\n return `${code}\\n`;\n}\n\nexport function stringBoolUsesInline(ir: StringBoolIR): boolean {\n return ir.truthy.length <= ENUM_INLINE_THRESHOLD && ir.falsy.length <= ENUM_INLINE_THRESHOLD;\n}\n\n/**\n * Boolean expression: is `input` verbatim one of an INLINE codec's spellings?\n *\n * The accepted lists come from probing the schema with lowercase candidates\n * (see extractStringBool), so for a case-insensitive codec an exact hit is\n * exactly what `input.toLowerCase()` would have produced — and a handful of\n * `===` on internalized strings is cheaper than the `toLowerCase()` call. The\n * hashed form has no use for this: there the verbatim `Map.get` IS the lookup,\n * retried on the lowercased string only when it misses.\n */\nexport function stringBoolInlineHit(ir: StringBoolIR, input: string): string {\n return [...ir.truthy, ...ir.falsy].map((v) => `${input}===${escapeString(v)}`).join(\"||\");\n}\n\n/** One lookup distinguishes true, false and absent; shared by hot and issue walks. */\nexport function emitStringBoolMap(ir: StringBoolIR, ctx: CodeGenContext): string {\n const pairs = [\n ...ir.truthy.map((value) => [value, true]),\n ...ir.falsy.map((value) => [value, false]),\n ];\n return emitConstant(ctx, \"map_sb\", `new Map(${JSON.stringify(pairs)})`);\n}\n"],"mappings":";;;;AAMA,SAAgB,eAAe,IAAkB,GAAoB;CACnE,IAAI,OAAO;CAGX,QAAQ,IAAI;gBACE,EAAE,MAAM;QAChB,YAAY,GAAG,QAAQ,EAAE;;;CAI/B,MAAM,YAAY,CAAC,GAAG,GAAG,QAAQ,GAAG,GAAG,KAAK;CAC5C,MAAM,aAAa,KAAK,UAAU,SAAS;CAM3C,MAAM,gBAAgB;CAStB,IANkB,qBAAqB,EAM3B,GAAG;EACb,MAAM,aAAa,GAAG,gBAAgB,EAAE,QAAQ,EAAE,KAAK,KAAK;EAC5D,IAAI,CAAC,GAAG,eACN,QAAQ,OAAO,WAAW,GAAG,oBAAoB,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM;EAEtF,MAAM,kBAAkB,GAAG,OAAO,KAAK,MAAM,GAAG,WAAW,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;EAC5F,MAAM,iBAAiB,GAAG,MAAM,KAAK,MAAM,GAAG,WAAW,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;EAC1F,QAAQ,IAAI;WACL,gBAAgB,IAAI,EAAE,OAAO;gBACxB,eAAe,IAAI,EAAE,OAAO;aAC/B,aAAa,GAAG,YAAY,EAAE,OAAO,cAAc,CAAC,EAAE;;CAEjE,OAAO;EACL,MAAM,QAAQ,EAAE,KAAK,KAAK;EAC1B,MAAM,SAAS,kBAAkB,IAAI,EAAE,GAAG;EAC1C,MAAM,UAAU,EAAE,KAAK,KAAK;EAC5B,MAAM,QAAQ,GAAG,gBACb,KACA,MAAM,MAAM,oBAAoB,QAAQ,GAAG,EAAE,MAAM,oBAC7C,QAAQ,KAAK,EAAE,MAAM,IAAI,MAAM,GAAG,OAAO,OAAO,QAAQ;EAClE,QAAQ,IAAI;YACJ,MAAM,GAAG,OAAO,OAAO,EAAE,MAAM,IAAI,MAAM;WAC1C,MAAM,gBAAgB,aAAa,GAAG,YAAY,EAAE,OAAO,cAAc,CAAC,EAAE;aAC1E,EAAE,OAAO,GAAG,MAAM;;CAE7B;CAEA,QAAQ,IAAI;CACZ,OAAO,GAAG,KAAK;AACjB;AAEA,SAAgB,qBAAqB,IAA2B;CAC9D,OAAO,GAAG,OAAO,UAAA,KAAmC,GAAG,MAAM,UAAA;AAC/D;;;;;;;;;;;AAYA,SAAgB,oBAAoB,IAAkB,OAAuB;CAC3E,OAAO,CAAC,GAAG,GAAG,QAAQ,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,MAAM,GAAG,MAAM,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;AAC1F;;AAGA,SAAgB,kBAAkB,IAAkB,KAA6B;CAC/E,MAAM,QAAQ,CACZ,GAAG,GAAG,OAAO,KAAK,UAAU,CAAC,OAAO,IAAI,CAAC,GACzC,GAAG,GAAG,MAAM,KAAK,UAAU,CAAC,OAAO,KAAK,CAAC,CAC3C;CACA,OAAO,aAAa,KAAK,UAAU,WAAW,KAAK,UAAU,KAAK,EAAE,EAAE;AACxE"}
@@ -1 +1 @@
1
- {"version":3,"file":"string.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/string.ts"],"mappings":";;;iBAoGgB,WAAW,IAAI,UAAU,GAAG;;;;;;;;;;;iBAwJ5B,gBAAgB,OAAO,SAAS,WAAW,KAAK;iBAkDhD,WAAW,IAAI,UAAU,GAAG"}
1
+ {"version":3,"file":"string.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/string.ts"],"mappings":";;;iBA2GgB,WAAW,IAAI,UAAU,GAAG;;;;;;;;;;;iBAmK5B,gBAAgB,OAAO,SAAS,WAAW,KAAK;iBAuDhD,WAAW,IAAI,UAAU,GAAG"}
@@ -1,7 +1,8 @@
1
- import { EMAIL_REGEX_SOURCE, fastTestSource } from "../well-known-regex.js";
2
- import { checkPriority, emitEffectCallable, emitEffectFn, emitRegex, emitRegexSourceString, escapeString } from "../context.js";
1
+ import { EMAIL_REGEX_SOURCE, fastTestSource, isDefaultEmailPattern } from "../well-known-regex.js";
2
+ import { checkPriority, emitEffectCallable, emitEffectFn, emitRegex, emitRegexSourceString, emitRuntimeHelper, escapeString } from "../context.js";
3
3
  import { emit } from "../emit.js";
4
4
  import { invalidFormat, invalidType, tooBig, tooSmall } from "../emit-issue.js";
5
+ import { ZC_EMAIL_DECL } from "../issue-decls.js";
5
6
  import { refineCheck, superRefineCheck, superRefineFastTest } from "./effect.js";
6
7
  import { stringLengthTests, whenGatedSizeChecks } from "./sizeable.js";
7
8
  //#region src/core/codegen/schemas/string.ts
@@ -163,7 +164,7 @@ function slowString(ir, g) {
163
164
  code += emit`${g.output}=${emitEffectFn(g.ctx, check.source)}(${g.input});`;
164
165
  break;
165
166
  case "string_format": {
166
- let regexVar;
167
+ let prefix;
167
168
  let pattern;
168
169
  if (check.format === "url" && !check.pattern) {
169
170
  code += slowUrlCheck(check, g);
@@ -171,22 +172,25 @@ function slowString(ir, g) {
171
172
  }
172
173
  if (check.format === "email") {
173
174
  pattern = check.pattern ?? EMAIL_REGEX_SOURCE;
174
- regexVar = g.regex("email", pattern, check.patternFlags);
175
+ prefix = "email";
175
176
  } else if (check.format === "regex" && check.pattern) {
176
177
  pattern = check.pattern;
177
- regexVar = g.regex("str", pattern, check.patternFlags);
178
+ prefix = "str";
178
179
  } else if (check.format === "uuid") {
179
180
  pattern = check.pattern ?? "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$";
180
- regexVar = g.regex("uuid", pattern, check.patternFlags);
181
+ prefix = "uuid";
181
182
  } else if (check.pattern) {
182
183
  pattern = check.pattern;
183
- regexVar = g.regex("str", pattern, check.patternFlags);
184
+ prefix = "str";
184
185
  } else continue;
186
+ const scanner = isDefaultEmailPattern(pattern, check.patternFlags) ? emitRuntimeHelper(g.ctx, "__zcEmail", ZC_EMAIL_DECL) : null;
187
+ const regexVar = scanner === null ? g.regex(prefix, pattern, check.patternFlags) : null;
185
188
  let extra;
186
- if (!check.bareIssue) extra = `pattern:${!check.patternFlags && fastTestSource(pattern) !== null ? emitRegexSourceString(g.ctx, pattern) : `${regexVar}.toString()`}`;
189
+ if (!check.bareIssue) extra = `pattern:${!check.patternFlags && fastTestSource(pattern) !== null || regexVar === null ? emitRegexSourceString(g.ctx, pattern) : `${regexVar}.toString()`}`;
190
+ const test = regexVar === null ? `${scanner}(${g.input})` : `${regexVar}.test(${g.input})`;
187
191
  code += emit`
188
- ${lastIndexReset(regexVar, check.patternFlags)}
189
- if(!${regexVar}.test(${g.input})){
192
+ ${regexVar === null ? "" : lastIndexReset(regexVar, check.patternFlags)}
193
+ if(!${test}){
190
194
  ${invalidFormat(g, { expr: escapeString(check.format) }, {
191
195
  origin: check.bareIssue ? void 0 : "string",
192
196
  extra,
@@ -232,6 +236,7 @@ function fastStringCheck(check, x, ctx) {
232
236
  prefix = "re";
233
237
  pattern = check.pattern;
234
238
  } else return null;
239
+ if (isDefaultEmailPattern(pattern, check.patternFlags)) return `${emitRuntimeHelper(ctx, "__zcEmail", ZC_EMAIL_DECL)}(${x})`;
235
240
  const v = emitRegex(ctx, prefix, pattern, check.patternFlags);
236
241
  return check.patternFlags && /[gy]/.test(check.patternFlags) ? `((${v}.lastIndex=0),${v}.test(${x}))` : `${v}.test(${x})`;
237
242
  }
@@ -1 +1 @@
1
- {"version":3,"file":"string.js","names":[],"sources":["../../../../src/core/codegen/schemas/string.ts"],"sourcesContent":["import type { CheckIR, CheckStringFormat, StringIR } from \"../../types.js\";\nimport type { CodeGenContext, FastGen, SlowGen } from \"../context.js\";\nimport {\n checkPriority,\n emitEffectCallable,\n emitEffectFn,\n emitRegex,\n emitRegexSourceString,\n escapeString,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidFormat, invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\nimport { EMAIL_REGEX_SOURCE, fastTestSource, UUID_REGEX_SOURCE } from \"../well-known-regex.js\";\nimport { refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\nimport { stringLengthTests, whenGatedSizeChecks } from \"./sizeable.js\";\n\n/** `re.lastIndex=0;` reset statement for stateful (g/y-flagged) regexes. */\nfunction lastIndexReset(regexVar: string, flags: string | undefined): string {\n return flags && /[gy]/.test(flags) ? `${regexVar}.lastIndex=0;` : \"\";\n}\n\n/**\n * `regexes.httpProtocol.source`. `parseURLObject` compares a url check's\n * protocol SOURCE against it — not the schema constructor — so any check whose\n * protocol is spelled this way gets the guard, `z.httpUrl()` or not.\n */\nconst HTTP_PROTOCOL_SOURCE = \"^https?$\";\n\n/**\n * Generate the url check, mirroring $ZodURL semantics:\n * trim → (for an http(s)-protocol check without normalize) require `://` →\n * new URL(trimmed) → optional hostname/protocol regex tests → write back\n * url.href (normalize) or the trimmed input with its tabs and newlines deleted.\n *\n * The `://` guard is `parseURLObject`'s: without it the URL parser accepts\n * `http:example.com`, and its rejection is a distinct issue (`note: \"Invalid\n * URL format\"`, no `pattern`) pushed BEFORE the parser runs. The deletion of\n * `\\t`, `\\n` and `\\r` (`stripTabAndNewline`) matches what the parser itself\n * drops before it reads the host, so the returned value names the host that was\n * validated.\n *\n * $ZodURL is another constructor that OVERRIDES the `??=`-installed default\n * check, so none of the issues below carries `origin` — and the two that do\n * carry a `pattern` use `regex.source`, not the default check's\n * `regex.toString()` (no delimiters, no flags). Both are reproduced verbatim.\n */\nfunction slowUrlCheck(check: CheckStringFormat, g: SlowGen): string {\n const trimmedVar = g.temp(\"ut\");\n const urlVar = g.temp(\"u\");\n let inner = \"\";\n if (check.hostname) {\n const re = g.regex(\"host\", check.hostname, check.hostnameFlags);\n inner += emit`\n ${lastIndexReset(re, check.hostnameFlags)}\n if(!${re}.test(${urlVar}.hostname)){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid hostname\",pattern:${escapeString(check.hostname)}`,\n message: check.message,\n })}\n }`;\n }\n if (check.protocol) {\n const re = g.regex(\"proto\", check.protocol, check.protocolFlags);\n const protoExpr = `(${urlVar}.protocol.endsWith(\":\")?${urlVar}.protocol.slice(0,-1):${urlVar}.protocol)`;\n inner += emit`\n ${lastIndexReset(re, check.protocolFlags)}\n if(!${re}.test(${protoExpr})){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid protocol\",pattern:${escapeString(check.protocol)}`,\n message: check.message,\n })}\n }`;\n }\n // Zod writes the value back even when hostname/protocol issues were pushed.\n const stripped = check.normalize\n ? `${urlVar}.href`\n : `${trimmedVar}.replace(${g.regex(\"tnl\", \"[\\\\t\\\\n\\\\r]\", \"g\")},\"\")`;\n inner += `${g.output}=${stripped};`;\n let parse = emit`\n var ${urlVar}=null;\n try{${urlVar}=new URL(${trimmedVar});}catch(_){}\n if(${urlVar}===null){\n ${invalidFormat(g, \"url\", { message: check.message })}\n }else{\n ${inner}\n }`;\n if (!check.normalize && check.protocol === HTTP_PROTOCOL_SOURCE) {\n const re = g.regex(\"httpUrl\", \"^https?:\\\\/\\\\/\", \"i\");\n parse = emit`\n if(!${re}.test(${trimmedVar})){\n ${invalidFormat(g, \"url\", { extra: `note:\"Invalid URL format\"`, message: check.message })}\n }else{\n ${parse}\n }`;\n }\n return emit`\n var ${trimmedVar}=${g.input}.trim();\n ${parse}`;\n}\n\nexport function slowString(ir: StringIR, g: SlowGen): string {\n let code = \"\";\n if (ir.coerce) {\n code += emit`try{${g.output}=String(${g.input});}catch(_){}`;\n }\n code += emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n ${whenGatedSizeChecks(ir.checks, g, \"length\")}\n }`;\n\n if (ir.checks.length > 0) {\n code += `else{`;\n // Insertion order mirrors zod's issue order for multi-failure inputs;\n // the slow path collects all issues with no short-circuit.\n for (const check of ir.checks) {\n switch (check.kind) {\n // Length is measured in code points where the unit count leaves the\n // verdict in doubt — see stringLengthTests.\n case \"min_length\":\n code += emit`\n if(${stringLengthTests.minFails(g.input, check.minimum, g.ctx)}){\n ${tooSmall(g, check.minimum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"max_length\":\n code += emit`\n if(${stringLengthTests.maxFails(g.input, check.maximum, g.ctx)}){\n ${tooBig(g, check.maximum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"length_equals\": {\n const length = g.temp(\"cl\");\n code += emit`\n var ${length}=${stringLengthTests.measure(g.input, check.length, g.ctx)};\n if(${length}<${check.length}){\n ${tooSmall(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }else if(${length}>${check.length}){\n ${tooBig(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }`;\n break;\n }\n // includes/starts_with/ends_with each carry `origin:\"string\"` but NO\n // `pattern`: $ZodCheckIncludes/StartsWith/EndsWith bypass\n // $ZodCheckStringFormat entirely (they init from $ZodCheck and assign\n // `inst._zod.check` directly), and the pattern they build is registered\n // in the bag for JSON Schema only, never put on the issue.\n case \"includes\":\n code += emit`\n if(!${g.input}.includes(${escapeString(check.includes)}${check.position !== undefined ? `,${check.position}` : \"\"})){\n ${invalidFormat(g, \"includes\", { origin: \"string\", extra: `includes:${escapeString(check.includes)}`, message: check.message })}\n }`;\n break;\n case \"starts_with\":\n code += emit`\n if(!${g.input}.startsWith(${escapeString(check.prefix)})){\n ${invalidFormat(g, \"starts_with\", { origin: \"string\", extra: `prefix:${escapeString(check.prefix)}`, message: check.message })}\n }`;\n break;\n case \"ends_with\":\n code += emit`\n if(!${g.input}.endsWith(${escapeString(check.suffix)})){\n ${invalidFormat(g, \"ends_with\", { origin: \"string\", extra: `suffix:${escapeString(check.suffix)}`, message: check.message })}\n }`;\n break;\n case \"refine_effect\":\n code += refineCheck(check, g.input, g);\n break;\n case \"super_refine_effect\":\n code += superRefineCheck(check, g.input, g);\n break;\n case \"overwrite_effect\":\n // $ZodCheckOverwrite: value = tx(value). Later checks read the\n // rewritten value because input aliases the output location.\n code += emit`${g.output}=${emitEffectFn(g.ctx, check.source)}(${g.input});`;\n break;\n case \"string_format\": {\n let regexVar: string;\n let pattern: string;\n // Only the BUILT-IN z.url() gets the URL-parser check, and extraction\n // never gives that one a pattern. A `pattern` on a \"url\"-named check\n // therefore marks a custom format that merely borrowed the name\n // (`z.stringFormat(\"url\", /re/)`); it validates through its own regex,\n // so fall through and compile that instead of the URL parser.\n if (check.format === \"url\" && !check.pattern) {\n code += slowUrlCheck(check, g);\n continue;\n }\n if (check.format === \"email\") {\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n regexVar = g.regex(\"email\", pattern, check.patternFlags);\n } else if (check.format === \"regex\" && check.pattern) {\n pattern = check.pattern;\n regexVar = g.regex(\"str\", pattern, check.patternFlags);\n } else if (check.format === \"uuid\") {\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n regexVar = g.regex(\"uuid\", pattern, check.patternFlags);\n } else {\n if (check.pattern) {\n pattern = check.pattern;\n regexVar = g.regex(\"str\", pattern, check.patternFlags);\n } else {\n // Extraction guarantees a pattern for non-special formats;\n // defensive skip kept for hand-built IR.\n continue;\n }\n }\n // Zod's invalid_format shape depends on WHICH check instance ran.\n // `$ZodCheckStringFormat.init` installs the default pattern check with\n // `??=`, and that default pushes `origin:\"string\"` + `pattern`. A\n // constructor that OVERRIDES `inst._zod.check` pushes its own issue\n // instead — `$ZodCustomStringFormat` (z.stringFormat/z.hex/z.hostname/\n // z.hash) pushes a bare `{code, format, input}` because it validates\n // through `def.fn` and never reads `def.pattern`. We test the pattern\n // either way, so the issue shape is driven off the extracted flag.\n let extra: string | undefined;\n if (!check.bareIssue) {\n // When emitRegex swapped in a faster equivalent pattern, the runtime\n // regex's toString() would leak the rewrite into the issue. Reference\n // the shared original-pattern string instead (pattern came from\n // RegExp.source, so it matches zod's `.toString()` byte-for-byte).\n const rewritten = !check.patternFlags && fastTestSource(pattern) !== null;\n const patternExpr = rewritten\n ? emitRegexSourceString(g.ctx, pattern)\n : `${regexVar}.toString()`;\n extra = `pattern:${patternExpr}`;\n }\n code += emit`\n ${lastIndexReset(regexVar, check.patternFlags)}\n if(!${regexVar}.test(${g.input})){\n ${invalidFormat(g, { expr: escapeString(check.format) }, { origin: check.bareIssue ? undefined : \"string\", extra, message: check.message })}\n }`;\n break;\n }\n }\n }\n code += `}`;\n }\n\n return `${code}\\n`;\n}\n\n/**\n * Boolean expression testing ONE compiled string check against `x`, or null when\n * the check is not expressible as a pure predicate (`z.url()`, which trims and\n * normalizes, and an unknown format with no pattern).\n *\n * Shared by the fast path — which sorts the checks cheapest-first and joins them\n * with `&&` — and by the build path, which emits them one statement at a time in\n * DECLARATION order so an interleaved `.trim()` rewrite is visible to the checks\n * that follow it (see buildString).\n */\nexport function fastStringCheck(check: CheckIR, x: string, ctx: CodeGenContext): string | null {\n switch (check.kind) {\n case \"min_length\":\n return stringLengthTests.min(x, check.minimum, ctx);\n case \"max_length\":\n return stringLengthTests.max(x, check.maximum, ctx);\n case \"length_equals\":\n return stringLengthTests.equals(x, check.length, ctx);\n case \"includes\":\n return check.position !== undefined\n ? `${x}.includes(${escapeString(check.includes)},${check.position})`\n : `${x}.includes(${escapeString(check.includes)})`;\n case \"starts_with\":\n return `${x}.startsWith(${escapeString(check.prefix)})`;\n case \"ends_with\":\n return `${x}.endsWith(${escapeString(check.suffix)})`;\n case \"string_format\": {\n // URL validation mutates (trims) and uses try/catch — not a predicate.\n // A patterned \"url\" check is a custom format that borrowed the name (see\n // buildString), and its regex IS a predicate.\n if (check.format === \"url\" && !check.pattern) return null;\n let pattern: string;\n let prefix: string;\n if (check.format === \"email\") {\n prefix = \"email\";\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n } else if (check.format === \"uuid\") {\n prefix = \"uuid\";\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n } else if (check.pattern) {\n prefix = \"re\";\n pattern = check.pattern;\n } else {\n // Unknown format without pattern — can't generate a check\n return null;\n }\n const v = emitRegex(ctx, prefix, pattern, check.patternFlags);\n // Stateful (g/y) regexes need lastIndex reset; comma expression keeps\n // this usable inside the boolean chain.\n return check.patternFlags && /[gy]/.test(check.patternFlags)\n ? `((${v}.lastIndex=0),${v}.test(${x}))`\n : `${v}.test(${x})`;\n }\n default:\n // A check kind this generator does not model (number/bigint/date/set\n // shapes never reach here from a string node).\n return null;\n }\n}\n\nexport function fastString(ir: StringIR, g: FastGen): string | null {\n if (ir.coerce) return null;\n // Overwrite effects rewrite the value — the fast path returns input\n // unchanged, so any mutation makes it ineligible.\n if (ir.checks.some((c) => c.kind === \"overwrite_effect\")) return null;\n\n const x = g.input;\n const parts: string[] = [`typeof ${x}===\"string\"`];\n const checks = ir.checks.filter(\n (c): c is CheckIR => c.kind !== \"refine_effect\" && c.kind !== \"overwrite_effect\",\n );\n\n for (const check of checks.sort(checkPriority)) {\n const expr = fastStringCheck(check, x, g.ctx);\n if (expr === null) return null;\n parts.push(expr);\n }\n\n // Refine effect checks (appended last — run after cheap checks short-circuit)\n for (const check of ir.checks) {\n if (check.kind === \"refine_effect\") {\n parts.push(`${emitEffectCallable(g.ctx, check)}(${x})`);\n } else if (check.kind === \"super_refine_effect\") {\n parts.push(superRefineFastTest(check, x, g));\n }\n }\n\n return parts.join(\"&&\");\n}\n"],"mappings":";;;;;;;;AAiBA,SAAS,eAAe,UAAkB,OAAmC;CAC3E,OAAO,SAAS,OAAO,KAAK,KAAK,IAAI,GAAG,SAAS,iBAAiB;AACpE;;;;;;AAOA,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;AAoB7B,SAAS,aAAa,OAA0B,GAAoB;CAClE,MAAM,aAAa,EAAE,KAAK,IAAI;CAC9B,MAAM,SAAS,EAAE,KAAK,GAAG;CACzB,IAAI,QAAQ;CACZ,IAAI,MAAM,UAAU;EAClB,MAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,UAAU,MAAM,aAAa;EAC9D,SAAS,IAAI;QACT,eAAe,IAAI,MAAM,aAAa,EAAE;YACpC,GAAG,QAAQ,OAAO;UACpB,cAAc,GAAG,OAAO;GACxB,OAAO,mCAAmC,aAAa,MAAM,QAAQ;GACrE,SAAS,MAAM;EACjB,CAAC,EAAE;;CAET;CACA,IAAI,MAAM,UAAU;EAClB,MAAM,KAAK,EAAE,MAAM,SAAS,MAAM,UAAU,MAAM,aAAa;EAC/D,MAAM,YAAY,IAAI,OAAO,0BAA0B,OAAO,wBAAwB,OAAO;EAC7F,SAAS,IAAI;QACT,eAAe,IAAI,MAAM,aAAa,EAAE;YACpC,GAAG,QAAQ,UAAU;UACvB,cAAc,GAAG,OAAO;GACxB,OAAO,mCAAmC,aAAa,MAAM,QAAQ;GACrE,SAAS,MAAM;EACjB,CAAC,EAAE;;CAET;CAEA,MAAM,WAAW,MAAM,YACnB,GAAG,OAAO,SACV,GAAG,WAAW,WAAW,EAAE,MAAM,OAAO,eAAe,GAAG,EAAE;CAChE,SAAS,GAAG,EAAE,OAAO,GAAG,SAAS;CACjC,IAAI,QAAQ,IAAI;UACR,OAAO;UACP,OAAO,WAAW,WAAW;SAC9B,OAAO;QACR,cAAc,GAAG,OAAO,EAAE,SAAS,MAAM,QAAQ,CAAC,EAAE;;QAEpD,MAAM;;CAEZ,IAAI,CAAC,MAAM,aAAa,MAAM,aAAa,sBAEzC,QAAQ,IAAI;YADD,EAAE,MAAM,WAAW,kBAAkB,GAEvC,EAAE,QAAQ,WAAW;UACxB,cAAc,GAAG,OAAO;EAAE,OAAO;EAA6B,SAAS,MAAM;CAAQ,CAAC,EAAE;;UAExF,MAAM;;CAGd,OAAO,IAAI;UACH,WAAW,GAAG,EAAE,MAAM;MAC1B;AACN;AAEA,SAAgB,WAAW,IAAc,GAAoB;CAC3D,IAAI,OAAO;CACX,IAAI,GAAG,QACL,QAAQ,IAAI,OAAO,EAAE,OAAO,UAAU,EAAE,MAAM;CAEhD,QAAQ,IAAI;gBACE,EAAE,MAAM;QAChB,YAAY,GAAG,QAAQ,EAAE;QACzB,oBAAoB,GAAG,QAAQ,GAAG,QAAQ,EAAE;;CAGlD,IAAI,GAAG,OAAO,SAAS,GAAG;EACxB,QAAQ;EAGR,KAAK,MAAM,SAAS,GAAG,QACrB,QAAQ,MAAM,MAAd;GAGE,KAAK;IACH,QAAQ,IAAI;iBACL,kBAAkB,SAAS,EAAE,OAAO,MAAM,SAAS,EAAE,GAAG,EAAE;gBAC3D,SAAS,GAAG,MAAM,SAAS,UAAU,MAAM,EAAE,SAAS,MAAM,QAAQ,CAAC,EAAE;;IAE7E;GACF,KAAK;IACH,QAAQ,IAAI;iBACL,kBAAkB,SAAS,EAAE,OAAO,MAAM,SAAS,EAAE,GAAG,EAAE;gBAC3D,OAAO,GAAG,MAAM,SAAS,UAAU,MAAM,EAAE,SAAS,MAAM,QAAQ,CAAC,EAAE;;IAE3E;GACF,KAAK,iBAAiB;IACpB,MAAM,SAAS,EAAE,KAAK,IAAI;IAC1B,QAAQ,IAAI;kBACJ,OAAO,GAAG,kBAAkB,QAAQ,EAAE,OAAO,MAAM,QAAQ,EAAE,GAAG,EAAE;iBACnE,OAAO,GAAG,MAAM,OAAO;gBACxB,SAAS,GAAG,MAAM,QAAQ,UAAU,MAAM;KAAE,OAAO;KAAM,SAAS,MAAM;IAAQ,CAAC,EAAE;uBAC5E,OAAO,GAAG,MAAM,OAAO;gBAC9B,OAAO,GAAG,MAAM,QAAQ,UAAU,MAAM;KAAE,OAAO;KAAM,SAAS,MAAM;IAAQ,CAAC,EAAE;;IAEvF;GACF;GAMA,KAAK;IACH,QAAQ,IAAI;kBACJ,EAAE,MAAM,YAAY,aAAa,MAAM,QAAQ,IAAI,MAAM,aAAa,KAAA,IAAY,IAAI,MAAM,aAAa,GAAG;gBAC9G,cAAc,GAAG,YAAY;KAAE,QAAQ;KAAU,OAAO,YAAY,aAAa,MAAM,QAAQ;KAAK,SAAS,MAAM;IAAQ,CAAC,EAAE;;IAEpI;GACF,KAAK;IACH,QAAQ,IAAI;kBACJ,EAAE,MAAM,cAAc,aAAa,MAAM,MAAM,EAAE;gBACnD,cAAc,GAAG,eAAe;KAAE,QAAQ;KAAU,OAAO,UAAU,aAAa,MAAM,MAAM;KAAK,SAAS,MAAM;IAAQ,CAAC,EAAE;;IAEnI;GACF,KAAK;IACH,QAAQ,IAAI;kBACJ,EAAE,MAAM,YAAY,aAAa,MAAM,MAAM,EAAE;gBACjD,cAAc,GAAG,aAAa;KAAE,QAAQ;KAAU,OAAO,UAAU,aAAa,MAAM,MAAM;KAAK,SAAS,MAAM;IAAQ,CAAC,EAAE;;IAEjI;GACF,KAAK;IACH,QAAQ,YAAY,OAAO,EAAE,OAAO,CAAC;IACrC;GACF,KAAK;IACH,QAAQ,iBAAiB,OAAO,EAAE,OAAO,CAAC;IAC1C;GACF,KAAK;IAGH,QAAQ,IAAI,GAAG,EAAE,OAAO,GAAG,aAAa,EAAE,KAAK,MAAM,MAAM,EAAE,GAAG,EAAE,MAAM;IACxE;GACF,KAAK,iBAAiB;IACpB,IAAI;IACJ,IAAI;IAMJ,IAAI,MAAM,WAAW,SAAS,CAAC,MAAM,SAAS;KAC5C,QAAQ,aAAa,OAAO,CAAC;KAC7B;IACF;IACA,IAAI,MAAM,WAAW,SAAS;KAC5B,UAAU,MAAM,WAAW;KAC3B,WAAW,EAAE,MAAM,SAAS,SAAS,MAAM,YAAY;IACzD,OAAO,IAAI,MAAM,WAAW,WAAW,MAAM,SAAS;KACpD,UAAU,MAAM;KAChB,WAAW,EAAE,MAAM,OAAO,SAAS,MAAM,YAAY;IACvD,OAAO,IAAI,MAAM,WAAW,QAAQ;KAClC,UAAU,MAAM,WAAA;KAChB,WAAW,EAAE,MAAM,QAAQ,SAAS,MAAM,YAAY;IACxD,OACE,IAAI,MAAM,SAAS;KACjB,UAAU,MAAM;KAChB,WAAW,EAAE,MAAM,OAAO,SAAS,MAAM,YAAY;IACvD,OAGE;IAWJ,IAAI;IACJ,IAAI,CAAC,MAAM,WAST,QAAQ,WAJU,CAAC,MAAM,gBAAgB,eAAe,OAAO,MAAM,OAEjE,sBAAsB,EAAE,KAAK,OAAO,IACpC,GAAG,SAAS;IAGlB,QAAQ,IAAI;cACR,eAAe,UAAU,MAAM,YAAY,EAAE;kBACzC,SAAS,QAAQ,EAAE,MAAM;gBAC3B,cAAc,GAAG,EAAE,MAAM,aAAa,MAAM,MAAM,EAAE,GAAG;KAAE,QAAQ,MAAM,YAAY,KAAA,IAAY;KAAU;KAAO,SAAS,MAAM;IAAQ,CAAC,EAAE;;IAEhJ;GACF;EACF;EAEF,QAAQ;CACV;CAEA,OAAO,GAAG,KAAK;AACjB;;;;;;;;;;;AAYA,SAAgB,gBAAgB,OAAgB,GAAW,KAAoC;CAC7F,QAAQ,MAAM,MAAd;EACE,KAAK,cACH,OAAO,kBAAkB,IAAI,GAAG,MAAM,SAAS,GAAG;EACpD,KAAK,cACH,OAAO,kBAAkB,IAAI,GAAG,MAAM,SAAS,GAAG;EACpD,KAAK,iBACH,OAAO,kBAAkB,OAAO,GAAG,MAAM,QAAQ,GAAG;EACtD,KAAK,YACH,OAAO,MAAM,aAAa,KAAA,IACtB,GAAG,EAAE,YAAY,aAAa,MAAM,QAAQ,EAAE,GAAG,MAAM,SAAS,KAChE,GAAG,EAAE,YAAY,aAAa,MAAM,QAAQ,EAAE;EACpD,KAAK,eACH,OAAO,GAAG,EAAE,cAAc,aAAa,MAAM,MAAM,EAAE;EACvD,KAAK,aACH,OAAO,GAAG,EAAE,YAAY,aAAa,MAAM,MAAM,EAAE;EACrD,KAAK,iBAAiB;GAIpB,IAAI,MAAM,WAAW,SAAS,CAAC,MAAM,SAAS,OAAO;GACrD,IAAI;GACJ,IAAI;GACJ,IAAI,MAAM,WAAW,SAAS;IAC5B,SAAS;IACT,UAAU,MAAM,WAAW;GAC7B,OAAO,IAAI,MAAM,WAAW,QAAQ;IAClC,SAAS;IACT,UAAU,MAAM,WAAA;GAClB,OAAO,IAAI,MAAM,SAAS;IACxB,SAAS;IACT,UAAU,MAAM;GAClB,OAEE,OAAO;GAET,MAAM,IAAI,UAAU,KAAK,QAAQ,SAAS,MAAM,YAAY;GAG5D,OAAO,MAAM,gBAAgB,OAAO,KAAK,MAAM,YAAY,IACvD,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MACnC,GAAG,EAAE,QAAQ,EAAE;EACrB;EACA,SAGE,OAAO;CACX;AACF;AAEA,SAAgB,WAAW,IAAc,GAA2B;CAClE,IAAI,GAAG,QAAQ,OAAO;CAGtB,IAAI,GAAG,OAAO,MAAM,MAAM,EAAE,SAAS,kBAAkB,GAAG,OAAO;CAEjE,MAAM,IAAI,EAAE;CACZ,MAAM,QAAkB,CAAC,UAAU,EAAE,YAAY;CACjD,MAAM,SAAS,GAAG,OAAO,QACtB,MAAoB,EAAE,SAAS,mBAAmB,EAAE,SAAS,kBAChE;CAEA,KAAK,MAAM,SAAS,OAAO,KAAK,aAAa,GAAG;EAC9C,MAAM,OAAO,gBAAgB,OAAO,GAAG,EAAE,GAAG;EAC5C,IAAI,SAAS,MAAM,OAAO;EAC1B,MAAM,KAAK,IAAI;CACjB;CAGA,KAAK,MAAM,SAAS,GAAG,QACrB,IAAI,MAAM,SAAS,iBACjB,MAAM,KAAK,GAAG,mBAAmB,EAAE,KAAK,KAAK,EAAE,GAAG,EAAE,EAAE;MACjD,IAAI,MAAM,SAAS,uBACxB,MAAM,KAAK,oBAAoB,OAAO,GAAG,CAAC,CAAC;CAI/C,OAAO,MAAM,KAAK,IAAI;AACxB"}
1
+ {"version":3,"file":"string.js","names":[],"sources":["../../../../src/core/codegen/schemas/string.ts"],"sourcesContent":["import type { CheckIR, CheckStringFormat, StringIR } from \"../../types.js\";\nimport type { CodeGenContext, FastGen, SlowGen } from \"../context.js\";\nimport {\n checkPriority,\n emitEffectCallable,\n emitEffectFn,\n emitRegex,\n emitRegexSourceString,\n emitRuntimeHelper,\n escapeString,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidFormat, invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\nimport { ZC_EMAIL_DECL } from \"../issue-decls.js\";\nimport {\n EMAIL_REGEX_SOURCE,\n fastTestSource,\n isDefaultEmailPattern,\n UUID_REGEX_SOURCE,\n} from \"../well-known-regex.js\";\nimport { refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\nimport { stringLengthTests, whenGatedSizeChecks } from \"./sizeable.js\";\n\n/** `re.lastIndex=0;` reset statement for stateful (g/y-flagged) regexes. */\nfunction lastIndexReset(regexVar: string, flags: string | undefined): string {\n return flags && /[gy]/.test(flags) ? `${regexVar}.lastIndex=0;` : \"\";\n}\n\n/**\n * `regexes.httpProtocol.source`. `parseURLObject` compares a url check's\n * protocol SOURCE against it — not the schema constructor — so any check whose\n * protocol is spelled this way gets the guard, `z.httpUrl()` or not.\n */\nconst HTTP_PROTOCOL_SOURCE = \"^https?$\";\n\n/**\n * Generate the url check, mirroring $ZodURL semantics:\n * trim → (for an http(s)-protocol check without normalize) require `://` →\n * new URL(trimmed) → optional hostname/protocol regex tests → write back\n * url.href (normalize) or the trimmed input with its tabs and newlines deleted.\n *\n * The `://` guard is `parseURLObject`'s: without it the URL parser accepts\n * `http:example.com`, and its rejection is a distinct issue (`note: \"Invalid\n * URL format\"`, no `pattern`) pushed BEFORE the parser runs. The deletion of\n * `\\t`, `\\n` and `\\r` (`stripTabAndNewline`) matches what the parser itself\n * drops before it reads the host, so the returned value names the host that was\n * validated.\n *\n * $ZodURL is another constructor that OVERRIDES the `??=`-installed default\n * check, so none of the issues below carries `origin` — and the two that do\n * carry a `pattern` use `regex.source`, not the default check's\n * `regex.toString()` (no delimiters, no flags). Both are reproduced verbatim.\n */\nfunction slowUrlCheck(check: CheckStringFormat, g: SlowGen): string {\n const trimmedVar = g.temp(\"ut\");\n const urlVar = g.temp(\"u\");\n let inner = \"\";\n if (check.hostname) {\n const re = g.regex(\"host\", check.hostname, check.hostnameFlags);\n inner += emit`\n ${lastIndexReset(re, check.hostnameFlags)}\n if(!${re}.test(${urlVar}.hostname)){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid hostname\",pattern:${escapeString(check.hostname)}`,\n message: check.message,\n })}\n }`;\n }\n if (check.protocol) {\n const re = g.regex(\"proto\", check.protocol, check.protocolFlags);\n const protoExpr = `(${urlVar}.protocol.endsWith(\":\")?${urlVar}.protocol.slice(0,-1):${urlVar}.protocol)`;\n inner += emit`\n ${lastIndexReset(re, check.protocolFlags)}\n if(!${re}.test(${protoExpr})){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid protocol\",pattern:${escapeString(check.protocol)}`,\n message: check.message,\n })}\n }`;\n }\n // Zod writes the value back even when hostname/protocol issues were pushed.\n const stripped = check.normalize\n ? `${urlVar}.href`\n : `${trimmedVar}.replace(${g.regex(\"tnl\", \"[\\\\t\\\\n\\\\r]\", \"g\")},\"\")`;\n inner += `${g.output}=${stripped};`;\n let parse = emit`\n var ${urlVar}=null;\n try{${urlVar}=new URL(${trimmedVar});}catch(_){}\n if(${urlVar}===null){\n ${invalidFormat(g, \"url\", { message: check.message })}\n }else{\n ${inner}\n }`;\n if (!check.normalize && check.protocol === HTTP_PROTOCOL_SOURCE) {\n const re = g.regex(\"httpUrl\", \"^https?:\\\\/\\\\/\", \"i\");\n parse = emit`\n if(!${re}.test(${trimmedVar})){\n ${invalidFormat(g, \"url\", { extra: `note:\"Invalid URL format\"`, message: check.message })}\n }else{\n ${parse}\n }`;\n }\n return emit`\n var ${trimmedVar}=${g.input}.trim();\n ${parse}`;\n}\n\nexport function slowString(ir: StringIR, g: SlowGen): string {\n let code = \"\";\n if (ir.coerce) {\n code += emit`try{${g.output}=String(${g.input});}catch(_){}`;\n }\n code += emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n ${whenGatedSizeChecks(ir.checks, g, \"length\")}\n }`;\n\n if (ir.checks.length > 0) {\n code += `else{`;\n // Insertion order mirrors zod's issue order for multi-failure inputs;\n // the slow path collects all issues with no short-circuit.\n for (const check of ir.checks) {\n switch (check.kind) {\n // Length is measured in code points where the unit count leaves the\n // verdict in doubt — see stringLengthTests.\n case \"min_length\":\n code += emit`\n if(${stringLengthTests.minFails(g.input, check.minimum, g.ctx)}){\n ${tooSmall(g, check.minimum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"max_length\":\n code += emit`\n if(${stringLengthTests.maxFails(g.input, check.maximum, g.ctx)}){\n ${tooBig(g, check.maximum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"length_equals\": {\n const length = g.temp(\"cl\");\n code += emit`\n var ${length}=${stringLengthTests.measure(g.input, check.length, g.ctx)};\n if(${length}<${check.length}){\n ${tooSmall(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }else if(${length}>${check.length}){\n ${tooBig(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }`;\n break;\n }\n // includes/starts_with/ends_with each carry `origin:\"string\"` but NO\n // `pattern`: $ZodCheckIncludes/StartsWith/EndsWith bypass\n // $ZodCheckStringFormat entirely (they init from $ZodCheck and assign\n // `inst._zod.check` directly), and the pattern they build is registered\n // in the bag for JSON Schema only, never put on the issue.\n case \"includes\":\n code += emit`\n if(!${g.input}.includes(${escapeString(check.includes)}${check.position !== undefined ? `,${check.position}` : \"\"})){\n ${invalidFormat(g, \"includes\", { origin: \"string\", extra: `includes:${escapeString(check.includes)}`, message: check.message })}\n }`;\n break;\n case \"starts_with\":\n code += emit`\n if(!${g.input}.startsWith(${escapeString(check.prefix)})){\n ${invalidFormat(g, \"starts_with\", { origin: \"string\", extra: `prefix:${escapeString(check.prefix)}`, message: check.message })}\n }`;\n break;\n case \"ends_with\":\n code += emit`\n if(!${g.input}.endsWith(${escapeString(check.suffix)})){\n ${invalidFormat(g, \"ends_with\", { origin: \"string\", extra: `suffix:${escapeString(check.suffix)}`, message: check.message })}\n }`;\n break;\n case \"refine_effect\":\n code += refineCheck(check, g.input, g);\n break;\n case \"super_refine_effect\":\n code += superRefineCheck(check, g.input, g);\n break;\n case \"overwrite_effect\":\n // $ZodCheckOverwrite: value = tx(value). Later checks read the\n // rewritten value because input aliases the output location.\n code += emit`${g.output}=${emitEffectFn(g.ctx, check.source)}(${g.input});`;\n break;\n case \"string_format\": {\n let prefix: string;\n let pattern: string;\n // Only the BUILT-IN z.url() gets the URL-parser check, and extraction\n // never gives that one a pattern. A `pattern` on a \"url\"-named check\n // therefore marks a custom format that merely borrowed the name\n // (`z.stringFormat(\"url\", /re/)`); it validates through its own regex,\n // so fall through and compile that instead of the URL parser.\n if (check.format === \"url\" && !check.pattern) {\n code += slowUrlCheck(check, g);\n continue;\n }\n if (check.format === \"email\") {\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n prefix = \"email\";\n } else if (check.format === \"regex\" && check.pattern) {\n pattern = check.pattern;\n prefix = \"str\";\n } else if (check.format === \"uuid\") {\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n prefix = \"uuid\";\n } else {\n if (check.pattern) {\n pattern = check.pattern;\n prefix = \"str\";\n } else {\n // Extraction guarantees a pattern for non-special formats;\n // defensive skip kept for hand-built IR.\n continue;\n }\n }\n // Zod's default email pattern is tested by the `__zcEmail` scanner, so\n // no RegExp is declared for it at all (see ZC_EMAIL_DECL); the issue\n // below still names the pattern, through the shared source string.\n const scanner = isDefaultEmailPattern(pattern, check.patternFlags)\n ? emitRuntimeHelper(g.ctx, \"__zcEmail\", ZC_EMAIL_DECL)\n : null;\n const regexVar = scanner === null ? g.regex(prefix, pattern, check.patternFlags) : null;\n // Zod's invalid_format shape depends on WHICH check instance ran.\n // `$ZodCheckStringFormat.init` installs the default pattern check with\n // `??=`, and that default pushes `origin:\"string\"` + `pattern`. A\n // constructor that OVERRIDES `inst._zod.check` pushes its own issue\n // instead — `$ZodCustomStringFormat` (z.stringFormat/z.hex/z.hostname/\n // z.hash) pushes a bare `{code, format, input}` because it validates\n // through `def.fn` and never reads `def.pattern`. We test the pattern\n // either way, so the issue shape is driven off the extracted flag.\n let extra: string | undefined;\n if (!check.bareIssue) {\n // When emitRegex swapped in a faster equivalent pattern (or the\n // scanner stands in for the RegExp), the runtime regex's toString()\n // would leak the rewrite into the issue. Reference the shared\n // original-pattern string instead (pattern came from RegExp.source,\n // so it matches zod's `.toString()` byte-for-byte).\n const rewritten = !check.patternFlags && fastTestSource(pattern) !== null;\n const patternExpr =\n rewritten || regexVar === null\n ? emitRegexSourceString(g.ctx, pattern)\n : `${regexVar}.toString()`;\n extra = `pattern:${patternExpr}`;\n }\n const test =\n regexVar === null ? `${scanner}(${g.input})` : `${regexVar}.test(${g.input})`;\n code += emit`\n ${regexVar === null ? \"\" : lastIndexReset(regexVar, check.patternFlags)}\n if(!${test}){\n ${invalidFormat(g, { expr: escapeString(check.format) }, { origin: check.bareIssue ? undefined : \"string\", extra, message: check.message })}\n }`;\n break;\n }\n }\n }\n code += `}`;\n }\n\n return `${code}\\n`;\n}\n\n/**\n * Boolean expression testing ONE compiled string check against `x`, or null when\n * the check is not expressible as a pure predicate (`z.url()`, which trims and\n * normalizes, and an unknown format with no pattern).\n *\n * Shared by the fast path — which sorts the checks cheapest-first and joins them\n * with `&&` — and by the build path, which emits them one statement at a time in\n * DECLARATION order so an interleaved `.trim()` rewrite is visible to the checks\n * that follow it (see buildString).\n */\nexport function fastStringCheck(check: CheckIR, x: string, ctx: CodeGenContext): string | null {\n switch (check.kind) {\n case \"min_length\":\n return stringLengthTests.min(x, check.minimum, ctx);\n case \"max_length\":\n return stringLengthTests.max(x, check.maximum, ctx);\n case \"length_equals\":\n return stringLengthTests.equals(x, check.length, ctx);\n case \"includes\":\n return check.position !== undefined\n ? `${x}.includes(${escapeString(check.includes)},${check.position})`\n : `${x}.includes(${escapeString(check.includes)})`;\n case \"starts_with\":\n return `${x}.startsWith(${escapeString(check.prefix)})`;\n case \"ends_with\":\n return `${x}.endsWith(${escapeString(check.suffix)})`;\n case \"string_format\": {\n // URL validation mutates (trims) and uses try/catch — not a predicate.\n // A patterned \"url\" check is a custom format that borrowed the name (see\n // buildString), and its regex IS a predicate.\n if (check.format === \"url\" && !check.pattern) return null;\n let pattern: string;\n let prefix: string;\n if (check.format === \"email\") {\n prefix = \"email\";\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n } else if (check.format === \"uuid\") {\n prefix = \"uuid\";\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n } else if (check.pattern) {\n prefix = \"re\";\n pattern = check.pattern;\n } else {\n // Unknown format without pattern — can't generate a check\n return null;\n }\n // Zod's default email pattern runs as a linear scan instead of a RegExp\n // (see ZC_EMAIL_DECL) — a plain call, so it needs no parens either.\n if (isDefaultEmailPattern(pattern, check.patternFlags)) {\n return `${emitRuntimeHelper(ctx, \"__zcEmail\", ZC_EMAIL_DECL)}(${x})`;\n }\n const v = emitRegex(ctx, prefix, pattern, check.patternFlags);\n // Stateful (g/y) regexes need lastIndex reset; comma expression keeps\n // this usable inside the boolean chain.\n return check.patternFlags && /[gy]/.test(check.patternFlags)\n ? `((${v}.lastIndex=0),${v}.test(${x}))`\n : `${v}.test(${x})`;\n }\n default:\n // A check kind this generator does not model (number/bigint/date/set\n // shapes never reach here from a string node).\n return null;\n }\n}\n\nexport function fastString(ir: StringIR, g: FastGen): string | null {\n if (ir.coerce) return null;\n // Overwrite effects rewrite the value — the fast path returns input\n // unchanged, so any mutation makes it ineligible.\n if (ir.checks.some((c) => c.kind === \"overwrite_effect\")) return null;\n\n const x = g.input;\n const parts: string[] = [`typeof ${x}===\"string\"`];\n const checks = ir.checks.filter(\n (c): c is CheckIR => c.kind !== \"refine_effect\" && c.kind !== \"overwrite_effect\",\n );\n\n for (const check of checks.sort(checkPriority)) {\n const expr = fastStringCheck(check, x, g.ctx);\n if (expr === null) return null;\n parts.push(expr);\n }\n\n // Refine effect checks (appended last — run after cheap checks short-circuit)\n for (const check of ir.checks) {\n if (check.kind === \"refine_effect\") {\n parts.push(`${emitEffectCallable(g.ctx, check)}(${x})`);\n } else if (check.kind === \"super_refine_effect\") {\n parts.push(superRefineFastTest(check, x, g));\n }\n }\n\n return parts.join(\"&&\");\n}\n"],"mappings":"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"}