@llui/vite-plugin 0.0.42 → 0.2.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.
- package/README.md +2 -2
- package/dist/collect-deps.d.ts +16 -2
- package/dist/collect-deps.d.ts.map +1 -1
- package/dist/collect-deps.js +25 -13
- package/dist/collect-deps.js.map +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +214 -101
- package/dist/transform.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,5 +50,5 @@ rules so they surface as editor squiggles instead of build-time console
|
|
|
50
50
|
output. Install the plugin and enable its `recommended` config to get the
|
|
51
51
|
full set — `empty-props`, `namespace-import`, `spread-in-children`,
|
|
52
52
|
`map-on-state-array`, `exhaustive-update`, `accessibility`,
|
|
53
|
-
`controlled-input`, `
|
|
54
|
-
`
|
|
53
|
+
`controlled-input`, `bitmask-overflow`, `static-on`,
|
|
54
|
+
`subapp-requires-reason`, and the `agent-*` annotation rules.
|
package/dist/collect-deps.d.ts
CHANGED
|
@@ -29,7 +29,21 @@ export declare function collectAccessorPathSets(sourceFile: ts.SourceFile): Set<
|
|
|
29
29
|
/**
|
|
30
30
|
* Pre-scan a source file to collect all unique state access paths
|
|
31
31
|
* referenced by reactive accessors (arrow functions in props and text() calls).
|
|
32
|
-
*
|
|
32
|
+
*
|
|
33
|
+
* Returns a pair of maps:
|
|
34
|
+
* - `lo`: paths at bit positions 0..30, with value `1 << position`
|
|
35
|
+
* - `hi`: paths at bit positions 31..61, with value `1 << (position - 31)`
|
|
36
|
+
*
|
|
37
|
+
* Bit positions past 61 collapse to `-1` (FULL_MASK) in the `lo` map and
|
|
38
|
+
* cause every binding reading them to re-evaluate on every cycle. The
|
|
39
|
+
* `bitmask-overflow` lint rule warns the user to restructure state.
|
|
40
|
+
*
|
|
41
|
+
* Components with ≤31 paths see an empty `hi` map; the compiler skips
|
|
42
|
+
* all high-word emit so the generated code is byte-identical to the
|
|
43
|
+
* pre-multi-word baseline.
|
|
33
44
|
*/
|
|
34
|
-
export declare function collectDeps(source: string):
|
|
45
|
+
export declare function collectDeps(source: string): {
|
|
46
|
+
lo: Map<string, number>;
|
|
47
|
+
hi: Map<string, number>;
|
|
48
|
+
};
|
|
35
49
|
//# 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
|
|
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,CAAC,MAAM,EAAE,MAAM,GAAG;IAC3C,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxB,CA4BA"}
|
package/dist/collect-deps.js
CHANGED
|
@@ -163,33 +163,45 @@ export function collectAccessorPathSets(sourceFile) {
|
|
|
163
163
|
/**
|
|
164
164
|
* Pre-scan a source file to collect all unique state access paths
|
|
165
165
|
* referenced by reactive accessors (arrow functions in props and text() calls).
|
|
166
|
-
*
|
|
166
|
+
*
|
|
167
|
+
* Returns a pair of maps:
|
|
168
|
+
* - `lo`: paths at bit positions 0..30, with value `1 << position`
|
|
169
|
+
* - `hi`: paths at bit positions 31..61, with value `1 << (position - 31)`
|
|
170
|
+
*
|
|
171
|
+
* Bit positions past 61 collapse to `-1` (FULL_MASK) in the `lo` map and
|
|
172
|
+
* cause every binding reading them to re-evaluate on every cycle. The
|
|
173
|
+
* `bitmask-overflow` lint rule warns the user to restructure state.
|
|
174
|
+
*
|
|
175
|
+
* Components with ≤31 paths see an empty `hi` map; the compiler skips
|
|
176
|
+
* all high-word emit so the generated code is byte-identical to the
|
|
177
|
+
* pre-multi-word baseline.
|
|
167
178
|
*/
|
|
168
179
|
export function collectDeps(source) {
|
|
169
180
|
const sourceFile = ts.createSourceFile('input.ts', source, ts.ScriptTarget.Latest, true);
|
|
170
181
|
// Check if file imports from @llui/dom
|
|
171
182
|
if (!hasLluiImport(sourceFile)) {
|
|
172
|
-
return new Map();
|
|
183
|
+
return { lo: new Map(), hi: new Map() };
|
|
173
184
|
}
|
|
174
185
|
const paths = collectStatePathsFromSource(sourceFile);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// — they always trigger re-evaluation, degrading gracefully. The
|
|
178
|
-
// diagnostic warns the user to decompose.
|
|
179
|
-
const fieldBits = new Map();
|
|
180
|
-
let bit = 1;
|
|
186
|
+
const lo = new Map();
|
|
187
|
+
const hi = new Map();
|
|
181
188
|
let index = 0;
|
|
182
189
|
for (const path of paths) {
|
|
183
|
-
if (index
|
|
184
|
-
|
|
190
|
+
if (index < 31) {
|
|
191
|
+
lo.set(path, 1 << index);
|
|
192
|
+
}
|
|
193
|
+
else if (index < 62) {
|
|
194
|
+
hi.set(path, 1 << (index - 31));
|
|
185
195
|
}
|
|
186
196
|
else {
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
// Past 61 paths — graceful FULL_MASK fallback in the low word.
|
|
198
|
+
// Realistic LLui components shouldn't hit this; the lint rule
|
|
199
|
+
// fires well before.
|
|
200
|
+
lo.set(path, -1);
|
|
189
201
|
}
|
|
190
202
|
index++;
|
|
191
203
|
}
|
|
192
|
-
return
|
|
204
|
+
return { lo, hi };
|
|
193
205
|
}
|
|
194
206
|
function hasLluiImport(sourceFile) {
|
|
195
207
|
for (const stmt of sourceFile.statements) {
|
package/dist/collect-deps.js.map
CHANGED
|
@@ -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 * Returns a Map<path, bitPosition> where each path gets a unique power-of-two bit.\n */\nexport function collectDeps(source: string): Map<string, number> {\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 new Map()\n }\n\n const paths = collectStatePathsFromSource(sourceFile)\n\n // Assign bit positions. The bitmask holds 31 unique paths (positions\n // 0..30). When the count exceeds 31, overflow paths use FULL_MASK (-1)\n // — they always trigger re-evaluation, degrading gracefully. The\n // diagnostic warns the user to decompose.\n const fieldBits = new Map<string, number>()\n let bit = 1\n let index = 0\n for (const path of paths) {\n if (index >= 31) {\n fieldBits.set(path, -1)\n } else {\n fieldBits.set(path, bit)\n bit <<= 1\n }\n index++\n }\n\n return fieldBits\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])\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(source: string): {\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\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])\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"]}
|
package/dist/transform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAO3B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EAIpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,qBAAqB,EAA2B,MAAM,sBAAsB,CAAA;AACrF,OAAO,EAAE,kBAAkB,EAAkB,MAAM,mBAAmB,CAAA;AAiOtE;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,GAAG,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,MAAM,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9C;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;IAC/C,cAAc,CAAC,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;IACzD,WAAW,CAAC,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;IACnD,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAA;CACtD;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,UAAQ,EACf,iBAAiB,UAAQ,EACzB,OAAO,GAAE,MAAM,GAAG,IAAW,EAC7B,OAAO,UAAQ,EACf,WAAW,CAAC,EAAE,mBAAmB,EACjC,YAAY,CAAC,EAAE,mBAAmB,GACjC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAO3B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EAIpB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,qBAAqB,EAA2B,MAAM,sBAAsB,CAAA;AACrF,OAAO,EAAE,kBAAkB,EAAkB,MAAM,mBAAmB,CAAA;AAiOtE;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,GAAG,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1C,MAAM,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9C;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;IAC/C,cAAc,CAAC,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;IACzD,WAAW,CAAC,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;IACnD,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAA;CACtD;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,UAAQ,EACf,iBAAiB,UAAQ,EACzB,OAAO,GAAE,MAAM,GAAG,IAAW,EAC7B,OAAO,UAAQ,EACf,WAAW,CAAC,EAAE,mBAAmB,EACjC,YAAY,CAAC,EAAE,mBAAmB,GACjC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,GAAG,IAAI,CAwYnD;AAo8ID,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,wBAAwB,GAAG,IAAI,CAoGjC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CA4B7D;AAID;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,GAAG,MAAM,GAAG,IAAI,CAcrF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CASzF;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,GAChE,MAAM,CAYR"}
|