zod-compiler 2.0.4 → 2.0.5
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/context.d.ts +38 -1
- package/dist/core/codegen/context.d.ts.map +1 -1
- package/dist/core/codegen/context.js +51 -1
- package/dist/core/codegen/context.js.map +1 -1
- package/dist/core/codegen/schemas/array.d.ts.map +1 -1
- package/dist/core/codegen/schemas/array.js +23 -17
- package/dist/core/codegen/schemas/array.js.map +1 -1
- package/dist/core/codegen/schemas/discriminated-union.d.ts.map +1 -1
- package/dist/core/codegen/schemas/discriminated-union.js +2 -2
- 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 +1 -1
- package/dist/core/codegen/schemas/effect.js.map +1 -1
- package/dist/core/codegen/schemas/map.d.ts.map +1 -1
- package/dist/core/codegen/schemas/map.js +70 -17
- package/dist/core/codegen/schemas/map.js.map +1 -1
- package/dist/core/codegen/schemas/record.d.ts.map +1 -1
- package/dist/core/codegen/schemas/record.js +23 -17
- package/dist/core/codegen/schemas/record.js.map +1 -1
- package/dist/core/codegen/schemas/set.d.ts.map +1 -1
- package/dist/core/codegen/schemas/set.js +51 -13
- package/dist/core/codegen/schemas/set.js.map +1 -1
- package/dist/core/codegen/schemas/tuple.d.ts.map +1 -1
- package/dist/core/codegen/schemas/tuple.js +16 -13
- 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 +21 -15
- package/dist/core/codegen/schemas/union.js.map +1 -1
- package/package.json +1 -1
|
@@ -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 {\n declareFastTemps,\n extendPath,\n extendStaticPathIndex,\n hasMutation,\n outputAlwaysDefined,\n tupleRewritesShortInput,\n} 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 * What an ABSENT slot (index at or past the input's length) does to the output,\n * per zod's `handleTupleResults`:\n *\n * - `present`: can never be absent — below `optStart` without a rest element,\n * where a shorter input is already `too_small`.\n * - `skip`: at or past `optoutStart` and on the \"optional\" rung of `optin`.\n * The output ends here; the item is not consulted and nothing after it runs.\n * - `tail`: at or past `optoutStart` on any other rung. The item runs on\n * `undefined`; a failure ends the output here with its issues dropped, a\n * success is written back and may be trimmed later if it is `undefined`.\n * - `pad`: below `optoutStart`, so a later slot has to keep its index. The\n * item runs on `undefined`, its issues count, and its result — an own\n * `undefined` at the least — is written back.\n */\ntype SlotKind = \"present\" | \"skip\" | \"tail\" | \"pad\";\n\nfunction slotKinds(ir: TupleIR): SlotKind[] {\n const len = ir.items.length;\n const optoutStart = ir.optoutStart ?? len;\n const optionalIn = new Set(ir.optionalIn ?? []);\n const absentFrom = ir.rest === null ? ir.optStart : 0;\n return ir.items.map((_, i) => {\n if (i < absentFrom) return \"present\";\n if (i < optoutStart) return \"pad\";\n return optionalIn.has(i) ? \"skip\" : \"tail\";\n });\n}\n\n/**\n * Mirrors $ZodTuple. Without rest, an input shorter than `optStart` is a single\n * `too_small` (`minimum: optStart`, `inclusive: true`) that skips item\n * validation, and a longer one a single `too_big` that does NOT — zod pushes it\n * and runs the items anyway, so their issues follow it. Both are created by\n * the tuple node (schema error applies) and both share the `code, minimum |\n * maximum, inclusive, origin` key order that check-created size issues do not.\n *\n * Every item then runs, absent slots included, and the output is shaped by\n * {@link slotKinds}. The generated code keeps zod's invariant that the output\n * grows one slot at a time from the input's length: a slot that is about to be\n * handled as absent is exactly the output's current length, and once a `skip`\n * or a failed `tail` ends the output, every later absent slot sees a shorter\n * array and falls through. Ending the output at slot `i` needs no truncation\n * beyond what the failed item may have written, because nothing past `i` was\n * ever assigned.\n */\nexport function slowTuple(ir: SchemaIR & { type: \"tuple\" }, g: SlowGen): string {\n const len = ir.items.length;\n const kinds = slotKinds(ir);\n const optoutStart = ir.optoutStart ?? len;\n\n // Every read and write goes through ONE binding, seeded from the input and\n // re-pointed by each copy, with the result written to `g.output` at the end.\n // Reading `g.input` and writing `g.output` directly only worked while the two\n // were the same identifier — true at every `createSlowGen` root, but NOT under\n // `z.preprocess()`, which visits with `{ input: valueVar, output: g.output }`\n // (see slowEffect). There a copy landed in `g.output` while the item writes\n // went on hitting the original, so the output kept the pristine short array\n // and the caller's array collected the padding instead.\n const x = g.temp(\"ta\");\n\n // With a rest element the fixed items' issues are BUFFERED and flushed after\n // the rest loop, because that is the order zod reports them in: `$ZodTuple`\n // collects the fixed items into `itemResults` WITHOUT touching the payload,\n // runs the rest loop (which pushes through `handleTupleResult`), and only\n // then calls `handleTupleResults`, which pushes what it buffered. So\n // `z.tuple([z.string()]).rest(z.number())` on `[1,\"b\"]` reports the rest\n // element's issue first. `ZodError.message` is `JSON.stringify(issues)`, so\n // the order is user-visible, not just an array detail.\n const itemIssues = ir.rest === null ? g.issues : g.temp(\"tqi\");\n\n let code = emit`\n if(!Array.isArray(${g.input})){\n ${invalidType(g, \"tuple\")}\n }else{\n var ${x}=${g.input};\n ${ir.rest === null ? \"\" : `var ${itemIssues}=[];`}`;\n\n let itemsCode = \"\";\n const mutates = ir.items.some(hasMutation) || (ir.rest !== null && hasMutation(ir.rest));\n if (mutates) {\n itemsCode += `${x}=${x}.slice();`;\n }\n\n // The input's length, read once: absent slots are written back and would\n // otherwise shift the presence test for the slots after them.\n const lenVar = kinds.some((k) => k !== \"present\") ? g.temp(\"tl\") : \"\";\n if (lenVar) itemsCode += `var ${lenVar}=${x}.length;`;\n // A short input gains slots, so it is copied before the first write — the\n // caller's array must not grow. Guarded on the length so a well-formed input\n // never allocates; a mutating item has already paid for the copy.\n if (!mutates && tupleRewritesShortInput(ir)) {\n itemsCode += `if(${lenVar}<${len}){${x}=${x}.slice();}`;\n }\n\n for (let i = 0; i < len; i++) {\n const itemIR = ir.items[i] as SchemaIR;\n const elemExpr = `${x}[${i}]`;\n const elemPath = extendStaticPathIndex(g.path, i);\n const itemCode = g.visit(itemIR, {\n input: elemExpr,\n output: elemExpr,\n path: elemPath,\n issues: itemIssues,\n });\n // One copy of the item code per slot: an absent slot is materialized as an\n // own `undefined` first (`x[i] = undefined`, which is also what extends the\n // copied array), then validated exactly as a present one would be.\n const absent = `${i}>=${lenVar}`;\n switch (kinds[i]) {\n case \"present\":\n itemsCode += itemCode;\n break;\n case \"skip\":\n itemsCode += emit`if(${i}<${lenVar}){${itemCode}}`;\n break;\n case \"tail\": {\n const beforeVar = g.temp(\"tb\");\n itemsCode += emit`\n if(${i}<${lenVar}||${x}.length===${i}){\n var ${beforeVar}=${itemIssues}.length;\n if(${absent}){${elemExpr}=undefined;}\n ${itemCode}\n if(${absent}&&${itemIssues}.length>${beforeVar}){${itemIssues}.length=${beforeVar};${x}.length=${i};}\n }`;\n break;\n }\n case \"pad\":\n itemsCode += emit`if(${absent}){${elemExpr}=undefined;}${itemCode}`;\n break;\n }\n }\n\n // zod's trailing trim: absent slots that produced `undefined` are dropped\n // from the end while the item is optional-out. Only a `tail` slot can leave\n // one behind (a `pad` slot sits below `optoutStart`, a `skip` slot writes\n // nothing), so the loop is emitted only when some tail item might.\n if (kinds.some((k, i) => k === \"tail\" && !outputAlwaysDefined(ir.items[i] as SchemaIR))) {\n const tVar = g.temp(\"tt\");\n const floor = optoutStart > 0 ? `${tVar}>=${optoutStart}&&` : \"\";\n itemsCode += `for(var ${tVar}=${x}.length-1;${floor}${tVar}>=${lenVar}&&${x}[${tVar}]===undefined;${tVar}--){${x}.length=${tVar};}`;\n }\n\n if (ir.rest !== null) {\n const idxVar = g.temp(\"ti\");\n const restExpr = `${x}[${idxVar}]`;\n const restPath = extendPath(g.path, idxVar);\n itemsCode += emit`\n for(var ${idxVar}=${len};${idxVar}<${x}.length;${idxVar}++){\n ${g.visit(ir.rest, { input: restExpr, output: restExpr, path: restPath })}\n }`;\n const flushVar = g.temp(\"tqj\");\n itemsCode += `for(var ${flushVar}=0;${flushVar}<${itemIssues}.length;${flushVar}++){${g.issues}.push(${itemIssues}[${flushVar}]);}`;\n itemsCode += `${g.output}=${x};`;\n code += itemsCode;\n } else {\n const body = emit`\n if(${x}.length>${len}){\n ${tooBig(g, len, \"array\", true, { layout: \"tuple\", aborts: true })}\n }\n ${itemsCode}\n ${g.output}=${x};`;\n code +=\n ir.optStart > 0\n ? emit`\n if(${x}.length<${ir.optStart}){\n ${tooSmall(g, ir.optStart, \"array\", true, { layout: \"tuple\", aborts: true })}\n }else{\n ${body}\n }`\n : body;\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 const kinds = slotKinds(ir);\n\n if (ir.rest === null) {\n if (ir.optStart === ir.items.length) {\n parts.push(`${x}.length===${ir.items.length}`);\n } else {\n if (ir.optStart > 0) parts.push(`${x}.length>=${ir.optStart}`);\n parts.push(`${x}.length<=${ir.items.length}`);\n }\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 const kind = kinds[index];\n // The fast check answers true only where the output IS the input (see\n // fastResultIsInput), so a slot that would be written back when absent —\n // `pad` and `tail` alike — must be present here; the slow walk builds the\n // longer output. A `skip` slot is the reverse: absent, it is accepted\n // whatever its item says, since zod ends the output there without\n // consulting it.\n if (kind === \"pad\" || kind === \"tail\") {\n parts.push(\n itemCheck === \"true\" ? `${x}.length>${index}` : `${x}.length>${index}&&${itemCheck}`,\n );\n } else if (itemCheck === \"true\") {\n continue;\n } else {\n parts.push(kind === \"skip\" ? `(${x}.length<=${index}||${itemCheck})` : itemCheck);\n }\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
|
+
{"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 {\n declareFastTemps,\n extendPath,\n extendStaticPathIndex,\n hasMutation,\n outputAlwaysDefined,\n tupleRewritesShortInput,\n visitMember,\n} 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 * What an ABSENT slot (index at or past the input's length) does to the output,\n * per zod's `handleTupleResults`:\n *\n * - `present`: can never be absent — below `optStart` without a rest element,\n * where a shorter input is already `too_small`.\n * - `skip`: at or past `optoutStart` and on the \"optional\" rung of `optin`.\n * The output ends here; the item is not consulted and nothing after it runs.\n * - `tail`: at or past `optoutStart` on any other rung. The item runs on\n * `undefined`; a failure ends the output here with its issues dropped, a\n * success is written back and may be trimmed later if it is `undefined`.\n * - `pad`: below `optoutStart`, so a later slot has to keep its index. The\n * item runs on `undefined`, its issues count, and its result — an own\n * `undefined` at the least — is written back.\n */\ntype SlotKind = \"present\" | \"skip\" | \"tail\" | \"pad\";\n\nfunction slotKinds(ir: TupleIR): SlotKind[] {\n const len = ir.items.length;\n const optoutStart = ir.optoutStart ?? len;\n const optionalIn = new Set(ir.optionalIn ?? []);\n const absentFrom = ir.rest === null ? ir.optStart : 0;\n return ir.items.map((_, i) => {\n if (i < absentFrom) return \"present\";\n if (i < optoutStart) return \"pad\";\n return optionalIn.has(i) ? \"skip\" : \"tail\";\n });\n}\n\n/**\n * Mirrors $ZodTuple. Without rest, an input shorter than `optStart` is a single\n * `too_small` (`minimum: optStart`, `inclusive: true`) that skips item\n * validation, and a longer one a single `too_big` that does NOT — zod pushes it\n * and runs the items anyway, so their issues follow it. Both are created by\n * the tuple node (schema error applies) and both share the `code, minimum |\n * maximum, inclusive, origin` key order that check-created size issues do not.\n *\n * Every item then runs, absent slots included, and the output is shaped by\n * {@link slotKinds}. The generated code keeps zod's invariant that the output\n * grows one slot at a time from the input's length: a slot that is about to be\n * handled as absent is exactly the output's current length, and once a `skip`\n * or a failed `tail` ends the output, every later absent slot sees a shorter\n * array and falls through. Ending the output at slot `i` needs no truncation\n * beyond what the failed item may have written, because nothing past `i` was\n * ever assigned.\n */\nexport function slowTuple(ir: SchemaIR & { type: \"tuple\" }, g: SlowGen): string {\n const len = ir.items.length;\n const kinds = slotKinds(ir);\n const optoutStart = ir.optoutStart ?? len;\n\n // Every read and write goes through ONE binding, seeded from the input and\n // re-pointed by each copy, with the result written to `g.output` at the end.\n // Reading `g.input` and writing `g.output` directly only works while the two\n // are the same identifier — true at every `createSlowGen` root, but not where\n // a parent hands over a separate local for each (an object's pass-through\n // property, a container member that rewrites nothing: see visitMember). There\n // a copy lands in `g.output` while the writes go on hitting the original, so\n // the output keeps the pristine array and the caller's array collects the\n // changes instead.\n const x = g.temp(\"ta\");\n\n // With a rest element the fixed items' issues are BUFFERED and flushed after\n // the rest loop, because that is the order zod reports them in: `$ZodTuple`\n // collects the fixed items into `itemResults` WITHOUT touching the payload,\n // runs the rest loop (which pushes through `handleTupleResult`), and only\n // then calls `handleTupleResults`, which pushes what it buffered. So\n // `z.tuple([z.string()]).rest(z.number())` on `[1,\"b\"]` reports the rest\n // element's issue first. `ZodError.message` is `JSON.stringify(issues)`, so\n // the order is user-visible, not just an array detail.\n const itemIssues = ir.rest === null ? g.issues : g.temp(\"tqi\");\n\n let code = emit`\n if(!Array.isArray(${g.input})){\n ${invalidType(g, \"tuple\")}\n }else{\n var ${x}=${g.input};\n ${ir.rest === null ? \"\" : `var ${itemIssues}=[];`}`;\n\n let itemsCode = \"\";\n const mutates = ir.items.some(hasMutation) || (ir.rest !== null && hasMutation(ir.rest));\n if (mutates) {\n itemsCode += `${x}=${x}.slice();`;\n }\n\n // The input's length, read once: absent slots are written back and would\n // otherwise shift the presence test for the slots after them.\n const lenVar = kinds.some((k) => k !== \"present\") ? g.temp(\"tl\") : \"\";\n if (lenVar) itemsCode += `var ${lenVar}=${x}.length;`;\n // A short input gains slots, so it is copied before the first write — the\n // caller's array must not grow. Guarded on the length so a well-formed input\n // never allocates; a mutating item has already paid for the copy.\n if (!mutates && tupleRewritesShortInput(ir)) {\n itemsCode += `if(${lenVar}<${len}){${x}=${x}.slice();}`;\n }\n\n for (let i = 0; i < len; i++) {\n const itemIR = ir.items[i] as SchemaIR;\n const elemExpr = `${x}[${i}]`;\n // Read into a local and handed back through visitMember, which lands a\n // replacement on a copy while `x` is still the caller's array.\n const itemCode = visitMember(g, itemIR, {\n container: x,\n original: g.input,\n copy: `${x}.slice()`,\n key: String(i),\n path: extendStaticPathIndex(g.path, i),\n issues: itemIssues,\n });\n // One copy of the item code per slot: an absent slot is materialized as an\n // own `undefined` first (`x[i] = undefined`, which is also what extends the\n // copied array), then validated exactly as a present one would be.\n const absent = `${i}>=${lenVar}`;\n switch (kinds[i]) {\n case \"present\":\n itemsCode += itemCode;\n break;\n case \"skip\":\n itemsCode += emit`if(${i}<${lenVar}){${itemCode}}`;\n break;\n case \"tail\": {\n const beforeVar = g.temp(\"tb\");\n itemsCode += emit`\n if(${i}<${lenVar}||${x}.length===${i}){\n var ${beforeVar}=${itemIssues}.length;\n if(${absent}){${elemExpr}=undefined;}\n ${itemCode}\n if(${absent}&&${itemIssues}.length>${beforeVar}){${itemIssues}.length=${beforeVar};${x}.length=${i};}\n }`;\n break;\n }\n case \"pad\":\n itemsCode += emit`if(${absent}){${elemExpr}=undefined;}${itemCode}`;\n break;\n }\n }\n\n // zod's trailing trim: absent slots that produced `undefined` are dropped\n // from the end while the item is optional-out. Only a `tail` slot can leave\n // one behind (a `pad` slot sits below `optoutStart`, a `skip` slot writes\n // nothing), so the loop is emitted only when some tail item might.\n if (kinds.some((k, i) => k === \"tail\" && !outputAlwaysDefined(ir.items[i] as SchemaIR))) {\n const tVar = g.temp(\"tt\");\n const floor = optoutStart > 0 ? `${tVar}>=${optoutStart}&&` : \"\";\n itemsCode += `for(var ${tVar}=${x}.length-1;${floor}${tVar}>=${lenVar}&&${x}[${tVar}]===undefined;${tVar}--){${x}.length=${tVar};}`;\n }\n\n if (ir.rest !== null) {\n const idxVar = g.temp(\"ti\");\n const restCode = visitMember(g, ir.rest, {\n container: x,\n original: g.input,\n copy: `${x}.slice()`,\n key: idxVar,\n path: extendPath(g.path, idxVar),\n issues: g.issues,\n });\n itemsCode += emit`\n for(var ${idxVar}=${len};${idxVar}<${x}.length;${idxVar}++){\n ${restCode}\n }`;\n const flushVar = g.temp(\"tqj\");\n itemsCode += `for(var ${flushVar}=0;${flushVar}<${itemIssues}.length;${flushVar}++){${g.issues}.push(${itemIssues}[${flushVar}]);}`;\n itemsCode += `${g.output}=${x};`;\n code += itemsCode;\n } else {\n const body = emit`\n if(${x}.length>${len}){\n ${tooBig(g, len, \"array\", true, { layout: \"tuple\", aborts: true })}\n }\n ${itemsCode}\n ${g.output}=${x};`;\n code +=\n ir.optStart > 0\n ? emit`\n if(${x}.length<${ir.optStart}){\n ${tooSmall(g, ir.optStart, \"array\", true, { layout: \"tuple\", aborts: true })}\n }else{\n ${body}\n }`\n : body;\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 const kinds = slotKinds(ir);\n\n if (ir.rest === null) {\n if (ir.optStart === ir.items.length) {\n parts.push(`${x}.length===${ir.items.length}`);\n } else {\n if (ir.optStart > 0) parts.push(`${x}.length>=${ir.optStart}`);\n parts.push(`${x}.length<=${ir.items.length}`);\n }\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 const kind = kinds[index];\n // The fast check answers true only where the output IS the input (see\n // fastResultIsInput), so a slot that would be written back when absent —\n // `pad` and `tail` alike — must be present here; the slow walk builds the\n // longer output. A `skip` slot is the reverse: absent, it is accepted\n // whatever its item says, since zod ends the output there without\n // consulting it.\n if (kind === \"pad\" || kind === \"tail\") {\n parts.push(\n itemCheck === \"true\" ? `${x}.length>${index}` : `${x}.length>${index}&&${itemCheck}`,\n );\n } else if (itemCheck === \"true\") {\n continue;\n } else {\n parts.push(kind === \"skip\" ? `(${x}.length<=${index}||${itemCheck})` : itemCheck);\n }\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;iBAiK/C,UAAU,IAAI,SAAS,GAAG"}
|
|
@@ -16,20 +16,19 @@ function slowUnion(ir, g) {
|
|
|
16
16
|
for (const option of ir.options) {
|
|
17
17
|
const tmpIssues = g.temp("ui");
|
|
18
18
|
const optAborted = g.temp("uoa");
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
code += emit`
|
|
19
|
+
const tmpOutput = g.temp("uo");
|
|
20
|
+
if (needsOutputIsolation) code += emit`
|
|
22
21
|
if(!${resultVar}){
|
|
23
22
|
var ${tmpIssues}=[];
|
|
24
23
|
var ${optAborted}=false;
|
|
25
24
|
var ${tmpOutput}=${g.input};
|
|
26
25
|
${g.visit(option, {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
issues: tmpIssues,
|
|
27
|
+
input: tmpOutput,
|
|
28
|
+
output: tmpOutput,
|
|
29
|
+
path: "[]",
|
|
30
|
+
aborted: optAborted
|
|
31
|
+
})}
|
|
33
32
|
if(${tmpIssues}.length===0){
|
|
34
33
|
${resultVar}=true;
|
|
35
34
|
${g.output}=${tmpOutput};
|
|
@@ -38,22 +37,29 @@ function slowUnion(ir, g) {
|
|
|
38
37
|
${abortedVar}.push(${optAborted});
|
|
39
38
|
}
|
|
40
39
|
}`;
|
|
41
|
-
|
|
40
|
+
else {
|
|
41
|
+
const optionCode = g.visit(option, {
|
|
42
|
+
issues: tmpIssues,
|
|
43
|
+
output: tmpOutput,
|
|
44
|
+
path: "[]",
|
|
45
|
+
aborted: optAborted
|
|
46
|
+
});
|
|
47
|
+
const writes = optionCode.includes(tmpOutput);
|
|
48
|
+
code += emit`
|
|
42
49
|
if(!${resultVar}){
|
|
43
50
|
var ${tmpIssues}=[];
|
|
44
51
|
var ${optAborted}=false;
|
|
45
|
-
${g.
|
|
46
|
-
|
|
47
|
-
path: "[]",
|
|
48
|
-
aborted: optAborted
|
|
49
|
-
})}
|
|
52
|
+
${writes ? `var ${tmpOutput}=${g.input};` : ""}
|
|
53
|
+
${optionCode}
|
|
50
54
|
if(${tmpIssues}.length===0){
|
|
51
55
|
${resultVar}=true;
|
|
56
|
+
${writes ? `${g.output}=${tmpOutput};` : ""}
|
|
52
57
|
}else{
|
|
53
58
|
${errorsVar}.push(${tmpIssues});
|
|
54
59
|
${abortedVar}.push(${optAborted});
|
|
55
60
|
}
|
|
56
61
|
}`;
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
const msgProp = g.typeMsg === void 0 ? "" : `,message:${JSON.stringify(g.typeMsg)}`;
|
|
59
65
|
const fz = emitRuntimeHelper(g.ctx, "__zcFz", ZC_FZ_DECL);
|
|
@@ -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 { 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 // zod prunes with `util.aborted`, i.e. `continue !== true` on ANY issue — a\n // superset of the code test below, and the only thing that catches a tuple's\n // length issue (schema-created, same code a continuable check uses). See\n // `abortsProp` in emit-issue.ts.\n const oiIssue = g.temp(\"uoq\");\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 ${oiIssue}=${errorsVar}[${oiVar}][${ojVar}];\n if(${oiIssue}.continue===false){${abVar}=true;break;}\n var ${ocVar}=${oiIssue}.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},input:${g.input},path:${unionPath}${msgProp}});\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 //\n // That \"unobservable\" holds for the VERDICT this expression reports, which is\n // all a nested conjunct or a `.is()` guard consumes. It does NOT hold for the\n // by-reference shortcut a root schema takes on a passing check, where WHICH\n // option zod picked decides the output value — see `fastResultIsInput`, which\n // withholds that shortcut rather than costing every union its fast check.\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 const tmpOutput = g.temp(\"uo\");\n\n if (needsOutputIsolation) {\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 // An option that rewrites nothing still writes its output — a loose object\n // hands back its input, or a copy an own `__proto__` was scrubbed from —\n // and zod's result is the output of the option that SUCCEEDED. Written\n // straight to the union's output, a failed option's copy stayed there\n // whenever the option that did succeed wrote nothing (`z.any()`), so an\n // option that names its output gets a local of its own, taken only on\n // success. Its input stays the union's: an option that rewrites nothing\n // does not need its input and output to be one expression (see\n // visitMember).\n const optionCode = g.visit(option, {\n issues: tmpIssues,\n output: tmpOutput,\n path: \"[]\",\n aborted: optAborted,\n });\n const writes = optionCode.includes(tmpOutput);\n code += emit`\n if(!${resultVar}){\n var ${tmpIssues}=[];\n var ${optAborted}=false;\n ${writes ? `var ${tmpOutput}=${g.input};` : \"\"}\n ${optionCode}\n if(${tmpIssues}.length===0){\n ${resultVar}=true;\n ${writes ? `${g.output}=${tmpOutput};` : \"\"}\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 // zod prunes with `util.aborted`, i.e. `continue !== true` on ANY issue — a\n // superset of the code test below, and the only thing that catches a tuple's\n // length issue (schema-created, same code a continuable check uses). See\n // `abortsProp` in emit-issue.ts.\n const oiIssue = g.temp(\"uoq\");\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 ${oiIssue}=${errorsVar}[${oiVar}][${ojVar}];\n if(${oiIssue}.continue===false){${abVar}=true;break;}\n var ${ocVar}=${oiIssue}.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},input:${g.input},path:${unionPath}${msgProp}});\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 //\n // That \"unobservable\" holds for the VERDICT this expression reports, which is\n // all a nested conjunct or a `.is()` guard consumes. It does NOT hold for the\n // by-reference shortcut a root schema takes on a passing check, where WHICH\n // option zod picked decides the output value — see `fastResultIsInput`, which\n // withholds that shortcut rather than costing every union its fast check.\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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"}
|