diff --git a/.changeset/lemon-plums-visit.md b/.changeset/lemon-plums-visit.md new file mode 100644 index 000000000..a5736b6bf --- /dev/null +++ b/.changeset/lemon-plums-visit.md @@ -0,0 +1,5 @@ +--- +"@marko/runtime-tags": patch +--- + +Ensure increment and decrement assignments don't prune change handler bindings diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/.name-cache.json b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/.name-cache.json new file mode 100644 index 000000000..bdc959dd2 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/.name-cache.json @@ -0,0 +1,16 @@ +{ + "vars": { + "props": { + "$_": "o", + "$init": "t", + "$$pattern2": "n", + "$$bar": "r", + "$$foo2__script": "m", + "$$foo2": "e", + "$$foo": "a", + "$$foo__OR__fooChange__script": "c", + "$$foo__OR__fooChange": "_", + "$$fooChange2": "f" + } + } +} diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/csr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/csr-sanitized.expected.md new file mode 100644 index 000000000..f1ad6884a --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/csr-sanitized.expected.md @@ -0,0 +1,39 @@ +# Render +```html + +``` + + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` + + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` + + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/csr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/csr.expected.md new file mode 100644 index 000000000..8b5c089ef --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/csr.expected.md @@ -0,0 +1,59 @@ +# Render +```html + +``` + +# Mutations +``` +INSERT button +``` + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` + +# Mutations +``` +UPDATE button/#text2 "0" => "1" +UPDATE button/#text0 "0" => "1" +``` + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` + +# Mutations +``` +UPDATE button/#text2 "1" => "2" +UPDATE button/#text0 "1" => "2" +``` + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` + +# Mutations +``` +UPDATE button/#text2 "2" => "3" +UPDATE button/#text0 "2" => "3" +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/dom.expected/template.hydrate.js new file mode 100644 index 000000000..181e825c4 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/dom.expected/template.hydrate.js @@ -0,0 +1,26 @@ +// size: 330 (min) 206 (brotli) +const $pattern2 = _._const(4, ($scope, $pattern) => { + ($foo2($scope, $pattern.foo), $fooChange2($scope, $pattern.fooChange)); + }), + $bar = _._let(3, ($scope, bar) => { + (_._text($scope[2], bar), + $pattern2($scope, { foo: bar, fooChange: $foo($scope) })); + }), + $foo__OR__fooChange__script = _._script( + "a1", + ($scope, { 5: foo, 6: $fooChange }) => + _._on($scope[0], "click", function () { + $fooChange(++foo); + }), + ), + $foo__OR__fooChange = _._or(7, $foo__OR__fooChange__script), + $foo2 = _._const(5, ($scope, foo) => { + (_._text($scope[1], foo), $foo__OR__fooChange($scope)); + }), + $fooChange2 = _._const(6, $foo__OR__fooChange); +function $foo($scope) { + return function (v) { + $bar($scope, v); + }; +} +(_._resume("a0", $foo), init()); diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/dom.expected/template.js new file mode 100644 index 000000000..0d3c27180 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/dom.expected/template.js @@ -0,0 +1,36 @@ +export const $template = ""; +export const $walks = /* get, next(1), replace, over(2), replace, out(1) */" D%c%l"; +import * as _ from "@marko/runtime-tags/debug/dom"; +const $pattern2 = /* @__PURE__ */_._const("$pattern", ($scope, $pattern) => { + $foo2($scope, $pattern.foo); + $fooChange2($scope, $pattern.fooChange); +}); +const $bar = /* @__PURE__ */_._let("bar/3", ($scope, bar) => { + _._text($scope["#text/2"], bar); + $pattern2($scope, { + foo: bar, + fooChange: $foo($scope) + }); +}); +export function $setup($scope) { + $bar($scope, 0); +} +const $foo__OR__fooChange__script = _._script("__tests__/template.marko_0_foo_$fooChange", ($scope, { + foo, + $fooChange +}) => _._on($scope["#button/0"], "click", function () { + $fooChange(++foo); +})); +const $foo__OR__fooChange = /* @__PURE__ */_._or(7, $foo__OR__fooChange__script); +const $foo2 = /* @__PURE__ */_._const("foo", ($scope, foo) => { + _._text($scope["#text/1"], foo); + $foo__OR__fooChange($scope); +}); +const $fooChange2 = /* @__PURE__ */_._const("$fooChange", $foo__OR__fooChange); +function $foo($scope) { + return function (v) { + $bar($scope, v); + }; +} +_._resume("__tests__/template.marko_0/foo", $foo); +export default /* @__PURE__ */_._template("__tests__/template.marko", $template, $walks, $setup); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/html.expected/template.js new file mode 100644 index 000000000..d0d847c4f --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/html.expected/template.js @@ -0,0 +1,24 @@ +import * as _ from "@marko/runtime-tags/debug/html"; +export default _._template("__tests__/template.marko", input => { + const $scope0_id = _._scope_id(); + let bar = 0; + const { + foo, + fooChange: $fooChange + } = { + foo: bar, + fooChange: _._resume(function (v) { + bar = v; + }, "__tests__/template.marko_0/foo", $scope0_id) + }; + _._html(`${_._el_resume($scope0_id, "#button/0")}`); + _._script($scope0_id, "__tests__/template.marko_0_foo_$fooChange"); + _._scope($scope0_id, { + foo, + $fooChange + }, "__tests__/template.marko", 0, { + foo: "2:9", + $fooChange: "9:20" + }); + _._resume_branch($scope0_id); +}); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/resume-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/resume-sanitized.expected.md new file mode 100644 index 000000000..f1ad6884a --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/resume-sanitized.expected.md @@ -0,0 +1,39 @@ +# Render +```html + +``` + + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` + + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` + + +# Render +```js +container.querySelector("button").click(); +``` +```html + +``` diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/resume.expected.md b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/resume.expected.md new file mode 100644 index 000000000..448574075 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/resume.expected.md @@ -0,0 +1,147 @@ +# Render +```html + + + + + + + + +``` + + +# Render +```js +container.querySelector("button").click(); +``` +```html + + + + + + + + +``` + +# Mutations +``` +UPDATE html/body/button/#text2 "0" => "1" +UPDATE html/body/button/#text0 "0" => "1" +``` + +# Render +```js +container.querySelector("button").click(); +``` +```html + + + + + + + + +``` + +# Mutations +``` +UPDATE html/body/button/#text2 "1" => "2" +UPDATE html/body/button/#text0 "1" => "2" +``` + +# Render +```js +container.querySelector("button").click(); +``` +```html + + + + + + + + +``` + +# Mutations +``` +UPDATE html/body/button/#text2 "2" => "3" +UPDATE html/body/button/#text0 "2" => "3" +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/ssr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/ssr-sanitized.expected.md new file mode 100644 index 000000000..d4c5ce7fd --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/ssr-sanitized.expected.md @@ -0,0 +1,6 @@ +# Render End +```html + +``` diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/ssr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/ssr.expected.md new file mode 100644 index 000000000..014a49bea --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/__snapshots__/ssr.expected.md @@ -0,0 +1,51 @@ +# Write +```html + +``` + +# Render End +```html + + + + + + + + +``` + +# Mutations +``` +INSERT html +INSERT html/head +INSERT html/body +INSERT html/body/button +INSERT html/body/button/#text0 +INSERT html/body/button/#comment0 +INSERT html/body/button/#text1 +INSERT html/body/button/#comment1 +INSERT html/body/button/#text2 +INSERT html/body/button/#comment2 +INSERT html/body/#comment +INSERT html/body/script +INSERT html/body/script/#text +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/template.marko b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/template.marko new file mode 100644 index 000000000..379d187f6 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/template.marko @@ -0,0 +1,10 @@ +let/bar=0 +const/{ foo }={ + foo: bar, + fooChange(v) { + bar = v; + } +} + +button onClick() { foo++ } + -- ${foo}:${bar} diff --git a/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/test.ts b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/test.ts new file mode 100644 index 000000000..d7fdaf5d2 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/assign-destructured-increment/test.ts @@ -0,0 +1,5 @@ +export const steps = [{}, click, click, click]; + +function click(container: Element) { + container.querySelector("button")!.click(); +} diff --git a/packages/runtime-tags/src/translator/util/references.ts b/packages/runtime-tags/src/translator/util/references.ts index 641ed98fb..dbe87dd72 100644 --- a/packages/runtime-tags/src/translator/util/references.ts +++ b/packages/runtime-tags/src/translator/util/references.ts @@ -1730,10 +1730,9 @@ function resolveReferencedBindings( const rootBindings = getRootBindings(reads); for (const read of reads) { let { binding } = read; - if (read.node) { - const exprReference = ((read.node.extra ??= {}).read ??= + if (read.node && read.node.extra?.assignmentTo !== binding) { + ({ binding } = (read.node.extra ??= {}).read ??= resolveExpressionReference(rootBindings, binding)); - ({ binding } = (read.node.extra ??= {}).read = exprReference); } referencedBindings = bindingUtil.add(referencedBindings, binding); }