Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic await tag ssr #2458

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eight-poems-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@marko/runtime-tags": patch
---

Add basic ssr try tag.
5 changes: 5 additions & 0 deletions .changeset/few-shirts-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@marko/runtime-tags": patch
---

Add await tag ssr.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const _template_ = "<div><button>Inc</button></div>";
export const _walks_ = /* next(1), get, out(1) */"D l";
import { resolveAfter } from "../../utils/resolve";
import * as _$ from "@marko/runtime-tags/debug/dom";
const _value$await_content3 = /* @__PURE__ */_$.value("value", (_scope, value) => _$.data(_scope["#text/0"], value));
const _params_4$await_content = /* @__PURE__ */_$.value("_params_4", (_scope, _params_4) => _value$await_content3(_scope, _params_4[0]));
const _count$await_content3 = /* @__PURE__ */_$.closure("count", (_scope, count) => _$.data(_scope["#text/1"], count));
const _await_content3 = _$.register("__tests__/template.marko_3_renderer", /* @__PURE__ */_$.createRenderer("Got: <!> <!>", /* over(1), replace, over(2), replace */"b%c%", void 0, () => [_count$await_content3], () => _params_4$await_content));
const _value$await_content2 = /* @__PURE__ */_$.value("value", (_scope, value) => _$.data(_scope["#text/0"], value));
const _params_3$await_content = /* @__PURE__ */_$.value("_params_3", (_scope, _params_3) => _value$await_content2(_scope, _params_3[0]));
const _count$await_content2 = /* @__PURE__ */_$.closure("count", (_scope, count) => _$.data(_scope["#text/1"], count));
const _await_content2 = _$.register("__tests__/template.marko_2_renderer", /* @__PURE__ */_$.createRenderer("Got: <!> <!>", /* over(1), replace, over(2), replace */"b%c%", void 0, () => [_count$await_content2], () => _params_3$await_content));
const _value$await_content = /* @__PURE__ */_$.value("value", (_scope, value) => _$.data(_scope["#text/0"], value));
const _params_2$await_content = /* @__PURE__ */_$.value("_params_2", (_scope, _params_2) => _value$await_content(_scope, _params_2[0]));
const _count$await_content = /* @__PURE__ */_$.closure("count", (_scope, count) => _$.data(_scope["#text/1"], count));
const _await_content = _$.register("__tests__/template.marko_1_renderer", /* @__PURE__ */_$.createRenderer("Got: <!> <!>", /* over(1), replace, over(2), replace */"b%c%", void 0, () => [_count$await_content], () => _params_2$await_content));
const _count_effect = _$.effect("__tests__/template.marko_0_count", (_scope, {
count
}) => _$.on(_scope["#button/0"], "click", function () {
_count(_scope, count + 1), count;
}));
const _count = /* @__PURE__ */_$.state("count", (_scope, count) => _count_effect(_scope), () => _$.intersections([_count$await_content, _count$await_content2, _count$await_content3]));
export function _setup_(_scope) {
_count(_scope, 0);
}
export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _template_, _walks_, _setup_);
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { resolveAfter } from "../../utils/resolve";
import * as _$ from "@marko/runtime-tags/debug/html";
const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
const _scope0_id = _$.nextScopeId();
const count = 0;
_$.write("<div>");
_$.fork(Promise.resolve("a"), value => {
const _scope1_id = _$.nextScopeId();
_$.write(`Got: ${_$.escapeXML(value)} <!>${_$.escapeXML(count)}${_$.markResumeNode(_scope1_id, "#text/1")}`);
_$.writeScope(_scope1_id, {
"_": _$.ensureScopeWithId(_scope0_id)
});
});
_$.fork(resolveAfter("b", 2), value => {
const _scope2_id = _$.nextScopeId();
_$.write(`Got: ${_$.escapeXML(value)} <!>${_$.escapeXML(count)}${_$.markResumeNode(_scope2_id, "#text/1")}`);
_$.writeScope(_scope2_id, {
"_": _$.ensureScopeWithId(_scope0_id)
});
});
_$.fork(resolveAfter("c", 1), value => {
const _scope3_id = _$.nextScopeId();
_$.write(`Got: ${_$.escapeXML(value)} <!>${_$.escapeXML(count)}${_$.markResumeNode(_scope3_id, "#text/1")}`);
_$.writeScope(_scope3_id, {
"_": _$.ensureScopeWithId(_scope0_id)
});
});
_$.write(`<button>Inc</button>${_$.markResumeNode(_scope0_id, "#button/0")}</div>`);
_$.writeEffect(_scope0_id, "__tests__/template.marko_0_count");
_$.writeScope(_scope0_id, {
"count": count
});
});
export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _renderer);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Render "End"
```html
<div>
Got: a 0Got: b 0Got: c 0
<button>
Inc
</button>
</div>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Write
<div>Got: a <!>0<!--M_*1 #text/1--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.b={0:_.a={count:0},1:{_:_.a}})]</script>


# Write
<script>M._.r.push(_=>(_.c={2:{_:_.a}}))</script>


# Write
Got: b <!>0<!--M_*3 #text/1-->Got: c <!>0<!--M_*2 #text/1--><button>Inc</button><!--M_*0 #button/0--></div><script>M._.r.push(_=>(_.d={3:{_:_.a}}),0,"__tests__/template.marko_0_count",0);M._.w()</script>


# Render "End"
```html
<html>
<head />
<body>
<div>
Got: a
<!---->
0
<!--M_*1 #text/1-->
<script>
WALKER_RUNTIME("M")("_");M._.r=[_=&gt;(_.b={0:_.a={count:0},1:{_:_.a}})]
</script>
<script>
M._.r.push(_=&gt;(_.c={2:{_:_.a}}))
</script>
Got: b
<!---->
0
<!--M_*3 #text/1-->
Got: c
<!---->
0
<!--M_*2 #text/1-->
<button>
Inc
</button>
<!--M_*0 #button/0-->
</div>
<script>
M._.r.push(_=&gt;(_.d={3:{_:_.a}}),0,"__tests__/template.marko_0_count",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/div0/#text2
inserted #document/html0/body1/div0/#comment3
inserted #document/html0/body1/div0/script4
inserted #document/html0/body1/div0/script4/#text0
inserted #document/html0/body1/div0/script5
inserted #document/html0/body1/div0/script5/#text0
inserted #document/html0/body1/div0/#text6
inserted #document/html0/body1/div0/#comment7
inserted #document/html0/body1/div0/#text8
inserted #document/html0/body1/div0/#comment9
inserted #document/html0/body1/div0/#text10
inserted #document/html0/body1/div0/#comment11
inserted #document/html0/body1/div0/#text12
inserted #document/html0/body1/div0/#comment13
inserted #document/html0/body1/div0/button14
inserted #document/html0/body1/div0/button14/#text0
inserted #document/html0/body1/div0/#comment15
inserted #document/html0/body1/script1
inserted #document/html0/body1/script1/#text0
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { resolveAfter } from "../../utils/resolve";

<let/count = 0/>
<div>
<await|value|=Promise.resolve("a")>
Got: ${value} ${count}
</await>

<await|value|=resolveAfter("b", 2)>
Got: ${value} ${count}
</await>

<await|value|=resolveAfter("c", 1)>
Got: ${value} ${count}
</await>

<button onClick() {
count++
}>
Inc
</button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const skip_csr = true;

export const steps = [{}, click, click, click];

function click(container: Element) {
container.querySelector("button")!.click();
}
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
const _scope1_ = new Map();
_$.forOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], (num, _index) => {
const _scope1_id = _$.nextScopeId();
_$.write(`<button${_$.attr("data-selected", selected === num)}${_$.attr("data-multiple", num % selected === 0)}>${_$.escapeXML(num)}${_$.markResumeNode(_scope1_id, "#text/1")}</button>${_$.markResumeNode(_scope1_id, "#button/0")}`);
_$.write(`<button${_$.attr("data-selected", selected === num)}${_$.attr("data-multiple", num % selected === 0)}>${_$.escapeXML(num)}</button>${_$.markResumeNode(_scope1_id, "#button/0")}`);
_$.writeEffect(_scope1_id, "__tests__/template.marko_1_num");
_$.writeScope(_scope1_id, {
"num": num,
Original file line number Diff line number Diff line change
@@ -5,62 +5,50 @@
<body>
<button>
1
<!--M_*1 #text/1-->
</button>
<!--M_*1 #button/0-->
<button>
2
<!--M_*2 #text/1-->
</button>
<!--M_*2 #button/0-->
<button>
3
<!--M_*3 #text/1-->
</button>
<!--M_*3 #button/0-->
<button>
4
<!--M_*4 #text/1-->
</button>
<!--M_*4 #button/0-->
<button>
5
<!--M_*5 #text/1-->
</button>
<!--M_*5 #button/0-->
<button>
6
<!--M_*6 #text/1-->
</button>
<!--M_*6 #button/0-->
<button>
7
<!--M_*7 #text/1-->
</button>
<!--M_*7 #button/0-->
<button>
8
<!--M_*8 #text/1-->
</button>
<!--M_*8 #button/0-->
<button>
9
<!--M_*9 #text/1-->
</button>
<!--M_*9 #button/0-->
<button>
10
<!--M_*10 #text/1-->
</button>
<!--M_*10 #button/0-->
<button>
11
<!--M_*11 #text/1-->
</button>
<!--M_*11 #button/0-->
<button>
12
<!--M_*12 #text/1-->
</button>
<!--M_*12 #button/0-->
<script>
@@ -85,75 +73,63 @@ c => click(c, 2)
<body>
<button>
1
<!--M_*1 #text/1-->
</button>
<!--M_*1 #button/0-->
<button
data-multiple=""
data-selected=""
>
2
<!--M_*2 #text/1-->
</button>
<!--M_*2 #button/0-->
<button>
3
<!--M_*3 #text/1-->
</button>
<!--M_*3 #button/0-->
<button
data-multiple=""
>
4
<!--M_*4 #text/1-->
</button>
<!--M_*4 #button/0-->
<button>
5
<!--M_*5 #text/1-->
</button>
<!--M_*5 #button/0-->
<button
data-multiple=""
>
6
<!--M_*6 #text/1-->
</button>
<!--M_*6 #button/0-->
<button>
7
<!--M_*7 #text/1-->
</button>
<!--M_*7 #button/0-->
<button
data-multiple=""
>
8
<!--M_*8 #text/1-->
</button>
<!--M_*8 #button/0-->
<button>
9
<!--M_*9 #text/1-->
</button>
<!--M_*9 #button/0-->
<button
data-multiple=""
>
10
<!--M_*10 #text/1-->
</button>
<!--M_*10 #button/0-->
<button>
11
<!--M_*11 #text/1-->
</button>
<!--M_*11 #button/0-->
<button
data-multiple=""
>
12
<!--M_*12 #text/1-->
</button>
<!--M_*12 #button/0-->
<script>
@@ -184,71 +160,59 @@ c => click(c, 3)
<body>
<button>
1
<!--M_*1 #text/1-->
</button>
<!--M_*1 #button/0-->
<button>
2
<!--M_*2 #text/1-->
</button>
<!--M_*2 #button/0-->
<button
data-multiple=""
data-selected=""
>
3
<!--M_*3 #text/1-->
</button>
<!--M_*3 #button/0-->
<button>
4
<!--M_*4 #text/1-->
</button>
<!--M_*4 #button/0-->
<button>
5
<!--M_*5 #text/1-->
</button>
<!--M_*5 #button/0-->
<button
data-multiple=""
>
6
<!--M_*6 #text/1-->
</button>
<!--M_*6 #button/0-->
<button>
7
<!--M_*7 #text/1-->
</button>
<!--M_*7 #button/0-->
<button>
8
<!--M_*8 #text/1-->
</button>
<!--M_*8 #button/0-->
<button
data-multiple=""
>
9
<!--M_*9 #text/1-->
</button>
<!--M_*9 #button/0-->
<button>
10
<!--M_*10 #text/1-->
</button>
<!--M_*10 #button/0-->
<button>
11
<!--M_*11 #text/1-->
</button>
<!--M_*11 #button/0-->
<button
data-multiple=""
>
12
<!--M_*12 #text/1-->
</button>
<!--M_*12 #button/0-->
<script>
@@ -280,67 +244,55 @@ c => click(c, 5)
<body>
<button>
1
<!--M_*1 #text/1-->
</button>
<!--M_*1 #button/0-->
<button>
2
<!--M_*2 #text/1-->
</button>
<!--M_*2 #button/0-->
<button>
3
<!--M_*3 #text/1-->
</button>
<!--M_*3 #button/0-->
<button>
4
<!--M_*4 #text/1-->
</button>
<!--M_*4 #button/0-->
<button
data-multiple=""
data-selected=""
>
5
<!--M_*5 #text/1-->
</button>
<!--M_*5 #button/0-->
<button>
6
<!--M_*6 #text/1-->
</button>
<!--M_*6 #button/0-->
<button>
7
<!--M_*7 #text/1-->
</button>
<!--M_*7 #button/0-->
<button>
8
<!--M_*8 #text/1-->
</button>
<!--M_*8 #button/0-->
<button>
9
<!--M_*9 #text/1-->
</button>
<!--M_*9 #button/0-->
<button
data-multiple=""
>
10
<!--M_*10 #text/1-->
</button>
<!--M_*10 #button/0-->
<button>
11
<!--M_*11 #text/1-->
</button>
<!--M_*11 #button/0-->
<button>
12
<!--M_*12 #text/1-->
</button>
<!--M_*12 #button/0-->
<script>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Write
<button>1<!--M_*1 #text/1--></button><!--M_*1 #button/0--><button>2<!--M_*2 #text/1--></button><!--M_*2 #button/0--><button>3<!--M_*3 #text/1--></button><!--M_*3 #button/0--><button>4<!--M_*4 #text/1--></button><!--M_*4 #button/0--><button>5<!--M_*5 #text/1--></button><!--M_*5 #button/0--><button>6<!--M_*6 #text/1--></button><!--M_*6 #button/0--><button>7<!--M_*7 #text/1--></button><!--M_*7 #button/0--><button>8<!--M_*8 #text/1--></button><!--M_*8 #button/0--><button>9<!--M_*9 #text/1--></button><!--M_*9 #button/0--><button>10<!--M_*10 #text/1--></button><!--M_*10 #button/0--><button>11<!--M_*11 #text/1--></button><!--M_*11 #button/0--><button>12<!--M_*12 #text/1--></button><!--M_*12 #button/0--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.o={0:_.b={"#text/0(":new Map(_.a=[[0,_.c={num:1}],[1,_.d={num:2}],[2,_.e={num:3}],[3,_.f={num:4}],[4,_.g={num:5}],[5,_.h={num:6}],[6,_.i={num:7}],[7,_.j={num:8}],[8,_.k={num:9}],[9,_.l={num:10}],[10,_.m={num:11}],[11,_.n={num:12}]])},1:_.c,2:_.d,3:_.e,4:_.f,5:_.g,6:_.h,7:_.i,8:_.j,9:_.k,10:_.l,11:_.m,12:_.n},_.c._=_.d._=_.e._=_.f._=_.g._=_.h._=_.i._=_.j._=_.k._=_.l._=_.m._=_.n._=_.b,_.o),1,"__tests__/template.marko_1_num",2,"__tests__/template.marko_1_num",3,"__tests__/template.marko_1_num",4,"__tests__/template.marko_1_num",5,"__tests__/template.marko_1_num",6,"__tests__/template.marko_1_num",7,"__tests__/template.marko_1_num",8,"__tests__/template.marko_1_num",9,"__tests__/template.marko_1_num",10,"__tests__/template.marko_1_num",11,"__tests__/template.marko_1_num",12,"__tests__/template.marko_1_num",0];M._.w()</script>
<button>1</button><!--M_*1 #button/0--><button>2</button><!--M_*2 #button/0--><button>3</button><!--M_*3 #button/0--><button>4</button><!--M_*4 #button/0--><button>5</button><!--M_*5 #button/0--><button>6</button><!--M_*6 #button/0--><button>7</button><!--M_*7 #button/0--><button>8</button><!--M_*8 #button/0--><button>9</button><!--M_*9 #button/0--><button>10</button><!--M_*10 #button/0--><button>11</button><!--M_*11 #button/0--><button>12</button><!--M_*12 #button/0--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.o={0:_.b={"#text/0(":new Map(_.a=[[0,_.c={num:1}],[1,_.d={num:2}],[2,_.e={num:3}],[3,_.f={num:4}],[4,_.g={num:5}],[5,_.h={num:6}],[6,_.i={num:7}],[7,_.j={num:8}],[8,_.k={num:9}],[9,_.l={num:10}],[10,_.m={num:11}],[11,_.n={num:12}]])},1:_.c,2:_.d,3:_.e,4:_.f,5:_.g,6:_.h,7:_.i,8:_.j,9:_.k,10:_.l,11:_.m,12:_.n},_.c._=_.d._=_.e._=_.f._=_.g._=_.h._=_.i._=_.j._=_.k._=_.l._=_.m._=_.n._=_.b,_.o),1,"__tests__/template.marko_1_num",2,"__tests__/template.marko_1_num",3,"__tests__/template.marko_1_num",4,"__tests__/template.marko_1_num",5,"__tests__/template.marko_1_num",6,"__tests__/template.marko_1_num",7,"__tests__/template.marko_1_num",8,"__tests__/template.marko_1_num",9,"__tests__/template.marko_1_num",10,"__tests__/template.marko_1_num",11,"__tests__/template.marko_1_num",12,"__tests__/template.marko_1_num",0];M._.w()</script>


# Render "End"
@@ -9,62 +9,50 @@
<body>
<button>
1
<!--M_*1 #text/1-->
</button>
<!--M_*1 #button/0-->
<button>
2
<!--M_*2 #text/1-->
</button>
<!--M_*2 #button/0-->
<button>
3
<!--M_*3 #text/1-->
</button>
<!--M_*3 #button/0-->
<button>
4
<!--M_*4 #text/1-->
</button>
<!--M_*4 #button/0-->
<button>
5
<!--M_*5 #text/1-->
</button>
<!--M_*5 #button/0-->
<button>
6
<!--M_*6 #text/1-->
</button>
<!--M_*6 #button/0-->
<button>
7
<!--M_*7 #text/1-->
</button>
<!--M_*7 #button/0-->
<button>
8
<!--M_*8 #text/1-->
</button>
<!--M_*8 #button/0-->
<button>
9
<!--M_*9 #text/1-->
</button>
<!--M_*9 #button/0-->
<button>
10
<!--M_*10 #text/1-->
</button>
<!--M_*10 #button/0-->
<button>
11
<!--M_*11 #text/1-->
</button>
<!--M_*11 #button/0-->
<button>
12
<!--M_*12 #text/1-->
</button>
<!--M_*12 #button/0-->
<script>
@@ -81,51 +69,39 @@ inserted #document/html0/head0
inserted #document/html0/body1
inserted #document/html0/body1/button0
inserted #document/html0/body1/button0/#text0
inserted #document/html0/body1/button0/#comment1
inserted #document/html0/body1/#comment1
inserted #document/html0/body1/button2
inserted #document/html0/body1/button2/#text0
inserted #document/html0/body1/button2/#comment1
inserted #document/html0/body1/#comment3
inserted #document/html0/body1/button4
inserted #document/html0/body1/button4/#text0
inserted #document/html0/body1/button4/#comment1
inserted #document/html0/body1/#comment5
inserted #document/html0/body1/button6
inserted #document/html0/body1/button6/#text0
inserted #document/html0/body1/button6/#comment1
inserted #document/html0/body1/#comment7
inserted #document/html0/body1/button8
inserted #document/html0/body1/button8/#text0
inserted #document/html0/body1/button8/#comment1
inserted #document/html0/body1/#comment9
inserted #document/html0/body1/button10
inserted #document/html0/body1/button10/#text0
inserted #document/html0/body1/button10/#comment1
inserted #document/html0/body1/#comment11
inserted #document/html0/body1/button12
inserted #document/html0/body1/button12/#text0
inserted #document/html0/body1/button12/#comment1
inserted #document/html0/body1/#comment13
inserted #document/html0/body1/button14
inserted #document/html0/body1/button14/#text0
inserted #document/html0/body1/button14/#comment1
inserted #document/html0/body1/#comment15
inserted #document/html0/body1/button16
inserted #document/html0/body1/button16/#text0
inserted #document/html0/body1/button16/#comment1
inserted #document/html0/body1/#comment17
inserted #document/html0/body1/button18
inserted #document/html0/body1/button18/#text0
inserted #document/html0/body1/button18/#comment1
inserted #document/html0/body1/#comment19
inserted #document/html0/body1/button20
inserted #document/html0/body1/button20/#text0
inserted #document/html0/body1/button20/#comment1
inserted #document/html0/body1/#comment21
inserted #document/html0/body1/button22
inserted #document/html0/body1/button22/#text0
inserted #document/html0/body1/button22/#comment1
inserted #document/html0/body1/#comment23
inserted #document/html0/body1/script24
inserted #document/html0/body1/script24/#text0
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import {
createTemplate,
fork,
tryCatch,
tryContent,
write,
} from "@marko/runtime-tags/html";

import { rejectAfter, resolveAfter } from "../../utils/resolve";

const renderer = () => {
write("a");
tryCatch(
() => {
tryContent({
content() {
write("b");
fork(rejectAfter(new Error("ERROR!"), 2), write);
write("c");
},
(err) => {
write((err as Error).message);
},
catch: {
content(err) {
write((err as Error).message);
}
}
},
);
write("d");
fork(resolveAfter("e", 1), write);
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import {
createTemplate,
fork,
tryCatch,
tryContent,
write,
} from "@marko/runtime-tags/html";

import { resolveAfter } from "../../utils/resolve";

const renderer = () => {
write("a");
tryCatch(
() => {
tryContent({
content() {
write("b");
fork(resolveAfter("c", 2), write);
write("d");
},
() => {
write("ERROR!");
catch: {
content() {
write("ERROR!");
}
},
);
});
write("f");
fork(resolveAfter("g", 1), write);
write("h");
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { createTemplate, tryCatch, write } from "@marko/runtime-tags/html";
import { createTemplate, tryContent, write } from "@marko/runtime-tags/html";

const renderer = () => {
write("a");
tryCatch(
() => {
tryContent({
content() {
write("b");
},
() => {
write("ERROR!");
catch: {
content() {
write("ERROR!");
}
},
);
});
write("c");
};

Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { createTemplate, tryCatch, write } from "@marko/runtime-tags/html";
import { createTemplate, tryContent, write } from "@marko/runtime-tags/html";

const renderer = () => {
write("a");
tryCatch(
() => {
tryContent({
content() {
write("b");
throw new Error("ERROR!");
},
(err) => {
write((err as Error).message);
catch: {
content(err) {
write((err as Error).message);
}
},
);
});
write("d");
};

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
createTemplate,
fork,
tryPlaceholder,
tryContent,
write,
} from "@marko/runtime-tags/html";

@@ -14,33 +14,37 @@ const renderer = () => {

const firstComponent = () => {
write("a");
tryPlaceholder(
() => {
tryContent({
content() {
write("b");
fork(resolveAfter("c", 2), write);
write("d");
},
() => {
write("_A_");
placeholder: {
content() {
write("_A_");
}
},
);
});
write("e");
fork(resolveAfter("f", 1), write);
write("g");
};

const secondComponent = () => {
write("1");
tryPlaceholder(
() => {
tryContent({
content() {
write("2");
fork(resolveAfter("3", 2), write);
write("4");
},
() => {
write("_B_");
placeholder: {
content() {
write("_B_");
}
},
);
});
write("5");
};

Original file line number Diff line number Diff line change
@@ -5,12 +5,12 @@ const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
_$.write("<div>");
_$.forOf(arrA, val => {
const _scope1_id = _$.nextScopeId();
_$.write(`<div>${_$.escapeXML(val)}${_$.markResumeNode(_scope1_id, "#text/0")}</div>`);
_$.write(`<div>${_$.escapeXML(val)}</div>`);
});
_$.write("</div><div>");
_$.forOf(arrA, val => {
const _scope2_id = _$.nextScopeId();
_$.write(`<div>${_$.escapeXML(val)}${_$.markResumeNode(_scope2_id, "#text/0")}</div>`);
_$.write(`<div>${_$.escapeXML(val)}</div>`);
});
_$.write("<div></div></div>");
});
Original file line number Diff line number Diff line change
@@ -6,35 +6,26 @@
<div>
<div>
1
<!--M_*1 #text/0-->
</div>
<div>
2
<!--M_*2 #text/0-->
</div>
<div>
3
<!--M_*3 #text/0-->
</div>
</div>
<div>
<div>
1
<!--M_*4 #text/0-->
</div>
<div>
2
<!--M_*5 #text/0-->
</div>
<div>
3
<!--M_*6 #text/0-->
</div>
<div />
</div>
<script>
WALKER_RUNTIME("M")("_")
</script>
</body>
</html>
```
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Write
<div><div>1<!--M_*1 #text/0--></div><div>2<!--M_*2 #text/0--></div><div>3<!--M_*3 #text/0--></div></div><div><div>1<!--M_*4 #text/0--></div><div>2<!--M_*5 #text/0--></div><div>3<!--M_*6 #text/0--></div><div></div></div><script>WALKER_RUNTIME("M")("_")</script>
<div><div>1</div><div>2</div><div>3</div></div><div><div>1</div><div>2</div><div>3</div><div></div></div>


# Render "End"
@@ -10,35 +10,26 @@
<div>
<div>
1
<!--M_*1 #text/0-->
</div>
<div>
2
<!--M_*2 #text/0-->
</div>
<div>
3
<!--M_*3 #text/0-->
</div>
</div>
<div>
<div>
1
<!--M_*4 #text/0-->
</div>
<div>
2
<!--M_*5 #text/0-->
</div>
<div>
3
<!--M_*6 #text/0-->
</div>
<div />
</div>
<script>
WALKER_RUNTIME("M")("_")
</script>
</body>
</html>
```
@@ -51,24 +42,16 @@ inserted #document/html0/body1
inserted #document/html0/body1/div0
inserted #document/html0/body1/div0/div0
inserted #document/html0/body1/div0/div0/#text0
inserted #document/html0/body1/div0/div0/#comment1
inserted #document/html0/body1/div0/div1
inserted #document/html0/body1/div0/div1/#text0
inserted #document/html0/body1/div0/div1/#comment1
inserted #document/html0/body1/div0/div2
inserted #document/html0/body1/div0/div2/#text0
inserted #document/html0/body1/div0/div2/#comment1
inserted #document/html0/body1/div1
inserted #document/html0/body1/div1/div0
inserted #document/html0/body1/div1/div0/#text0
inserted #document/html0/body1/div1/div0/#comment1
inserted #document/html0/body1/div1/div1
inserted #document/html0/body1/div1/div1/#text0
inserted #document/html0/body1/div1/div1/#comment1
inserted #document/html0/body1/div1/div2
inserted #document/html0/body1/div1/div2/#text0
inserted #document/html0/body1/div1/div2/#comment1
inserted #document/html0/body1/div1/div3
inserted #document/html0/body1/script2
inserted #document/html0/body1/script2/#text0
```
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
const arrA = [1, 2, 3];
_$.forOf(arrA, (val, i) => {
const _scope1_id = _$.nextScopeId();
_$.write(`<div>${_$.escapeXML(i)}${_$.markResumeNode(_scope1_id, "#text/0")}: <!>${_$.escapeXML(val)}${_$.markResumeNode(_scope1_id, "#text/1")}</div>`);
_$.write(`<div>${_$.escapeXML(i)}: ${_$.escapeXML(val)}</div>`);
});
const arrB = [1, 2, 3];
const _forScopeIds = [],
Original file line number Diff line number Diff line change
@@ -4,28 +4,13 @@
<head />
<body>
<div>
0
<!--M_*1 #text/0-->
:
<!---->
1
<!--M_*1 #text/1-->
0: 1
</div>
<div>
1
<!--M_*2 #text/0-->
:
<!---->
2
<!--M_*2 #text/1-->
1: 2
</div>
<div>
2
<!--M_*3 #text/0-->
:
<!---->
3
<!--M_*3 #text/1-->
2: 3
</div>
<div>
0
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Write
<div>0<!--M_*1 #text/0-->: <!>1<!--M_*1 #text/1--></div><div>1<!--M_*2 #text/0-->: <!>2<!--M_*2 #text/1--></div><div>2<!--M_*3 #text/0-->: <!>3<!--M_*3 #text/1--></div><div>0<!--M_*4 #text/0-->: <!>1<!--M_*4 #text/1--></div><div>1<!--M_*5 #text/0-->: <!>2<!--M_*5 #text/1--></div><div>2<!--M_*6 #text/0-->: <!>3<!--M_*6 #text/1--></div><!--M_|0 #text/1 4,5,6--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.e={0:{"#text/1(":new Map(_.a=[[0,_.b={}],[1,_.c={}],[2,_.d={}]])},4:_.b,5:_.c,6:_.d}),0]</script>
<div>0: 1</div><div>1: 2</div><div>2: 3</div><div>0<!--M_*4 #text/0-->: <!>1<!--M_*4 #text/1--></div><div>1<!--M_*5 #text/0-->: <!>2<!--M_*5 #text/1--></div><div>2<!--M_*6 #text/0-->: <!>3<!--M_*6 #text/1--></div><!--M_|0 #text/1 4,5,6--><script>WALKER_RUNTIME("M")("_");M._.r=[_=>(_.e={0:{"#text/1(":new Map(_.a=[[0,_.b={}],[1,_.c={}],[2,_.d={}]])},4:_.b,5:_.c,6:_.d}),0]</script>


# Render "End"
@@ -8,28 +8,13 @@
<head />
<body>
<div>
0
<!--M_*1 #text/0-->
:
<!---->
1
<!--M_*1 #text/1-->
0: 1
</div>
<div>
1
<!--M_*2 #text/0-->
:
<!---->
2
<!--M_*2 #text/1-->
1: 2
</div>
<div>
2
<!--M_*3 #text/0-->
:
<!---->
3
<!--M_*3 #text/1-->
2: 3
</div>
<div>
0
@@ -70,25 +55,10 @@ 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/div0/#text2
inserted #document/html0/body1/div0/#comment3
inserted #document/html0/body1/div0/#text4
inserted #document/html0/body1/div0/#comment5
inserted #document/html0/body1/div1
inserted #document/html0/body1/div1/#text0
inserted #document/html0/body1/div1/#comment1
inserted #document/html0/body1/div1/#text2
inserted #document/html0/body1/div1/#comment3
inserted #document/html0/body1/div1/#text4
inserted #document/html0/body1/div1/#comment5
inserted #document/html0/body1/div2
inserted #document/html0/body1/div2/#text0
inserted #document/html0/body1/div2/#comment1
inserted #document/html0/body1/div2/#text2
inserted #document/html0/body1/div2/#comment3
inserted #document/html0/body1/div2/#text4
inserted #document/html0/body1/div2/#comment5
inserted #document/html0/body1/div3
inserted #document/html0/body1/div3/#text0
inserted #document/html0/body1/div3/#comment1
Original file line number Diff line number Diff line change
@@ -9,35 +9,35 @@ const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
};
_$.forOf(arr, (val, i) => {
const _scope1_id = _$.nextScopeId();
_$.write(`<div>${_$.escapeXML(i)}${_$.markResumeNode(_scope1_id, "#text/0")}: <!>${_$.escapeXML(val)}${_$.markResumeNode(_scope1_id, "#text/1")}</div><div></div><div></div>`);
_$.write(`<div>${_$.escapeXML(i)}: ${_$.escapeXML(val)}</div><div></div><div></div>`);
});
_$.forIn(obj, (key, val) => {
const _scope2_id = _$.nextScopeId();
_$.write(`<div>${_$.escapeXML(key)}${_$.markResumeNode(_scope2_id, "#text/0")}: <!>${_$.escapeXML(val)}${_$.markResumeNode(_scope2_id, "#text/1")}</div><div></div><div></div>`);
_$.write(`<div>${_$.escapeXML(key)}: ${_$.escapeXML(val)}</div><div></div><div></div>`);
});
_$.forTo(10, 0, 2, i => {
const _scope3_id = _$.nextScopeId();
_$.write(`<div>${_$.escapeXML(i)}${_$.markResumeNode(_scope3_id, "#text/0")}</div><div></div><div></div>`);
_$.write(`<div>${_$.escapeXML(i)}</div><div></div><div></div>`);
});
_$.forOf(arr, (val, i) => {
const _scope4_id = _$.nextScopeId();
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}${_$.markResumeNode(_scope4_id, "#text/1")}: <!>${_$.escapeXML(val)}${_$.markResumeNode(_scope4_id, "#text/2")}</div>${_$.markResumeNode(_scope4_id, "#div/0")}<div></div><div${_$.attr("key", `other-${i}`)}></div>${_$.markResumeNode(_scope4_id, "#div/3")}`);
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}: ${_$.escapeXML(val)}</div><div></div><div${_$.attr("key", `other-${i}`)}></div>`);
});
_$.forIn(obj, (key, val) => {
const _scope5_id = _$.nextScopeId();
_$.write(`<div${_$.attr("key", key)}>${_$.escapeXML(key)}${_$.markResumeNode(_scope5_id, "#text/1")}: <!>${_$.escapeXML(val)}${_$.markResumeNode(_scope5_id, "#text/2")}</div>${_$.markResumeNode(_scope5_id, "#div/0")}<div></div><div${_$.attr("key", `other-${key}`)}></div>${_$.markResumeNode(_scope5_id, "#div/3")}`);
_$.write(`<div${_$.attr("key", key)}>${_$.escapeXML(key)}: ${_$.escapeXML(val)}</div><div></div><div${_$.attr("key", `other-${key}`)}></div>`);
});
_$.forTo(10, 0, 2, i => {
const _scope6_id = _$.nextScopeId();
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}${_$.markResumeNode(_scope6_id, "#text/1")}</div>${_$.markResumeNode(_scope6_id, "#div/0")}<div></div><div${_$.attr("key", `other-${i}`)}></div>${_$.markResumeNode(_scope6_id, "#div/2")}`);
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}</div><div></div><div${_$.attr("key", `other-${i}`)}></div>`);
_$.forTo(10, 0, 2, i => {
const _scope7_id = _$.nextScopeId();
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}${_$.markResumeNode(_scope7_id, "#text/1")}</div>${_$.markResumeNode(_scope7_id, "#div/0")}<div></div><div${_$.attr("key", `other-${i}`)}></div>${_$.markResumeNode(_scope7_id, "#div/2")}`);
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}</div><div></div><div${_$.attr("key", `other-${i}`)}></div>`);
});
});
_$.forTo(0, 10, -2, i => {
const _scope8_id = _$.nextScopeId();
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}${_$.markResumeNode(_scope8_id, "#text/1")}</div>${_$.markResumeNode(_scope8_id, "#div/0")}<div></div><div${_$.attr("key", `other-${i}`)}></div>${_$.markResumeNode(_scope8_id, "#div/2")}`);
_$.write(`<div${_$.attr("key", i)}>${_$.escapeXML(i)}</div><div></div><div${_$.attr("key", `other-${i}`)}></div>`);
});
_$.forTo(10, 0, 1, () => {
const _scope9_id = _$.nextScopeId();

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import {
createTemplate,
fork,
tryPlaceholder,
tryContent,
write,
} from "@marko/runtime-tags/html";

import { resolveAfter } from "../../utils/resolve";

const renderer = () => {
write("a");
tryPlaceholder(
() => {
tryContent({
content() {
write("b");
fork(resolveAfter("c", 2), write);
write("d");
},
() => {
write("_A_");
},
placeholder: {
content() {
write("_A_");
}
}
},
);
write("e");
fork(resolveAfter("f", 1), write);
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import {
createTemplate,
fork,
tryPlaceholder,
tryContent,
write,
} from "@marko/runtime-tags/html";

import { resolveAfter } from "../../utils/resolve";

const renderer = () => {
write("a");
tryPlaceholder(
() => {
tryContent({
content() {
write("b");
},
() => {
write("_A_");
},
placeholder: {
content() {
write("_A_");
}
}
},
);
write("c");
fork(resolveAfter("d", 1), write);
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
import {
createTemplate,
fork,
tryPlaceholder,
tryContent,
write,
} from "@marko/runtime-tags/html";

import { resolveAfter } from "../../utils/resolve";

const renderer = () => {
write("a");
tryPlaceholder(
() => {
tryContent({
content() {
write("b");
fork(resolveAfter("c", 2), write);
write("d");
tryPlaceholder(
() => {
tryContent({
content() {
write("e");
fork(resolveAfter("f", 3), write);
write("g");
},
() => {
write("_A_");
},
placeholder: {
content() {
write("_A_");
}
}
},
);
},
() => {
write("_B_");
},
placeholder: {
content() {
write("_B_");
}
}
},
);
write("h");
fork(resolveAfter("i", 1), write);
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as _$ from "@marko/runtime-tags/debug/html";
const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
const _scope0_id = _$.nextScopeId();
_$.write("Before");
_$.tryContent({
content: _$.register(/* @__PURE__ */_$.createRenderer(() => {
const _scope2_id = _$.nextScopeId();
_$.write(`Inside${_$.escapeXML((() => {
throw new Error("ERROR!");
})())}`);
}), "__tests__/template.marko_2_renderer", _scope0_id),
catch: _$.attrTag({
content: _$.register(/* @__PURE__ */_$.createRenderer(err => {
const _scope1_id = _$.nextScopeId();
_$.write(`${_$.escapeXML(err.message)}${_$.markResumeNode(_scope1_id, "#text/0")}`);
}), "__tests__/template.marko_1_renderer", _scope0_id)
})
});
_$.write("After");
});
export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _renderer);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Render "End"
```html
BeforeERROR!After
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Write
BeforeERROR!<!--M_*2 #text/0-->After<script>WALKER_RUNTIME("M")("_")</script>


# Render "End"
```html
<html>
<head />
<body>
BeforeERROR!
<!--M_*2 #text/0-->
After
<script>
WALKER_RUNTIME("M")("_")
</script>
</body>
</html>
```

# Mutations
```
inserted #document/html0
inserted #document/html0/head0
inserted #document/html0/body1
inserted #document/html0/body1/#text0
inserted #document/html0/body1/#comment1
inserted #document/html0/body1/#text2
inserted #document/html0/body1/script3
inserted #document/html0/body1/script3/#text0
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Before
try
-- Inside
-- ${(() => { throw new Error("ERROR!") })()}
@catch|err|
-- ${err.message}

-- After
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const skip_dom = true;
3 changes: 1 addition & 2 deletions packages/runtime-tags/src/html.ts
Original file line number Diff line number Diff line change
@@ -38,8 +38,7 @@ export {
nodeRef,
peekNextScope,
register,
tryCatch,
tryPlaceholder,
tryContent,
write,
writeEffect,
writeExistingScope,
6 changes: 3 additions & 3 deletions packages/runtime-tags/src/html/inlined-runtimes.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ export const WALKER_RUNTIME_CODE = MARKO_DEBUG
self[runtimeId] ||
((renderId) => {
let id,
markers = {},
lookup = {},
visits = [],
doc = document,
walker = doc.createTreeWalker(
@@ -14,7 +14,7 @@ export const WALKER_RUNTIME_CODE = MARKO_DEBUG
op = (self[runtimeId][renderId] = {
i: (renderId = runtimeId + renderId),
d: doc,
l: markers,
l: lookup,
v: visits,
x() {},
w(node) {
@@ -23,7 +23,7 @@ export const WALKER_RUNTIME_CODE = MARKO_DEBUG
(op =
(op = node.data) &&
!op.indexOf(renderId) &&
((markers[(id = op.slice(prefix + 1))] = node), op[prefix])),
((lookup[(id = op.slice(prefix + 1))] = node), op[prefix])),
id,
node,
);
36 changes: 31 additions & 5 deletions packages/runtime-tags/src/html/writer.ts
Original file line number Diff line number Diff line change
@@ -224,7 +224,36 @@ export function fork<T>(promise: Promise<T> | T, content: (value: T) => void) {
);
}

export function tryPlaceholder(content: () => void, placeholder: () => void) {
export function tryContent(input: {
content?(): void;
placeholder?: {
content?(): void;
};
catch?: {
content?(err: unknown): void;
};
}) {
const content = input.content;

if (content) {
const catchContent = input.catch?.content;
const placeholderContent = input.placeholder?.content;
if (catchContent) {
tryCatch(
placeholderContent
? () => tryPlaceholder(content, placeholderContent)
: content,
catchContent,
);
} else if (placeholderContent) {
tryPlaceholder(content, placeholderContent);
} else {
content();
}
}
}

function tryPlaceholder(content: () => void, placeholder: () => void) {
const chunk = $chunk;
const { boundary } = chunk;
const body = new Chunk(boundary, null, chunk.context);
@@ -239,10 +268,7 @@ export function tryPlaceholder(content: () => void, placeholder: () => void) {
chunk.placeholderRender = placeholder;
}

export function tryCatch(
content: () => void,
catchContent: (err: unknown) => void,
) {
function tryCatch(content: () => void, catchContent: (err: unknown) => void) {
const chunk = $chunk;
const { boundary } = chunk;
const { state } = boundary;
159 changes: 159 additions & 0 deletions packages/runtime-tags/src/translator/core/await.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { types as t } from "@marko/compiler";
import {
assertNoArgs,
assertNoAttributeTags,
assertNoVar,
type Tag,
} from "@marko/compiler/babel-utils";

import { assertNoSpreadAttrs } from "../util/assert";
import evaluate from "../util/evaluate";
import { isStatefulReferences } from "../util/is-stateful";
import { BindingType, trackParamsReferences } from "../util/references";
import { callRuntime } from "../util/runtime";
import runtimeInfo from "../util/runtime-info";
import {
checkStatefulClosures,
getOrCreateSection,
getSectionForBody,
setSectionParentIsOwner,
} from "../util/sections";
import {
setForceResumeScope,
setSubscriberBuilder,
writeHTMLResumeStatements,
} from "../util/signals";
import { toFirstExpressionOrBlock } from "../util/to-first-expression-or-block";
import { translateByTarget } from "../util/visitors";
import * as writer from "../util/writer";

export default {
analyze(tag: t.NodePath<t.MarkoTag>) {
assertNoVar(tag);
assertNoArgs(tag);
assertNoSpreadAttrs(tag);
assertNoAttributeTags(tag);
const { node } = tag;
const [valueAttr] = node.attributes;

if (!valueAttr) {
throw tag
.get("name")
.buildCodeFrameError("The `await` tag requires a value.");
}

if (
node.attributes.length > 1 ||
!t.isMarkoAttribute(valueAttr) ||
valueAttr.name !== "value"
) {
throw tag
.get("name")
.buildCodeFrameError(
"The `await` tag only supports the `value` attribute.",
);
}

if (!node.body.body.length) {
throw tag
.get("name")
.buildCodeFrameError("The `await` tag requires body content.");
}

if (
node.body.params.length &&
(node.body.params.length > 1 || t.isSpreadElement(node.body.params[0]))
) {
throw tag
.get("name")
.buildCodeFrameError(
"The `await` tag only supports a single parameter.",
);
}

getOrCreateSection(tag);
trackParamsReferences(
tag.get("body"),
BindingType.derived,
undefined,
evaluate(valueAttr.value),
);
},
translate: translateByTarget({
html: {
enter(tag) {
const tagBody = tag.get("body");
const bodySection = getSectionForBody(tagBody);

if (!bodySection) {
tag.remove();
return;
}

setSectionParentIsOwner(bodySection, true);
writer.flushBefore(tag);
},
exit(tag) {
const { node } = tag;
const [valueAttr] = node.attributes;
const tagBody = tag.get("body");
const bodySection = getSectionForBody(tagBody)!;

if (
isStatefulReferences(valueAttr.extra?.referencedBindings) ||
checkStatefulClosures(bodySection, true)
) {
setForceResumeScope(bodySection);
}

writer.flushInto(tag);
// TODO: this is a hack to get around the fact that we don't have a way to
// know if a scope requires dynamic subscriptions
setSubscriberBuilder(tag, (() => {}) as any);
writeHTMLResumeStatements(tagBody);

tag
.replaceWith(
t.expressionStatement(
callRuntime(
"fork",
valueAttr.value,
t.arrowFunctionExpression(
node.body.params,
toFirstExpressionOrBlock(node.body.body),
),
),
),
)[0]
.skip();
},
},
dom: {
enter(tag) {
const tagBody = tag.get("body");
const bodySection = getSectionForBody(tagBody);

if (!bodySection) {
tag.remove();
return;
}

setSectionParentIsOwner(bodySection, true);
// TODO: this is a hack to get around the fact that we don't have a way to
// know if a scope requires dynamic subscriptions
setSubscriberBuilder(tag, (signal) => signal);
},
exit(tag) {
tag.remove();
},
},
}),
attributes: {},
autocomplete: [
{
description: "Use to consume asynchronous an data.",
descriptionMoreURL: "https://markojs.com/docs/core-tags/#await",
},
],
types: runtimeInfo.name + "/tag-types/await.d.marko",
} as Tag;
2 changes: 2 additions & 0 deletions packages/runtime-tags/src/translator/core/define.ts
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import { types as t } from "@marko/compiler";
import { assertNoArgs, type Tag } from "@marko/compiler/babel-utils";

import { isOutputHTML } from "../util/marko-config";
import { analyzeAttributeTags } from "../util/nested-attribute-tags";
import {
BindingType,
getAllTagReferenceNodes,
@@ -35,6 +36,7 @@ export default {
trackVarReferences(tag, BindingType.derived);
// TODO: should determine if var bindings are nullable based on attrs.
trackParamsReferences(tagBody, BindingType.param);
analyzeAttributeTags(tag);
mergeReferences(
getOrCreateSection(tag),
tag.node,
4 changes: 4 additions & 0 deletions packages/runtime-tags/src/translator/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import runtimeInfo from "../util/runtime-info";
import AttrsTag from "./attrs";
import AwaitTag from "./await";
import ClientTag from "./client";
import ConstTag from "./const";
import DebugTag from "./debug";
@@ -21,10 +22,12 @@ import ScriptTag from "./script";
import ServerTag from "./server";
import StaticTag from "./static";
import StyleTag from "./style";
import TryTag from "./try";

export default {
taglibId: runtimeInfo.taglibId,
"<attrs>": AttrsTag,
"<await>": AwaitTag,
"<client>": ClientTag,
"<const>": ConstTag,
"<debug>": DebugTag,
@@ -48,4 +51,5 @@ export default {
"<server>": ServerTag,
"<static>": StaticTag,
"<style>": StyleTag,
"<try>": TryTag,
};
112 changes: 112 additions & 0 deletions packages/runtime-tags/src/translator/core/try.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { types as t } from "@marko/compiler";
import {
assertNoArgs,
assertNoAttributes,
assertNoParams,
assertNoVar,
type Tag,
} from "@marko/compiler/babel-utils";

import { assertNoSpreadAttrs } from "../util/assert";
import { analyzeAttributeTags } from "../util/nested-attribute-tags";
import { getAllTagReferenceNodes, mergeReferences } from "../util/references";
import { callRuntime } from "../util/runtime";
import runtimeInfo from "../util/runtime-info";
import {
getOrCreateSection,
getSectionForBody,
setSectionParentIsOwner,
} from "../util/sections";
import {
setSubscriberBuilder,
writeHTMLResumeStatements,
} from "../util/signals";
import { propsToExpression, translateAttrs } from "../util/translate-attrs";
import { translateByTarget } from "../util/visitors";
import * as writer from "../util/writer";

export default {
analyze(tag: t.NodePath<t.MarkoTag>) {
assertNoVar(tag);
assertNoArgs(tag);
assertNoParams(tag);
assertNoAttributes(tag);
assertNoSpreadAttrs(tag);
analyzeAttributeTags(tag);
const { node } = tag;
const section = getOrCreateSection(tag);

if (!node.body.body.length) {
throw tag
.get("name")
.buildCodeFrameError("The `try` tag requires body content.");
}

mergeReferences(section, tag.node, getAllTagReferenceNodes(tag.node));
},
translate: translateByTarget({
html: {
enter(tag) {
if (!getSectionForBody(tag.get("body"))) {
tag.remove();
return;
}

setAllSectionsParentIsOwner(tag);
writer.flushBefore(tag);
},
exit(tag) {
const tagBody = tag.get("body");
const translatedAttrs = translateAttrs(tag);

writer.flushInto(tag);
writeHTMLResumeStatements(tagBody);
tag.insertBefore(translatedAttrs.statements);

tag
.replaceWith(
t.expressionStatement(
callRuntime(
"tryContent",
propsToExpression(translatedAttrs.properties),
),
),
)[0]
.skip();
},
},
dom: {
enter(tag) {
setAllSectionsParentIsOwner(tag);
},
exit(tag) {
tag.remove();
},
},
}),
attributes: {},
autocomplete: [
{
description:
"Used to capture errors and display placeholders for nested content.",
descriptionMoreURL: "https://markojs.com/docs/core-tags/#try",
},
],
types: runtimeInfo.name + "/tag-types/try.d.marko",
} as Tag;

function setAllSectionsParentIsOwner(tag: t.NodePath<t.MarkoTag>) {
for (const attrTag of tag.get("attributeTags")) {
if (attrTag.isMarkoTag()) {
setAllSectionsParentIsOwner(attrTag);
}
}

const bodySection = getSectionForBody(tag.get("body"));
if (bodySection) {
setSectionParentIsOwner(bodySection, true);
// TODO: this is a hack to get around the fact that we don't have a way to
// know if a scope requires dynamic subscriptions
setSubscriberBuilder(tag, (signal) => signal);
}
}
2 changes: 1 addition & 1 deletion packages/runtime-tags/src/translator/util/references.ts
Original file line number Diff line number Diff line change
@@ -191,7 +191,7 @@ export function trackParamsReferences(
body.scope,
section,
paramsBinding,
undefined,
upstreamExpression,
i + "",
);
}
1 change: 0 additions & 1 deletion packages/runtime-tags/src/translator/util/signals.ts
Original file line number Diff line number Diff line change
@@ -407,7 +407,6 @@ export function buildSignalIntersections(signal: Signal) {
}
}
if (signal.hasDynamicSubscribers) {
signal.hasDynamicSubscribers = true;
intersections = push(
intersections,
callRuntime("dynamicSubscribers", signal.valueAccessor),
8 changes: 8 additions & 0 deletions packages/runtime-tags/tag-types/await.d.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** File for types only, not actual implementation **/

export interface Input<T> {
value: T;
content: Marko.Body<[Awaited<T>]>
}

return=input.value
7 changes: 7 additions & 0 deletions packages/runtime-tags/tag-types/try.d.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** File for types only, not actual implementation **/

export interface Input {
content: Marko.Body,
placeholder?: Marko.AttrTag<{ content?: Marko.Body }>,
catch?: Marko.AttrTag<{ content?: Marko.Body<[unknown]> }>,
}