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.
- package/dist/core/codegen/build-path.d.ts.map +1 -1
- package/dist/core/codegen/build-path.js +57 -6
- package/dist/core/codegen/build-path.js.map +1 -1
- package/dist/core/codegen/context.d.ts +23 -3
- package/dist/core/codegen/context.d.ts.map +1 -1
- package/dist/core/codegen/context.js +23 -1
- package/dist/core/codegen/context.js.map +1 -1
- package/dist/core/codegen/dedupe.js +4 -1
- package/dist/core/codegen/dedupe.js.map +1 -1
- package/dist/core/codegen/emit-issue.d.ts +27 -2
- package/dist/core/codegen/emit-issue.d.ts.map +1 -1
- package/dist/core/codegen/emit-issue.js +8 -3
- package/dist/core/codegen/emit-issue.js.map +1 -1
- package/dist/core/codegen/issue-decls.d.ts +9 -3
- package/dist/core/codegen/issue-decls.d.ts.map +1 -1
- package/dist/core/codegen/issue-decls.js +10 -4
- package/dist/core/codegen/issue-decls.js.map +1 -1
- package/dist/core/codegen/schemas/catch.d.ts.map +1 -1
- package/dist/core/codegen/schemas/catch.js +1 -1
- package/dist/core/codegen/schemas/catch.js.map +1 -1
- package/dist/core/codegen/schemas/discriminated-union.d.ts.map +1 -1
- package/dist/core/codegen/schemas/discriminated-union.js +11 -3
- package/dist/core/codegen/schemas/discriminated-union.js.map +1 -1
- package/dist/core/codegen/schemas/effect.d.ts.map +1 -1
- package/dist/core/codegen/schemas/effect.js +3 -2
- package/dist/core/codegen/schemas/effect.js.map +1 -1
- package/dist/core/codegen/schemas/enum.d.ts.map +1 -1
- package/dist/core/codegen/schemas/enum.js +25 -0
- package/dist/core/codegen/schemas/enum.js.map +1 -1
- package/dist/core/codegen/schemas/literal.d.ts.map +1 -1
- package/dist/core/codegen/schemas/literal.js +37 -3
- package/dist/core/codegen/schemas/literal.js.map +1 -1
- package/dist/core/codegen/schemas/string-bool.d.ts.map +1 -1
- package/dist/core/codegen/schemas/string-bool.js +3 -2
- package/dist/core/codegen/schemas/string-bool.js.map +1 -1
- package/dist/core/codegen/schemas/string.d.ts.map +1 -1
- package/dist/core/codegen/schemas/string.js +13 -7
- package/dist/core/codegen/schemas/string.js.map +1 -1
- package/dist/core/codegen/schemas/template-literal.d.ts.map +1 -1
- package/dist/core/codegen/schemas/template-literal.js +2 -2
- package/dist/core/codegen/schemas/template-literal.js.map +1 -1
- package/dist/core/codegen/schemas/tuple.d.ts +11 -5
- package/dist/core/codegen/schemas/tuple.d.ts.map +1 -1
- package/dist/core/codegen/schemas/tuple.js +12 -6
- package/dist/core/codegen/schemas/tuple.js.map +1 -1
- package/dist/core/codegen/schemas/union.d.ts.map +1 -1
- package/dist/core/codegen/schemas/union.js +17 -17
- package/dist/core/codegen/schemas/union.js.map +1 -1
- package/dist/core/extract/checks.d.ts +18 -2
- package/dist/core/extract/checks.d.ts.map +1 -1
- package/dist/core/extract/checks.js +138 -11
- package/dist/core/extract/checks.js.map +1 -1
- package/dist/core/extract/extractors/array.d.ts.map +1 -1
- package/dist/core/extract/extractors/array.js +2 -2
- package/dist/core/extract/extractors/array.js.map +1 -1
- package/dist/core/extract/extractors/intersection.js +44 -0
- package/dist/core/extract/extractors/intersection.js.map +1 -1
- package/dist/core/extract/extractors/lazy.d.ts.map +1 -1
- package/dist/core/extract/extractors/lazy.js +2 -13
- package/dist/core/extract/extractors/lazy.js.map +1 -1
- package/dist/core/extract/extractors/literal.d.ts +14 -0
- package/dist/core/extract/extractors/literal.d.ts.map +1 -1
- package/dist/core/extract/extractors/literal.js +32 -4
- package/dist/core/extract/extractors/literal.js.map +1 -1
- package/dist/core/extract/extractors/number.d.ts.map +1 -1
- package/dist/core/extract/extractors/number.js +2 -2
- package/dist/core/extract/extractors/number.js.map +1 -1
- package/dist/core/extract/extractors/object.d.ts.map +1 -1
- package/dist/core/extract/extractors/object.js +2 -2
- package/dist/core/extract/extractors/object.js.map +1 -1
- package/dist/core/extract/extractors/record.d.ts.map +1 -1
- package/dist/core/extract/extractors/record.js +2 -0
- package/dist/core/extract/extractors/record.js.map +1 -1
- package/dist/core/extract/extractors/string.d.ts.map +1 -1
- package/dist/core/extract/extractors/string.js +2 -2
- package/dist/core/extract/extractors/string.js.map +1 -1
- package/dist/core/extract/extractors/union.js +2 -0
- package/dist/core/extract/extractors/union.js.map +1 -1
- package/dist/core/extract/recursion.d.ts +26 -0
- package/dist/core/extract/recursion.d.ts.map +1 -0
- package/dist/core/extract/recursion.js +37 -0
- package/dist/core/extract/recursion.js.map +1 -0
- package/dist/core/extract/registry.d.ts.map +1 -1
- package/dist/core/extract/registry.js +2 -0
- package/dist/core/extract/registry.js.map +1 -1
- package/dist/core/extract/types.d.ts +21 -6
- package/dist/core/extract/types.d.ts.map +1 -1
- package/dist/core/iife.d.ts +13 -0
- package/dist/core/iife.d.ts.map +1 -1
- package/dist/core/iife.js +14 -1
- package/dist/core/iife.js.map +1 -1
- package/dist/core/types.d.ts +49 -2
- package/dist/core/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string.js","names":[],"sources":["../../../../src/core/codegen/schemas/string.ts"],"sourcesContent":["import type { CheckIR, CheckStringFormat, StringIR } from \"../../types.js\";\nimport type { CodeGenContext, FastGen, SlowGen } from \"../context.js\";\nimport {\n checkPriority,\n emitEffectCallable,\n emitEffectFn,\n emitRegex,\n emitRegexSourceString,\n escapeString,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidFormat, invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\nimport { EMAIL_REGEX_SOURCE, fastTestSource, UUID_REGEX_SOURCE } from \"../well-known-regex.js\";\nimport { refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\n\n/** `re.lastIndex=0;` reset statement for stateful (g/y-flagged) regexes. */\nfunction lastIndexReset(regexVar: string, flags: string | undefined): string {\n return flags && /[gy]/.test(flags) ? `${regexVar}.lastIndex=0;` : \"\";\n}\n\n/**\n * Generate the url check, mirroring $ZodURL semantics:\n * trim → new URL(trimmed) → optional hostname/protocol regex tests →\n * write back url.href (normalize) or the trimmed input.\n */\nfunction slowUrlCheck(check: CheckStringFormat, g: SlowGen): string {\n const trimmedVar = g.temp(\"ut\");\n const urlVar = g.temp(\"u\");\n let inner = \"\";\n if (check.hostname) {\n const re = g.regex(\"host\", check.hostname, check.hostnameFlags);\n inner += emit`\n ${lastIndexReset(re, check.hostnameFlags)}\n if(!${re}.test(${urlVar}.hostname)){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid hostname\",pattern:${escapeString(check.hostname)}`,\n message: check.message,\n })}\n }`;\n }\n if (check.protocol) {\n const re = g.regex(\"proto\", check.protocol, check.protocolFlags);\n const protoExpr = `(${urlVar}.protocol.endsWith(\":\")?${urlVar}.protocol.slice(0,-1):${urlVar}.protocol)`;\n inner += emit`\n ${lastIndexReset(re, check.protocolFlags)}\n if(!${re}.test(${protoExpr})){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid protocol\",pattern:${escapeString(check.protocol)}`,\n message: check.message,\n })}\n }`;\n }\n // Zod writes the value back even when hostname/protocol issues were pushed.\n inner += `${g.output}=${check.normalize ? `${urlVar}.href` : trimmedVar};`;\n return emit`\n var ${trimmedVar}=${g.input}.trim();\n var ${urlVar}=null;\n try{${urlVar}=new URL(${trimmedVar});}catch(_){}\n if(${urlVar}===null){\n ${invalidFormat(g, \"url\", { message: check.message })}\n }else{\n ${inner}\n }`;\n}\n\nexport function slowString(ir: StringIR, g: SlowGen): string {\n let code = \"\";\n if (ir.coerce) {\n code += emit`try{${g.output}=String(${g.input});}catch(_){}`;\n }\n code += emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n }`;\n\n if (ir.checks.length > 0) {\n code += `else{`;\n // Insertion order mirrors zod's issue order for multi-failure inputs;\n // the slow path collects all issues with no short-circuit.\n for (const check of ir.checks) {\n switch (check.kind) {\n case \"min_length\":\n code += emit`\n if(${g.input}.length<${check.minimum}){\n ${tooSmall(g, check.minimum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"max_length\":\n code += emit`\n if(${g.input}.length>${check.maximum}){\n ${tooBig(g, check.maximum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"length_equals\":\n code += emit`\n if(${g.input}.length<${check.length}){\n ${tooSmall(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }else if(${g.input}.length>${check.length}){\n ${tooBig(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }`;\n break;\n case \"includes\":\n code += emit`\n if(!${g.input}.includes(${escapeString(check.includes)}${check.position !== undefined ? `,${check.position}` : \"\"})){\n ${invalidFormat(g, \"includes\", { extra: `includes:${escapeString(check.includes)}`, message: check.message })}\n }`;\n break;\n case \"starts_with\":\n code += emit`\n if(!${g.input}.startsWith(${escapeString(check.prefix)})){\n ${invalidFormat(g, \"starts_with\", { extra: `prefix:${escapeString(check.prefix)}`, message: check.message })}\n }`;\n break;\n case \"ends_with\":\n code += emit`\n if(!${g.input}.endsWith(${escapeString(check.suffix)})){\n ${invalidFormat(g, \"ends_with\", { extra: `suffix:${escapeString(check.suffix)}`, message: check.message })}\n }`;\n break;\n case \"refine_effect\":\n code += refineCheck(check, g.input, g);\n break;\n case \"super_refine_effect\":\n code += superRefineCheck(check, g.input, g);\n break;\n case \"overwrite_effect\":\n // $ZodCheckOverwrite: value = tx(value). Later checks read the\n // rewritten value because input aliases the output location.\n code += emit`${g.output}=${emitEffectFn(g.ctx, check.source)}(${g.input});`;\n break;\n case \"string_format\": {\n let regexVar: string;\n let pattern: string;\n if (check.format === \"url\") {\n code += slowUrlCheck(check, g);\n continue;\n }\n if (check.format === \"email\") {\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n regexVar = g.regex(\"email\", pattern, check.patternFlags);\n } else if (check.format === \"regex\" && check.pattern) {\n pattern = check.pattern;\n regexVar = g.regex(\"str\", pattern, check.patternFlags);\n } else if (check.format === \"uuid\") {\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n regexVar = g.regex(\"uuid\", pattern, check.patternFlags);\n } else {\n if (check.pattern) {\n pattern = check.pattern;\n regexVar = g.regex(\"str\", pattern, check.patternFlags);\n } else {\n // Extraction guarantees a pattern for non-special formats;\n // defensive skip kept for hand-built IR.\n continue;\n }\n }\n // When emitRegex swapped in a faster equivalent pattern, the runtime\n // regex's toString() would leak the rewrite into the issue. Reference\n // the shared original-pattern string instead (pattern came from\n // RegExp.source, so it matches zod's `.toString()` byte-for-byte).\n const rewritten = !check.patternFlags && fastTestSource(pattern) !== null;\n const patternExpr = rewritten\n ? emitRegexSourceString(g.ctx, pattern)\n : `${regexVar}.toString()`;\n code += emit`\n ${lastIndexReset(regexVar, check.patternFlags)}\n if(!${regexVar}.test(${g.input})){\n ${invalidFormat(g, { expr: escapeString(check.format) }, { extra: `pattern:${patternExpr},origin:\"string\"`, message: check.message })}\n }`;\n break;\n }\n }\n }\n code += `}`;\n }\n\n return `${code}\\n`;\n}\n\n/**\n * Boolean expression testing ONE compiled string check against `x`, or null when\n * the check is not expressible as a pure predicate (`z.url()`, which trims and\n * normalizes, and an unknown format with no pattern).\n *\n * Shared by the fast path — which sorts the checks cheapest-first and joins them\n * with `&&` — and by the build path, which emits them one statement at a time in\n * DECLARATION order so an interleaved `.trim()` rewrite is visible to the checks\n * that follow it (see buildString).\n */\nexport function fastStringCheck(check: CheckIR, x: string, ctx: CodeGenContext): string | null {\n switch (check.kind) {\n case \"min_length\":\n return `${x}.length>=${check.minimum}`;\n case \"max_length\":\n return `${x}.length<=${check.maximum}`;\n case \"length_equals\":\n return `${x}.length===${check.length}`;\n case \"includes\":\n return check.position !== undefined\n ? `${x}.includes(${escapeString(check.includes)},${check.position})`\n : `${x}.includes(${escapeString(check.includes)})`;\n case \"starts_with\":\n return `${x}.startsWith(${escapeString(check.prefix)})`;\n case \"ends_with\":\n return `${x}.endsWith(${escapeString(check.suffix)})`;\n case \"string_format\": {\n // URL validation mutates (trims) and uses try/catch — not a predicate.\n if (check.format === \"url\") return null;\n let pattern: string;\n let prefix: string;\n if (check.format === \"email\") {\n prefix = \"email\";\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n } else if (check.format === \"uuid\") {\n prefix = \"uuid\";\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n } else if (check.pattern) {\n prefix = \"re\";\n pattern = check.pattern;\n } else {\n // Unknown format without pattern — can't generate a check\n return null;\n }\n const v = emitRegex(ctx, prefix, pattern, check.patternFlags);\n // Stateful (g/y) regexes need lastIndex reset; comma expression keeps\n // this usable inside the boolean chain.\n return check.patternFlags && /[gy]/.test(check.patternFlags)\n ? `((${v}.lastIndex=0),${v}.test(${x}))`\n : `${v}.test(${x})`;\n }\n default:\n // A check kind this generator does not model (number/bigint/date/set\n // shapes never reach here from a string node).\n return null;\n }\n}\n\nexport function fastString(ir: StringIR, g: FastGen): string | null {\n if (ir.coerce) return null;\n // Overwrite effects rewrite the value — the fast path returns input\n // unchanged, so any mutation makes it ineligible.\n if (ir.checks.some((c) => c.kind === \"overwrite_effect\")) return null;\n\n const x = g.input;\n const parts: string[] = [`typeof ${x}===\"string\"`];\n const checks = ir.checks.filter(\n (c): c is CheckIR => c.kind !== \"refine_effect\" && c.kind !== \"overwrite_effect\",\n );\n\n for (const check of checks.sort(checkPriority)) {\n const expr = fastStringCheck(check, x, g.ctx);\n if (expr === null) return null;\n parts.push(expr);\n }\n\n // Refine effect checks (appended last — run after cheap checks short-circuit)\n for (const check of ir.checks) {\n if (check.kind === \"refine_effect\") {\n parts.push(`${emitEffectCallable(g.ctx, check)}(${x})`);\n } else if (check.kind === \"super_refine_effect\") {\n parts.push(superRefineFastTest(check, x, g));\n }\n }\n\n return parts.join(\"&&\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"string.js","names":[],"sources":["../../../../src/core/codegen/schemas/string.ts"],"sourcesContent":["import type { CheckIR, CheckStringFormat, StringIR } from \"../../types.js\";\nimport type { CodeGenContext, FastGen, SlowGen } from \"../context.js\";\nimport {\n checkPriority,\n emitEffectCallable,\n emitEffectFn,\n emitRegex,\n emitRegexSourceString,\n escapeString,\n} from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidFormat, invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\nimport { EMAIL_REGEX_SOURCE, fastTestSource, UUID_REGEX_SOURCE } from \"../well-known-regex.js\";\nimport { refineCheck, superRefineCheck, superRefineFastTest } from \"./effect.js\";\n\n/** `re.lastIndex=0;` reset statement for stateful (g/y-flagged) regexes. */\nfunction lastIndexReset(regexVar: string, flags: string | undefined): string {\n return flags && /[gy]/.test(flags) ? `${regexVar}.lastIndex=0;` : \"\";\n}\n\n/**\n * Generate the url check, mirroring $ZodURL semantics:\n * trim → new URL(trimmed) → optional hostname/protocol regex tests →\n * write back url.href (normalize) or the trimmed input.\n *\n * $ZodURL is another constructor that OVERRIDES the `??=`-installed default\n * check, so none of the three issues below carries `origin` — and the two that\n * do carry a `pattern` use `regex.source`, not the default check's\n * `regex.toString()` (no delimiters, no flags). Both are reproduced verbatim.\n */\nfunction slowUrlCheck(check: CheckStringFormat, g: SlowGen): string {\n const trimmedVar = g.temp(\"ut\");\n const urlVar = g.temp(\"u\");\n let inner = \"\";\n if (check.hostname) {\n const re = g.regex(\"host\", check.hostname, check.hostnameFlags);\n inner += emit`\n ${lastIndexReset(re, check.hostnameFlags)}\n if(!${re}.test(${urlVar}.hostname)){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid hostname\",pattern:${escapeString(check.hostname)}`,\n message: check.message,\n })}\n }`;\n }\n if (check.protocol) {\n const re = g.regex(\"proto\", check.protocol, check.protocolFlags);\n const protoExpr = `(${urlVar}.protocol.endsWith(\":\")?${urlVar}.protocol.slice(0,-1):${urlVar}.protocol)`;\n inner += emit`\n ${lastIndexReset(re, check.protocolFlags)}\n if(!${re}.test(${protoExpr})){\n ${invalidFormat(g, \"url\", {\n extra: `note:\"Invalid protocol\",pattern:${escapeString(check.protocol)}`,\n message: check.message,\n })}\n }`;\n }\n // Zod writes the value back even when hostname/protocol issues were pushed.\n inner += `${g.output}=${check.normalize ? `${urlVar}.href` : trimmedVar};`;\n return emit`\n var ${trimmedVar}=${g.input}.trim();\n var ${urlVar}=null;\n try{${urlVar}=new URL(${trimmedVar});}catch(_){}\n if(${urlVar}===null){\n ${invalidFormat(g, \"url\", { message: check.message })}\n }else{\n ${inner}\n }`;\n}\n\nexport function slowString(ir: StringIR, g: SlowGen): string {\n let code = \"\";\n if (ir.coerce) {\n code += emit`try{${g.output}=String(${g.input});}catch(_){}`;\n }\n code += emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n }`;\n\n if (ir.checks.length > 0) {\n code += `else{`;\n // Insertion order mirrors zod's issue order for multi-failure inputs;\n // the slow path collects all issues with no short-circuit.\n for (const check of ir.checks) {\n switch (check.kind) {\n case \"min_length\":\n code += emit`\n if(${g.input}.length<${check.minimum}){\n ${tooSmall(g, check.minimum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"max_length\":\n code += emit`\n if(${g.input}.length>${check.maximum}){\n ${tooBig(g, check.maximum, \"string\", true, { message: check.message })}\n }`;\n break;\n case \"length_equals\":\n code += emit`\n if(${g.input}.length<${check.length}){\n ${tooSmall(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }else if(${g.input}.length>${check.length}){\n ${tooBig(g, check.length, \"string\", true, { exact: true, message: check.message })}\n }`;\n break;\n // includes/starts_with/ends_with each carry `origin:\"string\"` but NO\n // `pattern`: $ZodCheckIncludes/StartsWith/EndsWith bypass\n // $ZodCheckStringFormat entirely (they init from $ZodCheck and assign\n // `inst._zod.check` directly), and the pattern they build is registered\n // in the bag for JSON Schema only, never put on the issue.\n case \"includes\":\n code += emit`\n if(!${g.input}.includes(${escapeString(check.includes)}${check.position !== undefined ? `,${check.position}` : \"\"})){\n ${invalidFormat(g, \"includes\", { extra: `includes:${escapeString(check.includes)},origin:\"string\"`, message: check.message })}\n }`;\n break;\n case \"starts_with\":\n code += emit`\n if(!${g.input}.startsWith(${escapeString(check.prefix)})){\n ${invalidFormat(g, \"starts_with\", { extra: `prefix:${escapeString(check.prefix)},origin:\"string\"`, message: check.message })}\n }`;\n break;\n case \"ends_with\":\n code += emit`\n if(!${g.input}.endsWith(${escapeString(check.suffix)})){\n ${invalidFormat(g, \"ends_with\", { extra: `suffix:${escapeString(check.suffix)},origin:\"string\"`, message: check.message })}\n }`;\n break;\n case \"refine_effect\":\n code += refineCheck(check, g.input, g);\n break;\n case \"super_refine_effect\":\n code += superRefineCheck(check, g.input, g);\n break;\n case \"overwrite_effect\":\n // $ZodCheckOverwrite: value = tx(value). Later checks read the\n // rewritten value because input aliases the output location.\n code += emit`${g.output}=${emitEffectFn(g.ctx, check.source)}(${g.input});`;\n break;\n case \"string_format\": {\n let regexVar: string;\n let pattern: string;\n // Only the BUILT-IN z.url() gets the URL-parser check, and extraction\n // never gives that one a pattern. A `pattern` on a \"url\"-named check\n // therefore marks a custom format that merely borrowed the name\n // (`z.stringFormat(\"url\", /re/)`); it validates through its own regex,\n // so fall through and compile that instead of the URL parser.\n if (check.format === \"url\" && !check.pattern) {\n code += slowUrlCheck(check, g);\n continue;\n }\n if (check.format === \"email\") {\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n regexVar = g.regex(\"email\", pattern, check.patternFlags);\n } else if (check.format === \"regex\" && check.pattern) {\n pattern = check.pattern;\n regexVar = g.regex(\"str\", pattern, check.patternFlags);\n } else if (check.format === \"uuid\") {\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n regexVar = g.regex(\"uuid\", pattern, check.patternFlags);\n } else {\n if (check.pattern) {\n pattern = check.pattern;\n regexVar = g.regex(\"str\", pattern, check.patternFlags);\n } else {\n // Extraction guarantees a pattern for non-special formats;\n // defensive skip kept for hand-built IR.\n continue;\n }\n }\n // Zod's invalid_format shape depends on WHICH check instance ran.\n // `$ZodCheckStringFormat.init` installs the default pattern check with\n // `??=`, and that default pushes `origin:\"string\"` + `pattern`. A\n // constructor that OVERRIDES `inst._zod.check` pushes its own issue\n // instead — `$ZodCustomStringFormat` (z.stringFormat/z.hex/z.hostname/\n // z.hash) pushes a bare `{code, format, input}` because it validates\n // through `def.fn` and never reads `def.pattern`. We test the pattern\n // either way, so the issue shape is driven off the extracted flag.\n let extra: string | undefined;\n if (!check.bareIssue) {\n // When emitRegex swapped in a faster equivalent pattern, the runtime\n // regex's toString() would leak the rewrite into the issue. Reference\n // the shared original-pattern string instead (pattern came from\n // RegExp.source, so it matches zod's `.toString()` byte-for-byte).\n const rewritten = !check.patternFlags && fastTestSource(pattern) !== null;\n const patternExpr = rewritten\n ? emitRegexSourceString(g.ctx, pattern)\n : `${regexVar}.toString()`;\n extra = `pattern:${patternExpr},origin:\"string\"`;\n }\n code += emit`\n ${lastIndexReset(regexVar, check.patternFlags)}\n if(!${regexVar}.test(${g.input})){\n ${invalidFormat(g, { expr: escapeString(check.format) }, { extra, message: check.message })}\n }`;\n break;\n }\n }\n }\n code += `}`;\n }\n\n return `${code}\\n`;\n}\n\n/**\n * Boolean expression testing ONE compiled string check against `x`, or null when\n * the check is not expressible as a pure predicate (`z.url()`, which trims and\n * normalizes, and an unknown format with no pattern).\n *\n * Shared by the fast path — which sorts the checks cheapest-first and joins them\n * with `&&` — and by the build path, which emits them one statement at a time in\n * DECLARATION order so an interleaved `.trim()` rewrite is visible to the checks\n * that follow it (see buildString).\n */\nexport function fastStringCheck(check: CheckIR, x: string, ctx: CodeGenContext): string | null {\n switch (check.kind) {\n case \"min_length\":\n return `${x}.length>=${check.minimum}`;\n case \"max_length\":\n return `${x}.length<=${check.maximum}`;\n case \"length_equals\":\n return `${x}.length===${check.length}`;\n case \"includes\":\n return check.position !== undefined\n ? `${x}.includes(${escapeString(check.includes)},${check.position})`\n : `${x}.includes(${escapeString(check.includes)})`;\n case \"starts_with\":\n return `${x}.startsWith(${escapeString(check.prefix)})`;\n case \"ends_with\":\n return `${x}.endsWith(${escapeString(check.suffix)})`;\n case \"string_format\": {\n // URL validation mutates (trims) and uses try/catch — not a predicate.\n // A patterned \"url\" check is a custom format that borrowed the name (see\n // buildString), and its regex IS a predicate.\n if (check.format === \"url\" && !check.pattern) return null;\n let pattern: string;\n let prefix: string;\n if (check.format === \"email\") {\n prefix = \"email\";\n pattern = check.pattern ?? EMAIL_REGEX_SOURCE;\n } else if (check.format === \"uuid\") {\n prefix = \"uuid\";\n pattern = check.pattern ?? UUID_REGEX_SOURCE;\n } else if (check.pattern) {\n prefix = \"re\";\n pattern = check.pattern;\n } else {\n // Unknown format without pattern — can't generate a check\n return null;\n }\n const v = emitRegex(ctx, prefix, pattern, check.patternFlags);\n // Stateful (g/y) regexes need lastIndex reset; comma expression keeps\n // this usable inside the boolean chain.\n return check.patternFlags && /[gy]/.test(check.patternFlags)\n ? `((${v}.lastIndex=0),${v}.test(${x}))`\n : `${v}.test(${x})`;\n }\n default:\n // A check kind this generator does not model (number/bigint/date/set\n // shapes never reach here from a string node).\n return null;\n }\n}\n\nexport function fastString(ir: StringIR, g: FastGen): string | null {\n if (ir.coerce) return null;\n // Overwrite effects rewrite the value — the fast path returns input\n // unchanged, so any mutation makes it ineligible.\n if (ir.checks.some((c) => c.kind === \"overwrite_effect\")) return null;\n\n const x = g.input;\n const parts: string[] = [`typeof ${x}===\"string\"`];\n const checks = ir.checks.filter(\n (c): c is CheckIR => c.kind !== \"refine_effect\" && c.kind !== \"overwrite_effect\",\n );\n\n for (const check of checks.sort(checkPriority)) {\n const expr = fastStringCheck(check, x, g.ctx);\n if (expr === null) return null;\n parts.push(expr);\n }\n\n // Refine effect checks (appended last — run after cheap checks short-circuit)\n for (const check of ir.checks) {\n if (check.kind === \"refine_effect\") {\n parts.push(`${emitEffectCallable(g.ctx, check)}(${x})`);\n } else if (check.kind === \"super_refine_effect\") {\n parts.push(superRefineFastTest(check, x, g));\n }\n }\n\n return parts.join(\"&&\");\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-literal.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"mappings":";;;iBAOgB,oBAAoB,IAAI,mBAAmB,GAAG;
|
|
1
|
+
{"version":3,"file":"template-literal.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"mappings":";;;iBAOgB,oBAAoB,IAAI,mBAAmB,GAAG;iBAyB9C,oBAAoB,IAAI,mBAAmB,GAAG"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { fastTestSource } from "../well-known-regex.js";
|
|
2
|
-
import {
|
|
2
|
+
import { emitConstant, escapeString } from "../context.js";
|
|
3
3
|
import { emit } from "../emit.js";
|
|
4
4
|
import { invalidFormat, invalidType } from "../emit-issue.js";
|
|
5
5
|
//#region src/core/codegen/schemas/template-literal.ts
|
|
6
6
|
function slowTemplateLiteral(ir, g) {
|
|
7
7
|
const regexVar = g.regex("tl", ir.pattern);
|
|
8
|
-
const patternExpr = fastTestSource(ir.pattern) === null ? `${regexVar}.
|
|
8
|
+
const patternExpr = fastTestSource(ir.pattern) === null ? `${regexVar}.source` : emitConstant(g.ctx, "tls", escapeString(ir.pattern));
|
|
9
9
|
return `${emit`
|
|
10
10
|
if(typeof ${g.input}!=="string"){
|
|
11
11
|
${invalidType(g, "string")}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-literal.js","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"sourcesContent":["import type { TemplateLiteralIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"template-literal.js","names":[],"sources":["../../../../src/core/codegen/schemas/template-literal.ts"],"sourcesContent":["import type { TemplateLiteralIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { emitConstant, escapeString } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidFormat, invalidType } from \"../emit-issue.js\";\nimport { fastTestSource } from \"../well-known-regex.js\";\n\nexport function slowTemplateLiteral(ir: TemplateLiteralIR, g: SlowGen): string {\n const regexVar = g.regex(\"tl\", ir.pattern);\n // $ZodTemplateLiteral reports `pattern: inst._zod.pattern.source` — the BARE\n // source, with no enclosing slashes. That is the opposite of every string\n // FORMAT check, which zod reports as `def.pattern.toString()`; the shared\n // emitRegexSourceString helper (and its `<name>Src` virtual exports) produces\n // the slash-wrapped form for those, so it cannot serve this site.\n //\n // Same rewrite rule as slowString though: when emitRegex swapped in a faster\n // equivalent pattern, the runtime regex's own `.source` would leak the\n // rewrite, so the ORIGINAL source is emitted as a constant instead. IR\n // `pattern` IS a `.source` string (see extractTemplateLiteral), so it is\n // byte-identical to what zod reads.\n const patternExpr =\n fastTestSource(ir.pattern) === null\n ? `${regexVar}.source`\n : emitConstant(g.ctx, \"tls\", escapeString(ir.pattern));\n return `${emit`\n if(typeof ${g.input}!==\"string\"){\n ${invalidType(g, \"string\")}\n }else if(!${regexVar}.test(${g.input})){\n ${invalidFormat(g, \"template_literal\", { extra: `pattern:${patternExpr}` })}\n }`}\\n`;\n}\n\nexport function fastTemplateLiteral(ir: TemplateLiteralIR, g: FastGen): string | null {\n const regexVar = g.regex(\"tl\", ir.pattern);\n return `typeof ${g.input}===\"string\"&&${regexVar}.test(${g.input})`;\n}\n"],"mappings":";;;;;AAOA,SAAgB,oBAAoB,IAAuB,GAAoB;CAC7E,MAAM,WAAW,EAAE,MAAM,MAAM,GAAG,OAAO;CAYzC,MAAM,cACJ,eAAe,GAAG,OAAO,MAAM,OAC3B,GAAG,SAAS,WACZ,aAAa,EAAE,KAAK,OAAO,aAAa,GAAG,OAAO,CAAC;CACzD,OAAO,GAAG,IAAI;gBACA,EAAE,MAAM;QAChB,YAAY,GAAG,QAAQ,EAAE;gBACjB,SAAS,QAAQ,EAAE,MAAM;QACjC,cAAc,GAAG,oBAAoB,EAAE,OAAO,WAAW,cAAc,CAAC,EAAE;OAC3E;AACP;AAEA,SAAgB,oBAAoB,IAAuB,GAA2B;CACpF,MAAM,WAAW,EAAE,MAAM,MAAM,GAAG,OAAO;CACzC,OAAO,UAAU,EAAE,MAAM,eAAe,SAAS,QAAQ,EAAE,MAAM;AACnE"}
|
|
@@ -3,11 +3,17 @@ import { FastGen, SlowGen } from "../context.js";
|
|
|
3
3
|
//#region src/core/codegen/schemas/tuple.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Mirrors $ZodTuple: without rest, over-length input emits a single too_big
|
|
6
|
-
* and `length < optStart - 1` a single too_small (minimum = items.length
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* and `length < optStart - 1` a single too_small (minimum = items.length) —
|
|
7
|
+
* both created by the tuple node (schema error applies) and both skip item
|
|
8
|
+
* validation. Anything else validates items; missing required items read as
|
|
9
|
+
* undefined and fail their item schema's type check at the right path.
|
|
10
|
+
*
|
|
11
|
+
* The two halves of zod's ternary are NOT symmetric about `inclusive`:
|
|
12
|
+
* `tooBig ? { code: "too_big", maximum: items.length, inclusive: true } :
|
|
13
|
+
* { code: "too_small", minimum: items.length }`. The under-length issue has no
|
|
14
|
+
* `inclusive` key at all, so it is emitted with `"omit"` rather than `false` —
|
|
15
|
+
* which would be an invented field. The locale phrases it ">N items" off the
|
|
16
|
+
* key's absence, which is why the message matched even while the shape did not.
|
|
11
17
|
*/
|
|
12
18
|
declare function slowTuple(ir: SchemaIR & {
|
|
13
19
|
type: "tuple";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tuple.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/tuple.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"tuple.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/tuple.ts"],"mappings":";;;;;;;;;;;;;;;;;iBAmCgB,UAAU,IAAI;EAAa;GAAiB,GAAG;iBAmD/C,UAAU,IAAI,SAAS,GAAG"}
|
|
@@ -18,11 +18,17 @@ function optStart(ir) {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Mirrors $ZodTuple: without rest, over-length input emits a single too_big
|
|
21
|
-
* and `length < optStart - 1` a single too_small (minimum = items.length
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* and `length < optStart - 1` a single too_small (minimum = items.length) —
|
|
22
|
+
* both created by the tuple node (schema error applies) and both skip item
|
|
23
|
+
* validation. Anything else validates items; missing required items read as
|
|
24
|
+
* undefined and fail their item schema's type check at the right path.
|
|
25
|
+
*
|
|
26
|
+
* The two halves of zod's ternary are NOT symmetric about `inclusive`:
|
|
27
|
+
* `tooBig ? { code: "too_big", maximum: items.length, inclusive: true } :
|
|
28
|
+
* { code: "too_small", minimum: items.length }`. The under-length issue has no
|
|
29
|
+
* `inclusive` key at all, so it is emitted with `"omit"` rather than `false` —
|
|
30
|
+
* which would be an invented field. The locale phrases it ">N items" off the
|
|
31
|
+
* key's absence, which is why the message matched even while the shape did not.
|
|
26
32
|
*/
|
|
27
33
|
function slowTuple(ir, g) {
|
|
28
34
|
const len = ir.items.length;
|
|
@@ -63,7 +69,7 @@ function slowTuple(ir, g) {
|
|
|
63
69
|
if(${g.input}.length>${len}){
|
|
64
70
|
${tooBig(g, len, "array", true, { useTypeMsg: true })}
|
|
65
71
|
}else if(${g.input}.length<${start - 1}){
|
|
66
|
-
${tooSmall(g, len, "array",
|
|
72
|
+
${tooSmall(g, len, "array", "omit", { useTypeMsg: true })}
|
|
67
73
|
}else{
|
|
68
74
|
${itemsCode}
|
|
69
75
|
}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tuple.js","names":[],"sources":["../../../../src/core/codegen/schemas/tuple.ts"],"sourcesContent":["import type { SchemaIR, TupleIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { declareFastTemps, extendPath, extendStaticPathIndex, hasMutation } from \"../context.js\";\nimport { orderByRuntimeCost } from \"../fast-size.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\n\n/**\n * Index where the omittable tail begins (zod's `optStart`): trailing\n * optional/default items have `optin === \"optional\"` and may be absent.\n */\nfunction optStart(ir: TupleIR): number {\n let start = ir.items.length;\n for (let i = ir.items.length - 1; i >= 0; i--) {\n const itemType = (ir.items[i] as SchemaIR).type;\n if (itemType !== \"optional\" && itemType !== \"default\") break;\n start--;\n }\n return start;\n}\n\n/**\n * Mirrors $ZodTuple: without rest, over-length input emits a single too_big\n * and `length < optStart - 1` a single too_small (minimum = items.length
|
|
1
|
+
{"version":3,"file":"tuple.js","names":[],"sources":["../../../../src/core/codegen/schemas/tuple.ts"],"sourcesContent":["import type { SchemaIR, TupleIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { declareFastTemps, extendPath, extendStaticPathIndex, hasMutation } from \"../context.js\";\nimport { orderByRuntimeCost } from \"../fast-size.js\";\nimport { emit } from \"../emit.js\";\nimport { invalidType, tooBig, tooSmall } from \"../emit-issue.js\";\n\n/**\n * Index where the omittable tail begins (zod's `optStart`): trailing\n * optional/default items have `optin === \"optional\"` and may be absent.\n */\nfunction optStart(ir: TupleIR): number {\n let start = ir.items.length;\n for (let i = ir.items.length - 1; i >= 0; i--) {\n const itemType = (ir.items[i] as SchemaIR).type;\n if (itemType !== \"optional\" && itemType !== \"default\") break;\n start--;\n }\n return start;\n}\n\n/**\n * Mirrors $ZodTuple: without rest, over-length input emits a single too_big\n * and `length < optStart - 1` a single too_small (minimum = items.length) —\n * both created by the tuple node (schema error applies) and both skip item\n * validation. Anything else validates items; missing required items read as\n * undefined and fail their item schema's type check at the right path.\n *\n * The two halves of zod's ternary are NOT symmetric about `inclusive`:\n * `tooBig ? { code: \"too_big\", maximum: items.length, inclusive: true } :\n * { code: \"too_small\", minimum: items.length }`. The under-length issue has no\n * `inclusive` key at all, so it is emitted with `\"omit\"` rather than `false` —\n * which would be an invented field. The locale phrases it \">N items\" off the\n * key's absence, which is why the message matched even while the shape did not.\n */\nexport function slowTuple(ir: SchemaIR & { type: \"tuple\" }, g: SlowGen): string {\n const len = ir.items.length;\n\n let code = emit`\n if(!Array.isArray(${g.input})){\n ${invalidType(g, \"tuple\")}\n }else{`;\n\n let itemsCode = \"\";\n if (ir.items.some(hasMutation) || (ir.rest !== null && hasMutation(ir.rest))) {\n itemsCode += `${g.output}=${g.input}.slice();`;\n }\n\n for (let i = 0; i < len; i++) {\n const itemIR = ir.items[i] as SchemaIR;\n const elemExpr = `${g.input}[${i}]`;\n const elemPath = extendStaticPathIndex(g.path, i);\n const skipMissingOptional = i >= optStart(ir);\n const itemCode = g.visit(itemIR, { input: elemExpr, output: elemExpr, path: elemPath });\n // Zod skips absent omittable items entirely (no default materialization).\n itemsCode += skipMissingOptional ? emit`if(${i}<${g.input}.length){${itemCode}}` : itemCode;\n }\n\n if (ir.rest !== null) {\n const idxVar = g.temp(\"ti\");\n const restExpr = `${g.input}[${idxVar}]`;\n const restPath = extendPath(g.path, idxVar);\n itemsCode += emit`\n for(var ${idxVar}=${len};${idxVar}<${g.input}.length;${idxVar}++){\n ${g.visit(ir.rest, { input: restExpr, output: restExpr, path: restPath })}\n }`;\n }\n\n if (ir.rest === null) {\n const start = optStart(ir);\n code += emit`\n if(${g.input}.length>${len}){\n ${tooBig(g, len, \"array\", true, { useTypeMsg: true })}\n }else if(${g.input}.length<${start - 1}){\n ${tooSmall(g, len, \"array\", \"omit\", { useTypeMsg: true })}\n }else{\n ${itemsCode}\n }`;\n } else {\n code += itemsCode;\n }\n\n code += `}\\n`;\n return code;\n}\n\nexport function fastTuple(ir: TupleIR, g: FastGen): string | null {\n const x = g.input;\n const parts: string[] = [`Array.isArray(${x})`];\n\n const required = optStart(ir);\n if (ir.rest === null) {\n if (required === ir.items.length) {\n parts.push(`${x}.length===${ir.items.length}`);\n } else {\n parts.push(`${x}.length>=${required}`, `${x}.length<=${ir.items.length}`);\n }\n } else if (required > 0) {\n parts.push(`${x}.length>=${required}`);\n }\n\n // Per-index checks, cheapest-first: positions are independent, so the emitted\n // order only decides which one a reject stops on (see estimateRuntimeCost).\n // The Array.isArray + length conjuncts above stay in front — the element\n // reads are only meaningful once they hold.\n const indexed = ir.items.flatMap((itemIR, index) => (itemIR ? [{ index, itemIR }] : []));\n for (const { index, itemIR } of orderByRuntimeCost(indexed, (e) => e.itemIR, g.ctx)) {\n const itemCheck = g.visit(itemIR, { input: `${x}[${index}]` });\n if (itemCheck === null) return null;\n if (itemCheck !== \"true\") parts.push(itemCheck);\n }\n\n // Rest element validation via preamble helper (avoids .slice().every()\n // allocation). Fresh scope: the helper is its own function, size-gated\n // independently. (Fixed items above stay inline in the caller's && chain.)\n if (ir.rest !== null) {\n const rv = g.temp(\"tr\");\n const restGen = g.scoped(rv);\n const restCheck = restGen.visit(ir.rest);\n if (restCheck === null) return null;\n if (restCheck !== \"true\") {\n const helperName = g.temp(\"te\");\n g.ctx.preamble.push(\n `function ${helperName}(a,s){${declareFastTemps(restGen.scope)}for(var ${rv},i=s;i<a.length;i++){${rv}=a[i];if(!(${restCheck})){return false;}}return true;}`,\n );\n parts.push(`${helperName}(${x},${ir.items.length})`);\n }\n }\n\n return parts.join(\"&&\");\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/union.ts"],"mappings":";;;iBAQgB,UAAU,IAAI;EAAa;GAAiB,GAAG;
|
|
1
|
+
{"version":3,"file":"union.d.ts","names":[],"sources":["../../../../src/core/codegen/schemas/union.ts"],"mappings":";;;iBAQgB,UAAU,IAAI;EAAa;GAAiB,GAAG;iBAwI/C,UAAU,IAAI,SAAS,GAAG"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { hasMutation } from "../context.js";
|
|
1
|
+
import { emitRuntimeHelper, hasMutation } from "../context.js";
|
|
2
2
|
import { emit } from "../emit.js";
|
|
3
|
-
import { abortingCodeTest } from "../issue-decls.js";
|
|
3
|
+
import { ZC_FZ_DECL, abortingCodeTest } from "../issue-decls.js";
|
|
4
4
|
import { detectUnionDiscriminator, emitFastDiscriminatedSwitch } from "./discriminated-union.js";
|
|
5
5
|
import { orderByRuntimeCost } from "../fast-size.js";
|
|
6
6
|
//#region src/core/codegen/schemas/union.ts
|
|
@@ -9,10 +9,12 @@ function slowUnion(ir, g) {
|
|
|
9
9
|
const errorsVar = g.temp("ue");
|
|
10
10
|
const abortedVar = g.temp("uea");
|
|
11
11
|
let code = `var ${resultVar}=false;var ${errorsVar}=[];var ${abortedVar}=[];`;
|
|
12
|
+
const atPathRoot = g.path === "[]";
|
|
13
|
+
const pathVar = atPathRoot ? null : g.temp("up");
|
|
14
|
+
const unionPath = pathVar ?? "[]";
|
|
12
15
|
const needsOutputIsolation = ir.options.some(hasMutation);
|
|
13
16
|
for (const option of ir.options) {
|
|
14
17
|
const tmpIssues = g.temp("ui");
|
|
15
|
-
const innerIdx = g.temp("ufi");
|
|
16
18
|
const optAborted = g.temp("uoa");
|
|
17
19
|
if (needsOutputIsolation) {
|
|
18
20
|
const tmpOutput = g.temp("uo");
|
|
@@ -25,18 +27,13 @@ function slowUnion(ir, g) {
|
|
|
25
27
|
issues: tmpIssues,
|
|
26
28
|
input: tmpOutput,
|
|
27
29
|
output: tmpOutput,
|
|
30
|
+
path: "[]",
|
|
28
31
|
aborted: optAborted
|
|
29
32
|
})}
|
|
30
33
|
if(${tmpIssues}.length===0){
|
|
31
34
|
${resultVar}=true;
|
|
32
35
|
${g.output}=${tmpOutput};
|
|
33
36
|
}else{
|
|
34
|
-
for(var ${innerIdx}=0;${innerIdx}<${tmpIssues}.length;${innerIdx}++){
|
|
35
|
-
if(${tmpIssues}[${innerIdx}].message===undefined&&typeof __zcMsg==="function"){
|
|
36
|
-
${tmpIssues}[${innerIdx}].message=__zcMsg(${tmpIssues}[${innerIdx}]);
|
|
37
|
-
}
|
|
38
|
-
${tmpIssues}[${innerIdx}].input=undefined;
|
|
39
|
-
}
|
|
40
37
|
${errorsVar}.push(${tmpIssues});
|
|
41
38
|
${abortedVar}.push(${optAborted});
|
|
42
39
|
}
|
|
@@ -47,31 +44,30 @@ function slowUnion(ir, g) {
|
|
|
47
44
|
var ${optAborted}=false;
|
|
48
45
|
${g.visit(option, {
|
|
49
46
|
issues: tmpIssues,
|
|
47
|
+
path: "[]",
|
|
50
48
|
aborted: optAborted
|
|
51
49
|
})}
|
|
52
50
|
if(${tmpIssues}.length===0){
|
|
53
51
|
${resultVar}=true;
|
|
54
52
|
}else{
|
|
55
|
-
for(var ${innerIdx}=0;${innerIdx}<${tmpIssues}.length;${innerIdx}++){
|
|
56
|
-
if(${tmpIssues}[${innerIdx}].message===undefined&&typeof __zcMsg==="function"){
|
|
57
|
-
${tmpIssues}[${innerIdx}].message=__zcMsg(${tmpIssues}[${innerIdx}]);
|
|
58
|
-
}
|
|
59
|
-
${tmpIssues}[${innerIdx}].input=undefined;
|
|
60
|
-
}
|
|
61
53
|
${errorsVar}.push(${tmpIssues});
|
|
62
54
|
${abortedVar}.push(${optAborted});
|
|
63
55
|
}
|
|
64
56
|
}`;
|
|
65
57
|
}
|
|
66
58
|
const msgProp = g.typeMsg === void 0 ? "" : `,message:${JSON.stringify(g.typeMsg)}`;
|
|
59
|
+
const fz = emitRuntimeHelper(g.ctx, "__zcFz", ZC_FZ_DECL);
|
|
67
60
|
const naVar = g.temp("una");
|
|
68
61
|
const oiVar = g.temp("uoi");
|
|
69
62
|
const ojVar = g.temp("uoj");
|
|
70
63
|
const abVar = g.temp("uab");
|
|
71
64
|
const ocVar = g.temp("uoc");
|
|
72
65
|
const okVar = g.temp("uok");
|
|
66
|
+
const ofVar = g.temp("uof");
|
|
67
|
+
const surfaced = `${naVar}[0][${okVar}]`;
|
|
73
68
|
code += emit`
|
|
74
69
|
if(!${resultVar}){
|
|
70
|
+
${pathVar === null ? "" : `var ${pathVar}=${g.path};`}
|
|
75
71
|
var ${naVar}=[];
|
|
76
72
|
for(var ${oiVar}=0;${oiVar}<${errorsVar}.length;${oiVar}++){
|
|
77
73
|
var ${abVar}=${abortedVar}[${oiVar}]===true;
|
|
@@ -84,9 +80,13 @@ function slowUnion(ir, g) {
|
|
|
84
80
|
if(!${abVar}){${naVar}.push(${errorsVar}[${oiVar}]);}
|
|
85
81
|
}
|
|
86
82
|
if(${naVar}.length===1){
|
|
87
|
-
for(var ${okVar}=0;${okVar}<${naVar}[0].length;${okVar}++){
|
|
83
|
+
for(var ${okVar}=0;${okVar}<${naVar}[0].length;${okVar}++){
|
|
84
|
+
${atPathRoot ? "" : `${surfaced}.path=${unionPath}.concat(${surfaced}.path);`}
|
|
85
|
+
${g.issues}.push(${surfaced});
|
|
86
|
+
}
|
|
88
87
|
}else{
|
|
89
|
-
${
|
|
88
|
+
for(var ${ofVar}=0;${ofVar}<${errorsVar}.length;${ofVar}++){${fz}(${errorsVar}[${ofVar}]);}
|
|
89
|
+
${g.issues}.push({code:"invalid_union",errors:${errorsVar}${msgProp},input:${g.input},path:${unionPath}});
|
|
90
90
|
}
|
|
91
91
|
}`;
|
|
92
92
|
return `${code}\n`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union.js","names":[],"sources":["../../../../src/core/codegen/schemas/union.ts"],"sourcesContent":["import type { SchemaIR, UnionIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { hasMutation } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { orderByRuntimeCost } from \"../fast-size.js\";\nimport { abortingCodeTest } from \"../issue-decls.js\";\nimport { detectUnionDiscriminator, emitFastDiscriminatedSwitch } from \"./discriminated-union.js\";\n\nexport function slowUnion(ir: SchemaIR & { type: \"union\" }, g: SlowGen): string {\n const resultVar = g.temp(\"u\");\n const errorsVar = g.temp(\"ue\");\n // Parallel to errorsVar: zod's `payload.aborted` for each failed option. Set\n // by a pipe/codec option whose `in` failed (see slowPipe); read during pruning\n // alongside the per-issue code check.\n const abortedVar = g.temp(\"uea\");\n let code = `var ${resultVar}=false;var ${errorsVar}=[];var ${abortedVar}=[];`;\n\n // If any option can mutate output (default, catch, coerce, effect),\n // each branch gets its own temp output to prevent cross-branch leaks.\n const needsOutputIsolation = ir.options.some(hasMutation);\n\n for (const option of ir.options) {\n const tmpIssues = g.temp(\"ui\");\n const innerIdx = g.temp(\"ufi\");\n // This option's abort flag, forwarded into the option so a pipe `in` failure\n // can raise it (zod's handlePipeResult). Stays false for every other shape.\n const optAborted = g.temp(\"uoa\");\n\n if (needsOutputIsolation) {\n const tmpOutput = g.temp(\"uo\");\n code += emit`\n if(!${resultVar}){\n var ${tmpIssues}=[];\n var ${optAborted}=false;\n var ${tmpOutput}=${g.input};\n ${g.visit(option, { issues: tmpIssues, input: tmpOutput, output: tmpOutput, aborted: optAborted })}\n if(${tmpIssues}.length===0){\n ${resultVar}=true;\n ${g.output}=${tmpOutput};\n }else{\n for(var ${innerIdx}=0;${innerIdx}<${tmpIssues}.length;${innerIdx}++){\n if(${tmpIssues}[${innerIdx}].message===undefined&&typeof __zcMsg===\"function\"){\n ${tmpIssues}[${innerIdx}].message=__zcMsg(${tmpIssues}[${innerIdx}]);\n }\n ${tmpIssues}[${innerIdx}].input=undefined;\n }\n ${errorsVar}.push(${tmpIssues});\n ${abortedVar}.push(${optAborted});\n }\n }`;\n } else {\n code += emit`\n if(!${resultVar}){\n var ${tmpIssues}=[];\n var ${optAborted}=false;\n ${g.visit(option, { issues: tmpIssues, aborted: optAborted })}\n if(${tmpIssues}.length===0){\n ${resultVar}=true;\n }else{\n for(var ${innerIdx}=0;${innerIdx}<${tmpIssues}.length;${innerIdx}++){\n if(${tmpIssues}[${innerIdx}].message===undefined&&typeof __zcMsg===\"function\"){\n ${tmpIssues}[${innerIdx}].message=__zcMsg(${tmpIssues}[${innerIdx}]);\n }\n ${tmpIssues}[${innerIdx}].input=undefined;\n }\n ${errorsVar}.push(${tmpIssues});\n ${abortedVar}.push(${optAborted});\n }\n }`;\n }\n }\n\n // Mirrors zod's handleUnionResults pruning (`util.aborted`): an option is\n // \"aborted\" when its result carries `payload.aborted` (a pipe whose `in`\n // failed — tracked in abortedVar) OR it produced a parse-level issue\n // (continue !== true in zod — invalid_type and friends). Check-level issues\n // (too_small, invalid_format, custom, ...) alone don't abort. If exactly ONE\n // option is non-aborted, its issues are surfaced directly instead of an\n // invalid_union wrapper.\n const msgProp = g.typeMsg === undefined ? \"\" : `,message:${JSON.stringify(g.typeMsg)}`;\n const naVar = g.temp(\"una\");\n const oiVar = g.temp(\"uoi\");\n const ojVar = g.temp(\"uoj\");\n const abVar = g.temp(\"uab\");\n const ocVar = g.temp(\"uoc\");\n const okVar = g.temp(\"uok\");\n code += emit`\n if(!${resultVar}){\n var ${naVar}=[];\n for(var ${oiVar}=0;${oiVar}<${errorsVar}.length;${oiVar}++){\n var ${abVar}=${abortedVar}[${oiVar}]===true;\n if(!${abVar}){\n for(var ${ojVar}=0;${ojVar}<${errorsVar}[${oiVar}].length;${ojVar}++){\n var ${ocVar}=${errorsVar}[${oiVar}][${ojVar}].code;\n if(${abortingCodeTest(ocVar)}){${abVar}=true;break;}\n }\n }\n if(!${abVar}){${naVar}.push(${errorsVar}[${oiVar}]);}\n }\n if(${naVar}.length===1){\n for(var ${okVar}=0;${okVar}<${naVar}[0].length;${okVar}++){${g.issues}.push(${naVar}[0][${okVar}]);}\n }else{\n ${g.issues}.push({code:\"invalid_union\",errors:${errorsVar}${msgProp},input:${g.input},path:${g.path}});\n }\n }`;\n return `${code}\\n`;\n}\n\nexport function fastUnion(ir: UnionIR, g: FastGen): string | null {\n // A plain `z.union` of objects that all pin a shared key to disjoint literals\n // is structurally a discriminated union: dispatch on that key with an O(1)\n // switch instead of probing every arm in sequence. detectUnionDiscriminator\n // returns non-null only when the switch provably accepts exactly what the\n // ||-chain would (disjoint required literals). The slow path is untouched, so\n // error output stays identical to Zod's plain-union behavior.\n const discriminated = detectUnionDiscriminator(ir.options);\n if (discriminated !== null) {\n return emitFastDiscriminatedSwitch(\n g,\n discriminated.discriminator,\n discriminated.cases,\n ir.options,\n );\n }\n\n // Probe cheap options first: the ||-chain stops at the first match, and an\n // option that cannot match is rejected by its own cheapest-first conjunct\n // chain. Which option matches is unobservable here (the result is a single\n // boolean), and the slow path — where option order IS observable, through\n // zod's first-match output and invalid_union issue order — is untouched.\n const optionChecks: string[] = [];\n for (const option of orderByRuntimeCost(ir.options, (o) => o, g.ctx)) {\n const check = g.visit(option);\n if (check === null) return null;\n optionChecks.push(`(${check})`);\n }\n // Wrap in parens — || has lower precedence than && in parent expressions\n return `(${optionChecks.join(\"||\")})`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"union.js","names":[],"sources":["../../../../src/core/codegen/schemas/union.ts"],"sourcesContent":["import type { SchemaIR, UnionIR } from \"../../types.js\";\nimport type { FastGen, SlowGen } from \"../context.js\";\nimport { emitRuntimeHelper, hasMutation } from \"../context.js\";\nimport { emit } from \"../emit.js\";\nimport { orderByRuntimeCost } from \"../fast-size.js\";\nimport { abortingCodeTest, ZC_FZ_DECL } from \"../issue-decls.js\";\nimport { detectUnionDiscriminator, emitFastDiscriminatedSwitch } from \"./discriminated-union.js\";\n\nexport function slowUnion(ir: SchemaIR & { type: \"union\" }, g: SlowGen): string {\n const resultVar = g.temp(\"u\");\n const errorsVar = g.temp(\"ue\");\n // Parallel to errorsVar: zod's `payload.aborted` for each failed option. Set\n // by a pipe/codec option whose `in` failed (see slowPipe); read during pruning\n // alongside the per-issue code check.\n const abortedVar = g.temp(\"uea\");\n let code = `var ${resultVar}=false;var ${errorsVar}=[];var ${abortedVar}=[];`;\n\n // Options run at a path RELATIVE to the union, not at the union's own path.\n //\n // $ZodUnion hands each option a FRESH payload — `{ value: payload.value,\n // issues: [] }` — so every issue an option raises is numbered from the union's\n // position, and handleUnionResults copies those relative paths into the\n // `invalid_union` groups unchanged. Walking options at the union's absolute\n // path instead leaked it into all of them: `{a: z.union([...])}` reported the\n // nested errors at `[\"a\"]` where zod reports `[]`. Same model record/map\n // already use for their key and value schemas.\n //\n // The union's own path is re-applied in exactly one place, mirroring the one\n // place zod re-applies it: handleUnionResults' shortcut for a single\n // non-aborted option returns THAT OPTION'S payload, whose issues are still\n // relative, and the PARENT (an object's handlePropertyResult, say) prefixes\n // them exactly once. Compiled parents bake their path into each issue at\n // creation, so the union has to do that prefixing itself.\n //\n // That path expression is read ONCE, into `pathVar`, rather than at each issue\n // below — it may allocate a fresh array per evaluation (`[\"items\",__i_7]`).\n // The binding is emitted inside the failure block further down, not here: both\n // readers live there, so a union that matches an option never evaluates it at\n // all, and the whole of this generator's output is one contiguous block at the\n // union's site, so any enclosing loop variable the expression names is equally\n // in scope there. A union already at `[]` prefixes nothing (concat would only\n // copy the array), so it skips the binding entirely.\n const atPathRoot = g.path === \"[]\";\n const pathVar = atPathRoot ? null : g.temp(\"up\");\n const unionPath = pathVar ?? \"[]\";\n\n // If any option can mutate output (default, catch, coerce, effect),\n // each branch gets its own temp output to prevent cross-branch leaks.\n const needsOutputIsolation = ir.options.some(hasMutation);\n\n for (const option of ir.options) {\n const tmpIssues = g.temp(\"ui\");\n // This option's abort flag, forwarded into the option so a pipe `in` failure\n // can raise it (zod's handlePipeResult). Stays false for every other shape.\n const optAborted = g.temp(\"uoa\");\n\n if (needsOutputIsolation) {\n const tmpOutput = g.temp(\"uo\");\n code += emit`\n if(!${resultVar}){\n var ${tmpIssues}=[];\n var ${optAborted}=false;\n var ${tmpOutput}=${g.input};\n ${g.visit(option, { issues: tmpIssues, input: tmpOutput, output: tmpOutput, path: \"[]\", aborted: optAborted })}\n if(${tmpIssues}.length===0){\n ${resultVar}=true;\n ${g.output}=${tmpOutput};\n }else{\n ${errorsVar}.push(${tmpIssues});\n ${abortedVar}.push(${optAborted});\n }\n }`;\n } else {\n code += emit`\n if(!${resultVar}){\n var ${tmpIssues}=[];\n var ${optAborted}=false;\n ${g.visit(option, { issues: tmpIssues, path: \"[]\", aborted: optAborted })}\n if(${tmpIssues}.length===0){\n ${resultVar}=true;\n }else{\n ${errorsVar}.push(${tmpIssues});\n ${abortedVar}.push(${optAborted});\n }\n }`;\n }\n }\n\n // Mirrors zod's handleUnionResults pruning (`util.aborted`): an option is\n // \"aborted\" when its result carries `payload.aborted` (a pipe whose `in`\n // failed — tracked in abortedVar) OR it produced a parse-level issue\n // (continue !== true in zod — invalid_type and friends). Check-level issues\n // (too_small, invalid_format, custom, ...) alone don't abort. If exactly ONE\n // option is non-aborted, its issues are surfaced directly instead of an\n // invalid_union wrapper.\n const msgProp = g.typeMsg === undefined ? \"\" : `,message:${JSON.stringify(g.typeMsg)}`;\n const fz = emitRuntimeHelper(g.ctx, \"__zcFz\", ZC_FZ_DECL);\n const naVar = g.temp(\"una\");\n const oiVar = g.temp(\"uoi\");\n const ojVar = g.temp(\"uoj\");\n const abVar = g.temp(\"uab\");\n const ocVar = g.temp(\"uoc\");\n const okVar = g.temp(\"uok\");\n const ofVar = g.temp(\"uof\");\n const surfaced = `${naVar}[0][${okVar}]`;\n // Which branch fires decides where an option's issues are finalized, because\n // the two branches finalize at DIFFERENT paths — so neither can be done up\n // front, in the option loop, without being wrong for the other half:\n //\n // - invalid_union: zod maps each group through `finalizeIssue` while the paths\n // are still relative, so an error map reading `issue.path` sees `[]`.\n // __zcFz is that same locale-fill + input-strip, and is what record/map\n // already use for the issues they nest.\n // - sole non-aborted: zod surfaces the option's own issues, which reach the\n // top-level finalizer with the FULL path, so the message is computed from\n // the absolute path. Prefix here and leave them unfinalized — they land in\n // the parent's issue array, which is finalized at the top exactly once.\n code += emit`\n if(!${resultVar}){\n ${pathVar === null ? \"\" : `var ${pathVar}=${g.path};`}\n var ${naVar}=[];\n for(var ${oiVar}=0;${oiVar}<${errorsVar}.length;${oiVar}++){\n var ${abVar}=${abortedVar}[${oiVar}]===true;\n if(!${abVar}){\n for(var ${ojVar}=0;${ojVar}<${errorsVar}[${oiVar}].length;${ojVar}++){\n var ${ocVar}=${errorsVar}[${oiVar}][${ojVar}].code;\n if(${abortingCodeTest(ocVar)}){${abVar}=true;break;}\n }\n }\n if(!${abVar}){${naVar}.push(${errorsVar}[${oiVar}]);}\n }\n if(${naVar}.length===1){\n for(var ${okVar}=0;${okVar}<${naVar}[0].length;${okVar}++){\n ${atPathRoot ? \"\" : `${surfaced}.path=${unionPath}.concat(${surfaced}.path);`}\n ${g.issues}.push(${surfaced});\n }\n }else{\n for(var ${ofVar}=0;${ofVar}<${errorsVar}.length;${ofVar}++){${fz}(${errorsVar}[${ofVar}]);}\n ${g.issues}.push({code:\"invalid_union\",errors:${errorsVar}${msgProp},input:${g.input},path:${unionPath}});\n }\n }`;\n return `${code}\\n`;\n}\n\nexport function fastUnion(ir: UnionIR, g: FastGen): string | null {\n // A plain `z.union` of objects that all pin a shared key to disjoint literals\n // is structurally a discriminated union: dispatch on that key with an O(1)\n // switch instead of probing every arm in sequence. detectUnionDiscriminator\n // returns non-null only when the switch provably accepts exactly what the\n // ||-chain would (disjoint required literals). The slow path is untouched, so\n // error output stays identical to Zod's plain-union behavior.\n const discriminated = detectUnionDiscriminator(ir.options);\n if (discriminated !== null) {\n return emitFastDiscriminatedSwitch(\n g,\n discriminated.discriminator,\n discriminated.cases,\n ir.options,\n );\n }\n\n // Probe cheap options first: the ||-chain stops at the first match, and an\n // option that cannot match is rejected by its own cheapest-first conjunct\n // chain. Which option matches is unobservable here (the result is a single\n // boolean), and the slow path — where option order IS observable, through\n // zod's first-match output and invalid_union issue order — is untouched.\n const optionChecks: string[] = [];\n for (const option of orderByRuntimeCost(ir.options, (o) => o, g.ctx)) {\n const check = g.visit(option);\n if (check === null) return null;\n optionChecks.push(`(${check})`);\n }\n // Wrap in parens — || has lower precedence than && in parent expressions\n return `(${optionChecks.join(\"||\")})`;\n}\n"],"mappings":"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"}
|
|
@@ -9,6 +9,20 @@ import { ExtractorContext, ZodCheckDef, ZodCheckSchema } from "./types.js";
|
|
|
9
9
|
* before" — when the extraction is not collecting refs.
|
|
10
10
|
*/
|
|
11
11
|
declare function refineRefRegistrar(ctx: ExtractorContext, checks: ZodCheckSchema[]): ((index: number) => number | undefined) | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Build the `customParamsRef` registrar for {@link extractChecks}: it appends a
|
|
14
|
+
* {@link RefEntry} pointing at the check's own `params` object
|
|
15
|
+
* (`<schema>._zod.def.checks[i]._zod.def.params`), which $ZodCustom copies onto
|
|
16
|
+
* the issue by reference.
|
|
17
|
+
*
|
|
18
|
+
* A reference rather than a baked literal because `params` is opaque user data:
|
|
19
|
+
* it may hold functions, symbols or a cycle (none of which survive a literal),
|
|
20
|
+
* and zod hands out the SAME object on every issue, so a per-failure copy would
|
|
21
|
+
* break the identity comparison that is the point of passing params.
|
|
22
|
+
*
|
|
23
|
+
* Returns undefined — meaning "fall back to zod" — when refs are unavailable.
|
|
24
|
+
*/
|
|
25
|
+
declare function customParamsRefRegistrar(ctx: ExtractorContext, checks: ZodCheckSchema[]): ((index: number) => number | undefined) | undefined;
|
|
12
26
|
/**
|
|
13
27
|
* Register the payload-taking callback of check `index` (`superRefine`) as an
|
|
14
28
|
* `__rf[N]` reference, pointing at zod's own wrapper
|
|
@@ -37,7 +51,9 @@ declare function extractChecks(checks: ZodCheckSchema[],
|
|
|
37
51
|
*/
|
|
38
52
|
refineRef?: (index: number) => number | undefined,
|
|
39
53
|
/** Registers a payload-taking callback (superRefine); see payloadCheckRef. */
|
|
40
|
-
payloadRefFor?: (index: number) => number | undefined
|
|
54
|
+
payloadRefFor?: (index: number) => number | undefined,
|
|
55
|
+
/** Registers a `.refine(fn, { params })` payload; see customParamsRefRegistrar. */
|
|
56
|
+
customParamsRef?: (index: number) => number | undefined): {
|
|
41
57
|
checkIRs: CheckOrEffectIR[];
|
|
42
58
|
hasFallback: boolean;
|
|
43
59
|
};
|
|
@@ -61,5 +77,5 @@ type ResolvedMessage = {
|
|
|
61
77
|
*/
|
|
62
78
|
declare function resolveCheckMessage(error: unknown): ResolvedMessage;
|
|
63
79
|
//#endregion
|
|
64
|
-
export { ResolvedMessage, extractChecks, hasUncompilableModifiers, payloadCheckRef, refineRefRegistrar, resolveCheckMessage };
|
|
80
|
+
export { ResolvedMessage, customParamsRefRegistrar, extractChecks, hasUncompilableModifiers, payloadCheckRef, refineRefRegistrar, resolveCheckMessage };
|
|
65
81
|
//# sourceMappingURL=checks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checks.d.ts","names":[],"sources":["../../../src/core/extract/checks.ts"],"mappings":";;;;;;;;;;iBAWgB,mBACd,KAAK,kBACL,QAAQ,qBACL;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"checks.d.ts","names":[],"sources":["../../../src/core/extract/checks.ts"],"mappings":";;;;;;;;;;iBAWgB,mBACd,KAAK,kBACL,QAAQ,qBACL;;;;;;;;;;;;;;iBAwBW,yBACd,KAAK,kBACL,QAAQ,qBACL;;;;;;;;;;;iBAsBW,gBACd,KAAK,kBACL,QAAQ,kBACR;;;;;;;iBA6Ic,yBAAyB,KAAK;iBAI9B,cACd,QAAQ,kBAQR;;;;;;;;AAAA,aAAa,sCAEb;;AAAA,iBAAiB,sCAEjB;;AAAA,mBAAmB;EAEnB,UAAU;EACV;;KA6NU;EACN;;EACA;EAAgB;;EAChB;;;;;;;;;;;;iBAYU,oBAAoB,iBAAiB"}
|