@torpor/view 1.0.2 → 1.1.0

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.
Files changed (33) hide show
  1. package/dist/{fromWebSocket-DeB35Q4w.d.cts → AsyncOptions-BtMe2PAd.d.cts} +21 -2
  2. package/dist/AsyncOptions-BtMe2PAd.d.cts.map +1 -0
  3. package/dist/{fromWebSocket-B52kN3-W.d.mts → AsyncOptions-ClS1_ERX.d.mts} +21 -2
  4. package/dist/AsyncOptions-ClS1_ERX.d.mts.map +1 -0
  5. package/dist/{Effect-BTKurOpr.d.mts → Effect-DazmAdyC.d.mts} +3 -3
  6. package/dist/{Effect-BTKurOpr.d.mts.map → Effect-DazmAdyC.d.mts.map} +1 -1
  7. package/dist/{Effect-COl3aRJV.d.cts → Effect-Dewn7MLc.d.cts} +3 -3
  8. package/dist/{Effect-COl3aRJV.d.cts.map → Effect-Dewn7MLc.d.cts.map} +1 -1
  9. package/dist/compile.cjs +284 -224
  10. package/dist/compile.mjs +284 -224
  11. package/dist/compile.mjs.map +1 -1
  12. package/dist/dev.d.cts +1 -1
  13. package/dist/dev.d.mts +1 -1
  14. package/dist/{fromWebSocket-Dxc_uwm1.mjs → fromWebSocket-CFGoMkV2.mjs} +9 -7
  15. package/dist/{fromWebSocket-Dxc_uwm1.mjs.map → fromWebSocket-CFGoMkV2.mjs.map} +1 -1
  16. package/dist/{fromWebSocket-1QOjcrHE.cjs → fromWebSocket-DrN-IduP.cjs} +8 -6
  17. package/dist/index.cjs +121 -41
  18. package/dist/index.d.cts +33 -7
  19. package/dist/index.d.cts.map +1 -1
  20. package/dist/index.d.mts +33 -7
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +121 -42
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/ssr.cjs +293 -5
  25. package/dist/ssr.d.cts +108 -9
  26. package/dist/ssr.d.cts.map +1 -1
  27. package/dist/ssr.d.mts +108 -9
  28. package/dist/ssr.d.mts.map +1 -1
  29. package/dist/ssr.mjs +292 -6
  30. package/dist/ssr.mjs.map +1 -1
  31. package/package.json +3 -3
  32. package/dist/fromWebSocket-B52kN3-W.d.mts.map +0 -1
  33. package/dist/fromWebSocket-DeB35Q4w.d.cts.map +0 -1
package/dist/compile.cjs CHANGED
@@ -538,9 +538,7 @@ function buildNodeFragmentText(node, status, fragments, currentFragment) {
538
538
  if (currentFragment) currentFragment.text += isReactive(content) ? "#" : content;
539
539
  break;
540
540
  }
541
- case "special":
542
- buildSpecialFragmentText(node, status, fragments, currentFragment);
543
- break;
541
+ case "special": buildSpecialFragmentText(node, status, fragments, currentFragment);
544
542
  }
545
543
  }
546
544
  function buildRootFragmentText(node, status, fragments) {
@@ -585,7 +583,6 @@ function buildControlFragmentText(node, status, fragments, currentFragment) {
585
583
  };
586
584
  fragments.push(node.fragment);
587
585
  for (let child of node.children) buildNodeFragmentText(child, status, fragments, node.fragment);
588
- break;
589
586
  }
590
587
  }
591
588
  function buildComponentFragmentText(node, status, fragments, currentFragment) {
@@ -935,9 +932,7 @@ function declareControlFragmentVars(fragment, node, path, status, b, parentName,
935
932
  case "@html group":
936
933
  declareParentAndAnchorFragmentVars(fragment, node, path, status, b, parentName, anchorName, varPaths, node.operation.substring(1).replace(" group", ""), declare);
937
934
  break;
938
- default:
939
- for (let [i, child] of node.children.entries()) declareFragmentVars(fragment, child, path, status, b, parentName, anchorName, varPaths, i === node.children.length - 1, declare);
940
- break;
935
+ default: for (let [i, child] of node.children.entries()) declareFragmentVars(fragment, child, path, status, b, parentName, anchorName, varPaths, i === node.children.length - 1, declare);
941
936
  }
942
937
  }
943
938
  function declareComponentFragmentVars(fragment, node, path, status, b, parentName, anchorName, varPaths, declare) {
@@ -1006,8 +1001,10 @@ function declareElementFragmentVars(fragment, node, path, status, b, parentName,
1006
1001
  else b.append(`t_elm("${node.tagName}", {${attributes}}, [`);
1007
1002
  }
1008
1003
  for (let [i, child] of node.children.entries()) declareFragmentVars(fragment, child, elementPath, status, b, parentName, anchorName, varPaths, i === node.children.length - 1, declare);
1009
- if (!declare) if (declareVariable || childParentName) b.append("])),");
1010
- else b.append("]),");
1004
+ if (!declare) {
1005
+ if (declareVariable || childParentName) b.append("])),");
1006
+ else b.append("]),");
1007
+ }
1011
1008
  }
