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":"effect.js","names":[],"sources":["../../../../src/core/codegen/schemas/effect.ts"],"sourcesContent":["import type {\n PreprocessEffectIR,\n RefineEffectCheckIR,\n SuperRefineEffectCheckIR,\n TransformEffectIR,\n} from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport {\n emitConstant,\n emitEffectCallable,\n emitRuntimeHelper,\n extendStaticPath,\n extendStaticPathIndex,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { ZC_SR_DECL, ZC_SR_OK_DECL, ZC_SR_RUN_DECL } from \"../issue-decls.js\";\n\n/**\n * Generate code for a TransformEffectIR node.\n * Validates the inner schema, then applies the transform function and writes back the result.\n */\nexport function slowEffect(ir: TransformEffectIR | PreprocessEffectIR, g: SlowGen): string {\n if (ir.effectKind === \"preprocess\") {\n const valueVar = g.temp(\"pv\");\n return `${emit`\n var ${valueVar}=${emitEffectCallable(g.ctx, ir)}(${g.input});\n ${g.output}=${valueVar};\n ${g.visit(ir.inner, { input: valueVar, output: g.output, aborted: g.aborted })}\n `}\\n`;\n }\n\n const beforeVar = g.temp(\"ib\");\n const innerCode = g.visit(ir.inner);\n // A transform is `inner.transform(fn)` = a pipe(inner, transform): zod's\n // handlePipeResult aborts when `inner` produces any issue. Inside a union the\n // option must therefore count as aborted even if `inner`'s only issue is a\n // non-aborting `custom`/check-level code (mirrors slowPipe's abort branch).\n const abortBranch = g.aborted ? `else{${g.aborted}=true;}` : \"\";\n\n return `${emit`\n var ${beforeVar}=${g.issues}.length;\n ${innerCode}\n if(${g.issues}.length===${beforeVar}){\n ${g.output}=${emitEffectCallable(g.ctx, ir)}(${g.output});\n }${abortBranch}\n `}\\n`;\n}\n\n/**\n * Generate code for a RefineEffectCheckIR (inline refine function call).\n * Called from string/number/object check loops when a refine_effect is encountered.\n *\n * @param check - The refine effect check IR\n * @param expr - The expression to validate (may differ from g.input, e.g. objVar in object generators)\n * @param g - SlowGen context (provides path, issues)\n */\nexport function refineCheck(check: RefineEffectCheckIR, expr: string, g: SlowGen): string {\n // The refine's own message wins; without one, zod's finalizeIssue falls\n // through to the error map of the schema the check is attached to (the check\n // stamps its owner onto the issue), so the node's schema-level message is the\n // next rung. With neither, __zcFin applies the locale default.\n const message = check.message ?? g.typeMsg;\n const messageProp = message === undefined ? \"\" : `,message:${JSON.stringify(message)}`;\n // `.refine(fn, { path })` reports against a member of the refined value, so\n // the configured segments extend this node's path.\n const path = (check.path ?? []).reduce<string>(\n (acc, segment) =>\n typeof segment === \"number\"\n ? extendStaticPathIndex(acc, segment)\n : extendStaticPath(acc, segment),\n g.path,\n );\n // `.refine(fn, { params })`: $ZodCustom's check does\n // `if (def.params) _iss.params = def.params`, so the key is present only when\n // the schema declared one, and holds the ORIGINAL object — the extractor\n // parked it in `__rf` precisely so the reference survives (see\n // RefineEffectCheckIR.paramsRefIndex). Placed before `message` to keep the\n // key order zod produces.\n const paramsProp =\n check.paramsRefIndex === undefined\n ? \"\"\n : `,params:${emitConstant(g.ctx, \"rpa\", `__rf[${check.paramsRefIndex}]`)}`;\n return emit`\n if(!${emitEffectCallable(g.ctx, check)}(${expr})){\n ${g.issues}.push({code:\"custom\",path:${path}${paramsProp},input:${expr}${messageProp}});\n }`;\n}\n\n/**\n * Declare the shared invoker both superRefine helpers call. It is module-local\n * rather than an imported helper (lean mode declares it in the runtime module\n * beside them), so inline mode must place it in the preamble itself.\n */\nfunction emitSuperRefineRunner(ctx: SlowGen[\"ctx\"]): void {\n if (ctx.mode !== \"lean\" && !ctx.preamble.includes(ZC_SR_RUN_DECL)) {\n ctx.preamble.push(ZC_SR_RUN_DECL);\n }\n}\n\n/**\n * Fast-path test for a SuperRefineEffectCheckIR: a boolean term reporting that\n * the callback added no issue and left the value alone (see ZC_SR_OK_DECL).\n */\nexport function superRefineFastTest(\n check: SuperRefineEffectCheckIR,\n expr: string,\n g: FastGen,\n): string {\n emitSuperRefineRunner(g.ctx);\n const ok = emitRuntimeHelper(g.ctx, \"__zcSrOk\", ZC_SR_OK_DECL);\n return `${ok}(${emitEffectCallable(g.ctx, check)},${expr})`;\n}\n\n/**\n * Generate code for a SuperRefineEffectCheckIR: call the payload-taking\n * callback with a synthesized `{ value, issues }` and merge what it collected.\n * zod's own wrapper installs `addIssue` and normalizes the result, so the\n * issues are zod's — the helper only reprojects them onto this node's path and\n * strips the internal bookkeeping zod deletes before they become visible.\n *\n * The payload's `value` is writable public API, so it is written back to the\n * output slot the way an overwrite effect is. This walk is always the eager one\n * (the node reports as mutating, see hasMutation), so the write-back lands on\n * every parse that reaches it — not only on failures.\n */\nexport function superRefineCheck(\n check: SuperRefineEffectCheckIR,\n expr: string,\n g: SlowGen,\n): string {\n emitSuperRefineRunner(g.ctx);\n const helper = emitRuntimeHelper(g.ctx, \"__zcSr\", ZC_SR_DECL);\n const fn = emitEffectCallable(g.ctx, check);\n const p = g.temp(\"sp\");\n // The owning schema's message covers an added issue that carries none of its\n // own, as it does for a refine (see refineCheck); the helper applies it.\n const msgArg = g.typeMsg === undefined ? \"\" : `,${JSON.stringify(g.typeMsg)}`;\n let code = `var ${p}=${helper}(${fn},${expr},${g.path},${g.issues}${msgArg});${g.output}=${p}.value;`;\n // Inside a union option, an aborting issue must mark the option aborted so\n // pruning matches zod (see ZC_SR_DECL); elsewhere the flag is unobserved.\n if (g.aborted) code += `if(${p}.aborted){${g.aborted}=true;}`;\n return code;\n}\n"],"mappings":";;;;;;;;AAqBA,SAAgB,WAAW,IAA4C,GAAoB;CACzF,IAAI,GAAG,eAAe,cAAc;EAClC,MAAM,WAAW,EAAE,KAAK,IAAI;EAC5B,OAAO,GAAG,IAAI;YACN,SAAS,GAAG,mBAAmB,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM;QACzD,EAAE,OAAO,GAAG,SAAS;QACrB,EAAE,MAAM,GAAG,OAAO;GAAE,OAAO;GAAU,QAAQ,EAAE;GAAQ,SAAS,EAAE;EAAQ,CAAC,EAAE;MAC/E;CACJ;CAEA,MAAM,YAAY,EAAE,KAAK,IAAI;CAC7B,MAAM,YAAY,EAAE,MAAM,GAAG,KAAK;CAKlC,MAAM,cAAc,EAAE,UAAU,QAAQ,EAAE,QAAQ,WAAW;CAE7D,OAAO,GAAG,IAAI;UACN,UAAU,GAAG,EAAE,OAAO;MAC1B,UAAU;SACP,EAAE,OAAO,YAAY,UAAU;QAChC,EAAE,OAAO,GAAG,mBAAmB,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO;OACvD,YAAY;IACf;AACJ;;;;;;;;;AAUA,SAAgB,YAAY,OAA4B,MAAc,GAAoB;CAKxF,MAAM,UAAU,MAAM,WAAW,EAAE;CACnC,MAAM,cAAc,YAAY,KAAA,IAAY,KAAK,YAAY,KAAK,UAAU,OAAO;CAGnF,MAAM,QAAQ,MAAM,QAAQ,CAAC,EAAA,CAAG,QAC7B,KAAK,YACJ,OAAO,YAAY,WACf,sBAAsB,KAAK,OAAO,IAClC,iBAAiB,KAAK,OAAO,GACnC,EAAE,IACJ;CAOA,MAAM,aACJ,MAAM,mBAAmB,KAAA,IACrB,KACA,WAAW,aAAa,EAAE,KAAK,OAAO,QAAQ,MAAM,eAAe,EAAE;CAC3E,OAAO,IAAI;UACH,mBAAmB,EAAE,KAAK,KAAK,EAAE,GAAG,KAAK;QAC3C,EAAE,OAAO,4BAA4B,OAAO,WAAW,SAAS,OAAO,YAAY;;AAE3F;;;;;;AAOA,SAAS,sBAAsB,KAA2B;CACxD,IAAI,IAAI,SAAS,UAAU,CAAC,IAAI,SAAS,SAAA,+GAAuB,GAC9D,IAAI,SAAS,KAAK,cAAc;AAEpC;;;;;AAMA,SAAgB,oBACd,OACA,MACA,GACQ;CACR,sBAAsB,EAAE,GAAG;CAE3B,OAAO,GADI,kBAAkB,EAAE,KAAK,YAAY,aACrC,EAAE,GAAG,mBAAmB,EAAE,KAAK,KAAK,EAAE,GAAG,KAAK;AAC3D;;;;;;;;;;;;;AAcA,SAAgB,iBACd,OACA,MACA,GACQ;CACR,sBAAsB,EAAE,GAAG;CAC3B,MAAM,SAAS,kBAAkB,EAAE,KAAK,UAAU,UAAU;CAC5D,MAAM,KAAK,mBAAmB,EAAE,KAAK,KAAK;CAC1C,MAAM,IAAI,EAAE,KAAK,IAAI;CAGrB,MAAM,SAAS,EAAE,YAAY,KAAA,IAAY,KAAK,IAAI,KAAK,UAAU,EAAE,OAAO;CAC1E,IAAI,OAAO,OAAO,EAAE,GAAG,OAAO,GAAG,GAAG,GAAG,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS,OAAO,IAAI,EAAE,OAAO,GAAG,EAAE;CAG7F,IAAI,EAAE,SAAS,QAAQ,MAAM,EAAE,YAAY,EAAE,QAAQ;CACrD,OAAO;AACT"}
1
+ {"version":3,"file":"effect.js","names":[],"sources":["../../../../src/core/codegen/schemas/effect.ts"],"sourcesContent":["import type {\n PreprocessEffectIR,\n RefineEffectCheckIR,\n SuperRefineEffectCheckIR,\n TransformEffectIR,\n} from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport {\n emitConstant,\n emitEffectCallable,\n emitRuntimeHelper,\n extendStaticPath,\n extendStaticPathIndex,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { ZC_ASYNC_DECL, ZC_SR_DECL, ZC_SR_OK_DECL, ZC_SR_RUN_DECL } from \"../issue-decls.js\";\n\n/**\n * Generate code for a TransformEffectIR node.\n * Validates the inner schema, then applies the transform function and writes back the result.\n */\nexport function slowEffect(ir: TransformEffectIR | PreprocessEffectIR, g: SlowGen): string {\n // A callback that returns a Promise is zod's synchronous-parse error, not a\n // value (see ZC_ASYNC_DECL); zod tests `_out instanceof Promise` right after\n // the call, so the guard sits at the same point.\n const asy = emitRuntimeHelper(g.ctx, \"__zcAsy\", ZC_ASYNC_DECL);\n if (ir.effectKind === \"preprocess\") {\n const valueVar = g.temp(\"pv\");\n return `${emit`\n var ${valueVar}=${emitEffectCallable(g.ctx, ir)}(${g.input});\n if(${valueVar} instanceof Promise)${asy}();\n ${g.output}=${valueVar};\n ${g.visit(ir.inner, { input: valueVar, output: g.output, aborted: g.aborted })}\n `}\\n`;\n }\n\n const beforeVar = g.temp(\"ib\");\n const innerCode = g.visit(ir.inner);\n // A transform is `inner.transform(fn)` = a pipe(inner, transform): zod's\n // handlePipeResult aborts when `inner` produces any issue. Inside a union the\n // option must therefore count as aborted even if `inner`'s only issue is a\n // non-aborting `custom`/check-level code (mirrors slowPipe's abort branch).\n const abortBranch = g.aborted ? `else{${g.aborted}=true;}` : \"\";\n\n return `${emit`\n var ${beforeVar}=${g.issues}.length;\n ${innerCode}\n if(${g.issues}.length===${beforeVar}){\n ${g.output}=${emitEffectCallable(g.ctx, ir)}(${g.output});\n if(${g.output} instanceof Promise)${asy}();\n }${abortBranch}\n `}\\n`;\n}\n\n/**\n * Generate code for a RefineEffectCheckIR (inline refine function call).\n * Called from string/number/object check loops when a refine_effect is encountered.\n *\n * @param check - The refine effect check IR\n * @param expr - The expression to validate (may differ from g.input, e.g. objVar in object generators)\n * @param g - SlowGen context (provides path, issues)\n */\nexport function refineCheck(check: RefineEffectCheckIR, expr: string, g: SlowGen): string {\n // The refine's own message wins; without one, zod's finalizeIssue falls\n // through to the error map of the schema the check is attached to (the check\n // stamps its owner onto the issue), so the node's schema-level message is the\n // next rung. With neither, __zcFin applies the locale default.\n const message = check.message ?? g.typeMsg;\n const messageProp = message === undefined ? \"\" : `,message:${JSON.stringify(message)}`;\n // `.refine(fn, { path })` reports against a member of the refined value, so\n // the configured segments extend this node's path.\n const path = (check.path ?? []).reduce<string>(\n (acc, segment) =>\n typeof segment === \"number\"\n ? extendStaticPathIndex(acc, segment)\n : extendStaticPath(acc, segment),\n g.path,\n );\n // `.refine(fn, { params })`: $ZodCustom's check does\n // `if (def.params) _iss.params = def.params`, so the key is present only when\n // the schema declared one, and holds the ORIGINAL object — the extractor\n // parked it in `__rf` precisely so the reference survives (see\n // RefineEffectCheckIR.paramsRefIndex). Placed before `message` to keep the\n // key order zod produces.\n const paramsProp =\n check.paramsRefIndex === undefined\n ? \"\"\n : `,params:${emitConstant(g.ctx, \"rpa\", `__rf[${check.paramsRefIndex}]`)}`;\n // The predicate's return value is tested for a Promise before its truthiness\n // (see ZC_ASYNC_DECL): a Promise is truthy, so without the guard a plain\n // function returning one would ACCEPT every input where zod throws.\n const asy = emitRuntimeHelper(g.ctx, \"__zcAsy\", ZC_ASYNC_DECL);\n const result = g.temp(\"rr\");\n return emit`\n var ${result}=${emitEffectCallable(g.ctx, check)}(${expr});\n if(${result} instanceof Promise)${asy}();\n if(!${result}){\n ${g.issues}.push({code:\"custom\",path:${path}${paramsProp},input:${expr}${messageProp}});\n }`;\n}\n\n/**\n * Fast-path test for a RefineEffectCheckIR: the predicate's verdict, bound to a\n * local so a Promise can be told apart from a truthy value. A Promise throws\n * zod's `$ZodAsyncError` right here, EAGERLY: zod's `runChecks` throws the\n * moment a check returns a Promise under a synchronous parse — before any later\n * check, and even inside a union whose next option would have matched — so\n * deferring the throw to the slow walk (which a fast-eligible schema only runs\n * when `.error` is read) would turn zod's throw into a failure result. The\n * throw itself lives in a hosted helper, so the hot expression only pays the\n * `instanceof` test.\n */\nexport function fastRefineTest(check: RefineEffectCheckIR, expr: string, g: FastGen): string {\n const asy = emitRuntimeHelper(g.ctx, \"__zcAsy\", ZC_ASYNC_DECL);\n const verdict = g.local(\"fr\");\n return `((${verdict}=${emitEffectCallable(g.ctx, check)}(${expr})) instanceof Promise?${asy}():${verdict})`;\n}\n\n/**\n * Declare the shared invoker both superRefine helpers call. It is module-local\n * rather than an imported helper (lean mode declares it in the runtime module\n * beside them), so inline mode must place it in the preamble itself.\n */\nfunction emitSuperRefineRunner(ctx: SlowGen[\"ctx\"]): void {\n if (ctx.mode !== \"lean\" && !ctx.preamble.includes(ZC_SR_RUN_DECL)) {\n ctx.preamble.push(ZC_SR_RUN_DECL);\n }\n}\n\n/**\n * Fast-path test for a SuperRefineEffectCheckIR: a boolean term reporting that\n * the callback added no issue and left the value alone (see ZC_SR_OK_DECL).\n */\nexport function superRefineFastTest(\n check: SuperRefineEffectCheckIR,\n expr: string,\n g: FastGen,\n): string {\n emitSuperRefineRunner(g.ctx);\n const ok = emitRuntimeHelper(g.ctx, \"__zcSrOk\", ZC_SR_OK_DECL);\n return `${ok}(${emitEffectCallable(g.ctx, check)},${expr})`;\n}\n\n/**\n * Generate code for a SuperRefineEffectCheckIR: call the payload-taking\n * callback with a synthesized `{ value, issues }` and merge what it collected.\n * zod's own wrapper installs `addIssue` and normalizes the result, so the\n * issues are zod's — the helper only reprojects them onto this node's path and\n * strips the internal bookkeeping zod deletes before they become visible.\n *\n * The payload's `value` is writable public API, so it is written back to the\n * output slot the way an overwrite effect is. This walk is always the eager one\n * (the node reports as mutating, see hasMutation), so the write-back lands on\n * every parse that reaches it — not only on failures.\n */\nexport function superRefineCheck(\n check: SuperRefineEffectCheckIR,\n expr: string,\n g: SlowGen,\n): string {\n emitSuperRefineRunner(g.ctx);\n const helper = emitRuntimeHelper(g.ctx, \"__zcSr\", ZC_SR_DECL);\n const fn = emitEffectCallable(g.ctx, check);\n const p = g.temp(\"sp\");\n // The owning schema's message covers an added issue that carries none of its\n // own, as it does for a refine (see refineCheck); the helper applies it.\n const msgArg = g.typeMsg === undefined ? \"\" : `,${JSON.stringify(g.typeMsg)}`;\n let code = `var ${p}=${helper}(${fn},${expr},${g.path},${g.issues}${msgArg});${g.output}=${p}.value;`;\n // Inside a union option, an aborting issue must mark the option aborted so\n // pruning matches zod (see ZC_SR_DECL); elsewhere the flag is unobserved.\n if (g.aborted) code += `if(${p}.aborted){${g.aborted}=true;}`;\n return code;\n}\n"],"mappings":"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"}
@@ -2,7 +2,23 @@ import { FallbackIR } from "../../types.js";
2
2
  import { SlowGen } from "../context.js";
