zod-compiler 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +62 -58
  2. package/dist/cli/commands/check.d.ts.map +1 -1
  3. package/dist/cli/commands/check.js +5 -0
  4. package/dist/cli/commands/check.js.map +1 -1
  5. package/dist/core/codegen/build-path.d.ts.map +1 -1
  6. package/dist/core/codegen/build-path.js +107 -28
  7. package/dist/core/codegen/build-path.js.map +1 -1
  8. package/dist/core/codegen/context.d.ts +21 -11
  9. package/dist/core/codegen/context.d.ts.map +1 -1
  10. package/dist/core/codegen/context.js +15 -1
  11. package/dist/core/codegen/context.js.map +1 -1
  12. package/dist/core/codegen/fast-path.d.ts +3 -1
  13. package/dist/core/codegen/fast-path.d.ts.map +1 -1
  14. package/dist/core/codegen/fast-path.js +7 -4
  15. package/dist/core/codegen/fast-path.js.map +1 -1
  16. package/dist/core/codegen/index.js +4 -3
  17. package/dist/core/codegen/index.js.map +1 -1
  18. package/dist/core/codegen/issue-decls.d.ts +67 -5
  19. package/dist/core/codegen/issue-decls.d.ts.map +1 -1
  20. package/dist/core/codegen/issue-decls.js +72 -7
  21. package/dist/core/codegen/issue-decls.js.map +1 -1
  22. package/dist/core/codegen/schemas/array.d.ts.map +1 -1
  23. package/dist/core/codegen/schemas/array.js +3 -3
  24. package/dist/core/codegen/schemas/array.js.map +1 -1
  25. package/dist/core/codegen/schemas/default.d.ts +10 -0
  26. package/dist/core/codegen/schemas/default.d.ts.map +1 -1
  27. package/dist/core/codegen/schemas/default.js +11 -0
  28. package/dist/core/codegen/schemas/default.js.map +1 -1
  29. package/dist/core/codegen/schemas/effect.d.ts +13 -1
  30. package/dist/core/codegen/schemas/effect.d.ts.map +1 -1
  31. package/dist/core/codegen/schemas/effect.js +26 -3
  32. package/dist/core/codegen/schemas/effect.js.map +1 -1
  33. package/dist/core/codegen/schemas/fallback.d.ts +17 -1
  34. package/dist/core/codegen/schemas/fallback.d.ts.map +1 -1
  35. package/dist/core/codegen/schemas/fallback.js +31 -15
  36. package/dist/core/codegen/schemas/fallback.js.map +1 -1
  37. package/dist/core/codegen/schemas/number.d.ts.map +1 -1
  38. package/dist/core/codegen/schemas/number.js +35 -35
  39. package/dist/core/codegen/schemas/number.js.map +1 -1
  40. package/dist/core/codegen/schemas/object.d.ts.map +1 -1
  41. package/dist/core/codegen/schemas/object.js +64 -29
  42. package/dist/core/codegen/schemas/object.js.map +1 -1
  43. package/dist/core/codegen/schemas/string.d.ts.map +1 -1
  44. package/dist/core/codegen/schemas/string.js +3 -3
  45. package/dist/core/codegen/schemas/string.js.map +1 -1
  46. package/dist/core/codegen/schemas/template-literal.d.ts.map +1 -1
  47. package/dist/core/codegen/schemas/template-literal.js +1 -1
  48. package/dist/core/codegen/schemas/template-literal.js.map +1 -1
  49. package/dist/core/extract/index.d.ts.map +1 -1
  50. package/dist/core/extract/index.js +2 -0
  51. package/dist/core/extract/index.js.map +1 -1
  52. package/dist/core/extract/zod-version.d.ts +78 -0
  53. package/dist/core/extract/zod-version.d.ts.map +1 -0
  54. package/dist/core/extract/zod-version.js +109 -0
  55. package/dist/core/extract/zod-version.js.map +1 -0
  56. package/dist/core/iife.d.ts +8 -0
  57. package/dist/core/iife.d.ts.map +1 -1
  58. package/dist/core/iife.js +8 -0
  59. package/dist/core/iife.js.map +1 -1
  60. package/dist/jit.d.ts.map +1 -1
  61. package/dist/jit.js +9 -1
  62. package/dist/jit.js.map +1 -1
  63. package/dist/runtime.d.ts +3 -0
  64. package/dist/runtime.js +4 -1
  65. package/dist/unplugin/hoist-compile.d.ts.map +1 -1
  66. package/dist/unplugin/hoist-compile.js +3 -1
  67. package/dist/unplugin/hoist-compile.js.map +1 -1
  68. package/dist/unplugin/transform.d.ts.map +1 -1
  69. package/dist/unplugin/transform.js +5 -0
  70. package/dist/unplugin/transform.js.map +1 -1
  71. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"object.js","names":[],"sources":["../../../../src/core/codegen/schemas/object.ts"],"sourcesContent":["import type { ObjectIR, SchemaIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport {\n declareFastTemps,\n emitEffectCallable,\n emitRuntimeHelper,\n escapeString,\n extendPath,\n extendStaticPath,\n hasMutation,\n keyMembershipTest,\n outputAlwaysDefined,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, unrecognizedKeys } from \"../emit-issue.js\";\nimport { ZC_AB_DECL, ZC_PROTO_SCRUB_DECL } from \"../issue-decls.js\";\nimport { orderByRuntimeCost } from \"../fast-size.js\";\nimport { refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\n\n/**\n * The shape entries whose schemas actually RUN. `$ZodObject` skips a declared\n * `__proto__` key in its shape loop (`if (key === \"__proto__\") continue`), so\n * that property is never validated and never written to the output — it is\n * only a recognized name for the strict/catchall passes, which read\n * `Object.keys(ir.properties)` directly. Writing it would be worse than\n * pointless: `{__proto__: v}` in an object literal, and `o[\"__proto__\"] = v`\n * on a plain object, both SET THE PROTOTYPE rather than define a key.\n */\nexport function parsedProperties(ir: ObjectIR): [string, SchemaIR][] {\n return Object.entries(ir.properties).filter(([key]) => key !== \"__proto__\");\n}\n\nexport function slowObject(ir: SchemaIR & { type: \"object\" }, g: SlowGen): string {\n let code = emit`\n if(typeof ${g.input}!==\"object\"||${g.input}===null||Array.isArray(${g.input})){\n ${invalidType(g, \"object\")}\n }else{`;\n\n // Strip mode (zod's default z.object() output) rebuilds a FRESH object from\n // the declared keys, so it always writes back. Otherwise clone only when a\n // property mutates the value.\n const strip = ir.stripUnknownKeys === true;\n const needsClone =\n strip ||\n (ir.catchall !== undefined && hasMutation(ir.catchall)) ||\n Object.values(ir.properties).some(hasMutation);\n const objVar = g.temp(\"o\");\n if (!strip) {\n // Spread, not Object.assign: V8's CloneObjectIC makes `{...x}` ~25% faster\n // on the whole safeParse call for mutation-bearing schemas.\n code += needsClone ? `var ${objVar}={...${g.input}};` : `var ${objVar}=${g.input};`;\n // A loose or catchall output is the INPUT, or a spread of it — and spread\n // copies an own `__proto__` as a plain data property — where zod's fresh\n // `{}` never receives the key at all. Scrub it (see ZC_PROTO_SCRUB_DECL); a\n // strip object rebuilds and needs nothing here.\n const scrub = emitRuntimeHelper(g.ctx, \"__zcPs\", ZC_PROTO_SCRUB_DECL);\n code += `${objVar}=${scrub}(${objVar});`;\n }\n\n // Object-level refines are gated on zod's ABORT rule, not on \"did anything\n // fail\": zod parses the properties (plus the strict/catchall passes) into the\n // payload and then skips its check chain only when `util.aborted` holds — i.e.\n // when one of those issues is non-continuable. A property that failed its own\n // `min`/format check reports a CONTINUABLE issue, so the outer refine still\n // runs and both messages surface — and so does an unrecognized key, which zod\n // pushes with `continue: true`; a property that failed to parse at all\n // (`invalid_type`, a bad record key) aborts and suppresses it. Snapshot the\n // issue count before the properties so the scan covers exactly this node's\n // own parse, as zod's fresh sub-payload does.\n const refineMark = ir.checks && ir.checks.length > 0 ? g.temp(\"rm\") : \"\";\n if (refineMark) code += `var ${refineMark}=${g.issues}.length;`;\n\n const skipAbsent = new Set(ir.skipAbsentKeys ?? []);\n const suppressAbsent = new Set(ir.suppressAbsentKeys ?? []);\n const nonoptional = new Set(ir.nonoptionalKeys ?? []);\n /** Strip only: per-property output slot + whether it is always in the result. */\n const slots: { always: boolean; keyStr: string; value: string }[] = [];\n\n for (const [key, propIR] of parsedProperties(ir)) {\n const keyStr = escapeString(key);\n const propPath = extendStaticPath(g.path, key);\n // Strip validates the value read from the INPUT, held in a local, and\n // assembles the result afterwards. Reading through the half-built copy (the\n // previous shape) both cost a megamorphic access per key — the copy's map\n // changes with every key added — and diverged from zod, which parses\n // `input[key]` and so accepts a value found on the prototype.\n const propExpr = strip ? g.temp(\"sv\") : `${objVar}[${keyStr}]`;\n if (strip) {\n code += `var ${propExpr}=${g.input}[${keyStr}];`;\n slots.push({ always: outputAlwaysDefined(propIR), keyStr, value: propExpr });\n }\n const propCode = g.visit(propIR, { input: propExpr, output: propExpr, path: propPath });\n // The three absent-key rules of zod's handlePropertyResult (see ObjectIR).\n // Presence is tested on the ORIGINAL input, as zod's `key in input` is —\n // a clone would hide an inherited key.\n //\n // The two rules that test presence AFTER running the property snapshot it\n // FIRST. Running the property can create the very key the test asks about:\n // where nothing mutates, `objVar` IS `g.input`, so the write-back of a\n // property that accepted `undefined` (`o[key]=result`) adds an own `key`\n // and the guard then reads it as present. `z.looseObject({a: z.custom()})`\n // on `{}` lost its `nonoptional` issue entirely that way — the fast path\n // still rejected on `\"a\" in x`, so `safeParse` failed with an EMPTY issue\n // array — and left the caller's object carrying an `a` zod never writes.\n const dropValue = strip ? `${propExpr}=undefined;` : `delete ${objVar}[${keyStr}];`;\n if (skipAbsent.has(key)) {\n code += emit`if(${keyStr} in ${g.input}){${propCode}}`;\n } else if (suppressAbsent.has(key)) {\n // A defaulted optional-out property runs, but a failure on an absent key\n // is discarded whole: issues and whatever value it wrote before failing.\n const beforeVar = g.temp(\"ob\");\n const presentVar = g.temp(\"op\");\n code += emit`\n var ${presentVar}=${keyStr} in ${g.input};\n var ${beforeVar}=${g.issues}.length;\n ${propCode}\n if(!${presentVar}&&${g.issues}.length>${beforeVar}){\n ${g.issues}.length=${beforeVar};${dropValue}\n }`;\n } else if (nonoptional.has(key)) {\n // A required key that is absent fails as such when its schema raised\n // nothing for the `undefined` it saw. zod pushes this one without an\n // `inst`, so no schema-level message reaches it — and it returns without\n // assigning, so whatever the property made of `undefined` is dropped.\n const beforeVar = g.temp(\"ob\");\n const presentVar = g.temp(\"op\");\n code += emit`\n var ${presentVar}=${keyStr} in ${g.input};\n var ${beforeVar}=${g.issues}.length;\n ${propCode}\n if(!${presentVar}){\n ${dropValue}\n if(${g.issues}.length===${beforeVar}){\n ${invalidType(g, \"nonoptional\", { input: \"undefined\", path: propPath, codeFirst: true, useTypeMsg: false })}\n }\n }`;\n } else {\n code += propCode;\n }\n }\n\n if (strip) {\n // Assemble the result in shape order (zod's key order), taking as long a\n // LEADING run of always-present keys as possible into one object literal:\n // V8 stamps a literal out of a cached boilerplate map in a single\n // allocation, where adding keys one at a time walks a transition chain and\n // re-checks the map on every store — measured 8.1x (20 keys) / 2.8x (7\n // keys, one optional) on the whole safeParse.\n //\n // Everything after the first conditional key is appended so insertion order\n // still matches zod. The per-key test is zod's own: keep the key when the\n // parsed value is defined, or when it was present on the input at all\n // (`key in input`, prototype included — an own `k: undefined` survives).\n const literal: string[] = [];\n let appends = \"\";\n let leading = true;\n for (const slot of slots) {\n if (leading && slot.always) {\n literal.push(`${slot.keyStr}:${slot.value}`);\n continue;\n }\n leading = false;\n appends += slot.always\n ? `${objVar}[${slot.keyStr}]=${slot.value};`\n : `if(${slot.value}!==undefined||(${slot.keyStr} in ${g.input})){${objVar}[${slot.keyStr}]=${slot.value};}`;\n }\n code += `var ${objVar}={${literal.join(\",\")}};${appends}`;\n }\n\n // Strict unknown-key pass — zod's handleCatchall, byte-exact: for-in over\n // the ORIGINAL input (inherited enumerable keys count, no hasOwnProperty),\n // ALL unknown keys collected into one issue, pushed AFTER property issues\n // and before object-level refines.\n if (ir.strict) {\n const keys = Object.keys(ir.properties);\n const ukVar = g.temp(\"uk\");\n const kVar = g.temp(\"k\");\n const test = keyMembershipTest(g.ctx, keys, kVar);\n code += emit`\n var ${ukVar}=null;\n for(var ${kVar} in ${g.input}){\n if(!(${test})){(${ukVar}=${ukVar}||[]).push(${kVar});}\n }\n if(${ukVar}!==null){\n ${unrecognizedKeys(g, ukVar)}\n }`;\n }\n\n // .catchall(schema): validate every key NOT in the shape, mirroring zod's\n // handleCatchall — same bare for-in over the ORIGINAL input as the strict\n // pass (inherited enumerable keys count, no hasOwnProperty guard), each\n // issue reported at the key. Runs after the properties, as zod does. An\n // undeclared `__proto__` is skipped like zod skips it: never validated, and\n // never assigned, since `o[\"__proto__\"]=v` on the clone would replace its\n // prototype instead of adding a key. (The strict pass above still REPORTS\n // it — there it is an unknown key like any other.)\n //\n // The key's slot is BOTH the input and the output, exactly as a shape\n // property's is: a value-rewriting catchall (coerce, .trim(), a default)\n // writes through the same expression it later re-reads, so splitting them\n // makes the rewrite invisible to its own checks.\n //\n // When the catchall mutates, objVar is a clone, and each unknown key is\n // copied into it before validation — which also reproduces zod, whose fresh\n // output object gains an OWN key for every for-in key it saw, inherited ones\n // included. A non-mutating catchall writes nothing, so objVar is the input\n // and the object stays pass-through by reference.\n if (ir.catchall) {\n const keys = Object.keys(ir.properties);\n const kVar = g.temp(\"ck\");\n const test = keyMembershipTest(g.ctx, keys, kVar);\n const slot = `${objVar}[${kVar}]`;\n const seed = needsClone ? `${slot}=${g.input}[${kVar}];` : \"\";\n code += emit`\n for(var ${kVar} in ${g.input}){\n if(!(${test})&&${kVar}!==\"__proto__\"){\n ${seed}\n ${g.visit(ir.catchall, {\n input: slot,\n output: slot,\n path: extendPath(g.path, kVar),\n })}\n }\n }`;\n }\n\n // `!strip` also writes back: the scrub above may have re-pointed `objVar` at\n // a copy even where nothing else mutates.\n if (needsClone || !strip) {\n code += `${g.output}=${objVar};`;\n }\n\n // Object-level refine effects: z.object({...}).refine(fn), suppressed when the\n // parse phase aborted (see refineMark). One gate covers every effect: each of\n // them can only add a continuable `custom` issue, so zod's per-check\n // re-evaluation of `isAborted` can never flip between them.\n if (ir.checks && ir.checks.length > 0) {\n let refines = \"\";\n for (const check of ir.checks) {\n refines +=\n check.kind === \"super_refine_effect\"\n ? superRefineCheck(check, objVar, g)\n : refineCheck(check, objVar, g);\n }\n const aborted = emitRuntimeHelper(g.ctx, \"__zcAb\", ZC_AB_DECL);\n code += `if(!${aborted}(${g.issues},${refineMark})){${refines}}`;\n }\n\n code += `}\\n`;\n return code;\n}\n\n/**\n * Property entries in the order their fast-checks should be `&&`-chained:\n * cheapest first, declaration order preserved among equals (Array#sort is\n * stable). Valid input runs every conjunct whatever the order, so this costs\n * nothing on the hot path; a REJECT stops at the first false conjunct, so\n * pricing a `z.email()` behind the `kind` literal that actually discriminates\n * is what makes union probing and `.is()` misses cheap (see\n * estimateRuntimeCost). The SLOW path keeps declaration order — that one's\n * output is the issue list, whose order is part of zod parity.\n */\nfunction orderedProperties(ir: ObjectIR, g: FastGen): [string, SchemaIR][] {\n return orderByRuntimeCost(parsedProperties(ir), ([, propIR]) => propIR, g.ctx);\n}\n\n/**\n * Property/strict/refine fast-checks for an object, WITHOUT the leading\n * `typeof===object && !==null && !Array.isArray` type-guard. Returns the\n * conjunct parts (joinable with `&&`), or null if any child is fast-ineligible.\n *\n * `skipKey`, when given, omits that one property's check. Used by the\n * discriminated-union fast path (via `g.discSkipKey`): the enclosing `switch`\n * has already matched the discriminator's value, so re-checking it is redundant.\n */\nfunction fastObjectBody(ir: ObjectIR, g: FastGen, skipKey?: string): string[] | null {\n const x = g.input;\n const parts: string[] = [];\n const absentAccepts = new Set([...(ir.skipAbsentKeys ?? []), ...(ir.suppressAbsentKeys ?? [])]);\n const nonoptional = new Set(ir.nonoptionalKeys ?? []);\n\n for (const [key, propIR] of orderedProperties(ir, g)) {\n if (key === skipKey) continue;\n const keyStr = escapeString(key);\n const propCheck = g.visit(propIR, { input: `${x}[${keyStr}]` });\n if (propCheck === null) return null; // All-or-nothing\n // Presence rules keyed on the schema's `optin`/`optout` (see ObjectIR): a\n // required key must be there whatever its schema makes of `undefined`, and\n // an optional-out key on the \"optional\"/\"defaulted\" rungs is accepted when\n // it is not, whatever the property would say.\n if (nonoptional.has(key)) {\n parts.push(propCheck === \"true\" ? `${keyStr} in ${x}` : `${keyStr} in ${x}&&${propCheck}`);\n } else if (absentAccepts.has(key)) {\n parts.push(`(!(${keyStr} in ${x})||${propCheck})`);\n } else {\n parts.push(propCheck);\n }\n }\n\n // Strict unknown-key pass: hosted boolean helper (a for-in loop cannot live\n // in the && chain). Same for-in iteration as the slow path — fast/slow\n // agreement is load-bearing under the __zcFinD deferral. The membership set is\n // the FULL key list (the discriminator is a recognized key), independent of\n // skipKey, which only suppresses re-validating the discriminator's value.\n if (ir.strict) {\n const keys = Object.keys(ir.properties);\n const fnName = g.temp(\"so\");\n const test = keyMembershipTest(g.ctx, keys, \"k\");\n g.ctx.preamble.push(\n `function ${fnName}(o){for(var k in o){if(!(${test}))return false;}return true;}`,\n );\n parts.push(`${fnName}(${x})`);\n }\n\n // .catchall(schema): same hosted for-in as strict, but each unrecognized key\n // is checked against the catchall rather than rejected outright. The value is\n // hoisted into a local for the same reason fastRecord does it — repeated\n // `o[k]` computed loads are not eliminated across check boundaries.\n if (ir.catchall) {\n const kv = g.temp(\"cak\");\n const vv = g.temp(\"cav\");\n const catchallGen = g.scoped(vv);\n const valCheck = catchallGen.visit(ir.catchall, { input: vv });\n if (valCheck === null) return null;\n if (valCheck !== \"true\") {\n const fnName = g.temp(\"co\");\n const test = keyMembershipTest(g.ctx, Object.keys(ir.properties), kv);\n g.ctx.preamble.push(\n `function ${fnName}(o){${declareFastTemps(catchallGen.scope)}var ${kv},${vv};for(${kv} in o){if(!(${test})&&${kv}!==\"__proto__\"){${vv}=o[${kv}];if(!(${valCheck}))return false;}}return true;}`,\n );\n parts.push(`${fnName}(${x})`);\n }\n }\n\n // Object-level refine effects (appended last — run after property checks short-circuit)\n if (ir.checks) {\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\n return parts;\n}\n\nexport function fastObject(ir: ObjectIR, g: FastGen): string | null {\n // A strip object still gets an expression. Stripping reshapes the OUTPUT, not\n // the verdict, so this remains an exact acceptance predicate — which is what\n // `.is()` installs, and what the build path reuses to validate the subtrees it\n // passes through by reference. What it must NOT do is stand in for the parse\n // result: generateValidator withholds the `data:input` shortcut whenever the\n // schema rebuilds (see rebuildsOutput).\n const x = g.input;\n const body = fastObjectBody(ir, g, g.discSkipKey);\n if (body === null) return null;\n // Discriminated-union option: the enclosing switch (and the caller's guard)\n // already established object-ness and the discriminator value, so emit only\n // the remaining checks — no leading type-guard. An option with nothing left\n // to check accepts unconditionally (\"true\").\n if (g.discSkipKey !== undefined) {\n return body.length > 0 ? body.join(\"&&\") : \"true\";\n }\n return [`typeof ${x}===\"object\"`, `${x}!==null`, `!Array.isArray(${x})`, ...body].join(\"&&\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"object.js","names":[],"sources":["../../../../src/core/codegen/schemas/object.ts"],"sourcesContent":["import type { ObjectIR, SchemaIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport {\n declareFastTemps,\n emitRuntimeHelper,\n escapeString,\n extendPath,\n extendStaticPath,\n hasMutation,\n keyMembershipTest,\n outputAlwaysDefined,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, unrecognizedKeys } from \"../emit-issue.js\";\nimport { ZC_AB_DECL, ZC_PROTO_SCRUB_DECL } from \"../issue-decls.js\";\nimport { orderByRuntimeCost } from \"../fast-size.js\";\nimport { fastRefineTest, refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\n\n/**\n * The shape entries whose schemas actually RUN. `$ZodObject` skips a declared\n * `__proto__` key in its shape loop (`if (key === \"__proto__\") continue`), so\n * that property is never validated and never written to the output — it is\n * only a recognized name for the strict/catchall passes, which read\n * `Object.keys(ir.properties)` directly. Writing it would be worse than\n * pointless: `{__proto__: v}` in an object literal, and `o[\"__proto__\"] = v`\n * on a plain object, both SET THE PROTOTYPE rather than define a key.\n */\nexport function parsedProperties(ir: ObjectIR): [string, SchemaIR][] {\n return Object.entries(ir.properties).filter(([key]) => key !== \"__proto__\");\n}\n\nexport function slowObject(ir: SchemaIR & { type: \"object\" }, g: SlowGen): string {\n let code = emit`\n if(typeof ${g.input}!==\"object\"||${g.input}===null||Array.isArray(${g.input})){\n ${invalidType(g, \"object\")}\n }else{`;\n\n // zod parses every object into a FRESH `{}`: the shape keys land first, in\n // shape order (handlePropertyResult), and a loose or catchall object then\n // appends the unknown keys in the input's for-in order (handleCatchall).\n //\n // Two modes reproduce that. REBUILD assembles exactly that object: always\n // for strip mode (zod's default z.object() output is only the declared keys),\n // and for a loose, strict or catchall object whenever a property or the\n // catchall rewrites its value — a rewritten value has to land somewhere, and\n // a spread clone of the input (what this once did) put it at the wrong\n // position: the input's key order, with a substituted key appended last.\n // PASS-THROUGH hands the input back by reference when nothing rewrites\n // anything; identity, key order and inherited keys then ride along with it,\n // which is the documented container-identity divergence (see\n // known-divergences.test.ts).\n const strip = ir.stripUnknownKeys === true;\n const rebuild =\n strip ||\n (ir.catchall !== undefined && hasMutation(ir.catchall)) ||\n Object.values(ir.properties).some(hasMutation);\n const objVar = g.temp(\"o\");\n if (!rebuild) {\n code += `var ${objVar}=${g.input};`;\n // The pass-through output is the input, and an own `__proto__` must not\n // ride along on it where zod's fresh `{}` never receives the key. Scrub it\n // (see ZC_PROTO_SCRUB_DECL); a rebuilt object never copies the key in the\n // first place.\n const scrub = emitRuntimeHelper(g.ctx, \"__zcPs\", ZC_PROTO_SCRUB_DECL);\n code += `${objVar}=${scrub}(${objVar});`;\n }\n /**\n * Pass-through only: land a nested node's REPLACEMENT value on the output.\n * A pass-through property never rewrites its value (that is what\n * pass-through means), but a nested object or record can still hand back a\n * proto-scrubbed COPY of its input, and that copy has to reach the output\n * object — not the caller's object. Writing it straight into `objVar` did\n * exactly that when `objVar` was the input: the caller's own object was\n * edited in place (its nested value swapped for the copy), and a frozen\n * input threw \"Cannot assign to read only property\" out of `safeParse`. So\n * the output becomes a copy of its own the first time a replacement lands,\n * and only then. Spread is safe here: `objVar` is still the input only when\n * the scrub above found no own `__proto__` on it.\n */\n const handoff = (outVar: string, inVar: string, keyExpr: string): string =>\n `if(${outVar}!==${inVar}){if(${objVar}===${g.input}){${objVar}={...${g.input}};}${objVar}[${keyExpr}]=${outVar};}`;\n\n // Object-level refines are gated on zod's ABORT rule, not on \"did anything\n // fail\": zod parses the properties (plus the strict/catchall passes) into the\n // payload and then skips its check chain only when `util.aborted` holds — i.e.\n // when one of those issues is non-continuable. A property that failed its own\n // `min`/format check reports a CONTINUABLE issue, so the outer refine still\n // runs and both messages surface — and so does an unrecognized key, which zod\n // pushes with `continue: true`; a property that failed to parse at all\n // (`invalid_type`, a bad record key) aborts and suppresses it. Snapshot the\n // issue count before the properties so the scan covers exactly this node's\n // own parse, as zod's fresh sub-payload does.\n const refineMark = ir.checks && ir.checks.length > 0 ? g.temp(\"rm\") : \"\";\n if (refineMark) code += `var ${refineMark}=${g.issues}.length;`;\n\n const skipAbsent = new Set(ir.skipAbsentKeys ?? []);\n const suppressAbsent = new Set(ir.suppressAbsentKeys ?? []);\n const nonoptional = new Set(ir.nonoptionalKeys ?? []);\n /** Rebuild only: per-property output slot + whether it is always in the result. */\n const slots: { always: boolean; keyStr: string; value: string }[] = [];\n\n for (const [key, propIR] of parsedProperties(ir)) {\n const keyStr = escapeString(key);\n const propPath = extendStaticPath(g.path, key);\n // Every mode validates the value read from the ORIGINAL input, held in a\n // local. zod parses `input[key]` — a prototype-inclusive read — so a value\n // found on the prototype is accepted and, on a rebuild, copied out as an\n // own key. Reading through a spread clone, as the loose/strict/catchall\n // branch once did, turned such a value into `undefined` (spread copies own\n // keys only): the fast and build paths, which read `input[key]`, rejected\n // the input, this walk then found nothing wrong with it, and a strict\n // object came back as a failure with an EMPTY issue list. The local also\n // spares every check the megamorphic re-load of `o[key]` — the clone's map\n // changed with every key added.\n const propExpr = g.temp(\"sv\");\n code += `var ${propExpr}=${g.input}[${keyStr}];`;\n // A rebuild assembles the output from the local afterwards (in shape order,\n // below). A pass-through property is handed a slot of its own to write a\n // replacement into, which `handoff` then lands on the output.\n let outExpr = propExpr;\n if (rebuild) {\n slots.push({ always: outputAlwaysDefined(propIR), keyStr, value: propExpr });\n } else {\n outExpr = g.temp(\"ov\");\n code += `var ${outExpr}=${propExpr};`;\n }\n const propCode = g.visit(propIR, { input: propExpr, output: outExpr, path: propPath });\n // The three absent-key rules of zod's handlePropertyResult (see ObjectIR).\n // Presence is tested on the ORIGINAL input, as zod's `key in input` is —\n // a clone would hide an inherited key.\n //\n // The two rules that test presence AFTER running the property snapshot it\n // FIRST, exactly as zod reads `isPresent` before it looks at the result. A\n // property writes nowhere but its own local, so nothing it makes of\n // `undefined` can create the very key it is asked about (writing straight\n // into the output object once did that: `z.looseObject({a: z.custom()})` on\n // `{}` lost its `nonoptional` issue and left the caller's object carrying\n // an `a` zod never writes); dropping its value is resetting that local.\n const dropValue = rebuild ? `${propExpr}=undefined;` : `${outExpr}=${propExpr};`;\n if (skipAbsent.has(key)) {\n code += emit`if(${keyStr} in ${g.input}){${propCode}}`;\n } else if (suppressAbsent.has(key)) {\n // A defaulted optional-out property runs, but a failure on an absent key\n // is discarded whole: issues and whatever value it wrote before failing.\n const beforeVar = g.temp(\"ob\");\n const presentVar = g.temp(\"op\");\n code += emit`\n var ${presentVar}=${keyStr} in ${g.input};\n var ${beforeVar}=${g.issues}.length;\n ${propCode}\n if(!${presentVar}&&${g.issues}.length>${beforeVar}){\n ${g.issues}.length=${beforeVar};${dropValue}\n }`;\n } else if (nonoptional.has(key)) {\n // A required key that is absent fails as such when its schema raised\n // nothing for the `undefined` it saw. zod pushes this one without an\n // `inst`, so no schema-level message reaches it — and it returns without\n // assigning, so whatever the property made of `undefined` is dropped.\n const beforeVar = g.temp(\"ob\");\n const presentVar = g.temp(\"op\");\n code += emit`\n var ${presentVar}=${keyStr} in ${g.input};\n var ${beforeVar}=${g.issues}.length;\n ${propCode}\n if(!${presentVar}){\n ${dropValue}\n if(${g.issues}.length===${beforeVar}){\n ${invalidType(g, \"nonoptional\", { input: \"undefined\", path: propPath, codeFirst: true, useTypeMsg: false })}\n }\n }`;\n } else {\n code += propCode;\n }\n if (!rebuild) code += handoff(outExpr, propExpr, keyStr);\n }\n\n if (rebuild) {\n // Assemble the result in shape order (zod's key order), taking as long a\n // LEADING run of always-present keys as possible into one object literal:\n // V8 stamps a literal out of a cached boilerplate map in a single\n // allocation, where adding keys one at a time walks a transition chain and\n // re-checks the map on every store — measured 8.1x (20 keys) / 2.8x (7\n // keys, one optional) on the whole safeParse.\n //\n // Everything after the first conditional key is appended so insertion order\n // still matches zod. The per-key test is zod's own: keep the key when the\n // parsed value is defined, or when it was present on the input at all\n // (`key in input`, prototype included — an own `k: undefined` survives).\n const literal: string[] = [];\n let appends = \"\";\n let leading = true;\n for (const slot of slots) {\n if (leading && slot.always) {\n literal.push(`${slot.keyStr}:${slot.value}`);\n continue;\n }\n leading = false;\n appends += slot.always\n ? `${objVar}[${slot.keyStr}]=${slot.value};`\n : `if(${slot.value}!==undefined||(${slot.keyStr} in ${g.input})){${objVar}[${slot.keyStr}]=${slot.value};}`;\n }\n code += `var ${objVar}={${literal.join(\",\")}};${appends}`;\n\n // A rebuilt loose object then takes every unknown key, in the input's\n // for-in order — zod's handleCatchall running its `unknown` catchall, which\n // hands each value back as it is and assigns it as an own key, inherited\n // ones included. (A catchall with a schema does the same in its own pass\n // below; a strict object reports the keys instead.)\n if (!strip && !ir.strict && ir.catchall === undefined) {\n const kVar = g.temp(\"lk\");\n const test = keyMembershipTest(g.ctx, Object.keys(ir.properties), kVar);\n code += emit`\n for(var ${kVar} in ${g.input}){\n if(!(${test})&&${kVar}!==\"__proto__\"){${objVar}[${kVar}]=${g.input}[${kVar}];}\n }`;\n }\n }\n\n // Strict unknown-key pass — zod's handleCatchall, byte-exact: for-in over\n // the ORIGINAL input (inherited enumerable keys count, no hasOwnProperty),\n // ALL unknown keys collected into one issue, pushed AFTER property issues\n // and before object-level refines.\n if (ir.strict) {\n const keys = Object.keys(ir.properties);\n const ukVar = g.temp(\"uk\");\n const kVar = g.temp(\"k\");\n const test = keyMembershipTest(g.ctx, keys, kVar);\n code += emit`\n var ${ukVar}=null;\n for(var ${kVar} in ${g.input}){\n if(!(${test})){(${ukVar}=${ukVar}||[]).push(${kVar});}\n }\n if(${ukVar}!==null){\n ${unrecognizedKeys(g, ukVar)}\n }`;\n }\n\n // .catchall(schema): validate every key NOT in the shape, mirroring zod's\n // handleCatchall — same bare for-in over the ORIGINAL input as the strict\n // pass (inherited enumerable keys count, no hasOwnProperty guard), each\n // issue reported at the key. Runs after the properties, as zod does. An\n // undeclared `__proto__` is skipped like zod skips it: never validated, and\n // never assigned, since `o[\"__proto__\"]=v` on a plain object would replace\n // its prototype instead of adding a key. (The strict pass above still\n // REPORTS it — there it is an unknown key like any other.)\n //\n // On a rebuild each unknown key is copied onto the fresh output before it is\n // validated — which reproduces zod, whose fresh output object gains an OWN\n // key for every for-in key it saw, inherited ones included, whether or not\n // the catchall accepted its value. The key's slot is then BOTH the input and\n // the output, exactly as a shape property's local is: a value-rewriting\n // catchall (coerce, .trim(), a default) writes through the same expression\n // it later re-reads, so splitting them makes the rewrite invisible to its own\n // checks. A pass-through catchall writes nothing, so the object stays by\n // reference; it gets the same replacement slot a pass-through property does,\n // for the same reason.\n if (ir.catchall) {\n const keys = Object.keys(ir.properties);\n const kVar = g.temp(\"ck\");\n const test = keyMembershipTest(g.ctx, keys, kVar);\n const catchallPath = extendPath(g.path, kVar);\n let body: string;\n if (rebuild) {\n const slot = `${objVar}[${kVar}]`;\n body = `${slot}=${g.input}[${kVar}];${g.visit(ir.catchall, { input: slot, output: slot, path: catchallPath })}`;\n } else {\n const inVar = g.temp(\"cv\");\n const outVar = g.temp(\"co\");\n body =\n `var ${inVar}=${g.input}[${kVar}];var ${outVar}=${inVar};` +\n g.visit(ir.catchall, { input: inVar, output: outVar, path: catchallPath }) +\n handoff(outVar, inVar, kVar);\n }\n code += emit`\n for(var ${kVar} in ${g.input}){\n if(!(${test})&&${kVar}!==\"__proto__\"){${body}}\n }`;\n }\n\n // Always written back: a rebuild is a fresh object, and a pass-through may\n // have become a copy (the scrub above, or a handoff) even where nothing\n // rewrote a value.\n code += `${g.output}=${objVar};`;\n\n // Object-level refine effects: z.object({...}).refine(fn), suppressed when the\n // parse phase aborted (see refineMark). One gate covers every effect: each of\n // them can only add a continuable `custom` issue, so zod's per-check\n // re-evaluation of `isAborted` can never flip between them.\n if (ir.checks && ir.checks.length > 0) {\n let refines = \"\";\n for (const check of ir.checks) {\n refines +=\n check.kind === \"super_refine_effect\"\n ? superRefineCheck(check, objVar, g)\n : refineCheck(check, objVar, g);\n }\n const aborted = emitRuntimeHelper(g.ctx, \"__zcAb\", ZC_AB_DECL);\n code += `if(!${aborted}(${g.issues},${refineMark})){${refines}}`;\n }\n\n code += `}\\n`;\n return code;\n}\n\n/**\n * Property entries in the order their fast-checks should be `&&`-chained:\n * cheapest first, declaration order preserved among equals (Array#sort is\n * stable). Valid input runs every conjunct whatever the order, so this costs\n * nothing on the hot path; a REJECT stops at the first false conjunct, so\n * pricing a `z.email()` behind the `kind` literal that actually discriminates\n * is what makes union probing and `.is()` misses cheap (see\n * estimateRuntimeCost). The SLOW path keeps declaration order — that one's\n * output is the issue list, whose order is part of zod parity.\n */\nfunction orderedProperties(ir: ObjectIR, g: FastGen): [string, SchemaIR][] {\n return orderByRuntimeCost(parsedProperties(ir), ([, propIR]) => propIR, g.ctx);\n}\n\n/**\n * Property/strict/refine fast-checks for an object, WITHOUT the leading\n * `typeof===object && !==null && !Array.isArray` type-guard. Returns the\n * conjunct parts (joinable with `&&`), or null if any child is fast-ineligible.\n *\n * `skipKey`, when given, omits that one property's check. Used by the\n * discriminated-union fast path (via `g.discSkipKey`): the enclosing `switch`\n * has already matched the discriminator's value, so re-checking it is redundant.\n */\nfunction fastObjectBody(ir: ObjectIR, g: FastGen, skipKey?: string): string[] | null {\n const x = g.input;\n const parts: string[] = [];\n const absentAccepts = new Set([...(ir.skipAbsentKeys ?? []), ...(ir.suppressAbsentKeys ?? [])]);\n const nonoptional = new Set(ir.nonoptionalKeys ?? []);\n\n for (const [key, propIR] of orderedProperties(ir, g)) {\n if (key === skipKey) continue;\n const keyStr = escapeString(key);\n const propCheck = g.visit(propIR, { input: `${x}[${keyStr}]` });\n if (propCheck === null) return null; // All-or-nothing\n // Presence rules keyed on the schema's `optin`/`optout` (see ObjectIR): a\n // required key must be there whatever its schema makes of `undefined`, and\n // an optional-out key on the \"optional\"/\"defaulted\" rungs is accepted when\n // it is not, whatever the property would say.\n if (nonoptional.has(key)) {\n parts.push(propCheck === \"true\" ? `${keyStr} in ${x}` : `${keyStr} in ${x}&&${propCheck}`);\n } else if (absentAccepts.has(key)) {\n parts.push(`(!(${keyStr} in ${x})||${propCheck})`);\n } else {\n parts.push(propCheck);\n }\n }\n\n // Strict unknown-key pass: hosted boolean helper (a for-in loop cannot live\n // in the && chain). Same for-in iteration as the slow path — fast/slow\n // agreement is load-bearing under the __zcFinD deferral. The membership set is\n // the FULL key list (the discriminator is a recognized key), independent of\n // skipKey, which only suppresses re-validating the discriminator's value.\n if (ir.strict) {\n const keys = Object.keys(ir.properties);\n const fnName = g.temp(\"so\");\n const test = keyMembershipTest(g.ctx, keys, \"k\");\n g.ctx.preamble.push(\n `function ${fnName}(o){for(var k in o){if(!(${test}))return false;}return true;}`,\n );\n parts.push(`${fnName}(${x})`);\n }\n\n // .catchall(schema): same hosted for-in as strict, but each unrecognized key\n // is checked against the catchall rather than rejected outright. The value is\n // hoisted into a local for the same reason fastRecord does it — repeated\n // `o[k]` computed loads are not eliminated across check boundaries.\n if (ir.catchall) {\n const kv = g.temp(\"cak\");\n const vv = g.temp(\"cav\");\n const catchallGen = g.scoped(vv);\n const valCheck = catchallGen.visit(ir.catchall, { input: vv });\n if (valCheck === null) return null;\n if (valCheck !== \"true\") {\n const fnName = g.temp(\"co\");\n const test = keyMembershipTest(g.ctx, Object.keys(ir.properties), kv);\n g.ctx.preamble.push(\n `function ${fnName}(o){${declareFastTemps(catchallGen.scope)}var ${kv},${vv};for(${kv} in o){if(!(${test})&&${kv}!==\"__proto__\"){${vv}=o[${kv}];if(!(${valCheck}))return false;}}return true;}`,\n );\n parts.push(`${fnName}(${x})`);\n }\n }\n\n // Object-level refine effects (appended last — run after property checks short-circuit)\n if (ir.checks) {\n for (const check of ir.checks) {\n if (check.kind === \"refine_effect\") {\n parts.push(fastRefineTest(check, x, g));\n } else if (check.kind === \"super_refine_effect\") {\n parts.push(superRefineFastTest(check, x, g));\n }\n }\n }\n\n return parts;\n}\n\nexport function fastObject(ir: ObjectIR, g: FastGen): string | null {\n // A strip object still gets an expression. Stripping reshapes the OUTPUT, not\n // the verdict, so this remains an exact acceptance predicate — which is what\n // `.is()` installs, and what the build path reuses to validate the subtrees it\n // passes through by reference. What it must NOT do is stand in for the parse\n // result: generateValidator withholds the `data:input` shortcut whenever the\n // schema rebuilds (see rebuildsOutput).\n const x = g.input;\n const body = fastObjectBody(ir, g, g.discSkipKey);\n if (body === null) return null;\n // Discriminated-union option: the enclosing switch (and the caller's guard)\n // already established object-ness and the discriminator value, so emit only\n // the remaining checks — no leading type-guard. An option with nothing left\n // to check accepts unconditionally (\"true\").\n if (g.discSkipKey !== undefined) {\n return body.length > 0 ? body.join(\"&&\") : \"true\";\n }\n return [`typeof ${x}===\"object\"`, `${x}!==null`, `!Array.isArray(${x})`, ...body].join(\"&&\");\n}\n"],"mappings":"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"}
