diff --git a/.changeset/giant-ligers-hide.md b/.changeset/giant-ligers-hide.md new file mode 100644 index 0000000000..34f7060c18 --- /dev/null +++ b/.changeset/giant-ligers-hide.md @@ -0,0 +1,5 @@ +--- +"@marko/runtime-tags": patch +--- + +Fix issue reading custom tag var closures. diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/.name-cache.json b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/.name-cache.json new file mode 100644 index 0000000000..f3e335d987 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/.name-cache.json @@ -0,0 +1,11 @@ +{ + "vars": { + "props": { + "$_$": "r", + "$init": "t", + "$_value": "a", + "$_count$myTag_content_effect": "e", + "$_count$myTag_content": "n" + } + } +} diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/csr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/csr-sanitized.expected.md new file mode 100644 index 0000000000..cf47116d6e --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/csr-sanitized.expected.md @@ -0,0 +1,36 @@ +# Render {} +```html + +``` + + +# Render +container.querySelector("button").click() + +```html + +``` + + +# Render +container.querySelector("button").click() + +```html + +``` + + +# Render +container.querySelector("button").click() + +```html + +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/csr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/csr.expected.md new file mode 100644 index 0000000000..598ac66815 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/csr.expected.md @@ -0,0 +1,72 @@ +# Render {} +```html + + + + + +``` + +# Mutations +``` +inserted #comment0, #comment1, button2, #comment3, #comment4 +``` + + +# Render +container.querySelector("button").click() + +```html + + + + + +``` + +# Mutations +``` +button2/#text0: "0" => "1" +``` + + +# Render +container.querySelector("button").click() + +```html + + + + + +``` + +# Mutations +``` +button2/#text0: "1" => "2" +``` + + +# Render +container.querySelector("button").click() + +```html + + + + + +``` + +# Mutations +``` +button2/#text0: "2" => "3" +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/custom-tag.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/custom-tag.js new file mode 100644 index 0000000000..a4691b8557 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/custom-tag.js @@ -0,0 +1,8 @@ +export const _template_ = "
"; +export const _walks_ = /* get, over(1) */" b"; +export const _setup_ = () => {}; +import * as _$ from "@marko/runtime-tags/debug/dom"; +export const _style_ = /* @__PURE__ */_$.value("style", (_scope, style) => _$.styleAttr(_scope["#div/0"], style)); +export const _input_ = /* @__PURE__ */_$.value("input", (_scope, input) => _style_(_scope, input.style)); +export const _params__ = /* @__PURE__ */_$.value("_params_", (_scope, _params_) => _input_(_scope, _params_[0])); +export default /* @__PURE__ */_$.createTemplate("__tests__/tags/custom-tag.marko", _template_, _walks_, _setup_, void 0, () => _params__); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/my-let.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/my-let.js new file mode 100644 index 0000000000..888ad0311c --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/my-let.js @@ -0,0 +1,17 @@ +export const _template_ = ""; +export const _walks_ = ""; +import * as _$ from "@marko/runtime-tags/debug/dom"; +const _value = /* @__PURE__ */_$.state("value", (_scope, value) => _$.tagVarSignal(_scope, value), () => _$.tagVarSignal); +export const _input_value_ = /* @__PURE__ */_$.value("input_value", (_scope, input_value) => _value(_scope, input_value), () => _value); +export const _input_ = /* @__PURE__ */_$.value("input", (_scope, input) => _input_value_(_scope, input.value), () => _input_value_); +export const _params__ = /* @__PURE__ */_$.value("_params_", (_scope, _params_) => _input_(_scope, _params_[0]), () => _input_); +export function _setup_(_scope) { + _$.setTagVarChange(_scope, _valueChange(_scope)); +} +function _valueChange(_scope) { + return _new_value => { + _value(_scope, _new_value); + }; +} +_$.register("__tests__/tags/my-let.marko_0/valueChange", _valueChange); +export default /* @__PURE__ */_$.createTemplate("__tests__/tags/my-let.marko", _template_, _walks_, _setup_, void 0, () => _params__); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/my-tag.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/my-tag.js new file mode 100644 index 0000000000..cf77bb3d7a --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/tags/my-tag.js @@ -0,0 +1,10 @@ +export const _template_ = ""; +export const _walks_ = /* replace, over(1) */"D%bD"; +export const _setup_ = () => {}; +import * as _$ from "@marko/runtime-tags/debug/dom"; +const _inputContent_input = _$.dynamicTagAttrs("#text/0"); +const _dynamicTagName = /* @__PURE__ */_$.conditional("#text/0", _scope => _inputContent_input(_scope, () => ({})), () => _inputContent_input); +export const _input_content_ = /* @__PURE__ */_$.value("input_content", (_scope, input_content) => _dynamicTagName(_scope, input_content), () => _dynamicTagName); +export const _input_ = /* @__PURE__ */_$.value("input", (_scope, input) => _input_content_(_scope, input.content), () => _input_content_); +export const _params__ = /* @__PURE__ */_$.value("_params_", (_scope, _params_) => _input_(_scope, _params_[0]), () => _input_); +export default /* @__PURE__ */_$.createTemplate("__tests__/tags/my-tag.marko", _template_, _walks_, _setup_, void 0, () => _params__); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/template.hydrate.js new file mode 100644 index 0000000000..1c4cb58d85 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/template.hydrate.js @@ -0,0 +1,36 @@ +// size: 490 (min) 265 (brotli) +const _value = _$.state( + 3, + (_scope, value) => _$.tagVarSignal(_scope, value), + () => _$.tagVarSignal, +); +_$.register("a0", function (_scope) { + return (_new_value) => { + _value(_scope, _new_value); + }; +}), + _$.dynamicTagAttrs(0); +const _count$myTag_content_effect = _$.effect( + "c0", + (_scope, { _: { 2: count } }) => + _$.on(_scope[0], "click", function () { + _$.tagVarSignalChange(_scope._[0], count + 1); + }), + ), + _count$myTag_content = _$.registerSubscriber( + "c1", + _$.dynamicClosure(2, (_scope, count) => { + _$.data(_scope[1], count), _count$myTag_content_effect(_scope); + }), + ); +_$.register( + "c2", + _$.createRendererWithOwner("", " D ", void 0, () => [ + _count$myTag_content, + ]), +), + _$.registerBoundSignal( + "c3", + _$.value(2, 0, () => _$.dynamicSubscribers(2)), + ), + init(); diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/template.js new file mode 100644 index 0000000000..d30c612a5b --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/dom.expected/template.js @@ -0,0 +1,26 @@ +export const _template_ = `${_myLet_template}${_myTag_template}`; +export const _walks_ = /* beginChild, _myLet_walks, endChild, beginChild, _myTag_walks, endChild */`D/${_myLet_walks}&/${_myTag_walks}&D`; +import { _setup_ as _myLet, _input_value_ as _myLet_input_value, _template_ as _myLet_template, _walks_ as _myLet_walks } from "./tags/my-let.marko"; +import * as _$ from "@marko/runtime-tags/debug/dom"; +import { _setup_ as _myTag, _input_content_ as _myTag_input_content, _template_ as _myTag_template, _walks_ as _myTag_walks } from "./tags/my-tag.marko"; +const _count$myTag_content_effect = _$.effect("__tests__/template.marko_1_count", (_scope, { + _: { + count + } +}) => _$.on(_scope["#button/0"], "click", function () { + _$.tagVarSignalChange(_scope._["#childScope/0"], count + 1), count; +})); +const _count$myTag_content = _$.registerSubscriber("__tests__/template.marko_1_count/subscriber", /* @__PURE__ */_$.dynamicClosure("count", (_scope, count) => { + _$.data(_scope["#text/1"], count); + _count$myTag_content_effect(_scope); +})); +const _myTag_content = _$.register("__tests__/template.marko_1_renderer", /* @__PURE__ */_$.createRendererWithOwner("", /* get, next(1), get */" D ", void 0, () => [_count$myTag_content])); +const _count = _$.registerBoundSignal("__tests__/template.marko_0_count/var", /* @__PURE__ */_$.value("count", 0, () => _$.dynamicSubscribers("count"))); +export function _setup_(_scope) { + _$.setTagVar(_scope, "#childScope/0", _count); + _myLet(_scope["#childScope/0"]); + _myTag(_scope["#childScope/1"]); + _myLet_input_value(_scope["#childScope/0"], 0); + _myTag_input_content(_scope["#childScope/1"], _myTag_content(_scope)); +} +export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _template_, _walks_, _setup_); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/custom-tag.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/custom-tag.js new file mode 100644 index 0000000000..c53ae3d620 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/custom-tag.js @@ -0,0 +1,9 @@ +import * as _$ from "@marko/runtime-tags/debug/html"; +const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => { + const _scope0_id = _$.nextScopeId(); + const { + style + } = input; + _$.write(`${_$.markResumeNode(_scope0_id, "#div/0")}`); +}); +export default /* @__PURE__ */_$.createTemplate("__tests__/tags/custom-tag.marko", _renderer); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/my-let.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/my-let.js new file mode 100644 index 0000000000..8e9f5fe0eb --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/my-let.js @@ -0,0 +1,14 @@ +import * as _$ from "@marko/runtime-tags/debug/html"; +const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => { + const _scope0_id = _$.nextScopeId(); + const value = input.value; + const _return = value; + _$.writeScope(_scope0_id, { + "/": _tagVar, + "@": _$.register(_new_value => { + value = _new_value; + }, "__tests__/tags/my-let.marko_0/valueChange", _scope0_id) + }); + return _return; +}); +export default /* @__PURE__ */_$.createTemplate("__tests__/tags/my-let.marko", _renderer); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/my-tag.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/my-tag.js new file mode 100644 index 0000000000..39df8eb72f --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/tags/my-tag.js @@ -0,0 +1,12 @@ +import * as _$ from "@marko/runtime-tags/debug/html"; +const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => { + const _scope0_id = _$.nextScopeId(); + const _dynamicScope = _$.peekNextScope(); + _$.dynamicTagInput(_dynamicScope, input.content, {}); + _$.write(_$.markResumeControlEnd(_scope0_id, "#text/0")); + _$.writeScope(_scope0_id, { + "#text/0!": _$.writeExistingScope(_dynamicScope), + "#text/0(": _$.normalizeDynamicRenderer(input.content) + }); +}); +export default /* @__PURE__ */_$.createTemplate("__tests__/tags/my-tag.marko", _renderer); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/template.js new file mode 100644 index 0000000000..10d1c77cb8 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/html.expected/template.js @@ -0,0 +1,28 @@ +import _myLet from "./tags/my-let.marko"; +import * as _$ from "@marko/runtime-tags/debug/html"; +import _myTag from "./tags/my-tag.marko"; +const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => { + const _scope0_id = _$.nextScopeId(); + const _childScope = _$.peekNextScope(); + const count = _myLet({ + value: 0 + }, _$.register(() => {}, "__tests__/template.marko_0_count/var", _scope0_id)); + const _childScope2 = _$.peekNextScope(); + _myTag({ + content: _$.register(/* @__PURE__ */_$.createRenderer(() => { + const _scope1_id = _$.nextScopeId(); + _$.write(`${_$.markResumeNode(_scope1_id, "#button/0")}`); + _$.writeEffect(_scope1_id, "__tests__/template.marko_1_count/subscriber"); + _$.writeEffect(_scope1_id, "__tests__/template.marko_1_count"); + _$.writeScope(_scope1_id, { + "_": _$.ensureScopeWithId(_scope0_id) + }); + }), "__tests__/template.marko_1_renderer", _scope0_id) + }); + _$.writeScope(_scope0_id, { + "count": count, + "#childScope/0": _$.writeExistingScope(_childScope), + "#childScope/1": _$.writeExistingScope(_childScope2) + }); +}); +export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _renderer); \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/resume-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/resume-sanitized.expected.md new file mode 100644 index 0000000000..cf47116d6e --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/resume-sanitized.expected.md @@ -0,0 +1,36 @@ +# Render {} +```html + +``` + + +# Render +container.querySelector("button").click() + +```html + +``` + + +# Render +container.querySelector("button").click() + +```html + +``` + + +# Render +container.querySelector("button").click() + +```html + +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/resume.expected.md b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/resume.expected.md new file mode 100644 index 0000000000..1ce9c6d7c4 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/resume.expected.md @@ -0,0 +1,105 @@ +# Render {} +```html + + + + + + + + + +``` + +# Mutations +``` +removed #document/html0/body1/#comment0 before #document/html0 +inserted #document/html0/body1/#comment0 +``` + + +# Render +container.querySelector("button").click() + +```html + + + + + + + + + +``` + +# Mutations +``` +#document/html0/body1/button1/#text0: "0" => "1" +``` + + +# Render +container.querySelector("button").click() + +```html + + + + + + + + + +``` + +# Mutations +``` +#document/html0/body1/button1/#text0: "1" => "2" +``` + + +# Render +container.querySelector("button").click() + +```html + + + + + + + + + +``` + +# Mutations +``` +#document/html0/body1/button1/#text0: "2" => "3" +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/ssr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/ssr-sanitized.expected.md new file mode 100644 index 0000000000..28c35d3a53 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/ssr-sanitized.expected.md @@ -0,0 +1,6 @@ +# Render "End" +```html + +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/ssr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/ssr.expected.md new file mode 100644 index 0000000000..effa7f24de --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/__snapshots__/ssr.expected.md @@ -0,0 +1,37 @@ +# Write + + + +# Render "End" +```html + + + + + + + + + +``` + +# Mutations +``` +inserted #document/#comment0 +inserted #document/html1 +inserted #document/html1/head0 +inserted #document/html1/body1 +inserted #document/html1/body1/button0 +inserted #document/html1/body1/button0/#text0 +inserted #document/html1/body1/button0/#comment1 +inserted #document/html1/body1/#comment1 +inserted #document/html1/body1/#comment2 +inserted #document/html1/body1/script3 +inserted #document/html1/body1/script3/#text0 +``` \ No newline at end of file diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/tags/my-let.marko b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/tags/my-let.marko new file mode 100644 index 0000000000..0359d021e0 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/tags/my-let.marko @@ -0,0 +1,3 @@ +let/value=input.value + +return:=value diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/tags/my-tag.marko b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/tags/my-tag.marko new file mode 100644 index 0000000000..f684b436ac --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/tags/my-tag.marko @@ -0,0 +1 @@ +${input.content} diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/template.marko b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/template.marko new file mode 100644 index 0000000000..09a9f8d83e --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/template.marko @@ -0,0 +1,3 @@ +my-let/count=0 +my-tag + button onClick() { count++ } -- ${count} diff --git a/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/test.ts b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/test.ts new file mode 100644 index 0000000000..d7fdaf5d2d --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/cross-tag-closure/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/visitors/tag/custom-tag.ts b/packages/runtime-tags/src/translator/visitors/tag/custom-tag.ts index 88f615e7e8..60c643e0ba 100644 --- a/packages/runtime-tags/src/translator/visitors/tag/custom-tag.ts +++ b/packages/runtime-tags/src/translator/visitors/tag/custom-tag.ts @@ -300,9 +300,9 @@ function translateDOM(tag: t.NodePath