fix: hoisting computed member expressions

This commit is contained in:
dpiercey 2025-01-14 18:52:10 -07:00 committed by Dylan Piercey
parent 172247289a
commit d9cc4e723a
14 changed files with 567 additions and 0 deletions

View File

@ -0,0 +1,5 @@
---
"@marko/runtime-tags": patch
---
Fix issue with attempting to hoist a member expression that was a computed identifier.

View File

@ -0,0 +1,14 @@
{
"vars": {
"props": {
"$_$": "t",
"$init": "a",
"$_foo": "o",
"$_expr_items_index_effect": "e",
"$_expr_items_index": "n",
"$_index": "m",
"$_items_": "s",
"$_items": "c"
}
}
}

View File

@ -0,0 +1,76 @@
# Render {}
```html
<div>
a
</div>
<div>
a
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
b
</div>
<div>
c
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
c
</div>
<div>
c
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
</div>
<div>
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
</div>
<div>
</div>
<button>
Update
</button>
```

View File

@ -0,0 +1,103 @@
# Render {}
```html
<div>
a
</div>
<div>
a
</div>
<button>
Update
</button>
```
# Mutations
```
inserted div0, div1, button2
```
# Render
container.querySelector("button").click()
```html
<div>
b
</div>
<div>
c
</div>
<button>
Update
</button>
```
# Mutations
```
div0/#text0: "a" => "b"
div1/#text0: "a" => "c"
```
# Render
container.querySelector("button").click()
```html
<div>
c
</div>
<div>
c
</div>
<button>
Update
</button>
```
# Mutations
```
div0/#text0: "b" => "c"
```
# Render
container.querySelector("button").click()
```html
<div>
</div>
<div>
</div>
<button>
Update
</button>
```
# Mutations
```
div0/#text0: "c" => ""
div1/#text0: "c" => ""
```
# Render
container.querySelector("button").click()
```html
<div>
</div>
<div>
</div>
<button>
Update
</button>
```
# Mutations
```
```

View File

@ -0,0 +1,21 @@
// size: 292 (min) 191 (brotli)
const _expr_items_index_effect = _$.effect(
"a0",
(_scope, { 3: items, 5: index }) =>
_$.on(_scope[2], "click", function () {
const newItems = items.slice(1);
_items(_scope, newItems), _index(_scope, (index + 1) % newItems.length);
}),
),
_expr_items_index = _$.intersection(2, (_scope) => {
const { 3: items, 5: index } = _scope;
_$.data(_scope[1], items[index]), _expr_items_index_effect(_scope);
}),
_index = _$.state(5, 0, () => _expr_items_index),
_items_ = _$.value(4, (_scope, items_0) => _$.data(_scope[0], items_0)),
_items = _$.state(
3,
(_scope, items) => _items_(_scope, items?.[0]),
() => _expr_items_index,
);
init();

View File

@ -0,0 +1,27 @@
export const _template_ = "<div> </div><div> </div><button>Update</button>";
export const _walks_ = /* next(1), get, out(1), next(1), get, out(1), get, over(1) */"D lD l b";
import * as _$ from "@marko/runtime-tags/debug/dom";
const _expr_items_index_effect = _$.effect("__tests__/template.marko_0_items_index", (_scope, {
items,
index
}) => _$.on(_scope["#button/2"], "click", function () {
const newItems = items.slice(1);
_items(_scope, newItems);
_index(_scope, (index + 1) % newItems.length);
}));
const _expr_items_index = /* @__PURE__ */_$.intersection(2, _scope => {
const {
items,
index
} = _scope;
_$.data(_scope["#text/1"], items[index]);
_expr_items_index_effect(_scope);
});
const _index = /* @__PURE__ */_$.state("index", 0, () => _expr_items_index);
const _items_ = /* @__PURE__ */_$.value("items_0", (_scope, items_0) => _$.data(_scope["#text/0"], items_0));
const _items = /* @__PURE__ */_$.state("items", (_scope, items) => _items_(_scope, items?.[0]), () => _expr_items_index);
export function _setup_(_scope) {
_items(_scope, ["a", "b", "c"]);
_index(_scope, 0);
}
export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _template_, _walks_, _setup_);

View File

@ -0,0 +1,13 @@
import * as _$ from "@marko/runtime-tags/debug/html";
const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
const _scope0_id = _$.nextScopeId();
const items = ["a", "b", "c"];
const index = 0;
_$.write(`<div>${_$.escapeXML(items[0])}${_$.markResumeNode(_scope0_id, "#text/0")}</div><div>${_$.escapeXML(items[index])}${_$.markResumeNode(_scope0_id, "#text/1")}</div><button>Update</button>${_$.markResumeNode(_scope0_id, "#button/2")}`);
_$.writeEffect(_scope0_id, "__tests__/template.marko_0_items_index");
_$.writeScope(_scope0_id, {
"items": items,
"index": index
});
});
export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _renderer);

View File

