quietLoad
uses tcmts.cli.npm.isPureExport, which uses tcmts.cli.npm.npmFacts, which uses node:path
Whether loading a computed constant does nothing anyone could see but make its value; if so, the state computing
it could change: by hash, what holds state (an object, an array, a let, a class, a computed value) among the
definitions its computation uses, through what they use, and any it assigns to. Its computation is its
initializer less what it only holds: a function or a definition written into its value (run: (a) => … in an
object in an array), not passed to anything, isn't called or used by loading it. Loading it does something
(undefined) if that code reaches outside (reaches: the clock, files, the network, the environment, output),
uses an npm package not known to be pure, uses a global other than JavaScript's own (QUIET_GLOBALS: not
globalThis, process or timers), assigns to one or a built-in's prototype, imports a module, or waits; and, to
be sure, if it isn't a const of one name alone in its component.
import type { CodebaseCore } from "#codebase/tcmts/cli/codebase"; import { reaches } from "#codebase/tcmts/cli/effects"; import { holdsState, usesPackages } from "#codebase/tcmts/cli/kept"; import { isPureExport, parseExtRef } from "#codebase/tcmts/cli/npm"; import { QUIET_GLOBALS, quietLoads } from "#codebase/tcmts/cli/suites"; import { ownEffects } from "#codebase/tcmts/core/effects"; import { declarationOf, defParts, initializerOf } from "#codebase/tcmts/core/ir"; import type { DefRecord } from "#codebase/tcmts/core/types"; export function quietLoad(cb: CodebaseCore, rec: DefRecord): string[] | undefined { const known = quietLoads.get(rec.hash); if (known !== undefined) return known ?? undefined; const isKey = (c: unknown, key: string) => Array.isArray(c) && c[0] === key; const child = (n: unknown[], key: string) => (n.find((c) => isKey(c, key)) as unknown[] | undefined)?.[1]; // what code changes: the definition (by hash) or global (by name) an assignment's target belongs to const owner = (n: unknown): unknown => { while ( Array.isArray(n) && /^(PropertyAccessExpression|ElementAccessExpression|ParenthesizedExpression|NonNullExpression)$/.test( String(n[0]), ) ) n = child(n, "expression"); return n; }; const decide = (): string[] | undefined => { const { tag, body } = defParts(rec.ir); const decl = declarationOf(rec.ir); if ( rec.kind !== "term" || rec.componentSize !== 1 || rec.initKind !== "strict" || tag !== "Const" || body.length !== 1 || decl?.[0] !== "VariableDeclaration" || !/^(Cyc|Named)$/.test(String((child(decl, "name") as unknown[] | undefined)?.[0])) ) return undefined; const init = initializerOf(rec.ir); if ( !Array.isArray(init) || /^(ArrowFunction|FunctionExpression|ClassExpression)$/.test(String(init[0])) ) return undefined; const uses = new Set<string>(); const exts = new Set<string>(); const state = new Set<string>(); let loud = false; // code as loading runs it; `held`: every node above this one only holds what's under it (an object, an array, // a property's value, parentheses), so a function or definition here is only kept in the value const visit = (n: unknown, held: boolean): unknown => { if (!Array.isArray(n)) return n; const tag = String(n[0]); // (a node's child, by its key: types do nothing) if (/^[a-z]/.test(tag)) return /^type(Arguments|Parameters)?$/.test(tag) ? null : [tag, ...n.slice(1).map((c) => visit(c, held))]; if ( held && /^(ArrowFunction|FunctionExpression|MethodDeclaration|GetAccessor|SetAccessor)$/.test(tag) ) // (a method's computed name is worked out, though) return [ tag, ...n .slice(1) .filter((c) => isKey(c, "name")) .map((c) => visit(c, false)), ]; if (held && tag === "Ref") return null; if (tag === "Ref") uses.add(String(n[1])); else if (tag === "Ext") exts.add(`${String(n[1])}${n[2] ? `/${String(n[2])}` : ""}#${String(n[3])}`); else if (tag === "G" && !QUIET_GLOBALS.has(String(n[1]))) loud = true; else if (/^(ImportKeyword|AwaitExpression|YieldExpression)$/.test(tag)) loud = true; else if ( tag === "PropertyAccessExpression" && isKey(child(n, "expression"), "G") && JSON.stringify(child(n, "name")) === '["N","prototype"]' ) loud = true; const target = tag === "BinaryExpression" && /^(?!EqualsEquals|ExclamationEquals|LessThanEquals|GreaterThanEquals)\w*EqualsToken$/.test( String((child(n, "operatorToken") as unknown[] | undefined)?.[0]), ) ? child(n, "left") : /^(Prefix|Postfix)UnaryExpression$/.test(tag) && /^(\+\+|--)$/.test(String(n[1])) ? child(n, "operand") : tag === "DeleteExpression" ? child(n, "expression") : undefined; if (target !== undefined) { const o = owner(target); if (isKey(o, "G")) loud = true; else if (isKey(o, "Ref")) state.add(String((o as unknown[])[1])); } const holds = held && /^(ObjectLiteralExpression|ArrayLiteralExpression|PropertyAssignment|ShorthandPropertyAssignment|ParenthesizedExpression|AsExpression|SatisfiesExpression|NonNullExpression|\[)$/.test( tag, ); return [ tag, ...n .slice(1) .map((c) => visit(c, holds && !(tag === "PropertyAssignment" && isKey(c, "name")))), ]; }; const run = visit(init, true); if (loud || ownEffects(run).length) return undefined; const pure = (ref: string) => { const e = parseExtRef(ref); return !!e && isPureExport(cb.lay.cacheDir, e); }; if ([...exts].some((e) => !e.startsWith("node:") && !pure(e))) return undefined; const values = new Set(rec.deps.filter((d) => d.pos === "value").map((d) => d.ref.slice(1))); const used = [...uses].filter((h) => values.has(h)); const src = cb.source(); for (const effects of reaches(cb, used, src).values()) if (effects.length) return undefined; // what it uses runs (a function it calls) or is read (a value), and what that uses: whatever holds state const seen = new Set<string>(); for (const queue = [...used]; queue.length;) { const h = queue.pop()!; if (seen.has(h)) continue; seen.add(h); const d = src.get(h); if (!d) return undefined; if (d.kind === "type") continue; if (usesPackages(src, d.componentHash, pure)) return undefined; const holds = holdsState(d); if (holds === "state" || holds === "maybe") state.add(h); visit(JSON.parse(d.ir), false); if (loud) return undefined; for (const dep of d.deps) if (dep.pos === "value" && dep.ref.startsWith("#")) queue.push(dep.ref.slice(1)); } state.delete(rec.hash); return [...state].sort(); }; const r = decide(); quietLoads.set(rec.hash, r ?? null); return r; }
uses
- tcmts.cli.codebase.CodebaseCore
- tcmts.cli.effects.reaches
- tcmts.cli.kept.holdsState
- tcmts.cli.kept.usesPackages
- tcmts.cli.npm.isPureExport
- tcmts.cli.npm.parseExtRef
- tcmts.cli.suites.QUIET_GLOBALS
- tcmts.cli.suites.quietLoads
- tcmts.core.effects.ownEffects
- tcmts.core.ir.declarationOf
- tcmts.core.ir.defParts
- tcmts.core.ir.initializerOf
- tcmts.core.types.DefRecord