@reckona/mreact-compiler 0.0.119 → 0.0.121

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.
@@ -64,9 +64,8 @@ export function emitServerStream(
64
64
  ): EmitServerStreamResult {
65
65
  const serverBootstrap = options.serverBootstrap ?? "none";
66
66
  const escapeHelperName = allocateHelperName(ir, "_escapeHtml");
67
- const escapeBatchHelperName = options.escape === undefined
68
- ? undefined
69
- : allocateHelperName(ir, "_escapeHtmlBatch");
67
+ const escapeBatchHelperName =
68
+ options.escape === undefined ? undefined : allocateHelperName(ir, "_escapeHtmlBatch");
70
69
  const asyncBoundaryHelperName = allocateHelperName(ir, "_renderAsyncBoundary");
71
70
  const outOfOrderBoundaryHelperName = allocateHelperName(ir, "_renderOutOfOrderBoundary");
72
71
  const reorderScriptHelperName = allocateHelperName(ir, "_renderOutOfOrderReorderScript");
@@ -167,7 +166,9 @@ export function emitServerStream(
167
166
  .join("\n");
168
167
  const userImports = emitUserImports(ir);
169
168
  const moduleStatements = emitModuleStatements(ir);
170
- const importsBlock = [importLine, escapeImport, userImports, moduleStatements].filter(Boolean).join("\n");
169
+ const importsBlock = [importLine, escapeImport, userImports, moduleStatements]
170
+ .filter(Boolean)
171
+ .join("\n");
171
172
  const needsSpreadAttributesHelper = components.includes(spreadAttributesHelperName);
172
173
  const urlSafeBlock =
173
174
  components.includes(urlSafeHelperName) || needsSpreadAttributesHelper ? urlSafeHelper : "";
@@ -412,11 +413,12 @@ function emitComponent(
412
413
  const { serverBootstrap, serverBootstrapNonce, serverBootstrapSrc } = options;
413
414
  const sinkName = allocateComponentSinkName(component);
414
415
  const parameters = [sinkName, ...component.parameters].join(", ");
415
- const body = component.bodyStatements.map((statement) =>
416
- ` ${statement.replaceAll(
417
- oxcServerStringReactNodeRenderHelperPlaceholder,
418
- compatRenderToStringHelperName,
419
- )}`,
416
+ const body = component.bodyStatements.map(
417
+ (statement) =>
418
+ ` ${statement.replaceAll(
419
+ oxcServerStringReactNodeRenderHelperPlaceholder,
420
+ compatRenderToStringHelperName,
421
+ )}`,
420
422
  );
421
423
  const markerId = encodeURIComponent(component.name);
422
424
  const hydrationStartStatements =
@@ -450,8 +452,13 @@ function emitComponent(
450
452
  ? [` ${sinkName}.append(${stringLiteral(`<!--mreact-h:end:${markerId}-->`)});`]
451
453
  : [];
452
454
  const exportPrefix =
453
- component.exportDefault === true ? "export default " : component.exported === false ? "" : "export ";
454
- const asyncPrefix = component.async === true || containsAnyAsyncBoundary(component.root) ? "async " : "";
455
+ component.exportDefault === true
456
+ ? "export default "
457
+ : component.exported === false
458
+ ? ""
459
+ : "export ";
460
+ const asyncPrefix =
461
+ component.async === true || containsAnyAsyncBoundary(component.root) ? "async " : "";
455
462
  const functionKeyword = `${exportPrefix}${asyncPrefix}function`;
456
463
 
457
464
  return [
@@ -750,9 +757,7 @@ function emitListPart(
750
757
  part.indexName === undefined ? undefined : `${innerIndent}const ${part.indexName} = _i;`;
751
758
  const arrayBinding =
752
759
  part.arrayName === undefined ? undefined : `${innerIndent}const ${part.arrayName} = _arr;`;
753
- const bodyLines = part.bodyStatements.map(
754
- (statement) => `${innerIndent}${statement}`,
755
- );
760
+ const bodyLines = part.bodyStatements.map((statement) => `${innerIndent}${statement}`);
756
761
  const coalescedParts = coalesceAdjacentStaticParts(part.parts);
757
762
 
758
763
  // Issue 085 follow-up: if every child part can be expressed as a
@@ -794,13 +799,7 @@ function emitListPart(
794
799
 
795
800
  const childLines =
796
801
  syncCoalescedParts === undefined
797
- ? [
798
- emitNestedStreamAppendStatements(
799
- coalescedParts,
800
- sinkName,
801
- compatRenderToStringHelperName,
802
- ),
803
- ]
802
+ ? [emitNestedStreamAppendStatements(coalescedParts, sinkName, compatRenderToStringHelperName)]
804
803
  : syncCoalescedParts.map((child) =>
805
804
  emitSyncPartAsAppendStatement(
806
805
  child,
@@ -857,7 +856,9 @@ function tryEmitPartAsStringExpression(
857
856
  return `${stringLiteral(`<!--mreact-h:start:${encodeURIComponent(part.hydrationId)}-->`)} + ${rendered} + ${stringLiteral(`<!--mreact-h:end:${encodeURIComponent(part.hydrationId)}-->`)}`;
858
857
  }
859
858
  if (part.kind === "component" && part.hydrationId === undefined) {
860
- return `${part.name}(${emitPropsObject(part.props, part.children, part.escapeHelperName)})`;
859
+ return emitRenderableHtmlExpression(
860
+ `${part.name}(${emitPropsObject(part.props, part.children, part.escapeHelperName)})`,
861
+ );
861
862
  }
862
863
  // Non-compat component parts require `await sink-write`; lists with
863
864
  // sink-needing children also can't collapse. Signal fallback.
@@ -891,7 +892,9 @@ function emitNestedAppendStatements(
891
892
  compatRenderToStringHelperName: string,
892
893
  ): string {
893
894
  return coalesceAdjacentStaticParts([...parts])
894
- .map((part) => emitSyncPartAsAppendStatement(part, sinkName, compatRenderToStringHelperName, " "))
895
+ .map((part) =>
896
+ emitSyncPartAsAppendStatement(part, sinkName, compatRenderToStringHelperName, " "),
897
+ )
895
898
  .join("\n");
896
899
  }
897
900
 
@@ -933,17 +936,13 @@ function emitNestedStreamAppendStatements(
933
936
  return emitLoweredReactSuspenseOutOfOrderBoundary(part, {
934
937
  compatRenderToStringHelperName,
935
938
  emitNestedAppendStatements,
936
- reactSuspenseOutOfOrderBoundaryHelperName: currentReactSuspenseOutOfOrderBoundaryHelperName,
939
+ reactSuspenseOutOfOrderBoundaryHelperName:
940
+ currentReactSuspenseOutOfOrderBoundaryHelperName,
937
941
  sinkName,
938
942
  }).replace(/^/gm, " ");
939
943
  }
940
944
 
941
- return emitSyncPartAsAppendStatement(
942
- part,
943
- sinkName,
944
- compatRenderToStringHelperName,
945
- " ",
946
- );
945
+ return emitSyncPartAsAppendStatement(part, sinkName, compatRenderToStringHelperName, " ");
947
946
  })
948
947
  .join("\n");
949
948
  }
@@ -1196,9 +1195,7 @@ function collectHtmlParts(
1196
1195
  ...(node.placeholderTagCode === undefined
1197
1196
  ? {}
1198
1197
  : { placeholderTagCode: node.placeholderTagCode }),
1199
- ...(state.awaitHydration && node.awaitId !== undefined
1200
- ? { awaitId: node.awaitId }
1201
- : {}),
1198
+ ...(state.awaitHydration && node.awaitId !== undefined ? { awaitId: node.awaitId } : {}),
1202
1199
  ...(node.catchName === undefined || node.catchChildren === undefined
1203
1200
  ? {}
1204
1201
  : {
@@ -1235,9 +1232,7 @@ function collectHtmlParts(
1235
1232
  state,
1236
1233
  ),
1237
1234
  ) as HtmlSyncPart[],
1238
- ...(state.awaitHydration && node.awaitId !== undefined
1239
- ? { awaitId: node.awaitId }
1240
- : {}),
1235
+ ...(state.awaitHydration && node.awaitId !== undefined ? { awaitId: node.awaitId } : {}),
1241
1236
  ...(node.catchName === undefined || node.catchChildren === undefined
1242
1237
  ? {}
1243
1238
  : {
@@ -1403,14 +1398,14 @@ function collectHtmlParts(
1403
1398
  if (isClientBoundaryPlaceholder(node, state.hydration)) {
1404
1399
  const helperName = currentClientBoundaryHelperName;
1405
1400
  if (helperName !== undefined) {
1401
+ const boundaryProps = emitPropsObject(node.props, [], escapeHelperName);
1402
+ const fallbackHtml = shouldRenderClientBoundaryFallback(node)
1403
+ ? `${node.name}(${boundaryProps})`
1404
+ : emitHtmlExpressionFromChildren(node.children, escapeHelperName);
1406
1405
  return [
1407
1406
  {
1408
1407
  kind: "raw-dynamic",
1409
- code: `${helperName}(${stringLiteral(node.name)}, ${emitPropsObject(
1410
- node.props,
1411
- [],
1412
- escapeHelperName,
1413
- )}, ${emitHtmlExpressionFromChildren(node.children, escapeHelperName)})`,
1408
+ code: `${helperName}(${stringLiteral(node.name)}, ${boundaryProps}, ${fallbackHtml})`,
1414
1409
  },
1415
1410
  ];
1416
1411
  }
@@ -1461,18 +1456,18 @@ function collectHtmlParts(
1461
1456
  ];
1462
1457
  }
1463
1458
  const attributeScan = scanElementAttributes(node.tagName, node.attributes);
1464
- const childSelectedValueCode = node.tagName === "select"
1465
- ? attributeScan.formValueAttributeCode
1466
- : undefined;
1467
- const childState = childSelectedValueCode === undefined
1468
- ? state
1469
- : { ...state, selectedValueCode: childSelectedValueCode };
1459
+ const childSelectedValueCode =
1460
+ node.tagName === "select" ? attributeScan.formValueAttributeCode : undefined;
1461
+ const childState =
1462
+ childSelectedValueCode === undefined
1463
+ ? state
1464
+ : { ...state, selectedValueCode: childSelectedValueCode };
1470
1465
  const selectedAttributePart = collectOptionSelectedAttributePart(node, state.selectedValueCode);
1471
1466
  const dangerousInnerHtml = emitDangerouslySetInnerHtmlPart(node.attributes);
1472
1467
  const childrenParts =
1473
1468
  dangerousInnerHtml !== undefined
1474
1469
  ? [dangerousInnerHtml]
1475
- : (childState.selectedValueCode === undefined
1470
+ : ((childState.selectedValueCode === undefined
1476
1471
  ? collectBatchedSimpleChildrenParts(node.children, state.escapeBatchHelperName)
1477
1472
  : undefined) ??
1478
1473
  node.children.flatMap((child) =>
@@ -1485,7 +1480,7 @@ function collectHtmlParts(
1485
1480
  reactSuspenseOutOfOrderBoundaryHelperName,
1486
1481
  childState,
1487
1482
  ),
1488
- );
1483
+ ));
1489
1484
 
1490
1485
  return [
1491
1486
  { kind: "static", value: `<${node.tagName}` },
@@ -1585,7 +1580,16 @@ function collectHtmlAttributeParts(
1585
1580
  }
1586
1581
 
1587
1582
  if (attr.name === "style") {
1588
- return [{ kind: "raw-dynamic", code: emitDynamicStyleAttributeExpression(attr.code, escapeHelperName, escapeBatchHelperName) }];
1583
+ return [
1584
+ {
1585
+ kind: "raw-dynamic",
1586
+ code: emitDynamicStyleAttributeExpression(
1587
+ attr.code,
1588
+ escapeHelperName,
1589
+ escapeBatchHelperName,
1590
+ ),
1591
+ },
1592
+ ];
1589
1593
  }
1590
1594
 
1591
1595
  const dynamicHtmlName = htmlAttributeNameForElement(tagName, attr.name);
@@ -1593,7 +1597,7 @@ function collectHtmlAttributeParts(
1593
1597
  return [
1594
1598
  {
1595
1599
  kind: "raw-dynamic",
1596
- code: `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; if (typeof _value === "object" && _value !== null && typeof _value.__html === "string") return ${stringLiteral(` ${dynamicHtmlName}="`)} + ${escapeHelperName}(_value.__html) + ${stringLiteral("\"")}; return ""; })()`,
1600
+ code: `(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; if (typeof _value === "object" && _value !== null && typeof _value.__html === "string") return ${stringLiteral(` ${dynamicHtmlName}="`)} + ${escapeHelperName}(_value.__html) + ${stringLiteral('"')}; return ""; })()`,
1597
1601
  },
1598
1602
  ];
1599
1603
  }
@@ -1626,11 +1630,11 @@ function collectElementAttributeParts(
1626
1630
 
1627
1631
  return attrs.flatMap((attr) =>
1628
1632
  attr.kind !== "spread-attr" &&
1629
- ((tagName === "input" &&
1630
- ((attr.name === "defaultValue" && attributeScan.hasExplicitInputValue) ||
1631
- (attr.name === "defaultChecked" && attributeScan.hasExplicitInputChecked))) ||
1632
- ((tagName === "textarea" || tagName === "select") &&
1633
- (attr.name === "value" || attr.name === "defaultValue")))
1633
+ ((tagName === "input" &&
1634
+ ((attr.name === "defaultValue" && attributeScan.hasExplicitInputValue) ||
1635
+ (attr.name === "defaultChecked" && attributeScan.hasExplicitInputChecked))) ||
1636
+ ((tagName === "textarea" || tagName === "select") &&
1637
+ (attr.name === "value" || attr.name === "defaultValue")))
1634
1638
  ? []
1635
1639
  : collectHtmlAttributeParts(
1636
1640
  tagName,
@@ -1704,10 +1708,7 @@ function scanElementAttributes(
1704
1708
 
1705
1709
  if ((tagName === "textarea" || tagName === "select") && attr.name === "value") {
1706
1710
  valueAttributeCode = readFormValueAttributeCode(attr);
1707
- } else if (
1708
- (tagName === "textarea" || tagName === "select") &&
1709
- attr.name === "defaultValue"
1710
- ) {
1711
+ } else if ((tagName === "textarea" || tagName === "select") && attr.name === "defaultValue") {
1711
1712
  defaultValueAttributeCode = readFormValueAttributeCode(attr);
1712
1713
  }
1713
1714
  }
@@ -1735,17 +1736,17 @@ function emitDynamicAttributeExpression(
1735
1736
  escapeHelperName: string,
1736
1737
  ): string {
1737
1738
  if (isUrlAttribute(name)) {
1738
- return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; const _checked = ${currentUrlSafeHelperName}(${stringLiteral(name)}, _value === true ? "" : _value); return _checked === undefined ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_checked) + ${stringLiteral("\"")}; })()`;
1739
+ return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; const _checked = ${currentUrlSafeHelperName}(${stringLiteral(name)}, _value === true ? "" : _value); return _checked === undefined ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_checked) + ${stringLiteral('"')}; })()`;
1739
1740
  }
1740
1741
 
1741
1742
  const inlineExpr = simpleSideEffectFreeExpression(code);
1742
1743
 
1743
1744
  if (inlineExpr !== undefined) {
1744
1745
  // Inline 3 evaluations to avoid per-attribute IIFE closure allocation.
1745
- return `(${inlineExpr} == null || ${inlineExpr} === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(${inlineExpr} === true ? "" : ${inlineExpr}) + ${stringLiteral("\"")})`;
1746
+ return `(${inlineExpr} == null || ${inlineExpr} === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(${inlineExpr} === true ? "" : ${inlineExpr}) + ${stringLiteral('"')})`;
1746
1747
  }
1747
1748
 
1748
- return `(() => { const _value = (${code}); return _value == null || _value === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value === true ? "" : _value) + ${stringLiteral("\"")}; })()`;
1749
+ return `(() => { const _value = (${code}); return _value == null || _value === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value === true ? "" : _value) + ${stringLiteral('"')}; })()`;
1749
1750
  }
1750
1751
 
1751
1752
  function emitDynamicStyleAttributeExpression(
@@ -1759,11 +1760,12 @@ function emitDynamicStyleAttributeExpression(
1759
1760
  return staticStyleExpression;
1760
1761
  }
1761
1762
 
1762
- const escapedPair = escapeBatchHelperName === undefined
1763
- ? `${escapeHelperName}(_cssName) + ":" + ${escapeHelperName}(_styleValue === true ? "" : _styleValue)`
1764
- : `(() => { const _escaped = ${escapeBatchHelperName}([_cssName, _styleValue === true ? "" : _styleValue]); return _escaped[0] + ":" + _escaped[1]; })()`;
1763
+ const escapedPair =
1764
+ escapeBatchHelperName === undefined
1765
+ ? `${escapeHelperName}(_cssName) + ":" + ${escapeHelperName}(_styleValue === true ? "" : _styleValue)`
1766
+ : `(() => { const _escaped = ${escapeBatchHelperName}([_cssName, _styleValue === true ? "" : _styleValue]); return _escaped[0] + ":" + _escaped[1]; })()`;
1765
1767
 
1766
- return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; if (typeof _value === "string") { const _style = ${escapeHelperName}(_value); return _style === "" ? "" : ${stringLiteral(" style=\"")} + _style + ${stringLiteral("\"")}; } const _style = Object.entries(_value).filter(([, _styleValue]) => _styleValue != null && _styleValue !== false).map(([_styleName, _styleValue]) => { const _cssName = String(_styleName).startsWith("--") ? String(_styleName) : String(_styleName).replace(/[A-Z]/g, (_char) => "-" + _char.toLowerCase()); return ${escapedPair}; }).join(";"); return _style === "" ? "" : ${stringLiteral(" style=\"")} + _style + ${stringLiteral("\"")}; })()`;
1768
+ return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; if (typeof _value === "string") { const _style = ${escapeHelperName}(_value); return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; } const _style = Object.entries(_value).filter(([, _styleValue]) => _styleValue != null && _styleValue !== false).map(([_styleName, _styleValue]) => { const _cssName = String(_styleName).startsWith("--") ? String(_styleName) : String(_styleName).replace(/[A-Z]/g, (_char) => "-" + _char.toLowerCase()); return ${escapedPair}; }).join(";"); return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; })()`;
1767
1769
  }
1768
1770
 
1769
1771
  function emitStaticStyleObjectAttributeExpression(
@@ -1797,11 +1799,12 @@ function emitStaticStyleObjectAttributeExpression(
1797
1799
  return stringLiteral(` style="${parts.join(";")}"`);
1798
1800
  }
1799
1801
 
1800
- const statements = entries.map((entry) =>
1801
- `{ const _v = (${entry.valueCode}); if (_v != null && _v !== false) _style += (_style === "" ? "" : ";") + ${stringLiteral(`${entry.cssName}:`)} + ${escapeHelperName}(_v === true ? "" : _v); }`
1802
+ const statements = entries.map(
1803
+ (entry) =>
1804
+ `{ const _v = (${entry.valueCode}); if (_v != null && _v !== false) _style += (_style === "" ? "" : ";") + ${stringLiteral(`${entry.cssName}:`)} + ${escapeHelperName}(_v === true ? "" : _v); }`,
1802
1805
  );
1803
1806
 
1804
- return `(() => { let _style = ""; ${statements.join(" ")} return _style === "" ? "" : ${stringLiteral(" style=\"")} + _style + ${stringLiteral("\"")}; })()`;
1807
+ return `(() => { let _style = ""; ${statements.join(" ")} return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; })()`;
1805
1808
  }
1806
1809
 
1807
1810
  function collectTextareaValueParts(
@@ -1828,7 +1831,7 @@ function collectTextareaValueParts(
1828
1831
  reactSuspenseBoundaryHelperName,
1829
1832
  reactSuspenseOutOfOrderBoundaryHelperName,
1830
1833
  state,
1831
- )
1834
+ ),
1832
1835
  );
1833
1836
  }
1834
1837
 
@@ -1852,9 +1855,13 @@ function collectOptionSelectedAttributePart(
1852
1855
  }
1853
1856
 
1854
1857
  function findOptionValueCode(node: Extract<JsxNodeIr, { kind: "element" }>): string | undefined {
1855
- const valueAttr = node.attributes.find((attr) => attr.kind !== "spread-attr" && attr.name === "value");
1858
+ const valueAttr = node.attributes.find(
1859
+ (attr) => attr.kind !== "spread-attr" && attr.name === "value",
1860
+ );
1856
1861
  if (valueAttr !== undefined && valueAttr.kind !== "event" && valueAttr.kind !== "spread-attr") {
1857
- return valueAttr.kind === "static-attr" ? stringLiteral(valueAttr.value) : `(${valueAttr.code})`;
1862
+ return valueAttr.kind === "static-attr"
1863
+ ? stringLiteral(valueAttr.value)
1864
+ : `(${valueAttr.code})`;
1858
1865
  }
1859
1866
 
1860
1867
  return node.children.every((child) => child.kind === "text")
@@ -2045,7 +2052,8 @@ function collectBatchedSimpleChildrenParts(
2045
2052
  }
2046
2053
 
2047
2054
  const dynamicChildren = children.filter(
2048
- (child) => child.kind === "expr" && child.renderMode !== "html" && child.renderMode !== "react-node",
2055
+ (child) =>
2056
+ child.kind === "expr" && child.renderMode !== "html" && child.renderMode !== "react-node",
2049
2057
  ) as Array<Extract<JsxNodeIr, { kind: "expr" }>>;
2050
2058
 
2051
2059
  if (dynamicChildren.length < 2) {
@@ -2056,7 +2064,11 @@ function collectBatchedSimpleChildrenParts(
2056
2064
  children.some(
2057
2065
  (child) =>
2058
2066
  child.kind !== "text" &&
2059
- !(child.kind === "expr" && child.renderMode !== "html" && child.renderMode !== "react-node"),
2067
+ !(
2068
+ child.kind === "expr" &&
2069
+ child.renderMode !== "html" &&
2070
+ child.renderMode !== "react-node"
2071
+ ),
2060
2072
  )
2061
2073
  ) {
2062
2074
  return undefined;
@@ -2106,8 +2118,8 @@ function emitHtmlExpressionFromChildren(children: JsxNodeIr[], escapeHelperName:
2106
2118
  );
2107
2119
  const expressions = parts.map((part) =>
2108
2120
  isHtmlSyncPart(part)
2109
- ? tryEmitPartAsStringExpression(part, currentCompatRenderToStringHelperName) ?? '""'
2110
- : '""'
2121
+ ? (tryEmitPartAsStringExpression(part, currentCompatRenderToStringHelperName) ?? '""')
2122
+ : '""',
2111
2123
  );
2112
2124
 
2113
2125
  return expressions.length === 0 ? '""' : expressions.join(" + ");
@@ -2275,8 +2287,7 @@ function containsAsyncComponent(children: readonly JsxNodeIr[]): boolean {
2275
2287
  child.async === true ||
2276
2288
  containsAsyncComponent(child.children) ||
2277
2289
  child.props.some(
2278
- (prop) =>
2279
- prop.kind === "render-prop" && containsAsyncComponent(prop.children),
2290
+ (prop) => prop.kind === "render-prop" && containsAsyncComponent(prop.children),
2280
2291
  )
2281
2292
  );
2282
2293
  }
@@ -2522,7 +2533,20 @@ function isClientBoundaryPlaceholder(
2522
2533
  }
2523
2534
 
2524
2535
  function isCompatClientReference(node: Extract<JsxNodeIr, { kind: "component" }>): boolean {
2525
- return node.clientReference !== undefined && /\.(?:compat)\.[cm]?[jt]sx?$/.test(node.clientReference.moduleId);
2536
+ return (
2537
+ node.clientReference !== undefined &&
2538
+ /\.(?:compat)\.[cm]?[jt]sx?$/.test(node.clientReference.moduleId)
2539
+ );
2540
+ }
2541
+
2542
+ function emitRenderableHtmlExpression(code: string): string {
2543
+ return `((_value) => _value == null || typeof _value === "boolean" ? "" : _value)(${code})`;
2544
+ }
2545
+
2546
+ function shouldRenderClientBoundaryFallback(
2547
+ node: Extract<JsxNodeIr, { kind: "component" }>,
2548
+ ): boolean {
2549
+ return node.clientReference?.ssrFallback === true;
2526
2550
  }
2527
2551
 
2528
2552
  function clientBoundaryPlaceholder(node: Extract<JsxNodeIr, { kind: "component" }>): string {