writtenOutRefs
The definitions code only writes out as source text, never running them: ${f} in a template, f.toString(),
String(f). A function whose source goes into a file something else runs (a generated runtime, a script run with
node -e) runs there, not in the code writing it out, so what it needs (the DOM, Node, the clock) isn't that
code's. A definition the code also uses any other way (calls it, passes it along) isn't one.
import type { IR } from "#codebase/tcmts/core/hash"; import { childOf } from "#codebase/tcmts/core/ir"; export function writtenOutRefs(ir: string | IR): Set<string> { const written = new Set<string>(); const used = new Set<string>(); const isRef = (n: IR | undefined): n is [string, string] => Array.isArray(n) && n[0] === "Ref" && typeof n[1] === "string"; /** the reference `node` writes out as text, if it's one of those forms */ const writes = (node: IR[]): IR | undefined => { if (node[0] === "TemplateSpan") return childOf(node, "expression"); if (node[0] !== "CallExpression") return undefined; const callee = childOf(node, "expression"); const args = childOf(node, "arguments"); const list = Array.isArray(args) ? args.slice(1) : []; if (Array.isArray(callee) && callee[0] === "G" && callee[1] === "String" && list.length === 1) return list[0]; if (Array.isArray(callee) && callee[0] === "PropertyAccessExpression" && !list.length) { const name = childOf(callee, "name"); if (Array.isArray(name) && name[0] === "N" && name[1] === "toString") return childOf(callee, "expression"); } return undefined; }; const visit = (node: IR) => { if (!Array.isArray(node)) return; if (isRef(node)) { used.add(node[1]); return; } const w = writes(node); // (a template's other part is its text: nothing else of these forms holds code) if (isRef(w)) { written.add(w[1]); return; } for (const c of node) visit(c); }; visit(typeof ir === "string" ? (JSON.parse(ir) as IR) : ir); return new Set([...written].filter((h) => !used.has(h))); }