@barefootjs/jsx 0.5.2 → 0.6.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.
- package/dist/adapters/parsed-expr-emitter.d.ts +1 -1
- package/dist/adapters/parsed-expr-emitter.d.ts.map +1 -1
- package/dist/combine-client-js.d.ts.map +1 -1
- package/dist/expression-parser.d.ts +1 -1
- package/dist/expression-parser.d.ts.map +1 -1
- package/dist/index.js +330 -70
- package/dist/ir-to-client-js/collect-elements.d.ts +26 -14
- package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/event-delegation.d.ts +8 -3
- package/dist/ir-to-client-js/control-flow/plan/event-delegation.d.ts.map +1 -1
- package/dist/ir-to-client-js/emit-reactive.d.ts.map +1 -1
- package/dist/ir-to-client-js/generate-init.d.ts.map +1 -1
- package/dist/ir-to-client-js/html-template.d.ts +30 -1
- package/dist/ir-to-client-js/html-template.d.ts.map +1 -1
- package/dist/ir-to-client-js/imports.d.ts +2 -2
- package/dist/ir-to-client-js/imports.d.ts.map +1 -1
- package/dist/ir-to-client-js/phases/provider-and-child-inits.d.ts.map +1 -1
- package/dist/ir-to-client-js/plan/static-array-child-init.d.ts +3 -3
- package/dist/ir-to-client-js/plan/static-array-child-init.d.ts.map +1 -1
- package/dist/ir-to-client-js/types.d.ts +36 -4
- package/dist/ir-to-client-js/types.d.ts.map +1 -1
- package/dist/ir-to-client-js/utils.d.ts +19 -1
- package/dist/ir-to-client-js/utils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +203 -203
- package/src/__tests__/child-components-in-map.test.ts +333 -0
- package/src/__tests__/combine-client-js.test.ts +47 -0
- package/src/__tests__/dangerously-set-inner-html.test.ts +82 -0
- package/src/__tests__/expression-parser.test.ts +167 -13
- package/src/__tests__/ir-to-client-js/reactivity.test.ts +1 -0
- package/src/__tests__/staged-ir/06-multi-stage-soak.test.ts +18 -3
- package/src/__tests__/static-loop-csr-materialize.test.ts +6 -4
- package/src/__tests__/text-slot-escaping.test.ts +56 -0
- package/src/adapters/parsed-expr-emitter.ts +7 -0
- package/src/combine-client-js.ts +66 -22
- package/src/expression-parser.ts +200 -17
- package/src/ir-to-client-js/collect-elements.ts +170 -32
- package/src/ir-to-client-js/control-flow/plan/build-event-delegation.ts +1 -1
- package/src/ir-to-client-js/control-flow/plan/build-loop.ts +2 -1
- package/src/ir-to-client-js/control-flow/plan/event-delegation.ts +8 -3
- package/src/ir-to-client-js/control-flow/stringify/event-delegation.ts +3 -3
- package/src/ir-to-client-js/emit-reactive.ts +9 -0
- package/src/ir-to-client-js/emit-registration.ts +1 -1
- package/src/ir-to-client-js/generate-init.ts +16 -1
- package/src/ir-to-client-js/html-template.ts +238 -12
- package/src/ir-to-client-js/imports.ts +1 -1
- package/src/ir-to-client-js/index.ts +1 -0
- package/src/ir-to-client-js/phases/provider-and-child-inits.ts +12 -1
- package/src/ir-to-client-js/plan/build-static-array-child-init.ts +4 -8
- package/src/ir-to-client-js/plan/static-array-child-init.ts +3 -3
- package/src/ir-to-client-js/types.ts +37 -4
- package/src/ir-to-client-js/utils.ts +41 -1
package/dist/index.js
CHANGED
|
@@ -273,6 +273,21 @@ function buildChainedArrayExpr(elem) {
|
|
|
273
273
|
chainOrder: elem.chainOrder
|
|
274
274
|
});
|
|
275
275
|
}
|
|
276
|
+
function loopOffsetTerms(offset) {
|
|
277
|
+
if (!offset)
|
|
278
|
+
return [];
|
|
279
|
+
const terms = [];
|
|
280
|
+
if (offset.staticCount)
|
|
281
|
+
terms.push(String(offset.staticCount));
|
|
282
|
+
terms.push(...offset.dynamicTerms);
|
|
283
|
+
return terms;
|
|
284
|
+
}
|
|
285
|
+
function buildLoopChildIndexExpr(indexParam, offset) {
|
|
286
|
+
return [indexParam, ...loopOffsetTerms(offset)].join(" + ");
|
|
287
|
+
}
|
|
288
|
+
function buildLoopChildIndexSubtraction(offset) {
|
|
289
|
+
return loopOffsetTerms(offset).map((term) => ` - ${term}`).join("");
|
|
290
|
+
}
|
|
276
291
|
var jsxToDomEventMap = {
|
|
277
292
|
doubleclick: "dblclick"
|
|
278
293
|
};
|
|
@@ -1036,16 +1051,30 @@ function maybeHoistedScopeAttr(inHoistedChildren, node) {
|
|
|
1036
1051
|
}
|
|
1037
1052
|
var UNSAFE_TEMPLATE_EXPR = "undefined";
|
|
1038
1053
|
function templateAttrExpr(attrName, valExpr, presenceOrUndefined) {
|
|
1054
|
+
if (attrName === "dangerouslySetInnerHTML")
|
|
1055
|
+
return "";
|
|
1039
1056
|
if (isBooleanAttr(attrName) || presenceOrUndefined) {
|
|
1040
1057
|
return `\${${valExpr} ? '${attrName}' : ''}`;
|
|
1041
1058
|
}
|
|
1042
1059
|
if (attrName === "style") {
|
|
1043
|
-
return `\${((v) => v != null ? 'style="' + v + '"' : '')(styleToCss(${valExpr}))}`;
|
|
1060
|
+
return `\${((v) => v != null ? 'style="' + ${escapeAttrValueExpr("v")} + '"' : '')(styleToCss(${valExpr}))}`;
|
|
1044
1061
|
}
|
|
1045
1062
|
if (attrName === "data-key" || attrName.startsWith("data-key-")) {
|
|
1046
1063
|
return `${attrName}="\${${valExpr}}"`;
|
|
1047
1064
|
}
|
|
1048
|
-
return `\${(${valExpr}) != null ? '${attrName}="' +
|
|
1065
|
+
return `\${(${valExpr}) != null ? '${attrName}="' + ${escapeAttrValueExpr(valExpr)} + '"' : ''}`;
|
|
1066
|
+
}
|
|
1067
|
+
function escapeAttrValueExpr(valExpr) {
|
|
1068
|
+
return `escapeAttr(${valExpr})`;
|
|
1069
|
+
}
|
|
1070
|
+
function escapeTextSlotExpr(innerExpr) {
|
|
1071
|
+
return `escapeText(${innerExpr})`;
|
|
1072
|
+
}
|
|
1073
|
+
function dangerouslyHtmlChildren(attrs, toExpr) {
|
|
1074
|
+
const attr = attrs.find((a) => a.name === "dangerouslySetInnerHTML");
|
|
1075
|
+
if (!attr || attr.value.kind !== "expression")
|
|
1076
|
+
return null;
|
|
1077
|
+
return `\${((${toExpr(attr.value)}) ?? {}).__html ?? ''}`;
|
|
1049
1078
|
}
|
|
1050
1079
|
function transformKeyValue(value, transformExpr) {
|
|
1051
1080
|
switch (value.kind) {
|
|
@@ -1093,6 +1122,8 @@ function isMergeableAttr(a, ctx) {
|
|
|
1093
1122
|
return false;
|
|
1094
1123
|
if (a.name === "key")
|
|
1095
1124
|
return false;
|
|
1125
|
+
if (a.name === "dangerouslySetInnerHTML")
|
|
1126
|
+
return false;
|
|
1096
1127
|
const v = a.value;
|
|
1097
1128
|
if (v.kind === "jsx-children")
|
|
1098
1129
|
return false;
|
|
@@ -1191,7 +1222,7 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
|
|
|
1191
1222
|
}
|
|
1192
1223
|
const attrs = attrParts.join(" ");
|
|
1193
1224
|
const childrenRecurse = (n) => irToHtmlTemplate(n, restSpreadNames, loopDepth, loopParams, branchSlotsVar, insideLoop, false);
|
|
1194
|
-
const children = node.children.map(childrenRecurse).join("");
|
|
1225
|
+
const children = dangerouslyHtmlChildren(node.attrs, (v) => wrapExpr(v.expr)) ?? node.children.map(childrenRecurse).join("");
|
|
1195
1226
|
if (children || !VOID_ELEMENTS.has(node.tag)) {
|
|
1196
1227
|
return `<${node.tag}${attrs ? " " + attrs : ""}>${children}</${node.tag}>`;
|
|
1197
1228
|
}
|
|
@@ -1203,7 +1234,9 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
|
|
|
1203
1234
|
if (node.expr === "null" || node.expr === "undefined")
|
|
1204
1235
|
return "";
|
|
1205
1236
|
if (node.slotId) {
|
|
1206
|
-
|
|
1237
|
+
const inner = wrapInterpolation(wrapExpr(node.expr));
|
|
1238
|
+
const slotted = branchSlotsVar ? inner : escapeTextSlotExpr(inner);
|
|
1239
|
+
return `<!--bf:${node.slotId}-->\${${slotted}}<!--/-->`;
|
|
1207
1240
|
}
|
|
1208
1241
|
return `\${${wrapInterpolation(wrapExpr(node.expr))}}`;
|
|
1209
1242
|
case "conditional": {
|
|
@@ -1301,7 +1334,7 @@ function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParam
|
|
|
1301
1334
|
attrParts.push(`bf="${node.slotId}"`);
|
|
1302
1335
|
}
|
|
1303
1336
|
const attrs = attrParts.join(" ");
|
|
1304
|
-
const children = node.children.map(recurse).join("");
|
|
1337
|
+
const children = dangerouslyHtmlChildren(node.attrs, (v) => wrapExpr(v.expr)) ?? node.children.map(recurse).join("");
|
|
1305
1338
|
if (children || !VOID_ELEMENTS.has(node.tag)) {
|
|
1306
1339
|
return `<${node.tag}${attrs ? " " + attrs : ""}>${children}</${node.tag}>`;
|
|
1307
1340
|
}
|
|
@@ -1313,7 +1346,7 @@ function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParam
|
|
|
1313
1346
|
if (node.expr === "null" || node.expr === "undefined")
|
|
1314
1347
|
return "";
|
|
1315
1348
|
if (node.slotId) {
|
|
1316
|
-
return `<!--bf:${node.slotId}-->\${${wrapExpr(node.expr)}}<!--/-->`;
|
|
1349
|
+
return `<!--bf:${node.slotId}-->\${${escapeTextSlotExpr(wrapExpr(node.expr))}}<!--/-->`;
|
|
1317
1350
|
}
|
|
1318
1351
|
return `\${${wrapExpr(node.expr)}}`;
|
|
1319
1352
|
case "conditional": {
|
|
@@ -1529,7 +1562,7 @@ function irToComponentTemplateWithOpts(node, opts) {
|
|
|
1529
1562
|
attrParts.push(`bf="${node.slotId}"`);
|
|
1530
1563
|
}
|
|
1531
1564
|
const attrs = attrParts.join(" ");
|
|
1532
|
-
const children = node.children.map(childrenRecurse).join("");
|
|
1565
|
+
const children = dangerouslyHtmlChildren(node.attrs, (v) => transformExpr(v.expr, v.templateExpr)) ?? node.children.map(childrenRecurse).join("");
|
|
1533
1566
|
if (children || !VOID_ELEMENTS.has(node.tag)) {
|
|
1534
1567
|
return `<${node.tag}${attrs ? " " + attrs : ""}>${children}</${node.tag}>`;
|
|
1535
1568
|
}
|
|
@@ -1541,7 +1574,7 @@ function irToComponentTemplateWithOpts(node, opts) {
|
|
|
1541
1574
|
if (node.expr === "null" || node.expr === "undefined")
|
|
1542
1575
|
return "";
|
|
1543
1576
|
if (node.slotId) {
|
|
1544
|
-
return `<!--bf:${node.slotId}-->\${${transformExpr(node.expr, node.templateExpr)}}<!--/-->`;
|
|
1577
|
+
return `<!--bf:${node.slotId}-->\${${escapeTextSlotExpr(transformExpr(node.expr, node.templateExpr))}}<!--/-->`;
|
|
1545
1578
|
}
|
|
1546
1579
|
return `\${${transformExpr(node.expr, node.templateExpr)}}`;
|
|
1547
1580
|
case "conditional": {
|
|
@@ -1677,7 +1710,19 @@ function canGenerateStaticTemplate(node, propNames, inlinableConstants, unsafeLo
|
|
|
1677
1710
|
return assertNever(node);
|
|
1678
1711
|
}
|
|
1679
1712
|
}
|
|
1680
|
-
function generateCsrTemplate(node, inlinableConstants, ctx, insideLoop, restSpreadNames, propsObjectName, unsafeLocalNames) {
|
|
1713
|
+
function generateCsrTemplate(node, inlinableConstants, ctx, insideLoop, restSpreadNames, propsObjectName, unsafeLocalNames, deferredChildSlots) {
|
|
1714
|
+
const base = buildSignalMemoEnv(ctx.signals, ctx.memos, propsObjectName ?? null);
|
|
1715
|
+
const csrEnv = { substitutions: new Map(base.substitutions), propsObjectName: base.propsObjectName };
|
|
1716
|
+
if (inlinableConstants) {
|
|
1717
|
+
for (const [name, value] of inlinableConstants) {
|
|
1718
|
+
if (!csrEnv.substitutions.has(name)) {
|
|
1719
|
+
csrEnv.substitutions.set(name, { kind: "identifier", replacement: value, freeIdentifiers: new Set });
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
return generateCsrTemplateWithOpts(node, { inlinableConstants, restSpreadNames, propsObjectName, csrEnv, insideLoop, unsafeLocalNames, deferredChildSlots, loopDepth: -1 });
|
|
1724
|
+
}
|
|
1725
|
+
function buildCsrEnvForCtx(ctx, inlinableConstants, propsObjectName) {
|
|
1681
1726
|
const base = buildSignalMemoEnv(ctx.signals, ctx.memos, propsObjectName ?? null);
|
|
1682
1727
|
const csrEnv = { substitutions: new Map(base.substitutions), propsObjectName: base.propsObjectName };
|
|
1683
1728
|
if (inlinableConstants) {
|
|
@@ -1687,7 +1732,71 @@ function generateCsrTemplate(node, inlinableConstants, ctx, insideLoop, restSpre
|
|
|
1687
1732
|
}
|
|
1688
1733
|
}
|
|
1689
1734
|
}
|
|
1690
|
-
return
|
|
1735
|
+
return csrEnv;
|
|
1736
|
+
}
|
|
1737
|
+
function propResolvesUnsafe(prop, env, unsafeLocalNames) {
|
|
1738
|
+
if (unsafeLocalNames.size === 0)
|
|
1739
|
+
return false;
|
|
1740
|
+
let source;
|
|
1741
|
+
switch (prop.value.kind) {
|
|
1742
|
+
case "expression":
|
|
1743
|
+
case "spread":
|
|
1744
|
+
source = prop.value.expr;
|
|
1745
|
+
break;
|
|
1746
|
+
case "template":
|
|
1747
|
+
source = attrValueToString(prop.value, { useTemplate: true }) ?? undefined;
|
|
1748
|
+
break;
|
|
1749
|
+
default:
|
|
1750
|
+
return false;
|
|
1751
|
+
}
|
|
1752
|
+
if (!source)
|
|
1753
|
+
return false;
|
|
1754
|
+
const { freeIdentifiers } = csrSubstitute(source, env);
|
|
1755
|
+
return setIntersects(freeIdentifiers, unsafeLocalNames);
|
|
1756
|
+
}
|
|
1757
|
+
function computeDeferredChildSlots(node, ctx, inlinableConstants, unsafeLocalNames, propsObjectName) {
|
|
1758
|
+
const deferred = new Set;
|
|
1759
|
+
if (!unsafeLocalNames || unsafeLocalNames.size === 0)
|
|
1760
|
+
return deferred;
|
|
1761
|
+
const env = buildCsrEnvForCtx(ctx, inlinableConstants, propsObjectName);
|
|
1762
|
+
const visit = (n) => {
|
|
1763
|
+
switch (n.type) {
|
|
1764
|
+
case "component": {
|
|
1765
|
+
if (n.name === "Portal") {
|
|
1766
|
+
n.children.forEach(visit);
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
if (n.slotId) {
|
|
1770
|
+
const dropped = n.props.some((p) => {
|
|
1771
|
+
if (p.name === "..." || p.name.startsWith("...") || p.name === "key")
|
|
1772
|
+
return false;
|
|
1773
|
+
if (p.name.startsWith("on") && p.name.length > 2 && p.name[2] === p.name[2].toUpperCase())
|
|
1774
|
+
return false;
|
|
1775
|
+
if (p.clientOnly)
|
|
1776
|
+
return false;
|
|
1777
|
+
return propResolvesUnsafe(p, env, unsafeLocalNames);
|
|
1778
|
+
});
|
|
1779
|
+
if (dropped)
|
|
1780
|
+
deferred.add(n.slotId);
|
|
1781
|
+
}
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
case "element":
|
|
1785
|
+
n.children.forEach(visit);
|
|
1786
|
+
return;
|
|
1787
|
+
case "fragment":
|
|
1788
|
+
n.children.forEach(visit);
|
|
1789
|
+
return;
|
|
1790
|
+
case "conditional":
|
|
1791
|
+
return;
|
|
1792
|
+
case "loop":
|
|
1793
|
+
return;
|
|
1794
|
+
default:
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
visit(node);
|
|
1799
|
+
return deferred;
|
|
1691
1800
|
}
|
|
1692
1801
|
function generateCsrTemplateWithOpts(node, opts) {
|
|
1693
1802
|
const { restSpreadNames, propsObjectName, csrEnv, insideLoop, unsafeLocalNames, loopDepth = 0 } = opts;
|
|
@@ -1755,7 +1864,7 @@ function generateCsrTemplateWithOpts(node, opts) {
|
|
|
1755
1864
|
attrParts.push(`bf="${node.slotId}"`);
|
|
1756
1865
|
}
|
|
1757
1866
|
const attrs = attrParts.join(" ");
|
|
1758
|
-
const children = node.children.map(childrenRecurse).join("");
|
|
1867
|
+
const children = dangerouslyHtmlChildren(node.attrs, (v) => transformExpr(v.expr, v.templateExpr)) ?? node.children.map(childrenRecurse).join("");
|
|
1759
1868
|
if (children || !VOID_ELEMENTS.has(node.tag)) {
|
|
1760
1869
|
return `<${node.tag}${attrs ? " " + attrs : ""}>${children}</${node.tag}>`;
|
|
1761
1870
|
}
|
|
@@ -1773,7 +1882,7 @@ function generateCsrTemplateWithOpts(node, opts) {
|
|
|
1773
1882
|
const transformed = transformExpr(node.expr, node.templateExpr);
|
|
1774
1883
|
const expr = transformed === UNSAFE_TEMPLATE_EXPR ? "''" : transformed;
|
|
1775
1884
|
if (node.slotId) {
|
|
1776
|
-
return `<!--bf:${node.slotId}-->\${${expr}}<!--/-->`;
|
|
1885
|
+
return `<!--bf:${node.slotId}-->\${${escapeTextSlotExpr(expr)}}<!--/-->`;
|
|
1777
1886
|
}
|
|
1778
1887
|
return `\${${expr}}`;
|
|
1779
1888
|
}
|
|
@@ -1793,6 +1902,9 @@ function generateCsrTemplateWithOpts(node, opts) {
|
|
|
1793
1902
|
if (node.name === "Portal") {
|
|
1794
1903
|
return node.children.map(recurse).join("");
|
|
1795
1904
|
}
|
|
1905
|
+
if (node.slotId && opts.deferredChildSlots?.has(node.slotId)) {
|
|
1906
|
+
return `<div ${DATA_BF_PH}="${node.slotId}"></div>`;
|
|
1907
|
+
}
|
|
1796
1908
|
const propsEntries = node.props.filter((p) => p.name !== "..." && !p.name.startsWith("...") && p.name !== "key").filter((p) => !(p.name.startsWith("on") && p.name.length > 2 && p.name[2] === p.name[2].toUpperCase())).map((p) => {
|
|
1797
1909
|
if (p.clientOnly)
|
|
1798
1910
|
return null;
|
|
@@ -5228,14 +5340,7 @@ var UNSUPPORTED_METHODS = new Set([
|
|
|
5228
5340
|
"forEach",
|
|
5229
5341
|
"flatMap",
|
|
5230
5342
|
"flat",
|
|
5231
|
-
"split",
|
|
5232
|
-
"startsWith",
|
|
5233
|
-
"endsWith",
|
|
5234
|
-
"replace",
|
|
5235
5343
|
"replaceAll",
|
|
5236
|
-
"repeat",
|
|
5237
|
-
"padStart",
|
|
5238
|
-
"padEnd",
|
|
5239
5344
|
"charAt",
|
|
5240
5345
|
"charCodeAt",
|
|
5241
5346
|
"codePointAt",
|
|
@@ -5246,6 +5351,12 @@ var UNSUPPORTED_METHODS = new Set([
|
|
|
5246
5351
|
"matchAll",
|
|
5247
5352
|
"search"
|
|
5248
5353
|
]);
|
|
5354
|
+
var LOWERED_ARRAY_METHODS = new Set([
|
|
5355
|
+
"includes",
|
|
5356
|
+
"indexOf",
|
|
5357
|
+
"lastIndexOf",
|
|
5358
|
+
"concat"
|
|
5359
|
+
]);
|
|
5249
5360
|
function parseExpression(expr) {
|
|
5250
5361
|
const trimmed = expr.trim();
|
|
5251
5362
|
if (!trimmed) {
|
|
@@ -5306,7 +5417,7 @@ function convertNode(node, raw) {
|
|
|
5306
5417
|
}
|
|
5307
5418
|
}
|
|
5308
5419
|
if (callee.kind === "member" && !callee.computed) {
|
|
5309
|
-
if (callee.property === "join"
|
|
5420
|
+
if (callee.property === "join") {
|
|
5310
5421
|
return { kind: "array-method", method: "join", object: callee.object, args };
|
|
5311
5422
|
}
|
|
5312
5423
|
if (callee.property === "includes" && args.length === 1) {
|
|
@@ -5315,27 +5426,77 @@ function convertNode(node, raw) {
|
|
|
5315
5426
|
if ((callee.property === "indexOf" || callee.property === "lastIndexOf") && args.length === 1) {
|
|
5316
5427
|
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
5317
5428
|
}
|
|
5318
|
-
if (callee.property === "at"
|
|
5429
|
+
if (callee.property === "at") {
|
|
5319
5430
|
return { kind: "array-method", method: "at", object: callee.object, args };
|
|
5320
5431
|
}
|
|
5321
|
-
if (callee.property === "concat" && args.length
|
|
5432
|
+
if (callee.property === "concat" && args.length <= 1) {
|
|
5322
5433
|
return { kind: "array-method", method: "concat", object: callee.object, args };
|
|
5323
5434
|
}
|
|
5324
|
-
if (callee.property === "slice"
|
|
5435
|
+
if (callee.property === "slice") {
|
|
5325
5436
|
return { kind: "array-method", method: "slice", object: callee.object, args };
|
|
5326
5437
|
}
|
|
5327
|
-
if (
|
|
5438
|
+
if (callee.property === "reverse" || callee.property === "toReversed") {
|
|
5328
5439
|
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
5329
5440
|
}
|
|
5330
|
-
if (callee.property === "toLowerCase"
|
|
5441
|
+
if (callee.property === "toLowerCase") {
|
|
5331
5442
|
return { kind: "array-method", method: "toLowerCase", object: callee.object, args };
|
|
5332
5443
|
}
|
|
5333
|
-
if (callee.property === "toUpperCase"
|
|
5444
|
+
if (callee.property === "toUpperCase") {
|
|
5334
5445
|
return { kind: "array-method", method: "toUpperCase", object: callee.object, args };
|
|
5335
5446
|
}
|
|
5336
|
-
if (callee.property === "trim"
|
|
5447
|
+
if (callee.property === "trim") {
|
|
5337
5448
|
return { kind: "array-method", method: "trim", object: callee.object, args };
|
|
5338
5449
|
}
|
|
5450
|
+
if (callee.property === "split") {
|
|
5451
|
+
return { kind: "array-method", method: "split", object: callee.object, args };
|
|
5452
|
+
}
|
|
5453
|
+
if (LOWERED_ARRAY_METHODS.has(callee.property)) {
|
|
5454
|
+
const argName = callee.property === "concat" ? "other" : "x";
|
|
5455
|
+
const detail = callee.property === "concat" ? "the variadic `.concat(a, b, …)` form" : `\`.${callee.property}(…)\` with ${args.length} argument(s)`;
|
|
5456
|
+
return {
|
|
5457
|
+
kind: "unsupported",
|
|
5458
|
+
raw,
|
|
5459
|
+
reason: `${detail} is not yet lowered to the Go/Mojo template adapters. Use the single-argument \`.${callee.property}(${argName})\` form, or pre-compute the value before the template.`
|
|
5460
|
+
};
|
|
5461
|
+
}
|
|
5462
|
+
if (callee.property === "startsWith" || callee.property === "endsWith") {
|
|
5463
|
+
if (args.length === 0) {
|
|
5464
|
+
return {
|
|
5465
|
+
kind: "unsupported",
|
|
5466
|
+
raw,
|
|
5467
|
+
reason: `\`.${callee.property}()\` with no search string is not lowered — JS coerces the missing argument to the string "undefined", a degenerate result. Pass an explicit search string, or pre-compute the value before the template.`
|
|
5468
|
+
};
|
|
5469
|
+
}
|
|
5470
|
+
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
5471
|
+
}
|
|
5472
|
+
if (callee.property === "replace") {
|
|
5473
|
+
if (args.length < 2) {
|
|
5474
|
+
return {
|
|
5475
|
+
kind: "unsupported",
|
|
5476
|
+
raw,
|
|
5477
|
+
reason: `\`.replace(${args.length === 0 ? "" : "pattern"})\` needs both a pattern and a replacement — JS coerces the missing argument to the string "undefined", a degenerate result. Pass both arguments, or pre-compute the value before the template.`
|
|
5478
|
+
};
|
|
5479
|
+
}
|
|
5480
|
+
const patternNode = node.arguments[0];
|
|
5481
|
+
if (patternNode && ts8.isRegularExpressionLiteral(patternNode)) {
|
|
5482
|
+
return {
|
|
5483
|
+
kind: "unsupported",
|
|
5484
|
+
raw,
|
|
5485
|
+
reason: "String.prototype.replace supports only a string pattern + string replacement (the regex form is deferred); use a string pattern or wrap the expression in /* @client */"
|
|
5486
|
+
};
|
|
5487
|
+
}
|
|
5488
|
+
const badArg = args[0].kind === "unsupported" ? args[0] : args[1].kind === "unsupported" ? args[1] : undefined;
|
|
5489
|
+
if (badArg && badArg.kind === "unsupported") {
|
|
5490
|
+
return { kind: "unsupported", raw, reason: badArg.reason };
|
|
5491
|
+
}
|
|
5492
|
+
return { kind: "array-method", method: "replace", object: callee.object, args };
|
|
5493
|
+
}
|
|
5494
|
+
if (callee.property === "repeat") {
|
|
5495
|
+
return { kind: "array-method", method: "repeat", object: callee.object, args };
|
|
5496
|
+
}
|
|
5497
|
+
if (callee.property === "padStart" || callee.property === "padEnd") {
|
|
5498
|
+
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
5499
|
+
}
|
|
5339
5500
|
if ((callee.property === "sort" || callee.property === "toSorted") && node.arguments.length === 1) {
|
|
5340
5501
|
const comparator = extractSortComparatorFromTS(node.arguments[0], callee.property);
|
|
5341
5502
|
if (comparator) {
|
|
@@ -9710,24 +9871,80 @@ function collectLoopChildReactiveAttrs(node, ctx, loopParam, loopParamBindings)
|
|
|
9710
9871
|
}
|
|
9711
9872
|
|
|
9712
9873
|
// src/ir-to-client-js/collect-elements.ts
|
|
9713
|
-
|
|
9714
|
-
|
|
9874
|
+
var EMPTY_RENDER_EXPRS = new Set(["null", "undefined", "false", "''", '""', "``"]);
|
|
9875
|
+
function domElementCount(node) {
|
|
9876
|
+
switch (node.type) {
|
|
9877
|
+
case "element":
|
|
9878
|
+
case "component":
|
|
9879
|
+
case "provider":
|
|
9880
|
+
case "async":
|
|
9881
|
+
return 1;
|
|
9882
|
+
case "text":
|
|
9883
|
+
return 0;
|
|
9884
|
+
case "expression":
|
|
9885
|
+
return EMPTY_RENDER_EXPRS.has(node.expr.trim()) ? 0 : null;
|
|
9886
|
+
case "loop":
|
|
9887
|
+
if (node.bodyIsItemConditional || node.method === "flatMap")
|
|
9888
|
+
return null;
|
|
9889
|
+
return `(${buildLoopChainExpr({
|
|
9890
|
+
base: node.array,
|
|
9891
|
+
sortComparator: node.sortComparator,
|
|
9892
|
+
filterPredicate: node.filterPredicate,
|
|
9893
|
+
chainOrder: node.chainOrder
|
|
9894
|
+
})}).length`;
|
|
9895
|
+
case "conditional": {
|
|
9896
|
+
const t = domElementCount(node.whenTrue);
|
|
9897
|
+
const f = domElementCount(node.whenFalse);
|
|
9898
|
+
if (t === null || f === null)
|
|
9899
|
+
return null;
|
|
9900
|
+
if (typeof t === "number" && typeof f === "number" && t === f)
|
|
9901
|
+
return t;
|
|
9902
|
+
return `(${node.condition} ? ${t} : ${f})`;
|
|
9903
|
+
}
|
|
9904
|
+
case "fragment":
|
|
9905
|
+
return sumElementCounts(node.children);
|
|
9906
|
+
default:
|
|
9907
|
+
return null;
|
|
9908
|
+
}
|
|
9909
|
+
}
|
|
9910
|
+
function sumElementCounts(nodes) {
|
|
9911
|
+
let staticCount = 0;
|
|
9912
|
+
const dynamic = [];
|
|
9913
|
+
for (const n of nodes) {
|
|
9914
|
+
const c = domElementCount(n);
|
|
9915
|
+
if (c === null)
|
|
9916
|
+
return null;
|
|
9917
|
+
if (typeof c === "number")
|
|
9918
|
+
staticCount += c;
|
|
9919
|
+
else
|
|
9920
|
+
dynamic.push(c);
|
|
9921
|
+
}
|
|
9922
|
+
if (dynamic.length === 0)
|
|
9923
|
+
return staticCount;
|
|
9924
|
+
const parts = staticCount > 0 ? [String(staticCount), ...dynamic] : dynamic;
|
|
9925
|
+
return parts.length === 1 ? parts[0] : `(${parts.join(" + ")})`;
|
|
9926
|
+
}
|
|
9927
|
+
function legacyElementCount(node) {
|
|
9928
|
+
return node.type === "element" || node.type === "component" || node.type === "provider" || node.type === "async" || node.type === "text" || node.type === "expression" && !node.reactive || node.type === "conditional" ? 1 : 0;
|
|
9715
9929
|
}
|
|
9716
9930
|
function computeLoopSiblingOffsets(root) {
|
|
9717
9931
|
const offsets = new Map;
|
|
9718
|
-
const
|
|
9719
|
-
let nonLoopCount = 0;
|
|
9932
|
+
const recordRun = (children, preceding) => {
|
|
9720
9933
|
for (const child of children) {
|
|
9721
9934
|
if (child.type === "loop") {
|
|
9722
|
-
if (
|
|
9723
|
-
offsets.set(child,
|
|
9724
|
-
|
|
9725
|
-
|
|
9935
|
+
if (preceding.length > 0 && !offsets.has(child)) {
|
|
9936
|
+
offsets.set(child, [...preceding]);
|
|
9937
|
+
}
|
|
9938
|
+
preceding.push(child);
|
|
9939
|
+
} else if (child.type === "fragment" || child.type === "provider" || child.type === "async") {
|
|
9940
|
+
recordRun(child.children, preceding);
|
|
9941
|
+
} else {
|
|
9942
|
+
preceding.push(child);
|
|
9726
9943
|
}
|
|
9727
9944
|
}
|
|
9728
9945
|
};
|
|
9729
9946
|
const containerVisit = ({ node, descend }) => {
|
|
9730
|
-
|
|
9947
|
+
recordRun(node.children, []);
|
|
9731
9948
|
descend();
|
|
9732
9949
|
};
|
|
9733
9950
|
walkIR(root, null, {
|
|
@@ -9739,6 +9956,24 @@ function computeLoopSiblingOffsets(root) {
|
|
|
9739
9956
|
});
|
|
9740
9957
|
return offsets;
|
|
9741
9958
|
}
|
|
9959
|
+
function resolveLoopOffset(preceding) {
|
|
9960
|
+
if (!preceding || preceding.length === 0)
|
|
9961
|
+
return;
|
|
9962
|
+
let staticCount = 0;
|
|
9963
|
+
const dynamicTerms = [];
|
|
9964
|
+
for (const node of preceding) {
|
|
9965
|
+
const c = domElementCount(node);
|
|
9966
|
+
if (c === null)
|
|
9967
|
+
staticCount += legacyElementCount(node);
|
|
9968
|
+
else if (typeof c === "number")
|
|
9969
|
+
staticCount += c;
|
|
9970
|
+
else
|
|
9971
|
+
dynamicTerms.push(c);
|
|
9972
|
+
}
|
|
9973
|
+
if (staticCount === 0 && dynamicTerms.length === 0)
|
|
9974
|
+
return;
|
|
9975
|
+
return { staticCount, dynamicTerms };
|
|
9976
|
+
}
|
|
9742
9977
|
var branchInnerLoopOptions = {
|
|
9743
9978
|
collectItemBindings: true,
|
|
9744
9979
|
templateDepth: 1,
|
|
@@ -9824,7 +10059,7 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
|
|
|
9824
10059
|
refsOuterParam: refsOuter,
|
|
9825
10060
|
childComponents,
|
|
9826
10061
|
insideConditional: !flat && scope.insideCond ? true : undefined,
|
|
9827
|
-
|
|
10062
|
+
offset: flat ? undefined : resolveLoopOffset(siblingOffsets.get(n)),
|
|
9828
10063
|
bindings
|
|
9829
10064
|
});
|
|
9830
10065
|
if (!flat) {
|
|
@@ -10042,7 +10277,7 @@ function collectElements(node, ctx, siblingOffsets, insideConditional = false) {
|
|
|
10042
10277
|
isStaticArray: l.isStaticArray,
|
|
10043
10278
|
useElementReconciliation,
|
|
10044
10279
|
innerLoops: useElementReconciliation || l.isStaticArray && innerLoops?.length ? innerLoops : undefined,
|
|
10045
|
-
|
|
10280
|
+
offset: resolveLoopOffset(siblingOffsets.get(l)),
|
|
10046
10281
|
filterPredicate: l.filterPredicate ? {
|
|
10047
10282
|
param: l.filterPredicate.param,
|
|
10048
10283
|
raw: l.filterPredicate.raw
|
|
@@ -10812,6 +11047,8 @@ var RUNTIME_IMPORT_CANDIDATES = [
|
|
|
10812
11047
|
"splitProps",
|
|
10813
11048
|
"spreadAttrs",
|
|
10814
11049
|
"styleToCss",
|
|
11050
|
+
"escapeAttr",
|
|
11051
|
+
"escapeText",
|
|
10815
11052
|
"qsa",
|
|
10816
11053
|
"qsaItem",
|
|
10817
11054
|
"qsaChildScope",
|
|
@@ -11705,7 +11942,7 @@ function emitRegistrationAndHydration(lines, ctx, _ir, graph, inlinability) {
|
|
|
11705
11942
|
}
|
|
11706
11943
|
} else {
|
|
11707
11944
|
const csrInlinableConstants = csrInlinableConstantsFromCtx(ctx);
|
|
11708
|
-
const templateHtml = generateCsrTemplate(_ir.root, csrInlinableConstants, ctx, undefined, restSpreadNames, ctx.propsObjectName, unsafeLocalNames);
|
|
11945
|
+
const templateHtml = generateCsrTemplate(_ir.root, csrInlinableConstants, ctx, undefined, restSpreadNames, ctx.propsObjectName, unsafeLocalNames, ctx.deferredChildSlots);
|
|
11709
11946
|
if (templateHtml) {
|
|
11710
11947
|
defParts.push(`template: (${PROPS_PARAM}) => \`${templateHtml}\``);
|
|
11711
11948
|
}
|
|
@@ -12396,8 +12633,13 @@ function emitProviderAndChildInits(lines, ctx) {
|
|
|
12396
12633
|
lines.push("");
|
|
12397
12634
|
lines.push(` // Initialize child components with props`);
|
|
12398
12635
|
for (const child of ctx.childInits) {
|
|
12636
|
+
const registryName = nameForRegistryRef(child.name);
|
|
12637
|
+
if (child.slotId && ctx.deferredChildSlots.has(child.slotId)) {
|
|
12638
|
+
lines.push(` upsertChild(__scope, '${registryName}', '${child.slotId}', ${child.propsExpr})`);
|
|
12639
|
+
continue;
|
|
12640
|
+
}
|
|
12399
12641
|
const scopeRef = child.slotId ? `_${varSlotId(child.slotId)}` : "__scope";
|
|
12400
|
-
lines.push(` initChild('${
|
|
12642
|
+
lines.push(` initChild('${registryName}', ${scopeRef}, ${child.propsExpr})`);
|
|
12401
12643
|
}
|
|
12402
12644
|
}
|
|
12403
12645
|
}
|
|
@@ -12678,7 +12920,7 @@ function buildOuterNestedPlan(elem, comp) {
|
|
|
12678
12920
|
arrayExpr: elem.array,
|
|
12679
12921
|
param: elem.param,
|
|
12680
12922
|
indexParam,
|
|
12681
|
-
offsetExpr:
|
|
12923
|
+
offsetExpr: buildLoopChildIndexExpr(indexParam, elem.offset),
|
|
12682
12924
|
outerPreludeStatements: elem.mapPreamble ? [elem.mapPreamble] : [],
|
|
12683
12925
|
propsExpr: buildStaticPropsExpr(comp.props)
|
|
12684
12926
|
};
|
|
@@ -12696,12 +12938,12 @@ function buildInnerLoopNestedPlan(elem, innerLoop, innerComps) {
|
|
|
12696
12938
|
outerArrayExpr: elem.array,
|
|
12697
12939
|
outerParam: elem.param,
|
|
12698
12940
|
outerIndexParam,
|
|
12699
|
-
outerOffsetExpr:
|
|
12941
|
+
outerOffsetExpr: buildLoopChildIndexExpr(outerIndexParam, elem.offset),
|
|
12700
12942
|
outerPreludeStatements: elem.mapPreamble ? [elem.mapPreamble] : [],
|
|
12701
12943
|
innerContainerSlotId: innerLoop.containerSlotId ?? null,
|
|
12702
12944
|
innerArrayExpr: innerLoop.array,
|
|
12703
12945
|
innerParam: innerLoop.param,
|
|
12704
|
-
innerOffsetExpr:
|
|
12946
|
+
innerOffsetExpr: buildLoopChildIndexExpr("__innerIdx", innerLoop.offset),
|
|
12705
12947
|
innerPreludeStatements: innerLoop.mapPreamble ? [innerLoop.mapPreamble] : [],
|
|
12706
12948
|
depth: innerLoop.depth,
|
|
12707
12949
|
comps
|
|
@@ -13463,7 +13705,7 @@ function buildStaticArrayDelegationPlan(elem) {
|
|
|
13463
13705
|
arrayExpr: buildChainedArrayExpr(elem),
|
|
13464
13706
|
param: elem.param,
|
|
13465
13707
|
mapPreamble: elem.mapPreamble ?? null,
|
|
13466
|
-
|
|
13708
|
+
offset: elem.offset ?? null
|
|
13467
13709
|
}
|
|
13468
13710
|
};
|
|
13469
13711
|
}
|
|
@@ -13581,6 +13823,11 @@ function buildArmBody(branch, options) {
|
|
|
13581
13823
|
// src/ir-to-client-js/emit-reactive.ts
|
|
13582
13824
|
function emitAttrUpdate(target, attrName, expression, meta) {
|
|
13583
13825
|
const htmlName = toHtmlAttrName(attrName);
|
|
13826
|
+
if (attrName === "dangerouslySetInnerHTML" || htmlName === "dangerouslySetInnerHTML") {
|
|
13827
|
+
return [
|
|
13828
|
+
`{ const __v = ${expression}; ${target}.innerHTML = __v != null && __v.__html != null ? String(__v.__html) : '' }`
|
|
13829
|
+
];
|
|
13830
|
+
}
|
|
13584
13831
|
if (htmlName === "style") {
|
|
13585
13832
|
return [
|
|
13586
13833
|
`{ const __v = styleToCss(${expression}); if (__v != null) ${target}.setAttribute('style', __v); else ${target}.removeAttribute('style') }`
|
|
@@ -14592,11 +14839,11 @@ function emitDynamicIndexLookup(ls, ev, handlerCall, lookup) {
|
|
|
14592
14839
|
ls.push(` }`);
|
|
14593
14840
|
}
|
|
14594
14841
|
function emitStaticIndexLookup(ls, ev, handlerCall, lookup, containerVar) {
|
|
14595
|
-
const { arrayExpr, param, mapPreamble,
|
|
14842
|
+
const { arrayExpr, param, mapPreamble, offset } = lookup;
|
|
14596
14843
|
ls.push(` let __el = ${varSlotId(ev.childSlotId)}El`);
|
|
14597
14844
|
ls.push(` while (__el.parentElement && __el.parentElement !== ${containerVar}) __el = __el.parentElement`);
|
|
14598
14845
|
ls.push(` if (__el.parentElement === ${containerVar}) {`);
|
|
14599
|
-
const idxOffset =
|
|
14846
|
+
const idxOffset = buildLoopChildIndexSubtraction(offset ?? undefined);
|
|
14600
14847
|
ls.push(` const __idx = Array.from(${containerVar}.children).indexOf(__el)${idxOffset}`);
|
|
14601
14848
|
ls.push(` const ${param} = ${arrayExpr}[__idx]`);
|
|
14602
14849
|
if (mapPreamble)
|
|
@@ -14873,7 +15120,7 @@ function buildStaticLoopPlan(elem, unsafeLocalNames) {
|
|
|
14873
15120
|
}
|
|
14874
15121
|
}
|
|
14875
15122
|
const indexParam = elem.index || "__idx";
|
|
14876
|
-
const childIndexExpr =
|
|
15123
|
+
const childIndexExpr = buildLoopChildIndexExpr(indexParam, elem.offset);
|
|
14877
15124
|
return {
|
|
14878
15125
|
kind: "static",
|
|
14879
15126
|
containerVar: `_${varSlotId(elem.slotId)}`,
|
|
@@ -15192,6 +15439,7 @@ function generateInitFunction(ir, ctx, siblingComponents, localImportPrefixes) {
|
|
|
15192
15439
|
const classification = classifyLocalDeclarations(ctx, graph);
|
|
15193
15440
|
const propUsage = computePropUsage(ctx, classification.neededConstants);
|
|
15194
15441
|
const inlinability = buildInlinableConstants(ctx, graph, ir.root);
|
|
15442
|
+
ctx.deferredChildSlots = computeDeferredChildSlots(ir.root, ctx, csrInlinableConstantsFromCtx(ctx), inlinability.unsafeLocalNames, ctx.propsObjectName);
|
|
15195
15443
|
const phaseCtx = buildPhaseCtx({
|
|
15196
15444
|
ctx,
|
|
15197
15445
|
ir,
|
|
@@ -15460,6 +15708,7 @@ function createContext(ir, scope, adapterCapabilities) {
|
|
|
15460
15708
|
loopElements: [],
|
|
15461
15709
|
refElements: [],
|
|
15462
15710
|
childInits: [],
|
|
15711
|
+
deferredChildSlots: new Set,
|
|
15463
15712
|
reactiveProps: [],
|
|
15464
15713
|
reactiveChildProps: [],
|
|
15465
15714
|
reactiveAttrs: [],
|
|
@@ -17161,6 +17410,7 @@ function emitAttrValue(value, emitter, name) {
|
|
|
17161
17410
|
}
|
|
17162
17411
|
}
|
|
17163
17412
|
// src/combine-client-js.ts
|
|
17413
|
+
import ts18 from "typescript";
|
|
17164
17414
|
var CHILD_PLACEHOLDER_RE = /import '\/\* @bf-child:(\w+) \*\/'/g;
|
|
17165
17415
|
function combineParentChildClientJs(files) {
|
|
17166
17416
|
const result = new Map;
|
|
@@ -17217,33 +17467,43 @@ function combineParentChildClientJs(files) {
|
|
|
17217
17467
|
return result;
|
|
17218
17468
|
}
|
|
17219
17469
|
function parseAndMerge(content, importsBySource, otherImports, codeSections) {
|
|
17220
|
-
const
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
if (
|
|
17224
|
-
|
|
17225
|
-
|
|
17226
|
-
|
|
17227
|
-
|
|
17228
|
-
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
|
|
17234
|
-
|
|
17235
|
-
|
|
17236
|
-
|
|
17237
|
-
|
|
17238
|
-
|
|
17239
|
-
|
|
17470
|
+
const sourceFile = ts18.createSourceFile("combine.js", content, ts18.ScriptTarget.Latest, false, ts18.ScriptKind.JS);
|
|
17471
|
+
const importSpans = [];
|
|
17472
|
+
for (const stmt of sourceFile.statements) {
|
|
17473
|
+
if (!ts18.isImportDeclaration(stmt))
|
|
17474
|
+
continue;
|
|
17475
|
+
const start = stmt.getStart(sourceFile);
|
|
17476
|
+
const end = stmt.getEnd();
|
|
17477
|
+
importSpans.push([start, end]);
|
|
17478
|
+
const stmtText = content.slice(start, end);
|
|
17479
|
+
if (stmtText.includes("@bf-child:"))
|
|
17480
|
+
continue;
|
|
17481
|
+
const clause = stmt.importClause;
|
|
17482
|
+
const bindings = clause?.namedBindings;
|
|
17483
|
+
const specifier = ts18.isStringLiteral(stmt.moduleSpecifier) ? stmt.moduleSpecifier.text : "";
|
|
17484
|
+
if (clause && !clause.name && bindings && ts18.isNamedImports(bindings)) {
|
|
17485
|
+
if (!importsBySource.has(specifier)) {
|
|
17486
|
+
importsBySource.set(specifier, new Set);
|
|
17487
|
+
}
|
|
17488
|
+
const set = importsBySource.get(specifier);
|
|
17489
|
+
for (const el of bindings.elements) {
|
|
17490
|
+
const name = el.propertyName ? `${el.propertyName.text} as ${el.name.text}` : el.name.text;
|
|
17491
|
+
set.add(name);
|
|
17240
17492
|
}
|
|
17241
17493
|
} else {
|
|
17242
|
-
|
|
17494
|
+
if (!otherImports.includes(stmtText)) {
|
|
17495
|
+
otherImports.push(stmtText);
|
|
17496
|
+
}
|
|
17243
17497
|
}
|
|
17244
17498
|
}
|
|
17245
|
-
|
|
17246
|
-
|
|
17499
|
+
let code = "";
|
|
17500
|
+
let cursor = 0;
|
|
17501
|
+
for (const [start, end] of importSpans) {
|
|
17502
|
+
code += content.slice(cursor, start);
|
|
17503
|
+
cursor = end;
|
|
17504
|
+
}
|
|
17505
|
+
code += content.slice(cursor);
|
|
17506
|
+
code = code.trim();
|
|
17247
17507
|
if (code) {
|
|
17248
17508
|
codeSections.push(code);
|
|
17249
17509
|
}
|