3
3
  //#region src/core/codegen/schemas/fallback.d.ts
4
4
  declare function slowFallback(ir: FallbackIR, g: SlowGen): string;
5
- /** Delegate a cold slow-walk leaf to a pristine retained Zod schema. */
5
+ /**
6
+ * Delegate a cold slow-walk leaf to a pristine retained Zod schema.
7
+ *
8
+ * The schema is run through `_zod.run` and its RAW payload read, not through
9
+ * `safeParse`: the payload is where zod's per-issue `continue` flags and the
10
+ * `aborted` bit still exist, and a plain union prunes its options on exactly
11
+ * those (see ZC_RUN_DELEGATE_DECL). The issues are then finalized by zod's own
12
+ * `finalizeIssue` and re-homed under this node's path (ZC_DELEGATE_ISSUES_DECL),
13
+ * so what lands in the validator's list is what `safeParse` would have built,
14
+ * plus a `continue:false` marker on each aborting issue that the top-level
15
+ * finalizer strips again. The per-call `{async:false}` ctx is the one zod's
16
+ * `_safeParse` allocates, handed to both `run` and `finalizeIssue` as zod does.
17
+ *
18
+ * `payload.aborted` — set by a pipe whose `in` failed — is forwarded only when
19
+ * this delegate IS a union option (`g.aborted` bound). Nested deeper it is
20
+ * dropped, as zod's `handlePropertyResult` drops it: only the issues travel up.
21
+ */
6
22
  declare function slowZodDelegate(refIndex: number, g: SlowGen, onFailure?: string): string;
