zod-compiler 1.23.6 → 1.23.7

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 (94) hide show
  1. package/dist/core/codegen/build-path.d.ts.map +1 -1
  2. package/dist/core/codegen/build-path.js +57 -6
  3. package/dist/core/codegen/build-path.js.map +1 -1
  4. package/dist/core/codegen/context.d.ts +23 -3
  5. package/dist/core/codegen/context.d.ts.map +1 -1
  6. package/dist/core/codegen/context.js +23 -1
  7. package/dist/core/codegen/context.js.map +1 -1
  8. package/dist/core/codegen/dedupe.js +4 -1
  9. package/dist/core/codegen/dedupe.js.map +1 -1
  10. package/dist/core/codegen/emit-issue.d.ts +27 -2
  11. package/dist/core/codegen/emit-issue.d.ts.map +1 -1
  12. package/dist/core/codegen/emit-issue.js +8 -3
  13. package/dist/core/codegen/emit-issue.js.map +1 -1
  14. package/dist/core/codegen/issue-decls.d.ts +9 -3
  15. package/dist/core/codegen/issue-decls.d.ts.map +1 -1
  16. package/dist/core/codegen/issue-decls.js +10 -4
  17. package/dist/core/codegen/issue-decls.js.map +1 -1
  18. package/dist/core/codegen/schemas/catch.d.ts.map +1 -1
  19. package/dist/core/codegen/schemas/catch.js +1 -1
  20. package/dist/core/codegen/schemas/catch.js.map +1 -1
  21. package/dist/core/codegen/schemas/discriminated-union.d.ts.map +1 -1
  22. package/dist/core/codegen/schemas/discriminated-union.js +11 -3
  23. package/dist/core/codegen/schemas/discriminated-union.js.map +1 -1
  24. package/dist/core/codegen/schemas/effect.d.ts.map +1 -1
  25. package/dist/core/codegen/schemas/effect.js +3 -2
  26. package/dist/core/codegen/schemas/effect.js.map +1 -1
  27. package/dist/core/codegen/schemas/enum.d.ts.map +1 -1
  28. package/dist/core/codegen/schemas/enum.js +25 -0
  29. package/dist/core/codegen/schemas/enum.js.map +1 -1
  30. package/dist/core/codegen/schemas/literal.d.ts.map +1 -1
  31. package/dist/core/codegen/schemas/literal.js +37 -3
  32. package/dist/core/codegen/schemas/literal.js.map +1 -1
  33. package/dist/core/codegen/schemas/string-bool.d.ts.map +1 -1
  34. package/dist/core/codegen/schemas/string-bool.js +3 -2
  35. package/dist/core/codegen/schemas/string-bool.js.map +1 -1
  36. package/dist/core/codegen/schemas/string.d.ts.map +1 -1
  37. package/dist/core/codegen/schemas/string.js +13 -7
  38. package/dist/core/codegen/schemas/string.js.map +1 -1
  39. package/dist/core/codegen/schemas/template-literal.d.ts.map +1 -1
  40. package/dist/core/codegen/schemas/template-literal.js +2 -2
  41. package/dist/core/codegen/schemas/template-literal.js.map +1 -1
  42. package/dist/core/codegen/schemas/tuple.d.ts +11 -5
  43. package/dist/core/codegen/schemas/tuple.d.ts.map +1 -1
  44. package/dist/core/codegen/schemas/tuple.js +12 -6
  45. package/dist/core/codegen/schemas/tuple.js.map +1 -1
  46. package/dist/core/codegen/schemas/union.d.ts.map +1 -1
  47. package/dist/core/codegen/schemas/union.js +17 -17
  48. package/dist/core/codegen/schemas/union.js.map +1 -1
  49. package/dist/core/extract/checks.d.ts +18 -2
  50. package/dist/core/extract/checks.d.ts.map +1 -1
  51. package/dist/core/extract/checks.js +138 -11
  52. package/dist/core/extract/checks.js.map +1 -1
  53. package/dist/core/extract/extractors/array.d.ts.map +1 -1
  54. package/dist/core/extract/extractors/array.js +2 -2
  55. package/dist/core/extract/extractors/array.js.map +1 -1
  56. package/dist/core/extract/extractors/intersection.js +44 -0
  57. package/dist/core/extract/extractors/intersection.js.map +1 -1
  58. package/dist/core/extract/extractors/lazy.d.ts.map +1 -1
  59. package/dist/core/extract/extractors/lazy.js +2 -13
  60. package/dist/core/extract/extractors/lazy.js.map +1 -1
  61. package/dist/core/extract/extractors/literal.d.ts +14 -0
  62. package/dist/core/extract/extractors/literal.d.ts.map +1 -1
  63. package/dist/core/extract/extractors/literal.js +32 -4
  64. package/dist/core/extract/extractors/literal.js.map +1 -1
  65. package/dist/core/extract/extractors/number.d.ts.map +1 -1
  66. package/dist/core/extract/extractors/number.js +2 -2
  67. package/dist/core/extract/extractors/number.js.map +1 -1
  68. package/dist/core/extract/extractors/object.d.ts.map +1 -1
  69. package/dist/core/extract/extractors/object.js +2 -2
  70. package/dist/core/extract/extractors/object.js.map +1 -1
  71. package/dist/core/extract/extractors/record.d.ts.map +1 -1
  72. package/dist/core/extract/extractors/record.js +2 -0
  73. package/dist/core/extract/extractors/record.js.map +1 -1
  74. package/dist/core/extract/extractors/string.d.ts.map +1 -1
  75. package/dist/core/extract/extractors/string.js +2 -2
  76. package/dist/core/extract/extractors/string.js.map +1 -1
  77. package/dist/core/extract/extractors/union.js +2 -0
  78. package/dist/core/extract/extractors/union.js.map +1 -1
  79. package/dist/core/extract/recursion.d.ts +26 -0
  80. package/dist/core/extract/recursion.d.ts.map +1 -0
  81. package/dist/core/extract/recursion.js +37 -0
  82. package/dist/core/extract/recursion.js.map +1 -0
  83. package/dist/core/extract/registry.d.ts.map +1 -1
  84. package/dist/core/extract/registry.js +2 -0
  85. package/dist/core/extract/registry.js.map +1 -1
  86. package/dist/core/extract/types.d.ts +21 -6
  87. package/dist/core/extract/types.d.ts.map +1 -1
  88. package/dist/core/iife.d.ts +13 -0
  89. package/dist/core/iife.d.ts.map +1 -1
  90. package/dist/core/iife.js +14 -1
  91. package/dist/core/iife.js.map +1 -1
  92. package/dist/core/types.d.ts +49 -2
  93. package/dist/core/types.d.ts.map +1 -1
  94. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"number.js","names":[],"sources":["../../../../src/core/extract/extractors/number.ts"],"sourcesContent":["import type { CheckOrEffectIR, SchemaIR } from \"../../types.js\";\nimport {\n extractChecks,\n payloadCheckRef,\n refineRefRegistrar,\n resolveCheckMessage,\n} from \"../checks.js\";\nimport type { ExtractorContext, ZodDef } from \"../types.js\";\n\n/** Check kinds the number codegen knows how to emit. Anything else → fallback. */\nconst NUMBER_CHECK_KINDS = new Set([\n \"greater_than\",\n \"less_than\",\n \"multiple_of\",\n \"number_format\",\n \"refine_effect\",\n \"super_refine_effect\",\n]);\n\nexport function extractNumber(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n const coerce = def.coerce ? { coerce: true as const } : {};\n const allChecks: CheckOrEffectIR[] = [];\n\n // Number format schemas (z.int(), z.int32(), ...): the schema def doubles as\n // its own check def. Schema-level custom error applies to the format issue.\n if (def.check === \"number_format\" && def.format) {\n const resolved = resolveCheckMessage(def.error);\n if (resolved.kind === \"dynamic\") return ctx.fallback(\"refine\");\n allChecks.push({\n kind: \"number_format\",\n format: def.format as \"safeint\" | \"int32\" | \"uint32\" | \"float32\" | \"float64\",\n ...(resolved.kind === \"static\" ? { message: resolved.message } : {}),\n });\n }\n\n // Appended checks (.min(), .refine(), ... — also present on format schemas\n // like z.int().refine(fn), which previously lost them entirely).\n if (def.checks && def.checks.length > 0) {\n const { checkIRs, hasFallback } = extractChecks(\n def.checks,\n refineRefRegistrar(ctx, def.checks),\n (index) => payloadCheckRef(ctx, def.checks, index),\n );\n if (hasFallback) return ctx.fallback(\"refine\");\n allChecks.push(...checkIRs);\n }\n\n if (allChecks.some((c) => !NUMBER_CHECK_KINDS.has(c.kind))) {\n return ctx.fallback(\"unsupported\");\n }\n\n return { type: \"number\", checks: allChecks, ...coerce };\n}\n"],"mappings":";;;AAUA,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,cAAc,KAAa,KAAiC;CAC1E,MAAM,SAAS,IAAI,SAAS,EAAE,QAAQ,KAAc,IAAI,CAAC;CACzD,MAAM,YAA+B,CAAC;CAItC,IAAI,IAAI,UAAU,mBAAmB,IAAI,QAAQ;EAC/C,MAAM,WAAW,oBAAoB,IAAI,KAAK;EAC9C,IAAI,SAAS,SAAS,WAAW,OAAO,IAAI,SAAS,QAAQ;EAC7D,UAAU,KAAK;GACb,MAAM;GACN,QAAQ,IAAI;GACZ,GAAI,SAAS,SAAS,WAAW,EAAE,SAAS,SAAS,QAAQ,IAAI,CAAC;EACpE,CAAC;CACH;CAIA,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,GAAG;EACvC,MAAM,EAAE,UAAU,gBAAgB,cAChC,IAAI,QACJ,mBAAmB,KAAK,IAAI,MAAM,IACjC,UAAU,gBAAgB,KAAK,IAAI,QAAQ,KAAK,CACnD;EACA,IAAI,aAAa,OAAO,IAAI,SAAS,QAAQ;EAC7C,UAAU,KAAK,GAAG,QAAQ;CAC5B;CAEA,IAAI,UAAU,MAAM,MAAM,CAAC,mBAAmB,IAAI,EAAE,IAAI,CAAC,GACvD,OAAO,IAAI,SAAS,aAAa;CAGnC,OAAO;EAAE,MAAM;EAAU,QAAQ;EAAW,GAAG;CAAO;AACxD"}
1
+ {"version":3,"file":"number.js","names":[],"sources":["../../../../src/core/extract/extractors/number.ts"],"sourcesContent":["import type { CheckOrEffectIR, SchemaIR } from \"../../types.js\";\nimport {\n customParamsRefRegistrar,\n extractChecks,\n payloadCheckRef,\n refineRefRegistrar,\n resolveCheckMessage,\n} from \"../checks.js\";\nimport type { ExtractorContext, ZodDef } from \"../types.js\";\n\n/** Check kinds the number codegen knows how to emit. Anything else → fallback. */\nconst NUMBER_CHECK_KINDS = new Set([\n \"greater_than\",\n \"less_than\",\n \"multiple_of\",\n \"number_format\",\n \"refine_effect\",\n \"super_refine_effect\",\n]);\n\nexport function extractNumber(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n const coerce = def.coerce ? { coerce: true as const } : {};\n const allChecks: CheckOrEffectIR[] = [];\n\n // Number format schemas (z.int(), z.int32(), ...): the schema def doubles as\n // its own check def. Schema-level custom error applies to the format issue.\n if (def.check === \"number_format\" && def.format) {\n const resolved = resolveCheckMessage(def.error);\n if (resolved.kind === \"dynamic\") return ctx.fallback(\"refine\");\n allChecks.push({\n kind: \"number_format\",\n format: def.format as \"safeint\" | \"int32\" | \"uint32\" | \"float32\" | \"float64\",\n ...(resolved.kind === \"static\" ? { message: resolved.message } : {}),\n });\n }\n\n // Appended checks (.min(), .refine(), ... — also present on format schemas\n // like z.int().refine(fn), which previously lost them entirely).\n if (def.checks && def.checks.length > 0) {\n const { checkIRs, hasFallback } = extractChecks(\n def.checks,\n refineRefRegistrar(ctx, def.checks),\n (index) => payloadCheckRef(ctx, def.checks, index),\n customParamsRefRegistrar(ctx, def.checks),\n );\n if (hasFallback) return ctx.fallback(\"refine\");\n allChecks.push(...checkIRs);\n }\n\n if (allChecks.some((c) => !NUMBER_CHECK_KINDS.has(c.kind))) {\n return ctx.fallback(\"unsupported\");\n }\n\n return { type: \"number\", checks: allChecks, ...coerce };\n}\n"],"mappings":";;;AAWA,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,cAAc,KAAa,KAAiC;CAC1E,MAAM,SAAS,IAAI,SAAS,EAAE,QAAQ,KAAc,IAAI,CAAC;CACzD,MAAM,YAA+B,CAAC;CAItC,IAAI,IAAI,UAAU,mBAAmB,IAAI,QAAQ;EAC/C,MAAM,WAAW,oBAAoB,IAAI,KAAK;EAC9C,IAAI,SAAS,SAAS,WAAW,OAAO,IAAI,SAAS,QAAQ;EAC7D,UAAU,KAAK;GACb,MAAM;GACN,QAAQ,IAAI;GACZ,GAAI,SAAS,SAAS,WAAW,EAAE,SAAS,SAAS,QAAQ,IAAI,CAAC;EACpE,CAAC;CACH;CAIA,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,GAAG;EACvC,MAAM,EAAE,UAAU,gBAAgB,cAChC,IAAI,QACJ,mBAAmB,KAAK,IAAI,MAAM,IACjC,UAAU,gBAAgB,KAAK,IAAI,QAAQ,KAAK,GACjD,yBAAyB,KAAK,IAAI,MAAM,CAC1C;EACA,IAAI,aAAa,OAAO,IAAI,SAAS,QAAQ;EAC7C,UAAU,KAAK,GAAG,QAAQ;CAC5B;CAEA,IAAI,UAAU,MAAM,MAAM,CAAC,mBAAmB,IAAI,EAAE,IAAI,CAAC,GACvD,OAAO,IAAI,SAAS,aAAa;CAGnC,OAAO;EAAE,MAAM;EAAU,QAAQ;EAAW,GAAG;CAAO;AACxD"}
@@ -1 +1 @@
1
- {"version":3,"file":"object.d.ts","names":[],"sources":["../../../../src/core/extract/extractors/object.ts"],"mappings":";;;iBAIgB,cAAc,KAAK,QAAQ,KAAK,mBAAmB"}
1
+ {"version":3,"file":"object.d.ts","names":[],"sources":["../../../../src/core/extract/extractors/object.ts"],"mappings":";;;iBASgB,cAAc,KAAK,QAAQ,KAAK,mBAAmB"}
@@ -1,4 +1,4 @@
1
- import { extractChecks, payloadCheckRef, refineRefRegistrar } from "../checks.js";
1
+ import { customParamsRefRegistrar, extractChecks, payloadCheckRef, refineRefRegistrar } from "../checks.js";
2
2
  //#region src/core/extract/extractors/object.ts