@@ -1 +1 @@
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
+ {"version":3,"file":"string.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/string.ts"],"mappings":";;;iBA0GgB,WAAW,IAAI,UAAU,GAAG;;;;;;;;;;;iBAmK5B,gBAAgB,OAAO,SAAS,WAAW,KAAK;iBAuDhD,WAAW,IAAI,UAAU,GAAG"}
@@ -1,9 +1,9 @@
1
1
  import { EMAIL_REGEX_SOURCE, fastTestSource, isDefaultEmailPattern } from "../well-known-regex.js";
2
- import { checkPriority, emitEffectCallable, emitEffectFn, emitRegex, emitRegexSourceString, emitRuntimeHelper, escapeString } from "../context.js";
2
+ import { checkPriority, 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
5
  import { ZC_EMAIL_DECL } from "../issue-decls.js";
6
- import { refineCheck, superRefineCheck, superRefineFastTest } from "./effect.js";
6
+ import { fastRefineTest, refineCheck, superRefineCheck, superRefineFastTest } from "./effect.js";
7
7
  import { stringLengthTests, whenGatedSizeChecks } from "./sizeable.js";
8
8
  //#region src/core/codegen/schemas/string.ts
9
9
  /** `re.lastIndex=0;` reset statement for stateful (g/y-flagged) regexes. */
@@ -254,7 +254,7 @@ function fastString(ir, g) {
254
254
  if (expr === null) return null;
255
255
  parts.push(expr);
256
256
  }
257
- for (const check of ir.checks) if (check.kind === "refine_effect") parts.push(`${emitEffectCallable(g.ctx, check)}(${x})`);
257
+ for (const check of ir.checks) if (check.kind === "refine_effect") parts.push(fastRefineTest(check, x, g));
258
258
  else if (check.kind === "super_refine_effect") parts.push(superRefineFastTest(check, x, g));
259
259
  return parts.join("&&");
260
260
  }