7
23
  //#endregion
8
24
  export { slowFallback, slowZodDelegate };
@@ -1 +1 @@
1
- {"version":3,"file":"fallback.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/fallback.ts"],"mappings":";;;iBAKgB,aAAa,IAAI,YAAY,GAAG;;iBAQhC,gBAAgB,kBAAkB,GAAG,SAAS"}
1
+ {"version":3,"file":"fallback.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/fallback.ts"],"mappings":";;;iBAMgB,aAAa,IAAI,YAAY,GAAG;;;;;;;;;;;;;;;;;;iBAwBhC,gBAAgB,kBAAkB,GAAG,SAAS"}
@@ -1,28 +1,44 @@
1
- import { emitRfDelegate } from "../context.js";
1
+ import { emitRfZod, emitRuntimeHelper } from "../context.js";
2
2
  import { emit } from "../emit.js";
3
+ import { ZC_DELEGATE_ISSUES_DECL, ZC_RUN_DELEGATE_DECL } from "../issue-decls.js";
3
4
  //#region src/core/codegen/schemas/fallback.ts
4
5
  function slowFallback(ir, g) {
5
6
  if (ir.refIndex !== void 0) return slowZodDelegate(ir.refIndex, g);
6
7
  return `${g.issues}.push({code:"custom",path:${g.path},message:"Fallback schema: ${ir.reason}"});\n`;
7
8
  }