1012
1009
  function elementNodeNeedsDeclaration(node, topLevel, lastChild) {
1013
1010
  const hasReactiveAttribute = node.attributes.some((a) => a.value && a.reactive);
@@ -1128,10 +1125,12 @@ function getFragmentVarPath(fragment, status, name, path, varPaths) {
1128
1125
  let level = 0;
1129
1126
  let end = 0;
1130
1127
  for (let i = pos + match.length; i < varPath.length; i++) if (varPath[i] === "(") level++;
1131
- else if (varPath[i] === ")") if (level === 0) {
1132
- end = i;
1133
- break;
1134
- } else level--;
1128
+ else if (varPath[i] === ")") {
1129
+ if (level === 0) {
1130
+ end = i;
1131
+ break;
1132
+ } else level--;
1133
+ }
1135
1134
  const tail = varPath.substring(end + count);
1136
1135
  varPath = `${head}t_skip(${varPath.substring(pos + match.length, end)}, ${count})${tail}`;
1137
1136
  }
@@ -1147,10 +1146,12 @@ function getFragmentVarPathPart(path, varPath, status, root = false, rootFn = "t
1147
1146
  varPath = `t_child(${varPath})`;
1148
1147
  }
1149
1148
  for (let [i, child] of path.children.entries()) {
1150
- if (i > 0) if (child.type === "text" || child.type === "space") varPath = `t_next_text(${varPath}, true)`;
1151
- else {
1152
- status.imports.add("t_next");
1153
- varPath = `t_next(${varPath})`;
1149
+ if (i > 0) {
1150
+ if (child.type === "text" || child.type === "space") varPath = `t_next_text(${varPath}, true)`;
1151
+ else {
1152
+ status.imports.add("t_next");
1153
+ varPath = `t_next(${varPath})`;
1154
+ }
1154
1155
  }
1155
1156
  if (i === path.children.length - 1 && child.children.length) varPath = getFragmentVarPathPart(child, varPath, status);
1156
1157
  }
@@ -1285,39 +1286,40 @@ function buildComponentNode(node, status, b, root = false) {
1285
1286
  let props = [];
1286
1287
  let runs = [];
1287
1288
  let bindingRuns = [];
1288
- for (let { name, value, reactive, fullyReactive, span } of node.attributes) if (name === "self" && node.tagName === "@component") {} else if (value != null && fullyReactive) if (name.startsWith("&")) {
1289
- name = name.substring(1);
1290
- props.push({
1291
- name,
1292
- value,
1293
- spans: [span]
1294
- });
1295
- runs.push(`${propsName}["${name}"] = ${value};`);
1296
- bindingRuns.push(bindingTarget(value, `${propsName}["${name}"]`, name, status.imports));
1297
- } else if (name === "class") {
1298
- if (node.scopeStyles) value = `[${value}, "torp-${status.styleHash}"]`;
1299
- props.push({
1300
- name,
1301
- value,
1302
- spans: [span]
1303
- });
1304
- runs.push(`${propsName}["${name}"] = ${value};`);
1305
- } else if (name === "style") {
1306
- props.push({
1307
- name,
1308
- value,
1309
- spans: [span]
1310
- });
1311
- runs.push(`${propsName}["${name}"] = ${value};`);
1312
- } else {
1313
- props.push({
1314
- name,
1315
- value,
1316
- spans: [span]
1317
- });
1318
- runs.push(`${propsName}["${name}"] = ${value};`);
1319
- }
1320
- else if (value != null && reactive) {
1289
+ for (let { name, value, reactive, fullyReactive, span } of node.attributes) if (name === "self" && node.tagName === "@component") {} else if (value != null && fullyReactive) {
1290
+ if (name.startsWith("&")) {
1291
+ name = name.substring(1);
1292
+ props.push({
1293
+ name,
1294
+ value,
1295
+ spans: [span]
1296
+ });
1297
+ runs.push(`${propsName}["${name}"] = ${value};`);
1298
+ bindingRuns.push(bindingTarget(value, `${propsName}["${name}"]`, name, status.imports));
1299
+ } else if (name === "class") {
1300
+ if (node.scopeStyles) value = `[${value}, "torp-${status.styleHash}"]`;
1301
+ props.push({
1302
+ name,
1303
+ value,
1304
+ spans: [span]
1305
+ });
1306
+ runs.push(`${propsName}["${name}"] = ${value};`);
1307
+ } else if (name === "style") {
1308
+ props.push({
1309
+ name,
1310
+ value,
1311
+ spans: [span]
1312
+ });
1313
+ runs.push(`${propsName}["${name}"] = ${value};`);
1314
+ } else {
1315
+ props.push({
1316
+ name,
1317
+ value,
1318
+ spans: [span]
1319
+ });
1320
+ runs.push(`${propsName}["${name}"] = ${value};`);
1321
+ }
1322
+ } else if (value != null && reactive) {
1321
1323
  const { newValue, spans, offsets, lengths } = getAttributeOffsets(value, span);
1322
1324
  value = newValue;
1323
1325
  if (name === "class") {
@@ -1575,8 +1577,10 @@ function collectExpressionStrings(node, out) {
1575
1577
  }
1576
1578
  if (isElementLike(node)) {
1577
1579
  for (const attr of node.attributes) {
1578
- if (attr.value !== void 0) if (attr.name.startsWith("&")) out.push(`${attr.value} =`);
1579
- else out.push(attr.value);
1580
+ if (attr.value !== void 0) {
1581
+ if (attr.name.startsWith("&")) out.push(`${attr.value} =`);
1582
+ else out.push(attr.value);
1583
+ }
1580
1584
  if (attr.fullyReactive && attr.name !== attr.value) out.push(attr.name);
1581
1585
  }
1582
1586
  for (const child of node.children) collectExpressionStrings(child, out);
@@ -2159,10 +2163,11 @@ function buildTitleNode(node, status, b) {
2159
2163
  }
2160
2164
  function buildHeadNode(node, status, b) {
2161
2165
  status.imports.add("$run");
2166
+ status.imports.add("t_head_element");
2167
+ const selector = headElementSelector(node);
2162
2168
  b.append("$run(() => {");
2163
2169
  b.append(`
2164
- const t_head_el = document.createElement("${node.tagName}");
2165
- document.getElementsByTagName("head")[0].appendChild(t_head_el);`);
2170
+ const t_head_el = t_head_element("${node.tagName}", ${JSON.stringify(selector)});`);
2166
2171
  for (let { name, value, span } of node.attributes) if (value != null) {
2167
2172
  status.imports.add("t_attribute");
2168
2173
  value = replaceForVarNames(value, status);
@@ -2170,31 +2175,55 @@ function buildHeadNode(node, status, b) {
2170
2175
  }
2171
2176
  b.append(`}${status.options.dev === true ? `, "runHead"` : ""});`);
2172
2177
  }
2178
+ /**
2179
+ * Builds a selector that finds an equivalent element in the head, from the
2180
+ * attributes that identify it (e.g. `meta[name="description"]`). Returns an
2181
+ * empty string when the element has no identifying attributes, in which case
2182
+ * a new element is always created.
2183
+ */
2184
+ function headElementSelector(node) {
2185
+ const identityAttributes = [
2186
+ "name",
2187
+ "property",
2188
+ "rel",
2189
+ "charset",
2190
+ "http-equiv",
2191
+ "itemprop"
2192
+ ];
2193
+ const parts = [];
2194
+ for (let { name, value, reactive } of node.attributes) {
2195
+ if (!identityAttributes.includes(name) || value == null || reactive) continue;
2196
+ const attributeValue = trimQuotes(value).replaceAll("\\", "\\\\").replaceAll("\"", "\\\"");
2197
+ parts.push(`[${name}="${attributeValue}"]`);
2198
+ }
2199
+ return parts.length ? node.tagName + parts.join("") : "";
2200
+ }
2173
2201
  function buildElementAttributes$1(node, varName, status, b) {
2174
2202
  let fragment = status.fragmentStack.at(-1)?.fragment;
2175
2203
  if (!fragment) throw new Error("No fragment on stack");
2176
- for (let { name, value, reactive, fullyReactive, span } of node.attributes) if (name === "self" && node.tagName === "@element") {} else if (name === "&ref") {} else if (value != null && fullyReactive) if (name === "&group") buildBindGroupAttribute(node, varName, value, status, b);
2177
- else if (name === "&value" || name === "&checked") buildBindAttribute(node, varName, name, value, status, b);
2178
- else if (name === "onmount") buildMount("elMount", `return (${trimEnd(value.trim(), ";")})(${varName});`, status, b);
2179
- else if (name.startsWith("on")) buildEventAttribute(varName, name, value, span, status, b);
2180
- else if (name.startsWith("transition")) buildTransitionAttribute(node, varName, name, value, status, b);
2181
- else if (name === "class") {
2182
- status.imports.add("t_class");
2183
- const params = [value];
2184
- if (node.scopeStyles) params.push(`"torp-${status.styleHash}"`);
2185
- const propName = status.ns ? "className.baseVal" : "className";
2186
- stashRun(fragment, `${status.ns ? "// @ts-ignore\n" : ""}${varName}.${propName} = t_class(`, params.join(", "), ");", span, status);
2187
- } else if (name === "style") {
2188
- status.imports.add("t_style");
2189
- stashRun(fragment, `${varName}.style.cssText += t_style(`, value, ");", span, status);
2190
- } else if (name.includes("-")) {
2191
- status.imports.add("t_attribute");
2192
- stashRun(fragment, `t_attribute(${varName}, "${name}", `, value, ");", span, status);
2193
- } else {
2194
- status.imports.add("t_attribute");
2195
- stashRun(fragment, `t_attribute(${varName}, "${name}", `, value, ");", span, status);
2196
- }
2197
- else if (value != null && reactive) {
2204
+ for (let { name, value, reactive, fullyReactive, span } of node.attributes) if (name === "self" && node.tagName === "@element") {} else if (name === "&ref") {} else if (value != null && fullyReactive) {
2205
+ if (name === "&group") buildBindGroupAttribute(node, varName, value, status, b);
2206
+ else if (name === "&value" || name === "&checked") buildBindAttribute(node, varName, name, value, status, b);
2207
+ else if (name === "onmount") buildMount("elMount", `return (${trimEnd(value.trim(), ";")})(${varName});`, status, b);
2208
+ else if (name.startsWith("on")) buildEventAttribute(varName, name, value, span, status, b);
2209
+ else if (name.startsWith("transition")) buildTransitionAttribute(node, varName, name, value, status, b);
2210
+ else if (name === "class") {
2211
+ status.imports.add("t_class");
2212
+ const params = [value];
2213
+ if (node.scopeStyles) params.push(`"torp-${status.styleHash}"`);
2214
+ const propName = status.ns ? "className.baseVal" : "className";
2215
+ stashRun(fragment, `${status.ns ? "// @ts-ignore\n" : ""}${varName}.${propName} = t_class(`, params.join(", "), ");", span, status);
2216
+ } else if (name === "style") {
2217
+ status.imports.add("t_style");
2218
+ stashRun(fragment, `${varName}.style.cssText += t_style(`, value, ");", span, status);
2219
+ } else if (name.includes("-")) {
2220
+ status.imports.add("t_attribute");
2221
+ stashRun(fragment, `t_attribute(${varName}, "${name}", `, value, ");", span, status);
2222
+ } else {
2223
+ status.imports.add("t_attribute");
2224
+ stashRun(fragment, `t_attribute(${varName}, "${name}", `, value, ");", span, status);
2225
+ }
2226
+ } else if (value != null && reactive) {
2198
2227
  const { newValue, spans, offsets, lengths } = getAttributeOffsets(value, span);
2199
2228
  value = newValue;
2200
2229
  if (name === "class") {
@@ -2246,7 +2275,6 @@ function buildBindAttribute(node, varName, name, value, status, b) {
2246
2275
  case "radio":
2247
2276
  eventName = "change";
2248
2277
  inputValue = "e.target.value";
2249
- break;
2250
2278
  }
2251
2279
  } else if (node.tagName === "select") {
2252
2280
  eventName = "change";
@@ -2289,10 +2317,12 @@ function buildTransitionAttribute(node, varName, name, value, status, b) {
2289
2317
  b.append(`const ${entryVarName} = (${value})(${varName});`);
2290
2318
  b.append(`t_animate(${varName}, ${entryVarName});`);
2291
2319
  }
2292
- } else if (name === "transition-out") if (node.attributes.find((a) => a.name === "transition-in")) return;
2293
- else {
2294
- b.append(`const ${exitVarName} = (${value})(${varName});`);
2295
- b.append(`t_animate(${varName}, null, ${entryVarName});`);
2320
+ } else if (name === "transition-out") {
2321
+ if (node.attributes.find((a) => a.name === "transition-in")) return;
2322
+ else {
2323
+ b.append(`const ${exitVarName} = (${value})(${varName});`);
2324
+ b.append(`t_animate(${varName}, null, ${entryVarName});`);
2325
+ }
2296
2326
  }
2297
2327
  }
2298
2328
  //#endregion
@@ -2505,6 +2535,7 @@ const importsMap$1 = {
2505
2535
  t_attribute: "import { t_attribute } from \"${folder}\";",
2506
2536
  t_dynamic: "import { t_dynamic } from \"${folder}\";",
2507
2537
  t_fmt: "import { t_fmt } from \"${folder}\";",
2538
+ t_head_element: "import { t_head_element } from \"${folder}\";",
2508
2539
  t_fragment: "import { t_fragment } from \"${folder}\";",
2509
2540
  t_fragment_el: "import { t_fragment_el } from \"${folder}\";",
2510
2541
  t_event: "import { t_event } from \"${folder}\";",
@@ -2716,13 +2747,22 @@ function buildAttributeNode(attribute, b) {
2716
2747
  b.append(`${attribute.name}: ${attribute.value};`);
2717
2748
  }
2718
2749
  //#endregion
2719
- //#region src/compile/build/server/buildServerComponentNode.ts
2720
- function buildServerComponentNode(node, status, b) {
2721
- status.output += HYDRATION_START_COMMENT;
2750
+ //#region src/compile/build/server/flushOutput.ts
2751
+ /**
2752
+ * Appends any pending output to the generated code, targeting the body
2753
+ * string -- or the head string, when building inside a @head block.
2754
+ */
2755
+ function flushOutput(status, b) {
2722
2756
  if (status.output) {
2723
- b.append(`t_body += \`${status.output}\`;`);
2757
+ b.append(`${status.inHead ? "t_head" : "t_body"} += \`${status.output}\`;`);
2724
2758
  status.output = "";
2725
2759
  }
2760
+ }
2761
+ //#endregion
2762
+ //#region src/compile/build/server/buildServerComponentNode.ts
2763
+ function buildServerComponentNode(node, status, b) {
2764
+ status.output += HYDRATION_START_COMMENT;
2765
+ flushOutput(status, b);
2726
2766
  const componentHasProps = node.attributes.length;
2727
2767
  const propsName = componentHasProps ? nextVarName("props", status) : "undefined";
2728
2768
  if (componentHasProps) {
@@ -2760,7 +2800,7 @@ function buildServerComponentNode(node, status, b) {
2760
2800
  const nameAttribute = slot.attributes.find((a) => a.name === "name");
2761
2801
  const slotName = nameAttribute?.value ? trimQuotes(nameAttribute.value) : "_";
2762
2802
  const slotParams = [slot.hasSlotProps ? "$slot: Record<PropertyKey, any>" : "_$slot?: Record<PropertyKey, any>", "// @ts-ignore\n// eslint-disable-next-line no-unused-vars\n$context?: Record<PropertyKey, any>"];
2763
- b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = (\n${slotParams.join(",\n")}\n) => {`);
2803
+ b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = async (\n${slotParams.join(",\n")}\n) => {`);
2764
2804
  b.append(`let t_body = "";`);
2765
2805
  for (let child of slot.children) buildServerNode(child, status, b);
2766
2806
  if (status.output) {
@@ -2779,39 +2819,51 @@ function buildServerComponentNode(node, status, b) {
2779
2819
  let renderParams = `${propsName}, $context`;
2780
2820
  if (slotsName !== "undefined") renderParams += `, ${slotsName}`;
2781
2821
  const componentResult = nextVarName("comp", status);
2782
- b.append(`const ${componentResult} = ${componentName}(${renderParams});`);
2783
- b.append(`t_body += ${componentResult}.body;`);
2822
+ b.append(`const ${componentResult} = await ${componentName}(${renderParams});`);
2823
+ b.append(`${status.inHead ? "t_head" : "t_body"} += ${componentResult}.body;`);
2784
2824
  b.append(`t_head += ${componentResult}.head;`);
2785
2825
  status.output += HYDRATION_END_COMMENT;
2786
2826
  status.output += "<!>";
2787
2827
  }
2788
2828
  //#endregion
2789
2829
  //#region src/compile/build/server/buildServerAwaitNode.ts
2830
+ /**
2831
+ * Builds an `@await` boundary for the server (ASYNC.md → "Server rendering").
2832
+ *
2833
+ * Rather than inlining the `with` branch (the old shape), the boundary is
2834
+ * handed to the `t_await_server` runtime helper: content and `with` branches
2835
+ * become closures, and the helper decides at render time whether resolved
2836
+ * content can ship (all `source: "server"` reads settled) or the `with`
2837
+ * branch + client fetch is the honest output. The runtime emits the
2838
+ * hydration markers and anchor itself, including the `<!--t-await:...-->`
2839
+ * values payload for resolved boundaries.
2840
+ */
2790
2841
  function buildServerAwaitNode(node, status, b) {
2791
- status.output += HYDRATION_START_COMMENT;
2792
- if (status.output) {
2793
- b.append(`t_body += \`${status.output}\`;`);
2794
- status.output = "";
2795
- }
2796
- for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@with") buildServerAwaitBranch(branch, status, b);
2797
- status.output += HYDRATION_END_COMMENT;
2798
- status.output += "<!>";
2799
- }
2800
- function buildServerAwaitBranch(node, status, b) {
2801
- for (let child of node.children) buildServerNode(child, status, b);
2802
- if (status.output) {
2803
- b.append(`t_body += \`${status.output}\`;`);
2804
- status.output = "";
2805
- }
2842
+ flushOutput(status, b);
2843
+ status.imports.add("t_await_server");
2844
+ const id = status.awaitCount++;
2845
+ const resultName = nextVarName("await", status);
2846
+ b.append(`const ${resultName} = await t_await_server("${id}", async () => {`);
2847
+ b.append(`let t_body = "";`);
2848
+ b.append(`let t_head = "";`);
2849
+ for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@await") for (let child of branch.children) buildServerNode(child, status, b);
2850
+ flushOutput(status, b);
2851
+ b.append(`return { body: t_body, head: t_head };`);
2852
+ b.append(`}, async () => {`);
2853
+ b.append(`let t_body = "";`);
2854
+ b.append(`let t_head = "";`);
2855
+ for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@with") for (let child of branch.children) buildServerNode(child, status, b);
2856
+ flushOutput(status, b);
2857
+ b.append(`return { body: t_body, head: t_head };`);
2858
+ b.append(`});`);
2859
+ b.append(`${status.inHead ? "t_head" : "t_body"} += ${resultName}.body;`);
2860
+ b.append(`t_head += ${resultName}.head;`);
2806
2861
  }
2807
2862
  //#endregion
2808
2863
  //#region src/compile/build/server/buildServerForNode.ts
2809
2864
  function buildServerForNode(node, status, b) {
2810
2865
  status.output += HYDRATION_START_COMMENT;
2811
- if (status.output) {
2812
- b.append(`t_body += \`${status.output}\`;`);
2813
- status.output = "";
2814
- }
2866
+ flushOutput(status, b);
2815
2867
  for (let branch of node.children) if (isControlNode(branch)) buildServerForBranch(branch, status, b);
2816
2868
  status.output += HYDRATION_END_COMMENT;
2817
2869
  status.output += "<!>";
@@ -2820,10 +2872,7 @@ function buildServerForBranch(node, status, b) {
2820
2872
  b.append(`${node.statement} {`);
2821
2873
  status.output += HYDRATION_BREAK_COMMENT;
2822
2874
  for (let child of node.children) buildServerNode(child, status, b);
2823
- if (status.output) {
2824
- b.append(`t_body += \`${status.output}\`;`);
2825
- status.output = "";
2826
- }
2875
+ flushOutput(status, b);
2827
2876
  b.append("}");
2828
2877
  }
2829
2878
  //#endregion
@@ -2838,10 +2887,7 @@ function buildServerHtmlNode(node, status) {
2838
2887
  //#region src/compile/build/server/buildServerIfNode.ts
2839
2888
  function buildServerIfNode(node, status, b) {
2840
2889
  status.output += HYDRATION_START_COMMENT;
2841
- if (status.output) {
2842
- b.append(`t_body += \`${status.output}\`;`);
2843
- status.output = "";
2844
- }
2890
+ flushOutput(status, b);
2845
2891
  for (let branch of node.children) if (isControlNode(branch)) buildServerIfBranch(branch, status, b);
2846
2892
  status.output += HYDRATION_END_COMMENT;
2847
2893
  status.output += "<!>";
@@ -2850,20 +2896,14 @@ function buildServerIfBranch(node, status, b) {
2850
2896
  b.append(`${node.statement} {`);
2851
2897
  status.output += HYDRATION_BREAK_COMMENT;
2852
2898
  for (let child of node.children) buildServerNode(child, status, b);
2853
- if (status.output) {
2854
- b.append(`t_body += \`${status.output}\`;`);
2855
- status.output = "";
2856
- }
2899
+ flushOutput(status, b);
2857
2900
  b.append("}");
2858
2901
  }
2859
2902
  //#endregion
2860
2903
  //#region src/compile/build/server/buildServerReplaceNode.ts
2861
2904
  function buildServerReplaceNode(node, status, b) {
2862
2905
  status.output += HYDRATION_START_COMMENT;
2863
- if (status.output) {
2864
- b.append(`t_body += \`${status.output}\`;`);
2865
- status.output = "";
2866
- }
2906
+ flushOutput(status, b);
2867
2907
  for (let branch of node.children) if (isControlNode(branch)) buildServerReplaceBranch(branch, status, b);
2868
2908
  status.output += HYDRATION_END_COMMENT;
2869
2909
  status.output += "<!>";
@@ -2871,10 +2911,7 @@ function buildServerReplaceNode(node, status, b) {
2871
2911
  function buildServerReplaceBranch(node, status, b) {
2872
2912
  b.append(`${node.statement};`);
2873
2913
  for (let child of node.children) buildServerNode(child, status, b);
2874
- if (status.output) {
2875
- b.append(`t_body += \`${status.output}\`;`);
2876
- status.output = "";
2877
- }
2914
+ flushOutput(status, b);
2878
2915
  }
2879
2916
  //#endregion
2880
2917
  //#region src/compile/build/server/buildServerScriptNode.ts
@@ -2889,10 +2926,7 @@ function maybeAppend(text, end) {
2889
2926
  //#region src/compile/build/server/buildServerSwitchNode.ts
2890
2927
  function buildServerSwitchNode(node, status, b) {
2891
2928
  status.output += HYDRATION_START_COMMENT;
2892
- if (status.output) {
2893
- b.append(`t_body += \`${status.output}\`;`);
2894
- status.output = "";
2895
- }
2929
+ flushOutput(status, b);
2896
2930
  b.append(`${node.statement} {`);
2897
2931
  for (let branch of node.children.filter((c) => isControlNode(c))) if (isControlNode(branch)) buildServerSwitchBranch(branch, status, b);
2898
2932
  b.append("}");
@@ -2903,10 +2937,7 @@ function buildServerSwitchBranch(node, status, b) {
2903
2937
  b.append(`${node.statement} {`);
2904
2938
  status.output += HYDRATION_BREAK_COMMENT;
2905
2939
  for (let child of node.children) buildServerNode(child, status, b);
2906
- if (status.output) {
2907
- b.append(`t_body += \`${status.output}\`;`);
2908
- status.output = "";
2909
- }
2940
+ flushOutput(status, b);
2910
2941
  b.append("break;");
2911
2942
  b.append("}");
2912
2943
  }
@@ -2914,10 +2945,7 @@ function buildServerSwitchBranch(node, status, b) {
2914
2945
  //#region src/compile/build/server/buildServerTryNode.ts
2915
2946
  function buildServerTryNode(node, status, b) {
2916
2947
  status.output += HYDRATION_START_COMMENT;
2917
- if (status.output) {
2918
- b.append(`t_body += \`${status.output}\`;`);
2919
- status.output = "";
2920
- }
2948
+ flushOutput(status, b);
2921
2949
  const branches = node.children.filter((n) => isControlNode(n));
2922
2950
  let tryBranch = branches.find((n) => n.operation === "@try");
2923
2951
  let catchBranch = branches.find((n) => n.operation === "@catch");
@@ -2938,10 +2966,7 @@ function buildServerTryNode(node, status, b) {
2938
2966
  }
2939
2967
  function buildServerTryBranch(node, status, b) {
2940
2968
  for (let child of node.children) buildServerNode(child, status, b);
2941
- if (status.output) {
2942
- b.append(`t_body += \`${status.output}\`;`);
2943
- status.output = "";
2944
- }
2969
+ flushOutput(status, b);
2945
2970
  }
2946
2971
  //#endregion
2947
2972
  //#region src/compile/build/server/buildServerControlNode.ts
@@ -2982,18 +3007,12 @@ function buildServerControlNode(node, status, b) {
2982
3007
  break;
2983
3008
  case "@html": break;
2984
3009
  case "@const":
2985
- if (status.output) {
2986
- b.append(`t_body += \`${status.output}\`;`);
2987
- status.output = "";
2988
- }
3010
+ flushOutput(status, b);
2989
3011
  buildServerScriptNode(node, b);
2990
3012
  break;
2991
3013
  case "@function":
2992
3014
  case "@async function":
2993
- if (status.output) {
2994
- b.append(`t_body += \`${status.output}\`;`);
2995
- status.output = "";
2996
- }
3015
+ flushOutput(status, b);
2997
3016
  b.append("");
2998
3017
  buildServerScriptNode(node, b);
2999
3018
  b.append("");
@@ -3023,48 +3042,47 @@ function buildServerElementNode(node, status, b) {
3023
3042
  }
3024
3043
  }
3025
3044
  function buildElementAttributes(node, status) {
3026
- let needsClass = node.scopeStyles;
3045
+ let needsClass = node.scopeStyles && !status.inHead;
3027
3046
  let attributes = [];
3028
- for (let { name, value, reactive, fullyReactive } of node.attributes) if (name === "self" && node.tagName === "@element") {} else if (name === "&ref") {} else if (name.startsWith("on") || name.startsWith(":on")) {} else if (name.startsWith("transition") && value) {} else if (value != null && fullyReactive) if (name === "&value" || name === "&checked" || name === "&group") {
3029
- if (name === "&value" && node.tagName === "select" && node.attributes.some((a) => a.name === "multiple")) continue;
3030
- let defaultValue = "";
3031
- let typeAttribute = node.attributes.find((a) => a.name === "type");
3032
- if (typeAttribute && typeAttribute.value) switch (trimQuotes(typeAttribute.value)) {
3033
- case "number":
3034
- defaultValue = "0";
3035
- break;
3036
- case "checkbox":
3037
- defaultValue = "false";
3038
- break;
3039
- }
3040
- if (!defaultValue) {
3047
+ for (let { name, value, reactive, fullyReactive } of node.attributes) if (name === "self" && node.tagName === "@element") {} else if (name === "&ref") {} else if (name.startsWith("on") || name.startsWith(":on")) {} else if (name.startsWith("transition") && value) {} else if (value != null && fullyReactive) {
3048
+ if (name === "&value" || name === "&checked" || name === "&group") {
3049
+ if (name === "&value" && node.tagName === "select" && node.attributes.some((a) => a.name === "multiple")) continue;
3050
+ let defaultValue = "";
3051
+ let typeAttribute = node.attributes.find((a) => a.name === "type");
3052
+ if (typeAttribute && typeAttribute.value) switch (trimQuotes(typeAttribute.value)) {
3053
+ case "number":
3054
+ defaultValue = "0";
3055
+ break;
3056
+ case "checkbox": defaultValue = "false";
3057
+ }
3058
+ if (!defaultValue) {
3059
+ status.imports.add("t_attr");
3060
+ value = `t_attr(${value})`;
3061
+ defaultValue = "\"\"";
3062
+ }
3063
+ let valueOrDefault = `${value} || ${defaultValue}`;
3064
+ const propName = name.substring(1);
3065
+ attributes.push(`${propName}="\${${valueOrDefault}}"`);
3066
+ } else if (name === "class") {
3067
+ status.imports.add("t_class");
3068
+ let params = [value];
3069
+ if (node.scopeStyles && !status.inHead) {
3070
+ params.push(`"torp-${status.styleHash}"`);
3071
+ needsClass = false;
3072
+ }
3073
+ value = params.join(", ");
3074
+ attributes.push(`\${t_class(${value}) !== "" ? \`class="\${t_class(${value})}"\` : ""}`);
3075
+ } else if (name === "style") {
3076
+ status.imports.add("t_style");
3077
+ attributes.push(`\${t_style(${value}) !== "" ? \`style="\${t_style(${value})}"\` : ""}`);
3078
+ } else {
3041
3079
  status.imports.add("t_attr");
3042
- value = `t_attr(${value})`;
3043
- defaultValue = "\"\"";
3080
+ attributes.push(`\${${value} ? \`${name}="\${t_attr(${value})}"\` : ""}`);
3044
3081
  }
3045
- let valueOrDefault = `${value} || ${defaultValue}`;
3046
- const propName = name.substring(1);
3047
- attributes.push(`${propName}="\${${valueOrDefault}}"`);
3048
- } else if (name === "class") {
3049
- status.imports.add("t_class");
3050
- let params = [value];
3051
- if (node.scopeStyles) {
3052
- params.push(`"torp-${status.styleHash}"`);
3053
- needsClass = false;
3054
- }
3055
- value = params.join(", ");
3056
- attributes.push(`\${t_class(${value}) !== "" ? \`class="\${t_class(${value})}"\` : ""}`);
3057
- } else if (name === "style") {
3058
- status.imports.add("t_style");
3059
- attributes.push(`\${t_style(${value}) !== "" ? \`style="\${t_style(${value})}"\` : ""}`);
3060
- } else {
3061
- status.imports.add("t_attr");
3062
- attributes.push(`\${${value} ? \`${name}="\${t_attr(${value})}"\` : ""}`);
3063
- }
3064
- else if (value != null && reactive) {
3082
+ } else if (value != null && reactive) {
3065
3083
  status.imports.add("t_attr");
3066
3084
  attributes.push(`${name}="${trimQuotes(value).replaceAll("{", "${t_attr(").replaceAll("}", ")}")}"`);
3067
- } else if (name === "class" && node.scopeStyles) {
3085
+ } else if (name === "class" && node.scopeStyles && !status.inHead) {
3068
3086
  value = value ? `"${trimQuotes(value)} torp-${status.styleHash}"` : `"torp-${status.styleHash}"`;
3069
3087
  attributes.push(`${name}="${trimQuotes(value).replaceAll("\"", "&quot;")}"`);
3070
3088
  needsClass = false;
@@ -3082,10 +3100,7 @@ function buildServerRootNode(node, status, b) {
3082
3100
  //#region src/compile/build/server/buildServerSlotNode.ts
3083
3101
  function buildServerSlotNode(node, status, b) {
3084
3102
  status.output += HYDRATION_START_COMMENT;
3085
- if (status.output) {
3086
- b.append(`t_body += \`${status.output}\`;`);
3087
- status.output = "";
3088
- }
3103
+ flushOutput(status, b);
3089
3104
  let slotName = node.attributes.find((a) => a.name === "name")?.value;
3090
3105
  slotName = slotName ? trimQuotes(slotName) : "_";
3091
3106
  const propsName = nextVarName("slot_props", status);
@@ -3097,15 +3112,12 @@ function buildServerSlotNode(node, status, b) {
3097
3112
  else b.append(`${propsName}["${name}"] = true;`);
3098
3113
  }
3099
3114
  b.append(`if ($slots && $slots["${slotName}"]) {`);
3100
- b.append(`t_body += $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
3115
+ b.append(`${status.inHead ? "t_head" : "t_body"} += await $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
3101
3116
  const fill = node.children.find((c) => isSpecialNode(c) && (c.tagName === "fill" || c.tagName === "filldef"));
3102
3117
  if (fill && isSpecialNode(fill) && fill.children.length) {
3103
3118
  b.append(`} else {`);
3104
3119
  for (let child of fill.children) buildServerNode(child, status, b);
3105
- if (status.output) {
3106
- b.append(`t_body += \`${status.output}\`;`);
3107
- status.output = "";
3108
- }
3120
+ flushOutput(status, b);
3109
3121
  }
3110
3122
  b.append(`}`);
3111
3123
  status.output += HYDRATION_END_COMMENT;
@@ -3203,6 +3215,8 @@ const importsMap = {
3203
3215
  $unwrap: "import { $unwrap } from \"${folder}\";",
3204
3216
  $peek: "import { $peek } from \"${folder}\";",
3205
3217
  $batch: "import { $batch } from \"${folder}\";",
3218
+ t_server_flush: "import { t_server_flush } from \"${folder}\";",
3219
+ t_await_server: "import { t_await_server } from \"${folder}\";",
3206
3220
  t_fmt: "import { t_fmt } from \"${folder}\";",
3207
3221
  t_attr: "import { t_attr } from \"${folder}\";",
3208
3222
  t_class: "import { t_class } from \"${folder}\";",
@@ -3245,18 +3259,24 @@ function buildServerTemplate(template, imports, b, options) {
3245
3259
  if (/\$unwrap\b/.test(scriptCode)) imports.add("$unwrap");
3246
3260
  if (/\$peek\b/.test(scriptCode)) imports.add("$peek");
3247
3261
  if (/\$batch\b/.test(scriptCode)) imports.add("$batch");
3262
+ const asyncChunks = /* @__PURE__ */ new Set();
3263
+ for (let [i, chunk] of template.script.entries()) if (chunk.script === "/* @params */" && i > 0) asyncChunks.add(i - 1);
3248
3264
  let currentIndex = 0;
3249
3265
  let current = template.components[0];
3250
- for (let chunk of template.script) if (chunk.script === "/* @params */") {
3266
+ for (let [chunkIndex, chunk] of template.script.entries()) if (chunk.script === "/* @params */") {
3251
3267
  let params = [
3252
3268
  current.params ?? `${current.props?.length ? "$props: Record<PropertyKey, any>" : "_$props?: Record<PropertyKey, any>"}`,
3253
3269
  `${current.contextProps?.length || current.markup && markupRendersComponent(current.markup) || current.error && markupRendersComponent(current.error) ? "$context" : "_$context"}?: Record<PropertyKey, any>`,
3254
3270
  `${current.slotProps?.length ? "$slots" : "_$slots"}?: Record<string, ServerSlotRender>`
3255
3271
  ];
3256
3272
  b.append(params.join(",\n") + ",");
3257
- } else if (chunk.script === ") /* @return_type */ {") b.append("): { body: string; head: string } {");
3273
+ } else if (chunk.script === ") /* @return_type */ {") b.append("): Promise<{ body: string; head: string }> {");
3258
3274
  else if (chunk.script === "/* @start */") {
3259
3275
  if (current.contextProps?.length) b.append(`$context = Object.assign({}, $context);`);
3276
+ if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) {
3277
+ imports.add("t_server_flush");
3278
+ b.append(`return t_server_flush(async () => {`);
3279
+ }
3260
3280
  b.append(`let t_body = "";`);
3261
3281
  b.append(`let t_head = "";`);
3262
3282
  } else if (chunk.script === "/* @render */") {
@@ -3267,6 +3287,7 @@ function buildServerTemplate(template, imports, b, options) {
3267
3287
  styleHash: current.style?.hash || "",
3268
3288
  varNames: {},
3269
3289
  preserveWhitespace: false,
3290
+ awaitCount: 0,
3270
3291
  options
3271
3292
  };
3272
3293
  b.append("");
@@ -3290,6 +3311,7 @@ function buildServerTemplate(template, imports, b, options) {
3290
3311
  styleHash: current.style?.hash || "",
3291
3312
  varNames: {},
3292
3313
  preserveWhitespace: false,
3314
+ awaitCount: 0,
3293
3315
  options
3294
3316
  };
3295
3317
  b.append(`} catch (${current.errorVar}) {`);
@@ -3303,7 +3325,24 @@ function buildServerTemplate(template, imports, b, options) {
3303
3325
  }
3304
3326
  b.append("}");
3305
3327
  }
3306
- } else if (chunk.script === "/* @head */") {} else if (chunk.script === "/* @style */") {
3328
+ } else if (chunk.script === "/* @head */") {
3329
+ if (current.head) {
3330
+ const status = {
3331
+ imports,
3332
+ output: "",
3333
+ styleHash: current.style?.hash || "",
3334
+ varNames: {},
3335
+ preserveWhitespace: false,
3336
+ inHead: true,
3337
+ awaitCount: 0,
3338
+ options
3339
+ };
3340
+ b.append("");
3341
+ b.append("/* Head */");
3342
+ buildServerNode(current.head, status, b);
3343
+ flushOutput(status, b);
3344
+ }
3345
+ } else if (chunk.script === "/* @style */") {
3307
3346
  if (current.style) {
3308
3347
  b.append("");
3309
3348
  b.append("/* Style */");
@@ -3312,9 +3351,23 @@ function buildServerTemplate(template, imports, b, options) {
3312
3351
  }
3313
3352
  } else if (chunk.script === "/* @end */") {
3314
3353
  b.append(`return { body: t_body, head: t_head };`);
3354
+ if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) b.append(`});`);
3315
3355
  currentIndex += 1;
3316
3356
  current = template.components[currentIndex];
3317
- } else b.append(chunk.script);
3357
+ } else if (asyncChunks.has(chunkIndex)) b.append(chunk.script.replace(/(?<!async\s)function\s+([A-Za-z_$][\w$]*)((?:<(?:[^<>]|<[^<>]*>)*>)?)\s*\($/, "async function $1$2("));
3358
+ else b.append(chunk.script);
3359
+ }
3360
+ /**
3361
+ * Whether a markup tree contains an `@await` boundary, so the component's
3362
+ * render must be wrapped in a flush.
3363
+ */
3364
+ function containsAwaitGroup(node) {
3365
+ if (node === void 0 || node === null) return false;
3366
+ if (isControlNode(node) && node.operation === "@await group") return true;
3367
+ if (node.type !== "text" && node.type !== "comment") {
3368
+ for (let child of node.children) if (containsAwaitGroup(child)) return true;
3369
+ }
3370
+ return false;
3318
3371
  }
3319
3372
  //#endregion
3320
3373
  //#region src/compile/utils/trimWhitespace.ts
@@ -3532,9 +3585,10 @@ function parseInlineScript(status) {
3532
3585
  continue;
3533
3586
  }
3534
3587
  if (accept("{", status)) braceCount += 1;
3535
- else if (accept("}", status)) if (braceCount > 0) braceCount -= 1;
3536
- else return status.source.substring(start, status.i - 1);
3537
- else status.i += 1;
3588
+ else if (accept("}", status)) {
3589
+ if (braceCount > 0) braceCount -= 1;
3590
+ else return status.source.substring(start, status.i - 1);
3591
+ } else status.i += 1;
3538
3592
  }
3539
3593
  return "";
3540
3594
  }
@@ -3890,9 +3944,10 @@ function usesSlot(nodes) {
3890
3944
  */
3891
3945
  function slottifyChildNodes(node) {
3892
3946
  let nonFillNodes = [];
3893
- for (let child of node.children) if (isFillNode(child)) if (nonFillNodes.find((n) => !isSpaceNode(n)) === void 0) nonFillNodes = [];
3894
- else break;
3895
- else nonFillNodes.push(child);
3947
+ for (let child of node.children) if (isFillNode(child)) {
3948
+ if (nonFillNodes.find((n) => !isSpaceNode(n)) === void 0) nonFillNodes = [];
3949
+ else break;
3950
+ } else nonFillNodes.push(child);
3896
3951
  if (nonFillNodes.find((n) => !isSpaceNode(n)) === void 0) nonFillNodes = [];
3897
3952
  if (nonFillNodes.length) {
3898
3953
  let defaultFillNode = node.children.find((n) => isFillNode(n) && !n.attributes.find((a) => a.name === "name"));
@@ -4378,11 +4433,12 @@ function hash(input) {
4378
4433
  * @returns True if the supplied string was found at the current parse position
4379
4434
  */
4380
4435
  function expect(value, status, advance = true) {
4381
- if (status.i < status.source.length) if (status.source.substring(status.i, status.i + value.length) == value) {
4382
- status.i += advance ? value.length : 0;
4383
- return true;
4384
- } else addError(status, `Expected ${value}`);
4385
- else addError(status, "Expected token");
4436
+ if (status.i < status.source.length) {
4437
+ if (status.source.substring(status.i, status.i + value.length) == value) {
4438
+ status.i += advance ? value.length : 0;
4439
+ return true;
4440
+ } else addError(status, `Expected ${value}`);
4441
+ } else addError(status, "Expected token");
4386
4442
  return false;
4387
4443
  }
4388
4444
  //#endregion
@@ -4533,21 +4589,25 @@ function parseCode(source) {
4533
4589
  status.level = 0;
4534
4590
  }
4535
4591
  } else if (accept("function", status)) {
4536
- if (consumeSpace(status)) if (/[A-Z]/.test(source[status.i])) parseComponentStart(status);
4537
- else status.i--;
4592
+ if (consumeSpace(status)) {
4593
+ if (/[A-Z]/.test(source[status.i])) parseComponentStart(status);
4594
+ else status.i--;
4595
+ }
4538
4596
  } else if (accept("const", status)) {
4539
- if (consumeSpace(status)) if (/[A-Z]/.test(source[status.i])) {
4540
- const start = status.i;
4541
- consumeAlphaNumeric(status);
4542
- consumeSpace(status);
4543
- if (accept("=", status)) {
4597
+ if (consumeSpace(status)) {
4598
+ if (/[A-Z]/.test(source[status.i])) {
4599
+ const start = status.i;
4600
+ consumeAlphaNumeric(status);
4544
4601
  consumeSpace(status);
4545
- if (accept("(", status, false)) {
4546
- status.i = start;
4547
- parseComponentStart(status);
4602
+ if (accept("=", status)) {
4603
+ consumeSpace(status);
4604
+ if (accept("(", status, false)) {
4605
+ status.i = start;
4606
+ parseComponentStart(status);
4607
+ }
4548
4608
  }
4549
- }
4550
- } else status.i--;
4609
+ } else status.i--;
4610
+ }
4551
4611
  } else if (accept("export", status)) {
4552
4612
  const start = status.i;
4553
4613
  if (consumeSpace(status) && accept("default", status) && consumeSpace(status) && accept("(", status, false)) parseComponentStart(status);