@llui/compiler 0.5.1 → 0.5.2
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/collect-deps.d.ts +5 -1
- package/dist/collect-deps.d.ts.map +1 -1
- package/dist/collect-deps.js +93 -14
- package/dist/collect-deps.js.map +1 -1
- package/dist/cross-file-walker.d.ts +4 -1
- package/dist/cross-file-walker.d.ts.map +1 -1
- package/dist/cross-file-walker.js +72 -9
- package/dist/cross-file-walker.js.map +1 -1
- package/dist/lint-modules.d.ts.map +1 -1
- package/dist/lint-modules.js +2 -0
- package/dist/lint-modules.js.map +1 -1
- package/dist/modules/bitmask-overflow.js +1 -1
- package/dist/modules/bitmask-overflow.js.map +1 -1
- package/dist/modules/core-synthesis.d.ts +7 -0
- package/dist/modules/core-synthesis.d.ts.map +1 -1
- package/dist/modules/core-synthesis.js +24 -12
- package/dist/modules/core-synthesis.js.map +1 -1
- package/dist/modules/opaque-state-flow.d.ts +3 -0
- package/dist/modules/opaque-state-flow.d.ts.map +1 -0
- package/dist/modules/opaque-state-flow.js +208 -0
- package/dist/modules/opaque-state-flow.js.map +1 -0
- package/dist/transform.d.ts +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +75 -5
- package/dist/transform.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cross-file-walker.js","sourceRoot":"","sources":["../src/cross-file-walker.ts"],"names":[],"mappings":"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","sourcesContent":["// Cross-file walker — v2b prototype (Phase 1).\n//\n// Classifies every call expression in a TypeScript Program against the\n// §2.1 view-helper resolution rule. Returns diagnostics + a per-callsite\n// classification trace.\n//\n// This is *prototype-grade*: no manifest consumption, no incremental cache,\n// no reverse-deps tracking. Phase 3 adds those layers on top.\n//\n// The rule (§2.1):\n// A call is a view-helper iff at least one of:\n// case 1 — the callee accepts a parameter assignable to View<S,M> or\n// one of the documented structural subsets (send-only,\n// text-only, send+text, send+show+each+branch).\n// case 2 — the callee's *declared* return type is assignable to\n// Node, Node[], Node|undefined, or ReadonlyArray<Node>.\n// case 3 — the callee has a `/** @llui-helper */` JSDoc tag.\n//\n// Async helpers (declared return Promise<Node[]>) are NOT view-helpers\n// and produce `llui/async-view-helper` (hard error).\n//\n// Everything else: opaque. Emits `llui/opaque-view-call` if the call site\n// is structurally a view position (its result flows into a view-returning\n// expression); otherwise the call is uninteresting and not reported.\n\nimport ts from 'typescript'\nimport {\n type Diagnostic,\n type DiagnosticCategory,\n type DiagnosticSeverity,\n rangeFromOffsets,\n relativizeFile,\n} from './diagnostic.js'\nimport { isReactiveAccessor } from './collect-deps.js'\n\nexport type ViewHelperKind = 'walked' | 'opaque' | 'async' | 'not-a-helper'\n\nexport interface ViewHelperClassification {\n kind: ViewHelperKind\n /** Which §2.1 case fired. Only populated when kind === 'walked'. */\n cases: Array<1 | 2 | 3>\n /** Human-readable reason. */\n reason: string\n}\n\nexport type DiagnosticId = 'llui/opaque-view-call' | 'llui/async-view-helper' | 'llui/helper-cycle'\n\nexport interface WalkerDiagnostic {\n id: DiagnosticId\n file: string\n pos: number\n end: number\n message: string\n helperName: string | undefined\n}\n\nexport interface WalkerResult {\n diagnostics: WalkerDiagnostic[]\n /** Per-file counts for telemetry. */\n perFile: Map<\n string,\n {\n callsClassified: number\n walked: number\n opaque: number\n async: number\n notAHelper: number\n }\n >\n}\n\n/**\n * Classify the symbol's declaration against the §2.1 rule.\n *\n * Operates on the *declared* type (`getTypeOfSymbolAtLocation(symbol,\n * symbol.declarations[0])`), not the inferred-at-call-site type. This is\n * load-bearing: TypeScript inference at call sites widens to union\n * shapes (`Node[] | undefined`, `JSX.Element | string`) that miss\n * assignability for case 2. The rule's intent is \"did the author commit\n * to a view-helper signature in the declaration\" — inference-narrowed\n * types don't satisfy that intent.\n */\nexport function classifyViewHelper(\n symbol: ts.Symbol,\n checker: ts.TypeChecker,\n): ViewHelperClassification {\n const decls = symbol.getDeclarations() ?? []\n const decl = decls.find(isCallableDeclaration)\n if (!decl) return { kind: 'not-a-helper', cases: [], reason: 'no callable declaration found' }\n\n const cases: Array<1 | 2 | 3> = []\n const reasons: string[] = []\n\n // Case 3: @llui-helper JSDoc tag. Cheap to check, decisive when present.\n if (hasLluiHelperTag(decl)) {\n cases.push(3)\n reasons.push('@llui-helper tag')\n }\n\n // Get the signature's parameters + return type from the *declaration*.\n const declType = checker.getTypeOfSymbolAtLocation(symbol, decl)\n const sigs = declType.getCallSignatures()\n if (sigs.length === 0) {\n if (cases.includes(3)) {\n return { kind: 'walked', cases, reason: reasons.join('; ') }\n }\n return { kind: 'not-a-helper', cases: [], reason: 'declared type has no call signature' }\n }\n // Use the first signature. Overloaded helpers are rare in view code;\n // production walker should iterate all.\n const sig = sigs[0]!\n\n // Case 2: declared return type assignable to Node / Node[] / etc.\n const returnType = checker.getReturnTypeOfSignature(sig)\n const asyncMatch = returnTypeIsAsyncNode(returnType, checker)\n if (asyncMatch) {\n return { kind: 'async', cases: [], reason: 'declared return is Promise<Node[] | Node>' }\n }\n if (returnTypeIsNodeShape(returnType, checker)) {\n cases.push(2)\n reasons.push('declared return is Node[]-like')\n }\n\n // Case 1: at least one parameter assignable to View<S,M> or a documented\n // structural subset. Match on the declared parameter type's shape — we\n // use property-name plus per-property callability as a structural\n // signature. The 5 documented subsets are listed below.\n for (const param of sig.getParameters()) {\n const paramDecl = param.getDeclarations()?.[0]\n if (!paramDecl) continue\n const paramType = checker.getTypeOfSymbolAtLocation(param, paramDecl)\n const subset = matchViewSubset(paramType, checker)\n if (subset) {\n cases.push(1)\n reasons.push(`accepts View subset (${subset})`)\n break\n }\n }\n\n if (cases.length === 0) {\n return { kind: 'opaque', cases: [], reason: 'no §2.1 case matched' }\n }\n return { kind: 'walked', cases, reason: reasons.join('; ') }\n}\n\n/**\n * The 5 documented View subsets, enumerated. New subsets require a doc\n * revision and a fixture per §2.1.\n *\n * Returns the subset's identifier when matched, undefined otherwise.\n * Matching is by *property presence* — we check that the parameter type\n * exposes the required property names, each with a callable type. We\n * intentionally do NOT call `isTypeAssignableTo` against a synthetic\n * subset type, because TypeScript's structural assignability would\n * accept arbitrary supersets and lose the \"documented subset\" guarantee.\n */\nfunction matchViewSubset(t: ts.Type, _checker: ts.TypeChecker): string | undefined {\n if (!isObjectLike(t)) return undefined\n const props = t.getProperties().map((p) => p.getName())\n const has = (name: string): boolean => props.includes(name)\n\n // Full View<S,M> bag — must expose at least send + show + each + branch.\n // Real-world callers spread or destructure; the type they pass is the\n // full View<S,M> regardless of how much they use.\n if (has('send') && has('show') && has('each') && has('branch') && has('text')) {\n return 'View<S, M>'\n }\n // send + show + each + branch (no text)\n if (has('send') && has('show') && has('each') && has('branch') && !has('text')) {\n return '{ send, show, each, branch }'\n }\n // send + text\n if (has('send') && has('text') && !has('show') && !has('each')) {\n return '{ send, text }'\n }\n // send only\n if (has('send') && !has('text') && !has('show') && !has('each')) {\n return '{ send }'\n }\n // text only\n if (has('text') && !has('send') && !has('show') && !has('each')) {\n return '{ text }'\n }\n\n return undefined\n}\n\nfunction isObjectLike(t: ts.Type): boolean {\n return (t.getFlags() & ts.TypeFlags.Object) !== 0\n}\n\n/**\n * Returns true if `t` is assignable to one of: `Node`, `Node[]`,\n * `Node | undefined`, `ReadonlyArray<Node>`.\n *\n * Uses the type checker's structural matching against a synthesized\n * `Node`-like — we look up the global `Node` symbol from the lib.dom\n * declarations.\n */\nfunction returnTypeIsNodeShape(t: ts.Type, checker: ts.TypeChecker): boolean {\n // Strip undefined from a union for the \"Node | undefined\" case.\n const nonUndefined = stripUndefined(t)\n\n // Array / ReadonlyArray case: element type is Node-like.\n // TypeScript represents both as a `TypeReference` whose target is the\n // global Array / ReadonlyArray and whose first type-arg is the element.\n if (isArrayOrReadonlyArray(nonUndefined)) {\n const elem = getFirstTypeArg(nonUndefined)\n if (elem && isNodeLike(elem, checker)) return true\n }\n // Singular Node return: `function (...): Node`.\n if (isNodeLike(nonUndefined, checker)) return true\n // Union: any member is Node-shaped.\n if (nonUndefined.isUnion()) {\n for (const u of nonUndefined.types) {\n if (returnTypeIsNodeShape(u, checker)) return true\n }\n }\n return false\n}\n\nfunction returnTypeIsAsyncNode(t: ts.Type, checker: ts.TypeChecker): boolean {\n // Promise<X> where X is Node-shaped.\n const sym = t.getSymbol()\n if (!sym || sym.getName() !== 'Promise') return false\n const args = (t as ts.TypeReference).typeArguments\n if (!args || args.length === 0) return false\n return returnTypeIsNodeShape(args[0]!, checker)\n}\n\nfunction stripUndefined(t: ts.Type): ts.Type {\n if (!t.isUnion()) return t\n const nonUndef = t.types.filter(\n (u) => (u.getFlags() & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) === 0,\n )\n if (nonUndef.length === t.types.length) return t\n if (nonUndef.length === 1) return nonUndef[0]!\n return t\n}\n\nfunction isArrayOrReadonlyArray(t: ts.Type): boolean {\n const sym = t.getSymbol()\n if (!sym) return false\n const name = sym.getName()\n return name === 'ReadonlyArray' || name === 'Array'\n}\n\nfunction getFirstTypeArg(t: ts.Type): ts.Type | undefined {\n const args = (t as ts.TypeReference).typeArguments\n return args?.[0]\n}\n\nfunction isNodeLike(t: ts.Type, _checker: ts.TypeChecker): boolean {\n const sym = t.getSymbol()\n if (!sym) return false\n const name = sym.getName()\n // Built-in DOM Node base types — return true on the abstract names.\n if (\n name === 'Node' ||\n name === 'Element' ||\n name === 'HTMLElement' ||\n name === 'Text' ||\n name === 'Comment' ||\n name === 'DocumentFragment' ||\n name === 'ChildNode'\n ) {\n return true\n }\n // The concrete `HTMLDivElement` / `SVGCircleElement` / `MathMLMathElement`\n // names that `HTMLElementTagNameMap[K]` resolves to. Element helpers\n // (`div(...)`, `button(...)`) all hit this branch — without it they\n // would be misclassified as opaque and flood the diagnostic stream.\n return (\n /^HTML[A-Z]\\w*Element$/.test(name) ||\n /^SVG[A-Z]\\w*Element$/.test(name) ||\n /^MathML[A-Z]\\w*Element$/.test(name)\n )\n}\n\nfunction hasLluiHelperTag(decl: ts.Declaration): boolean {\n const jsDocs = ts.getJSDocTags(decl)\n for (const tag of jsDocs) {\n if (tag.tagName.text === 'llui-helper') return true\n }\n return false\n}\n\nfunction isCallableDeclaration(d: ts.Declaration): boolean {\n return (\n ts.isFunctionDeclaration(d) ||\n ts.isFunctionExpression(d) ||\n ts.isArrowFunction(d) ||\n ts.isMethodDeclaration(d) ||\n ts.isVariableDeclaration(d)\n )\n}\n\n/**\n * Whether the call site is structurally in a view position. A view\n * position is one where the result flows into:\n * - the return of a `view()` callback,\n * - a `Node[]` literal element being built by a structural primitive\n * (`each.render`, `show.render`, `branch.cases.X`, `scope.render`),\n * - the children array of an element-helper call.\n *\n * Approximation for the prototype: the call is inside a function whose\n * return type (declared OR inferred from the surrounding context) is\n * Node-shaped. Less precise than tracking JSX-style returns, but\n * sufficient to gate the diagnostic emission for the validation run.\n */\nfunction isViewPositionCall(call: ts.CallExpression, checker: ts.TypeChecker): boolean {\n // Walk up: an enclosing function declaration / arrow whose return is\n // Node-shaped. Stop at the source file.\n let cur: ts.Node | undefined = call.parent\n while (cur) {\n if (\n ts.isFunctionDeclaration(cur) ||\n ts.isFunctionExpression(cur) ||\n ts.isArrowFunction(cur) ||\n ts.isMethodDeclaration(cur)\n ) {\n const sig = checker.getSignatureFromDeclaration(cur)\n if (sig) {\n const ret = checker.getReturnTypeOfSignature(sig)\n if (returnTypeIsNodeShape(ret, checker)) return true\n }\n return false\n }\n cur = cur.parent\n }\n return false\n}\n\n/**\n * Walk a Program looking for call expressions that should be classified\n * by the §2.1 rule. Restricts the walk to files matching `filter` so\n * tests can scope to a subdirectory.\n */\nexport function walkProgram(\n program: ts.Program,\n options: { filter?: (sourceFile: ts.SourceFile) => boolean } = {},\n): WalkerResult {\n const checker = program.getTypeChecker()\n const filter = options.filter ?? (() => true)\n const diagnostics: WalkerDiagnostic[] = []\n const perFile = new Map<\n string,\n WalkerResult['perFile'] extends Map<string, infer V> ? V : never\n >()\n\n for (const sf of program.getSourceFiles()) {\n if (sf.isDeclarationFile) continue\n if (!filter(sf)) continue\n const counts = { callsClassified: 0, walked: 0, opaque: 0, async: 0, notAHelper: 0 }\n perFile.set(sf.fileName, counts)\n\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node)) {\n // Resolve the symbol of the callee.\n const callee = node.expression\n let symbol = checker.getSymbolAtLocation(callee)\n if (symbol && symbol.flags & ts.SymbolFlags.Alias) {\n symbol = checker.getAliasedSymbol(symbol)\n }\n if (symbol && !(symbol.flags & ts.SymbolFlags.Transient)) {\n const cls = classifyViewHelper(symbol, checker)\n counts.callsClassified++\n if (cls.kind === 'walked') counts.walked++\n else if (cls.kind === 'opaque') counts.opaque++\n else if (cls.kind === 'async') counts.async++\n else counts.notAHelper++\n\n if (cls.kind === 'opaque' && isViewPositionCall(node, checker)) {\n diagnostics.push({\n id: 'llui/opaque-view-call',\n file: sf.fileName,\n pos: node.getStart(sf),\n end: node.getEnd(),\n helperName: getCalleeName(callee),\n message: `Call to \"${getCalleeName(callee) ?? '<unknown>'}\" in a view position is opaque to the cross-file walker (${cls.reason}). Either add an explicit return-type annotation (Node[] / Node / ReadonlyArray<Node>), accept a View bag parameter (or a documented subset), or mark with /** @llui-helper */ if the helper genuinely cannot be annotated. As a last resort, use track({ deps: ... }) at the call site.`,\n })\n } else if (cls.kind === 'async' && isViewPositionCall(node, checker)) {\n diagnostics.push({\n id: 'llui/async-view-helper',\n file: sf.fileName,\n pos: node.getStart(sf),\n end: node.getEnd(),\n helperName: getCalleeName(callee),\n message: `Call to \"${getCalleeName(callee) ?? '<unknown>'}\" in a view position returns Promise<Node[] | Node>. LLui's view layer is synchronous — wrap async work in onMount() or use clientOnly() instead.`,\n })\n }\n }\n }\n ts.forEachChild(node, visit)\n }\n visit(sf)\n }\n\n return { diagnostics, perFile }\n}\n\nfunction getCalleeName(expr: ts.Expression): string | undefined {\n if (ts.isIdentifier(expr)) return expr.text\n if (ts.isPropertyAccessExpression(expr)) return expr.name.text\n return undefined\n}\n\n// ── Diagnostic schema integration (v2c §3) ──────────────────────────\n//\n// The walker emits a lightweight `WalkerDiagnostic` (with raw byte\n// offsets) for internal accumulation. Adapters and the host pipeline\n// want the canonical `Diagnostic` shape with project-relative paths\n// and line/column ranges. This converter resolves the position pair to\n// a Range and relativizes the file path; the caller supplies the\n// project root.\n\nconst WALKER_DIAGNOSTIC_META: Record<\n DiagnosticId,\n {\n severity: DiagnosticSeverity\n category: DiagnosticCategory\n documentation?: string\n }\n> = {\n 'llui/opaque-view-call': {\n severity: 'warning',\n category: 'reactivity',\n documentation:\n 'https://github.com/fponticelli/llui/blob/main/docs/proposals/v2-compiler/v2b.md#21-view-helper-resolution-rule',\n },\n 'llui/async-view-helper': {\n severity: 'error',\n category: 'composition',\n documentation:\n 'https://github.com/fponticelli/llui/blob/main/docs/proposals/v2-compiler/v2b.md#21-view-helper-resolution-rule',\n },\n 'llui/helper-cycle': {\n severity: 'warning',\n category: 'composition',\n documentation:\n 'https://github.com/fponticelli/llui/blob/main/docs/proposals/v2-compiler/v2b.md#23-recursion-and-cycles',\n },\n}\n\n/**\n * Convert a walker-internal diagnostic to the canonical `Diagnostic`\n * shape. Reads the source text (for line/column resolution) and a\n * project root (for path relativization).\n */\nexport function toCanonicalDiagnostic(\n d: WalkerDiagnostic,\n sourceText: string,\n projectRoot: string,\n): Diagnostic {\n const meta = WALKER_DIAGNOSTIC_META[d.id]\n return {\n id: d.id,\n severity: meta.severity,\n category: meta.category,\n message: d.message,\n location: {\n file: relativizeFile(d.file, projectRoot),\n range: rangeFromOffsets(sourceText, d.pos, d.end),\n },\n ...(meta.documentation ? { documentation: meta.documentation } : {}),\n }\n}\n\n// ── Cross-file accessor path collection ─────────────────────────────\n//\n// Given a focal source file inside a Program, walk every reactive-accessor\n// arrow in the file. For each accessor:\n// - Collect paths it reads directly (the existing AST-only collector\n// handles this — see `collect-deps.ts`).\n// - For every call site inside the accessor whose callee resolves to a\n// view-helper (per §2.1), descend into the callee and merge its reads.\n//\n// This is the cross-file extension of `collectStatePathsFromSource`. The\n// AST-only collector terminates at the file boundary; the cross-file\n// version follows view-helper calls into other files using the TypeChecker.\n//\n// Used by the focal file's compiler to compute its __prefixes table. The\n// production wiring (Vite adapter builds a Program; compileFile consumes\n// it) is v2c module work — for v2b this is exposed as a callable engine\n// API that downstream tools can drive.\n\n/**\n * Collect the cross-file union of accessor paths read from a focal file.\n * Returns the union over every reactive accessor in `focalFile`, with\n * cross-file view-helper descents merged in.\n *\n * Reactive-accessor entry is gated by `isReactiveAccessor` (the same\n * predicate the file-local `collect-deps` walker uses) *plus* a\n * cross-file extension: an arrow at the first-arg position of a call\n * to a §2.1 view-helper also counts as reactive, because that's the\n * lift the helper applies to our state.\n *\n * Without the gate, every 1-param arrow in the file gets walked —\n * including `onEffect: (bag) => bag.send(...)`, where `bag.send` ends\n * up in the path set as a phantom \"send\" prefix. Issue #5, bug 3.\n */\nexport function crossFileAccessorPaths(program: ts.Program, focalFile: ts.SourceFile): Set<string> {\n const checker = program.getTypeChecker()\n const paths = new Set<string>()\n const visitedHelpers = new Set<ts.Declaration>()\n\n const isViewHelperCallArg0 = (arrow: ts.ArrowFunction | ts.FunctionExpression): boolean => {\n const parent = arrow.parent\n if (!parent || !ts.isCallExpression(parent)) return false\n if (parent.arguments[0] !== arrow) return false\n const sym = resolveAliasedSymbol(parent.expression, checker)\n if (!sym) return false\n return classifyViewHelper(sym, checker).kind === 'walked'\n }\n\n const visit = (node: ts.Node): void => {\n if (\n (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&\n node.parameters.length === 1\n ) {\n const p0 = node.parameters[0]!\n if (ts.isIdentifier(p0.name) && node.body) {\n if (isReactiveAccessor(node) || isViewHelperCallArg0(node)) {\n walkAccessorBody(node.body, p0.name.text, paths, checker, visitedHelpers)\n }\n }\n }\n ts.forEachChild(node, visit)\n }\n visit(focalFile)\n return paths\n}\n\n// Helpers whose arrow args are NOT state accessors — same exclusion list\n// the file-local walker uses (collect-deps.ts § NON_DELEGATION_HELPERS).\n// `item` / `sample` read state imperatively or per-row; descending into\n// their bodies would attribute reads to the wrong scope. `memo` / `text` /\n// `unsafeHtml` already have their inline arrow walked by the top-level\n// visitor — we'd double-count if we recursed through the call again.\nconst NON_DELEGATION_CALLEES = new Set(['sample', 'item', 'memo', 'text', 'unsafeHtml'])\n\nfunction walkAccessorBody(\n body: ts.Node,\n paramName: string,\n paths: Set<string>,\n checker: ts.TypeChecker,\n visitedHelpers: Set<ts.Declaration>,\n): void {\n const visit = (node: ts.Node): void => {\n // Property-chain extraction (mirrors collect-deps' depth-2 normaliser).\n if (ts.isPropertyAccessExpression(node)) {\n const chain = resolveDepth2(node, paramName)\n if (chain) paths.add(chain)\n }\n\n if (ts.isCallExpression(node)) {\n const callee = node.expression\n const sym = resolveAliasedSymbol(callee, checker)\n if (sym) {\n const cls = classifyViewHelper(sym, checker)\n const decl = sym.getDeclarations()?.find(isFunctionLikeDecl)\n\n if (cls.kind === 'walked' && decl && !visitedHelpers.has(decl)) {\n // §2.1 view-helper: full descent (arrow-arg accessors lift\n // into our state, identifier args pass our state through).\n visitedHelpers.add(decl)\n descendIntoHelper(\n decl,\n node,\n paramName,\n paths,\n checker,\n visitedHelpers,\n /*viewHelper*/ true,\n )\n } else if (decl && !visitedHelpers.has(decl)) {\n // Non-view-helper: only follow if our state param is passed\n // through unchanged. A helper returning string / boolean /\n // anything-non-Node that reads `s.foo.bar` still contributes\n // those paths to our accessor's read set when called as\n // `helper(s)`. Without this, helpers like\n // `(s) => s.route.kind === 'a'` would have their reads\n // silently dropped, producing a stale-render bug rather than\n // a crash (issue #5, bug 3 false-negative).\n //\n // Skip framework primitives whose arrow args are visited\n // separately (see NON_DELEGATION_CALLEES) — descending would\n // double-count.\n if (\n ts.isIdentifier(callee) &&\n !NON_DELEGATION_CALLEES.has(callee.text) &&\n callPassesParamIdent(node, paramName)\n ) {\n visitedHelpers.add(decl)\n descendIntoHelper(\n decl,\n node,\n paramName,\n paths,\n checker,\n visitedHelpers,\n /*viewHelper*/ false,\n )\n }\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n visit(body)\n}\n\nfunction callPassesParamIdent(call: ts.CallExpression, paramName: string): boolean {\n for (const arg of call.arguments) {\n if (ts.isIdentifier(arg) && arg.text === paramName) return true\n }\n return false\n}\n\nfunction descendIntoHelper(\n decl: ts.Declaration,\n callSite: ts.CallExpression,\n outerParamName: string,\n paths: Set<string>,\n checker: ts.TypeChecker,\n visitedHelpers: Set<ts.Declaration>,\n viewHelper: boolean,\n): void {\n // Match each parameter to its argument at the call site.\n //\n // For §2.1 view-helpers: arrow-arg accessors like `(t) => t.foo` are\n // lifts that bind the helper's parameter to a slice of our state;\n // walk their bodies so the slice's reads chain into our path set.\n //\n // For non-view-helpers: we don't know what the helper does with its\n // arrow args — could be a filter callback over a per-item type, or a\n // mapper that doesn't touch state at all. Only the identifier-arg\n // branch (`helper(s)`) is unambiguous, so the non-view-helper case\n // is conservative and only takes that path.\n const fnDecl = decl as ts.FunctionLikeDeclaration\n if (!fnDecl.body) return\n const params = fnDecl.parameters\n for (let i = 0; i < params.length; i++) {\n const param = params[i]!\n const arg = callSite.arguments[i]\n if (!arg) continue\n if (!ts.isIdentifier(param.name)) continue\n if (viewHelper && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {\n const a0 = arg.parameters[0]\n if (a0 && ts.isIdentifier(a0.name) && arg.body) {\n walkAccessorBody(arg.body, a0.name.text, paths, checker, visitedHelpers)\n }\n } else if (ts.isIdentifier(arg) && arg.text === outerParamName) {\n walkAccessorBody(fnDecl.body, param.name.text, paths, checker, visitedHelpers)\n }\n }\n}\n\nfunction resolveAliasedSymbol(node: ts.Node, checker: ts.TypeChecker): ts.Symbol | undefined {\n let sym = checker.getSymbolAtLocation(node)\n if (!sym) return undefined\n if (sym.flags & ts.SymbolFlags.Alias) sym = checker.getAliasedSymbol(sym)\n if (sym.flags & ts.SymbolFlags.Transient) return undefined\n return sym\n}\n\nfunction resolveDepth2(node: ts.PropertyAccessExpression, paramName: string): string | null {\n const parts: string[] = []\n let current: ts.Expression = node\n while (ts.isPropertyAccessExpression(current)) {\n parts.unshift(current.name.text)\n current = current.expression\n }\n if (!ts.isIdentifier(current) || current.text !== paramName) return null\n if (parts.length === 0) return null\n return parts.slice(0, 2).join('.')\n}\n\nfunction isFunctionLikeDecl(d: ts.Declaration): boolean {\n return (\n ts.isFunctionDeclaration(d) ||\n ts.isFunctionExpression(d) ||\n ts.isArrowFunction(d) ||\n ts.isMethodDeclaration(d)\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cross-file-walker.js","sourceRoot":"","sources":["../src/cross-file-walker.ts"],"names":[],"mappings":"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","sourcesContent":["// Cross-file walker — v2b prototype (Phase 1).\n//\n// Classifies every call expression in a TypeScript Program against the\n// §2.1 view-helper resolution rule. Returns diagnostics + a per-callsite\n// classification trace.\n//\n// This is *prototype-grade*: no manifest consumption, no incremental cache,\n// no reverse-deps tracking. Phase 3 adds those layers on top.\n//\n// The rule (§2.1):\n// A call is a view-helper iff at least one of:\n// case 1 — the callee accepts a parameter assignable to View<S,M> or\n// one of the documented structural subsets (send-only,\n// text-only, send+text, send+show+each+branch).\n// case 2 — the callee's *declared* return type is assignable to\n// Node, Node[], Node|undefined, or ReadonlyArray<Node>.\n// case 3 — the callee has a `/** @llui-helper */` JSDoc tag.\n//\n// Async helpers (declared return Promise<Node[]>) are NOT view-helpers\n// and produce `llui/async-view-helper` (hard error).\n//\n// Everything else: opaque. Emits `llui/opaque-view-call` if the call site\n// is structurally a view position (its result flows into a view-returning\n// expression); otherwise the call is uninteresting and not reported.\n\nimport ts from 'typescript'\nimport {\n type Diagnostic,\n type DiagnosticCategory,\n type DiagnosticSeverity,\n rangeFromOffsets,\n relativizeFile,\n} from './diagnostic.js'\nimport { isReactiveAccessor } from './collect-deps.js'\n\nexport type ViewHelperKind = 'walked' | 'opaque' | 'async' | 'not-a-helper'\n\nexport interface ViewHelperClassification {\n kind: ViewHelperKind\n /** Which §2.1 case fired. Only populated when kind === 'walked'. */\n cases: Array<1 | 2 | 3>\n /** Human-readable reason. */\n reason: string\n}\n\nexport type DiagnosticId = 'llui/opaque-view-call' | 'llui/async-view-helper' | 'llui/helper-cycle'\n\nexport interface WalkerDiagnostic {\n id: DiagnosticId\n file: string\n pos: number\n end: number\n message: string\n helperName: string | undefined\n}\n\nexport interface WalkerResult {\n diagnostics: WalkerDiagnostic[]\n /** Per-file counts for telemetry. */\n perFile: Map<\n string,\n {\n callsClassified: number\n walked: number\n opaque: number\n async: number\n notAHelper: number\n }\n >\n}\n\n/**\n * Classify the symbol's declaration against the §2.1 rule.\n *\n * Operates on the *declared* type (`getTypeOfSymbolAtLocation(symbol,\n * symbol.declarations[0])`), not the inferred-at-call-site type. This is\n * load-bearing: TypeScript inference at call sites widens to union\n * shapes (`Node[] | undefined`, `JSX.Element | string`) that miss\n * assignability for case 2. The rule's intent is \"did the author commit\n * to a view-helper signature in the declaration\" — inference-narrowed\n * types don't satisfy that intent.\n */\nexport function classifyViewHelper(\n symbol: ts.Symbol,\n checker: ts.TypeChecker,\n): ViewHelperClassification {\n const decls = symbol.getDeclarations() ?? []\n const decl = decls.find(isCallableDeclaration)\n if (!decl) return { kind: 'not-a-helper', cases: [], reason: 'no callable declaration found' }\n\n const cases: Array<1 | 2 | 3> = []\n const reasons: string[] = []\n\n // Case 3: @llui-helper JSDoc tag. Cheap to check, decisive when present.\n if (hasLluiHelperTag(decl)) {\n cases.push(3)\n reasons.push('@llui-helper tag')\n }\n\n // Get the signature's parameters + return type from the *declaration*.\n const declType = checker.getTypeOfSymbolAtLocation(symbol, decl)\n const sigs = declType.getCallSignatures()\n if (sigs.length === 0) {\n if (cases.includes(3)) {\n return { kind: 'walked', cases, reason: reasons.join('; ') }\n }\n return { kind: 'not-a-helper', cases: [], reason: 'declared type has no call signature' }\n }\n // Use the first signature. Overloaded helpers are rare in view code;\n // production walker should iterate all.\n const sig = sigs[0]!\n\n // Case 2: declared return type assignable to Node / Node[] / etc.\n const returnType = checker.getReturnTypeOfSignature(sig)\n const asyncMatch = returnTypeIsAsyncNode(returnType, checker)\n if (asyncMatch) {\n return { kind: 'async', cases: [], reason: 'declared return is Promise<Node[] | Node>' }\n }\n if (returnTypeIsNodeShape(returnType, checker)) {\n cases.push(2)\n reasons.push('declared return is Node[]-like')\n }\n\n // Case 1: at least one parameter assignable to View<S,M> or a documented\n // structural subset. Match on the declared parameter type's shape — we\n // use property-name plus per-property callability as a structural\n // signature. The 5 documented subsets are listed below.\n for (const param of sig.getParameters()) {\n const paramDecl = param.getDeclarations()?.[0]\n if (!paramDecl) continue\n const paramType = checker.getTypeOfSymbolAtLocation(param, paramDecl)\n const subset = matchViewSubset(paramType, checker)\n if (subset) {\n cases.push(1)\n reasons.push(`accepts View subset (${subset})`)\n break\n }\n }\n\n if (cases.length === 0) {\n return { kind: 'opaque', cases: [], reason: 'no §2.1 case matched' }\n }\n return { kind: 'walked', cases, reason: reasons.join('; ') }\n}\n\n/**\n * The 5 documented View subsets, enumerated. New subsets require a doc\n * revision and a fixture per §2.1.\n *\n * Returns the subset's identifier when matched, undefined otherwise.\n * Matching is by *property presence* — we check that the parameter type\n * exposes the required property names, each with a callable type. We\n * intentionally do NOT call `isTypeAssignableTo` against a synthetic\n * subset type, because TypeScript's structural assignability would\n * accept arbitrary supersets and lose the \"documented subset\" guarantee.\n */\nfunction matchViewSubset(t: ts.Type, _checker: ts.TypeChecker): string | undefined {\n if (!isObjectLike(t)) return undefined\n const props = t.getProperties().map((p) => p.getName())\n const has = (name: string): boolean => props.includes(name)\n\n // Full View<S,M> bag — must expose at least send + show + each + branch.\n // Real-world callers spread or destructure; the type they pass is the\n // full View<S,M> regardless of how much they use.\n if (has('send') && has('show') && has('each') && has('branch') && has('text')) {\n return 'View<S, M>'\n }\n // send + show + each + branch (no text)\n if (has('send') && has('show') && has('each') && has('branch') && !has('text')) {\n return '{ send, show, each, branch }'\n }\n // send + text\n if (has('send') && has('text') && !has('show') && !has('each')) {\n return '{ send, text }'\n }\n // send only\n if (has('send') && !has('text') && !has('show') && !has('each')) {\n return '{ send }'\n }\n // text only\n if (has('text') && !has('send') && !has('show') && !has('each')) {\n return '{ text }'\n }\n\n return undefined\n}\n\nfunction isObjectLike(t: ts.Type): boolean {\n return (t.getFlags() & ts.TypeFlags.Object) !== 0\n}\n\n/**\n * Returns true if `t` is assignable to one of: `Node`, `Node[]`,\n * `Node | undefined`, `ReadonlyArray<Node>`.\n *\n * Uses the type checker's structural matching against a synthesized\n * `Node`-like — we look up the global `Node` symbol from the lib.dom\n * declarations.\n */\nfunction returnTypeIsNodeShape(t: ts.Type, checker: ts.TypeChecker): boolean {\n // Strip undefined from a union for the \"Node | undefined\" case.\n const nonUndefined = stripUndefined(t)\n\n // Array / ReadonlyArray case: element type is Node-like.\n // TypeScript represents both as a `TypeReference` whose target is the\n // global Array / ReadonlyArray and whose first type-arg is the element.\n if (isArrayOrReadonlyArray(nonUndefined)) {\n const elem = getFirstTypeArg(nonUndefined)\n if (elem && isNodeLike(elem, checker)) return true\n }\n // Singular Node return: `function (...): Node`.\n if (isNodeLike(nonUndefined, checker)) return true\n // Union: any member is Node-shaped.\n if (nonUndefined.isUnion()) {\n for (const u of nonUndefined.types) {\n if (returnTypeIsNodeShape(u, checker)) return true\n }\n }\n return false\n}\n\nfunction returnTypeIsAsyncNode(t: ts.Type, checker: ts.TypeChecker): boolean {\n // Promise<X> where X is Node-shaped.\n const sym = t.getSymbol()\n if (!sym || sym.getName() !== 'Promise') return false\n const args = (t as ts.TypeReference).typeArguments\n if (!args || args.length === 0) return false\n return returnTypeIsNodeShape(args[0]!, checker)\n}\n\nfunction stripUndefined(t: ts.Type): ts.Type {\n if (!t.isUnion()) return t\n const nonUndef = t.types.filter(\n (u) => (u.getFlags() & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) === 0,\n )\n if (nonUndef.length === t.types.length) return t\n if (nonUndef.length === 1) return nonUndef[0]!\n return t\n}\n\nfunction isArrayOrReadonlyArray(t: ts.Type): boolean {\n const sym = t.getSymbol()\n if (!sym) return false\n const name = sym.getName()\n return name === 'ReadonlyArray' || name === 'Array'\n}\n\nfunction getFirstTypeArg(t: ts.Type): ts.Type | undefined {\n const args = (t as ts.TypeReference).typeArguments\n return args?.[0]\n}\n\nfunction isNodeLike(t: ts.Type, _checker: ts.TypeChecker): boolean {\n const sym = t.getSymbol()\n if (!sym) return false\n const name = sym.getName()\n // Built-in DOM Node base types — return true on the abstract names.\n if (\n name === 'Node' ||\n name === 'Element' ||\n name === 'HTMLElement' ||\n name === 'Text' ||\n name === 'Comment' ||\n name === 'DocumentFragment' ||\n name === 'ChildNode'\n ) {\n return true\n }\n // The concrete `HTMLDivElement` / `SVGCircleElement` / `MathMLMathElement`\n // names that `HTMLElementTagNameMap[K]` resolves to. Element helpers\n // (`div(...)`, `button(...)`) all hit this branch — without it they\n // would be misclassified as opaque and flood the diagnostic stream.\n return (\n /^HTML[A-Z]\\w*Element$/.test(name) ||\n /^SVG[A-Z]\\w*Element$/.test(name) ||\n /^MathML[A-Z]\\w*Element$/.test(name)\n )\n}\n\nfunction hasLluiHelperTag(decl: ts.Declaration): boolean {\n const jsDocs = ts.getJSDocTags(decl)\n for (const tag of jsDocs) {\n if (tag.tagName.text === 'llui-helper') return true\n }\n return false\n}\n\nfunction isCallableDeclaration(d: ts.Declaration): boolean {\n return (\n ts.isFunctionDeclaration(d) ||\n ts.isFunctionExpression(d) ||\n ts.isArrowFunction(d) ||\n ts.isMethodDeclaration(d) ||\n ts.isVariableDeclaration(d)\n )\n}\n\n/**\n * Whether the call site is structurally in a view position. A view\n * position is one where the result flows into:\n * - the return of a `view()` callback,\n * - a `Node[]` literal element being built by a structural primitive\n * (`each.render`, `show.render`, `branch.cases.X`, `scope.render`),\n * - the children array of an element-helper call.\n *\n * Approximation for the prototype: the call is inside a function whose\n * return type (declared OR inferred from the surrounding context) is\n * Node-shaped. Less precise than tracking JSX-style returns, but\n * sufficient to gate the diagnostic emission for the validation run.\n */\nfunction isViewPositionCall(call: ts.CallExpression, checker: ts.TypeChecker): boolean {\n // Walk up: an enclosing function declaration / arrow whose return is\n // Node-shaped. Stop at the source file.\n let cur: ts.Node | undefined = call.parent\n while (cur) {\n if (\n ts.isFunctionDeclaration(cur) ||\n ts.isFunctionExpression(cur) ||\n ts.isArrowFunction(cur) ||\n ts.isMethodDeclaration(cur)\n ) {\n const sig = checker.getSignatureFromDeclaration(cur)\n if (sig) {\n const ret = checker.getReturnTypeOfSignature(sig)\n if (returnTypeIsNodeShape(ret, checker)) return true\n }\n return false\n }\n cur = cur.parent\n }\n return false\n}\n\n/**\n * Walk a Program looking for call expressions that should be classified\n * by the §2.1 rule. Restricts the walk to files matching `filter` so\n * tests can scope to a subdirectory.\n */\nexport function walkProgram(\n program: ts.Program,\n options: { filter?: (sourceFile: ts.SourceFile) => boolean } = {},\n): WalkerResult {\n const checker = program.getTypeChecker()\n const filter = options.filter ?? (() => true)\n const diagnostics: WalkerDiagnostic[] = []\n const perFile = new Map<\n string,\n WalkerResult['perFile'] extends Map<string, infer V> ? V : never\n >()\n\n for (const sf of program.getSourceFiles()) {\n if (sf.isDeclarationFile) continue\n if (!filter(sf)) continue\n const counts = { callsClassified: 0, walked: 0, opaque: 0, async: 0, notAHelper: 0 }\n perFile.set(sf.fileName, counts)\n\n const visit = (node: ts.Node): void => {\n if (ts.isCallExpression(node)) {\n // Resolve the symbol of the callee.\n const callee = node.expression\n let symbol = checker.getSymbolAtLocation(callee)\n if (symbol && symbol.flags & ts.SymbolFlags.Alias) {\n symbol = checker.getAliasedSymbol(symbol)\n }\n if (symbol && !(symbol.flags & ts.SymbolFlags.Transient)) {\n const cls = classifyViewHelper(symbol, checker)\n counts.callsClassified++\n if (cls.kind === 'walked') counts.walked++\n else if (cls.kind === 'opaque') counts.opaque++\n else if (cls.kind === 'async') counts.async++\n else counts.notAHelper++\n\n if (cls.kind === 'opaque' && isViewPositionCall(node, checker)) {\n diagnostics.push({\n id: 'llui/opaque-view-call',\n file: sf.fileName,\n pos: node.getStart(sf),\n end: node.getEnd(),\n helperName: getCalleeName(callee),\n message: `Call to \"${getCalleeName(callee) ?? '<unknown>'}\" in a view position is opaque to the cross-file walker (${cls.reason}). Either add an explicit return-type annotation (Node[] / Node / ReadonlyArray<Node>), accept a View bag parameter (or a documented subset), or mark with /** @llui-helper */ if the helper genuinely cannot be annotated. As a last resort, use track({ deps: ... }) at the call site.`,\n })\n } else if (cls.kind === 'async' && isViewPositionCall(node, checker)) {\n diagnostics.push({\n id: 'llui/async-view-helper',\n file: sf.fileName,\n pos: node.getStart(sf),\n end: node.getEnd(),\n helperName: getCalleeName(callee),\n message: `Call to \"${getCalleeName(callee) ?? '<unknown>'}\" in a view position returns Promise<Node[] | Node>. LLui's view layer is synchronous — wrap async work in onMount() or use clientOnly() instead.`,\n })\n }\n }\n }\n ts.forEachChild(node, visit)\n }\n visit(sf)\n }\n\n return { diagnostics, perFile }\n}\n\nfunction getCalleeName(expr: ts.Expression): string | undefined {\n if (ts.isIdentifier(expr)) return expr.text\n if (ts.isPropertyAccessExpression(expr)) return expr.name.text\n return undefined\n}\n\n// ── Diagnostic schema integration (v2c §3) ──────────────────────────\n//\n// The walker emits a lightweight `WalkerDiagnostic` (with raw byte\n// offsets) for internal accumulation. Adapters and the host pipeline\n// want the canonical `Diagnostic` shape with project-relative paths\n// and line/column ranges. This converter resolves the position pair to\n// a Range and relativizes the file path; the caller supplies the\n// project root.\n\nconst WALKER_DIAGNOSTIC_META: Record<\n DiagnosticId,\n {\n severity: DiagnosticSeverity\n category: DiagnosticCategory\n documentation?: string\n }\n> = {\n 'llui/opaque-view-call': {\n severity: 'warning',\n category: 'reactivity',\n documentation:\n 'https://github.com/fponticelli/llui/blob/main/docs/proposals/v2-compiler/v2b.md#21-view-helper-resolution-rule',\n },\n 'llui/async-view-helper': {\n severity: 'error',\n category: 'composition',\n documentation:\n 'https://github.com/fponticelli/llui/blob/main/docs/proposals/v2-compiler/v2b.md#21-view-helper-resolution-rule',\n },\n 'llui/helper-cycle': {\n severity: 'warning',\n category: 'composition',\n documentation:\n 'https://github.com/fponticelli/llui/blob/main/docs/proposals/v2-compiler/v2b.md#23-recursion-and-cycles',\n },\n}\n\n/**\n * Convert a walker-internal diagnostic to the canonical `Diagnostic`\n * shape. Reads the source text (for line/column resolution) and a\n * project root (for path relativization).\n */\nexport function toCanonicalDiagnostic(\n d: WalkerDiagnostic,\n sourceText: string,\n projectRoot: string,\n): Diagnostic {\n const meta = WALKER_DIAGNOSTIC_META[d.id]\n return {\n id: d.id,\n severity: meta.severity,\n category: meta.category,\n message: d.message,\n location: {\n file: relativizeFile(d.file, projectRoot),\n range: rangeFromOffsets(sourceText, d.pos, d.end),\n },\n ...(meta.documentation ? { documentation: meta.documentation } : {}),\n }\n}\n\n// ── Cross-file accessor path collection ─────────────────────────────\n//\n// Given a focal source file inside a Program, walk every reactive-accessor\n// arrow in the file. For each accessor:\n// - Collect paths it reads directly (the existing AST-only collector\n// handles this — see `collect-deps.ts`).\n// - For every call site inside the accessor whose callee resolves to a\n// view-helper (per §2.1), descend into the callee and merge its reads.\n//\n// This is the cross-file extension of `collectStatePathsFromSource`. The\n// AST-only collector terminates at the file boundary; the cross-file\n// version follows view-helper calls into other files using the TypeChecker.\n//\n// Used by the focal file's compiler to compute its __prefixes table. The\n// production wiring (Vite adapter builds a Program; compileFile consumes\n// it) is v2c module work — for v2b this is exposed as a callable engine\n// API that downstream tools can drive.\n\n/**\n * Collect the cross-file union of accessor paths read from a focal file.\n * Returns the union over every reactive accessor in `focalFile`, with\n * cross-file view-helper descents merged in.\n *\n * Reactive-accessor entry is gated by `isReactiveAccessor` (the same\n * predicate the file-local `collect-deps` walker uses) *plus* a\n * cross-file extension: an arrow at the first-arg position of a call\n * to a §2.1 view-helper also counts as reactive, because that's the\n * lift the helper applies to our state.\n *\n * Without the gate, every 1-param arrow in the file gets walked —\n * including `onEffect: (bag) => bag.send(...)`, where `bag.send` ends\n * up in the path set as a phantom \"send\" prefix. Issue #5, bug 3.\n */\nexport function crossFileAccessorPaths(\n program: ts.Program,\n focalFile: ts.SourceFile,\n): { paths: Set<string>; opaque: boolean } {\n const checker = program.getTypeChecker()\n const paths = new Set<string>()\n const opaqueOut = { value: false }\n const visitedHelpers = new Set<ts.Declaration>()\n\n const isViewHelperCallArg0 = (arrow: ts.ArrowFunction | ts.FunctionExpression): boolean => {\n const parent = arrow.parent\n if (!parent || !ts.isCallExpression(parent)) return false\n if (parent.arguments[0] !== arrow) return false\n const sym = resolveAliasedSymbol(parent.expression, checker)\n if (!sym) return false\n return classifyViewHelper(sym, checker).kind === 'walked'\n }\n\n const visit = (node: ts.Node): void => {\n if (\n (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&\n node.parameters.length === 1\n ) {\n const p0 = node.parameters[0]!\n if (ts.isIdentifier(p0.name) && node.body) {\n if (isReactiveAccessor(node) || isViewHelperCallArg0(node)) {\n walkAccessorBody(node.body, p0.name.text, paths, checker, visitedHelpers, opaqueOut)\n }\n }\n }\n ts.forEachChild(node, visit)\n }\n visit(focalFile)\n return { paths, opaque: opaqueOut.value }\n}\n\n// Helpers whose arrow args are NOT state accessors — same exclusion list\n// the file-local walker uses (collect-deps.ts § NON_DELEGATION_HELPERS).\n// `item` / `sample` read state imperatively or per-row; descending into\n// their bodies would attribute reads to the wrong scope. `memo` / `text` /\n// `unsafeHtml` already have their inline arrow walked by the top-level\n// visitor — we'd double-count if we recursed through the call again.\nconst NON_DELEGATION_CALLEES = new Set(['sample', 'item', 'memo', 'text', 'unsafeHtml'])\n\nfunction walkAccessorBody(\n body: ts.Node,\n paramName: string,\n paths: Set<string>,\n checker: ts.TypeChecker,\n visitedHelpers: Set<ts.Declaration>,\n opaqueOut: { value: boolean },\n): void {\n const visit = (node: ts.Node): void => {\n // Property-chain extraction (mirrors collect-deps' depth-2 normaliser).\n if (ts.isPropertyAccessExpression(node)) {\n const chain = resolveDepth2(node, paramName)\n if (chain) paths.add(chain)\n }\n\n // Opaque-state-flow classifier (mirrors the per-binding mask\n // classifier in transform.ts:computeAccessorMask). Any standalone\n // appearance of the param identifier in a non-tracked container\n // means the helper reads through an expression we can't trace, so\n // a precise prefix table is insufficient — the host needs a\n // whole-state sentinel in `__prefixes`.\n if (ts.isIdentifier(node) && node.text === paramName) {\n const parent = node.parent\n const isBinding = !!parent && ts.isParameter(parent)\n if (!isBinding) {\n let isTracked = false\n if (parent) {\n if (ts.isPropertyAccessExpression(parent) && parent.expression === node) {\n isTracked = true\n } else if (ts.isElementAccessExpression(parent) && parent.expression === node) {\n isTracked =\n ts.isStringLiteralLike(parent.argumentExpression) ||\n ts.isNumericLiteral(parent.argumentExpression)\n } else if (\n ts.isCallExpression(parent) &&\n ts.isIdentifier(parent.expression) &&\n parent.arguments[0] === node &&\n !NON_DELEGATION_CALLEES.has(parent.expression.text)\n ) {\n // Identifier-callee delegations are handled by the\n // descend-into-helper branch below — if the callee\n // resolves, recursion finds opaque inside; if not, the\n // call's `sym` is undefined and the host sees no descent.\n // Treat as tracked here so this branch alone doesn't flip\n // opaque on every well-formed `helper(s)`.\n isTracked = true\n }\n }\n if (!isTracked) opaqueOut.value = true\n }\n }\n\n if (ts.isCallExpression(node)) {\n const callee = node.expression\n const sym = resolveAliasedSymbol(callee, checker)\n if (sym) {\n const cls = classifyViewHelper(sym, checker)\n const decl = sym.getDeclarations()?.find(isFunctionLikeDecl)\n\n if (cls.kind === 'walked' && decl && !visitedHelpers.has(decl)) {\n // §2.1 view-helper: full descent (arrow-arg accessors lift\n // into our state, identifier args pass our state through).\n visitedHelpers.add(decl)\n descendIntoHelper(\n decl,\n node,\n paramName,\n paths,\n checker,\n visitedHelpers,\n /*viewHelper*/ true,\n opaqueOut,\n )\n } else if (decl && !visitedHelpers.has(decl)) {\n // Non-view-helper: only follow if our state param is passed\n // through unchanged. A helper returning string / boolean /\n // anything-non-Node that reads `s.foo.bar` still contributes\n // those paths to our accessor's read set when called as\n // `helper(s)`. Without this, helpers like\n // `(s) => s.route.kind === 'a'` would have their reads\n // silently dropped, producing a stale-render bug rather than\n // a crash (issue #5, bug 3 false-negative).\n //\n // Skip framework primitives whose arrow args are visited\n // separately (see NON_DELEGATION_CALLEES) — descending would\n // double-count.\n if (\n ts.isIdentifier(callee) &&\n !NON_DELEGATION_CALLEES.has(callee.text) &&\n callPassesParamIdent(node, paramName)\n ) {\n visitedHelpers.add(decl)\n const fnDecl = decl as ts.FunctionLikeDeclaration\n if (fnDecl.body) {\n descendIntoHelper(\n decl,\n node,\n paramName,\n paths,\n checker,\n visitedHelpers,\n /*viewHelper*/ false,\n opaqueOut,\n )\n } else {\n // Declaration without a body — ambient `declare function`,\n // overload signature, or compiled .d.ts. State flows in\n // but we can't see what it reads. Conservative: opaque.\n opaqueOut.value = true\n }\n }\n } else if (!decl && ts.isIdentifier(callee) && !NON_DELEGATION_CALLEES.has(callee.text)) {\n // Callee resolved to a symbol but no function-like\n // declaration (e.g., ambient declaration, type-only import,\n // or a binding whose initializer the checker can't pin\n // down). If state flows in, treat as opaque — same\n // conservative read as the file-local classifier.\n if (callPassesParamIdent(node, paramName)) opaqueOut.value = true\n }\n } else if (ts.isIdentifier(callee) && !NON_DELEGATION_CALLEES.has(callee.text)) {\n // Callee identifier didn't resolve to ANY symbol (declared\n // outside the program, lost through transient binding, etc.).\n // The standalone `s` classifier above already flagged the arg\n // as opaque, so no additional bookkeeping is needed here; the\n // branch is kept to mirror the file-local handling shape.\n }\n }\n\n ts.forEachChild(node, visit)\n }\n visit(body)\n}\n\nfunction callPassesParamIdent(call: ts.CallExpression, paramName: string): boolean {\n for (const arg of call.arguments) {\n if (ts.isIdentifier(arg) && arg.text === paramName) return true\n }\n return false\n}\n\nfunction descendIntoHelper(\n decl: ts.Declaration,\n callSite: ts.CallExpression,\n outerParamName: string,\n paths: Set<string>,\n checker: ts.TypeChecker,\n visitedHelpers: Set<ts.Declaration>,\n viewHelper: boolean,\n opaqueOut: { value: boolean },\n): void {\n // Match each parameter to its argument at the call site.\n //\n // For §2.1 view-helpers: arrow-arg accessors like `(t) => t.foo` are\n // lifts that bind the helper's parameter to a slice of our state;\n // walk their bodies so the slice's reads chain into our path set.\n //\n // For non-view-helpers: we don't know what the helper does with its\n // arrow args — could be a filter callback over a per-item type, or a\n // mapper that doesn't touch state at all. Only the identifier-arg\n // branch (`helper(s)`) is unambiguous, so the non-view-helper case\n // is conservative and only takes that path.\n const fnDecl = decl as ts.FunctionLikeDeclaration\n if (!fnDecl.body) return\n const params = fnDecl.parameters\n for (let i = 0; i < params.length; i++) {\n const param = params[i]!\n const arg = callSite.arguments[i]\n if (!arg) continue\n if (!ts.isIdentifier(param.name)) continue\n if (viewHelper && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {\n const a0 = arg.parameters[0]\n if (a0 && ts.isIdentifier(a0.name) && arg.body) {\n walkAccessorBody(arg.body, a0.name.text, paths, checker, visitedHelpers, opaqueOut)\n }\n } else if (ts.isIdentifier(arg) && arg.text === outerParamName) {\n walkAccessorBody(fnDecl.body, param.name.text, paths, checker, visitedHelpers, opaqueOut)\n }\n }\n}\n\nfunction resolveAliasedSymbol(node: ts.Node, checker: ts.TypeChecker): ts.Symbol | undefined {\n let sym = checker.getSymbolAtLocation(node)\n if (!sym) return undefined\n if (sym.flags & ts.SymbolFlags.Alias) sym = checker.getAliasedSymbol(sym)\n if (sym.flags & ts.SymbolFlags.Transient) return undefined\n return sym\n}\n\nfunction resolveDepth2(node: ts.PropertyAccessExpression, paramName: string): string | null {\n const parts: string[] = []\n let current: ts.Expression = node\n while (ts.isPropertyAccessExpression(current)) {\n parts.unshift(current.name.text)\n current = current.expression\n }\n if (!ts.isIdentifier(current) || current.text !== paramName) return null\n if (parts.length === 0) return null\n return parts.slice(0, 2).join('.')\n}\n\nfunction isFunctionLikeDecl(d: ts.Declaration): boolean {\n return (\n ts.isFunctionDeclaration(d) ||\n ts.isFunctionExpression(d) ||\n ts.isArrowFunction(d) ||\n ts.isMethodDeclaration(d)\n )\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint-modules.d.ts","sourceRoot":"","sources":["../src/lint-modules.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"lint-modules.d.ts","sourceRoot":"","sources":["../src/lint-modules.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AA8CjD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,EAAE,CA+CpD"}
|
package/dist/lint-modules.js
CHANGED
|
@@ -55,6 +55,7 @@ import { noSampleInEventHandlerModule } from './modules/no-sample-in-event-handl
|
|
|
55
55
|
import { noRepeatedItemCurrentModule } from './modules/no-repeated-item-current.js';
|
|
56
56
|
import { agentEmitsDriftModule } from './modules/agent-emits-drift.js';
|
|
57
57
|
import { agentMsgResolvableModule } from './modules/agent-msg-resolvable.js';
|
|
58
|
+
import { opaqueStateFlowModule } from './modules/opaque-state-flow.js';
|
|
58
59
|
/**
|
|
59
60
|
* Construct fresh instances of every always-on lint module.
|
|
60
61
|
*
|
|
@@ -107,6 +108,7 @@ export function createLintModules() {
|
|
|
107
108
|
noRepeatedItemCurrentModule(),
|
|
108
109
|
agentEmitsDriftModule(),
|
|
109
110
|
agentMsgResolvableModule(),
|
|
111
|
+
opaqueStateFlowModule(),
|
|
110
112
|
];
|
|
111
113
|
}
|
|
112
114
|
//# sourceMappingURL=lint-modules.js.map
|
package/dist/lint-modules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint-modules.js","sourceRoot":"","sources":["../src/lint-modules.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"lint-modules.js","sourceRoot":"","sources":["../src/lint-modules.ts"],"names":[],"mappings":"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","sourcesContent":["// Always-on lint modules.\n//\n// Every entry here is a zero-arg `CompilerModule` factory whose output\n// is registered unconditionally on every `transformLlui` invocation.\n// The function is the single source of truth — `transform.ts`'s active-\n// module list spreads it, and `scripts/generate-rule-docs.ts` calls it\n// to enumerate diagnostic IDs for the rule reference. Adding or removing\n// a rule in one place propagates everywhere.\n//\n// Note: this does NOT include modules with per-file options (e.g.\n// `maskLegendModule({ fieldBits, fieldBitsHi })`, `coreSynthesisModule`,\n// etc.) — those stay constructed inline in `transform.ts` because they\n// take per-file context. The `compilerStampModule` is unconditional but\n// it's an instance-not-factory; appended separately by callers.\n\nimport type { CompilerModule } from './module.js'\nimport { bitmaskOverflowModule } from './modules/bitmask-overflow.js'\nimport { asyncUpdateModule } from './modules/async-update.js'\nimport { mapOnStateArrayModule } from './modules/map-on-state-array.js'\nimport { nestedSendInUpdateModule } from './modules/nested-send-in-update.js'\nimport { directStateInViewModule } from './modules/direct-state-in-view.js'\nimport { imperativeDomInViewModule } from './modules/imperative-dom-in-view.js'\nimport { accessorSideEffectModule } from './modules/accessor-side-effect.js'\nimport { stateMutationModule } from './modules/state-mutation.js'\nimport { effectWithoutHandlerModule } from './modules/effect-without-handler.js'\nimport { exhaustiveEffectHandlingModule } from './modules/exhaustive-effect-handling.js'\nimport { noEagerItemAccessorModule } from './modules/no-eager-item-accessor.js'\nimport { pureUpdateFunctionModule } from './modules/pure-update-function.js'\nimport { exhaustiveUpdateModule } from './modules/exhaustive-update.js'\nimport { noLetReactiveAccessorModule } from './modules/no-let-reactive-accessor.js'\nimport { eachClosureViolationModule } from './modules/each-closure-violation.js'\nimport { stringEffectCallbackModule } from './modules/string-effect-callback.js'\nimport { agentMissingIntentModule } from './modules/agent-missing-intent.js'\nimport { agentWarningOnConfirmModule } from './modules/agent-warning-on-confirm.js'\nimport { agentExampleOnPayloadModule } from './modules/agent-example-on-payload.js'\nimport { agentExclusiveAnnotationsModule } from './modules/agent-exclusive-annotations.js'\nimport { agentOptionalFieldUndocumentedModule } from './modules/agent-optional-field-undocumented.js'\nimport { agentTagsendTranslatorMissingModule } from './modules/agent-tagsend-translator-missing.js'\nimport { agentNonextractableHandlerModule } from './modules/agent-nonextractable-handler.js'\nimport { subappRequiresReasonModule } from './modules/subapp-requires-reason.js'\nimport { emptyPropsModule } from './modules/empty-props.js'\nimport { forgottenSpreadModule } from './modules/forgotten-spread.js'\nimport { accessibilityModule } from './modules/accessibility.js'\nimport { viewBagImportModule } from './modules/view-bag-import.js'\nimport { controlledInputModule } from './modules/controlled-input.js'\nimport { missingMemoModule } from './modules/missing-memo.js'\nimport { namespaceImportModule } from './modules/namespace-import.js'\nimport { noBarrelImportWhenSubpathExistsModule } from './modules/no-barrel-import-when-subpath-exists.js'\nimport { formBoilerplateModule } from './modules/form-boilerplate.js'\nimport { spreadInChildrenModule } from './modules/spread-in-children.js'\nimport { staticItemsModule } from './modules/static-items.js'\nimport { staticOnModule } from './modules/static-on.js'\nimport { noListRenderInSampleModule } from './modules/no-list-render-in-sample.js'\nimport { noSampleInAccessorModule } from './modules/no-sample-in-accessor.js'\nimport { noSampleInReactivePositionModule } from './modules/no-sample-in-reactive-position.js'\nimport { noSampleInEventHandlerModule } from './modules/no-sample-in-event-handler.js'\nimport { noRepeatedItemCurrentModule } from './modules/no-repeated-item-current.js'\nimport { agentEmitsDriftModule } from './modules/agent-emits-drift.js'\nimport { agentMsgResolvableModule } from './modules/agent-msg-resolvable.js'\nimport { opaqueStateFlowModule } from './modules/opaque-state-flow.js'\n\n/**\n * Construct fresh instances of every always-on lint module.\n *\n * Returns a new array per call. Modules are stateful within a single\n * `ModuleRegistry.run()` (slot accumulators), so reusing instances\n * across files would leak state — always call this once per file.\n */\nexport function createLintModules(): CompilerModule[] {\n return [\n bitmaskOverflowModule(),\n asyncUpdateModule(),\n mapOnStateArrayModule(),\n nestedSendInUpdateModule(),\n directStateInViewModule(),\n imperativeDomInViewModule(),\n accessorSideEffectModule(),\n stateMutationModule(),\n effectWithoutHandlerModule(),\n exhaustiveEffectHandlingModule(),\n noEagerItemAccessorModule(),\n pureUpdateFunctionModule(),\n exhaustiveUpdateModule(),\n noLetReactiveAccessorModule(),\n eachClosureViolationModule(),\n stringEffectCallbackModule(),\n agentMissingIntentModule(),\n agentWarningOnConfirmModule(),\n agentExampleOnPayloadModule(),\n agentExclusiveAnnotationsModule(),\n agentOptionalFieldUndocumentedModule(),\n agentTagsendTranslatorMissingModule(),\n agentNonextractableHandlerModule(),\n subappRequiresReasonModule(),\n emptyPropsModule(),\n forgottenSpreadModule(),\n accessibilityModule(),\n viewBagImportModule(),\n controlledInputModule(),\n missingMemoModule(),\n namespaceImportModule(),\n noBarrelImportWhenSubpathExistsModule(),\n formBoilerplateModule(),\n spreadInChildrenModule(),\n staticItemsModule(),\n staticOnModule(),\n noListRenderInSampleModule(),\n noSampleInAccessorModule(),\n noSampleInReactivePositionModule(),\n noSampleInEventHandlerModule(),\n noRepeatedItemCurrentModule(),\n agentEmitsDriftModule(),\n agentMsgResolvableModule(),\n opaqueStateFlowModule(),\n ]\n}\n"]}
|
|
@@ -96,7 +96,7 @@ export function bitmaskOverflowModule() {
|
|
|
96
96
|
if (componentCalls.length === 0)
|
|
97
97
|
return;
|
|
98
98
|
const componentCall = componentCalls[0];
|
|
99
|
-
const paths = collectStatePathsFromSource(sf);
|
|
99
|
+
const { paths } = collectStatePathsFromSource(sf);
|
|
100
100
|
const pathCount = paths.size;
|
|
101
101
|
if (pathCount <= PATH_LIMIT)
|
|
102
102
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitmask-overflow.js","sourceRoot":"","sources":["../../src/modules/bitmask-overflow.ts"],"names":[],"mappings":"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","sourcesContent":["// `bitmask-overflow` — errors when a component reads more than 62 unique\n// state paths. The runtime bitmask is two 31-bit words (`mask` 0..30,\n// `maskHi` 31..61); paths past the 62-path limit collapse to FULL_MASK\n// (-1) and re-evaluate every binding on change, negating the optimization.\n//\n// Migrated from `@llui/eslint-plugin`'s bitmask-overflow rule\n// (v0.x). Promoted to a compiler error (was an ESLint warning) so the\n// LLM-first authoring path cannot silently ship overflowing components.\n// LLMs ignore warnings; the compiler-error channel is non-bypassable.\n//\n// The diagnostic message includes:\n// - the per-top-level-field breakdown so authors know where to slice,\n// - a co-occurrence note for fields whose every sub-path always fires\n// in the same accessor sets (those collapse to one bit if the parent\n// object is read as a unit),\n// - a recommendation to restructure state so the most-read paths\n// collapse to fewer top-level prefixes, or to factor the offending\n// subtree into a subApp.\n//\n// Anchors the diagnostic on the file's first `component(...)` call so\n// the location is meaningful. Files without a `component()` call are\n// silent — utility modules that happen to read state-shaped accessors\n// don't trigger the rule.\n\nimport ts from 'typescript'\nimport { collectAccessorPathSets, collectStatePathsFromSource } from '../collect-deps.js'\nimport { rangeFromOffsets } from '../diagnostic.js'\nimport type { CompilerModule } from '../module.js'\nimport { findComponentCalls } from './_shared.js'\n\nconst PATH_LIMIT = 62\n\nfunction setsEqual<T>(a: Set<T>, b: Set<T>): boolean {\n if (a.size !== b.size) return false\n for (const x of a) if (!b.has(x)) return false\n return true\n}\n\nfunction findCooccurringFields(\n paths: Set<string>,\n accessorSets: Set<string>[],\n): Array<{ field: string; saved: number }> {\n const subPathsByTop = new Map<string, string[]>()\n for (const p of paths) {\n const dot = p.indexOf('.')\n if (dot < 0) continue\n const top = p.slice(0, dot)\n const arr = subPathsByTop.get(top) ?? []\n arr.push(p)\n subPathsByTop.set(top, arr)\n }\n const appearances = new Map<string, Set<number>>()\n for (let i = 0; i < accessorSets.length; i++) {\n for (const path of accessorSets[i]!) {\n if (!appearances.has(path)) appearances.set(path, new Set())\n appearances.get(path)!.add(i)\n }\n }\n const out: Array<{ field: string; saved: number }> = []\n for (const [field, subPaths] of subPathsByTop) {\n if (subPaths.length < 2) continue\n const first = appearances.get(subPaths[0]!) ?? new Set<number>()\n let uniform = true\n for (let i = 1; i < subPaths.length; i++) {\n const set = appearances.get(subPaths[i]!) ?? new Set<number>()\n if (!setsEqual(first, set)) {\n uniform = false\n break\n }\n }\n if (uniform) out.push({ field, saved: subPaths.length - 1 })\n }\n return out.sort((a, b) => b.saved - a.saved)\n}\n\nexport function bitmaskOverflowModule(): CompilerModule {\n return {\n name: 'bitmask-overflow',\n compilerVersion: '^0.3.0',\n diagnostics: [\n {\n id: 'llui/bitmask-overflow',\n description:\n 'Component reads more than 62 unique state paths — paths past the limit fall back to FULL_MASK.',\n },\n ],\n visitors: {\n [ts.SyntaxKind.SourceFile]: (ctx, node) => {\n const visited = node as ts.SourceFile\n // Re-parse from text. PreTransform passes (e.g.\n // `bindingDescriptorsModule` in agent mode) produce synthetic\n // AST nodes that lack parent pointers; `collectStatePathsFromSource`\n // walks parent chains and crashes on undefined. Re-parsing\n // guarantees a clean tree with `setParentNodes=true` — the\n // analysis is over the user's source, which is what we want\n // regardless of upstream rewrites.\n const sf = ts.createSourceFile(visited.fileName, visited.text, ts.ScriptTarget.Latest, true)\n const componentCalls = findComponentCalls(sf)\n if (componentCalls.length === 0) return\n const componentCall = componentCalls[0]!\n\n const paths = collectStatePathsFromSource(sf)\n const pathCount = paths.size\n if (pathCount <= PATH_LIMIT) return\n\n const overflow = pathCount - PATH_LIMIT\n const byTopLevel = new Map<string, number>()\n for (const p of paths) {\n const top = p.split('.', 1)[0]!\n byTopLevel.set(top, (byTopLevel.get(top) ?? 0) + 1)\n }\n const sorted = [...byTopLevel.entries()].sort((a, b) => b[1] - a[1])\n const candidates: string[] = []\n let saved = 0\n for (const [field, n] of sorted) {\n if (pathCount - saved <= 31) break\n candidates.push(field)\n saved += n\n }\n const breakdown = sorted.map(([field, n]) => `${field} (${n})`).join(', ')\n const candidateList = candidates.map((f) => `\\`${f}\\``).join(', ')\n\n const accessorSets = collectAccessorPathSets(sf)\n const cooccurring = findCooccurringFields(paths, accessorSets)\n const cooccurrenceNote =\n cooccurring.length > 0\n ? `\\n\\nCo-occurrence detected: ` +\n cooccurring\n .map(\n ({ field, saved: s }) =>\n `every sub-path under \\`${field}\\` always fires together; reading \\`s.${field}\\` as one unit saves ${s} bit${s === 1 ? '' : 's'}`,\n )\n .join('; ') +\n `. Bundle those reads into a single \\`s.${cooccurring[0]!.field}\\` access (e.g. \\`const ${cooccurring[0]!.field} = s.${cooccurring[0]!.field}\\`) before extraction — cheaper refactor, same budget relief.`\n : ''\n\n const message =\n `Component has ${pathCount} unique state access paths (${overflow} past the ${PATH_LIMIT}-path limit). ` +\n `Paths ${PATH_LIMIT + 1}..${pathCount} fall back to FULL_MASK — their changes re-evaluate every binding ` +\n `in the component, negating the bitmask optimization for those updates.\\n\\n` +\n `Top-level fields by path count: ${breakdown}.${cooccurrenceNote}\\n\\n` +\n `Recommended fix: restructure state so ${candidateList} are grouped under one or two ` +\n `reference-stable parents, or factor that subtree into a separate module that consumes ` +\n `the parent's state via the standard view-function \\`(props, send)\\` convention. ` +\n `Alternative: use \\`combine()\\` to split the reducer into slices when the parent's \\`update()\\` ` +\n `is mostly mechanical routing.`\n\n ctx.reportDiagnostic({\n id: 'llui/bitmask-overflow',\n severity: 'error',\n category: 'perf',\n message,\n location: {\n file: sf.fileName,\n range: rangeFromOffsets(sf.text, componentCall.getStart(sf), componentCall.getEnd()),\n },\n })\n },\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bitmask-overflow.js","sourceRoot":"","sources":["../../src/modules/bitmask-overflow.ts"],"names":[],"mappings":"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","sourcesContent":["// `bitmask-overflow` — errors when a component reads more than 62 unique\n// state paths. The runtime bitmask is two 31-bit words (`mask` 0..30,\n// `maskHi` 31..61); paths past the 62-path limit collapse to FULL_MASK\n// (-1) and re-evaluate every binding on change, negating the optimization.\n//\n// Migrated from `@llui/eslint-plugin`'s bitmask-overflow rule\n// (v0.x). Promoted to a compiler error (was an ESLint warning) so the\n// LLM-first authoring path cannot silently ship overflowing components.\n// LLMs ignore warnings; the compiler-error channel is non-bypassable.\n//\n// The diagnostic message includes:\n// - the per-top-level-field breakdown so authors know where to slice,\n// - a co-occurrence note for fields whose every sub-path always fires\n// in the same accessor sets (those collapse to one bit if the parent\n// object is read as a unit),\n// - a recommendation to restructure state so the most-read paths\n// collapse to fewer top-level prefixes, or to factor the offending\n// subtree into a subApp.\n//\n// Anchors the diagnostic on the file's first `component(...)` call so\n// the location is meaningful. Files without a `component()` call are\n// silent — utility modules that happen to read state-shaped accessors\n// don't trigger the rule.\n\nimport ts from 'typescript'\nimport { collectAccessorPathSets, collectStatePathsFromSource } from '../collect-deps.js'\nimport { rangeFromOffsets } from '../diagnostic.js'\nimport type { CompilerModule } from '../module.js'\nimport { findComponentCalls } from './_shared.js'\n\nconst PATH_LIMIT = 62\n\nfunction setsEqual<T>(a: Set<T>, b: Set<T>): boolean {\n if (a.size !== b.size) return false\n for (const x of a) if (!b.has(x)) return false\n return true\n}\n\nfunction findCooccurringFields(\n paths: Set<string>,\n accessorSets: Set<string>[],\n): Array<{ field: string; saved: number }> {\n const subPathsByTop = new Map<string, string[]>()\n for (const p of paths) {\n const dot = p.indexOf('.')\n if (dot < 0) continue\n const top = p.slice(0, dot)\n const arr = subPathsByTop.get(top) ?? []\n arr.push(p)\n subPathsByTop.set(top, arr)\n }\n const appearances = new Map<string, Set<number>>()\n for (let i = 0; i < accessorSets.length; i++) {\n for (const path of accessorSets[i]!) {\n if (!appearances.has(path)) appearances.set(path, new Set())\n appearances.get(path)!.add(i)\n }\n }\n const out: Array<{ field: string; saved: number }> = []\n for (const [field, subPaths] of subPathsByTop) {\n if (subPaths.length < 2) continue\n const first = appearances.get(subPaths[0]!) ?? new Set<number>()\n let uniform = true\n for (let i = 1; i < subPaths.length; i++) {\n const set = appearances.get(subPaths[i]!) ?? new Set<number>()\n if (!setsEqual(first, set)) {\n uniform = false\n break\n }\n }\n if (uniform) out.push({ field, saved: subPaths.length - 1 })\n }\n return out.sort((a, b) => b.saved - a.saved)\n}\n\nexport function bitmaskOverflowModule(): CompilerModule {\n return {\n name: 'bitmask-overflow',\n compilerVersion: '^0.3.0',\n diagnostics: [\n {\n id: 'llui/bitmask-overflow',\n description:\n 'Component reads more than 62 unique state paths — paths past the limit fall back to FULL_MASK.',\n },\n ],\n visitors: {\n [ts.SyntaxKind.SourceFile]: (ctx, node) => {\n const visited = node as ts.SourceFile\n // Re-parse from text. PreTransform passes (e.g.\n // `bindingDescriptorsModule` in agent mode) produce synthetic\n // AST nodes that lack parent pointers; `collectStatePathsFromSource`\n // walks parent chains and crashes on undefined. Re-parsing\n // guarantees a clean tree with `setParentNodes=true` — the\n // analysis is over the user's source, which is what we want\n // regardless of upstream rewrites.\n const sf = ts.createSourceFile(visited.fileName, visited.text, ts.ScriptTarget.Latest, true)\n const componentCalls = findComponentCalls(sf)\n if (componentCalls.length === 0) return\n const componentCall = componentCalls[0]!\n\n const { paths } = collectStatePathsFromSource(sf)\n const pathCount = paths.size\n if (pathCount <= PATH_LIMIT) return\n\n const overflow = pathCount - PATH_LIMIT\n const byTopLevel = new Map<string, number>()\n for (const p of paths) {\n const top = p.split('.', 1)[0]!\n byTopLevel.set(top, (byTopLevel.get(top) ?? 0) + 1)\n }\n const sorted = [...byTopLevel.entries()].sort((a, b) => b[1] - a[1])\n const candidates: string[] = []\n let saved = 0\n for (const [field, n] of sorted) {\n if (pathCount - saved <= 31) break\n candidates.push(field)\n saved += n\n }\n const breakdown = sorted.map(([field, n]) => `${field} (${n})`).join(', ')\n const candidateList = candidates.map((f) => `\\`${f}\\``).join(', ')\n\n const accessorSets = collectAccessorPathSets(sf)\n const cooccurring = findCooccurringFields(paths, accessorSets)\n const cooccurrenceNote =\n cooccurring.length > 0\n ? `\\n\\nCo-occurrence detected: ` +\n cooccurring\n .map(\n ({ field, saved: s }) =>\n `every sub-path under \\`${field}\\` always fires together; reading \\`s.${field}\\` as one unit saves ${s} bit${s === 1 ? '' : 's'}`,\n )\n .join('; ') +\n `. Bundle those reads into a single \\`s.${cooccurring[0]!.field}\\` access (e.g. \\`const ${cooccurring[0]!.field} = s.${cooccurring[0]!.field}\\`) before extraction — cheaper refactor, same budget relief.`\n : ''\n\n const message =\n `Component has ${pathCount} unique state access paths (${overflow} past the ${PATH_LIMIT}-path limit). ` +\n `Paths ${PATH_LIMIT + 1}..${pathCount} fall back to FULL_MASK — their changes re-evaluate every binding ` +\n `in the component, negating the bitmask optimization for those updates.\\n\\n` +\n `Top-level fields by path count: ${breakdown}.${cooccurrenceNote}\\n\\n` +\n `Recommended fix: restructure state so ${candidateList} are grouped under one or two ` +\n `reference-stable parents, or factor that subtree into a separate module that consumes ` +\n `the parent's state via the standard view-function \\`(props, send)\\` convention. ` +\n `Alternative: use \\`combine()\\` to split the reducer into slices when the parent's \\`update()\\` ` +\n `is mostly mechanical routing.`\n\n ctx.reportDiagnostic({\n id: 'llui/bitmask-overflow',\n severity: 'error',\n category: 'perf',\n message,\n location: {\n file: sf.fileName,\n range: rangeFromOffsets(sf.text, componentCall.getStart(sf), componentCall.getEnd()),\n },\n })\n },\n },\n }\n}\n"]}
|
|
@@ -6,6 +6,13 @@ export interface CoreSynthesisModuleOptions {
|
|
|
6
6
|
/** Component() call detection requires the @llui/dom import binding
|
|
7
7
|
* to disambiguate from user-local `component` identifiers. */
|
|
8
8
|
lluiImport: ts.ImportDeclaration;
|
|
9
|
+
/** At least one reactive accessor in the file flows the state
|
|
10
|
+
* identifier into an expression the walker can't trace (opaque
|
|
11
|
+
* callee, spread, ternary branch, dynamic key, …). Forces emission
|
|
12
|
+
* of a `(s) => s` whole-state sentinel at the tail of `__prefixes`
|
|
13
|
+
* so FULL_MASK bindings catch a dirty bit on every update,
|
|
14
|
+
* regardless of which fields the opaque expression actually reads. */
|
|
15
|
+
hasOpaqueAccessor?: boolean;
|
|
9
16
|
}
|
|
10
17
|
export interface CoreSynthesisSlot {
|
|
11
18
|
/** True when at least one component() call got the __update/__handlers/__prefixes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-synthesis.d.ts","sourceRoot":"","sources":["../../src/modules/core-synthesis.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;mEAC+D;IAC/D,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"core-synthesis.d.ts","sourceRoot":"","sources":["../../src/modules/core-synthesis.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAGlD,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;mEAC+D;IAC/D,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAA;IAChC;;;;;2EAKuE;IACvE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC;;2CAEuC;IACvC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,eAAO,MAAM,mBAAmB,yBAAyB,CAAA;AAEzD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,cAAc,CAqBpF"}
|
|
@@ -27,7 +27,7 @@ import ts from 'typescript';
|
|
|
27
27
|
import { computeAccessorMask, createMaskLiteral, isComponentCall } from '../transform.js';
|
|
28
28
|
export const CORE_SYNTHESIS_SLOT = 'core-synthesis:state';
|
|
29
29
|
export function coreSynthesisModule(opts) {
|
|
30
|
-
const { fieldBits, fieldBitsHi, lluiImport } = opts;
|
|
30
|
+
const { fieldBits, fieldBitsHi, lluiImport, hasOpaqueAccessor = false } = opts;
|
|
31
31
|
return {
|
|
32
32
|
name: 'core-synthesis',
|
|
33
33
|
compilerVersion: '^0.3.0',
|
|
@@ -36,7 +36,7 @@ export function coreSynthesisModule(opts) {
|
|
|
36
36
|
transformCallEnter(ctx, node) {
|
|
37
37
|
if (!isComponentCall(node, lluiImport))
|
|
38
38
|
return null;
|
|
39
|
-
const rewritten = tryInjectDirty(node, fieldBits, ctx.factory, fieldBitsHi);
|
|
39
|
+
const rewritten = tryInjectDirty(node, fieldBits, ctx.factory, fieldBitsHi, hasOpaqueAccessor);
|
|
40
40
|
if (!rewritten)
|
|
41
41
|
return null;
|
|
42
42
|
const slot = ctx.analysis.perModule.get(CORE_SYNTHESIS_SLOT);
|
|
@@ -51,8 +51,8 @@ export function coreSynthesisModule(opts) {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
// ─── Synthesis implementation (moved verbatim from transform.ts) ────
|
|
54
|
-
function tryInjectDirty(node, fieldBits, f, fieldBitsHi = new Map()) {
|
|
55
|
-
if (fieldBits.size === 0 && fieldBitsHi.size === 0)
|
|
54
|
+
function tryInjectDirty(node, fieldBits, f, fieldBitsHi = new Map(), hasOpaqueAccessor = false) {
|
|
55
|
+
if (fieldBits.size === 0 && fieldBitsHi.size === 0 && !hasOpaqueAccessor)
|
|
56
56
|
return null;
|
|
57
57
|
const configArg = node.arguments[0];
|
|
58
58
|
if (!configArg || !ts.isObjectLiteralExpression(configArg))
|
|
@@ -120,7 +120,7 @@ function tryInjectDirty(node, fieldBits, f, fieldBitsHi = new Map()) {
|
|
|
120
120
|
// emit layer today, so high-position bindings still re-evaluate
|
|
121
121
|
// every cycle — but the dirty computation itself is now precise,
|
|
122
122
|
// which lets memo()'d aggregates short-circuit correctly.
|
|
123
|
-
const prefixesProp = buildPrefixesProp(fieldBits, fieldBitsHi, f);
|
|
123
|
+
const prefixesProp = buildPrefixesProp(fieldBits, fieldBitsHi, f, hasOpaqueAccessor);
|
|
124
124
|
if (prefixesProp)
|
|
125
125
|
extraProps.push(prefixesProp);
|
|
126
126
|
const newConfig = f.createObjectLiteralExpression([...configArg.properties, ...extraProps], true);
|
|
@@ -602,8 +602,8 @@ function computeStructuralMask(configArg, fieldBits) {
|
|
|
602
602
|
*
|
|
603
603
|
* Returns null if no paths are present.
|
|
604
604
|
*/
|
|
605
|
-
function buildPrefixesProp(fieldBits, fieldBitsHi, f) {
|
|
606
|
-
if (fieldBits.size === 0 && fieldBitsHi.size === 0)
|
|
605
|
+
function buildPrefixesProp(fieldBits, fieldBitsHi, f, hasOpaqueAccessor = false) {
|
|
606
|
+
if (fieldBits.size === 0 && fieldBitsHi.size === 0 && !hasOpaqueAccessor)
|
|
607
607
|
return null;
|
|
608
608
|
// Sort paths by bit value within each word. Bits are powers of two
|
|
609
609
|
// inside their word (1, 2, 4, …, 1<<30), so sorting numerically gives
|
|
@@ -613,15 +613,27 @@ function buildPrefixesProp(fieldBits, fieldBitsHi, f) {
|
|
|
613
613
|
.filter(([, bit]) => bit > 0)
|
|
614
614
|
.sort(([, a], [, b]) => a - b);
|
|
615
615
|
const orderedHi = [...fieldBitsHi.entries()].sort(([, a], [, b]) => a - b);
|
|
616
|
-
const buildArrow = (
|
|
617
|
-
|
|
618
|
-
|
|
616
|
+
const buildArrow = (parts) => {
|
|
617
|
+
// Empty parts → `(s) => s` (whole-state sentinel). Any other path
|
|
618
|
+
// builds the optional-chain access expression.
|
|
619
|
+
const body = parts.length === 0 ? f.createIdentifier('s') : buildAccess(f, 's', parts);
|
|
619
620
|
return f.createArrowFunction(undefined, undefined, [f.createParameterDeclaration(undefined, undefined, 's')], undefined, f.createToken(ts.SyntaxKind.EqualsGreaterThanToken), body);
|
|
620
621
|
};
|
|
621
622
|
const arrows = [
|
|
622
|
-
...orderedLo.map(([path]) => buildArrow(path)),
|
|
623
|
-
...orderedHi.map(([path]) => buildArrow(path)),
|
|
623
|
+
...orderedLo.map(([path]) => buildArrow(path.split('.'))),
|
|
624
|
+
...orderedHi.map(([path]) => buildArrow(path.split('.'))),
|
|
624
625
|
];
|
|
626
|
+
// Append the whole-state sentinel `(s) => s` when any accessor in
|
|
627
|
+
// the file flows state opaquely. Its prefix bit dirties on every
|
|
628
|
+
// update (immutable reducers always return a new object identity),
|
|
629
|
+
// so FULL_MASK bindings — whose mask covers every bit — fire even
|
|
630
|
+
// when the changed field has no traceable prefix entry. Without
|
|
631
|
+
// this, a field read ONLY through an opaque expression would
|
|
632
|
+
// disappear from `__prefixes`; computeDirtyFromPrefixes would
|
|
633
|
+
// return 0 for changes to it; (-1) & 0 = 0; the binding would
|
|
634
|
+
// silently never re-evaluate.
|
|
635
|
+
if (hasOpaqueAccessor)
|
|
636
|
+
arrows.push(buildArrow([]));
|
|
625
637
|
return f.createPropertyAssignment('__prefixes', f.createArrayLiteralExpression(arrows, false));
|
|
626
638
|
}
|
|
627
639
|
function buildAccess(f, root, parts) {
|