8
- /** Delegate a cold slow-walk leaf to a pristine retained Zod schema. */
9
+ /**
10
+ * Delegate a cold slow-walk leaf to a pristine retained Zod schema.
11
+ *
12
+ * The schema is run through `_zod.run` and its RAW payload read, not through
13
+ * `safeParse`: the payload is where zod's per-issue `continue` flags and the
14
+ * `aborted` bit still exist, and a plain union prunes its options on exactly
15
+ * those (see ZC_RUN_DELEGATE_DECL). The issues are then finalized by zod's own
16
+ * `finalizeIssue` and re-homed under this node's path (ZC_DELEGATE_ISSUES_DECL),
17
+ * so what lands in the validator's list is what `safeParse` would have built,
18
+ * plus a `continue:false` marker on each aborting issue that the top-level
19
+ * finalizer strips again. The per-call `{async:false}` ctx is the one zod's
20
+ * `_safeParse` allocates, handed to both `run` and `finalizeIssue` as zod does.
21
+ *
22
+ * `payload.aborted` — set by a pipe whose `in` failed — is forwarded only when
23
+ * this delegate IS a union option (`g.aborted` bound). Nested deeper it is
24
+ * dropped, as zod's `handlePropertyResult` drops it: only the issues travel up.
25
+ */
9
26
  function slowZodDelegate(refIndex, g, onFailure = "") {
10
- const idx = refIndex;
11
- const delegate = emitRfDelegate(g.ctx, idx);
12
- const rVar = `__rf_r${idx}`;
13
- const iVar = `__rf_i${idx}`;
14
- const jVar = `__rf_j${idx}`;
27
+ const zod = emitRfZod(g.ctx, refIndex);
28
+ const run = emitRuntimeHelper(g.ctx, "__zcRd", ZC_RUN_DELEGATE_DECL);
29
+ const finalize = emitRuntimeHelper(g.ctx, "__zcRf", ZC_DELEGATE_ISSUES_DECL);
30
+ const cVar = `__rf_c${refIndex}`;
31
+ const rVar = `__rf_r${refIndex}`;
32
+ const abort = g.aborted === void 0 ? "" : `if(${rVar}.aborted===true){${g.aborted}=true;}`;
15
33
  return `${emit`
16
- var ${rVar}=${delegate}(${g.input});
17
- if(!${rVar}.success){
34
+ var ${cVar}={async:false};
35
+ var ${rVar}=${run}(${zod},${g.input},${cVar});
36
+ if(${rVar}.issues.length){
18
37
  ${onFailure}
19
- var ${iVar}=${rVar}.error.issues;
20
- for(var ${jVar}=0;${jVar}<${iVar}.length;${jVar}++){
21
- ${g.issues}.push({...${iVar}[${jVar}],
22
- path:${g.path}.concat(${iVar}[${jVar}].path)});
23
- }
38
+ ${finalize}(${rVar}.issues,${cVar},${g.issues},${g.path});
39
+ ${abort}
24
40
  }else{
25
- ${g.output}=${rVar}.data;
41
+ ${g.output}=${rVar}.value;
26
42
  }
27
43
  `}\n`;
28
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fallback.js","names":[],"sources":["../../../../src/core/codegen/schemas/fallback.ts"],"sourcesContent":["import type { FallbackIR } from \"../../types.js\";\nimport type { SlowGen } from \"../context.js\";\nimport { emitRfDelegate } from \"../context.js\";\nimport { emit } from \"../emit.js\";\n\nexport function slowFallback(ir: FallbackIR, g: SlowGen): string {\n if (ir.refIndex !== undefined) {\n return slowZodDelegate(ir.refIndex, g);\n }\n return `${g.issues}.push({code:\"custom\",path:${g.path},message:\"Fallback schema: ${ir.reason}\"});\\n`;\n}\n\n/** Delegate a cold slow-walk leaf to a pristine retained Zod schema. */\nexport function slowZodDelegate(refIndex: number, g: SlowGen, onFailure = \"\"): string {\n const idx = refIndex;\n // Captured pre-__zcMkv (emitRfDelegate): a per-parse `__rf[N].safeParse`\n // read resolves to the compiled validator itself when CSE/dedup or an\n // identifier schemaExpr makes the entry alias the mutated schema object.\n const delegate = emitRfDelegate(g.ctx, idx);\n const rVar = `__rf_r${idx}`;\n const iVar = `__rf_i${idx}`;\n const jVar = `__rf_j${idx}`;\n return `${emit`\n var ${rVar}=${delegate}(${g.input});\n if(!${rVar}.success){\n ${onFailure}\n var ${iVar}=${rVar}.error.issues;\n for(var ${jVar}=0;${jVar}<${iVar}.length;${jVar}++){\n ${g.issues}.push({...${iVar}[${jVar}],\n path:${g.path}.concat(${iVar}[${jVar}].path)});\n }\n }else{\n ${g.output}=${rVar}.data;\n }\n `}\\n`;\n}\n"],"mappings":";;;AAKA,SAAgB,aAAa,IAAgB,GAAoB;CAC/D,IAAI,GAAG,aAAa,KAAA,GAClB,OAAO,gBAAgB,GAAG,UAAU,CAAC;CAEvC,OAAO,GAAG,EAAE,OAAO,4BAA4B,EAAE,KAAK,6BAA6B,GAAG,OAAO;AAC/F;;AAGA,SAAgB,gBAAgB,UAAkB,GAAY,YAAY,IAAY;CACpF,MAAM,MAAM;CAIZ,MAAM,WAAW,eAAe,EAAE,KAAK,GAAG;CAC1C,MAAM,OAAO,SAAS;CACtB,MAAM,OAAO,SAAS;CACtB,MAAM,OAAO,SAAS;CACtB,OAAO,GAAG,IAAI;UACN,KAAK,GAAG,SAAS,GAAG,EAAE,MAAM;UAC5B,KAAK;QACP,UAAU;YACN,KAAK,GAAG,KAAK;gBACT,KAAK,KAAK,KAAK,GAAG,KAAK,UAAU,KAAK;UAC5C,EAAE,OAAO,YAAY,KAAK,GAAG,KAAK;iBAC3B,EAAE,KAAK,UAAU,KAAK,GAAG,KAAK;;;QAGvC,EAAE,OAAO,GAAG,KAAK;;IAErB;AACJ"}
1
+ {"version":3,"file":"fallback.js","names":[],"sources":["../../../../src/core/codegen/schemas/fallback.ts"],"sourcesContent":["import type { FallbackIR } from \"../../types.js\";\nimport type { SlowGen } from \"../context.js\";\nimport { emitRfZod, emitRuntimeHelper } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { ZC_DELEGATE_ISSUES_DECL, ZC_RUN_DELEGATE_DECL } from \"../issue-decls.js\";\n\nexport function slowFallback(ir: FallbackIR, g: SlowGen): string {\n if (ir.refIndex !== undefined) {\n return slowZodDelegate(ir.refIndex, g);\n }\n return `${g.issues}.push({code:\"custom\",path:${g.path},message:\"Fallback schema: ${ir.reason}\"});\\n`;\n}\n\n/**\n * Delegate a cold slow-walk leaf to a pristine retained Zod schema.\n *\n * The schema is run through `_zod.run` and its RAW payload read, not through\n * `safeParse`: the payload is where zod's per-issue `continue` flags and the\n * `aborted` bit still exist, and a plain union prunes its options on exactly\n * those (see ZC_RUN_DELEGATE_DECL). The issues are then finalized by zod's own\n * `finalizeIssue` and re-homed under this node's path (ZC_DELEGATE_ISSUES_DECL),\n * so what lands in the validator's list is what `safeParse` would have built,\n * plus a `continue:false` marker on each aborting issue that the top-level\n * finalizer strips again. The per-call `{async:false}` ctx is the one zod's\n * `_safeParse` allocates, handed to both `run` and `finalizeIssue` as zod does.\n *\n * `payload.aborted` — set by a pipe whose `in` failed — is forwarded only when\n * this delegate IS a union option (`g.aborted` bound). Nested deeper it is\n * dropped, as zod's `handlePropertyResult` drops it: only the issues travel up.\n */\nexport function slowZodDelegate(refIndex: number, g: SlowGen, onFailure = \"\"): string {\n const zod = emitRfZod(g.ctx, refIndex);\n const run = emitRuntimeHelper(g.ctx, \"__zcRd\", ZC_RUN_DELEGATE_DECL);\n const finalize = emitRuntimeHelper(g.ctx, \"__zcRf\", ZC_DELEGATE_ISSUES_DECL);\n const cVar = `__rf_c${refIndex}`;\n const rVar = `__rf_r${refIndex}`;\n const abort = g.aborted === undefined ? \"\" : `if(${rVar}.aborted===true){${g.aborted}=true;}`;\n return `${emit`\n var ${cVar}={async:false};\n var ${rVar}=${run}(${zod},${g.input},${cVar});\n if(${rVar}.issues.length){\n ${onFailure}\n ${finalize}(${rVar}.issues,${cVar},${g.issues},${g.path});\n ${abort}\n }else{\n ${g.output}=${rVar}.value;\n }\n `}\\n`;\n}\n"],"mappings":";;;;AAMA,SAAgB,aAAa,IAAgB,GAAoB;CAC/D,IAAI,GAAG,aAAa,KAAA,GAClB,OAAO,gBAAgB,GAAG,UAAU,CAAC;CAEvC,OAAO,GAAG,EAAE,OAAO,4BAA4B,EAAE,KAAK,6BAA6B,GAAG,OAAO;AAC/F;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,gBAAgB,UAAkB,GAAY,YAAY,IAAY;CACpF,MAAM,MAAM,UAAU,EAAE,KAAK,QAAQ;CACrC,MAAM,MAAM,kBAAkB,EAAE,KAAK,UAAU,oBAAoB;CACnE,MAAM,WAAW,kBAAkB,EAAE,KAAK,UAAU,uBAAuB;CAC3E,MAAM,OAAO,SAAS;CACtB,MAAM,OAAO,SAAS;CACtB,MAAM,QAAQ,EAAE,YAAY,KAAA,IAAY,KAAK,MAAM,KAAK,mBAAmB,EAAE,QAAQ;CACrF,OAAO,GAAG,IAAI;UACN,KAAK;UACL,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,EAAE,MAAM,GAAG,KAAK;SACvC,KAAK;QACN,UAAU;QACV,SAAS,GAAG,KAAK,UAAU,KAAK,GAAG,EAAE,OAAO,GAAG,EAAE,KAAK;QACtD,MAAM;;QAEN,EAAE,OAAO,GAAG,KAAK;;IAErB;AACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"number.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/number.ts"],"mappings":";;;iBAQgB,WAAW,IAAI,UAAU,GAAG;iBA6I5B,WAAW,IAAI,UAAU,GAAG"}
1
+ {"version":3,"file":"number.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/number.ts"],"mappings":";;;iBAqBgB,WAAW,IAAI,UAAU,GAAG;iBAoJ5B,WAAW,IAAI,UAAU,GAAG"}
@@ -1,9 +1,21 @@
1
- import { checkPriority, emitEffectCallable, emitRuntimeHelper } from "../context.js";
1
+ import { checkPriority, emitRuntimeHelper } from "../context.js";
2
2
  import { emit } from "../emit.js";
3
3
  import { invalidType, tooBig, tooSmall } from "../emit-issue.js";
4
4
  import { ZC_FSR_DECL } from "../issue-decls.js";
5
- import { refineCheck, superRefineCheck, superRefineFastTest } from "./effect.js";
5
+ import { fastRefineTest, refineCheck, superRefineCheck, superRefineFastTest } from "./effect.js";
6
6
  //#region src/core/codegen/schemas/number.ts
