ownEffects
What one definition's own code (its stored IR) reaches outside the codebase, not counting what it uses: from
Node's modules it imports, the globals it reads (fetch, process.env, Date.now(), new Date(),
Math.random()), and which of their members. What's only named in types (b: Buffer, typeof process in a type, a
type imported from node:fs) is erased, so it reaches nothing. What npm packages do inside isn't seen.
import { EFFECT_EXPORTS, EFFECT_GLOBALS, EFFECT_MEMBERS, EFFECT_MODULES, QUIET_PROCESS, } from "#codebase/tcmts/core/effects"; import type { Effect } from "#codebase/tcmts/core/effects"; import type { IR } from "#codebase/tcmts/core/hash"; import { isErased } from "#codebase/tcmts/core/ir"; export function ownEffects(ir: unknown): Effect[] { const found = new Set<Effect>(); const child = (node: unknown[], key: string): unknown => (node.find((c) => Array.isArray(c) && c[0] === key) as unknown[] | undefined)?.[1]; const isRef = (n: unknown, tag: string): n is unknown[] => Array.isArray(n) && n[0] === tag; /** `G` → its name; `Ext` → `module`, or `module#export` for a named import */ const named = (n: unknown): string | undefined => isRef(n, "G") ? String(n[1]) : isRef(n, "Ext") ? n[3] === "default" || n[3] === "*" ? String(n[1]) : undefined : undefined; const visit = (node: unknown, member?: boolean) => { if (!Array.isArray(node) || isErased(node as IR)) return; const tag = node[0]; if (tag === "Ext") { const mod = String(node[1]); const e = EFFECT_MODULES[mod] ?? EFFECT_EXPORTS[`${mod}#${String(node[3])}`]; if (e) found.add(e); return; } if (tag === "G") { const name = String(node[1]); const e = EFFECT_GLOBALS[name]; if (e) found.add(e); // `process` itself, passed around or destructured, could be read for anything else if (name === "process" && !member) found.add("environment"); return; } if (tag === "PropertyAccessExpression") { const target = child(node, "expression"); const name = child(node, "name"); const owner = named(target); if (owner && isRef(name, "N")) { const key = `${owner}.${String(name[1])}`; const e = EFFECT_MEMBERS[key]; if (e) found.add(e); else if (owner === "process" && !QUIET_PROCESS.has(String(name[1]))) found.add("environment"); visit(target, true); return; } } // `new Date()` and `Date()`: now if ( (tag === "NewExpression" || tag === "CallExpression") && isRef(child(node, "expression"), "G") ) { const callee = child(node, "expression") as unknown[]; const args = child(node, "arguments"); if ( callee[1] === "Date" && (tag === "CallExpression" || !Array.isArray(args) || args.length <= 1) ) found.add("clock"); } for (const c of node) visit(c); }; visit(typeof ir === "string" ? JSON.parse(ir) : ir); return [...found].sort(); }
uses
- tcmts.core.effects.EFFECT_EXPORTS
- tcmts.core.effects.EFFECT_GLOBALS
- tcmts.core.effects.EFFECT_MEMBERS
- tcmts.core.effects.EFFECT_MODULES
- tcmts.core.effects.Effect
- tcmts.core.effects.QUIET_PROCESS
- tcmts.core.hash.IR
- tcmts.core.ir.isErased