@@ -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 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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"}
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 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 { fastRefineTest, 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(fastRefineTest(check, x, g));\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":";;;;;;;;;AAuBA,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,SAAS;IACX,OAAO,IAAI,MAAM,WAAW,WAAW,MAAM,SAAS;KACpD,UAAU,MAAM;KAChB,SAAS;IACX,OAAO,IAAI,MAAM,WAAW,QAAQ;KAClC,UAAU,MAAM,WAAA;KAChB,SAAS;IACX,OACE,IAAI,MAAM,SAAS;KACjB,UAAU,MAAM;KAChB,SAAS;IACX,OAGE;IAMJ,MAAM,UAAU,sBAAsB,SAAS,MAAM,YAAY,IAC7D,kBAAkB,EAAE,KAAK,aAAa,aAAa,IACnD;IACJ,MAAM,WAAW,YAAY,OAAO,EAAE,MAAM,QAAQ,SAAS,MAAM,YAAY,IAAI;IASnF,IAAI;IACJ,IAAI,CAAC,MAAM,WAWT,QAAQ,WALU,CAAC,MAAM,gBAAgB,eAAe,OAAO,MAAM,QAEtD,aAAa,OACtB,sBAAsB,EAAE,KAAK,OAAO,IACpC,GAAG,SAAS;IAGpB,MAAM,OACJ,aAAa,OAAO,GAAG,QAAQ,GAAG,EAAE,MAAM,KAAK,GAAG,SAAS,QAAQ,EAAE,MAAM;IAC7E,QAAQ,IAAI;cACR,aAAa,OAAO,KAAK,eAAe,UAAU,MAAM,YAAY,EAAE;kBAClE,KAAK;gBACP,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;GAIT,IAAI,sBAAsB,SAAS,MAAM,YAAY,GACnD,OAAO,GAAG,kBAAkB,KAAK,aAAa,aAAa,EAAE,GAAG,EAAE;GAEpE,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,eAAe,OAAO,GAAG,CAAC,CAAC;MACjC,IAAI,MAAM,SAAS,uBACxB,MAAM,KAAK,oBAAoB,OAAO,GAAG,CAAC,CAAC;CAI/C,OAAO,MAAM,KAAK,IAAI;AACxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"template-literal.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"mappings":";;;iBAOgB,oBAAoB,IAAI,mBAAmB,GAAG;iBAyB9C,oBAAoB,IAAI,mBAAmB,GAAG"}
1
+ {"version":3,"file":"template-literal.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"mappings":";;;iBAOgB,oBAAoB,IAAI,mBAAmB,GAAG;iBAgC9C,oBAAoB,IAAI,mBAAmB,GAAG"}
@@ -10,7 +10,7 @@ function slowTemplateLiteral(ir, g) {
10
10
  if(typeof ${g.input}!=="string"){
11
11
  ${invalidType(g, "string")}
12
12
  }else if(!${regexVar}.test(${g.input})){
13
- ${invalidFormat(g, "template_literal", { extra: `pattern:${patternExpr}` })}
13
+ ${invalidFormat(g, "template_literal", { extra: `pattern:${patternExpr},continue:false` })}
14
14
  }`}\n`;
15
15
  }
16
16
  function fastTemplateLiteral(ir, g) {
@@ -1 +1 @@
1
- {"version":3,"file":"template-literal.js","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"sourcesContent":["import type { TemplateLiteralIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { emitConstant, escapeString } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidFormat, invalidType } from \"../emit-issue.js\";\nimport { fastTestSource } from \"../well-known-regex.js\";\n\nexport function slowTemplateLiteral(ir: TemplateLiteralIR, g: SlowGen): string {\n const regexVar = g.regex(\"tl\", ir.pattern);\n // $ZodTemplateLiteral reports `pattern: inst._zod.pattern.source` — the BARE\n // source, with no enclosing slashes. That is the opposite of every string\n // FORMAT check, which zod reports as `def.pattern.toString()`; the shared\n // emitRegexSourceString helper (and its `<name>Src` virtual exports) produces\n // the slash-wrapped form for those, so it cannot serve this site.\n //\n // Same rewrite rule as slowString though: when emitRegex swapped in a faster\n // equivalent pattern, the runtime regex's own `.source` would leak the\n // rewrite, so the ORIGINAL source is emitted as a constant instead. IR\n // `pattern` IS a `.source` string (see extractTemplateLiteral), so it is\n // byte-identical to what zod reads.\n const patternExpr =\n fastTestSource(ir.pattern) === null\n ? `${regexVar}.source`\n : emitConstant(g.ctx, \"tls\", escapeString(ir.pattern));\n return `${emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n }else if(!${regexVar}.test(${g.input})){\n ${invalidFormat(g, \"template_literal\", { extra: `pattern:${patternExpr}` })}\n }`}\\n`;\n}\n\nexport function fastTemplateLiteral(ir: TemplateLiteralIR, g: FastGen): string | null {\n const regexVar = g.regex(\"tl\", ir.pattern);\n return `typeof ${g.input}===\"string\"&&${regexVar}.test(${g.input})`;\n}\n"],"mappings":";;;;;AAOA,SAAgB,oBAAoB,IAAuB,GAAoB;CAC7E,MAAM,WAAW,EAAE,MAAM,MAAM,GAAG,OAAO;CAYzC,MAAM,cACJ,eAAe,GAAG,OAAO,MAAM,OAC3B,GAAG,SAAS,WACZ,aAAa,EAAE,KAAK,OAAO,aAAa,GAAG,OAAO,CAAC;CACzD,OAAO,GAAG,IAAI;gBACA,EAAE,MAAM;QAChB,YAAY,GAAG,QAAQ,EAAE;gBACjB,SAAS,QAAQ,EAAE,MAAM;QACjC,cAAc,GAAG,oBAAoB,EAAE,OAAO,WAAW,cAAc,CAAC,EAAE;OAC3E;AACP;AAEA,SAAgB,oBAAoB,IAAuB,GAA2B;CACpF,MAAM,WAAW,EAAE,MAAM,MAAM,GAAG,OAAO;CACzC,OAAO,UAAU,EAAE,MAAM,eAAe,SAAS,QAAQ,EAAE,MAAM;AACnE"}
1
+ {"version":3,"file":"template-literal.js","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"sourcesContent":["import type { TemplateLiteralIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { emitConstant, escapeString } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidFormat, invalidType } from \"../emit-issue.js\";\nimport { fastTestSource } from \"../well-known-regex.js\";\n\nexport function slowTemplateLiteral(ir: TemplateLiteralIR, g: SlowGen): string {\n const regexVar = g.regex(\"tl\", ir.pattern);\n // $ZodTemplateLiteral reports `pattern: inst._zod.pattern.source` — the BARE\n // source, with no enclosing slashes. That is the opposite of every string\n // FORMAT check, which zod reports as `def.pattern.toString()`; the shared\n // emitRegexSourceString helper (and its `<name>Src` virtual exports) produces\n // the slash-wrapped form for those, so it cannot serve this site.\n //\n // Same rewrite rule as slowString though: when emitRegex swapped in a faster\n // equivalent pattern, the runtime regex's own `.source` would leak the\n // rewrite, so the ORIGINAL source is emitted as a constant instead. IR\n // `pattern` IS a `.source` string (see extractTemplateLiteral), so it is\n // byte-identical to what zod reads.\n const patternExpr =\n fastTestSource(ir.pattern) === null\n ? `${regexVar}.source`\n : emitConstant(g.ctx, \"tls\", escapeString(ir.pattern));\n // The issue is pushed by the NODE (`$ZodTemplateLiteral._zod.parse`), not by\n // a `$ZodCheck`, so zod's carries no `continue: true` and `util.aborted`\n // counts it as aborting: a union option that fails only here goes inside\n // `invalid_union` rather than being surfaced as the sole non-aborted option,\n // and a container's `.refine()` does not run after it. Every other\n // `invalid_format` is check-raised and continuable, so the marker is set here\n // rather than in the shared factory; the finalizer deletes it, as zod's does.\n return `${emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n }else if(!${regexVar}.test(${g.input})){\n ${invalidFormat(g, \"template_literal\", { extra: `pattern:${patternExpr},continue:false` })}\n }`}\\n`;\n}\n\nexport function fastTemplateLiteral(ir: TemplateLiteralIR, g: FastGen): string | null {\n const regexVar = g.regex(\"tl\", ir.pattern);\n return `typeof ${g.input}===\"string\"&&${regexVar}.test(${g.input})`;\n}\n"],"mappings":";;;;;AAOA,SAAgB,oBAAoB,IAAuB,GAAoB;CAC7E,MAAM,WAAW,EAAE,MAAM,MAAM,GAAG,OAAO;CAYzC,MAAM,cACJ,eAAe,GAAG,OAAO,MAAM,OAC3B,GAAG,SAAS,WACZ,aAAa,EAAE,KAAK,OAAO,aAAa,GAAG,OAAO,CAAC;CAQzD,OAAO,GAAG,IAAI;gBACA,EAAE,MAAM;QAChB,YAAY,GAAG,QAAQ,EAAE;gBACjB,SAAS,QAAQ,EAAE,MAAM;QACjC,cAAc,GAAG,oBAAoB,EAAE,OAAO,WAAW,YAAY,iBAAiB,CAAC,EAAE;OAC1F;AACP;AAEA,SAAgB,oBAAoB,IAAuB,GAA2B;CACpF,MAAM,WAAW,EAAE,MAAM,MAAM,GAAG,OAAO;CACzC,OAAO,UAAU,EAAE,MAAM,eAAe,SAAS,QAAQ,EAAE,MAAM;AACnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/core/extract/index.ts"],"mappings":";;;;;;;;;iBAYgB,cAAc,oBAAoB,OAAO,aAAa"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/core/extract/index.ts"],"mappings":";;;;;;;;;iBAagB,cAAc,oBAAoB,OAAO,aAAa"}
@@ -1,3 +1,4 @@
1
+ import { assertSupportedZod } from "./zod-version.js";
1
2
  import { dispatch } from "./registry.js";
2
3
  //#region src/core/extract/index.ts
3
4
  /**
@@ -7,6 +8,7 @@ import { dispatch } from "./registry.js";
7
8
  * access paths for partial fallback (Zod delegation at runtime).
8
9
  */
9
10
  function extractSchema(zodSchema, refs) {
11
+ assertSupportedZod(zodSchema);
10
12
  return dispatch(zodSchema, "", refs, /* @__PURE__ */ new Set(), {
11
13
  root: zodSchema,
12
14
  targets: /* @__PURE__ */ new Map(),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/extract/index.ts"],"sourcesContent":["import type { SchemaIR } from \"../types.js\";\nimport { dispatch } from \"./registry.js\";\nimport type { RecursionState, RefEntry } from \"./types.js\";\n\nexport type { RefEntry } from \"./types.js\";\n\n/**\n * Extract SchemaIR from a Zod schema by traversing its `_zod.def` and `_zod.bag`.\n *\n * When `fallbacks` is provided, non-compilable sub-schemas are collected with their\n * access paths for partial fallback (Zod delegation at runtime).\n */\nexport function extractSchema(zodSchema: unknown, refs?: RefEntry[]): SchemaIR {\n // Path, cycle-detection set, and recursion bookkeeping are internal to one\n // extraction — recursion re-enters through dispatch()/ctx.visit(), never back\n // through extractSchema — so they're always seeded fresh here.\n const rec: RecursionState = {\n root: zodSchema,\n targets: new Map<unknown, number>(),\n next: 1,\n };\n return dispatch(zodSchema, \"\", refs, new Set<unknown>(), rec);\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,cAAc,WAAoB,MAA6B;CAS7E,OAAO,SAAS,WAAW,IAAI,sBAAM,IAAI,IAAa,GAAG;EAJvD,MAAM;EACN,yBAAS,IAAI,IAAqB;EAClC,MAAM;CAEmD,CAAC;AAC9D"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/core/extract/index.ts"],"sourcesContent":["import type { SchemaIR } from \"../types.js\";\nimport { dispatch } from \"./registry.js\";\nimport type { RecursionState, RefEntry } from \"./types.js\";\nimport { assertSupportedZod } from \"./zod-version.js\";\n\nexport type { RefEntry } from \"./types.js\";\n\n/**\n * Extract SchemaIR from a Zod schema by traversing its `_zod.def` and `_zod.bag`.\n *\n * When `fallbacks` is provided, non-compilable sub-schemas are collected with their\n * access paths for partial fallback (Zod delegation at runtime).\n */\nexport function extractSchema(zodSchema: unknown, refs?: RefEntry[]): SchemaIR {\n // Refuse a zod whose semantics the emitted code does not reproduce (see\n // zod-version.ts). Once, at the root: every entry point reaches extraction\n // through here, and a schema's subtree comes from the same zod copy as its\n // root does.\n assertSupportedZod(zodSchema);\n // Path, cycle-detection set, and recursion bookkeeping are internal to one\n // extraction — recursion re-enters through dispatch()/ctx.visit(), never back\n // through extractSchema — so they're always seeded fresh here.\n const rec: RecursionState = {\n root: zodSchema,\n targets: new Map<unknown, number>(),\n next: 1,\n };\n return dispatch(zodSchema, \"\", refs, new Set<unknown>(), rec);\n}\n"],"mappings":";;;;;;;;;AAaA,SAAgB,cAAc,WAAoB,MAA6B;CAK7E,mBAAmB,SAAS;CAS5B,OAAO,SAAS,WAAW,IAAI,sBAAM,IAAI,IAAa,GAAG;EAJvD,MAAM;EACN,yBAAS,IAAI,IAAqB;EAClC,MAAM;CAEmD,CAAC;AAC9D"}
@@ -0,0 +1,78 @@
1
+ //#region src/core/extract/zod-version.d.ts
2
+ /**
3
+ * The zod release a schema was built by, and whether this compiler can stand
4
+ * in for it.
5
+ *
6
+ * Compiled validators reproduce zod 4.5's semantics byte-for-byte: the
7
+ * absent-key `expected: "nonoptional"` rule that 4.4 introduced, the
8
+ * code-point string lengths and tuple issue order of 4.5, the 4.5 format
9
+ * regexes. That fidelity is the contract, and it cuts both ways — a validator
10
+ * compiled here but installed on a schema from zod 4.3 accepts and rejects
11
+ * differently from the zod the application actually calls everywhere else,
12
+ * with nothing to say so. The peer range (`^4.5.0`) is meant to prevent that
13
+ * pairing, but only npm treats a violated peer range as an error; pnpm, yarn
14
+ * and bun warn and install anyway. This guard is the second line: one check at
15
+ * the root of extraction, which every entry point (CLI, build plugin, register
16
+ * hook, `jit()`) passes through, so an unsupported zod is refused with an
17
+ * explanation instead of compiled into subtly different validators.
18
+ *
19
+ * The version is read off the SCHEMA INSTANCE — `_zod.version`, which
20
+ * `$ZodType.init` stamps on every schema, classic and mini alike, since 4.0 —
21
+ * rather than off an imported zod module. A project can hold two zod copies
22
+ * (a hoisted one and a nested one, or a build-time and a runtime one), and the
23
+ * copy that built the schema is the one whose semantics its validator must
24
+ * match. A schema with no version at all is refused too: every zod 4 stamps
25
+ * one, so its absence means a zod older than this compiler has ever targeted.
26
+ * A value that is not a zod schema in the first place (no `_zod.def`) is not
27
+ * this guard's to judge — extraction reports it the way it always has, and
28
+ * calling it a version problem would send the user chasing the wrong fix.
29
+ */
30
+ /** Lowest zod release whose semantics the emitted validators reproduce. */
31
+ declare const MIN_ZOD_VERSION: {
32
+ readonly major: 4;
33
+ readonly minor: 5;
34
+ };
35
+ interface ZodVersion {
36
+ major: number;
37
+ minor: number;
38
+ patch: number;
39
+ }
40
+ /**
41
+ * `name` of the error {@link assertSupportedZod} throws. Matched by name, not
42
+ * by identity, so a second copy of this module in the graph still recognises it.
43
+ */
44
+ declare const UNSUPPORTED_ZOD_VERSION_ERROR = "UnsupportedZodVersionError";
45
+ /** The `_zod.version` a schema carries, or `undefined` when it has none (or is not a schema). */
46
+ declare function zodVersionOf(schema: unknown): ZodVersion | undefined;
47
+ /**
48
+ * Within the peer range: the same major, at or past the minimum minor. A
49
+ * hypothetical zod 5 is refused as well — its semantics are unknown here, and
50
+ * the promise is exactness, not best effort.
51
+ */
52
+ declare function isSupportedZodVersion(version: ZodVersion | undefined): boolean;
53
+ declare function unsupportedZodVersionMessage(version: ZodVersion | undefined): string;
54
+ /**
55
+ * Throw a recognisable error (see {@link isUnsupportedZodVersionError}) when
56
+ * `schema` is a zod schema from an unsupported zod. Anything that is not a zod
57
+ * schema at all passes through untouched, for the caller's own error path.
58
+ */
59
+ declare function assertSupportedZod(schema: unknown): void;
60
+ /**
61
+ * The predicate's target is deliberately narrower than `Error`: a caller that
62
+ * already holds an `Error` keeps it on the negative branch (a bare `error is
63
+ * Error` would leave `never` there).
64
+ */
65
+ declare function isUnsupportedZodVersionError(error: unknown): error is Error & {
66
+ name: typeof UNSUPPORTED_ZOD_VERSION_ERROR;
67
+ };
68
+ /**
69
+ * Print the refusal once per process. Every schema in an application fails the
70
+ * guard the same way, so one explanation is the useful amount — and the paths
71
+ * that call this (`jit()` at module scope, the plugin's per-export failure
72
+ * hook, the hoist compiler's catch-all) would otherwise either say nothing or
73
+ * say it once per export.
74
+ */
75
+ declare function warnUnsupportedZodOnce(message: string): void;
76
+ //#endregion
77
+ export { MIN_ZOD_VERSION, UNSUPPORTED_ZOD_VERSION_ERROR, ZodVersion, assertSupportedZod, isSupportedZodVersion, isUnsupportedZodVersionError, unsupportedZodVersionMessage, warnUnsupportedZodOnce, zodVersionOf };
78
+ //# sourceMappingURL=zod-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-version.d.ts","names":[],"sources":["../../../src/core/extract/zod-version.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgCa;WAAA;WAAA;;UAEI;EACf;EACA;EACA;;;;;;cAOW;;iBAGG,aAAa,kBAAkB;;;;;;iBAuB/B,sBAAsB,SAAS;iBAQ/B,6BAA6B,SAAS;;;;;;iBAoBtC,mBAAmB;;;;;;iBAcnB,6BACd,iBACC,SAAS;EAAU,aAAa;;;;;;;;;iBAcnB,uBAAuB"}
@@ -0,0 +1,109 @@
1
+ import { isZodSchema } from "../../is-zod-schema.js";
2
+ //#region src/core/extract/zod-version.ts
3
+ /**
4
+ * The zod release a schema was built by, and whether this compiler can stand
5
+ * in for it.
6
+ *
7
+ * Compiled validators reproduce zod 4.5's semantics byte-for-byte: the
8
+ * absent-key `expected: "nonoptional"` rule that 4.4 introduced, the
9
+ * code-point string lengths and tuple issue order of 4.5, the 4.5 format
10
+ * regexes. That fidelity is the contract, and it cuts both ways — a validator
11
+ * compiled here but installed on a schema from zod 4.3 accepts and rejects
12
+ * differently from the zod the application actually calls everywhere else,
13
+ * with nothing to say so. The peer range (`^4.5.0`) is meant to prevent that
14
+ * pairing, but only npm treats a violated peer range as an error; pnpm, yarn
15
+ * and bun warn and install anyway. This guard is the second line: one check at
16
+ * the root of extraction, which every entry point (CLI, build plugin, register
17
+ * hook, `jit()`) passes through, so an unsupported zod is refused with an
18
+ * explanation instead of compiled into subtly different validators.
19
+ *
20
+ * The version is read off the SCHEMA INSTANCE — `_zod.version`, which
21
+ * `$ZodType.init` stamps on every schema, classic and mini alike, since 4.0 —
22
+ * rather than off an imported zod module. A project can hold two zod copies
23
+ * (a hoisted one and a nested one, or a build-time and a runtime one), and the
24
+ * copy that built the schema is the one whose semantics its validator must
25
+ * match. A schema with no version at all is refused too: every zod 4 stamps
26
+ * one, so its absence means a zod older than this compiler has ever targeted.
27
+ * A value that is not a zod schema in the first place (no `_zod.def`) is not
28
+ * this guard's to judge — extraction reports it the way it always has, and
29
+ * calling it a version problem would send the user chasing the wrong fix.
30
+ */
31
+ /** Lowest zod release whose semantics the emitted validators reproduce. */
32
+ const MIN_ZOD_VERSION = {
33
+ major: 4,
34
+ minor: 5
35
+ };
36
+ /**
37
+ * `name` of the error {@link assertSupportedZod} throws. Matched by name, not
38
+ * by identity, so a second copy of this module in the graph still recognises it.
39
+ */
40
+ const UNSUPPORTED_ZOD_VERSION_ERROR = "UnsupportedZodVersionError";
41
+ /** The `_zod.version` a schema carries, or `undefined` when it has none (or is not a schema). */
42
+ function zodVersionOf(schema) {
43
+ if (typeof schema !== "object" || schema === null) return void 0;
44
+ try {
45
+ const internal = schema._zod;
46
+ if (typeof internal !== "object" || internal === null) return void 0;
47
+ const version = internal.version;
48
+ if (typeof version !== "object" || version === null) return void 0;
49
+ const { major, minor, patch } = version;
50
+ if (typeof major !== "number" || typeof minor !== "number" || typeof patch !== "number") return;
51
+ return {
52
+ major,
53
+ minor,
54
+ patch
55
+ };
56
+ } catch {
57
+ return;
58
+ }
59
+ }
60
+ /**
61
+ * Within the peer range: the same major, at or past the minimum minor. A
62
+ * hypothetical zod 5 is refused as well — its semantics are unknown here, and
63
+ * the promise is exactness, not best effort.
64
+ */
65
+ function isSupportedZodVersion(version) {
66
+ return version !== void 0 && version.major === MIN_ZOD_VERSION.major && version.minor >= MIN_ZOD_VERSION.minor;
67
+ }
68
+ function unsupportedZodVersionMessage(version) {
69
+ return `Unsupported zod version: this schema was built by ${version === void 0 ? "a zod that carries no _zod.version (older than 4.0, or not a zod schema)" : `zod ${version.major}.${version.minor}.${version.patch}`}, and this zod-compiler release requires zod ${`^${MIN_ZOD_VERSION.major}.${MIN_ZOD_VERSION.minor}.0`}. Compiled validators reproduce zod ${MIN_ZOD_VERSION.major}.${MIN_ZOD_VERSION.minor}'s semantics exactly (the absent-key \`expected: "nonoptional"\` rule, code-point string lengths, tuple issue order), so an older zod would accept and reject differently from the validator compiled for it. Upgrade zod to ${MIN_ZOD_VERSION.major}.${MIN_ZOD_VERSION.minor} or later, or stay on zod-compiler 1.x.`;
70
+ }
71
+ /**
72
+ * Throw a recognisable error (see {@link isUnsupportedZodVersionError}) when
73
+ * `schema` is a zod schema from an unsupported zod. Anything that is not a zod
74
+ * schema at all passes through untouched, for the caller's own error path.
75
+ */
76
+ function assertSupportedZod(schema) {
77
+ if (!isZodSchema(schema)) return;
78
+ const version = zodVersionOf(schema);
79
+ if (isSupportedZodVersion(version)) return;
80
+ const error = new Error(unsupportedZodVersionMessage(version));
81
+ error.name = UNSUPPORTED_ZOD_VERSION_ERROR;
82
+ throw error;
83
+ }
84
+ /**
85
+ * The predicate's target is deliberately narrower than `Error`: a caller that
86
+ * already holds an `Error` keeps it on the negative branch (a bare `error is
87
+ * Error` would leave `never` there).
88
+ */
89
+ function isUnsupportedZodVersionError(error) {
90
+ return error instanceof Error && error.name === "UnsupportedZodVersionError";
91
+ }
92
+ /** Messages already printed by {@link warnUnsupportedZodOnce}, per process. */
93
+ const warned = /* @__PURE__ */ new Set();
94
+ /**
95
+ * Print the refusal once per process. Every schema in an application fails the
96
+ * guard the same way, so one explanation is the useful amount — and the paths
97
+ * that call this (`jit()` at module scope, the plugin's per-export failure
98
+ * hook, the hoist compiler's catch-all) would otherwise either say nothing or
99
+ * say it once per export.
100
+ */
101
+ function warnUnsupportedZodOnce(message) {
102
+ if (warned.has(message)) return;
103
+ warned.add(message);
104
+ console.warn(`[zod-compiler] ${message}`);
105
+ }
106
+ //#endregion
107
+ export { MIN_ZOD_VERSION, UNSUPPORTED_ZOD_VERSION_ERROR, assertSupportedZod, isSupportedZodVersion, isUnsupportedZodVersionError, unsupportedZodVersionMessage, warnUnsupportedZodOnce, zodVersionOf };
108
+
109
+ //# sourceMappingURL=zod-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-version.js","names":[],"sources":["../../../src/core/extract/zod-version.ts"],"sourcesContent":["/**\n * The zod release a schema was built by, and whether this compiler can stand\n * in for it.\n *\n * Compiled validators reproduce zod 4.5's semantics byte-for-byte: the\n * absent-key `expected: \"nonoptional\"` rule that 4.4 introduced, the\n * code-point string lengths and tuple issue order of 4.5, the 4.5 format\n * regexes. That fidelity is the contract, and it cuts both ways — a validator\n * compiled here but installed on a schema from zod 4.3 accepts and rejects\n * differently from the zod the application actually calls everywhere else,\n * with nothing to say so. The peer range (`^4.5.0`) is meant to prevent that\n * pairing, but only npm treats a violated peer range as an error; pnpm, yarn\n * and bun warn and install anyway. This guard is the second line: one check at\n * the root of extraction, which every entry point (CLI, build plugin, register\n * hook, `jit()`) passes through, so an unsupported zod is refused with an\n * explanation instead of compiled into subtly different validators.\n *\n * The version is read off the SCHEMA INSTANCE — `_zod.version`, which\n * `$ZodType.init` stamps on every schema, classic and mini alike, since 4.0 —\n * rather than off an imported zod module. A project can hold two zod copies\n * (a hoisted one and a nested one, or a build-time and a runtime one), and the\n * copy that built the schema is the one whose semantics its validator must\n * match. A schema with no version at all is refused too: every zod 4 stamps\n * one, so its absence means a zod older than this compiler has ever targeted.\n * A value that is not a zod schema in the first place (no `_zod.def`) is not\n * this guard's to judge — extraction reports it the way it always has, and\n * calling it a version problem would send the user chasing the wrong fix.\n */\n\nimport { isZodSchema } from \"../../is-zod-schema.js\";\n\n/** Lowest zod release whose semantics the emitted validators reproduce. */\nexport const MIN_ZOD_VERSION = { major: 4, minor: 5 } as const;\n\nexport interface ZodVersion {\n major: number;\n minor: number;\n patch: number;\n}\n\n/**\n * `name` of the error {@link assertSupportedZod} throws. Matched by name, not\n * by identity, so a second copy of this module in the graph still recognises it.\n */\nexport const UNSUPPORTED_ZOD_VERSION_ERROR = \"UnsupportedZodVersionError\";\n\n/** The `_zod.version` a schema carries, or `undefined` when it has none (or is not a schema). */\nexport function zodVersionOf(schema: unknown): ZodVersion | undefined {\n if (typeof schema !== \"object\" || schema === null) return undefined;\n try {\n const internal = (schema as { _zod?: unknown })._zod;\n if (typeof internal !== \"object\" || internal === null) return undefined;\n const version = (internal as { version?: unknown }).version;\n if (typeof version !== \"object\" || version === null) return undefined;\n const { major, minor, patch } = version as Record<string, unknown>;\n if (typeof major !== \"number\" || typeof minor !== \"number\" || typeof patch !== \"number\") {\n return undefined;\n }\n return { major, minor, patch };\n } catch {\n // A Proxy trapping `get` — not a zod schema, and not one this can compile.\n return undefined;\n }\n}\n\n/**\n * Within the peer range: the same major, at or past the minimum minor. A\n * hypothetical zod 5 is refused as well — its semantics are unknown here, and\n * the promise is exactness, not best effort.\n */\nexport function isSupportedZodVersion(version: ZodVersion | undefined): boolean {\n return (\n version !== undefined &&\n version.major === MIN_ZOD_VERSION.major &&\n version.minor >= MIN_ZOD_VERSION.minor\n );\n}\n\nexport function unsupportedZodVersionMessage(version: ZodVersion | undefined): string {\n const found =\n version === undefined\n ? \"a zod that carries no _zod.version (older than 4.0, or not a zod schema)\"\n : `zod ${version.major}.${version.minor}.${version.patch}`;\n const required = `^${MIN_ZOD_VERSION.major}.${MIN_ZOD_VERSION.minor}.0`;\n return (\n `Unsupported zod version: this schema was built by ${found}, and this zod-compiler release requires zod ${required}. ` +\n `Compiled validators reproduce zod ${MIN_ZOD_VERSION.major}.${MIN_ZOD_VERSION.minor}'s semantics exactly ` +\n '(the absent-key `expected: \"nonoptional\"` rule, code-point string lengths, tuple issue order), ' +\n \"so an older zod would accept and reject differently from the validator compiled for it. \" +\n `Upgrade zod to ${MIN_ZOD_VERSION.major}.${MIN_ZOD_VERSION.minor} or later, or stay on zod-compiler 1.x.`\n );\n}\n\n/**\n * Throw a recognisable error (see {@link isUnsupportedZodVersionError}) when\n * `schema` is a zod schema from an unsupported zod. Anything that is not a zod\n * schema at all passes through untouched, for the caller's own error path.\n */\nexport function assertSupportedZod(schema: unknown): void {\n if (!isZodSchema(schema)) return;\n const version = zodVersionOf(schema);\n if (isSupportedZodVersion(version)) return;\n const error = new Error(unsupportedZodVersionMessage(version));\n error.name = UNSUPPORTED_ZOD_VERSION_ERROR;\n throw error;\n}\n\n/**\n * The predicate's target is deliberately narrower than `Error`: a caller that\n * already holds an `Error` keeps it on the negative branch (a bare `error is\n * Error` would leave `never` there).\n */\nexport function isUnsupportedZodVersionError(\n error: unknown,\n): error is Error & { name: typeof UNSUPPORTED_ZOD_VERSION_ERROR } {\n return error instanceof Error && error.name === UNSUPPORTED_ZOD_VERSION_ERROR;\n}\n\n/** Messages already printed by {@link warnUnsupportedZodOnce}, per process. */\nconst warned = new Set<string>();\n\n/**\n * Print the refusal once per process. Every schema in an application fails the\n * guard the same way, so one explanation is the useful amount — and the paths\n * that call this (`jit()` at module scope, the plugin's per-export failure\n * hook, the hoist compiler's catch-all) would otherwise either say nothing or\n * say it once per export.\n */\nexport function warnUnsupportedZodOnce(message: string): void {\n if (warned.has(message)) return;\n warned.add(message);\n // oxlint-disable-next-line no-console -- being heard is the point\n console.warn(`[zod-compiler] ${message}`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,kBAAkB;CAAE,OAAO;CAAG,OAAO;AAAE;;;;;AAYpD,MAAa,gCAAgC;;AAG7C,SAAgB,aAAa,QAAyC;CACpE,IAAI,OAAO,WAAW,YAAY,WAAW,MAAM,OAAO,KAAA;CAC1D,IAAI;EACF,MAAM,WAAY,OAA8B;EAChD,IAAI,OAAO,aAAa,YAAY,aAAa,MAAM,OAAO,KAAA;EAC9D,MAAM,UAAW,SAAmC;EACpD,IAAI,OAAO,YAAY,YAAY,YAAY,MAAM,OAAO,KAAA;EAC5D,MAAM,EAAE,OAAO,OAAO,UAAU;EAChC,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,UAC7E;EAEF,OAAO;GAAE;GAAO;GAAO;EAAM;CAC/B,QAAQ;EAEN;CACF;AACF;;;;;;AAOA,SAAgB,sBAAsB,SAA0C;CAC9E,OACE,YAAY,KAAA,KACZ,QAAQ,UAAU,gBAAgB,SAClC,QAAQ,SAAS,gBAAgB;AAErC;AAEA,SAAgB,6BAA6B,SAAyC;CAMpF,OACE,qDALA,YAAY,KAAA,IACR,6EACA,OAAO,QAAQ,MAAM,GAAG,QAAQ,MAAM,GAAG,QAAQ,QAGM,+CAA+C,IAFvF,gBAAgB,MAAM,GAAG,gBAAgB,MAAM,IAEiD,sCAC9E,gBAAgB,MAAM,GAAG,gBAAgB,MAAM,+NAGlE,gBAAgB,MAAM,GAAG,gBAAgB,MAAM;AAErE;;;;;;AAOA,SAAgB,mBAAmB,QAAuB;CACxD,IAAI,CAAC,YAAY,MAAM,GAAG;CAC1B,MAAM,UAAU,aAAa,MAAM;CACnC,IAAI,sBAAsB,OAAO,GAAG;CACpC,MAAM,QAAQ,IAAI,MAAM,6BAA6B,OAAO,CAAC;CAC7D,MAAM,OAAO;CACb,MAAM;AACR;;;;;;AAOA,SAAgB,6BACd,OACiE;CACjE,OAAO,iBAAiB,SAAS,MAAM,SAAA;AACzC;;AAGA,MAAM,yBAAS,IAAI,IAAY;;;;;;;;AAS/B,SAAgB,uBAAuB,SAAuB;CAC5D,IAAI,OAAO,IAAI,OAAO,GAAG;CACzB,OAAO,IAAI,OAAO;CAElB,QAAQ,KAAK,kBAAkB,SAAS;AAC1C"}
@@ -211,6 +211,14 @@ declare const FINZ_DECL = "function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);
211
211
  * Installed with defineProperty rather than assignment: Zod's lazy setter
212
212
  * redefines the slot as non-writable, so a second `__zcMkv` on the same schema
213
213
  * object — two exports aliasing one schema — would throw under ESM strict mode.
214
+ *
215
+ * A rebuilding schema (no `fc`) reaches `parse()` through `fn`, i.e. through a
216
+ * SafeParseResult unwrapped a line later. Handing the build function over so
217
+ * `parse()` could call it directly was measured and declined: the wrapper is a
218
+ * young-generation bump allocation that V8 elides outright where `fn` inlines,
219
+ * and even across eight schemas sharing this closure — where it cannot — the
220
+ * direct call came out level (41.5 vs 41.8 ns), for a wider signature on every
221
+ * bundle.
214
222
  */
215
223
  declare const MK_VALIDATOR_DECL: string;
216
224
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAca;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8CA;;;cAUA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA6FA;;;;;;;;;;;;;;;;;iBA6BG,iBAAiB,QAAQ;;;;;;;;;;;;;iBAgBzB,aACd,oBACA,QAAQ,oBACR;EAAY;EAAiC"}
1
+ {"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAca;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8CA;;;cAUA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;;;;cA2BA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqGA;;;;;;;;;;;;;;;;;iBA6BG,iBAAiB,QAAQ;;;;;;;;;;;;;iBAgBzB,aACd,oBACA,QAAQ,oBACR;EAAY;EAAiC"}
package/dist/core/iife.js CHANGED
@@ -215,6 +215,14 @@ const FINZ_DECL = "function __zcFinZ(z,r,i){return new __ZcFailZ(z,r,i);}";
215
215
  * Installed with defineProperty rather than assignment: Zod's lazy setter
216
216
  * redefines the slot as non-writable, so a second `__zcMkv` on the same schema
217
217
  * object — two exports aliasing one schema — would throw under ESM strict mode.
218
+ *
219
+ * A rebuilding schema (no `fc`) reaches `parse()` through `fn`, i.e. through a
220
+ * SafeParseResult unwrapped a line later. Handing the build function over so
221
+ * `parse()` could call it directly was measured and declined: the wrapper is a
222
+ * young-generation bump allocation that V8 elides outright where `fn` inlines,
223
+ * and even across eight schemas sharing this closure — where it cannot — the
224
+ * direct call came out level (41.5 vs 41.8 ns), for a wider signature on every
225
+ * bundle.
218
226
  */
219
227
  const MK_VALIDATOR_DECL = "function __zcMkv(fn,schema,fc,is){var w=schema||{};var zpa=w.parseAsync,zspa=w.safeParseAsync;w.parse=fc?function(input){if(fc(input))return input;var r=fn(input);if(r.success)return r.data;throw r.error;}:function(input){var r=fn(input);if(r.success)return r.data;throw r.error;};w.safeParse=fn;w.safeParseAsync=function(input){try{return Promise.resolve(fn(input));}catch(e){if(zspa)return zspa(input);throw e;}};w.parseAsync=fc?function(input){try{if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}}:function(input){try{var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}catch(e){if(zpa)return zpa(input);throw e;}};w.is=is||function(input){return fn(input).success;};Object.defineProperty(w,\"~standard\",{configurable:true,value:{version:1,vendor:\"zod\",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zspa)return zspa(input).then(function(q){return q.success?{value:q.data}:{issues:q.error.issues};});throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});return w;}";
220
228
  function extractFunctionName(functionDef) {