@llui/compiler 0.3.1 → 0.4.0

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.
@@ -46,4 +46,16 @@ export declare function collectDeps(source: string, extraPaths?: ReadonlySet<str
46
46
  lo: Map<string, number>;
47
47
  hi: Map<string, number>;
48
48
  };
49
+ /**
50
+ * Determines if a node is at a reactive-accessor position — either an
51
+ * inline arrow / function expression OR an identifier that's about to
52
+ * be resolved to one. The check is identity-based on `parent.arguments[0]`
53
+ * etc., so the same logic works for both shapes.
54
+ *
55
+ * Exported so the cross-file walker can use the same gate. Without this
56
+ * gate the walker descends into every 1-param arrow in the file —
57
+ * including `onEffect: (bag) => bag.send(...)` — and pollutes
58
+ * `__prefixes` with non-state property names (issue #5, bug 3).
59
+ */
60
+ export declare function isReactiveAccessor(node: ts.Node): boolean;
49
61
  //# sourceMappingURL=collect-deps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collect-deps.d.ts","sourceRoot":"","sources":["../src/collect-deps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAyG3B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CAuBlF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAwBhF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B;IACD,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxB,CAsCA"}
1
+ {"version":3,"file":"collect-deps.d.ts","sourceRoot":"","sources":["../src/collect-deps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAyG3B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CAuBlF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAwBhF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B;IACD,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxB,CAsCA;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,OAAO,CAiDzD"}
@@ -229,8 +229,13 @@ function hasLluiImport(sourceFile) {
229
229
  * inline arrow / function expression OR an identifier that's about to
230
230
  * be resolved to one. The check is identity-based on `parent.arguments[0]`
231
231
  * etc., so the same logic works for both shapes.
232
+ *
233
+ * Exported so the cross-file walker can use the same gate. Without this
234
+ * gate the walker descends into every 1-param arrow in the file —
235
+ * including `onEffect: (bag) => bag.send(...)` — and pollutes
236
+ * `__prefixes` with non-state property names (issue #5, bug 3).
232
237
  */
233
- function isReactiveAccessor(node) {
238
+ export function isReactiveAccessor(node) {
234
239
  const parent = node.parent;
235
240
  // text(s => s.count) — first arg to a call
236
241
  if (ts.isCallExpression(parent) && parent.arguments[0] === node) {
@@ -1 +1 @@
1
- {"version":3,"file":"collect-deps.js","sourceRoot":"","sources":["../src/collect-deps.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript'\nimport { resolveAccessorBody } from './accessor-resolver.js'\n\n/**\n * Names whose first arg is itself a reactive accessor (the existing\n * arrow walker handles them) or which are explicitly excluded\n * (sample/item read state imperatively / per-row, not as state\n * accessors). When a delegating accessor's body contains a call to one\n * of these, we don't follow it — recursion is reserved for \"this is\n * just a thin wrapper that hands the state to another local helper.\"\n */\nconst NON_DELEGATION_HELPERS = new Set(['sample', 'item', 'memo', 'text', 'unsafeHtml'])\n\n/**\n * Walk a delegating accessor's body looking for calls to OTHER local\n * functions that take the state param verbatim — `helper(s)` where\n * `s` matches the outer accessor's param name. For each, hand the\n * resolved declaration back so the caller can recurse into its body.\n *\n * Skips:\n * - Framework helpers (`memo`, `text`, etc.) — their arrow args are\n * visited by the top-level arrow walker; we'd double-count.\n * - Method calls (`s.items.filter(...)`) — the callee is a builtin,\n * not a local function we can resolve.\n * - Nested function bodies — params inside a `(item) => …` shadow\n * ours, so a `helper(s)` deep in there isn't (necessarily)\n * handing OUR state in. Conservative: don't recurse through\n * lambda boundaries.\n */\nfunction visitTopLevelDelegations(\n body: ts.Node,\n stateParamName: string,\n follow: (resolved: ts.ArrowFunction | ts.FunctionExpression | ts.FunctionDeclaration) => void,\n): void {\n function visit(node: ts.Node): void {\n if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {\n const name = node.expression.text\n if (!NON_DELEGATION_HELPERS.has(name)) {\n const arg0 = node.arguments[0]\n if (arg0 && ts.isIdentifier(arg0) && arg0.text === stateParamName) {\n const resolved = resolveAccessorBody(node.expression)\n if (resolved) follow(resolved)\n }\n }\n }\n // Don't descend into nested function bodies — their params shadow\n // ours, and any call inside them isn't unambiguously delegating\n // our state.\n if (\n ts.isArrowFunction(node) ||\n ts.isFunctionExpression(node) ||\n ts.isFunctionDeclaration(node)\n ) {\n return\n }\n ts.forEachChild(node, visit)\n }\n // If the body itself is a function, there's nothing at the top\n // level to inspect — its own body is a separate scope.\n if (ts.isArrowFunction(body) || ts.isFunctionExpression(body) || ts.isFunctionDeclaration(body)) {\n return\n }\n visit(body)\n}\n\n/**\n * Extract paths from a callable accessor (arrow / fn-expr / fn-decl)\n * into the given set. Recurses through call-delegations to other local\n * helpers so that `(s) => filtered(s)` / `(s) => { void s.x; return\n * inner(s) }` correctly contribute the helper's state-path reads.\n * Without recursion the precise mask under-counts — fields read only\n * via the helper drop off the bitmask, and any sibling reactive\n * accessor that reads them produces a non-zero `dirty` that AND'd with\n * the narrow each.__mask is zero, silently skipping the reconcile.\n *\n * `visited` breaks cycles on mutually-recursive helpers — terminates\n * the walk; doesn't try to be precise about what such helpers read.\n */\nfunction extractAccessorPaths(\n accessor: ts.ArrowFunction | ts.FunctionExpression | ts.FunctionDeclaration,\n paths: Set<string>,\n visited: Set<ts.Node> = new Set(),\n): boolean {\n if (visited.has(accessor)) return false\n visited.add(accessor)\n\n const params = accessor.parameters\n if (params.length !== 1) return false\n const paramName = params[0]!.name\n if (!ts.isIdentifier(paramName)) return false\n if (!accessor.body) return false\n const before = paths.size\n\n extractPaths(accessor.body, paramName.text, '', paths)\n\n // Follow delegations: `(s) => helper(s)` — extract `helper`'s body's\n // state paths too. Reuses the `visited` set across the recursion\n // chain so cycles terminate.\n visitTopLevelDelegations(accessor.body, paramName.text, (resolved) => {\n extractAccessorPaths(resolved, paths, visited)\n })\n\n return paths.size > before\n}\n\n/**\n * Walk the AST and collect every unique state access path referenced by\n * a reactive accessor. A reactive accessor is one of:\n *\n * - An inline arrow / function expression at a reactive position\n * (`text(s => s.count)`, `div({ title: s => s.title })`,\n * `show({ when: s => s.gated })`, etc.).\n * - An Identifier at a reactive position that resolves to a callable\n * in this file — a const-bound arrow / function expression,\n * a hoisted function declaration, or `const x = memo(arrow)`.\n *\n * The second case lets authors refactor a literal arrow into a named\n * helper without losing the reactive-mask optimization (a precise mask\n * for `__dirty` and structural-primitive `__mask`). Without it, the\n * runtime falls back to FULL_MASK — correct, but every binding fires\n * on every state change.\n *\n * Shared by the bit-assignment path (`collectDeps`, below) and the\n * `diagnostics.ts` bitmask-overflow warning.\n */\nexport function collectStatePathsFromSource(sourceFile: ts.SourceFile): Set<string> {\n const paths = new Set<string>()\n\n function visit(node: ts.Node): void {\n // Inline arrow / function expression at a reactive position.\n if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {\n if (isReactiveAccessor(node)) extractAccessorPaths(node, paths)\n }\n\n // Identifier at a reactive position — resolve to its declaration\n // and extract paths from the resolved body. Skip identifiers\n // imported from elsewhere (resolver returns null) — there's no\n // body to scan, runtime falls back to FULL_MASK.\n if (ts.isIdentifier(node) && isReactiveAccessor(node)) {\n const resolved = resolveAccessorBody(node)\n if (resolved) extractAccessorPaths(resolved, paths)\n }\n\n ts.forEachChild(node, visit)\n }\n\n visit(sourceFile)\n return paths\n}\n\n/**\n * Per-accessor path sets — one entry per reactive arrow/function. Used\n * by the bitmask-overflow diagnostic to find clusters of paths that\n * always fire together (co-occurrence analysis).\n */\nexport function collectAccessorPathSets(sourceFile: ts.SourceFile): Set<string>[] {\n const sets: Set<string>[] = []\n\n function visit(node: ts.Node): void {\n if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {\n if (isReactiveAccessor(node)) {\n const set = new Set<string>()\n if (extractAccessorPaths(node, set)) sets.push(set)\n }\n }\n\n if (ts.isIdentifier(node) && isReactiveAccessor(node)) {\n const resolved = resolveAccessorBody(node)\n if (resolved) {\n const set = new Set<string>()\n if (extractAccessorPaths(resolved, set)) sets.push(set)\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n visit(sourceFile)\n return sets\n}\n\n/**\n * Pre-scan a source file to collect all unique state access paths\n * referenced by reactive accessors (arrow functions in props and text() calls).\n *\n * Returns a pair of maps:\n * - `lo`: paths at bit positions 0..30, with value `1 << position`\n * - `hi`: paths at bit positions 31..61, with value `1 << (position - 31)`\n *\n * Bit positions past 61 collapse to `-1` (FULL_MASK) in the `lo` map and\n * cause every binding reading them to re-evaluate on every cycle. The\n * `bitmask-overflow` lint rule warns the user to restructure state.\n *\n * Components with ≤31 paths see an empty `hi` map; the compiler skips\n * all high-word emit so the generated code is byte-identical to the\n * pre-multi-word baseline.\n */\nexport function collectDeps(\n source: string,\n extraPaths?: ReadonlySet<string>,\n): {\n lo: Map<string, number>\n hi: Map<string, number>\n} {\n const sourceFile = ts.createSourceFile('input.ts', source, ts.ScriptTarget.Latest, true)\n\n // Check if file imports from @llui/dom\n if (!hasLluiImport(sourceFile)) {\n return { lo: new Map(), hi: new Map() }\n }\n\n const paths = collectStatePathsFromSource(sourceFile)\n // Cross-file extension (v2c pipeline integration): the host adapter may\n // pass paths discovered by `crossFileAccessorPaths()` — paths read\n // through in-repo view-helpers in *other* files. Union them with the\n // file-local set before bit assignment. Without this merge the\n // sentinel-`show()` workaround from v2b §1 remains necessary; with\n // it, helpers in other files contribute to the consumer's __prefixes\n // table automatically.\n if (extraPaths) {\n for (const p of extraPaths) paths.add(p)\n }\n\n const lo = new Map<string, number>()\n const hi = new Map<string, number>()\n let index = 0\n for (const path of paths) {\n if (index < 31) {\n lo.set(path, 1 << index)\n } else if (index < 62) {\n hi.set(path, 1 << (index - 31))\n } else {\n // Past 61 paths — graceful FULL_MASK fallback in the low word.\n // Realistic LLui components shouldn't hit this; the lint rule\n // fires well before.\n lo.set(path, -1)\n }\n index++\n }\n\n return { lo, hi }\n}\n\nfunction hasLluiImport(sourceFile: ts.SourceFile): boolean {\n for (const stmt of sourceFile.statements) {\n if (\n ts.isImportDeclaration(stmt) &&\n ts.isStringLiteral(stmt.moduleSpecifier) &&\n stmt.moduleSpecifier.text === '@llui/dom'\n ) {\n return true\n }\n }\n return false\n}\n\n/**\n * Determines if a node is at a reactive-accessor position — either an\n * inline arrow / function expression OR an identifier that's about to\n * be resolved to one. The check is identity-based on `parent.arguments[0]`\n * etc., so the same logic works for both shapes.\n */\nfunction isReactiveAccessor(node: ts.Node): boolean {\n const parent = node.parent\n\n // text(s => s.count) — first arg to a call\n if (ts.isCallExpression(parent) && parent.arguments[0] === node) {\n // Skip item(t => t.id) — per-item selectors inside each() render.\n // Skip sample(s => s.x) — imperative one-shot read, no binding created\n // (both the top-level import and the destructured-from-h form).\n if (ts.isIdentifier(parent.expression)) {\n if (parent.expression.text === 'item' || parent.expression.text === 'sample') {\n return false\n }\n }\n // Skip array method callbacks: .filter(t => ...), .map(t => ...), .some(t => ...), etc.\n // Allow view-helper primitive calls: h.text(s => ...), h.memo(s => ...)\n if (ts.isPropertyAccessExpression(parent.expression)) {\n const methodName = parent.expression.name.text\n if (methodName === 'text' || methodName === 'memo') {\n return true\n }\n return false\n }\n return true\n }\n\n // div({ title: s => s.title }) — value in a property assignment inside an object literal.\n // Only treat as reactive if the containing call is a known framework API whose\n // properties are reactive accessors. Otherwise user-land helpers like\n // sliceHandler({ narrow: (m) => m.type === ... }) would pollute the path set.\n if (ts.isPropertyAssignment(parent)) {\n const key = parent.name\n if (ts.isIdentifier(key)) {\n // Skip event handlers (onClick, onInput, etc.)\n if (/^on[A-Z]/.test(key.text)) return false\n // Skip each() key function and other non-reactive props\n if (key.text === 'key' || key.text === 'name') return false\n // Walk up to find the enclosing call expression\n let ancestor: ts.Node | undefined = parent.parent // ObjectLiteralExpression\n while (ancestor && !ts.isCallExpression(ancestor)) {\n ancestor = ancestor.parent\n }\n if (!ancestor) return false\n const callExpr = ancestor as ts.CallExpression\n if (!ts.isIdentifier(callExpr.expression)) return false\n return REACTIVE_API_NAMES.has(callExpr.expression.text)\n }\n }\n\n return false\n}\n\n// Framework APIs whose object-literal arguments contain reactive accessors.\n// Arrow functions in property values of these calls are state-tracked.\nconst REACTIVE_API_NAMES = new Set([\n // Element helpers (see ELEMENT_HELPERS in transform.ts — we keep a superset here)\n ...[\n 'a',\n 'abbr',\n 'article',\n 'aside',\n 'b',\n 'blockquote',\n 'br',\n 'button',\n 'canvas',\n 'code',\n 'dd',\n 'details',\n 'dialog',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hr',\n 'i',\n 'iframe',\n 'img',\n 'input',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'mark',\n 'nav',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'pre',\n 'progress',\n 'section',\n 'select',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'ul',\n 'video',\n ],\n // Structural primitives\n 'each',\n 'branch',\n 'scope',\n 'show',\n 'memo',\n 'portal',\n 'foreign',\n 'child',\n 'errorBoundary',\n // track({ deps: (s) => [...] }) — explicit reactivity declaration for\n // paths static analysis can't infer. The compiler treats `deps` as a\n // reactive accessor so its paths fold into the host component's\n // __prefixes; the call expression is then stripped from emission\n // (see transform.ts). v2b §3.\n 'track',\n])\n\n/**\n * Extract state access paths from an expression body.\n * Handles:\n * - Direct property access: param.field, param.field.subfield\n * - Bracket notation with string literal: param['field']\n */\nfunction extractPaths(node: ts.Node, paramName: string, _prefix: string, paths: Set<string>): void {\n if (ts.isPropertyAccessExpression(node)) {\n // Skip if this is an intermediate in a deeper chain\n if (ts.isPropertyAccessExpression(node.parent)) {\n // handled when the leaf is visited\n }\n // Skip if this is the callee of a method call: s.todos.filter(...)\n else if (ts.isCallExpression(node.parent) && node.parent.expression === node) {\n // It's a method call — record the object, not the method\n // e.g. s.todos.filter(...) → record 'todos', not 'todos.filter'\n if (ts.isPropertyAccessExpression(node.expression)) {\n const chain = resolvePropertyChain(node.expression, paramName)\n if (chain) paths.add(chain)\n }\n } else {\n const chain = resolvePropertyChain(node, paramName)\n if (chain) {\n paths.add(chain)\n }\n }\n }\n\n if (ts.isElementAccessExpression(node)) {\n const chain = resolveElementAccess(node, paramName)\n if (chain) {\n paths.add(chain)\n }\n }\n\n ts.forEachChild(node, (child) => extractPaths(child, paramName, _prefix, paths))\n}\n\n/**\n * Resolve a property access chain like s.user.name to \"user.name\".\n * Returns null if the chain doesn't start with the state parameter.\n * Stops at depth 2.\n */\nfunction resolvePropertyChain(node: ts.PropertyAccessExpression, paramName: string): string | null {\n const parts: string[] = []\n let current: ts.Expression = node\n\n while (ts.isPropertyAccessExpression(current)) {\n parts.unshift(current.name.text)\n current = current.expression\n }\n\n // The root must be the state parameter\n if (!ts.isIdentifier(current) || current.text !== paramName) {\n return null\n }\n\n // Limit to depth 2\n if (parts.length > 2) {\n return parts.slice(0, 2).join('.')\n }\n\n return parts.join('.')\n}\n\n/**\n * Resolve bracket access with string literal: s['count'] → \"count\"\n */\nfunction resolveElementAccess(node: ts.ElementAccessExpression, paramName: string): string | null {\n if (!ts.isIdentifier(node.expression) || node.expression.text !== paramName) {\n return null\n }\n\n if (ts.isStringLiteral(node.argumentExpression)) {\n return node.argumentExpression.text\n }\n\n return null\n}\n"]}
1
+ {"version":3,"file":"collect-deps.js","sourceRoot":"","sources":["../src/collect-deps.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript'\nimport { resolveAccessorBody } from './accessor-resolver.js'\n\n/**\n * Names whose first arg is itself a reactive accessor (the existing\n * arrow walker handles them) or which are explicitly excluded\n * (sample/item read state imperatively / per-row, not as state\n * accessors). When a delegating accessor's body contains a call to one\n * of these, we don't follow it — recursion is reserved for \"this is\n * just a thin wrapper that hands the state to another local helper.\"\n */\nconst NON_DELEGATION_HELPERS = new Set(['sample', 'item', 'memo', 'text', 'unsafeHtml'])\n\n/**\n * Walk a delegating accessor's body looking for calls to OTHER local\n * functions that take the state param verbatim — `helper(s)` where\n * `s` matches the outer accessor's param name. For each, hand the\n * resolved declaration back so the caller can recurse into its body.\n *\n * Skips:\n * - Framework helpers (`memo`, `text`, etc.) — their arrow args are\n * visited by the top-level arrow walker; we'd double-count.\n * - Method calls (`s.items.filter(...)`) — the callee is a builtin,\n * not a local function we can resolve.\n * - Nested function bodies — params inside a `(item) => …` shadow\n * ours, so a `helper(s)` deep in there isn't (necessarily)\n * handing OUR state in. Conservative: don't recurse through\n * lambda boundaries.\n */\nfunction visitTopLevelDelegations(\n body: ts.Node,\n stateParamName: string,\n follow: (resolved: ts.ArrowFunction | ts.FunctionExpression | ts.FunctionDeclaration) => void,\n): void {\n function visit(node: ts.Node): void {\n if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {\n const name = node.expression.text\n if (!NON_DELEGATION_HELPERS.has(name)) {\n const arg0 = node.arguments[0]\n if (arg0 && ts.isIdentifier(arg0) && arg0.text === stateParamName) {\n const resolved = resolveAccessorBody(node.expression)\n if (resolved) follow(resolved)\n }\n }\n }\n // Don't descend into nested function bodies — their params shadow\n // ours, and any call inside them isn't unambiguously delegating\n // our state.\n if (\n ts.isArrowFunction(node) ||\n ts.isFunctionExpression(node) ||\n ts.isFunctionDeclaration(node)\n ) {\n return\n }\n ts.forEachChild(node, visit)\n }\n // If the body itself is a function, there's nothing at the top\n // level to inspect — its own body is a separate scope.\n if (ts.isArrowFunction(body) || ts.isFunctionExpression(body) || ts.isFunctionDeclaration(body)) {\n return\n }\n visit(body)\n}\n\n/**\n * Extract paths from a callable accessor (arrow / fn-expr / fn-decl)\n * into the given set. Recurses through call-delegations to other local\n * helpers so that `(s) => filtered(s)` / `(s) => { void s.x; return\n * inner(s) }` correctly contribute the helper's state-path reads.\n * Without recursion the precise mask under-counts — fields read only\n * via the helper drop off the bitmask, and any sibling reactive\n * accessor that reads them produces a non-zero `dirty` that AND'd with\n * the narrow each.__mask is zero, silently skipping the reconcile.\n *\n * `visited` breaks cycles on mutually-recursive helpers — terminates\n * the walk; doesn't try to be precise about what such helpers read.\n */\nfunction extractAccessorPaths(\n accessor: ts.ArrowFunction | ts.FunctionExpression | ts.FunctionDeclaration,\n paths: Set<string>,\n visited: Set<ts.Node> = new Set(),\n): boolean {\n if (visited.has(accessor)) return false\n visited.add(accessor)\n\n const params = accessor.parameters\n if (params.length !== 1) return false\n const paramName = params[0]!.name\n if (!ts.isIdentifier(paramName)) return false\n if (!accessor.body) return false\n const before = paths.size\n\n extractPaths(accessor.body, paramName.text, '', paths)\n\n // Follow delegations: `(s) => helper(s)` — extract `helper`'s body's\n // state paths too. Reuses the `visited` set across the recursion\n // chain so cycles terminate.\n visitTopLevelDelegations(accessor.body, paramName.text, (resolved) => {\n extractAccessorPaths(resolved, paths, visited)\n })\n\n return paths.size > before\n}\n\n/**\n * Walk the AST and collect every unique state access path referenced by\n * a reactive accessor. A reactive accessor is one of:\n *\n * - An inline arrow / function expression at a reactive position\n * (`text(s => s.count)`, `div({ title: s => s.title })`,\n * `show({ when: s => s.gated })`, etc.).\n * - An Identifier at a reactive position that resolves to a callable\n * in this file — a const-bound arrow / function expression,\n * a hoisted function declaration, or `const x = memo(arrow)`.\n *\n * The second case lets authors refactor a literal arrow into a named\n * helper without losing the reactive-mask optimization (a precise mask\n * for `__dirty` and structural-primitive `__mask`). Without it, the\n * runtime falls back to FULL_MASK — correct, but every binding fires\n * on every state change.\n *\n * Shared by the bit-assignment path (`collectDeps`, below) and the\n * `diagnostics.ts` bitmask-overflow warning.\n */\nexport function collectStatePathsFromSource(sourceFile: ts.SourceFile): Set<string> {\n const paths = new Set<string>()\n\n function visit(node: ts.Node): void {\n // Inline arrow / function expression at a reactive position.\n if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {\n if (isReactiveAccessor(node)) extractAccessorPaths(node, paths)\n }\n\n // Identifier at a reactive position — resolve to its declaration\n // and extract paths from the resolved body. Skip identifiers\n // imported from elsewhere (resolver returns null) — there's no\n // body to scan, runtime falls back to FULL_MASK.\n if (ts.isIdentifier(node) && isReactiveAccessor(node)) {\n const resolved = resolveAccessorBody(node)\n if (resolved) extractAccessorPaths(resolved, paths)\n }\n\n ts.forEachChild(node, visit)\n }\n\n visit(sourceFile)\n return paths\n}\n\n/**\n * Per-accessor path sets — one entry per reactive arrow/function. Used\n * by the bitmask-overflow diagnostic to find clusters of paths that\n * always fire together (co-occurrence analysis).\n */\nexport function collectAccessorPathSets(sourceFile: ts.SourceFile): Set<string>[] {\n const sets: Set<string>[] = []\n\n function visit(node: ts.Node): void {\n if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {\n if (isReactiveAccessor(node)) {\n const set = new Set<string>()\n if (extractAccessorPaths(node, set)) sets.push(set)\n }\n }\n\n if (ts.isIdentifier(node) && isReactiveAccessor(node)) {\n const resolved = resolveAccessorBody(node)\n if (resolved) {\n const set = new Set<string>()\n if (extractAccessorPaths(resolved, set)) sets.push(set)\n }\n }\n\n ts.forEachChild(node, visit)\n }\n\n visit(sourceFile)\n return sets\n}\n\n/**\n * Pre-scan a source file to collect all unique state access paths\n * referenced by reactive accessors (arrow functions in props and text() calls).\n *\n * Returns a pair of maps:\n * - `lo`: paths at bit positions 0..30, with value `1 << position`\n * - `hi`: paths at bit positions 31..61, with value `1 << (position - 31)`\n *\n * Bit positions past 61 collapse to `-1` (FULL_MASK) in the `lo` map and\n * cause every binding reading them to re-evaluate on every cycle. The\n * `bitmask-overflow` lint rule warns the user to restructure state.\n *\n * Components with ≤31 paths see an empty `hi` map; the compiler skips\n * all high-word emit so the generated code is byte-identical to the\n * pre-multi-word baseline.\n */\nexport function collectDeps(\n source: string,\n extraPaths?: ReadonlySet<string>,\n): {\n lo: Map<string, number>\n hi: Map<string, number>\n} {\n const sourceFile = ts.createSourceFile('input.ts', source, ts.ScriptTarget.Latest, true)\n\n // Check if file imports from @llui/dom\n if (!hasLluiImport(sourceFile)) {\n return { lo: new Map(), hi: new Map() }\n }\n\n const paths = collectStatePathsFromSource(sourceFile)\n // Cross-file extension (v2c pipeline integration): the host adapter may\n // pass paths discovered by `crossFileAccessorPaths()` — paths read\n // through in-repo view-helpers in *other* files. Union them with the\n // file-local set before bit assignment. Without this merge the\n // sentinel-`show()` workaround from v2b §1 remains necessary; with\n // it, helpers in other files contribute to the consumer's __prefixes\n // table automatically.\n if (extraPaths) {\n for (const p of extraPaths) paths.add(p)\n }\n\n const lo = new Map<string, number>()\n const hi = new Map<string, number>()\n let index = 0\n for (const path of paths) {\n if (index < 31) {\n lo.set(path, 1 << index)\n } else if (index < 62) {\n hi.set(path, 1 << (index - 31))\n } else {\n // Past 61 paths — graceful FULL_MASK fallback in the low word.\n // Realistic LLui components shouldn't hit this; the lint rule\n // fires well before.\n lo.set(path, -1)\n }\n index++\n }\n\n return { lo, hi }\n}\n\nfunction hasLluiImport(sourceFile: ts.SourceFile): boolean {\n for (const stmt of sourceFile.statements) {\n if (\n ts.isImportDeclaration(stmt) &&\n ts.isStringLiteral(stmt.moduleSpecifier) &&\n stmt.moduleSpecifier.text === '@llui/dom'\n ) {\n return true\n }\n }\n return false\n}\n\n/**\n * Determines if a node is at a reactive-accessor position — either an\n * inline arrow / function expression OR an identifier that's about to\n * be resolved to one. The check is identity-based on `parent.arguments[0]`\n * etc., so the same logic works for both shapes.\n *\n * Exported so the cross-file walker can use the same gate. Without this\n * gate the walker descends into every 1-param arrow in the file —\n * including `onEffect: (bag) => bag.send(...)` — and pollutes\n * `__prefixes` with non-state property names (issue #5, bug 3).\n */\nexport function isReactiveAccessor(node: ts.Node): boolean {\n const parent = node.parent\n\n // text(s => s.count) — first arg to a call\n if (ts.isCallExpression(parent) && parent.arguments[0] === node) {\n // Skip item(t => t.id) — per-item selectors inside each() render.\n // Skip sample(s => s.x) — imperative one-shot read, no binding created\n // (both the top-level import and the destructured-from-h form).\n if (ts.isIdentifier(parent.expression)) {\n if (parent.expression.text === 'item' || parent.expression.text === 'sample') {\n return false\n }\n }\n // Skip array method callbacks: .filter(t => ...), .map(t => ...), .some(t => ...), etc.\n // Allow view-helper primitive calls: h.text(s => ...), h.memo(s => ...)\n if (ts.isPropertyAccessExpression(parent.expression)) {\n const methodName = parent.expression.name.text\n if (methodName === 'text' || methodName === 'memo') {\n return true\n }\n return false\n }\n return true\n }\n\n // div({ title: s => s.title }) — value in a property assignment inside an object literal.\n // Only treat as reactive if the containing call is a known framework API whose\n // properties are reactive accessors. Otherwise user-land helpers like\n // sliceHandler({ narrow: (m) => m.type === ... }) would pollute the path set.\n if (ts.isPropertyAssignment(parent)) {\n const key = parent.name\n if (ts.isIdentifier(key)) {\n // Skip event handlers (onClick, onInput, etc.)\n if (/^on[A-Z]/.test(key.text)) return false\n // Skip each() key function and other non-reactive props\n if (key.text === 'key' || key.text === 'name') return false\n // Walk up to find the enclosing call expression\n let ancestor: ts.Node | undefined = parent.parent // ObjectLiteralExpression\n while (ancestor && !ts.isCallExpression(ancestor)) {\n ancestor = ancestor.parent\n }\n if (!ancestor) return false\n const callExpr = ancestor as ts.CallExpression\n if (!ts.isIdentifier(callExpr.expression)) return false\n return REACTIVE_API_NAMES.has(callExpr.expression.text)\n }\n }\n\n return false\n}\n\n// Framework APIs whose object-literal arguments contain reactive accessors.\n// Arrow functions in property values of these calls are state-tracked.\nconst REACTIVE_API_NAMES = new Set([\n // Element helpers (see ELEMENT_HELPERS in transform.ts — we keep a superset here)\n ...[\n 'a',\n 'abbr',\n 'article',\n 'aside',\n 'b',\n 'blockquote',\n 'br',\n 'button',\n 'canvas',\n 'code',\n 'dd',\n 'details',\n 'dialog',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hr',\n 'i',\n 'iframe',\n 'img',\n 'input',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'mark',\n 'nav',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'pre',\n 'progress',\n 'section',\n 'select',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'ul',\n 'video',\n ],\n // Structural primitives\n 'each',\n 'branch',\n 'scope',\n 'show',\n 'memo',\n 'portal',\n 'foreign',\n 'child',\n 'errorBoundary',\n // track({ deps: (s) => [...] }) — explicit reactivity declaration for\n // paths static analysis can't infer. The compiler treats `deps` as a\n // reactive accessor so its paths fold into the host component's\n // __prefixes; the call expression is then stripped from emission\n // (see transform.ts). v2b §3.\n 'track',\n])\n\n/**\n * Extract state access paths from an expression body.\n * Handles:\n * - Direct property access: param.field, param.field.subfield\n * - Bracket notation with string literal: param['field']\n */\nfunction extractPaths(node: ts.Node, paramName: string, _prefix: string, paths: Set<string>): void {\n if (ts.isPropertyAccessExpression(node)) {\n // Skip if this is an intermediate in a deeper chain\n if (ts.isPropertyAccessExpression(node.parent)) {\n // handled when the leaf is visited\n }\n // Skip if this is the callee of a method call: s.todos.filter(...)\n else if (ts.isCallExpression(node.parent) && node.parent.expression === node) {\n // It's a method call — record the object, not the method\n // e.g. s.todos.filter(...) → record 'todos', not 'todos.filter'\n if (ts.isPropertyAccessExpression(node.expression)) {\n const chain = resolvePropertyChain(node.expression, paramName)\n if (chain) paths.add(chain)\n }\n } else {\n const chain = resolvePropertyChain(node, paramName)\n if (chain) {\n paths.add(chain)\n }\n }\n }\n\n if (ts.isElementAccessExpression(node)) {\n const chain = resolveElementAccess(node, paramName)\n if (chain) {\n paths.add(chain)\n }\n }\n\n ts.forEachChild(node, (child) => extractPaths(child, paramName, _prefix, paths))\n}\n\n/**\n * Resolve a property access chain like s.user.name to \"user.name\".\n * Returns null if the chain doesn't start with the state parameter.\n * Stops at depth 2.\n */\nfunction resolvePropertyChain(node: ts.PropertyAccessExpression, paramName: string): string | null {\n const parts: string[] = []\n let current: ts.Expression = node\n\n while (ts.isPropertyAccessExpression(current)) {\n parts.unshift(current.name.text)\n current = current.expression\n }\n\n // The root must be the state parameter\n if (!ts.isIdentifier(current) || current.text !== paramName) {\n return null\n }\n\n // Limit to depth 2\n if (parts.length > 2) {\n return parts.slice(0, 2).join('.')\n }\n\n return parts.join('.')\n}\n\n/**\n * Resolve bracket access with string literal: s['count'] → \"count\"\n */\nfunction resolveElementAccess(node: ts.ElementAccessExpression, paramName: string): string | null {\n if (!ts.isIdentifier(node.expression) || node.expression.text !== paramName) {\n return null\n }\n\n if (ts.isStringLiteral(node.argumentExpression)) {\n return node.argumentExpression.text\n }\n\n return null\n}\n"]}
@@ -58,6 +58,16 @@ export declare function toCanonicalDiagnostic(d: WalkerDiagnostic, sourceText: s
58
58
  * Collect the cross-file union of accessor paths read from a focal file.
59
59
  * Returns the union over every reactive accessor in `focalFile`, with
60
60
  * cross-file view-helper descents merged in.
61
+ *
62
+ * Reactive-accessor entry is gated by `isReactiveAccessor` (the same
63
+ * predicate the file-local `collect-deps` walker uses) *plus* a
64
+ * cross-file extension: an arrow at the first-arg position of a call
65
+ * to a §2.1 view-helper also counts as reactive, because that's the
66
+ * lift the helper applies to our state.
67
+ *
68
+ * Without the gate, every 1-param arrow in the file gets walked —
69
+ * including `onEffect: (bag) => bag.send(...)`, where `bag.send` ends
70
+ * up in the path set as a phantom "send" prefix. Issue #5, bug 3.
61
71
  */
62
72
  export declare function crossFileAccessorPaths(program: ts.Program, focalFile: ts.SourceFile): Set<string>;
63
73
  //# sourceMappingURL=cross-file-walker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cross-file-walker.d.ts","sourceRoot":"","sources":["../src/cross-file-walker.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EACL,KAAK,UAAU,EAKhB,MAAM,iBAAiB,CAAA;AAExB,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,CAAA;AAE3E,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,cAAc,CAAA;IACpB,oEAAoE;IACpE,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;IACvB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,YAAY,GAAG,uBAAuB,GAAG,wBAAwB,GAAG,mBAAmB,CAAA;AAEnG,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,YAAY,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,gBAAgB,EAAE,CAAA;IAC/B,qCAAqC;IACrC,OAAO,EAAE,GAAG,CACV,MAAM,EACN;QACE,eAAe,EAAE,MAAM,CAAA;QACvB,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;KACnB,CACF,CAAA;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,EAAE,CAAC,MAAM,EACjB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,wBAAwB,CA0D1B;AA8LD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,EAAE,CAAC,OAAO,EACnB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAA;CAAO,GAChE,YAAY,CA0Dd;AA6CD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,EAAE,gBAAgB,EACnB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,UAAU,CAaZ;AAoBD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CAsBjG"}
1
+ {"version":3,"file":"cross-file-walker.d.ts","sourceRoot":"","sources":["../src/cross-file-walker.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EACL,KAAK,UAAU,EAKhB,MAAM,iBAAiB,CAAA;AAGxB,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,CAAA;AAE3E,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,cAAc,CAAA;IACpB,oEAAoE;IACpE,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;IACvB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,YAAY,GAAG,uBAAuB,GAAG,wBAAwB,GAAG,mBAAmB,CAAA;AAEnG,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,YAAY,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,gBAAgB,EAAE,CAAA;IAC/B,qCAAqC;IACrC,OAAO,EAAE,GAAG,CACV,MAAM,EACN;QACE,eAAe,EAAE,MAAM,CAAA;QACvB,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;KACnB,CACF,CAAA;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,EAAE,CAAC,MAAM,EACjB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,wBAAwB,CA0D1B;AA8LD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,EAAE,CAAC,OAAO,EACnB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAA;CAAO,GAChE,YAAY,CA0Dd;AA6CD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,CAAC,EAAE,gBAAgB,EACnB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,UAAU,CAaZ;AAoBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CA8BjG"}
@@ -24,6 +24,7 @@
24
24
  // expression); otherwise the call is uninteresting and not reported.
25
25
  import ts from 'typescript';
26
26
  import { rangeFromOffsets, relativizeFile, } from './diagnostic.js';
27
+ import { isReactiveAccessor } from './collect-deps.js';
27
28
  /**
28
29
  * Classify the symbol's declaration against the §2.1 rule.
29
30
  *
@@ -403,27 +404,54 @@ export function toCanonicalDiagnostic(d, sourceText, projectRoot) {
403
404
  * Collect the cross-file union of accessor paths read from a focal file.
404
405
  * Returns the union over every reactive accessor in `focalFile`, with
405
406
  * cross-file view-helper descents merged in.
407
+ *
408
+ * Reactive-accessor entry is gated by `isReactiveAccessor` (the same
409
+ * predicate the file-local `collect-deps` walker uses) *plus* a
410
+ * cross-file extension: an arrow at the first-arg position of a call
411
+ * to a §2.1 view-helper also counts as reactive, because that's the
412
+ * lift the helper applies to our state.
413
+ *
414
+ * Without the gate, every 1-param arrow in the file gets walked —
415
+ * including `onEffect: (bag) => bag.send(...)`, where `bag.send` ends
416
+ * up in the path set as a phantom "send" prefix. Issue #5, bug 3.
406
417
  */
407
418
  export function crossFileAccessorPaths(program, focalFile) {
408
419
  const checker = program.getTypeChecker();
409
420
  const paths = new Set();
410
421
  const visitedHelpers = new Set();
411
- const visit = (node, paramName) => {
412
- // Reactive accessor entry: a 1-param arrow or function expression.
422
+ const isViewHelperCallArg0 = (arrow) => {
423
+ const parent = arrow.parent;
424
+ if (!parent || !ts.isCallExpression(parent))
425
+ return false;
426
+ if (parent.arguments[0] !== arrow)
427
+ return false;
428
+ const sym = resolveAliasedSymbol(parent.expression, checker);
429
+ if (!sym)
430
+ return false;
431
+ return classifyViewHelper(sym, checker).kind === 'walked';
432
+ };
433
+ const visit = (node) => {
413
434
  if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
414
435
  node.parameters.length === 1) {
415
436
  const p0 = node.parameters[0];
416
437
  if (ts.isIdentifier(p0.name) && node.body) {
417
- // Inner walk over the body — collect property chains rooted at
418
- // this accessor's param, AND chase view-helper call sites.
419
- walkAccessorBody(node.body, p0.name.text, paths, checker, visitedHelpers);
438
+ if (isReactiveAccessor(node) || isViewHelperCallArg0(node)) {
439
+ walkAccessorBody(node.body, p0.name.text, paths, checker, visitedHelpers);
440
+ }
420
441
  }
421
442
  }
422
- ts.forEachChild(node, (child) => visit(child, paramName));
443
+ ts.forEachChild(node, visit);
423
444
  };
424
- visit(focalFile, undefined);
445
+ visit(focalFile);
425
446
  return paths;
426
447
  }
448
+ // Helpers whose arrow args are NOT state accessors — same exclusion list
449
+ // the file-local walker uses (collect-deps.ts § NON_DELEGATION_HELPERS).
450
+ // `item` / `sample` read state imperatively or per-row; descending into
451
+ // their bodies would attribute reads to the wrong scope. `memo` / `text` /
452
+ // `unsafeHtml` already have their inline arrow walked by the top-level
453
+ // visitor — we'd double-count if we recursed through the call again.
454
+ const NON_DELEGATION_CALLEES = new Set(['sample', 'item', 'memo', 'text', 'unsafeHtml']);
427
455
  function walkAccessorBody(body, paramName, paths, checker, visitedHelpers) {
428
456
  const visit = (node) => {
429
457
  // Property-chain extraction (mirrors collect-deps' depth-2 normaliser).
@@ -432,19 +460,38 @@ function walkAccessorBody(body, paramName, paths, checker, visitedHelpers) {
432
460
  if (chain)
433
461
  paths.add(chain);
434
462
  }
435
- // View-helper call chase. The call may pass the state through to the
436
- // helper, in which case the helper's own reads contribute to our
437
- // accessor's read set.
438
463
  if (ts.isCallExpression(node)) {
439
464
  const callee = node.expression;
440
465
  const sym = resolveAliasedSymbol(callee, checker);
441
466
  if (sym) {
442
467
  const cls = classifyViewHelper(sym, checker);
443
- if (cls.kind === 'walked') {
444
- const decl = sym.getDeclarations()?.find(isFunctionLikeDecl);
445
- if (decl && !visitedHelpers.has(decl)) {
468
+ const decl = sym.getDeclarations()?.find(isFunctionLikeDecl);
469
+ if (cls.kind === 'walked' && decl && !visitedHelpers.has(decl)) {
470
+ // §2.1 view-helper: full descent (arrow-arg accessors lift
471
+ // into our state, identifier args pass our state through).
472
+ visitedHelpers.add(decl);
473
+ descendIntoHelper(decl, node, paramName, paths, checker, visitedHelpers,
474
+ /*viewHelper*/ true);
475
+ }
476
+ else if (decl && !visitedHelpers.has(decl)) {
477
+ // Non-view-helper: only follow if our state param is passed
478
+ // through unchanged. A helper returning string / boolean /
479
+ // anything-non-Node that reads `s.foo.bar` still contributes
480
+ // those paths to our accessor's read set when called as
481
+ // `helper(s)`. Without this, helpers like
482
+ // `(s) => s.route.kind === 'a'` would have their reads
483
+ // silently dropped, producing a stale-render bug rather than
484
+ // a crash (issue #5, bug 3 false-negative).
485
+ //
486
+ // Skip framework primitives whose arrow args are visited
487
+ // separately (see NON_DELEGATION_CALLEES) — descending would
488
+ // double-count.
489
+ if (ts.isIdentifier(callee) &&
490
+ !NON_DELEGATION_CALLEES.has(callee.text) &&
491
+ callPassesParamIdent(node, paramName)) {
446
492
  visitedHelpers.add(decl);
447
- descendIntoHelper(decl, node, paramName, paths, checker, visitedHelpers);
493
+ descendIntoHelper(decl, node, paramName, paths, checker, visitedHelpers,
494
+ /*viewHelper*/ false);
448
495
  }
449
496
  }
450
497
  }
@@ -453,11 +500,25 @@ function walkAccessorBody(body, paramName, paths, checker, visitedHelpers) {
453
500
  };
454
501
  visit(body);
455
502
  }
456
- function descendIntoHelper(decl, callSite, outerParamName, paths, checker, visitedHelpers) {
457
- // Match each parameter to its argument at the call site. For accessor
458
- // arguments `(t) => t.foo`, the helper's body reads `t` which is our
459
- // outer state slice. Track this so reads inside the helper get
460
- // attributed to our state shape.
503
+ function callPassesParamIdent(call, paramName) {
504
+ for (const arg of call.arguments) {
505
+ if (ts.isIdentifier(arg) && arg.text === paramName)
506
+ return true;
507
+ }
508
+ return false;
509
+ }
510
+ function descendIntoHelper(decl, callSite, outerParamName, paths, checker, visitedHelpers, viewHelper) {
511
+ // Match each parameter to its argument at the call site.
512
+ //
513
+ // For §2.1 view-helpers: arrow-arg accessors like `(t) => t.foo` are
514
+ // lifts that bind the helper's parameter to a slice of our state;
515
+ // walk their bodies so the slice's reads chain into our path set.
516
+ //
517
+ // For non-view-helpers: we don't know what the helper does with its
518
+ // arrow args — could be a filter callback over a per-item type, or a
519
+ // mapper that doesn't touch state at all. Only the identifier-arg
520
+ // branch (`helper(s)`) is unambiguous, so the non-view-helper case
521
+ // is conservative and only takes that path.
461
522
  const fnDecl = decl;
462
523
  if (!fnDecl.body)
463
524
  return;
@@ -469,17 +530,13 @@ function descendIntoHelper(decl, callSite, outerParamName, paths, checker, visit
469
530
  continue;
470
531
  if (!ts.isIdentifier(param.name))
471
532
  continue;
472
- if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
533
+ if (viewHelper && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
473
534
  const a0 = arg.parameters[0];
474
535
  if (a0 && ts.isIdentifier(a0.name) && arg.body) {
475
- // The arg accessor binds the helper's lift; walk it under the
476
- // outer paramName so paths chain into our state.
477
536
  walkAccessorBody(arg.body, a0.name.text, paths, checker, visitedHelpers);
478
537
  }
479
538
  }
480
539
  else if (ts.isIdentifier(arg) && arg.text === outerParamName) {
481
- // The helper is called with our state directly — recurse into its
482
- // body under the helper's parameter name.
483
540
  walkAccessorBody(fnDecl.body, param.name.text, paths, checker, visitedHelpers);
484
541
  }
485
542
  }
@@ -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'\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 */\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 visit = (node: ts.Node, paramName: string | undefined): void => {\n // Reactive accessor entry: a 1-param arrow or function expression.\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 // Inner walk over the body — collect property chains rooted at\n // this accessor's param, AND chase view-helper call sites.\n walkAccessorBody(node.body, p0.name.text, paths, checker, visitedHelpers)\n }\n }\n ts.forEachChild(node, (child) => visit(child, paramName))\n }\n visit(focalFile, undefined)\n return paths\n}\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 // View-helper call chase. The call may pass the state through to the\n // helper, in which case the helper's own reads contribute to our\n // accessor's read set.\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 if (cls.kind === 'walked') {\n const decl = sym.getDeclarations()?.find(isFunctionLikeDecl)\n if (decl && !visitedHelpers.has(decl)) {\n visitedHelpers.add(decl)\n descendIntoHelper(decl, node, paramName, paths, checker, visitedHelpers)\n }\n }\n }\n }\n\n ts.forEachChild(node, visit)\n }\n visit(body)\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): void {\n // Match each parameter to its argument at the call site. For accessor\n // arguments `(t) => t.foo`, the helper's body reads `t` which is our\n // outer state slice. Track this so reads inside the helper get\n // attributed to our state shape.\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 (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {\n const a0 = arg.parameters[0]\n if (a0 && ts.isIdentifier(a0.name) && arg.body) {\n // The arg accessor binds the helper's lift; walk it under the\n // outer paramName so paths chain into our state.\n walkAccessorBody(arg.body, a0.name.text, paths, checker, visitedHelpers)\n }\n } else if (ts.isIdentifier(arg) && arg.text === outerParamName) {\n // The helper is called with our state directly — recurse into its\n // body under the helper's parameter name.\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(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"]}