7
+ /**
8
+ * The integer number formats, each with the range zod's `NUMBER_FORMAT_RANGES`
9
+ * gives it. `null` for safeint, whose own range IS the safe-integer range that
10
+ * every integer format reports first (see the number_format case below), so it
11
+ * has no range branch of its own. float32/float64 are absent on purpose: they
12
+ * are pure range checks and never report `invalid_type`.
13
+ */
14
+ const INT_FORMAT_RANGES = {
15
+ int32: [-2147483648, 2147483647],
16
+ safeint: null,
17
+ uint32: [0, 4294967295]
18
+ };
7
19
  function slowNumber(ir, g) {
8
20
  let code = "";
9
21
  if (ir.coerce) code += emit`try{${g.output}=Number(${g.input});}catch(_){}`;
@@ -17,7 +29,7 @@ function slowNumber(ir, g) {
17
29
  }`;
18
30
  if (ir.checks.length > 0) {
19
31
  code += `else{`;
20
- const opensIntGuard = (check) => check.kind === "number_format" && (check.format === "safeint" || check.format === "int32" || check.format === "uint32");
32
+ const opensIntGuard = (check) => check.kind === "number_format" && INT_FORMAT_RANGES[check.format] !== void 0;
21
33
  let seenIntFormat = false;
22
34
  let intGuardOpen = false;
23
35
  for (const check of ir.checks) {
@@ -48,46 +60,34 @@ function slowNumber(ir, g) {
48
60
  break;
49
61
  case "number_format": {
50
62
  const message = check.message ?? g.typeMsg;
51
- if (check.format === "safeint") {
63
+ const intRange = INT_FORMAT_RANGES[check.format];
64
+ if (intRange !== void 0) {
52
65
  const note = `note:"Integers must be within the safe integer range."`;
53
66
  const msgProp = message !== void 0 ? `,message:${JSON.stringify(message)}` : "";
54
67
  code += emit`
55
68
  if(!Number.isInteger(${g.input})){
56
69
  ${invalidType(g, "int", {
57
- extra: "format:\"safeint\"",
70
+ extra: `format:"${check.format}"`,
58
71
  extraBeforeCode: true,
59
72
  message
60
73
  })}
61
- }else if(${g.input}<-9007199254740991){
62
- ${g.issues}.push({code:"too_small",minimum:-9007199254740991,${note},origin:"int",inclusive:true,input:${g.input},path:${g.path}${msgProp}});
63
- }else if(${g.input}>9007199254740991){
64
- ${g.issues}.push({code:"too_big",maximum:9007199254740991,${note},origin:"int",inclusive:true,input:${g.input},path:${g.path}${msgProp}});
74
+ }else if(!Number.isSafeInteger(${g.input})){
75
+ if(${g.input}>0){
76
+ ${g.issues}.push({code:"too_big",maximum:9007199254740991,${note},origin:"int",inclusive:true,input:${g.input},path:${g.path}${msgProp}});
77
+ }else{
78
+ ${g.issues}.push({code:"too_small",minimum:-9007199254740991,${note},origin:"int",inclusive:true,input:${g.input},path:${g.path}${msgProp}});
79
+ }
65
80
  }`;
66
- } else if (check.format === "int32") code += emit`
67
- if(!Number.isInteger(${g.input})){
68
- ${invalidType(g, "int", {
69
- extra: "format:\"int32\"",
70
- extraBeforeCode: true,
71
- message
72
- })}
73
- }else if(${g.input}<-2147483648){
74
- ${tooSmall(g, -2147483648, "number", true, { message })}
75
- }else if(${g.input}>2147483647){
76
- ${tooBig(g, 2147483647, "number", true, { message })}
77
- }`;
78
- else if (check.format === "uint32") code += emit`
79
- if(!Number.isInteger(${g.input})){
80
- ${invalidType(g, "int", {
81
- extra: "format:\"uint32\"",
82
- extraBeforeCode: true,
83
- message
84
- })}
85
- }else if(${g.input}<0){
86
- ${tooSmall(g, 0, "number", true, { message })}
87
- }else if(${g.input}>4294967295){
88
- ${tooBig(g, 4294967295, "number", true, { message })}
89
- }`;
90
- else if (check.format === "float32") code += emit`
81
+ if (intRange !== null) {
82
+ const [minimum, maximum] = intRange;
83
+ code += emit`
84
+ else if(${g.input}<${minimum}){
85
+ ${tooSmall(g, minimum, "number", true, { message })}
86
+ }else if(${g.input}>${maximum}){
87
+ ${tooBig(g, maximum, "number", true, { message })}
88
+ }`;
89
+ }
90
+ } else if (check.format === "float32") code += emit`
91
91
  if(${g.input}<-3.4028234663852886e+38){
92
92
  ${tooSmall(g, "-3.4028234663852886e+38", "number", true, { message })}
93
93
  }else if(${g.input}>3.4028234663852886e+38){
@@ -165,7 +165,7 @@ function fastNumber(ir, g) {
165
165
  case "starts_with":
166
166
  case "ends_with": break;
167
167
  }
168
- for (const check of ir.checks) if (check.kind === "refine_effect") parts.push(`${emitEffectCallable(g.ctx, check)}(${x})`);
168
+ for (const check of ir.checks) if (check.kind === "refine_effect") parts.push(fastRefineTest(check, x, g));
169
169
  else if (check.kind === "super_refine_effect") parts.push(superRefineFastTest(check, x, g));
170
170
  return parts.join("&&");
171
171
  }
@@ -1 +1 @@
1
- {"version":3,"file":"number.js","names":[],"sources":["../../../../src/core/codegen/schemas/number.ts"],"sourcesContent":["import type { CheckIR, NumberIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { checkPriority, emitEffectCallable, emitRuntimeHelper } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\nimport { ZC_FSR_DECL } from \"../issue-decls.js\";\nimport { refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\n\nexport function slowNumber(ir: NumberIR, g: SlowGen): string {\n let code = \"\";\n if (ir.coerce) {\n code += emit`try{${g.output}=Number(${g.input});}catch(_){}`;\n }\n code += emit`\n if(typeof ${g.input}!==\"number\"){\n ${invalidType(g, \"number\")}\n }else if(Number.isNaN(${g.input})){\n ${invalidType(g, \"number\", { extra: 'received:\"NaN\"' })}\n }else if(!Number.isFinite(${g.input})){\n ${invalidType(g, \"number\", { extra: `received:String(${g.input})` })}\n }`;\n\n if (ir.checks.length > 0) {\n code += `else{`;\n // An integer FORMAT check (`.int()`, `.int32()`, `.uint32()`) is the one\n // check here that can report `invalid_type` — non-continuable — and zod's\n // `runChecks` then skips every check after it (`else if (isAborted)\n // continue`). So `z.number().int().min(5)` on 1.5 reports the int failure\n // ALONE, where an ungated chain also volunteers too_small. Its aborting\n // branch is exactly `!Number.isInteger(value)` (the range branches report\n // continuable too_small/too_big, which do NOT stop later checks), so one\n // guard opened after the first such check reproduces zod without any\n // runtime abort bookkeeping. Non-integer formats (float32/float64) never\n // report invalid_type and so never open it.\n const opensIntGuard = (check: (typeof ir.checks)[number]): boolean =>\n check.kind === \"number_format\" &&\n (check.format === \"safeint\" || check.format === \"int32\" || check.format === \"uint32\");\n let seenIntFormat = false;\n let intGuardOpen = false;\n // Insertion order mirrors zod's issue order for multi-failure inputs.\n // The slow path collects ALL issues (no short-circuit), so cost ordering\n // buys nothing here — only the fast path's && chain benefits from it.\n for (const check of ir.checks) {\n // Opened lazily, on the first check that actually needs gating: an integer\n // format check in LAST position has nothing after it, so the guard would\n // be dead code.\n if (seenIntFormat && !intGuardOpen) {\n code += `if(Number.isInteger(${g.input})){`;\n intGuardOpen = true;\n }\n switch (check.kind) {\n case \"greater_than\":\n if (check.inclusive) {\n code += emit`\n if(${g.input}<${check.value}){\n ${tooSmall(g, check.value, \"number\", true, { message: check.message })}\n }`;\n } else {\n code += emit`\n if(${g.input}<=${check.value}){\n ${tooSmall(g, check.value, \"number\", false, { message: check.message })}\n }`;\n }\n break;\n case \"less_than\":\n if (check.inclusive) {\n code += emit`\n if(${g.input}>${check.value}){\n ${tooBig(g, check.value, \"number\", true, { message: check.message })}\n }`;\n } else {\n code += emit`\n if(${g.input}>=${check.value}){\n ${tooBig(g, check.value, \"number\", false, { message: check.message })}\n }`;\n }\n break;\n case \"number_format\": {\n const message = check.message ?? g.typeMsg;\n if (check.format === \"safeint\") {\n // Mirrors $ZodCheckNumberFormat: non-integers → invalid_type;\n // integers outside the safe range → too_small/too_big with\n // origin \"int\" and zod's explanatory note.\n const note = `note:\"Integers must be within the safe integer range.\"`;\n const msgProp = message !== undefined ? `,message:${JSON.stringify(message)}` : \"\";\n code += emit`\n if(!Number.isInteger(${g.input})){\n ${invalidType(g, \"int\", { extra: 'format:\"safeint\"', extraBeforeCode: true, message })}\n }else if(${g.input}<-9007199254740991){\n ${g.issues}.push({code:\"too_small\",minimum:-9007199254740991,${note},origin:\"int\",inclusive:true,input:${g.input},path:${g.path}${msgProp}});\n }else if(${g.input}>9007199254740991){\n ${g.issues}.push({code:\"too_big\",maximum:9007199254740991,${note},origin:\"int\",inclusive:true,input:${g.input},path:${g.path}${msgProp}});\n }`;\n } else if (check.format === \"int32\") {\n code += emit`\n if(!Number.isInteger(${g.input})){\n ${invalidType(g, \"int\", { extra: 'format:\"int32\"', extraBeforeCode: true, message })}\n }else if(${g.input}<-2147483648){\n ${tooSmall(g, -2147483648, \"number\", true, { message })}\n }else if(${g.input}>2147483647){\n ${tooBig(g, 2147483647, \"number\", true, { message })}\n }`;\n } else if (check.format === \"uint32\") {\n code += emit`\n if(!Number.isInteger(${g.input})){\n ${invalidType(g, \"int\", { extra: 'format:\"uint32\"', extraBeforeCode: true, message })}\n }else if(${g.input}<0){\n ${tooSmall(g, 0, \"number\", true, { message })}\n }else if(${g.input}>4294967295){\n ${tooBig(g, 4294967295, \"number\", true, { message })}\n }`;\n } else if (check.format === \"float32\") {\n code += emit`\n if(${g.input}<-3.4028234663852886e+38){\n ${tooSmall(g, \"-3.4028234663852886e+38\", \"number\", true, { message })}\n }else if(${g.input}>3.4028234663852886e+38){\n ${tooBig(g, \"3.4028234663852886e+38\", \"number\", true, { message })}\n }`;\n }\n // float64 range is [-Number.MAX_VALUE, Number.MAX_VALUE], already covered by the isFinite check above\n break;\n }\n case \"multiple_of\": {\n const message = check.message ?? g.typeMsg;\n const msgProp = message !== undefined ? `,message:${JSON.stringify(message)}` : \"\";\n // zod uses a float-safe remainder: raw % mis-rejects 0.3 % 0.1\n const fsr = emitRuntimeHelper(g.ctx, \"__zcFsr\", ZC_FSR_DECL);\n code += emit`\n if(${fsr}(${g.input},${check.value})!==0){\n ${g.issues}.push({origin:\"number\",code:\"not_multiple_of\",divisor:${check.value},input:${g.input},path:${g.path}${msgProp}});\n }`;\n break;\n }\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 }\n if (opensIntGuard(check)) seenIntFormat = true;\n }\n if (intGuardOpen) code += `}`;\n code += `}`;\n }\n\n return `${code}\\n`;\n}\n\nexport function fastNumber(ir: NumberIR, g: FastGen): string | null {\n if (ir.coerce) return null;\n\n const x = g.input;\n const checks = ir.checks.filter((c): c is CheckIR => c.kind !== \"refine_effect\");\n\n // Number.isFinite(x) alone implies typeof number && !NaN && finite — zod's\n // entire number type gate in one non-coercing intrinsic. Likewise\n // Number.isSafeInteger covers the safeint format gate. Only the bitwise int\n // formats ((x|0)===x, (x>>>0)===x) still need the typeof guard: applying\n // ToNumber to an arbitrary input would invoke valueOf side effects zod\n // never triggers. Math.fround(Infinity)===Infinity, so float32 keeps the\n // isFinite gate.\n const hasSafeInt = checks.some((c) => c.kind === \"number_format\" && c.format === \"safeint\");\n const hasBitwiseInt = checks.some(\n (c) => c.kind === \"number_format\" && (c.format === \"int32\" || c.format === \"uint32\"),\n );\n const parts: string[] = [];\n if (hasBitwiseInt) {\n parts.push(`typeof ${x}===\"number\"`);\n } else if (!hasSafeInt) {\n parts.push(`Number.isFinite(${x})`);\n }\n\n for (const check of checks.sort(checkPriority)) {\n switch (check.kind) {\n case \"number_format\":\n switch (check.format) {\n case \"safeint\":\n parts.push(`Number.isSafeInteger(${x})`);\n break;\n case \"int32\":\n parts.push(`(${x}|0)===${x}`);\n break;\n case \"uint32\":\n parts.push(`${x}>=0`, `${x}<=4294967295`, `(${x}>>>0)===${x}`);\n break;\n case \"float32\":\n // zod's float32 check is a pure RANGE check (3.14 is accepted\n // even though Math.fround(3.14) !== 3.14) — fround here would\n // make the fast path stricter than the slow path / zod.\n parts.push(`${x}>=-3.4028234663852886e+38`, `${x}<=3.4028234663852886e+38`);\n break;\n case \"float64\":\n // All finite numbers are valid float64\n break;\n }\n break;\n case \"greater_than\":\n parts.push(check.inclusive ? `${x}>=${check.value}` : `${x}>${check.value}`);\n break;\n case \"less_than\":\n parts.push(check.inclusive ? `${x}<=${check.value}` : `${x}<${check.value}`);\n break;\n case \"multiple_of\": {\n const fsr = emitRuntimeHelper(g.ctx, \"__zcFsr\", ZC_FSR_DECL);\n parts.push(`${fsr}(${x},${check.value})===0`);\n break;\n }\n case \"min_length\":\n case \"max_length\":\n case \"length_equals\":\n case \"string_format\":\n case \"includes\":\n case \"starts_with\":\n case \"ends_with\":\n // String-only checks on a number schema — shouldn't happen, skip\n break;\n }\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":"number.js","names":[],"sources":["../../../../src/core/codegen/schemas/number.ts"],"sourcesContent":["import type { CheckIR, NumberIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { checkPriority, emitRuntimeHelper } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\nimport { ZC_FSR_DECL } from \"../issue-decls.js\";\nimport { fastRefineTest, refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\n\n/**\n * The integer number formats, each with the range zod's `NUMBER_FORMAT_RANGES`\n * gives it. `null` for safeint, whose own range IS the safe-integer range that\n * every integer format reports first (see the number_format case below), so it\n * has no range branch of its own. float32/float64 are absent on purpose: they\n * are pure range checks and never report `invalid_type`.\n */\nconst INT_FORMAT_RANGES: { readonly [format: string]: readonly [number, number] | null } = {\n int32: [-2147483648, 2147483647],\n safeint: null,\n uint32: [0, 4294967295],\n};\n\nexport function slowNumber(ir: NumberIR, g: SlowGen): string {\n let code = \"\";\n if (ir.coerce) {\n code += emit`try{${g.output}=Number(${g.input});}catch(_){}`;\n }\n code += emit`\n if(typeof ${g.input}!==\"number\"){\n ${invalidType(g, \"number\")}\n }else if(Number.isNaN(${g.input})){\n ${invalidType(g, \"number\", { extra: 'received:\"NaN\"' })}\n }else if(!Number.isFinite(${g.input})){\n ${invalidType(g, \"number\", { extra: `received:String(${g.input})` })}\n }`;\n\n if (ir.checks.length > 0) {\n code += `else{`;\n // An integer FORMAT check (`.int()`, `.int32()`, `.uint32()`) is the one\n // check here that can report `invalid_type` — non-continuable — and zod's\n // `runChecks` then skips every check after it (`else if (isAborted)\n // continue`). So `z.number().int().min(5)` on 1.5 reports the int failure\n // ALONE, where an ungated chain also volunteers too_small. Its aborting\n // branch is exactly `!Number.isInteger(value)` (the range branches report\n // continuable too_small/too_big, which do NOT stop later checks), so one\n // guard opened after the first such check reproduces zod without any\n // runtime abort bookkeeping. Non-integer formats (float32/float64) never\n // report invalid_type and so never open it.\n const opensIntGuard = (check: (typeof ir.checks)[number]): boolean =>\n check.kind === \"number_format\" && INT_FORMAT_RANGES[check.format] !== undefined;\n let seenIntFormat = false;\n let intGuardOpen = false;\n // Insertion order mirrors zod's issue order for multi-failure inputs.\n // The slow path collects ALL issues (no short-circuit), so cost ordering\n // buys nothing here — only the fast path's && chain benefits from it.\n for (const check of ir.checks) {\n // Opened lazily, on the first check that actually needs gating: an integer\n // format check in LAST position has nothing after it, so the guard would\n // be dead code.\n if (seenIntFormat && !intGuardOpen) {\n code += `if(Number.isInteger(${g.input})){`;\n intGuardOpen = true;\n }\n switch (check.kind) {\n case \"greater_than\":\n if (check.inclusive) {\n code += emit`\n if(${g.input}<${check.value}){\n ${tooSmall(g, check.value, \"number\", true, { message: check.message })}\n }`;\n } else {\n code += emit`\n if(${g.input}<=${check.value}){\n ${tooSmall(g, check.value, \"number\", false, { message: check.message })}\n }`;\n }\n break;\n case \"less_than\":\n if (check.inclusive) {\n code += emit`\n if(${g.input}>${check.value}){\n ${tooBig(g, check.value, \"number\", true, { message: check.message })}\n }`;\n } else {\n code += emit`\n if(${g.input}>=${check.value}){\n ${tooBig(g, check.value, \"number\", false, { message: check.message })}\n }`;\n }\n break;\n case \"number_format\": {\n const message = check.message ?? g.typeMsg;\n const intRange = INT_FORMAT_RANGES[check.format];\n if (intRange !== undefined) {\n // Mirrors $ZodCheckNumberFormat's integer branch, in ITS order: a\n // non-integer is an aborting `invalid_type`; an integer outside the\n // SAFE range is reported against the safe bounds — origin \"int\",\n // zod's explanatory note — and the check returns there, whatever the\n // format's own range says; only a safe integer reaches the format\n // range, reported with origin \"number\". So `z.int32()` on 1e21 is a\n // too_big with `maximum: 2^53-1` and origin \"int\", not one with\n // 2147483647 and origin \"number\" (the format range never runs for it),\n // and the same input against `z.int32().max(10)` reports BOTH the\n // safe-range issue and the max — the safe-range issue is continuable,\n // so later checks still run (see the isInteger guard above). safeint's\n // own range IS the safe range, so its third branch is dead and omitted.\n //\n // Key order is zod's push order minus the fields its finalizer\n // strips: `{code, maximum, note, origin, inclusive}` for the safe\n // range, where a format-range issue leads with `origin` like any\n // check-created size issue.\n const note = `note:\"Integers must be within the safe integer range.\"`;\n const msgProp = message !== undefined ? `,message:${JSON.stringify(message)}` : \"\";\n code += emit`\n if(!Number.isInteger(${g.input})){\n ${invalidType(g, \"int\", { extra: `format:\"${check.format}\"`, extraBeforeCode: true, message })}\n }else if(!Number.isSafeInteger(${g.input})){\n if(${g.input}>0){\n ${g.issues}.push({code:\"too_big\",maximum:9007199254740991,${note},origin:\"int\",inclusive:true,input:${g.input},path:${g.path}${msgProp}});\n }else{\n ${g.issues}.push({code:\"too_small\",minimum:-9007199254740991,${note},origin:\"int\",inclusive:true,input:${g.input},path:${g.path}${msgProp}});\n }\n }`;\n if (intRange !== null) {\n const [minimum, maximum] = intRange;\n code += emit`\n else if(${g.input}<${minimum}){\n ${tooSmall(g, minimum, \"number\", true, { message })}\n }else if(${g.input}>${maximum}){\n ${tooBig(g, maximum, \"number\", true, { message })}\n }`;\n }\n } else if (check.format === \"float32\") {\n code += emit`\n if(${g.input}<-3.4028234663852886e+38){\n ${tooSmall(g, \"-3.4028234663852886e+38\", \"number\", true, { message })}\n }else if(${g.input}>3.4028234663852886e+38){\n ${tooBig(g, \"3.4028234663852886e+38\", \"number\", true, { message })}\n }`;\n }\n // float64 range is [-Number.MAX_VALUE, Number.MAX_VALUE], already covered by the isFinite check above\n break;\n }\n case \"multiple_of\": {\n const message = check.message ?? g.typeMsg;\n const msgProp = message !== undefined ? `,message:${JSON.stringify(message)}` : \"\";\n // zod uses a float-safe remainder: raw % mis-rejects 0.3 % 0.1\n const fsr = emitRuntimeHelper(g.ctx, \"__zcFsr\", ZC_FSR_DECL);\n code += emit`\n if(${fsr}(${g.input},${check.value})!==0){\n ${g.issues}.push({origin:\"number\",code:\"not_multiple_of\",divisor:${check.value},input:${g.input},path:${g.path}${msgProp}});\n }`;\n break;\n }\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 }\n if (opensIntGuard(check)) seenIntFormat = true;\n }\n if (intGuardOpen) code += `}`;\n code += `}`;\n }\n\n return `${code}\\n`;\n}\n\nexport function fastNumber(ir: NumberIR, g: FastGen): string | null {\n if (ir.coerce) return null;\n\n const x = g.input;\n const checks = ir.checks.filter((c): c is CheckIR => c.kind !== \"refine_effect\");\n\n // Number.isFinite(x) alone implies typeof number && !NaN && finite — zod's\n // entire number type gate in one non-coercing intrinsic. Likewise\n // Number.isSafeInteger covers the safeint format gate. Only the bitwise int\n // formats ((x|0)===x, (x>>>0)===x) still need the typeof guard: applying\n // ToNumber to an arbitrary input would invoke valueOf side effects zod\n // never triggers. Math.fround(Infinity)===Infinity, so float32 keeps the\n // isFinite gate.\n const hasSafeInt = checks.some((c) => c.kind === \"number_format\" && c.format === \"safeint\");\n const hasBitwiseInt = checks.some(\n (c) => c.kind === \"number_format\" && (c.format === \"int32\" || c.format === \"uint32\"),\n );\n const parts: string[] = [];\n if (hasBitwiseInt) {\n parts.push(`typeof ${x}===\"number\"`);\n } else if (!hasSafeInt) {\n parts.push(`Number.isFinite(${x})`);\n }\n\n for (const check of checks.sort(checkPriority)) {\n switch (check.kind) {\n case \"number_format\":\n switch (check.format) {\n case \"safeint\":\n parts.push(`Number.isSafeInteger(${x})`);\n break;\n case \"int32\":\n parts.push(`(${x}|0)===${x}`);\n break;\n case \"uint32\":\n parts.push(`${x}>=0`, `${x}<=4294967295`, `(${x}>>>0)===${x}`);\n break;\n case \"float32\":\n // zod's float32 check is a pure RANGE check (3.14 is accepted\n // even though Math.fround(3.14) !== 3.14) — fround here would\n // make the fast path stricter than the slow path / zod.\n parts.push(`${x}>=-3.4028234663852886e+38`, `${x}<=3.4028234663852886e+38`);\n break;\n case \"float64\":\n // All finite numbers are valid float64\n break;\n }\n break;\n case \"greater_than\":\n parts.push(check.inclusive ? `${x}>=${check.value}` : `${x}>${check.value}`);\n break;\n case \"less_than\":\n parts.push(check.inclusive ? `${x}<=${check.value}` : `${x}<${check.value}`);\n break;\n case \"multiple_of\": {\n const fsr = emitRuntimeHelper(g.ctx, \"__zcFsr\", ZC_FSR_DECL);\n parts.push(`${fsr}(${x},${check.value})===0`);\n break;\n }\n case \"min_length\":\n case \"max_length\":\n case \"length_equals\":\n case \"string_format\":\n case \"includes\":\n case \"starts_with\":\n case \"ends_with\":\n // String-only checks on a number schema — shouldn't happen, skip\n break;\n }\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":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/object.ts"],"mappings":";;;;;;;;;;;;iBA4BgB,iBAAiB,IAAI,oBAAoB;iBAIzC,WAAW,IAAI;EAAa;GAAkB,GAAG;iBA4TjD,WAAW,IAAI,UAAU,GAAG"}
1
+ {"version":3,"file":"object.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/object.ts"],"mappings":";;;;;;;;;;;;iBA2BgB,iBAAiB,IAAI,oBAAoB;iBAIzC,WAAW,IAAI;EAAa;GAAkB,GAAG;iBAiXjD,WAAW,IAAI,UAAU,GAAG"}
@@ -1,8 +1,8 @@
1
- import { declareFastTemps, emitEffectCallable, emitRuntimeHelper, escapeString, extendPath, extendStaticPath, hasMutation, keyMembershipTest, outputAlwaysDefined } from "../context.js";
1
+ import { declareFastTemps, emitRuntimeHelper, escapeString, extendPath, extendStaticPath, hasMutation, keyMembershipTest, outputAlwaysDefined } from "../context.js";
2
2
  import { emit } from "../emit.js";
3
3
  import { invalidType, unrecognizedKeys } from "../emit-issue.js";
4
4
  import { ZC_AB_DECL, ZC_PROTO_SCRUB_DECL } from "../issue-decls.js";
5
- import { refineCheck, superRefineCheck, superRefineFastTest } from "./effect.js";
5
+ import { fastRefineTest, refineCheck, superRefineCheck, superRefineFastTest } from "./effect.js";
6
6
  import { orderByRuntimeCost } from "../fast-size.js";
7
7
  //#region src/core/codegen/schemas/object.ts
8
8
  /**
@@ -23,38 +23,55 @@ function slowObject(ir, g) {
23
23
  ${invalidType(g, "object")}
24
24
  }else{`;
25
25
  const strip = ir.stripUnknownKeys === true;
26
- const needsClone = strip || ir.catchall !== void 0 && hasMutation(ir.catchall) || Object.values(ir.properties).some(hasMutation);
26
+ const rebuild = strip || ir.catchall !== void 0 && hasMutation(ir.catchall) || Object.values(ir.properties).some(hasMutation);
27
27
  const objVar = g.temp("o");
28
- if (!strip) {
29
- code += needsClone ? `var ${objVar}={...${g.input}};` : `var ${objVar}=${g.input};`;
28
+ if (!rebuild) {
29
+ code += `var ${objVar}=${g.input};`;
30
30
  const scrub = emitRuntimeHelper(g.ctx, "__zcPs", ZC_PROTO_SCRUB_DECL);
31
31
  code += `${objVar}=${scrub}(${objVar});`;
32
32
  }
33
+ /**
34
+ * Pass-through only: land a nested node's REPLACEMENT value on the output.
35
+ * A pass-through property never rewrites its value (that is what
36
+ * pass-through means), but a nested object or record can still hand back a
37
+ * proto-scrubbed COPY of its input, and that copy has to reach the output
38
+ * object — not the caller's object. Writing it straight into `objVar` did
39
+ * exactly that when `objVar` was the input: the caller's own object was
40
+ * edited in place (its nested value swapped for the copy), and a frozen
41
+ * input threw "Cannot assign to read only property" out of `safeParse`. So
42
+ * the output becomes a copy of its own the first time a replacement lands,
43
+ * and only then. Spread is safe here: `objVar` is still the input only when
44
+ * the scrub above found no own `__proto__` on it.
45
+ */
46
+ const handoff = (outVar, inVar, keyExpr) => `if(${outVar}!==${inVar}){if(${objVar}===${g.input}){${objVar}={...${g.input}};}${objVar}[${keyExpr}]=${outVar};}`;
33
47
  const refineMark = ir.checks && ir.checks.length > 0 ? g.temp("rm") : "";
34
48
  if (refineMark) code += `var ${refineMark}=${g.issues}.length;`;
35
49
  const skipAbsent = new Set(ir.skipAbsentKeys ?? []);
36
50
  const suppressAbsent = new Set(ir.suppressAbsentKeys ?? []);
37
51
  const nonoptional = new Set(ir.nonoptionalKeys ?? []);
38
- /** Strip only: per-property output slot + whether it is always in the result. */
52
+ /** Rebuild only: per-property output slot + whether it is always in the result. */
39
53
  const slots = [];
40
54
  for (const [key, propIR] of parsedProperties(ir)) {
41
55
  const keyStr = escapeString(key);
42
56
  const propPath = extendStaticPath(g.path, key);
43
- const propExpr = strip ? g.temp("sv") : `${objVar}[${keyStr}]`;
44
- if (strip) {
45
- code += `var ${propExpr}=${g.input}[${keyStr}];`;
46
- slots.push({
47
- always: outputAlwaysDefined(propIR),
48
- keyStr,
49
- value: propExpr
50
- });
57
+ const propExpr = g.temp("sv");
58
+ code += `var ${propExpr}=${g.input}[${keyStr}];`;
59
+ let outExpr = propExpr;
60
+ if (rebuild) slots.push({
61
+ always: outputAlwaysDefined(propIR),
62
+ keyStr,
63
+ value: propExpr
64
+ });
65
+ else {
66
+ outExpr = g.temp("ov");
67
+ code += `var ${outExpr}=${propExpr};`;
51
68
  }
52
69
  const propCode = g.visit(propIR, {
53
70
  input: propExpr,
54
- output: propExpr,
71
+ output: outExpr,
55
72
  path: propPath
56
73
  });
57
- const dropValue = strip ? `${propExpr}=undefined;` : `delete ${objVar}[${keyStr}];`;
74
+ const dropValue = rebuild ? `${propExpr}=undefined;` : `${outExpr}=${propExpr};`;
58
75
  if (skipAbsent.has(key)) code += emit`if(${keyStr} in ${g.input}){${propCode}}`;
59
76
  else if (suppressAbsent.has(key)) {
60
77
  const beforeVar = g.temp("ob");
@@ -85,8 +102,9 @@ function slowObject(ir, g) {
85
102
  }
86
103
  }`;
87
104
  } else code += propCode;
105
+ if (!rebuild) code += handoff(outExpr, propExpr, keyStr);
88
106
  }
89
- if (strip) {
107
+ if (rebuild) {
90
108
  const literal = [];
91
109
  let appends = "";
92
110
  let leading = true;
@@ -99,6 +117,14 @@ function slowObject(ir, g) {
99
117
  appends += slot.always ? `${objVar}[${slot.keyStr}]=${slot.value};` : `if(${slot.value}!==undefined||(${slot.keyStr} in ${g.input})){${objVar}[${slot.keyStr}]=${slot.value};}`;
100
118
  }
101
119
  code += `var ${objVar}={${literal.join(",")}};${appends}`;
120
+ if (!strip && !ir.strict && ir.catchall === void 0) {
121
+ const kVar = g.temp("lk");
122
+ const test = keyMembershipTest(g.ctx, Object.keys(ir.properties), kVar);
123
+ code += emit`
124
+ for(var ${kVar} in ${g.input}){
125
+ if(!(${test})&&${kVar}!=="__proto__"){${objVar}[${kVar}]=${g.input}[${kVar}];}
126
+ }`;
127
+ }
102
128
  }
103
129
  if (ir.strict) {
104
130
  const keys = Object.keys(ir.properties);
@@ -118,21 +144,30 @@ function slowObject(ir, g) {
118
144
  const keys = Object.keys(ir.properties);
119
145
  const kVar = g.temp("ck");
120
146
  const test = keyMembershipTest(g.ctx, keys, kVar);
121
- const slot = `${objVar}[${kVar}]`;
122
- const seed = needsClone ? `${slot}=${g.input}[${kVar}];` : "";
147
+ const catchallPath = extendPath(g.path, kVar);
148
+ let body;
149
+ if (rebuild) {
150
+ const slot = `${objVar}[${kVar}]`;
151
+ body = `${slot}=${g.input}[${kVar}];${g.visit(ir.catchall, {
152
+ input: slot,
153
+ output: slot,
154
+ path: catchallPath
155
+ })}`;
156
+ } else {
157
+ const inVar = g.temp("cv");
158
+ const outVar = g.temp("co");
159
+ body = `var ${inVar}=${g.input}[${kVar}];var ${outVar}=${inVar};` + g.visit(ir.catchall, {
160
+ input: inVar,
161
+ output: outVar,
162
+ path: catchallPath
163
+ }) + handoff(outVar, inVar, kVar);
164
+ }
123
165
  code += emit`
124
166
  for(var ${kVar} in ${g.input}){
125
- if(!(${test})&&${kVar}!=="__proto__"){
126
- ${seed}
127
- ${g.visit(ir.catchall, {
128
- input: slot,
129
- output: slot,
130
- path: extendPath(g.path, kVar)
131
- })}
132
- }
167
+ if(!(${test})&&${kVar}!=="__proto__"){${body}}
133
168
  }`;
134
169
  }
135
- if (needsClone || !strip) code += `${g.output}=${objVar};`;
170
+ code += `${g.output}=${objVar};`;
136
171
  if (ir.checks && ir.checks.length > 0) {
137
172
  let refines = "";
138
173
  for (const check of ir.checks) refines += check.kind === "super_refine_effect" ? superRefineCheck(check, objVar, g) : refineCheck(check, objVar, g);
@@ -199,7 +234,7 @@ function fastObjectBody(ir, g, skipKey) {
199
234
  }
200
235
  }
201
236
  if (ir.checks) {
202
- for (const check of ir.checks) if (check.kind === "refine_effect") parts.push(`${emitEffectCallable(g.ctx, check)}(${x})`);
237
+ for (const check of ir.checks) if (check.kind === "refine_effect") parts.push(fastRefineTest(check, x, g));
203
238
  else if (check.kind === "super_refine_effect") parts.push(superRefineFastTest(check, x, g));
204
239
  }
205
240
  return parts;