@ -0,0 +1,76 @@
# Render {}
```html
<div>
a
</div>
<div>
a
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
b
</div>
<div>
c
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
c
</div>
<div>
c
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
</div>
<div>
</div>
<button>
Update
</button>
```
# Render
container.querySelector("button").click()
```html
<div>
</div>
<div>
</div>
<button>
Update
</button>
```

View File

@ -0,0 +1,158 @@
# Render {}
```html
<html>
<head />
<body>
<div>
a
<!--M_*0 #text/0-->
</div>
<div>
a
<!--M_*0 #text/1-->
</div>
<button>
Update
</button>
<!--M_*0 #button/2-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.a={0:{items:["a","b","c"],index:0}}),0,"__tests__/template.marko_0_items_index",0];M._.w()
</script>
</body>
</html>
```
# Mutations
```
```
# Render
container.querySelector("button").click()
```html
<html>
<head />
<body>
<div>
b
<!--M_*0 #text/0-->
</div>
<div>
c
<!--M_*0 #text/1-->
</div>
<button>
Update
</button>
<!--M_*0 #button/2-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.a={0:{items:["a","b","c"],index:0}}),0,"__tests__/template.marko_0_items_index",0];M._.w()
</script>
</body>
</html>
```
# Mutations
```
#document/html0/body1/div0/#text0: "a" => "b"
#document/html0/body1/div1/#text0: "a" => "c"
```
# Render
container.querySelector("button").click()
```html
<html>
<head />
<body>
<div>
c
<!--M_*0 #text/0-->
</div>
<div>
c
<!--M_*0 #text/1-->
</div>
<button>
Update
</button>
<!--M_*0 #button/2-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.a={0:{items:["a","b","c"],index:0}}),0,"__tests__/template.marko_0_items_index",0];M._.w()
</script>
</body>
</html>
```
# Mutations
```
#document/html0/body1/div0/#text0: "b" => "c"
```
# Render
container.querySelector("button").click()
```html
<html>
<head />
<body>
<div>
<!--M_*0 #text/0-->
</div>
<div>
<!--M_*0 #text/1-->
</div>
<button>
Update
</button>
<!--M_*0 #button/2-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.a={0:{items:["a","b","c"],index:0}}),0,"__tests__/template.marko_0_items_index",0];M._.w()
</script>
</body>
</html>
```
# Mutations
```
#document/html0/body1/div0/#text0: "c" => ""
#document/html0/body1/div1/#text0: "c" => ""
```
# Render
container.querySelector("button").click()
```html
<html>
<head />
<body>
<div>
<!--M_*0 #text/0-->
</div>
<div>
<!--M_*0 #text/1-->
</div>
<button>
Update
</button>
<!--M_*0 #button/2-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.a={0:{items:["a","b","c"],index:0}}),0,"__tests__/template.marko_0_items_index",0];M._.w()
</script>
</body>
</html>
```
# Mutations
```
```

View File

@ -0,0 +1,12 @@
# Render "End"
```html
<div>
a
</div>
<div>
a
</div>
<button>
Update
</button>
```

View File

@ -0,0 +1,45 @@
# Write
<div>a<!--M_*0 #text/0--></div><div>a<!--M_*0 #text/1--></div><button>Update</button><!--M_*0 #button/2--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.a={0:{items:["a","b","c"],index:0}}),0,"__tests__/template.marko_0_items_index",0];M._.w()</script>
# Render "End"
```html
<html>
<head />
<body>
<div>
a
<!--M_*0 #text/0-->
</div>
<div>
a
<!--M_*0 #text/1-->
</div>
<button>
Update
</button>
<!--M_*0 #button/2-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.a={0:{items:["a","b","c"],index:0}}),0,"__tests__/template.marko_0_items_index",0];M._.w()
</script>
</body>
</html>
```
# Mutations
```
inserted #document/html0
inserted #document/html0/head0
inserted #document/html0/body1
inserted #document/html0/body1/div0
inserted #document/html0/body1/div0/#text0
inserted #document/html0/body1/div0/#comment1
inserted #document/html0/body1/div1
inserted #document/html0/body1/div1/#text0
inserted #document/html0/body1/div1/#comment1
inserted #document/html0/body1/button2
inserted #document/html0/body1/button2/#text0
inserted #document/html0/body1/#comment3
inserted #document/html0/body1/script4
inserted #document/html0/body1/script4/#text0
```

View File

@ -0,0 +1,11 @@
let/items=["a", "b", "c"]
let/index=0
div -- ${items[0]}
div -- ${items[index]}
button onClick() {
const newItems = items.slice(1);
items = newItems;
index = (index + 1) % newItems.length;
} -- Update

View File

@ -0,0 +1,5 @@
export const steps = [{}, click, click, click, click]
function click(container: Element) {
container.querySelector("button")!.click();
}

View File

@ -915,6 +915,7 @@ function getMemberExpressionPropString(expr: t.MemberExpression) {
case "NumericLiteral":
return "" + expr.property.value;
case "Identifier":
if (expr.computed) return;
return expr.property.name;
}
}