3
3
  function extractObject(def, ctx) {
4
4
  const catchallType = def.catchall?._zod?.def?.type;
@@ -23,7 +23,7 @@ function extractObject(def, ctx) {
23
23
  }
24
24
  const suppress = suppressAbsentKeys.length > 0 ? { suppressAbsentKeys } : {};
25
25
  if (def.checks && def.checks.length > 0) {
26
- const { checkIRs, hasFallback } = extractChecks(def.checks, refineRefRegistrar(ctx, def.checks), (index) => payloadCheckRef(ctx, def.checks, index));
26
+ const { checkIRs, hasFallback } = extractChecks(def.checks, refineRefRegistrar(ctx, def.checks), (index) => payloadCheckRef(ctx, def.checks, index), customParamsRefRegistrar(ctx, def.checks));
27
27
  if (hasFallback) return ctx.fallback("refine");
28
28
  if (checkIRs.some((c) => c.kind !== "refine_effect" && c.kind !== "super_refine_effect")) return ctx.fallback("unsupported");
29
29
  const refineChecks = checkIRs.filter((c) => c.kind === "refine_effect" || c.kind === "super_refine_effect");
@@ -1 +1 @@
1
- {"version":3,"file":"object.js","names":[],"sources":["../../../../src/core/extract/extractors/object.ts"],"sourcesContent":["import type { RefineEffectCheckIR, SchemaIR, SuperRefineEffectCheckIR } from \"../../types.js\";\nimport { extractChecks, payloadCheckRef, refineRefRegistrar } from \"../checks.js\";\nimport type { ExtractorContext, ZodDef } from \"../types.js\";\n\nexport function extractObject(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n // Unknown-key policies:\n // - z.strictObject / .strict() / .catchall(z.never()) reject unknown keys —\n // compiled as a for-in membership pass (ObjectIR.strict). Pass-through is\n // preserved: valid strict data has no extras, so no clone is needed.\n // - z.looseObject (catchall: unknown/any) matches compiled pass-through.\n // - .catchall(schema) validates unknown keys against a schema (ObjectIR.catchall).\n // - default z.object() (no catchall): STRIPS unknown keys, as zod does\n // (ObjectIR.stripUnknownKeys). looseObject/strictObject are unaffected —\n // the first keeps extras by design, the second rejects them outright.\n const catchallType = def.catchall?._zod?.def?.type;\n const strict = catchallType === \"never\";\n const valueCatchall =\n def.catchall && !strict && catchallType !== \"unknown\" && catchallType !== \"any\"\n ? ctx.visit(def.catchall, \"._zod.def.catchall\")\n : undefined;\n // A delegating catchall would need zod per unknown key; hand it the object.\n if (valueCatchall?.type === \"fallback\") return ctx.fallback(\"unsupported\");\n const catchallFlag = valueCatchall ? { catchall: valueCatchall } : {};\n const strictFlag = strict ? { strict: true } : {};\n const stripFlag = def.catchall ? {} : { stripUnknownKeys: true };\n\n // Null-prototype: on a normal object `properties[\"__proto__\"] = ir` sets the\n // prototype instead of defining a key, so a shape declaring `__proto__` (only\n // reachable via a computed key or a dynamically built shape — an object\n // literal's `__proto__:` is the same setter) silently lost that property.\n // Every consumer reads this through Object.keys/values/entries, so dropping\n // the prototype is invisible to them.\n const properties: Record<string, SchemaIR> = Object.create(null) as Record<string, SchemaIR>;\n // Fallback props whose zod schema is optional-out: mirror zod's\n // handlePropertyResult, which suppresses issues for ABSENT keys (this is\n // how z.exactOptional() accepts missing keys while rejecting explicit\n // undefined). Compiled optional/default IRs already handle absence.\n const suppressAbsentKeys: string[] = [];\n const refMark = ctx.refs?.length ?? 0;\n for (const [key, value] of Object.entries(def.shape)) {\n const propIR = ctx.visit(value, `.shape[${JSON.stringify(key)}]`);\n properties[key] = propIR;\n if (propIR.type === \"fallback\" && value._zod.optout === \"optional\") {\n suppressAbsentKeys.push(key);\n }\n }\n\n // Fallback coalescing: when EVERY property delegates to Zod, the per-field\n // wrapper (clone + N safeParse calls + issue path rewrites) is pure overhead\n // — measured ~1.4x slower than letting Zod validate the object in one pass.\n // Delegate the whole object instead. The discarded property fallbacks'\n // ref-table entries are rolled back so __rf[] holds only live schemas.\n const propIRs = Object.values(properties);\n if (propIRs.length > 0 && propIRs.every((p) => p.type === \"fallback\")) {\n if (ctx.refs) ctx.refs.length = refMark;\n return ctx.fallback(\"coalesced\");\n }\n const suppress = suppressAbsentKeys.length > 0 ? { suppressAbsentKeys } : {};\n\n if (def.checks && def.checks.length > 0) {\n const { checkIRs, hasFallback } = extractChecks(\n def.checks,\n refineRefRegistrar(ctx, def.checks),\n (index) => payloadCheckRef(ctx, def.checks, index),\n );\n if (hasFallback) return ctx.fallback(\"refine\");\n // Object codegen supports the two callback kinds; anything else (overwrite,\n // exotic .check() entries) must not be dropped.\n if (checkIRs.some((c) => c.kind !== \"refine_effect\" && c.kind !== \"super_refine_effect\")) {\n return ctx.fallback(\"unsupported\");\n }\n const refineChecks = checkIRs.filter(\n (c): c is RefineEffectCheckIR | SuperRefineEffectCheckIR =>\n c.kind === \"refine_effect\" || c.kind === \"super_refine_effect\",\n );\n if (refineChecks.length > 0) {\n return {\n type: \"object\",\n properties,\n checks: refineChecks,\n ...strictFlag,\n ...stripFlag,\n ...catchallFlag,\n ...suppress,\n };\n }\n }\n return { type: \"object\", properties, ...strictFlag, ...stripFlag, ...catchallFlag, ...suppress };\n}\n"],"mappings":";;AAIA,SAAgB,cAAc,KAAa,KAAiC;CAU1E,MAAM,eAAe,IAAI,UAAU,MAAM,KAAK;CAC9C,MAAM,SAAS,iBAAiB;CAChC,MAAM,gBACJ,IAAI,YAAY,CAAC,UAAU,iBAAiB,aAAa,iBAAiB,QACtE,IAAI,MAAM,IAAI,UAAU,oBAAoB,IAC5C,KAAA;CAEN,IAAI,eAAe,SAAS,YAAY,OAAO,IAAI,SAAS,aAAa;CACzE,MAAM,eAAe,gBAAgB,EAAE,UAAU,cAAc,IAAI,CAAC;CACpE,MAAM,aAAa,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;CAChD,MAAM,YAAY,IAAI,WAAW,CAAC,IAAI,EAAE,kBAAkB,KAAK;CAQ/D,MAAM,aAAuC,OAAO,OAAO,IAAI;CAK/D,MAAM,qBAA+B,CAAC;CACtC,MAAM,UAAU,IAAI,MAAM,UAAU;CACpC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,KAAK,GAAG;EACpD,MAAM,SAAS,IAAI,MAAM,OAAO,UAAU,KAAK,UAAU,GAAG,EAAE,EAAE;EAChE,WAAW,OAAO;EAClB,IAAI,OAAO,SAAS,cAAc,MAAM,KAAK,WAAW,YACtD,mBAAmB,KAAK,GAAG;CAE/B;CAOA,MAAM,UAAU,OAAO,OAAO,UAAU;CACxC,IAAI,QAAQ,SAAS,KAAK,QAAQ,OAAO,MAAM,EAAE,SAAS,UAAU,GAAG;EACrE,IAAI,IAAI,MAAM,IAAI,KAAK,SAAS;EAChC,OAAO,IAAI,SAAS,WAAW;CACjC;CACA,MAAM,WAAW,mBAAmB,SAAS,IAAI,EAAE,mBAAmB,IAAI,CAAC;CAE3E,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,GAAG;EACvC,MAAM,EAAE,UAAU,gBAAgB,cAChC,IAAI,QACJ,mBAAmB,KAAK,IAAI,MAAM,IACjC,UAAU,gBAAgB,KAAK,IAAI,QAAQ,KAAK,CACnD;EACA,IAAI,aAAa,OAAO,IAAI,SAAS,QAAQ;EAG7C,IAAI,SAAS,MAAM,MAAM,EAAE,SAAS,mBAAmB,EAAE,SAAS,qBAAqB,GACrF,OAAO,IAAI,SAAS,aAAa;EAEnC,MAAM,eAAe,SAAS,QAC3B,MACC,EAAE,SAAS,mBAAmB,EAAE,SAAS,qBAC7C;EACA,IAAI,aAAa,SAAS,GACxB,OAAO;GACL,MAAM;GACN;GACA,QAAQ;GACR,GAAG;GACH,GAAG;GACH,GAAG;GACH,GAAG;EACL;CAEJ;CACA,OAAO;EAAE,MAAM;EAAU;EAAY,GAAG;EAAY,GAAG;EAAW,GAAG;EAAc,GAAG;CAAS;AACjG"}
1
+ {"version":3,"file":"object.js","names":[],"sources":["../../../../src/core/extract/extractors/object.ts"],"sourcesContent":["import type { RefineEffectCheckIR, SchemaIR, SuperRefineEffectCheckIR } from \"../../types.js\";\nimport {\n customParamsRefRegistrar,\n extractChecks,\n payloadCheckRef,\n refineRefRegistrar,\n} from \"../checks.js\";\nimport type { ExtractorContext, ZodDef } from \"../types.js\";\n\nexport function extractObject(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n // Unknown-key policies:\n // - z.strictObject / .strict() / .catchall(z.never()) reject unknown keys —\n // compiled as a for-in membership pass (ObjectIR.strict). Pass-through is\n // preserved: valid strict data has no extras, so no clone is needed.\n // - z.looseObject (catchall: unknown/any) matches compiled pass-through.\n // - .catchall(schema) validates unknown keys against a schema (ObjectIR.catchall).\n // - default z.object() (no catchall): STRIPS unknown keys, as zod does\n // (ObjectIR.stripUnknownKeys). looseObject/strictObject are unaffected —\n // the first keeps extras by design, the second rejects them outright.\n const catchallType = def.catchall?._zod?.def?.type;\n const strict = catchallType === \"never\";\n const valueCatchall =\n def.catchall && !strict && catchallType !== \"unknown\" && catchallType !== \"any\"\n ? ctx.visit(def.catchall, \"._zod.def.catchall\")\n : undefined;\n // A delegating catchall would need zod per unknown key; hand it the object.\n if (valueCatchall?.type === \"fallback\") return ctx.fallback(\"unsupported\");\n const catchallFlag = valueCatchall ? { catchall: valueCatchall } : {};\n const strictFlag = strict ? { strict: true } : {};\n const stripFlag = def.catchall ? {} : { stripUnknownKeys: true };\n\n // Null-prototype: on a normal object `properties[\"__proto__\"] = ir` sets the\n // prototype instead of defining a key, so a shape declaring `__proto__` (only\n // reachable via a computed key or a dynamically built shape — an object\n // literal's `__proto__:` is the same setter) silently lost that property.\n // Every consumer reads this through Object.keys/values/entries, so dropping\n // the prototype is invisible to them.\n const properties: Record<string, SchemaIR> = Object.create(null) as Record<string, SchemaIR>;\n // Fallback props whose zod schema is optional-out: mirror zod's\n // handlePropertyResult, which suppresses issues for ABSENT keys (this is\n // how z.exactOptional() accepts missing keys while rejecting explicit\n // undefined). Compiled optional/default IRs already handle absence.\n const suppressAbsentKeys: string[] = [];\n const refMark = ctx.refs?.length ?? 0;\n for (const [key, value] of Object.entries(def.shape)) {\n const propIR = ctx.visit(value, `.shape[${JSON.stringify(key)}]`);\n properties[key] = propIR;\n if (propIR.type === \"fallback\" && value._zod.optout === \"optional\") {\n suppressAbsentKeys.push(key);\n }\n }\n\n // Fallback coalescing: when EVERY property delegates to Zod, the per-field\n // wrapper (clone + N safeParse calls + issue path rewrites) is pure overhead\n // — measured ~1.4x slower than letting Zod validate the object in one pass.\n // Delegate the whole object instead. The discarded property fallbacks'\n // ref-table entries are rolled back so __rf[] holds only live schemas.\n const propIRs = Object.values(properties);\n if (propIRs.length > 0 && propIRs.every((p) => p.type === \"fallback\")) {\n if (ctx.refs) ctx.refs.length = refMark;\n return ctx.fallback(\"coalesced\");\n }\n const suppress = suppressAbsentKeys.length > 0 ? { suppressAbsentKeys } : {};\n\n if (def.checks && def.checks.length > 0) {\n const { checkIRs, hasFallback } = extractChecks(\n def.checks,\n refineRefRegistrar(ctx, def.checks),\n (index) => payloadCheckRef(ctx, def.checks, index),\n customParamsRefRegistrar(ctx, def.checks),\n );\n if (hasFallback) return ctx.fallback(\"refine\");\n // Object codegen supports the two callback kinds; anything else (overwrite,\n // exotic .check() entries) must not be dropped.\n if (checkIRs.some((c) => c.kind !== \"refine_effect\" && c.kind !== \"super_refine_effect\")) {\n return ctx.fallback(\"unsupported\");\n }\n const refineChecks = checkIRs.filter(\n (c): c is RefineEffectCheckIR | SuperRefineEffectCheckIR =>\n c.kind === \"refine_effect\" || c.kind === \"super_refine_effect\",\n );\n if (refineChecks.length > 0) {\n return {\n type: \"object\",\n properties,\n checks: refineChecks,\n ...strictFlag,\n ...stripFlag,\n ...catchallFlag,\n ...suppress,\n };\n }\n }\n return { type: \"object\", properties, ...strictFlag, ...stripFlag, ...catchallFlag, ...suppress };\n}\n"],"mappings":";;AASA,SAAgB,cAAc,KAAa,KAAiC;CAU1E,MAAM,eAAe,IAAI,UAAU,MAAM,KAAK;CAC9C,MAAM,SAAS,iBAAiB;CAChC,MAAM,gBACJ,IAAI,YAAY,CAAC,UAAU,iBAAiB,aAAa,iBAAiB,QACtE,IAAI,MAAM,IAAI,UAAU,oBAAoB,IAC5C,KAAA;CAEN,IAAI,eAAe,SAAS,YAAY,OAAO,IAAI,SAAS,aAAa;CACzE,MAAM,eAAe,gBAAgB,EAAE,UAAU,cAAc,IAAI,CAAC;CACpE,MAAM,aAAa,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC;CAChD,MAAM,YAAY,IAAI,WAAW,CAAC,IAAI,EAAE,kBAAkB,KAAK;CAQ/D,MAAM,aAAuC,OAAO,OAAO,IAAI;CAK/D,MAAM,qBAA+B,CAAC;CACtC,MAAM,UAAU,IAAI,MAAM,UAAU;CACpC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,KAAK,GAAG;EACpD,MAAM,SAAS,IAAI,MAAM,OAAO,UAAU,KAAK,UAAU,GAAG,EAAE,EAAE;EAChE,WAAW,OAAO;EAClB,IAAI,OAAO,SAAS,cAAc,MAAM,KAAK,WAAW,YACtD,mBAAmB,KAAK,GAAG;CAE/B;CAOA,MAAM,UAAU,OAAO,OAAO,UAAU;CACxC,IAAI,QAAQ,SAAS,KAAK,QAAQ,OAAO,MAAM,EAAE,SAAS,UAAU,GAAG;EACrE,IAAI,IAAI,MAAM,IAAI,KAAK,SAAS;EAChC,OAAO,IAAI,SAAS,WAAW;CACjC;CACA,MAAM,WAAW,mBAAmB,SAAS,IAAI,EAAE,mBAAmB,IAAI,CAAC;CAE3E,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,GAAG;EACvC,MAAM,EAAE,UAAU,gBAAgB,cAChC,IAAI,QACJ,mBAAmB,KAAK,IAAI,MAAM,IACjC,UAAU,gBAAgB,KAAK,IAAI,QAAQ,KAAK,GACjD,yBAAyB,KAAK,IAAI,MAAM,CAC1C;EACA,IAAI,aAAa,OAAO,IAAI,SAAS,QAAQ;EAG7C,IAAI,SAAS,MAAM,MAAM,EAAE,SAAS,mBAAmB,EAAE,SAAS,qBAAqB,GACrF,OAAO,IAAI,SAAS,aAAa;EAEnC,MAAM,eAAe,SAAS,QAC3B,MACC,EAAE,SAAS,mBAAmB,EAAE,SAAS,qBAC7C;EACA,IAAI,aAAa,SAAS,GACxB,OAAO;GACL,MAAM;GACN;GACA,QAAQ;GACR,GAAG;GACH,GAAG;GACH,GAAG;GACH,GAAG;EACL;CAEJ;CACA,OAAO;EAAE,MAAM;EAAU;EAAY,GAAG;EAAY,GAAG;EAAW,GAAG;EAAc,GAAG;CAAS;AACjG"}
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.ts","names":[],"sources":["../../../../src/core/extract/extractors/record.ts"],"mappings":";;;iBAGgB,cAAc,KAAK,QAAQ,KAAK,mBAAmB"}
1
+ {"version":3,"file":"record.d.ts","names":[],"sources":["../../../../src/core/extract/extractors/record.ts"],"mappings":";;;iBAIgB,cAAc,KAAK,QAAQ,KAAK,mBAAmB"}
@@ -1,3 +1,4 @@
1
+ import { hasMutation } from "../../codegen/context.js";
1
2
  //#region src/core/extract/extractors/record.ts
2
3
  function extractRecord(def, ctx) {
3
4
  if (!def.valueType) return ctx.fallback("unsupported");
@@ -6,6 +7,7 @@ function extractRecord(def, ctx) {
6
7
  const keyType = ctx.visit(def.keyType, "._zod.def.keyType");
7
8
  const valueType = ctx.visit(def.valueType, "._zod.def.valueType");
8
9
  if (!isStringShapedKey(keyType)) return ctx.fallback("unsupported");
10
+ if (hasMutation(keyType)) return ctx.fallback("unsupported");
9
11
  return {
10
12
  type: "record",
11
13
  keyType,
@@ -1 +1 @@
1
- {"version":3,"file":"record.js","names":[],"sources":["../../../../src/core/extract/extractors/record.ts"],"sourcesContent":["import type { SchemaIR } from \"../../types.js\";\nimport type { ExtractorContext, ZodDef } from \"../types.js\";\n\nexport function extractRecord(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n if (!def.valueType) {\n return ctx.fallback(\"unsupported\");\n }\n // Exhaustive-key records: when the key schema exposes a finite value set\n // (z.record(z.enum(...))), Zod requires EVERY key to be present and rejects\n // unrecognized keys. Compiled records only iterate input keys — delegate to\n // Zod. z.partialRecord() clears `_zod.values`, so it still compiles.\n const keyValues = def.keyType?._zod?.values;\n if (keyValues !== undefined && keyValues.size > 0) {\n return ctx.fallback(\"unsupported\");\n }\n const keyType = ctx.visit(def.keyType, \"._zod.def.keyType\");\n const valueType = ctx.visit(def.valueType, \"._zod.def.valueType\");\n // Object keys are strings at runtime. Zod coerces/validates numeric-string\n // keys for z.record(z.number(), ...) — the compiled key check would run\n // typeof on the string key and reject everything. Only string-shaped key\n // schemas compile; everything else delegates to Zod.\n if (!isStringShapedKey(keyType)) {\n return ctx.fallback(\"unsupported\");\n }\n return { type: \"record\", keyType, valueType };\n}\n\nfunction isStringShapedKey(ir: SchemaIR): boolean {\n switch (ir.type) {\n case \"string\":\n case \"templateLiteral\":\n return true;\n case \"enum\":\n return ir.values.every((v) => typeof v === \"string\");\n case \"literal\":\n return ir.values.every((v) => typeof v === \"string\");\n case \"union\":\n return ir.options.every(isStringShapedKey);\n default:\n return false;\n }\n}\n"],"mappings":";AAGA,SAAgB,cAAc,KAAa,KAAiC;CAC1E,IAAI,CAAC,IAAI,WACP,OAAO,IAAI,SAAS,aAAa;CAMnC,MAAM,YAAY,IAAI,SAAS,MAAM;CACrC,IAAI,cAAc,KAAA,KAAa,UAAU,OAAO,GAC9C,OAAO,IAAI,SAAS,aAAa;CAEnC,MAAM,UAAU,IAAI,MAAM,IAAI,SAAS,mBAAmB;CAC1D,MAAM,YAAY,IAAI,MAAM,IAAI,WAAW,qBAAqB;CAKhE,IAAI,CAAC,kBAAkB,OAAO,GAC5B,OAAO,IAAI,SAAS,aAAa;CAEnC,OAAO;EAAE,MAAM;EAAU;EAAS;CAAU;AAC9C;AAEA,SAAS,kBAAkB,IAAuB;CAChD,QAAQ,GAAG,MAAX;EACE,KAAK;EACL,KAAK,mBACH,OAAO;EACT,KAAK,QACH,OAAO,GAAG,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ;EACrD,KAAK,WACH,OAAO,GAAG,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ;EACrD,KAAK,SACH,OAAO,GAAG,QAAQ,MAAM,iBAAiB;EAC3C,SACE,OAAO;CACX;AACF"}
1
+ {"version":3,"file":"record.js","names":[],"sources":["../../../../src/core/extract/extractors/record.ts"],"sourcesContent":["import { hasMutation } from \"../../codegen/context.js\";\nimport type { SchemaIR } from \"../../types.js\";\nimport type { ExtractorContext, ZodDef } from \"../types.js\";\n\nexport function extractRecord(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n if (!def.valueType) {\n return ctx.fallback(\"unsupported\");\n }\n // Exhaustive-key records: when the key schema exposes a finite value set\n // (z.record(z.enum(...))), Zod requires EVERY key to be present and rejects\n // unrecognized keys. Compiled records only iterate input keys — delegate to\n // Zod. z.partialRecord() clears `_zod.values`, so it still compiles.\n const keyValues = def.keyType?._zod?.values;\n if (keyValues !== undefined && keyValues.size > 0) {\n return ctx.fallback(\"unsupported\");\n }\n const keyType = ctx.visit(def.keyType, \"._zod.def.keyType\");\n const valueType = ctx.visit(def.valueType, \"._zod.def.valueType\");\n // Object keys are strings at runtime. Zod coerces/validates numeric-string\n // keys for z.record(z.number(), ...) — the compiled key check would run\n // typeof on the string key and reject everything. Only string-shaped key\n // schemas compile; everything else delegates to Zod.\n if (!isStringShapedKey(keyType)) {\n return ctx.fallback(\"unsupported\");\n }\n // Rewriting key schemas (z.string().trim()/.toUpperCase(), z.url() — whose\n // check writes back the normalized href) RE-HOME the entry in zod: the output\n // carries the parsed key, so `z.record(z.string().toUpperCase(), z.number())`\n // turns `{ a: 1 }` into `{ A: 1 }`. The compiled record cannot follow, on two\n // independent counts.\n //\n // First, the key is validated with `{ input: keyVar, output: keyVar }`, so an\n // overwrite effect reassigns the loop variable in place; the value is then\n // read as `input[keyVar]` — i.e. at the REWRITTEN key, which is absent from\n // the input object — so the value check sees `undefined` and the record is\n // wrongly rejected with `invalid_type` at the rewritten path.\n //\n // Second, even with the lookup pinned to the original key, the walk iterates\n // the input with for-in and returns it BY REFERENCE, so it has nowhere to put\n // the moved entry: producing zod's output would mean building a fresh object\n // under the parsed keys, which also has to resolve collisions (two keys\n // normalizing to one). Neither half is expressible here, so delegate.\n if (hasMutation(keyType)) {\n return ctx.fallback(\"unsupported\");\n }\n return { type: \"record\", keyType, valueType };\n}\n\nfunction isStringShapedKey(ir: SchemaIR): boolean {\n switch (ir.type) {\n case \"string\":\n case \"templateLiteral\":\n return true;\n case \"enum\":\n return ir.values.every((v) => typeof v === \"string\");\n case \"literal\":\n // `typeof v === \"string\"` (not merely \"has a source form\") is what keeps a\n // SYMBOL key out, and it has to: the compiled record walks its input with\n // `for-in`, which yields string keys only, so a symbol-keyed entry would\n // be invisible to it — while zod's record enumerates the symbol keys too.\n // Only zod can decide such a record, so delegate.\n return ir.values.every((v) => typeof v === \"string\");\n case \"union\":\n return ir.options.every(isStringShapedKey);\n default:\n return false;\n }\n}\n"],"mappings":";;AAIA,SAAgB,cAAc,KAAa,KAAiC;CAC1E,IAAI,CAAC,IAAI,WACP,OAAO,IAAI,SAAS,aAAa;CAMnC,MAAM,YAAY,IAAI,SAAS,MAAM;CACrC,IAAI,cAAc,KAAA,KAAa,UAAU,OAAO,GAC9C,OAAO,IAAI,SAAS,aAAa;CAEnC,MAAM,UAAU,IAAI,MAAM,IAAI,SAAS,mBAAmB;CAC1D,MAAM,YAAY,IAAI,MAAM,IAAI,WAAW,qBAAqB;CAKhE,IAAI,CAAC,kBAAkB,OAAO,GAC5B,OAAO,IAAI,SAAS,aAAa;CAmBnC,IAAI,YAAY,OAAO,GACrB,OAAO,IAAI,SAAS,aAAa;CAEnC,OAAO;EAAE,MAAM;EAAU;EAAS;CAAU;AAC9C;AAEA,SAAS,kBAAkB,IAAuB;CAChD,QAAQ,GAAG,MAAX;EACE,KAAK;EACL,KAAK,mBACH,OAAO;EACT,KAAK,QACH,OAAO,GAAG,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ;EACrD,KAAK,WAMH,OAAO,GAAG,OAAO,OAAO,MAAM,OAAO,MAAM,QAAQ;EACrD,KAAK,SACH,OAAO,GAAG,QAAQ,MAAM,iBAAiB;EAC3C,SACE,OAAO;CACX;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"string.d.ts","names":[],"sources":["../../../../src/core/extract/extractors/string.ts"],"mappings":";;;iBAkBgB,cAAc,KAAK,QAAQ,KAAK,mBAAmB"}
1
+ {"version":3,"file":"string.d.ts","names":[],"sources":["../../../../src/core/extract/extractors/string.ts"],"mappings":";;;iBAuBgB,cAAc,KAAK,QAAQ,KAAK,mBAAmB"}
@@ -1,4 +1,4 @@
1
- import { extractChecks, payloadCheckRef, refineRefRegistrar } from "../checks.js";
1
+ import { customParamsRefRegistrar, extractChecks, payloadCheckRef, refineRefRegistrar } from "../checks.js";
2
2
  //#region src/core/extract/extractors/string.ts
3
3
  /** Check kinds the string codegen knows how to emit. Anything else → fallback. */
4
4
  const STRING_CHECK_KINDS = /* @__PURE__ */ new Set([
@@ -22,7 +22,7 @@ function extractString(def, ctx) {
22
22
  allChecks.push(...checkIRs);
23
23
  }
24
24
  if (def.checks && def.checks.length > 0) {
25
- const { checkIRs, hasFallback } = extractChecks(def.checks, refineRefRegistrar(ctx, def.checks), (index) => payloadCheckRef(ctx, def.checks, index));
25
+ const { checkIRs, hasFallback } = extractChecks(def.checks, refineRefRegistrar(ctx, def.checks), (index) => payloadCheckRef(ctx, def.checks, index), customParamsRefRegistrar(ctx, def.checks));
26
26
  if (hasFallback) return ctx.fallback("refine");
27
27
  allChecks.push(...checkIRs);
28
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"string.js","names":[],"sources":["../../../../src/core/extract/extractors/string.ts"],"sourcesContent":["import type { CheckOrEffectIR, SchemaIR } from \"../../types.js\";\nimport { extractChecks, payloadCheckRef, refineRefRegistrar } from \"../checks.js\";\nimport type { ExtractorContext, ZodCheckSchema, ZodDef } from \"../types.js\";\n\n/** Check kinds the string codegen knows how to emit. Anything else → fallback. */\nconst STRING_CHECK_KINDS = new Set([\n \"min_length\",\n \"max_length\",\n \"length_equals\",\n \"includes\",\n \"starts_with\",\n \"ends_with\",\n \"string_format\",\n \"refine_effect\",\n \"super_refine_effect\",\n \"overwrite_effect\",\n]);\n\nexport function extractString(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n const coerce = def.coerce ? { coerce: true as const } : {};\n const allChecks: CheckOrEffectIR[] = [];\n\n // String format schemas (z.email(), z.url(), ...): the schema def doubles as\n // its own check def (check: \"string_format\"). Reuse extractChecks so pattern\n // flags, url constraints, and custom messages are handled uniformly.\n if (def.check === \"string_format\") {\n const { checkIRs, hasFallback } = extractChecks([\n { _zod: { def } } as unknown as ZodCheckSchema,\n ]);\n if (hasFallback) return ctx.fallback(\"unsupported\");\n allChecks.push(...checkIRs);\n }\n\n // Appended checks (.min(), .refine(), .trim(), ... — also present on format\n // schemas like z.email().min(5), which previously lost them entirely).\n if (def.checks && def.checks.length > 0) {\n const { checkIRs, hasFallback } = extractChecks(\n def.checks,\n refineRefRegistrar(ctx, def.checks),\n (index) => payloadCheckRef(ctx, def.checks, index),\n );\n if (hasFallback) return ctx.fallback(\"refine\");\n allChecks.push(...checkIRs);\n }\n\n if (allChecks.some((c) => !STRING_CHECK_KINDS.has(c.kind))) {\n return ctx.fallback(\"unsupported\");\n }\n\n return { type: \"string\", checks: allChecks, ...coerce };\n}\n"],"mappings":";;;AAKA,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,cAAc,KAAa,KAAiC;CAC1E,MAAM,SAAS,IAAI,SAAS,EAAE,QAAQ,KAAc,IAAI,CAAC;CACzD,MAAM,YAA+B,CAAC;CAKtC,IAAI,IAAI,UAAU,iBAAiB;EACjC,MAAM,EAAE,UAAU,gBAAgB,cAAc,CAC9C,EAAE,MAAM,EAAE,IAAI,EAAE,CAClB,CAAC;EACD,IAAI,aAAa,OAAO,IAAI,SAAS,aAAa;EAClD,UAAU,KAAK,GAAG,QAAQ;CAC5B;CAIA,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,GAAG;EACvC,MAAM,EAAE,UAAU,gBAAgB,cAChC,IAAI,QACJ,mBAAmB,KAAK,IAAI,MAAM,IACjC,UAAU,gBAAgB,KAAK,IAAI,QAAQ,KAAK,CACnD;EACA,IAAI,aAAa,OAAO,IAAI,SAAS,QAAQ;EAC7C,UAAU,KAAK,GAAG,QAAQ;CAC5B;CAEA,IAAI,UAAU,MAAM,MAAM,CAAC,mBAAmB,IAAI,EAAE,IAAI,CAAC,GACvD,OAAO,IAAI,SAAS,aAAa;CAGnC,OAAO;EAAE,MAAM;EAAU,QAAQ;EAAW,GAAG;CAAO;AACxD"}
1
+ {"version":3,"file":"string.js","names":[],"sources":["../../../../src/core/extract/extractors/string.ts"],"sourcesContent":["import type { CheckOrEffectIR, SchemaIR } from \"../../types.js\";\nimport {\n customParamsRefRegistrar,\n extractChecks,\n payloadCheckRef,\n refineRefRegistrar,\n} from \"../checks.js\";\nimport type { ExtractorContext, ZodCheckSchema, ZodDef } from \"../types.js\";\n\n/** Check kinds the string codegen knows how to emit. Anything else → fallback. */\nconst STRING_CHECK_KINDS = new Set([\n \"min_length\",\n \"max_length\",\n \"length_equals\",\n \"includes\",\n \"starts_with\",\n \"ends_with\",\n \"string_format\",\n \"refine_effect\",\n \"super_refine_effect\",\n \"overwrite_effect\",\n]);\n\nexport function extractString(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n const coerce = def.coerce ? { coerce: true as const } : {};\n const allChecks: CheckOrEffectIR[] = [];\n\n // String format schemas (z.email(), z.url(), ...): the schema def doubles as\n // its own check def (check: \"string_format\"). Reuse extractChecks so pattern\n // flags, url constraints, and custom messages are handled uniformly.\n if (def.check === \"string_format\") {\n const { checkIRs, hasFallback } = extractChecks([\n { _zod: { def } } as unknown as ZodCheckSchema,\n ]);\n if (hasFallback) return ctx.fallback(\"unsupported\");\n allChecks.push(...checkIRs);\n }\n\n // Appended checks (.min(), .refine(), .trim(), ... — also present on format\n // schemas like z.email().min(5), which previously lost them entirely).\n if (def.checks && def.checks.length > 0) {\n const { checkIRs, hasFallback } = extractChecks(\n def.checks,\n refineRefRegistrar(ctx, def.checks),\n (index) => payloadCheckRef(ctx, def.checks, index),\n customParamsRefRegistrar(ctx, def.checks),\n );\n if (hasFallback) return ctx.fallback(\"refine\");\n allChecks.push(...checkIRs);\n }\n\n if (allChecks.some((c) => !STRING_CHECK_KINDS.has(c.kind))) {\n return ctx.fallback(\"unsupported\");\n }\n\n return { type: \"string\", checks: allChecks, ...coerce };\n}\n"],"mappings":";;;AAUA,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,cAAc,KAAa,KAAiC;CAC1E,MAAM,SAAS,IAAI,SAAS,EAAE,QAAQ,KAAc,IAAI,CAAC;CACzD,MAAM,YAA+B,CAAC;CAKtC,IAAI,IAAI,UAAU,iBAAiB;EACjC,MAAM,EAAE,UAAU,gBAAgB,cAAc,CAC9C,EAAE,MAAM,EAAE,IAAI,EAAE,CAClB,CAAC;EACD,IAAI,aAAa,OAAO,IAAI,SAAS,aAAa;EAClD,UAAU,KAAK,GAAG,QAAQ;CAC5B;CAIA,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,GAAG;EACvC,MAAM,EAAE,UAAU,gBAAgB,cAChC,IAAI,QACJ,mBAAmB,KAAK,IAAI,MAAM,IACjC,UAAU,gBAAgB,KAAK,IAAI,QAAQ,KAAK,GACjD,yBAAyB,KAAK,IAAI,MAAM,CAC1C;EACA,IAAI,aAAa,OAAO,IAAI,SAAS,QAAQ;EAC7C,UAAU,KAAK,GAAG,QAAQ;CAC5B;CAEA,IAAI,UAAU,MAAM,MAAM,CAAC,mBAAmB,IAAI,EAAE,IAAI,CAAC,GACvD,OAAO,IAAI,SAAS,aAAa;CAGnC,OAAO;EAAE,MAAM;EAAU,QAAQ;EAAW,GAAG;CAAO;AACxD"}
@@ -6,6 +6,7 @@ function extractUnion(def, ctx) {
6
6
  return ctx.visit(def.options[0], "._zod.def.options[0]");
7
7
  }
8
8
  if (def.discriminator) {
9
+ if (def.unionFallback) return ctx.fallback("unsupported");
9
10
  const cases = [];
10
11
  const seenValues = /* @__PURE__ */ new Set();
11
12
  for (let i = 0; i < def.options.length; i++) {
@@ -13,6 +14,7 @@ function extractUnion(def, ctx) {
13
14
  if (!propValues || propValues.size === 0) return ctx.fallback("unsupported");
14
15
  for (const v of propValues) {
15
16
  if (v !== null && v !== void 0 && typeof v !== "string" && typeof v !== "number" && typeof v !== "boolean" && typeof v !== "bigint") return ctx.fallback("unsupported");
17
+ if (typeof v === "number" && Number.isNaN(v)) return ctx.fallback("unsupported");
16
18
  if (seenValues.has(v)) return ctx.fallback("unsupported");
17
19
  seenValues.add(v);
18
20
  cases.push({
@@ -1 +1 @@
1
- {"version":3,"file":"union.js","names":[],"sources":["../../../../src/core/extract/extractors/union.ts"],"sourcesContent":["import type { SchemaIR } from \"../../types.js\";\nimport type { ExtractorContext, ZodDef, ZodSchema } from \"../types.js\";\n\nexport function extractUnion(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n // z.xor(): exactly-one-match semantics (def.inclusive === false without a\n // discriminator). Compiled plain unions accept any match — delegate to Zod.\n // Discriminated unions also carry inclusive:false, but their compiled\n // switch dispatch is exclusive by construction.\n if (def.inclusive === false && !def.discriminator) {\n return ctx.fallback(\"unsupported\");\n }\n // A plain union of exactly one option IS that option: zod surfaces the single\n // option's issues directly (no invalid_union wrapper) and ignores a union-level\n // `{ error }`. Collapsing union([X]) → X matches that exactly — and avoids the\n // wrapper the slow path would otherwise emit when the sole option aborts\n // (invalid_type), which diverged from zod's inner message. When the union\n // carries its own `error`, delegate to zod instead: dispatch() would re-apply\n // it as the collapsed node's typeMessage, but zod drops it for a single-option\n // union — fallback reproduces zod's exact (inner) message.\n if (!def.discriminator && def.options.length === 1) {\n if (def.error !== undefined) return ctx.fallback(\"unsupported\");\n return ctx.visit(def.options[0], \"._zod.def.options[0]\");\n }\n if (def.discriminator) {\n // zod's `_zod.propValues[discriminator]` is the authoritative dispatch\n // table — it covers literal AND enum discriminators with typed values.\n // An option without resolvable values would be unreachable in the\n // compiled switch (rejecting valid input) — fall back instead.\n const cases: {\n value: string | number | boolean | null | bigint | undefined;\n option: number;\n }[] = [];\n // A discriminator value claimed by two options is a misconfigured schema:\n // zod throws \"Duplicate discriminator value\" at PARSE time. The compiled\n // switch would instead silently dispatch to the first matching case, so\n // delegate to zod to reproduce the throw exactly.\n const seenValues = new Set<string | number | boolean | null | bigint | undefined>();\n for (let i = 0; i < def.options.length; i++) {\n const opt = def.options[i] as ZodSchema;\n const propValues = opt._zod.propValues?.[def.discriminator];\n if (!propValues || propValues.size === 0) {\n return ctx.fallback(\"unsupported\");\n }\n for (const v of propValues) {\n if (\n v !== null &&\n v !== undefined &&\n typeof v !== \"string\" &&\n typeof v !== \"number\" &&\n typeof v !== \"boolean\" &&\n typeof v !== \"bigint\"\n ) {\n return ctx.fallback(\"unsupported\");\n }\n if (seenValues.has(v)) {\n return ctx.fallback(\"unsupported\");\n }\n seenValues.add(v);\n cases.push({\n value: v as string | number | boolean | null | bigint | undefined,\n option: i,\n });\n }\n }\n const options = def.options.map((opt, i) => ctx.visit(opt, `._zod.def.options[${i}]`));\n return { type: \"discriminatedUnion\", discriminator: def.discriminator, options, cases };\n }\n return {\n type: \"union\",\n options: def.options.map((opt, i) => ctx.visit(opt, `._zod.def.options[${i}]`)),\n };\n}\n"],"mappings":";AAGA,SAAgB,aAAa,KAAa,KAAiC;CAKzE,IAAI,IAAI,cAAc,SAAS,CAAC,IAAI,eAClC,OAAO,IAAI,SAAS,aAAa;CAUnC,IAAI,CAAC,IAAI,iBAAiB,IAAI,QAAQ,WAAW,GAAG;EAClD,IAAI,IAAI,UAAU,KAAA,GAAW,OAAO,IAAI,SAAS,aAAa;EAC9D,OAAO,IAAI,MAAM,IAAI,QAAQ,IAAI,sBAAsB;CACzD;CACA,IAAI,IAAI,eAAe;EAKrB,MAAM,QAGA,CAAC;EAKP,MAAM,6BAAa,IAAI,IAA2D;EAClF,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,QAAQ,KAAK;GAE3C,MAAM,aADM,IAAI,QAAQ,EACF,CAAC,KAAK,aAAa,IAAI;GAC7C,IAAI,CAAC,cAAc,WAAW,SAAS,GACrC,OAAO,IAAI,SAAS,aAAa;GAEnC,KAAK,MAAM,KAAK,YAAY;IAC1B,IACE,MAAM,QACN,MAAM,KAAA,KACN,OAAO,MAAM,YACb,OAAO,MAAM,YACb,OAAO,MAAM,aACb,OAAO,MAAM,UAEb,OAAO,IAAI,SAAS,aAAa;IAEnC,IAAI,WAAW,IAAI,CAAC,GAClB,OAAO,IAAI,SAAS,aAAa;IAEnC,WAAW,IAAI,CAAC;IAChB,MAAM,KAAK;KACT,OAAO;KACP,QAAQ;IACV,CAAC;GACH;EACF;EACA,MAAM,UAAU,IAAI,QAAQ,KAAK,KAAK,MAAM,IAAI,MAAM,KAAK,qBAAqB,EAAE,EAAE,CAAC;EACrF,OAAO;GAAE,MAAM;GAAsB,eAAe,IAAI;GAAe;GAAS;EAAM;CACxF;CACA,OAAO;EACL,MAAM;EACN,SAAS,IAAI,QAAQ,KAAK,KAAK,MAAM,IAAI,MAAM,KAAK,qBAAqB,EAAE,EAAE,CAAC;CAChF;AACF"}
1
+ {"version":3,"file":"union.js","names":[],"sources":["../../../../src/core/extract/extractors/union.ts"],"sourcesContent":["import type { SchemaIR } from \"../../types.js\";\nimport type { ExtractorContext, ZodDef, ZodSchema } from \"../types.js\";\n\nexport function extractUnion(def: ZodDef, ctx: ExtractorContext): SchemaIR {\n // z.xor(): exactly-one-match semantics (def.inclusive === false without a\n // discriminator). Compiled plain unions accept any match — delegate to Zod.\n // Discriminated unions also carry inclusive:false, but their compiled\n // switch dispatch is exclusive by construction.\n if (def.inclusive === false && !def.discriminator) {\n return ctx.fallback(\"unsupported\");\n }\n // A plain union of exactly one option IS that option: zod surfaces the single\n // option's issues directly (no invalid_union wrapper) and ignores a union-level\n // `{ error }`. Collapsing union([X]) → X matches that exactly — and avoids the\n // wrapper the slow path would otherwise emit when the sole option aborts\n // (invalid_type), which diverged from zod's inner message. When the union\n // carries its own `error`, delegate to zod instead: dispatch() would re-apply\n // it as the collapsed node's typeMessage, but zod drops it for a single-option\n // union — fallback reproduces zod's exact (inner) message.\n if (!def.discriminator && def.options.length === 1) {\n if (def.error !== undefined) return ctx.fallback(\"unsupported\");\n return ctx.visit(def.options[0], \"._zod.def.options[0]\");\n }\n if (def.discriminator) {\n // `z.discriminatedUnion(disc, opts, { unionFallback: true })` means \"on a\n // dispatch miss, behave like a PLAIN union\": zod runs `_super(payload, ctx)`\n // — $ZodUnion's own parse — retrying every option instead of reporting\n // \"No matching discriminator\". The compiled discriminated IR has no room for\n // that retry: its `default:` arm is the terminal no-match. Modelling it would\n // mean emitting a second, full plain-union walk behind the switch, and the\n // two arms differ in BOTH directions — the error shape (zod's plain\n // `invalid_union` at path `[]` carrying per-option `errors`, not the\n // discriminator-tagged issue at `[disc]`) and the VERDICT, whenever an option\n // accepts input the dispatch table never routes to it (a `.default()` on the\n // discriminator contributes only its literal value to `propValues` while its\n // own parse also accepts a MISSING key, so `{}` misses dispatch yet the\n // retry accepts it). Delegate to zod — parity by construction.\n if (def.unionFallback) {\n return ctx.fallback(\"unsupported\");\n }\n // zod's `_zod.propValues[discriminator]` is the authoritative dispatch\n // table — it covers literal AND enum discriminators with typed values.\n // An option without resolvable values would be unreachable in the\n // compiled switch (rejecting valid input) — fall back instead.\n const cases: {\n value: string | number | boolean | null | bigint | undefined;\n option: number;\n }[] = [];\n // A discriminator value claimed by two options is a misconfigured schema:\n // zod throws \"Duplicate discriminator value\" at PARSE time. The compiled\n // switch would instead silently dispatch to the first matching case, so\n // delegate to zod to reproduce the throw exactly.\n const seenValues = new Set<string | number | boolean | null | bigint | undefined>();\n for (let i = 0; i < def.options.length; i++) {\n const opt = def.options[i] as ZodSchema;\n const propValues = opt._zod.propValues?.[def.discriminator];\n if (!propValues || propValues.size === 0) {\n return ctx.fallback(\"unsupported\");\n }\n for (const v of propValues) {\n if (\n v !== null &&\n v !== undefined &&\n typeof v !== \"string\" &&\n typeof v !== \"number\" &&\n typeof v !== \"boolean\" &&\n typeof v !== \"bigint\"\n ) {\n return ctx.fallback(\"unsupported\");\n }\n // NaN is a LIVE dispatch key for zod: its table is a `Map`, and\n // `Map.prototype.get` matches by SameValueZero, under which NaN equals\n // itself — so `z.literal(NaN)` really does route. Every compiled dispatch\n // form is `===`-shaped instead (the slow walk's `switch`, the fast\n // check's `switch`, the build pass's `switch`, and the ordinal table's\n // string-keyed lookup), and `NaN === NaN` is false, so `case NaN:` is\n // dead code and the input falls through to the \"No matching\n // discriminator\" arm zod never reaches. A switch label cannot express\n // SameValueZero, so delegate. (`isSwitchableDiscriminant` refuses NaN on\n // the plain-union auto-discrimination path for exactly this reason; the\n // `seenValues` Set below would only have caught a DUPLICATE NaN.)\n if (typeof v === \"number\" && Number.isNaN(v)) {\n return ctx.fallback(\"unsupported\");\n }\n if (seenValues.has(v)) {\n return ctx.fallback(\"unsupported\");\n }\n seenValues.add(v);\n cases.push({\n value: v as string | number | boolean | null | bigint | undefined,\n option: i,\n });\n }\n }\n const options = def.options.map((opt, i) => ctx.visit(opt, `._zod.def.options[${i}]`));\n return { type: \"discriminatedUnion\", discriminator: def.discriminator, options, cases };\n }\n return {\n type: \"union\",\n options: def.options.map((opt, i) => ctx.visit(opt, `._zod.def.options[${i}]`)),\n };\n}\n"],"mappings":";AAGA,SAAgB,aAAa,KAAa,KAAiC;CAKzE,IAAI,IAAI,cAAc,SAAS,CAAC,IAAI,eAClC,OAAO,IAAI,SAAS,aAAa;CAUnC,IAAI,CAAC,IAAI,iBAAiB,IAAI,QAAQ,WAAW,GAAG;EAClD,IAAI,IAAI,UAAU,KAAA,GAAW,OAAO,IAAI,SAAS,aAAa;EAC9D,OAAO,IAAI,MAAM,IAAI,QAAQ,IAAI,sBAAsB;CACzD;CACA,IAAI,IAAI,eAAe;EAcrB,IAAI,IAAI,eACN,OAAO,IAAI,SAAS,aAAa;EAMnC,MAAM,QAGA,CAAC;EAKP,MAAM,6BAAa,IAAI,IAA2D;EAClF,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,QAAQ,KAAK;GAE3C,MAAM,aADM,IAAI,QAAQ,EACF,CAAC,KAAK,aAAa,IAAI;GAC7C,IAAI,CAAC,cAAc,WAAW,SAAS,GACrC,OAAO,IAAI,SAAS,aAAa;GAEnC,KAAK,MAAM,KAAK,YAAY;IAC1B,IACE,MAAM,QACN,MAAM,KAAA,KACN,OAAO,MAAM,YACb,OAAO,MAAM,YACb,OAAO,MAAM,aACb,OAAO,MAAM,UAEb,OAAO,IAAI,SAAS,aAAa;IAanC,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,CAAC,GACzC,OAAO,IAAI,SAAS,aAAa;IAEnC,IAAI,WAAW,IAAI,CAAC,GAClB,OAAO,IAAI,SAAS,aAAa;IAEnC,WAAW,IAAI,CAAC;IAChB,MAAM,KAAK;KACT,OAAO;KACP,QAAQ;IACV,CAAC;GACH;EACF;EACA,MAAM,UAAU,IAAI,QAAQ,KAAK,KAAK,MAAM,IAAI,MAAM,KAAK,qBAAqB,EAAE,EAAE,CAAC;EACrF,OAAO;GAAE,MAAM;GAAsB,eAAe,IAAI;GAAe;GAAS;EAAM;CACxF;CACA,OAAO;EACL,MAAM;EACN,SAAS,IAAI,QAAQ,KAAK,KAAK,MAAM,IAAI,MAAM,KAAK,qBAAqB,EAAE,EAAE,CAAC;CAChF;AACF"}
@@ -0,0 +1,26 @@
1
+ import { RecursiveRefIR } from "../types.js";
2
+ import { RecursionState } from "./types.js";
3
+ //#region src/core/extract/recursion.d.ts
4
+ /**
5
+ * Mint the back-edge for a detected cycle, keyed on the schema the cycle
6
+ * RE-ENTERS.
7
+ *
8
+ * Two detectors reach here and they MUST agree on refIds, or a back-edge calls
9
+ * a validator hosting a different shape: `extractLazy` sees a cycle one level
10
+ * early — at the `z.lazy()` wrapper, keyed on the schema it resolves to — while
11
+ * `dispatch` sees a getter-declared cycle only by re-entering the target
12
+ * itself. Keying on the re-entered schema in both makes them mint the same id.
13
+ *
14
+ * A `recursiveRef` re-invokes the validator hosting its target's shape. The
15
+ * ROOT schema's resolution is hosted by the schema's own `safeParse_<name>` /
16
+ * fast-check, so a cycle back to it emits the implicit refId 0 (the directly
17
+ * self-recursive case). A cycle back to a NON-root sub-schema (recursive schema
18
+ * nested in a wrapper, multiple distinct recursive sub-schemas, or mutual
19
+ * recursion) gets a stable refId (≥ 1) keyed by schema identity; `dispatch`
20
+ * wraps that schema's IR in a `recursionTarget` node so codegen hosts it as a
21
+ * standalone validator the ref can call.
22
+ */
23
+ declare function makeRecursiveRef(target: unknown, recursion: RecursionState): RecursiveRefIR;
24
+ //#endregion
25
+ export { makeRecursiveRef };
26
+ //# sourceMappingURL=recursion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recursion.d.ts","names":[],"sources":["../../../src/core/extract/recursion.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;iBAsBgB,iBAAiB,iBAAiB,WAAW,iBAAiB"}
@@ -0,0 +1,37 @@
1
+ //#region src/core/extract/recursion.ts
2
+ /**
3
+ * Mint the back-edge for a detected cycle, keyed on the schema the cycle
4
+ * RE-ENTERS.
5
+ *
6
+ * Two detectors reach here and they MUST agree on refIds, or a back-edge calls
7
+ * a validator hosting a different shape: `extractLazy` sees a cycle one level
8
+ * early — at the `z.lazy()` wrapper, keyed on the schema it resolves to — while
9
+ * `dispatch` sees a getter-declared cycle only by re-entering the target
10
+ * itself. Keying on the re-entered schema in both makes them mint the same id.
11
+ *
12
+ * A `recursiveRef` re-invokes the validator hosting its target's shape. The
13
+ * ROOT schema's resolution is hosted by the schema's own `safeParse_<name>` /
14
+ * fast-check, so a cycle back to it emits the implicit refId 0 (the directly
15
+ * self-recursive case). A cycle back to a NON-root sub-schema (recursive schema
16
+ * nested in a wrapper, multiple distinct recursive sub-schemas, or mutual
17
+ * recursion) gets a stable refId (≥ 1) keyed by schema identity; `dispatch`
18
+ * wraps that schema's IR in a `recursionTarget` node so codegen hosts it as a
19
+ * standalone validator the ref can call.
20
+ */
21
+ function makeRecursiveRef(target, recursion) {
22
+ const root = recursion.root;
23
+ if ((root?._zod?.def?.type === "lazy" ? root._zod.innerType : root) === target) return { type: "recursiveRef" };
24
+ let refId = recursion.targets.get(target);
25
+ if (refId === void 0) {
26
+ refId = recursion.next++;
27
+ recursion.targets.set(target, refId);
28
+ }
29
+ return {
30
+ type: "recursiveRef",
31
+ refId
32
+ };
33
+ }
34
+ //#endregion
35
+ export { makeRecursiveRef };
36
+
37
+ //# sourceMappingURL=recursion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recursion.js","names":[],"sources":["../../../src/core/extract/recursion.ts"],"sourcesContent":["import type { RecursiveRefIR } from \"../types.js\";\nimport type { RecursionState, ZodSchema } from \"./types.js\";\n\n/**\n * Mint the back-edge for a detected cycle, keyed on the schema the cycle\n * RE-ENTERS.\n *\n * Two detectors reach here and they MUST agree on refIds, or a back-edge calls\n * a validator hosting a different shape: `extractLazy` sees a cycle one level\n * early — at the `z.lazy()` wrapper, keyed on the schema it resolves to — while\n * `dispatch` sees a getter-declared cycle only by re-entering the target\n * itself. Keying on the re-entered schema in both makes them mint the same id.\n *\n * A `recursiveRef` re-invokes the validator hosting its target's shape. The\n * ROOT schema's resolution is hosted by the schema's own `safeParse_<name>` /\n * fast-check, so a cycle back to it emits the implicit refId 0 (the directly\n * self-recursive case). A cycle back to a NON-root sub-schema (recursive schema\n * nested in a wrapper, multiple distinct recursive sub-schemas, or mutual\n * recursion) gets a stable refId (≥ 1) keyed by schema identity; `dispatch`\n * wraps that schema's IR in a `recursionTarget` node so codegen hosts it as a\n * standalone validator the ref can call.\n */\nexport function makeRecursiveRef(target: unknown, recursion: RecursionState): RecursiveRefIR {\n // A lazy root is transparent — extraction emits the resolved shape as the\n // root's own IR — so a cycle back to what it resolves to is still refId 0.\n const root = recursion.root as ZodSchema | undefined;\n const rootResolved = root?._zod?.def?.type === \"lazy\" ? root._zod.innerType : root;\n if (rootResolved === target) {\n return { type: \"recursiveRef\" };\n }\n let refId = recursion.targets.get(target);\n if (refId === undefined) {\n refId = recursion.next++;\n recursion.targets.set(target, refId);\n }\n return { type: \"recursiveRef\", refId };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,iBAAiB,QAAiB,WAA2C;CAG3F,MAAM,OAAO,UAAU;CAEvB,KADqB,MAAM,MAAM,KAAK,SAAS,SAAS,KAAK,KAAK,YAAY,UACzD,QACnB,OAAO,EAAE,MAAM,eAAe;CAEhC,IAAI,QAAQ,UAAU,QAAQ,IAAI,MAAM;CACxC,IAAI,UAAU,KAAA,GAAW;EACvB,QAAQ,UAAU;EAClB,UAAU,QAAQ,IAAI,QAAQ,KAAK;CACrC;CACA,OAAO;EAAE,MAAM;EAAgB;CAAM;AACvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","names":[],"sources":["../../../src/core/extract/registry.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;cAsDa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0FG,SACd,oBACA,cACA,MAAM,wBACN,UAAU,cACV,WAAW,iBACV"}
1
+ {"version":3,"file":"registry.d.ts","names":[],"sources":["../../../src/core/extract/registry.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;cAuDa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0FG,SACd,oBACA,cACA,MAAM,wBACN,UAAU,cACV,WAAW,iBACV"}
@@ -10,6 +10,7 @@ import { extractDefault } from "./extractors/default.js";
10
10
  import { extractEnum } from "./extractors/enum.js";
11
11
  import { extractFile } from "./extractors/file.js";
12
12
  import { extractIntersection } from "./extractors/intersection.js";
13
+ import { makeRecursiveRef } from "./recursion.js";
13
14
  import { extractLazy } from "./extractors/lazy.js";
14
15
  import { extractLiteral } from "./extractors/literal.js";
15
16
  import { extractMap } from "./extractors/map.js";
@@ -108,6 +109,7 @@ const CHECKS_AWARE_TYPES = /* @__PURE__ */ new Set([
108
109
  */
109
110
  function dispatch(zodSchema, path, refs, visiting, recursion) {
110
111
  const def = zodSchema._zod.def;
112
+ if (def.type !== "lazy" && visiting.has(zodSchema)) return makeRecursiveRef(zodSchema, recursion);
111
113
  visiting.add(zodSchema);
112
114
  try {
113
115
  const extractor = extractRegistry[def.type];
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","names":["schema"],"sources":["../../../src/core/extract/registry.ts"],"sourcesContent":["import type { FallbackIR, SchemaIR } from \"../types.js\";\nimport { resolveCheckMessage } from \"./checks.js\";\nimport { extractAny } from \"./extractors/any.js\";\nimport { extractArray } from \"./extractors/array.js\";\nimport { extractBigint } from \"./extractors/bigint.js\";\nimport { extractBoolean } from \"./extractors/boolean.js\";\nimport { extractCatch } from \"./extractors/catch.js\";\nimport { extractCustom } from \"./extractors/custom.js\";\nimport { extractDate } from \"./extractors/date.js\";\nimport { extractDefault } from \"./extractors/default.js\";\nimport { extractEnum } from \"./extractors/enum.js\";\nimport { extractFile } from \"./extractors/file.js\";\nimport { extractIntersection } from \"./extractors/intersection.js\";\nimport { extractLazy } from \"./extractors/lazy.js\";\nimport { extractLiteral } from \"./extractors/literal.js\";\nimport { extractMap } from \"./extractors/map.js\";\nimport { extractNan } from \"./extractors/nan.js\";\nimport { extractNever } from \"./extractors/never.js\";\nimport { extractNull } from \"./extractors/null.js\";\nimport { extractNullable } from \"./extractors/nullable.js\";\nimport { extractNumber } from \"./extractors/number.js\";\nimport { extractObject } from \"./extractors/object.js\";\nimport { extractOptional } from \"./extractors/optional.js\";\nimport { extractPipe } from \"./extractors/pipe.js\";\nimport { extractReadonly } from \"./extractors/readonly.js\";\nimport { extractRecord } from \"./extractors/record.js\";\nimport { extractSet } from \"./extractors/set.js\";\nimport { extractString } from \"./extractors/string.js\";\nimport { extractSymbol } from \"./extractors/symbol.js\";\nimport { extractTemplateLiteral } from \"./extractors/template-literal.js\";\nimport { extractTuple } from \"./extractors/tuple.js\";\nimport { extractUndefined } from \"./extractors/undefined.js\";\nimport { extractUnion } from \"./extractors/union.js\";\nimport { extractUnknown } from \"./extractors/unknown.js\";\nimport { extractVoid } from \"./extractors/void.js\";\nimport { makeFallback } from \"./fallback.js\";\nimport type {\n Extractor,\n ExtractorContext,\n RecursionState,\n RefEntry,\n SupportedZodDefType,\n ZodSchema,\n} from \"./types.js\";\n\n// ─── Typed registry ─────────────────────────────────────────────────────────\n// Adding a new SupportedZodDefType without registering an extractor here causes\n// a compile error, preventing silent-missing-case bugs.\n//\n// Note: SupportedZodDefType covers Zod's def.type values, not SchemaIR types.\n// SchemaIR types like discriminatedUnion, recursiveRef, effect, and fallback are\n// produced by extractors (e.g. union emits discriminatedUnion, lazy emits\n// recursiveRef) but have no corresponding Zod def.type.\n\nexport const extractRegistry = {\n // Primitives (order follows SupportedZodDefType union in types.ts)\n boolean: extractBoolean,\n null: extractNull,\n undefined: extractUndefined,\n any: extractAny,\n unknown: extractUnknown,\n symbol: extractSymbol,\n void: extractVoid,\n nan: extractNan,\n never: extractNever,\n literal: extractLiteral,\n enum: extractEnum,\n optional: extractOptional,\n nullable: extractNullable,\n readonly: extractReadonly,\n intersection: extractIntersection,\n custom: extractCustom,\n // Complex extractors\n string: extractString,\n number: extractNumber,\n bigint: extractBigint,\n date: extractDate,\n object: extractObject,\n array: extractArray,\n tuple: extractTuple,\n record: extractRecord,\n set: extractSet,\n map: extractMap,\n union: extractUnion,\n default: extractDefault,\n pipe: extractPipe,\n lazy: extractLazy,\n catch: extractCatch,\n template_literal: extractTemplateLiteral,\n file: extractFile,\n} satisfies Record<SupportedZodDefType, Extractor>;\n\n// ─── Factory ────────────────────────────────────────────────────────────────\n// Lives here (not in types.ts) to avoid circular imports:\n// visit() → dispatch() → imports from types.ts\n\nfunction createExtractorContext(\n schema: unknown,\n path: string,\n refs: RefEntry[] | undefined,\n visiting: Set<unknown>,\n recursion: RecursionState,\n): ExtractorContext {\n return {\n schema,\n path,\n refs,\n visiting,\n recursion,\n visit(childSchema: unknown, pathSuffix?: string): SchemaIR {\n const childPath = pathSuffix ? `${path}${pathSuffix}` : path;\n return dispatch(childSchema, childPath, refs, visiting, recursion);\n },\n fallback(reason: FallbackIR[\"reason\"]) {\n return makeFallback(reason, schema, refs, path);\n },\n };\n}\n\n// ─── Dispatch ───────────────────────────────────────────────────────────────\n\n/**\n * def.type values whose extractors consume `def.checks`. In Zod v4, `.refine()`\n * (and `.check()`) appends to the checks array of WHATEVER schema type it is\n * called on — z.string().nullable().refine(...) puts the check on the nullable.\n * For every other type, checks present on the def would be silently dropped by\n * extraction, so dispatch() forces a Zod fallback instead (validation hole\n * otherwise: compiled output accepts input Zod rejects).\n */\nconst CHECKS_AWARE_TYPES: ReadonlySet<string> = new Set([\n \"string\",\n \"number\",\n \"bigint\",\n \"date\",\n \"object\",\n \"array\",\n \"set\",\n \"file\",\n]);\n\n/**\n * Central dispatch — replaces extractSchemaInner().\n * visit() and dispatch() form a mutually recursive pair, both in this file.\n */\nexport function dispatch(\n zodSchema: unknown,\n path: string,\n refs: RefEntry[] | undefined,\n visiting: Set<unknown>,\n recursion: RecursionState,\n): SchemaIR {\n const schema = zodSchema as ZodSchema;\n const def = schema._zod.def;\n\n visiting.add(zodSchema);\n try {\n const extractor = extractRegistry[def.type as SupportedZodDefType];\n const ctx = createExtractorContext(zodSchema, path, refs, visiting, recursion);\n let ir = extractor ? extractor(def, ctx) : makeFallback(\"unsupported\", zodSchema, refs, path);\n if (ir.type === \"fallback\") return ir;\n\n // Safety net: checks attached to a type whose extractor ignores them.\n if (def.checks && def.checks.length > 0 && !CHECKS_AWARE_TYPES.has(def.type)) {\n return makeFallback(\"refine\", zodSchema, refs, path);\n }\n\n // Schema-level custom error (z.string({ error: \"...\" })): bake static\n // messages as the node's default issue message; dynamic error maps can't\n // be compiled — delegate to Zod so messages stay exact.\n if (def.error !== undefined) {\n const resolved = resolveCheckMessage(def.error);\n if (resolved.kind === \"dynamic\") {\n return makeFallback(\"refine\", zodSchema, refs, path);\n }\n if (resolved.kind === \"static\") {\n ir = { ...ir, typeMessage: resolved.message };\n }\n }\n\n // This schema is the target of a non-root recursive cycle (a `recursiveRef`\n // with refId ≥ 1 was emitted for it deeper in the walk): wrap its IR as the\n // OUTERMOST transformation so codegen hosts it as a standalone validator.\n // Done last — after the fallback post-processing above — so a target that\n // delegates to Zod returns its fallback leaf, discarding the whole subtree\n // (including the inner `recursiveRef`) instead of leaving a dangling ref.\n // The root target (refId 0) is the schema's own function and is never\n // wrapped.\n const refId = recursion.targets.get(zodSchema);\n if (refId !== undefined) {\n return { type: \"recursionTarget\", refId, inner: ir };\n }\n return ir;\n } finally {\n visiting.delete(zodSchema);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,MAAa,kBAAkB;CAE7B,SAAS;CACT,MAAM;CACN,WAAW;CACX,KAAK;CACL,SAAS;CACT,QAAQ;CACR,MAAM;CACN,KAAK;CACL,OAAO;CACP,SAAS;CACT,MAAM;CACN,UAAU;CACV,UAAU;CACV,UAAU;CACV,cAAc;CACd,QAAQ;CAER,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,OAAO;CACP,OAAO;CACP,QAAQ;CACR,KAAK;CACL,KAAK;CACL,OAAO;CACP,SAAS;CACT,MAAM;CACN,MAAM;CACN,OAAO;CACP,kBAAkB;CAClB,MAAM;AACR;AAMA,SAAS,uBACP,QACA,MACA,MACA,UACA,WACkB;CAClB,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,MAAM,aAAsB,YAA+B;GAEzD,OAAO,SAAS,aADE,aAAa,GAAG,OAAO,eAAe,MAChB,MAAM,UAAU,SAAS;EACnE;EACA,SAAS,QAA8B;GACrC,OAAO,aAAa,QAAQ,QAAQ,MAAM,IAAI;EAChD;CACF;AACF;;;;;;;;;AAYA,MAAM,qCAA0C,IAAI,IAAI;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;AAMD,SAAgB,SACd,WACA,MACA,MACA,UACA,WACU;CAEV,MAAM,MAAMA,UAAO,KAAK;CAExB,SAAS,IAAI,SAAS;CACtB,IAAI;EACF,MAAM,YAAY,gBAAgB,IAAI;EACtC,MAAM,MAAM,uBAAuB,WAAW,MAAM,MAAM,UAAU,SAAS;EAC7E,IAAI,KAAK,YAAY,UAAU,KAAK,GAAG,IAAI,aAAa,eAAe,WAAW,MAAM,IAAI;EAC5F,IAAI,GAAG,SAAS,YAAY,OAAO;EAGnC,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,KAAK,CAAC,mBAAmB,IAAI,IAAI,IAAI,GACzE,OAAO,aAAa,UAAU,WAAW,MAAM,IAAI;EAMrD,IAAI,IAAI,UAAU,KAAA,GAAW;GAC3B,MAAM,WAAW,oBAAoB,IAAI,KAAK;GAC9C,IAAI,SAAS,SAAS,WACpB,OAAO,aAAa,UAAU,WAAW,MAAM,IAAI;GAErD,IAAI,SAAS,SAAS,UACpB,KAAK;IAAE,GAAG;IAAI,aAAa,SAAS;GAAQ;EAEhD;EAUA,MAAM,QAAQ,UAAU,QAAQ,IAAI,SAAS;EAC7C,IAAI,UAAU,KAAA,GACZ,OAAO;GAAE,MAAM;GAAmB;GAAO,OAAO;EAAG;EAErD,OAAO;CACT,UAAU;EACR,SAAS,OAAO,SAAS;CAC3B;AACF"}
1
+ {"version":3,"file":"registry.js","names":["schema"],"sources":["../../../src/core/extract/registry.ts"],"sourcesContent":["import type { FallbackIR, SchemaIR } from \"../types.js\";\nimport { resolveCheckMessage } from \"./checks.js\";\nimport { extractAny } from \"./extractors/any.js\";\nimport { extractArray } from \"./extractors/array.js\";\nimport { extractBigint } from \"./extractors/bigint.js\";\nimport { extractBoolean } from \"./extractors/boolean.js\";\nimport { extractCatch } from \"./extractors/catch.js\";\nimport { extractCustom } from \"./extractors/custom.js\";\nimport { extractDate } from \"./extractors/date.js\";\nimport { extractDefault } from \"./extractors/default.js\";\nimport { extractEnum } from \"./extractors/enum.js\";\nimport { extractFile } from \"./extractors/file.js\";\nimport { extractIntersection } from \"./extractors/intersection.js\";\nimport { extractLazy } from \"./extractors/lazy.js\";\nimport { extractLiteral } from \"./extractors/literal.js\";\nimport { extractMap } from \"./extractors/map.js\";\nimport { extractNan } from \"./extractors/nan.js\";\nimport { extractNever } from \"./extractors/never.js\";\nimport { extractNull } from \"./extractors/null.js\";\nimport { extractNullable } from \"./extractors/nullable.js\";\nimport { extractNumber } from \"./extractors/number.js\";\nimport { extractObject } from \"./extractors/object.js\";\nimport { extractOptional } from \"./extractors/optional.js\";\nimport { extractPipe } from \"./extractors/pipe.js\";\nimport { extractReadonly } from \"./extractors/readonly.js\";\nimport { extractRecord } from \"./extractors/record.js\";\nimport { extractSet } from \"./extractors/set.js\";\nimport { extractString } from \"./extractors/string.js\";\nimport { extractSymbol } from \"./extractors/symbol.js\";\nimport { extractTemplateLiteral } from \"./extractors/template-literal.js\";\nimport { extractTuple } from \"./extractors/tuple.js\";\nimport { extractUndefined } from \"./extractors/undefined.js\";\nimport { extractUnion } from \"./extractors/union.js\";\nimport { extractUnknown } from \"./extractors/unknown.js\";\nimport { extractVoid } from \"./extractors/void.js\";\nimport { makeFallback } from \"./fallback.js\";\nimport { makeRecursiveRef } from \"./recursion.js\";\nimport type {\n Extractor,\n ExtractorContext,\n RecursionState,\n RefEntry,\n SupportedZodDefType,\n ZodSchema,\n} from \"./types.js\";\n\n// ─── Typed registry ─────────────────────────────────────────────────────────\n// Adding a new SupportedZodDefType without registering an extractor here causes\n// a compile error, preventing silent-missing-case bugs.\n//\n// Note: SupportedZodDefType covers Zod's def.type values, not SchemaIR types.\n// SchemaIR types like discriminatedUnion, recursiveRef, effect, and fallback are\n// produced by extractors (e.g. union emits discriminatedUnion, lazy emits\n// recursiveRef) but have no corresponding Zod def.type.\n\nexport const extractRegistry = {\n // Primitives (order follows SupportedZodDefType union in types.ts)\n boolean: extractBoolean,\n null: extractNull,\n undefined: extractUndefined,\n any: extractAny,\n unknown: extractUnknown,\n symbol: extractSymbol,\n void: extractVoid,\n nan: extractNan,\n never: extractNever,\n literal: extractLiteral,\n enum: extractEnum,\n optional: extractOptional,\n nullable: extractNullable,\n readonly: extractReadonly,\n intersection: extractIntersection,\n custom: extractCustom,\n // Complex extractors\n string: extractString,\n number: extractNumber,\n bigint: extractBigint,\n date: extractDate,\n object: extractObject,\n array: extractArray,\n tuple: extractTuple,\n record: extractRecord,\n set: extractSet,\n map: extractMap,\n union: extractUnion,\n default: extractDefault,\n pipe: extractPipe,\n lazy: extractLazy,\n catch: extractCatch,\n template_literal: extractTemplateLiteral,\n file: extractFile,\n} satisfies Record<SupportedZodDefType, Extractor>;\n\n// ─── Factory ────────────────────────────────────────────────────────────────\n// Lives here (not in types.ts) to avoid circular imports:\n// visit() → dispatch() → imports from types.ts\n\nfunction createExtractorContext(\n schema: unknown,\n path: string,\n refs: RefEntry[] | undefined,\n visiting: Set<unknown>,\n recursion: RecursionState,\n): ExtractorContext {\n return {\n schema,\n path,\n refs,\n visiting,\n recursion,\n visit(childSchema: unknown, pathSuffix?: string): SchemaIR {\n const childPath = pathSuffix ? `${path}${pathSuffix}` : path;\n return dispatch(childSchema, childPath, refs, visiting, recursion);\n },\n fallback(reason: FallbackIR[\"reason\"]) {\n return makeFallback(reason, schema, refs, path);\n },\n };\n}\n\n// ─── Dispatch ───────────────────────────────────────────────────────────────\n\n/**\n * def.type values whose extractors consume `def.checks`. In Zod v4, `.refine()`\n * (and `.check()`) appends to the checks array of WHATEVER schema type it is\n * called on — z.string().nullable().refine(...) puts the check on the nullable.\n * For every other type, checks present on the def would be silently dropped by\n * extraction, so dispatch() forces a Zod fallback instead (validation hole\n * otherwise: compiled output accepts input Zod rejects).\n */\nconst CHECKS_AWARE_TYPES: ReadonlySet<string> = new Set([\n \"string\",\n \"number\",\n \"bigint\",\n \"date\",\n \"object\",\n \"array\",\n \"set\",\n \"file\",\n]);\n\n/**\n * Central dispatch — replaces extractSchemaInner().\n * visit() and dispatch() form a mutually recursive pair, both in this file.\n */\nexport function dispatch(\n zodSchema: unknown,\n path: string,\n refs: RefEntry[] | undefined,\n visiting: Set<unknown>,\n recursion: RecursionState,\n): SchemaIR {\n const schema = zodSchema as ZodSchema;\n const def = schema._zod.def;\n\n // Cycle with no `z.lazy()` marker. Zod v4's documented getter form\n // (`get subcategories() { return z.array(Category) }`) closes the loop through\n // an ordinary shape entry, so nothing on the way down announces the back-edge\n // — re-entering a schema still on the `visiting` stack IS the announcement.\n // Without this, the walk recurses through the same shape forever and dies\n // with \"Maximum call stack size exceeded\" before codegen ever runs.\n //\n // `lazy` is excluded because a lazy node is NOT the cycle's target — the\n // schema it RESOLVES to is, and that is what the ref must be keyed on.\n // Re-entering a lazy node is normal (`z.lazy(() => z.object({ next:\n // Lazy.optional() }))` reaches the ROOT lazy again through its own subtree),\n // and keying the ref on the wrapper would compare it against a root that\n // `makeRecursiveRef` has already resolved through its lazy, miss the match,\n // and mint a non-root refId — costing every root-level `z.lazy()` recursion\n // a hosted helper validator instead of self-calling `safeParse_<name>`.\n // extractLazy re-checks `visiting` against the resolved schema on the way in,\n // so those cycles are still caught, one frame later and with the right key.\n //\n // Checked BEFORE `visiting.add` and outside the try: `visiting` is a plain\n // Set, so returning from inside it would run the `finally` and delete an\n // entry the OUTER frame for this same schema still owns — blinding the\n // detector to every later back-edge to that target (a second self-reference\n // in the same object would recurse forever again).\n if (def.type !== \"lazy\" && visiting.has(zodSchema)) {\n return makeRecursiveRef(zodSchema, recursion);\n }\n\n visiting.add(zodSchema);\n try {\n const extractor = extractRegistry[def.type as SupportedZodDefType];\n const ctx = createExtractorContext(zodSchema, path, refs, visiting, recursion);\n let ir = extractor ? extractor(def, ctx) : makeFallback(\"unsupported\", zodSchema, refs, path);\n if (ir.type === \"fallback\") return ir;\n\n // Safety net: checks attached to a type whose extractor ignores them.\n if (def.checks && def.checks.length > 0 && !CHECKS_AWARE_TYPES.has(def.type)) {\n return makeFallback(\"refine\", zodSchema, refs, path);\n }\n\n // Schema-level custom error (z.string({ error: \"...\" })): bake static\n // messages as the node's default issue message; dynamic error maps can't\n // be compiled — delegate to Zod so messages stay exact.\n if (def.error !== undefined) {\n const resolved = resolveCheckMessage(def.error);\n if (resolved.kind === \"dynamic\") {\n return makeFallback(\"refine\", zodSchema, refs, path);\n }\n if (resolved.kind === \"static\") {\n ir = { ...ir, typeMessage: resolved.message };\n }\n }\n\n // This schema is the target of a non-root recursive cycle (a `recursiveRef`\n // with refId ≥ 1 was emitted for it deeper in the walk): wrap its IR as the\n // OUTERMOST transformation so codegen hosts it as a standalone validator.\n // Done last — after the fallback post-processing above — so a target that\n // delegates to Zod returns its fallback leaf, discarding the whole subtree\n // (including the inner `recursiveRef`) instead of leaving a dangling ref.\n // The root target (refId 0) is the schema's own function and is never\n // wrapped.\n const refId = recursion.targets.get(zodSchema);\n if (refId !== undefined) {\n return { type: \"recursionTarget\", refId, inner: ir };\n }\n return ir;\n } finally {\n visiting.delete(zodSchema);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,MAAa,kBAAkB;CAE7B,SAAS;CACT,MAAM;CACN,WAAW;CACX,KAAK;CACL,SAAS;CACT,QAAQ;CACR,MAAM;CACN,KAAK;CACL,OAAO;CACP,SAAS;CACT,MAAM;CACN,UAAU;CACV,UAAU;CACV,UAAU;CACV,cAAc;CACd,QAAQ;CAER,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,OAAO;CACP,OAAO;CACP,QAAQ;CACR,KAAK;CACL,KAAK;CACL,OAAO;CACP,SAAS;CACT,MAAM;CACN,MAAM;CACN,OAAO;CACP,kBAAkB;CAClB,MAAM;AACR;AAMA,SAAS,uBACP,QACA,MACA,MACA,UACA,WACkB;CAClB,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,MAAM,aAAsB,YAA+B;GAEzD,OAAO,SAAS,aADE,aAAa,GAAG,OAAO,eAAe,MAChB,MAAM,UAAU,SAAS;EACnE;EACA,SAAS,QAA8B;GACrC,OAAO,aAAa,QAAQ,QAAQ,MAAM,IAAI;EAChD;CACF;AACF;;;;;;;;;AAYA,MAAM,qCAA0C,IAAI,IAAI;CACtD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;AAMD,SAAgB,SACd,WACA,MACA,MACA,UACA,WACU;CAEV,MAAM,MAAMA,UAAO,KAAK;CAyBxB,IAAI,IAAI,SAAS,UAAU,SAAS,IAAI,SAAS,GAC/C,OAAO,iBAAiB,WAAW,SAAS;CAG9C,SAAS,IAAI,SAAS;CACtB,IAAI;EACF,MAAM,YAAY,gBAAgB,IAAI;EACtC,MAAM,MAAM,uBAAuB,WAAW,MAAM,MAAM,UAAU,SAAS;EAC7E,IAAI,KAAK,YAAY,UAAU,KAAK,GAAG,IAAI,aAAa,eAAe,WAAW,MAAM,IAAI;EAC5F,IAAI,GAAG,SAAS,YAAY,OAAO;EAGnC,IAAI,IAAI,UAAU,IAAI,OAAO,SAAS,KAAK,CAAC,mBAAmB,IAAI,IAAI,IAAI,GACzE,OAAO,aAAa,UAAU,WAAW,MAAM,IAAI;EAMrD,IAAI,IAAI,UAAU,KAAA,GAAW;GAC3B,MAAM,WAAW,oBAAoB,IAAI,KAAK;GAC9C,IAAI,SAAS,SAAS,WACpB,OAAO,aAAa,UAAU,WAAW,MAAM,IAAI;GAErD,IAAI,SAAS,SAAS,UACpB,KAAK;IAAE,GAAG;IAAI,aAAa,SAAS;GAAQ;EAEhD;EAUA,MAAM,QAAQ,UAAU,QAAQ,IAAI,SAAS;EAC7C,IAAI,UAAU,KAAA,GACZ,OAAO;GAAE,MAAM;GAAmB;GAAO,OAAO;EAAG;EAErD,OAAO;CACT,UAAU;EACR,SAAS,OAAO,SAAS;CAC3B;AACF"}
@@ -1,4 +1,4 @@
1
- import { FallbackIR, SchemaIR } from "../types.js";
1
+ import { FallbackIR, LiteralValue, SchemaIR } from "../types.js";
2
2
  //#region src/core/extract/types.d.ts
3
3
  interface ZodCheckDef {
4
4
  check: string;
@@ -18,6 +18,8 @@ interface ZodCheckDef {
18
18
  fn: unknown;
19
19
  /** `.refine(fn, { path })` — issue path suffix, relative to the refined value. */
20
20
  path?: unknown;
21
+ /** `.refine(fn, { params })` — opaque payload $ZodCustom copies onto the issue. */
22
+ params?: unknown;
21
23
  /** $ZodCheckOverwrite transform function (.trim(), .toLowerCase(), ...). */
22
24
  tx?: unknown;
23
25
  /** Runtime predicate gating check execution — forces fallback when present. */
@@ -62,7 +64,12 @@ interface ZodDef {
62
64
  element: ZodSchema;
63
65
  options: ZodSchema[];
64
66
  innerType: ZodSchema;
65
- values: (string | number | boolean | null | bigint | undefined)[];
67
+ /**
68
+ * z.literal() values. Wider than zod's own `util.Literal` type on purpose:
69
+ * `$ZodLiteral` never inspects them beyond `new Set(def.values)`, so a symbol
70
+ * (or any other reference value) arrives here intact. See {@link LiteralValue}.
71
+ */
72
+ values: LiteralValue[];
66
73
  entries: Record<string, string>;
67
74
  in: ZodSchema;
68
75
  out: ZodSchema;
@@ -73,6 +80,12 @@ interface ZodDef {
73
80
  left: ZodSchema;
74
81
  right: ZodSchema;
75
82
  discriminator: string;
83
+ /**
84
+ * `z.discriminatedUnion(disc, opts, { unionFallback: true })` — on a dispatch
85
+ * miss zod retries every option plain-union style instead of reporting
86
+ * "No matching discriminator". Forces fallback.
87
+ */
88
+ unionFallback?: boolean;
76
89
  /** false on z.xor() unions (exactly-one-match semantics). */
77
90
  inclusive?: boolean;
78
91
  defaultValue: unknown;
@@ -112,10 +125,12 @@ interface RefEntry {
112
125
  type SupportedZodDefType = "boolean" | "null" | "undefined" | "any" | "unknown" | "symbol" | "void" | "nan" | "never" | "literal" | "enum" | "optional" | "nullable" | "readonly" | "intersection" | "custom" | "string" | "number" | "bigint" | "date" | "object" | "array" | "tuple" | "record" | "set" | "map" | "union" | "default" | "pipe" | "lazy" | "catch" | "template_literal" | "file";
113
126
  /**
114
127
  * Shared, mutable recursion-target bookkeeping for one {@link extractSchema}
115
- * call. Lazy cycle detection assigns each NON-root recursion target a stable
116
- * refId (≥ 1) keyed by Zod schema identity; the root schema is identified
117
- * separately and uses the implicit refId 0. `dispatch` wraps a schema's IR in
118
- * a `recursionTarget` node when that schema turns out to be a non-root target.
128
+ * call. Both cycle detectors — `extractLazy` for `z.lazy()` cycles, `dispatch`
129
+ * for getter-declared ones — route through `makeRecursiveRef`, which assigns
130
+ * each NON-root recursion target a stable refId (≥ 1) keyed by Zod schema
131
+ * identity; the root schema is identified separately and uses the implicit
132
+ * refId 0. `dispatch` wraps a schema's IR in a `recursionTarget` node when that
133
+ * schema turns out to be a non-root target.
119
134
  */
120
135
  interface RecursionState {
121
136
  /** The root schema of this extraction (first dispatched), for root detection. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/extract/types.ts"],"mappings":";;UAAiB;EACf;EACA;EACA;EACA,SAAS;EACT;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;;EAEA,WAAW;EACX,WAAW;EACX;EACA;;UAGe;EACf;IACE,KAAK;;;;;;IAML;;;UAIa;EACf;;EAEA;;EAEA;;EAEA;EACA,QAAQ;EACR;EACA;EACA,SAAS;;EAET;;EAEA,WAAW;EACX,OAAO,eAAe;EACtB,SAAS;EACT,SAAS;EACT,WAAW;EACX;EACA,SAAS;EACT,IAAI;EACJ,KAAK;EACL,OAAO;EACP,MAAM;EACN,SAAS;EACT,WAAW;EACX,MAAM;EACN,OAAO;EACP;;EAEA;EACA;EACA;EACA,cAAc;;EAEd;;EAEA;;UAGe;EACf;IACE,KAAK;IACL,MAAM;;IAEN,YAAY;;IAEZ,UAAU;;IAEV,SAAS;;IAET,SAAS;;IAET;;IAEA,aAAa,eAAe;;;;UAKf;;EAEf;;EAEA;;;KAMU;;;;;;;;UA4CK;;WAEN;;WAEA,SAAS;;EAElB;;;UAMe;;WAEN;;WAEA;;WAEA,MAAM;;WAEN,UAAU;;WAEV,WAAW;;EAGpB,MAAM,sBAAsB,sBAHR;;EAMpB,SAAS,QAH+D,uBAGjC;;;KAI7B,aAAa,KAAK,QAAQ,KAAK,qBAAA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/extract/types.ts"],"mappings":";;UAEiB;EACf;EACA;EACA;EACA,SAAS;EACT;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;EACA;;EAEA,WAAW;EACX,WAAW;EACX;EACA;;UAGe;EACf;IACE,KAAK;;;;;;IAML;;;UAIa;EACf;;EAEA;;EAEA;;EAEA;EACA,QAAQ;EACR;EACA;EACA,SAAS;;EAET;;EAEA,WAAW;EACX,OAAO,eAAe;EACtB,SAAS;EACT,SAAS;EACT,WAAW;;;;;;EAMX,QAAQ;EACR,SAAS;EACT,IAAI;EACJ,KAAK;EACL,OAAO;EACP,MAAM;EACN,SAAS;EACT,WAAW;EACX,MAAM;EACN,OAAO;EACP;;;;;;EAMA;;EAEA;EACA;EACA;EACA,cAAc;;EAEd;;EAEA;;UAGe;EACf;IACE,KAAK;IACL,MAAM;;IAEN,YAAY;;IAEZ,UAAU;;IAEV,SAAS;;IAET,SAAS;;IAET;;IAEA,aAAa,eAAe;;;;UAKf;;EAEf;;EAEA;;;KAMU;;;;;;;;;;UA8CK;;WAEN;;WAEA,SAAS;;EAElB;;;UAMe;;WAEN;;WAEA;;WAEA,MAAM;;WAEN,UAAU;;WAEV,WAAW;;EAGpB,MAAM,sBAAsB,sBAHR;;EAMpB,SAAS,QAH+D,uBAGjC;;;KAI7B,aAAa,KAAK,QAAQ,KAAK,qBAAA"}
@@ -52,6 +52,19 @@ declare const ZOD_MSG_DECLARATION: string;
52
52
  * (zod v4 JSON.stringifies every issue into `message` and captures a stack
53
53
  * trace) — stays deferred inside the cached accessor exactly as before, since
54
54
  * the issues array is observable solely through `.error`.
55
+ *
56
+ * `input` is `delete`d, not assigned `undefined`. Key PRESENCE is observable —
57
+ * `"input" in issue`, `Object.keys(issue)`, object spread, `toStrictEqual`
58
+ * against a zod issue — and zod's `util.finalizeIssue` does `delete full.input`
59
+ * whenever `reportInput` is off, so assignment left every compiled issue one
60
+ * enumerable key wider than zod's. The delete's dictionary-mode transition is
61
+ * affordable precisely BECAUSE of the deferral above: it runs only after a
62
+ * caller asks for `.error` on a failed parse, and is memoised in `_c`. Neither
63
+ * a successful parse nor a `.success`/`.is()` check on a rejected one reaches
64
+ * it — measured, the two are unchanged, while the `.error` read itself goes
65
+ * ~3.95us -> ~4.19us per failure, i.e. ~6% of a path whose cost is already
66
+ * dominated by the ZodError construction on the next line (stack capture plus a
67
+ * JSON.stringify of every issue).
55
68
  */
56
69
  declare const FAIL_CLASS_DECL: string;
57
70
  /** Eager finalizer (mutation / partial-fast-path schemas): issues already
@@ -1 +1 @@
1
- {"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAaa;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiCA;;;cAUA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;cAwBA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyDA;;;;;;;;;iBAsBG,aACd,oBACA,QAAQ,oBACR;EAAY"}
1
+ {"version":3,"file":"iife.d.ts","names":[],"sources":["../../src/core/iife.ts"],"mappings":";;;;;;;;cAaa;;;;;;;;;;;;;;;;;;;;cAsBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA8CA;;;cAUA;;;;;;;;;;;;;;;;;;;;;;;cAyBA;;;;;;;;;;;;;;;;;;;;;;;cAwBA;;cAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyDA;;;;;;;;;iBAsBG,aACd,oBACA,QAAQ,oBACR;EAAY"}
package/dist/core/iife.js CHANGED
@@ -51,8 +51,21 @@ const ZOD_MSG_DECLARATION = "function __zcUw(m){return typeof m===\"string\"?m:(
51
51
  * (zod v4 JSON.stringifies every issue into `message` and captures a stack
52
52
  * trace) — stays deferred inside the cached accessor exactly as before, since
53
53
  * the issues array is observable solely through `.error`.
54
+ *
55
+ * `input` is `delete`d, not assigned `undefined`. Key PRESENCE is observable —
56
+ * `"input" in issue`, `Object.keys(issue)`, object spread, `toStrictEqual`
57
+ * against a zod issue — and zod's `util.finalizeIssue` does `delete full.input`
58
+ * whenever `reportInput` is off, so assignment left every compiled issue one
59
+ * enumerable key wider than zod's. The delete's dictionary-mode transition is
60
+ * affordable precisely BECAUSE of the deferral above: it runs only after a
61
+ * caller asks for `.error` on a failed parse, and is memoised in `_c`. Neither
62
+ * a successful parse nor a `.success`/`.is()` check on a rejected one reaches
63
+ * it — measured, the two are unchanged, while the `.error` read itself goes
64
+ * ~3.95us -> ~4.19us per failure, i.e. ~6% of a path whose cost is already
65
+ * dominated by the ZodError construction on the next line (stack capture plus a
66
+ * JSON.stringify of every issue).
54
67
  */
55
- const FAIL_CLASS_DECL = "function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){if(this._c)return this._c;var e=this._f!==null?this._f(this._i):this._e;for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);e[i].input=undefined;}return this._c=new __zcZodError(e);}});";
68
+ const FAIL_CLASS_DECL = "function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){if(this._c)return this._c;var e=this._f!==null?this._f(this._i):this._e;for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);delete e[i].input;}return this._c=new __zcZodError(e);}});";
56
69
  /** Eager finalizer (mutation / partial-fast-path schemas): issues already
57
70
  * collected in `e`; success short-circuits to a plain result literal. */
58
71
  const FIN_DECL = "function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}";
@@ -1 +1 @@
1
- {"version":3,"file":"iife.js","names":[],"sources":["../../src/core/iife.ts"],"sourcesContent":["/**\n * Shared CompiledSchema<T> IIFE generation.\n * Used by both CLI emitter and unplugin transform.\n */\n\nimport type { CompiledSchemaInfo } from \"./pipeline.js\";\n\n/**\n * Import statement required by generateIIFE output (references\n * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and\n * custom callbacks may only reveal that they are async through the promise\n * they return, at which point zod's own synchronous parse raises.\n */\nexport const ZOD_CONFIG_IMPORT =\n 'import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";';\n\n/**\n * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):\n * the message an issue gets when nothing was baked into it at build time.\n *\n * Resolves zod's tail of `finalizeIssue` — `config.customError` then\n * `config.localeError` then \"Invalid input\" — and does it PER CALL, because the\n * config is mutable: `z.config({ localeError })` in an entry point runs after\n * the schema modules it imports, so a value snapshotted at module init misses\n * it. Reading a captured `localeError` alone also dropped `customError`\n * outright, silently ignoring the global map most i18n setups install.\n *\n * The head of zod's chain — the schema's own `error` option — is baked into the\n * issue at build time and short-circuits this. The one link that cannot be\n * reproduced is a per-CALL `ctx.error`, which would have to travel through\n * `safeParse`; that entry point sits at V8's inlining budget, where even an\n * unused extra parameter measured ~12% on every parse.\n *\n * Only ever called while building an error, never on a successful parse.\n */\nexport const ZOD_MSG_DECLARATION =\n 'function __zcUw(m){return typeof m===\"string\"?m:(m===undefined||m===null?undefined:m.message);}' +\n \"var __zcMsg=function(iss){var c=__zodCompilerConfig(),m;\" +\n \"if(c.customError){m=__zcUw(c.customError(iss));if(m!==undefined&&m!==null)return m;}\" +\n \"if(c.localeError){m=__zcUw(c.localeError(iss));if(m!==undefined&&m!==null)return m;}\" +\n 'return \"Invalid input\";};';\n\n/**\n * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)\n * declares it once per compiled file; lean mode (all unplugin bundlers) declares\n * it once per bundle in the plugin-materialized runtime module (module-local —\n * generated code only ever references __zcFin/__zcFinD, never __ZcFail).\n *\n * Why a prototype getter and not `{success:false, get error(){...}}`: an object\n * literal with an inline accessor forces V8 down its slow accessor-defining\n * allocation path — ~110ns per failure, measured — which dominates the entire\n * invalid-input cost whenever callers never read `.error`. Hosting `error` on\n * the prototype turns each failure into a plain field-only instantiation (~2ns,\n * ~13x), with the lazy-cache semantics intact. (Trade-off: `error` is a\n * prototype accessor, so it no longer shows up in `Object.keys(result)` / spread\n * / JSON.stringify of the result wrapper — `.success`/`.error`/`.data` access,\n * destructuring, and `in` are unaffected.)\n *\n * One class serves both finalizers, so the instances share one hidden class:\n * __zcFin passes pre-collected issues in `_e` (with `_f===null`); __zcFinD\n * passes the hosted slow-walk in `_f` plus the input in `_i`, and the getter\n * runs the walk on first `.error` read. The whole finalization — locale fill\n * (__zcMsg applied ONLY when an issue carries no message, never overwriting a\n * baked-in custom/fallback message), input strip, and ZodError construction\n * (zod v4 JSON.stringifies every issue into `message` and captures a stack\n * trace) — stays deferred inside the cached accessor exactly as before, since\n * the issues array is observable solely through `.error`.\n */\nexport const FAIL_CLASS_DECL =\n \"function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){' +\n \"if(this._c)return this._c;\" +\n \"var e=this._f!==null?this._f(this._i):this._e;\" +\n 'for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);e[i].input=undefined;}' +\n \"return this._c=new __zcZodError(e);}});\";\n\n/** Eager finalizer (mutation / partial-fast-path schemas): issues already\n * collected in `e`; success short-circuits to a plain result literal. */\nexport const FIN_DECL =\n \"function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}\";\n\n/**\n * Deferred-collection finalizer for Fast-Path-eligible schemas. When the\n * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is\n * pushed into the cached `.error` accessor instead of running eagerly:\n * fast-eligible schemas never mutate, so the walk's only output is the\n * issues array, which is observable solely through `.error` — one step\n * further along the same lazy boundary `__zcFin` already established (locale\n * fill, input strip, ZodError construction). A failed safeParse whose\n * `.error` is never read costs the fast check alone.\n *\n * Takes the schema's HOSTED slow-walk function plus the input — NOT a\n * per-call closure: `__zcFinD(__sw_N, input)` allocates only the result\n * object, where `__zcFinD(function(){...})` paid a closure environment and\n * function object per failure. Hosting the walk also shrinks safeParse to\n * two statements, within V8's inlining budget (the success-path result\n * literal becomes escape-analyzable at monomorphic call sites).\n *\n * The walk re-reads `input` at `.error`-read time; a caller that mutates\n * the input between safeParse and reading `.error` sees issues for the\n * mutated value (zod materializes at parse time). Same caveat class as the\n * documented __zcFin deferral.\n */\nexport const FIN_DEFERRED_DECL = \"function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}\";\n\n/**\n * Compact-mode failure class — a lazy failure that delegates error reporting to\n * the ORIGINAL Zod schema's `safeParse`. Used by `output: \"compact\"`, where the\n * compiled slow walk is dropped entirely: a mutation-free schema's fast check\n * is the only generated validation, and on a fast-check failure the cold error\n * path is produced by the retained Zod schema itself (`zod` is the source of\n * truth, so the issues are byte-identical — no second validation engine).\n *\n * `_z` is the schema's PRISTINE bound safeParse (`__rf[N].safeParse.bind(...)`,\n * captured pre-`__zcMkv` by emitRfDelegate — see context.ts — so it is zod's\n * own implementation, never the compiled delegate, avoiding infinite\n * recursion). The zod parse is deferred until `.error` is read and cached, so\n * the common `safeParse(x).success`/`.is(x)` checks on invalid input cost only\n * the fast check (zod never runs) — the same deferral boundary `__zcFinD`\n * establishes for the compiled slow walk. Sound because compact mode is gated\n * on a TOTAL fast path: `fc(input) === false` ⟹ zod rejects, so `success:false`\n * holds without consulting zod.\n *\n * The getter returns zod's OWN ZodError verbatim (no locale fill / input strip /\n * re-wrap — zod already finalized it), so a delegated failure is exactly what\n * the unaltered schema would have produced.\n */\nexport const FAILZ_CLASS_DECL =\n \"function __ZcFailZ(z,i){this.success=false;this._z=z;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFailZ.prototype,\"error\",{configurable:true,get:function(){' +\n \"return this._c||(this._c=this._z(this._i).error);}});\";\n\n/** Compact-mode finalizer: wrap a pristine bound safeParse + input into a lazy delegated failure. */\nexport const FINZ_DECL = \"function __zcFinZ(z,i){return new __ZcFailZ(z,i);}\";\n\n/**\n * Validator factory. Inline mode (CLI emitter) declares it once per compiled\n * file; lean mode (all unplugin bundlers) exports it once per bundle from the\n * plugin-materialized runtime module — generated code never imports it from\n * the zod-compiler package itself, so zod-compiler stays a devDependency and\n * the helper set is always version-locked to the codegen that calls it.\n * Wraps a safeParse function into the CompiledSchema interface.\n *\n * IDENTITY-PRESERVING: with zodCompat (schema != null) the compiled\n * parse/safeParse/parseAsync/safeParseAsync are installed as OWN properties\n * on the original schema object, which is returned as-is. zod v4 keys\n * several APIs on object identity — toJSONSchema's ctx.seen registers the\n * object it is handed while each processor closure captures the original\n * inst (a wrapper crashes `optionalProcessor` with \"Cannot set properties\n * of undefined (setting 'ref')\" the moment a compiled schema is composed\n * into another schema), and globalRegistry/.meta() is a WeakMap keyed by\n * the schema instance (a wrapper silently loses OpenAPI titles/ids). An\n * Object.create wrapper breaks both; mutating the original breaks neither\n * (zod's internal parsing flows through _zod.run, never the public\n * methods, and derived schemas — .optional(), .extend() — are fresh\n * instances that fall back to plain zod). schema=null (zodCompat: false)\n * still produces a plain method-bag object.\n *\n * fc is the schema's hosted fast-check boolean function (null when no Fast\n * Path exists). parse()/parseAsync() try it first and return the input\n * directly on success: fc is small enough for V8 to inline, so the hot parse\n * path runs with zero allocations — calling fn would allocate an intermediate\n * SafeParseResult that escape analysis cannot remove (fn never inlines).\n * Fast-path-eligible schemas never mutate, so fc(input) ⟹ data === input.\n *\n * is is the TOTAL fast-check predicate (fc when the fast path is total, else\n * null). Installed as `.is()` — a zero-allocation boolean type guard. When\n * null (partial fast path or none) `.is()` derives from fn(input).success: a\n * partial fc can pass-through valid input but its `false` does not imply\n * rejection (a default/catch may still succeed), so it would be unsound as a\n * standalone guard.\n *\n * `~standard` is REPLACED, not merely preserved. Zod builds it lazily as\n * `validate: (v) => safeParse(inst, v)` — the core FUNCTION, which goes straight\n * to `inst._zod.run`. It never reads the schema's own `safeParse` property, so\n * installing the compiled one leaves this route entirely uncompiled: measured\n * 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema\n * consumers (tRPC, Hono, TanStack) were getting plain Zod.\n *\n * Zod's own validate is captured first and kept as the throw path: it catches a\n * synchronous throw and retries through `safeParseAsync`, which is how an async\n * refinement resolves and how a throwing check surfaces as a rejected promise\n * rather than a synchronous throw. The compiled validator cannot reproduce that\n * (async schemas delegate to Zod anyway), so deferring to the original is both\n * simpler and exact.\n *\n * Installed with defineProperty rather than assignment: Zod's lazy setter\n * redefines the slot as non-writable, so a second `__zcMkv` on the same schema\n * object — two exports aliasing one schema — would throw under ESM strict mode.\n */\nexport const MK_VALIDATOR_DECL =\n \"function __zcMkv(fn,schema,fc,is){var w=schema||{};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){return Promise.resolve(fn(input));};w.parseAsync=fc?function(input){if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}:function(input){var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);};w.is=is||function(input){return fn(input).success;};\" +\n 'var s=w[\"~standard\"],zv=s&&s.validate;' +\n 'Object.defineProperty(w,\"~standard\",{configurable:true,value:{version:1,vendor:(s&&s.vendor)||\"zod\",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zv)return zv(input);throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});' +\n \"return w;}\";\n\nfunction extractFunctionName(functionDef: string): string {\n const match = /^function\\s+(\\w+)\\s*\\(/.exec(functionDef);\n if (!match?.[1]) {\n throw new Error(\"Cannot extract function name from generated code\");\n }\n return match[1];\n}\n\n/**\n * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.\n *\n * @param schemaExpr - Expression resolving to the original Zod schema\n * (e.g. `\"UserSchema\"` in unplugin, `\"(__src_X as any).schema\"` in CLI)\n * @param schema\n * @param options\n */\nexport function generateIIFE(\n schemaExpr: string,\n schema: CompiledSchemaInfo,\n options?: { zodCompat?: boolean | undefined },\n): string {\n const { codegenResult, refEntries } = schema;\n const fnName = extractFunctionName(codegenResult.functionDef);\n const zodCompat = options?.zodCompat !== false;\n const schemaArg = zodCompat ? schemaExpr : \"null\";\n const fcArg = codegenResult.fastFnName ?? \"null\";\n // `.is()` gets the fast-check directly only when it is a total predicate;\n // partial/none falls back to safeParse().success inside __zcMkv. A rebuilding\n // schema has no by-reference `fc` but still names its predicate separately.\n const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : \"null\");\n\n return [\n \"/* @__PURE__ */ (() => {\",\n ...(refEntries.length > 0\n ? [`var __rf=[${refEntries.map((fb) => `${schemaExpr}${fb.accessPath}`).join(\",\")}];`]\n : []),\n ...codegenResult.code\n .split(\"\\n\")\n .filter((l) => l.trim() !== \"\" && l.trim() !== \"/* zod-compiler */\"),\n codegenResult.functionDef,\n `return __zcMkv(${fnName},${schemaArg},${fcArg},${isArg});`,\n \"})()\",\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;AAaA,MAAa,oBACX;;;;;;;;;;;;;;;;;;;;AAqBF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCF,MAAa,kBACX;;;AASF,MAAa,WACX;;;;;;;;;;;;;;;;;;;;;;;AAwBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;AAwBjC,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDzB,MAAa,oBACX;AAKF,SAAS,oBAAoB,aAA6B;CACxD,MAAM,QAAQ,yBAAyB,KAAK,WAAW;CACvD,IAAI,CAAC,QAAQ,IACX,MAAM,IAAI,MAAM,kDAAkD;CAEpE,OAAO,MAAM;AACf;;;;;;;;;AAUA,SAAgB,aACd,YACA,QACA,SACQ;CACR,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,SAAS,oBAAoB,cAAc,WAAW;CAE5D,MAAM,YADY,SAAS,cAAc,QACX,aAAa;CAC3C,MAAM,QAAQ,cAAc,cAAc;CAI1C,MAAM,QAAQ,cAAc,aAAa,cAAc,YAAY,QAAQ;CAE3E,OAAO;EACL;EACA,GAAI,WAAW,SAAS,IACpB,CAAC,aAAa,WAAW,KAAK,OAAO,GAAG,aAAa,GAAG,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG,IACnF,CAAC;EACL,GAAG,cAAc,KACd,MAAM,IAAI,CAAC,CACX,QAAQ,MAAM,EAAE,KAAK,MAAM,MAAM,EAAE,KAAK,MAAM,oBAAoB;EACrE,cAAc;EACd,kBAAkB,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM;EACxD;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}
1
+ {"version":3,"file":"iife.js","names":[],"sources":["../../src/core/iife.ts"],"sourcesContent":["/**\n * Shared CompiledSchema<T> IIFE generation.\n * Used by both CLI emitter and unplugin transform.\n */\n\nimport type { CompiledSchemaInfo } from \"./pipeline.js\";\n\n/**\n * Import statement required by generateIIFE output (references\n * __zodCompilerConfig). `core` is bound for $ZodAsyncError: superRefine and\n * custom callbacks may only reveal that they are async through the promise\n * they return, at which point zod's own synchronous parse raises.\n */\nexport const ZOD_CONFIG_IMPORT =\n 'import { config as __zodCompilerConfig, core as __zcCore, ZodRealError as __zcZodError } from \"zod\";';\n\n/**\n * File-level `__zcMsg` declaration (must appear once after ZOD_CONFIG_IMPORT):\n * the message an issue gets when nothing was baked into it at build time.\n *\n * Resolves zod's tail of `finalizeIssue` — `config.customError` then\n * `config.localeError` then \"Invalid input\" — and does it PER CALL, because the\n * config is mutable: `z.config({ localeError })` in an entry point runs after\n * the schema modules it imports, so a value snapshotted at module init misses\n * it. Reading a captured `localeError` alone also dropped `customError`\n * outright, silently ignoring the global map most i18n setups install.\n *\n * The head of zod's chain — the schema's own `error` option — is baked into the\n * issue at build time and short-circuits this. The one link that cannot be\n * reproduced is a per-CALL `ctx.error`, which would have to travel through\n * `safeParse`; that entry point sits at V8's inlining budget, where even an\n * unused extra parameter measured ~12% on every parse.\n *\n * Only ever called while building an error, never on a successful parse.\n */\nexport const ZOD_MSG_DECLARATION =\n 'function __zcUw(m){return typeof m===\"string\"?m:(m===undefined||m===null?undefined:m.message);}' +\n \"var __zcMsg=function(iss){var c=__zodCompilerConfig(),m;\" +\n \"if(c.customError){m=__zcUw(c.customError(iss));if(m!==undefined&&m!==null)return m;}\" +\n \"if(c.localeError){m=__zcUw(c.localeError(iss));if(m!==undefined&&m!==null)return m;}\" +\n 'return \"Invalid input\";};';\n\n/**\n * Shared failure-result for __zcFin / __zcFinD. Inline mode (CLI emitter)\n * declares it once per compiled file; lean mode (all unplugin bundlers) declares\n * it once per bundle in the plugin-materialized runtime module (module-local —\n * generated code only ever references __zcFin/__zcFinD, never __ZcFail).\n *\n * Why a prototype getter and not `{success:false, get error(){...}}`: an object\n * literal with an inline accessor forces V8 down its slow accessor-defining\n * allocation path — ~110ns per failure, measured — which dominates the entire\n * invalid-input cost whenever callers never read `.error`. Hosting `error` on\n * the prototype turns each failure into a plain field-only instantiation (~2ns,\n * ~13x), with the lazy-cache semantics intact. (Trade-off: `error` is a\n * prototype accessor, so it no longer shows up in `Object.keys(result)` / spread\n * / JSON.stringify of the result wrapper — `.success`/`.error`/`.data` access,\n * destructuring, and `in` are unaffected.)\n *\n * One class serves both finalizers, so the instances share one hidden class:\n * __zcFin passes pre-collected issues in `_e` (with `_f===null`); __zcFinD\n * passes the hosted slow-walk in `_f` plus the input in `_i`, and the getter\n * runs the walk on first `.error` read. The whole finalization — locale fill\n * (__zcMsg applied ONLY when an issue carries no message, never overwriting a\n * baked-in custom/fallback message), input strip, and ZodError construction\n * (zod v4 JSON.stringifies every issue into `message` and captures a stack\n * trace) — stays deferred inside the cached accessor exactly as before, since\n * the issues array is observable solely through `.error`.\n *\n * `input` is `delete`d, not assigned `undefined`. Key PRESENCE is observable —\n * `\"input\" in issue`, `Object.keys(issue)`, object spread, `toStrictEqual`\n * against a zod issue — and zod's `util.finalizeIssue` does `delete full.input`\n * whenever `reportInput` is off, so assignment left every compiled issue one\n * enumerable key wider than zod's. The delete's dictionary-mode transition is\n * affordable precisely BECAUSE of the deferral above: it runs only after a\n * caller asks for `.error` on a failed parse, and is memoised in `_c`. Neither\n * a successful parse nor a `.success`/`.is()` check on a rejected one reaches\n * it — measured, the two are unchanged, while the `.error` read itself goes\n * ~3.95us -> ~4.19us per failure, i.e. ~6% of a path whose cost is already\n * dominated by the ZodError construction on the next line (stack capture plus a\n * JSON.stringify of every issue).\n */\nexport const FAIL_CLASS_DECL =\n \"function __ZcFail(e,f,i){this.success=false;this._e=e;this._f=f;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFail.prototype,\"error\",{configurable:true,get:function(){' +\n \"if(this._c)return this._c;\" +\n \"var e=this._f!==null?this._f(this._i):this._e;\" +\n 'for(var i=0;i<e.length;i++){if(e[i].message===undefined&&typeof __zcMsg===\"function\")e[i].message=__zcMsg(e[i]);delete e[i].input;}' +\n \"return this._c=new __zcZodError(e);}});\";\n\n/** Eager finalizer (mutation / partial-fast-path schemas): issues already\n * collected in `e`; success short-circuits to a plain result literal. */\nexport const FIN_DECL =\n \"function __zcFin(e,d){if(!e.length)return{success:true,data:d};return new __ZcFail(e,null,null);}\";\n\n/**\n * Deferred-collection finalizer for Fast-Path-eligible schemas. When the\n * fast check fails, the ENTIRE slow path (the issue-collecting re-walk) is\n * pushed into the cached `.error` accessor instead of running eagerly:\n * fast-eligible schemas never mutate, so the walk's only output is the\n * issues array, which is observable solely through `.error` — one step\n * further along the same lazy boundary `__zcFin` already established (locale\n * fill, input strip, ZodError construction). A failed safeParse whose\n * `.error` is never read costs the fast check alone.\n *\n * Takes the schema's HOSTED slow-walk function plus the input — NOT a\n * per-call closure: `__zcFinD(__sw_N, input)` allocates only the result\n * object, where `__zcFinD(function(){...})` paid a closure environment and\n * function object per failure. Hosting the walk also shrinks safeParse to\n * two statements, within V8's inlining budget (the success-path result\n * literal becomes escape-analyzable at monomorphic call sites).\n *\n * The walk re-reads `input` at `.error`-read time; a caller that mutates\n * the input between safeParse and reading `.error` sees issues for the\n * mutated value (zod materializes at parse time). Same caveat class as the\n * documented __zcFin deferral.\n */\nexport const FIN_DEFERRED_DECL = \"function __zcFinD(f,inp){return new __ZcFail(null,f,inp);}\";\n\n/**\n * Compact-mode failure class — a lazy failure that delegates error reporting to\n * the ORIGINAL Zod schema's `safeParse`. Used by `output: \"compact\"`, where the\n * compiled slow walk is dropped entirely: a mutation-free schema's fast check\n * is the only generated validation, and on a fast-check failure the cold error\n * path is produced by the retained Zod schema itself (`zod` is the source of\n * truth, so the issues are byte-identical — no second validation engine).\n *\n * `_z` is the schema's PRISTINE bound safeParse (`__rf[N].safeParse.bind(...)`,\n * captured pre-`__zcMkv` by emitRfDelegate — see context.ts — so it is zod's\n * own implementation, never the compiled delegate, avoiding infinite\n * recursion). The zod parse is deferred until `.error` is read and cached, so\n * the common `safeParse(x).success`/`.is(x)` checks on invalid input cost only\n * the fast check (zod never runs) — the same deferral boundary `__zcFinD`\n * establishes for the compiled slow walk. Sound because compact mode is gated\n * on a TOTAL fast path: `fc(input) === false` ⟹ zod rejects, so `success:false`\n * holds without consulting zod.\n *\n * The getter returns zod's OWN ZodError verbatim (no locale fill / input strip /\n * re-wrap — zod already finalized it), so a delegated failure is exactly what\n * the unaltered schema would have produced.\n */\nexport const FAILZ_CLASS_DECL =\n \"function __ZcFailZ(z,i){this.success=false;this._z=z;this._i=i;this._c=undefined;}\" +\n 'Object.defineProperty(__ZcFailZ.prototype,\"error\",{configurable:true,get:function(){' +\n \"return this._c||(this._c=this._z(this._i).error);}});\";\n\n/** Compact-mode finalizer: wrap a pristine bound safeParse + input into a lazy delegated failure. */\nexport const FINZ_DECL = \"function __zcFinZ(z,i){return new __ZcFailZ(z,i);}\";\n\n/**\n * Validator factory. Inline mode (CLI emitter) declares it once per compiled\n * file; lean mode (all unplugin bundlers) exports it once per bundle from the\n * plugin-materialized runtime module — generated code never imports it from\n * the zod-compiler package itself, so zod-compiler stays a devDependency and\n * the helper set is always version-locked to the codegen that calls it.\n * Wraps a safeParse function into the CompiledSchema interface.\n *\n * IDENTITY-PRESERVING: with zodCompat (schema != null) the compiled\n * parse/safeParse/parseAsync/safeParseAsync are installed as OWN properties\n * on the original schema object, which is returned as-is. zod v4 keys\n * several APIs on object identity — toJSONSchema's ctx.seen registers the\n * object it is handed while each processor closure captures the original\n * inst (a wrapper crashes `optionalProcessor` with \"Cannot set properties\n * of undefined (setting 'ref')\" the moment a compiled schema is composed\n * into another schema), and globalRegistry/.meta() is a WeakMap keyed by\n * the schema instance (a wrapper silently loses OpenAPI titles/ids). An\n * Object.create wrapper breaks both; mutating the original breaks neither\n * (zod's internal parsing flows through _zod.run, never the public\n * methods, and derived schemas — .optional(), .extend() — are fresh\n * instances that fall back to plain zod). schema=null (zodCompat: false)\n * still produces a plain method-bag object.\n *\n * fc is the schema's hosted fast-check boolean function (null when no Fast\n * Path exists). parse()/parseAsync() try it first and return the input\n * directly on success: fc is small enough for V8 to inline, so the hot parse\n * path runs with zero allocations — calling fn would allocate an intermediate\n * SafeParseResult that escape analysis cannot remove (fn never inlines).\n * Fast-path-eligible schemas never mutate, so fc(input) ⟹ data === input.\n *\n * is is the TOTAL fast-check predicate (fc when the fast path is total, else\n * null). Installed as `.is()` — a zero-allocation boolean type guard. When\n * null (partial fast path or none) `.is()` derives from fn(input).success: a\n * partial fc can pass-through valid input but its `false` does not imply\n * rejection (a default/catch may still succeed), so it would be unsound as a\n * standalone guard.\n *\n * `~standard` is REPLACED, not merely preserved. Zod builds it lazily as\n * `validate: (v) => safeParse(inst, v)` — the core FUNCTION, which goes straight\n * to `inst._zod.run`. It never reads the schema's own `safeParse` property, so\n * installing the compiled one leaves this route entirely uncompiled: measured\n * 271.7 ns against the compiled 26.6 ns on the same schema, i.e. Standard Schema\n * consumers (tRPC, Hono, TanStack) were getting plain Zod.\n *\n * Zod's own validate is captured first and kept as the throw path: it catches a\n * synchronous throw and retries through `safeParseAsync`, which is how an async\n * refinement resolves and how a throwing check surfaces as a rejected promise\n * rather than a synchronous throw. The compiled validator cannot reproduce that\n * (async schemas delegate to Zod anyway), so deferring to the original is both\n * simpler and exact.\n *\n * Installed with defineProperty rather than assignment: Zod's lazy setter\n * redefines the slot as non-writable, so a second `__zcMkv` on the same schema\n * object — two exports aliasing one schema — would throw under ESM strict mode.\n */\nexport const MK_VALIDATOR_DECL =\n \"function __zcMkv(fn,schema,fc,is){var w=schema||{};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){return Promise.resolve(fn(input));};w.parseAsync=fc?function(input){if(fc(input))return Promise.resolve(input);var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);}:function(input){var r=fn(input);if(r.success)return Promise.resolve(r.data);return Promise.reject(r.error);};w.is=is||function(input){return fn(input).success;};\" +\n 'var s=w[\"~standard\"],zv=s&&s.validate;' +\n 'Object.defineProperty(w,\"~standard\",{configurable:true,value:{version:1,vendor:(s&&s.vendor)||\"zod\",validate:function(input){var r;try{if(fc&&fc(input))return{value:input};r=fn(input);}catch(e){if(zv)return zv(input);throw e;}return r.success?{value:r.data}:{issues:r.error.issues};}}});' +\n \"return w;}\";\n\nfunction extractFunctionName(functionDef: string): string {\n const match = /^function\\s+(\\w+)\\s*\\(/.exec(functionDef);\n if (!match?.[1]) {\n throw new Error(\"Cannot extract function name from generated code\");\n }\n return match[1];\n}\n\n/**\n * Generate a `/* @__PURE__ * /` IIFE wrapping a compiled validator.\n *\n * @param schemaExpr - Expression resolving to the original Zod schema\n * (e.g. `\"UserSchema\"` in unplugin, `\"(__src_X as any).schema\"` in CLI)\n * @param schema\n * @param options\n */\nexport function generateIIFE(\n schemaExpr: string,\n schema: CompiledSchemaInfo,\n options?: { zodCompat?: boolean | undefined },\n): string {\n const { codegenResult, refEntries } = schema;\n const fnName = extractFunctionName(codegenResult.functionDef);\n const zodCompat = options?.zodCompat !== false;\n const schemaArg = zodCompat ? schemaExpr : \"null\";\n const fcArg = codegenResult.fastFnName ?? \"null\";\n // `.is()` gets the fast-check directly only when it is a total predicate;\n // partial/none falls back to safeParse().success inside __zcMkv. A rebuilding\n // schema has no by-reference `fc` but still names its predicate separately.\n const isArg = codegenResult.isFnName ?? (codegenResult.fastTotal ? fcArg : \"null\");\n\n return [\n \"/* @__PURE__ */ (() => {\",\n ...(refEntries.length > 0\n ? [`var __rf=[${refEntries.map((fb) => `${schemaExpr}${fb.accessPath}`).join(\",\")}];`]\n : []),\n ...codegenResult.code\n .split(\"\\n\")\n .filter((l) => l.trim() !== \"\" && l.trim() !== \"/* zod-compiler */\"),\n codegenResult.functionDef,\n `return __zcMkv(${fnName},${schemaArg},${fcArg},${isArg});`,\n \"})()\",\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;AAaA,MAAa,oBACX;;;;;;;;;;;;;;;;;;;;AAqBF,MAAa,sBACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CF,MAAa,kBACX;;;AASF,MAAa,WACX;;;;;;;;;;;;;;;;;;;;;;;AAwBF,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;AAwBjC,MAAa,mBACX;;AAKF,MAAa,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDzB,MAAa,oBACX;AAKF,SAAS,oBAAoB,aAA6B;CACxD,MAAM,QAAQ,yBAAyB,KAAK,WAAW;CACvD,IAAI,CAAC,QAAQ,IACX,MAAM,IAAI,MAAM,kDAAkD;CAEpE,OAAO,MAAM;AACf;;;;;;;;;AAUA,SAAgB,aACd,YACA,QACA,SACQ;CACR,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,SAAS,oBAAoB,cAAc,WAAW;CAE5D,MAAM,YADY,SAAS,cAAc,QACX,aAAa;CAC3C,MAAM,QAAQ,cAAc,cAAc;CAI1C,MAAM,QAAQ,cAAc,aAAa,cAAc,YAAY,QAAQ;CAE3E,OAAO;EACL;EACA,GAAI,WAAW,SAAS,IACpB,CAAC,aAAa,WAAW,KAAK,OAAO,GAAG,aAAa,GAAG,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG,IACnF,CAAC;EACL,GAAG,cAAc,KACd,MAAM,IAAI,CAAC,CACX,QAAQ,MAAM,EAAE,KAAK,MAAM,MAAM,EAAE,KAAK,MAAM,oBAAoB;EACrE,cAAc;EACd,kBAAkB,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM;EACxD;CACF,CAAC,CAAC,KAAK,IAAI;AACb"}