@llui/vite-plugin 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/collect-deps.d.ts +21 -0
- package/dist/collect-deps.d.ts.map +1 -1
- package/dist/collect-deps.js +59 -13
- package/dist/collect-deps.js.map +1 -1
- package/dist/diagnostics.d.ts +7 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +302 -60
- package/dist/diagnostics.js.map +1 -1
- package/dist/index.d.ts +40 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +136 -9
- package/dist/index.js.map +1 -1
- package/dist/transform.d.ts +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +20 -9
- package/dist/transform.js.map +1 -1
- package/package.json +1 -1
package/dist/transform.js
CHANGED
|
@@ -105,7 +105,7 @@ const PROP_KEYS = new Set([
|
|
|
105
105
|
* string. With resolution, we see that `cls` is an arrow and emit a
|
|
106
106
|
* binding exactly as if the arrow had been inlined.
|
|
107
107
|
*
|
|
108
|
-
*
|
|
108
|
+
* Lifetime rules:
|
|
109
109
|
* - Only single-binding `const`/`let`/`var` declarations with an
|
|
110
110
|
* initializer are considered. No destructuring, no multi-declarator
|
|
111
111
|
* statements (too easy to get wrong without a type checker).
|
|
@@ -172,7 +172,7 @@ function resolveKey(key, kind) {
|
|
|
172
172
|
return 'class';
|
|
173
173
|
return key;
|
|
174
174
|
}
|
|
175
|
-
export function transformLlui(source, _filename, devMode = false, mcpPort = 5200) {
|
|
175
|
+
export function transformLlui(source, _filename, devMode = false, mcpPort = 5200, verbose = false) {
|
|
176
176
|
const sourceFile = ts.createSourceFile('input.ts', source, ts.ScriptTarget.Latest, true);
|
|
177
177
|
// Find the @llui/dom import
|
|
178
178
|
const imp = findLluiImport(sourceFile);
|
|
@@ -189,6 +189,13 @@ export function transformLlui(source, _filename, devMode = false, mcpPort = 5200
|
|
|
189
189
|
// won't match. Files without component() get FULL_MASK on all bindings.
|
|
190
190
|
const fileHasComponent = hasComponentDef(sourceFile, lluiImport);
|
|
191
191
|
const fieldBits = fileHasComponent ? collectDeps(source) : new Map();
|
|
192
|
+
if (verbose && fileHasComponent) {
|
|
193
|
+
const pairs = [...fieldBits.entries()]
|
|
194
|
+
.map(([path, bit]) => `${path}=${bit === -1 ? 'FULL' : bit}`)
|
|
195
|
+
.join(', ');
|
|
196
|
+
console.info(`[llui] ${_filename}: ${fieldBits.size} reactive path${fieldBits.size === 1 ? '' : 's'}` +
|
|
197
|
+
(pairs.length > 0 ? ` — ${pairs}` : ''));
|
|
198
|
+
}
|
|
192
199
|
// Identifier names bound to the View<S,M> helpers parameter of a `view` callback.
|
|
193
200
|
// When the user writes `h.text(...)` / `h.show(...)` / `h.each(...)`, the
|
|
194
201
|
// compiler treats the call as if it were a bare import call.
|
|
@@ -551,9 +558,11 @@ function isViewTypeReference(t) {
|
|
|
551
558
|
const VIEW_HELPER_PRIMITIVES = new Set([
|
|
552
559
|
'show',
|
|
553
560
|
'branch',
|
|
561
|
+
'scope',
|
|
554
562
|
'each',
|
|
555
563
|
'text',
|
|
556
564
|
'memo',
|
|
565
|
+
'sample',
|
|
557
566
|
'selector',
|
|
558
567
|
'ctx',
|
|
559
568
|
'slice',
|
|
@@ -877,11 +886,12 @@ function tryInjectTextMask(node, lluiImport, viewHelperNames, viewHelperAliases,
|
|
|
877
886
|
function tryInjectStructuralMask(node, viewHelperNames, viewHelperAliases, fieldBits, f) {
|
|
878
887
|
if (fieldBits.size === 0)
|
|
879
888
|
return null;
|
|
880
|
-
// Match each(), branch(), show() — bare, aliased, or member-call
|
|
889
|
+
// Match each(), branch(), scope(), show() — bare, aliased, or member-call
|
|
881
890
|
const isEach = isHelperCall(node.expression, 'each', viewHelperNames, viewHelperAliases);
|
|
882
891
|
const isBranch = isHelperCall(node.expression, 'branch', viewHelperNames, viewHelperAliases);
|
|
892
|
+
const isScope = isHelperCall(node.expression, 'scope', viewHelperNames, viewHelperAliases);
|
|
883
893
|
const isShow = isHelperCall(node.expression, 'show', viewHelperNames, viewHelperAliases);
|
|
884
|
-
if (!isEach && !isBranch && !isShow)
|
|
894
|
+
if (!isEach && !isBranch && !isScope && !isShow)
|
|
885
895
|
return null;
|
|
886
896
|
const optsArg = node.arguments[0];
|
|
887
897
|
if (!optsArg || !ts.isObjectLiteralExpression(optsArg))
|
|
@@ -894,8 +904,9 @@ function tryInjectStructuralMask(node, viewHelperNames, viewHelperAliases, field
|
|
|
894
904
|
return null;
|
|
895
905
|
}
|
|
896
906
|
}
|
|
897
|
-
// Find the driving accessor property: items/on/when
|
|
898
|
-
|
|
907
|
+
// Find the driving accessor property: items / on / when
|
|
908
|
+
// each → 'items', branch/scope → 'on', show → 'when'
|
|
909
|
+
const driverProp = isEach ? 'items' : isBranch || isScope ? 'on' : 'when';
|
|
899
910
|
let driverAccessor = null;
|
|
900
911
|
for (const prop of optsArg.properties) {
|
|
901
912
|
if (ts.isPropertyAssignment(prop) &&
|
|
@@ -1749,7 +1760,7 @@ function _containsSelectorBind(node) {
|
|
|
1749
1760
|
}
|
|
1750
1761
|
function containsStructuralCall(node) {
|
|
1751
1762
|
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
|
|
1752
|
-
if (['each', 'branch', 'show', 'child', 'foreign'].includes(node.expression.text))
|
|
1763
|
+
if (['each', 'branch', 'scope', 'show', 'child', 'foreign'].includes(node.expression.text))
|
|
1753
1764
|
return true;
|
|
1754
1765
|
}
|
|
1755
1766
|
return ts.forEachChild(node, containsStructuralCall) ?? false;
|
|
@@ -1784,7 +1795,7 @@ function computeStructuralMask(configArg, fieldBits) {
|
|
|
1784
1795
|
function walk(node) {
|
|
1785
1796
|
if (ts.isCallExpression(node)) {
|
|
1786
1797
|
const name = ts.isIdentifier(node.expression) ? node.expression.text : '';
|
|
1787
|
-
if (['each', 'branch', 'show'].includes(name) && node.arguments[0]) {
|
|
1798
|
+
if (['each', 'branch', 'scope', 'show'].includes(name) && node.arguments[0]) {
|
|
1788
1799
|
foundStructural = true;
|
|
1789
1800
|
const opts = node.arguments[0];
|
|
1790
1801
|
if (ts.isObjectLiteralExpression(opts)) {
|
|
@@ -2978,7 +2989,7 @@ function isPerItemCall(node) {
|
|
|
2978
2989
|
return ts.isArrowFunction(arg) || ts.isFunctionExpression(arg);
|
|
2979
2990
|
}
|
|
2980
2991
|
// Matches: item.FIELD — the item-proxy shorthand equivalent of item(t => t.FIELD).
|
|
2981
|
-
//
|
|
2992
|
+
// Lifetime-checked: the `item` identifier must resolve to a parameter of an
|
|
2982
2993
|
// `each({ render })` callback. Without this check, plain
|
|
2983
2994
|
// `arr.map((item) => item.field)` outside each() would be rewritten as a
|
|
2984
2995
|
// per-item binding and crash at runtime with "accessor is not a function"
|