@barefootjs/jsx 0.18.5 → 0.18.7
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/dangerous-inner-html.d.ts +77 -0
- package/dist/adapters/dangerous-inner-html.d.ts.map +1 -0
- package/dist/adapters/loop-bound-names.d.ts +22 -0
- package/dist/adapters/loop-bound-names.d.ts.map +1 -0
- package/dist/adapters/parsed-expr-emitter.d.ts.map +1 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +977 -273
- package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-inner-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-loop-child-arm.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/loop-child-arm.d.ts +9 -0
- package/dist/ir-to-client-js/control-flow/plan/loop-child-arm.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/loop.d.ts +9 -0
- package/dist/ir-to-client-js/control-flow/plan/loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/shared.d.ts +45 -3
- package/dist/ir-to-client-js/control-flow/shared.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/loop.d.ts +1 -0
- package/dist/ir-to-client-js/control-flow/stringify/loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/reactive-effects.d.ts +10 -0
- package/dist/ir-to-client-js/control-flow/stringify/reactive-effects.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/skeleton-paths.d.ts +38 -0
- package/dist/ir-to-client-js/control-flow/stringify/skeleton-paths.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/stringify/template-parse.d.ts +19 -0
- package/dist/ir-to-client-js/control-flow/stringify/template-parse.d.ts.map +1 -1
- package/dist/ir-to-client-js/csr-substitute.d.ts +23 -0
- package/dist/ir-to-client-js/csr-substitute.d.ts.map +1 -1
- package/dist/ir-to-client-js/html-template.d.ts +42 -0
- 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/plan/static-array-child-init.d.ts +20 -1
- package/dist/ir-to-client-js/plan/static-array-child-init.d.ts.map +1 -1
- package/dist/ir-to-client-js/reactivity.d.ts.map +1 -1
- package/dist/ir-to-client-js/stringify/static-array-child-init.d.ts +1 -1
- package/dist/ir-to-client-js/types.d.ts +21 -0
- package/dist/ir-to-client-js/types.d.ts.map +1 -1
- package/dist/jsx-to-ir.d.ts.map +1 -1
- package/dist/signal-init-eval.d.ts +82 -0
- package/dist/signal-init-eval.d.ts.map +1 -0
- package/dist/static-literal.d.ts +45 -0
- package/dist/static-literal.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +19 -13
- package/src/__tests__/create-selector.test.ts +110 -0
- package/src/__tests__/csr-template-loop-shadowing.test.ts +214 -0
- package/src/__tests__/dangerous-inner-html-resolver.test.ts +197 -0
- package/src/__tests__/inner-loop-svg-namespace.test.ts +245 -0
- package/src/__tests__/loop-bound-names.test.ts +102 -0
- package/src/__tests__/loop-plan-classification.test.ts +2 -0
- package/src/__tests__/map-function-reference.test.ts +303 -0
- package/src/__tests__/nested-loop-index-param.test.ts +285 -0
- package/src/__tests__/signal-init-eval.test.ts +138 -0
- package/src/__tests__/static-array-inner-loop-index-param.test.ts +180 -0
- package/src/__tests__/static-literal.test.ts +126 -0
- package/src/__tests__/string-concat-identifier.test.ts +55 -0
- package/src/adapters/dangerous-inner-html.ts +186 -0
- package/src/adapters/loop-bound-names.ts +80 -0
- package/src/adapters/parsed-expr-emitter.ts +9 -0
- package/src/analyzer.ts +6 -0
- package/src/index.ts +19 -3
- package/src/ir-to-client-js/collect-elements.ts +15 -3
- package/src/ir-to-client-js/control-flow/plan/build-inner-loop.ts +21 -4
- package/src/ir-to-client-js/control-flow/plan/build-loop-child-arm.ts +13 -1
- package/src/ir-to-client-js/control-flow/plan/build-loop.ts +1 -0
- package/src/ir-to-client-js/control-flow/plan/loop-child-arm.ts +9 -0
- package/src/ir-to-client-js/control-flow/plan/loop.ts +9 -0
- package/src/ir-to-client-js/control-flow/shared.ts +103 -6
- package/src/ir-to-client-js/control-flow/stringify/inner-loop.ts +11 -2
- package/src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts +5 -0
- package/src/ir-to-client-js/control-flow/stringify/loop.ts +53 -10
- package/src/ir-to-client-js/control-flow/stringify/reactive-effects.ts +25 -4
- package/src/ir-to-client-js/control-flow/stringify/skeleton-paths.ts +70 -0
- package/src/ir-to-client-js/control-flow/stringify/template-parse.ts +25 -1
- package/src/ir-to-client-js/csr-substitute.ts +53 -0
- package/src/ir-to-client-js/html-template.ts +235 -2
- package/src/ir-to-client-js/imports.ts +1 -0
- package/src/ir-to-client-js/plan/build-static-array-child-init.ts +12 -1
- package/src/ir-to-client-js/plan/static-array-child-init.ts +20 -1
- package/src/ir-to-client-js/reactivity.ts +6 -0
- package/src/ir-to-client-js/stringify/static-array-child-init.ts +11 -6
- package/src/ir-to-client-js/types.ts +21 -0
- package/src/jsx-to-ir.ts +230 -39
- package/src/signal-init-eval.ts +165 -0
- package/src/static-literal.ts +128 -0
package/dist/index.js
CHANGED
|
@@ -2942,6 +2942,29 @@ function extractFreeIdentifiersFromText(text) {
|
|
|
2942
2942
|
const expr = ts4.isParenthesizedExpression(stmt.expression) ? stmt.expression.expression : stmt.expression;
|
|
2943
2943
|
return extractFreeIdentifiersFromNode(expr);
|
|
2944
2944
|
}
|
|
2945
|
+
function extractFreeIdentifiersFromStatementText(text) {
|
|
2946
|
+
if (!text || text.trim().length === 0)
|
|
2947
|
+
return new Set;
|
|
2948
|
+
const sf = ts4.createSourceFile("__free_ids_stmt__.ts", text, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TS);
|
|
2949
|
+
return extractFreeIdentifiersFromNode(sf);
|
|
2950
|
+
}
|
|
2951
|
+
function extractFreeIdentifiersFromTemplateText(template) {
|
|
2952
|
+
if (!template || template.length === 0)
|
|
2953
|
+
return new Set;
|
|
2954
|
+
const sf = ts4.createSourceFile("__free_ids_template__.ts", `(\`${template}\`);`, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TS);
|
|
2955
|
+
const stmt = sf.statements[0];
|
|
2956
|
+
if (!stmt || !ts4.isExpressionStatement(stmt))
|
|
2957
|
+
return new Set;
|
|
2958
|
+
const expr = ts4.isParenthesizedExpression(stmt.expression) ? stmt.expression.expression : stmt.expression;
|
|
2959
|
+
if (!ts4.isTemplateExpression(expr))
|
|
2960
|
+
return new Set;
|
|
2961
|
+
const ids = new Set;
|
|
2962
|
+
for (const span of expr.templateSpans) {
|
|
2963
|
+
for (const id of extractFreeIdentifiersFromNode(span.expression))
|
|
2964
|
+
ids.add(id);
|
|
2965
|
+
}
|
|
2966
|
+
return ids;
|
|
2967
|
+
}
|
|
2945
2968
|
function extractMemoBodyExpr(computation) {
|
|
2946
2969
|
const arrowMatch = computation.match(/^\(\)\s*=>\s*(.+)$/s);
|
|
2947
2970
|
if (!arrowMatch)
|
|
@@ -3470,6 +3493,133 @@ function buildLoopSkeletonTemplate(node, safe) {
|
|
|
3470
3493
|
return assertNever(node);
|
|
3471
3494
|
}
|
|
3472
3495
|
}
|
|
3496
|
+
var SKELETON_PATH_HAZARD_TAGS = new Set([
|
|
3497
|
+
"table",
|
|
3498
|
+
"thead",
|
|
3499
|
+
"tbody",
|
|
3500
|
+
"tfoot",
|
|
3501
|
+
"caption",
|
|
3502
|
+
"colgroup",
|
|
3503
|
+
"col",
|
|
3504
|
+
"select",
|
|
3505
|
+
"optgroup",
|
|
3506
|
+
"p",
|
|
3507
|
+
"pre",
|
|
3508
|
+
"textarea",
|
|
3509
|
+
"listing",
|
|
3510
|
+
"template",
|
|
3511
|
+
"math"
|
|
3512
|
+
]);
|
|
3513
|
+
var SKELETON_PATH_FORCE_CLOSE_GROUPS = [
|
|
3514
|
+
new Set(["a"]),
|
|
3515
|
+
new Set(["button"]),
|
|
3516
|
+
new Set(["form"]),
|
|
3517
|
+
new Set(["option"]),
|
|
3518
|
+
new Set(["h1", "h2", "h3", "h4", "h5", "h6"]),
|
|
3519
|
+
new Set(["dd", "dt"]),
|
|
3520
|
+
new Set(["li"])
|
|
3521
|
+
];
|
|
3522
|
+
function skeletonForceCloseGroup(tag) {
|
|
3523
|
+
return SKELETON_PATH_FORCE_CLOSE_GROUPS.findIndex((group) => group.has(tag));
|
|
3524
|
+
}
|
|
3525
|
+
function computeSkeletonSlotPaths(node, safe) {
|
|
3526
|
+
const state = { elementPaths: new Map, textMarkerPaths: new Map, bailed: false };
|
|
3527
|
+
walkSkeletonPathNode(node, [], safe, state, new Set);
|
|
3528
|
+
if (state.bailed)
|
|
3529
|
+
return null;
|
|
3530
|
+
return { elementPaths: state.elementPaths, textMarkerPaths: state.textMarkerPaths };
|
|
3531
|
+
}
|
|
3532
|
+
function walkSkeletonPathNode(node, path, safe, state, forceCloseAncestors) {
|
|
3533
|
+
if (state.bailed || node.type !== "element")
|
|
3534
|
+
return;
|
|
3535
|
+
if (SKELETON_PATH_HAZARD_TAGS.has(node.tag)) {
|
|
3536
|
+
state.bailed = true;
|
|
3537
|
+
return;
|
|
3538
|
+
}
|
|
3539
|
+
const groupIdx = skeletonForceCloseGroup(node.tag);
|
|
3540
|
+
if (groupIdx >= 0 && forceCloseAncestors.has(groupIdx)) {
|
|
3541
|
+
state.bailed = true;
|
|
3542
|
+
return;
|
|
3543
|
+
}
|
|
3544
|
+
const flatChildren = flattenSkeletonChildren(node.children);
|
|
3545
|
+
if (VOID_ELEMENTS.has(node.tag) && flatChildren.length > 0) {
|
|
3546
|
+
state.bailed = true;
|
|
3547
|
+
return;
|
|
3548
|
+
}
|
|
3549
|
+
if (node.tag === "tr" && hasForeignTableRowContent(flatChildren)) {
|
|
3550
|
+
state.bailed = true;
|
|
3551
|
+
return;
|
|
3552
|
+
}
|
|
3553
|
+
if (node.slotId)
|
|
3554
|
+
state.elementPaths.set(node.slotId, path);
|
|
3555
|
+
const nextAncestors = groupIdx >= 0 ? new Set([...forceCloseAncestors, groupIdx]) : forceCloseAncestors;
|
|
3556
|
+
walkSkeletonPathChildren(flatChildren, path, safe, state, nextAncestors);
|
|
3557
|
+
}
|
|
3558
|
+
function hasForeignTableRowContent(children) {
|
|
3559
|
+
for (const child of children) {
|
|
3560
|
+
if (child.type === "text") {
|
|
3561
|
+
if (child.value.trim() !== "")
|
|
3562
|
+
return true;
|
|
3563
|
+
continue;
|
|
3564
|
+
}
|
|
3565
|
+
if (child.type === "element" && child.tag !== "td" && child.tag !== "th") {
|
|
3566
|
+
return true;
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
return false;
|
|
3570
|
+
}
|
|
3571
|
+
function flattenSkeletonChildren(children) {
|
|
3572
|
+
const out = [];
|
|
3573
|
+
for (const child of children) {
|
|
3574
|
+
if (child.type === "fragment") {
|
|
3575
|
+
out.push(...flattenSkeletonChildren(child.children));
|
|
3576
|
+
} else {
|
|
3577
|
+
out.push(child);
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
return out;
|
|
3581
|
+
}
|
|
3582
|
+
function walkSkeletonPathChildren(children, parentPath, safe, state, forceCloseAncestors) {
|
|
3583
|
+
let idx = 0;
|
|
3584
|
+
let pendingText = false;
|
|
3585
|
+
for (const child of children) {
|
|
3586
|
+
if (state.bailed)
|
|
3587
|
+
return;
|
|
3588
|
+
switch (child.type) {
|
|
3589
|
+
case "text": {
|
|
3590
|
+
if (child.value === "")
|
|
3591
|
+
continue;
|
|
3592
|
+
if (!pendingText)
|
|
3593
|
+
idx += 1;
|
|
3594
|
+
pendingText = true;
|
|
3595
|
+
continue;
|
|
3596
|
+
}
|
|
3597
|
+
case "expression": {
|
|
3598
|
+
if (child.expr === "null" || child.expr === "undefined")
|
|
3599
|
+
continue;
|
|
3600
|
+
if (!child.slotId || !safe.reactiveTextSlotIds.has(child.slotId)) {
|
|
3601
|
+
state.bailed = true;
|
|
3602
|
+
return;
|
|
3603
|
+
}
|
|
3604
|
+
state.textMarkerPaths.set(child.slotId, [...parentPath, idx]);
|
|
3605
|
+
idx += 2;
|
|
3606
|
+
pendingText = false;
|
|
3607
|
+
continue;
|
|
3608
|
+
}
|
|
3609
|
+
case "element": {
|
|
3610
|
+
walkSkeletonPathNode(child, [...parentPath, idx], safe, state, forceCloseAncestors);
|
|
3611
|
+
idx += 1;
|
|
3612
|
+
pendingText = false;
|
|
3613
|
+
continue;
|
|
3614
|
+
}
|
|
3615
|
+
case "fragment":
|
|
3616
|
+
continue;
|
|
3617
|
+
default:
|
|
3618
|
+
state.bailed = true;
|
|
3619
|
+
return;
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3473
3623
|
function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParams) {
|
|
3474
3624
|
const recurse = (n) => irToPlaceholderTemplate(n, restSpreadNames, loopDepth, loopParams);
|
|
3475
3625
|
const wrapExpr = (expr) => wrapExprWithLoopParams(expr, loopParams);
|
|
@@ -4112,7 +4262,28 @@ function generateCsrTemplateWithOpts(node, opts) {
|
|
|
4112
4262
|
return `\${renderChild('${nameForRegistryRef(node.name)}', ${propsExpr}${keyArg || (slotArg ? ", undefined" : "")}${slotArg})}`;
|
|
4113
4263
|
}
|
|
4114
4264
|
case "loop": {
|
|
4115
|
-
|
|
4265
|
+
const boundHere = new Set(opts.loopBoundNames ?? []);
|
|
4266
|
+
if (node.paramBindings && node.paramBindings.length > 0) {
|
|
4267
|
+
for (const b of node.paramBindings)
|
|
4268
|
+
boundHere.add(b.name);
|
|
4269
|
+
} else if (!node.param.startsWith("[") && !node.param.startsWith("{")) {
|
|
4270
|
+
boundHere.add(node.param);
|
|
4271
|
+
}
|
|
4272
|
+
if (node.index)
|
|
4273
|
+
boundHere.add(node.index);
|
|
4274
|
+
const childEnv = {
|
|
4275
|
+
...env,
|
|
4276
|
+
substitutions: new Map([...env.substitutions].filter(([name]) => !boundHere.has(name)))
|
|
4277
|
+
};
|
|
4278
|
+
const recurseInLoopBody = (n) => generateCsrTemplateWithOpts(n, {
|
|
4279
|
+
...opts,
|
|
4280
|
+
insideLoop: true,
|
|
4281
|
+
loopDepth: loopDepth + 1,
|
|
4282
|
+
inHoistedChildren: false,
|
|
4283
|
+
loopBoundNames: boundHere,
|
|
4284
|
+
csrEnv: childEnv
|
|
4285
|
+
});
|
|
4286
|
+
let childTemplate = node.children.map(recurseInLoopBody).join("");
|
|
4116
4287
|
if (node.bodyIsItemConditional && node.key) {
|
|
4117
4288
|
childTemplate = `${itemAnchorTemplate(node.key)}${childTemplate}`;
|
|
4118
4289
|
}
|
|
@@ -4126,7 +4297,7 @@ function generateCsrTemplateWithOpts(node, opts) {
|
|
|
4126
4297
|
if (node.flatMapCallback) {
|
|
4127
4298
|
let body = node.flatMapCallback.templateBody ?? node.flatMapCallback.body;
|
|
4128
4299
|
for (const frag of node.flatMapCallback.fragments) {
|
|
4129
|
-
const renderedIr =
|
|
4300
|
+
const renderedIr = recurseInLoopBody(frag.ir);
|
|
4130
4301
|
body = body.replace(frag.placeholder, `\`${renderedIr}\``);
|
|
4131
4302
|
}
|
|
4132
4303
|
body = applyPropsRewrite(body, propsObjectName ?? null);
|
|
@@ -5086,6 +5257,8 @@ function needsTypeBasedDetection(source) {
|
|
|
5086
5257
|
return true;
|
|
5087
5258
|
if (/\.map\s*\(/.test(source))
|
|
5088
5259
|
return true;
|
|
5260
|
+
if (source.includes("createSelector"))
|
|
5261
|
+
return true;
|
|
5089
5262
|
return false;
|
|
5090
5263
|
}
|
|
5091
5264
|
function findBrandPackageImportLoc(sourceFile, filePath) {
|
|
@@ -6062,6 +6235,7 @@ var CLIENT_EXPORTS = new Set([
|
|
|
6062
6235
|
"createEffect",
|
|
6063
6236
|
"createDisposableEffect",
|
|
6064
6237
|
"createMemo",
|
|
6238
|
+
"createSelector",
|
|
6065
6239
|
"createRoot",
|
|
6066
6240
|
"onCleanup",
|
|
6067
6241
|
"onMount",
|
|
@@ -8148,9 +8322,15 @@ function exprHasFunctionCalls(expr) {
|
|
|
8148
8322
|
return found;
|
|
8149
8323
|
}
|
|
8150
8324
|
function rewriteBarePropRefs2(text, expr, ctx) {
|
|
8151
|
-
|
|
8325
|
+
let propNames = getDestructuredPropNames(ctx);
|
|
8152
8326
|
if (!propNames)
|
|
8153
8327
|
return;
|
|
8328
|
+
if (ctx.loopParams.size > 0) {
|
|
8329
|
+
const filtered = new Set([...propNames].filter((n) => !ctx.loopParams.has(n)));
|
|
8330
|
+
if (filtered.size === 0)
|
|
8331
|
+
return;
|
|
8332
|
+
propNames = filtered;
|
|
8333
|
+
}
|
|
8154
8334
|
const extraPropRefs = collectBranchLocalPropRefsViaSubstitution(expr, ctx);
|
|
8155
8335
|
return rewriteBarePropRefs(text, expr, propNames, extraPropRefs);
|
|
8156
8336
|
}
|
|
@@ -8316,26 +8496,29 @@ function makeBindingEnv(ctx) {
|
|
|
8316
8496
|
function parseValueExpr(trimmed) {
|
|
8317
8497
|
return parseExpression(trimmed.startsWith("{") ? `(${trimmed})` : trimmed);
|
|
8318
8498
|
}
|
|
8319
|
-
|
|
8499
|
+
var EMPTY_BOUND = new Set;
|
|
8500
|
+
function attachParsedExpressions(node, analyzer, bound = EMPTY_BOUND) {
|
|
8501
|
+
const parse2 = (trimmed) => resolveCallbackMethodFunctionReferences(parseExpression(trimmed), analyzer, bound);
|
|
8502
|
+
const parseValue = (trimmed) => resolveCallbackMethodFunctionReferences(parseValueExpr(trimmed), analyzer, bound);
|
|
8320
8503
|
if (node.type === "expression") {
|
|
8321
8504
|
const trimmed = node.expr.trim();
|
|
8322
8505
|
if (trimmed)
|
|
8323
|
-
node.parsed =
|
|
8506
|
+
node.parsed = parse2(trimmed);
|
|
8324
8507
|
} else if (node.type === "conditional" || node.type === "if-statement") {
|
|
8325
8508
|
const trimmed = node.condition.trim();
|
|
8326
8509
|
if (trimmed)
|
|
8327
|
-
node.parsedCondition =
|
|
8510
|
+
node.parsedCondition = parse2(trimmed);
|
|
8328
8511
|
}
|
|
8329
8512
|
if (node.type === "element") {
|
|
8330
8513
|
for (const attr of node.attrs) {
|
|
8331
8514
|
if (attr.value.kind === "expression") {
|
|
8332
8515
|
const trimmed = attr.value.expr.trim();
|
|
8333
8516
|
if (trimmed)
|
|
8334
|
-
attr.value.parsed =
|
|
8517
|
+
attr.value.parsed = parseValue(trimmed);
|
|
8335
8518
|
} else if (attr.value.kind === "spread") {
|
|
8336
8519
|
const trimmed = attr.value.expr.trim();
|
|
8337
8520
|
if (trimmed)
|
|
8338
|
-
attr.value.parsed =
|
|
8521
|
+
attr.value.parsed = parse2(trimmed);
|
|
8339
8522
|
}
|
|
8340
8523
|
}
|
|
8341
8524
|
} else if (node.type === "component") {
|
|
@@ -8343,14 +8526,14 @@ function attachParsedExpressions(node) {
|
|
|
8343
8526
|
if (prop.value.kind === "expression") {
|
|
8344
8527
|
const trimmed = prop.value.expr.trim();
|
|
8345
8528
|
if (trimmed)
|
|
8346
|
-
prop.value.parsed =
|
|
8529
|
+
prop.value.parsed = parseValue(trimmed);
|
|
8347
8530
|
}
|
|
8348
8531
|
}
|
|
8349
8532
|
} else if (node.type === "provider") {
|
|
8350
8533
|
if (node.valueProp.value.kind === "expression") {
|
|
8351
8534
|
const trimmed = node.valueProp.value.expr.trim();
|
|
8352
8535
|
if (trimmed)
|
|
8353
|
-
node.valueProp.value.parsed =
|
|
8536
|
+
node.valueProp.value.parsed = parseValue(trimmed);
|
|
8354
8537
|
}
|
|
8355
8538
|
}
|
|
8356
8539
|
switch (node.type) {
|
|
@@ -8359,47 +8542,51 @@ function attachParsedExpressions(node) {
|
|
|
8359
8542
|
case "fragment":
|
|
8360
8543
|
case "provider":
|
|
8361
8544
|
for (const child of node.children)
|
|
8362
|
-
attachParsedExpressions(child);
|
|
8545
|
+
attachParsedExpressions(child, analyzer, bound);
|
|
8363
8546
|
break;
|
|
8364
8547
|
case "async":
|
|
8365
|
-
attachParsedExpressions(node.fallback);
|
|
8548
|
+
attachParsedExpressions(node.fallback, analyzer, bound);
|
|
8366
8549
|
for (const child of node.children)
|
|
8367
|
-
attachParsedExpressions(child);
|
|
8550
|
+
attachParsedExpressions(child, analyzer, bound);
|
|
8368
8551
|
break;
|
|
8369
8552
|
case "loop": {
|
|
8370
8553
|
const trimmedArray = node.array.trim();
|
|
8371
8554
|
if (trimmedArray)
|
|
8372
|
-
node.arrayParsed =
|
|
8555
|
+
node.arrayParsed = parse2(trimmedArray);
|
|
8556
|
+
const loopBound = new Set(bound);
|
|
8557
|
+
loopBound.add(node.param);
|
|
8558
|
+
if (node.index)
|
|
8559
|
+
loopBound.add(node.index);
|
|
8373
8560
|
for (const child of node.children)
|
|
8374
|
-
attachParsedExpressions(child);
|
|
8561
|
+
attachParsedExpressions(child, analyzer, loopBound);
|
|
8375
8562
|
if (node.childComponent) {
|
|
8376
8563
|
for (const child of node.childComponent.children)
|
|
8377
|
-
attachParsedExpressions(child);
|
|
8564
|
+
attachParsedExpressions(child, analyzer, loopBound);
|
|
8378
8565
|
}
|
|
8379
8566
|
for (const nested of node.nestedComponents ?? []) {
|
|
8380
8567
|
for (const child of nested.children)
|
|
8381
|
-
attachParsedExpressions(child);
|
|
8568
|
+
attachParsedExpressions(child, analyzer, loopBound);
|
|
8382
8569
|
}
|
|
8383
8570
|
for (const frag of node.flatMapCallback?.fragments ?? []) {
|
|
8384
|
-
attachParsedExpressions(frag.ir);
|
|
8571
|
+
attachParsedExpressions(frag.ir, analyzer, loopBound);
|
|
8385
8572
|
}
|
|
8386
8573
|
break;
|
|
8387
8574
|
}
|
|
8388
8575
|
case "conditional":
|
|
8389
|
-
attachParsedExpressions(node.whenTrue);
|
|
8390
|
-
attachParsedExpressions(node.whenFalse);
|
|
8576
|
+
attachParsedExpressions(node.whenTrue, analyzer, bound);
|
|
8577
|
+
attachParsedExpressions(node.whenFalse, analyzer, bound);
|
|
8391
8578
|
break;
|
|
8392
8579
|
case "if-statement":
|
|
8393
|
-
attachParsedExpressions(node.consequent);
|
|
8580
|
+
attachParsedExpressions(node.consequent, analyzer, bound);
|
|
8394
8581
|
if (node.alternate)
|
|
8395
|
-
attachParsedExpressions(node.alternate);
|
|
8582
|
+
attachParsedExpressions(node.alternate, analyzer, bound);
|
|
8396
8583
|
break;
|
|
8397
8584
|
}
|
|
8398
8585
|
}
|
|
8399
8586
|
function jsxToIR(analyzer) {
|
|
8400
8587
|
const root = buildIRRoot(analyzer);
|
|
8401
8588
|
if (root)
|
|
8402
|
-
attachParsedExpressions(root);
|
|
8589
|
+
attachParsedExpressions(root, analyzer);
|
|
8403
8590
|
return root;
|
|
8404
8591
|
}
|
|
8405
8592
|
function buildIRRoot(analyzer) {
|
|
@@ -9486,8 +9673,23 @@ function extractSortComparator(callback, _method, ctx) {
|
|
|
9486
9673
|
};
|
|
9487
9674
|
}
|
|
9488
9675
|
function resolveSortComparatorIdentifier(name, ctx) {
|
|
9489
|
-
const constInfo = findLocalConst(name, ctx);
|
|
9490
|
-
const fnInfo = findLocalFunction(name, ctx);
|
|
9676
|
+
const constInfo = findLocalConst(name, ctx.analyzer);
|
|
9677
|
+
const fnInfo = findLocalFunction(name, ctx.analyzer);
|
|
9678
|
+
if (constInfo && fnInfo)
|
|
9679
|
+
return null;
|
|
9680
|
+
if (constInfo) {
|
|
9681
|
+
const ast = parseConstInitializer(constInfo);
|
|
9682
|
+
return ast && (ts11.isArrowFunction(ast) || ts11.isFunctionExpression(ast)) ? ast : null;
|
|
9683
|
+
}
|
|
9684
|
+
if (fnInfo) {
|
|
9685
|
+
const ast = parseFunctionInfoAsExpr(fnInfo);
|
|
9686
|
+
return ast && (ts11.isArrowFunction(ast) || ts11.isFunctionExpression(ast)) ? ast : null;
|
|
9687
|
+
}
|
|
9688
|
+
return null;
|
|
9689
|
+
}
|
|
9690
|
+
function resolveCallbackMethodFunctionReferenceIdentifier(name, analyzer) {
|
|
9691
|
+
const constInfo = findLocalConst(name, analyzer);
|
|
9692
|
+
const fnInfo = findLocalFunction(name, analyzer);
|
|
9491
9693
|
if (constInfo && fnInfo)
|
|
9492
9694
|
return null;
|
|
9493
9695
|
if (constInfo) {
|
|
@@ -9500,6 +9702,57 @@ function resolveSortComparatorIdentifier(name, ctx) {
|
|
|
9500
9702
|
}
|
|
9501
9703
|
return null;
|
|
9502
9704
|
}
|
|
9705
|
+
function resolveCallbackMethodFunctionReferences(expr, analyzer, bound = EMPTY_BOUND) {
|
|
9706
|
+
function visit2(e, bound2) {
|
|
9707
|
+
switch (e.kind) {
|
|
9708
|
+
case "literal":
|
|
9709
|
+
case "identifier":
|
|
9710
|
+
case "regex":
|
|
9711
|
+
case "unsupported":
|
|
9712
|
+
return e;
|
|
9713
|
+
case "call": {
|
|
9714
|
+
const callee = visit2(e.callee, bound2);
|
|
9715
|
+
const args = e.args.map((a) => visit2(a, bound2));
|
|
9716
|
+
if (callee.kind === "member" && !callee.computed && CALLBACK_METHODS.has(callee.property) && args[0]?.kind === "identifier" && !bound2.has(args[0].name)) {
|
|
9717
|
+
const resolved = resolveCallbackMethodFunctionReferenceIdentifier(args[0].name, analyzer);
|
|
9718
|
+
const arrow = resolved ? tsNodeToParsedExpr(resolved) : null;
|
|
9719
|
+
if (arrow && arrow.kind === "arrow")
|
|
9720
|
+
args[0] = arrow;
|
|
9721
|
+
}
|
|
9722
|
+
return { ...e, callee, args };
|
|
9723
|
+
}
|
|
9724
|
+
case "member":
|
|
9725
|
+
return { ...e, object: visit2(e.object, bound2) };
|
|
9726
|
+
case "index-access":
|
|
9727
|
+
return { ...e, object: visit2(e.object, bound2), index: visit2(e.index, bound2) };
|
|
9728
|
+
case "binary":
|
|
9729
|
+
case "logical":
|
|
9730
|
+
return { ...e, left: visit2(e.left, bound2), right: visit2(e.right, bound2) };
|
|
9731
|
+
case "unary":
|
|
9732
|
+
return { ...e, argument: visit2(e.argument, bound2) };
|
|
9733
|
+
case "conditional":
|
|
9734
|
+
return { ...e, test: visit2(e.test, bound2), consequent: visit2(e.consequent, bound2), alternate: visit2(e.alternate, bound2) };
|
|
9735
|
+
case "template-literal":
|
|
9736
|
+
return { ...e, parts: e.parts.map((p) => p.type === "expression" ? { ...p, expr: visit2(p.expr, bound2) } : p) };
|
|
9737
|
+
case "array-literal":
|
|
9738
|
+
return { ...e, elements: e.elements.map((el) => visit2(el, bound2)) };
|
|
9739
|
+
case "array-method":
|
|
9740
|
+
return {
|
|
9741
|
+
...e,
|
|
9742
|
+
object: visit2(e.object, bound2),
|
|
9743
|
+
args: e.args.map((a) => visit2(a, bound2)),
|
|
9744
|
+
...e.method === "flat" && e.depthExpr ? { depthExpr: visit2(e.depthExpr, bound2) } : {}
|
|
9745
|
+
};
|
|
9746
|
+
case "object-literal":
|
|
9747
|
+
return { ...e, properties: e.properties.map((p) => ({ ...p, value: visit2(p.value, bound2) })) };
|
|
9748
|
+
case "arrow": {
|
|
9749
|
+
const inner = e.params.length === 0 ? bound2 : new Set([...bound2, ...e.params]);
|
|
9750
|
+
return { ...e, body: visit2(e.body, inner) };
|
|
9751
|
+
}
|
|
9752
|
+
}
|
|
9753
|
+
}
|
|
9754
|
+
return visit2(expr, bound);
|
|
9755
|
+
}
|
|
9503
9756
|
function extractFilterPredicate(callback, ctx) {
|
|
9504
9757
|
if (!ts11.isArrowFunction(callback))
|
|
9505
9758
|
return { result: null };
|
|
@@ -9967,13 +10220,11 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
9967
10220
|
setArray(innerSort.array);
|
|
9968
10221
|
}
|
|
9969
10222
|
} else {
|
|
9970
|
-
|
|
9971
|
-
arrayExpr = filterInfo.array;
|
|
10223
|
+
setArray(filterInfo.array);
|
|
9972
10224
|
}
|
|
9973
10225
|
}
|
|
9974
10226
|
} else {
|
|
9975
|
-
|
|
9976
|
-
arrayExpr = chainSource;
|
|
10227
|
+
setArray(chainSource);
|
|
9977
10228
|
}
|
|
9978
10229
|
const callback = node.arguments[0];
|
|
9979
10230
|
let param = "item";
|
|
@@ -10523,7 +10774,7 @@ function parseTemplateLiteral(expr, ctx) {
|
|
|
10523
10774
|
}
|
|
10524
10775
|
function tryResolveTemplateSpanFromConst(expr, ctx) {
|
|
10525
10776
|
if (ts11.isIdentifier(expr)) {
|
|
10526
|
-
const constInfo = findLocalConst(expr.text, ctx);
|
|
10777
|
+
const constInfo = findLocalConst(expr.text, ctx.analyzer);
|
|
10527
10778
|
if (!constInfo)
|
|
10528
10779
|
return null;
|
|
10529
10780
|
const ast = parseConstInitializer(constInfo);
|
|
@@ -10537,7 +10788,7 @@ function tryResolveTemplateSpanFromConst(expr, ctx) {
|
|
|
10537
10788
|
if (ts11.isElementAccessExpression(expr)) {
|
|
10538
10789
|
if (!ts11.isIdentifier(expr.expression))
|
|
10539
10790
|
return null;
|
|
10540
|
-
const constInfo = findLocalConst(expr.expression.text, ctx);
|
|
10791
|
+
const constInfo = findLocalConst(expr.expression.text, ctx.analyzer);
|
|
10541
10792
|
if (!constInfo)
|
|
10542
10793
|
return null;
|
|
10543
10794
|
const ast = parseConstInitializer(constInfo);
|
|
@@ -10563,16 +10814,16 @@ function tryResolveTemplateSpanFromConst(expr, ctx) {
|
|
|
10563
10814
|
}
|
|
10564
10815
|
return null;
|
|
10565
10816
|
}
|
|
10566
|
-
function findLocalConst(name,
|
|
10567
|
-
const matches =
|
|
10817
|
+
function findLocalConst(name, analyzer) {
|
|
10818
|
+
const matches = analyzer.localConstants.filter((c) => c.name === name);
|
|
10568
10819
|
if (matches.length === 0)
|
|
10569
10820
|
return;
|
|
10570
10821
|
const fnScoped = matches.filter((c) => !c.isModule);
|
|
10571
10822
|
const pool = fnScoped.length > 0 ? fnScoped : matches;
|
|
10572
10823
|
return pool[pool.length - 1];
|
|
10573
10824
|
}
|
|
10574
|
-
function findLocalFunction(name,
|
|
10575
|
-
const matches =
|
|
10825
|
+
function findLocalFunction(name, analyzer) {
|
|
10826
|
+
const matches = analyzer.localFunctions.filter((f) => f.name === name);
|
|
10576
10827
|
if (matches.length === 0)
|
|
10577
10828
|
return;
|
|
10578
10829
|
const fnScoped = matches.filter((f) => !f.isModule);
|
|
@@ -10614,7 +10865,9 @@ function hasDynamicTagBinding(name, sourceFile) {
|
|
|
10614
10865
|
return found;
|
|
10615
10866
|
}
|
|
10616
10867
|
function tryResolveIdentifierAsTemplateLiteral(ident, ctx) {
|
|
10617
|
-
|
|
10868
|
+
if (ctx.loopParams.has(ident.text))
|
|
10869
|
+
return null;
|
|
10870
|
+
const constInfo = findLocalConst(ident.text, ctx.analyzer);
|
|
10618
10871
|
if (!constInfo)
|
|
10619
10872
|
return null;
|
|
10620
10873
|
const ast = parseConstInitializer(constInfo);
|
|
@@ -10711,8 +10964,8 @@ function tryDesugarInterleaveTaggedTemplate(expr, ctx) {
|
|
|
10711
10964
|
return rewritten ?? expr;
|
|
10712
10965
|
}
|
|
10713
10966
|
function resolveInterleaveTagIdentifier(name, ctx) {
|
|
10714
|
-
const constInfo = findLocalConst(name, ctx);
|
|
10715
|
-
const fnInfo = findLocalFunction(name, ctx);
|
|
10967
|
+
const constInfo = findLocalConst(name, ctx.analyzer);
|
|
10968
|
+
const fnInfo = findLocalFunction(name, ctx.analyzer);
|
|
10716
10969
|
if (constInfo && fnInfo)
|
|
10717
10970
|
return null;
|
|
10718
10971
|
if (constInfo) {
|
|
@@ -11466,6 +11719,7 @@ function collectLoopChildEventsWithNesting(node, initialNestingStack = []) {
|
|
|
11466
11719
|
depth: scope.nestingStack.length + 1,
|
|
11467
11720
|
array: l.array,
|
|
11468
11721
|
param: l.param,
|
|
11722
|
+
index: l.index,
|
|
11469
11723
|
key: l.key,
|
|
11470
11724
|
markerId: l.markerId,
|
|
11471
11725
|
containerSlotId: scope.lastElementSlotId,
|
|
@@ -11556,76 +11810,227 @@ function collectLoopChildReactiveAttrs(node, ctx, loopParam, loopParamBindings)
|
|
|
11556
11810
|
return attrs;
|
|
11557
11811
|
}
|
|
11558
11812
|
|
|
11559
|
-
// src/ir-to-client-js/
|
|
11560
|
-
var
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11813
|
+
// src/ir-to-client-js/control-flow/stringify/template-parse.ts
|
|
11814
|
+
var SVG_ROOT_TAGS = new Set([
|
|
11815
|
+
"svg",
|
|
11816
|
+
"path",
|
|
11817
|
+
"circle",
|
|
11818
|
+
"rect",
|
|
11819
|
+
"line",
|
|
11820
|
+
"polyline",
|
|
11821
|
+
"polygon",
|
|
11822
|
+
"ellipse",
|
|
11823
|
+
"text",
|
|
11824
|
+
"tspan",
|
|
11825
|
+
"textPath",
|
|
11826
|
+
"g",
|
|
11827
|
+
"defs",
|
|
11828
|
+
"use",
|
|
11829
|
+
"symbol",
|
|
11830
|
+
"switch",
|
|
11831
|
+
"clipPath",
|
|
11832
|
+
"mask",
|
|
11833
|
+
"marker",
|
|
11834
|
+
"pattern",
|
|
11835
|
+
"linearGradient",
|
|
11836
|
+
"radialGradient",
|
|
11837
|
+
"stop",
|
|
11838
|
+
"image",
|
|
11839
|
+
"foreignObject",
|
|
11840
|
+
"filter",
|
|
11841
|
+
"feBlend",
|
|
11842
|
+
"feColorMatrix",
|
|
11843
|
+
"feComposite",
|
|
11844
|
+
"feFlood",
|
|
11845
|
+
"feGaussianBlur",
|
|
11846
|
+
"feMerge",
|
|
11847
|
+
"feMergeNode",
|
|
11848
|
+
"feMorphology",
|
|
11849
|
+
"feOffset",
|
|
11850
|
+
"feTurbulence",
|
|
11851
|
+
"animate",
|
|
11852
|
+
"animateTransform",
|
|
11853
|
+
"animateMotion"
|
|
11854
|
+
]);
|
|
11855
|
+
function templateRootIsSvg(template) {
|
|
11856
|
+
const stripped = stripLeadingNonContent(template);
|
|
11857
|
+
const m = stripped.match(/^<\s*([A-Za-z][A-Za-z0-9-]*)/);
|
|
11858
|
+
if (m) {
|
|
11859
|
+
const tag = m[1];
|
|
11860
|
+
if (SVG_ROOT_TAGS.has(tag))
|
|
11861
|
+
return true;
|
|
11862
|
+
return SVG_ROOT_TAGS.has(tag.toLowerCase());
|
|
11594
11863
|
}
|
|
11864
|
+
const branches = extractConditionalBranchTemplates(stripped);
|
|
11865
|
+
if (branches === null || branches.length === 0)
|
|
11866
|
+
return false;
|
|
11867
|
+
return branches.every(templateRootIsSvg);
|
|
11595
11868
|
}
|
|
11596
|
-
function
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11869
|
+
function multiRootTemplateNeedsSvgWrap(template) {
|
|
11870
|
+
const m = stripLeadingNonContent(template).match(/^<\s*([A-Za-z][A-Za-z0-9-]*)/);
|
|
11871
|
+
if (m && m[1].toLowerCase() === "svg")
|
|
11872
|
+
return false;
|
|
11873
|
+
return templateRootIsSvg(template);
|
|
11874
|
+
}
|
|
11875
|
+
function stripLeadingNonContent(template) {
|
|
11876
|
+
let s = template.trimStart();
|
|
11877
|
+
while (s.startsWith("<!--")) {
|
|
11878
|
+
const end = s.indexOf("-->");
|
|
11879
|
+
if (end < 0)
|
|
11880
|
+
return s;
|
|
11881
|
+
s = s.slice(end + 3).trimStart();
|
|
11607
11882
|
}
|
|
11608
|
-
|
|
11609
|
-
return staticCount;
|
|
11610
|
-
const parts = staticCount > 0 ? [String(staticCount), ...dynamic] : dynamic;
|
|
11611
|
-
return parts.length === 1 ? parts[0] : `(${parts.join(" + ")})`;
|
|
11883
|
+
return s;
|
|
11612
11884
|
}
|
|
11613
|
-
function
|
|
11614
|
-
|
|
11885
|
+
function extractConditionalBranchTemplates(template) {
|
|
11886
|
+
if (!template.startsWith("${"))
|
|
11887
|
+
return null;
|
|
11888
|
+
const exprEnd = findInterpolationEnd(template, 2);
|
|
11889
|
+
if (exprEnd < 0)
|
|
11890
|
+
return null;
|
|
11891
|
+
const trailing = stripLeadingNonContent(template.slice(exprEnd + 1));
|
|
11892
|
+
if (trailing.length > 0)
|
|
11893
|
+
return null;
|
|
11894
|
+
const expr = template.slice(2, exprEnd);
|
|
11895
|
+
return findTopLevelTemplateLiterals(expr);
|
|
11615
11896
|
}
|
|
11616
|
-
function
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11897
|
+
function emitTemplateCloneInline(template) {
|
|
11898
|
+
if (templateRootIsSvg(template)) {
|
|
11899
|
+
return `const __tpl = document.createElement('template'); __tpl.innerHTML = \`<svg>${template}</svg>\`; return __tpl.content.firstElementChild.firstElementChild.cloneNode(true)`;
|
|
11900
|
+
}
|
|
11901
|
+
return `const __tpl = document.createElement('template'); __tpl.innerHTML = \`${template}\`; return __tpl.content.firstElementChild.cloneNode(true)`;
|
|
11902
|
+
}
|
|
11903
|
+
function emitHoistedTemplateDecl(lines, indent, tplVar, skeletonTemplate) {
|
|
11904
|
+
const isSvg = templateRootIsSvg(skeletonTemplate);
|
|
11905
|
+
const html = isSvg ? `<svg>${skeletonTemplate}</svg>` : skeletonTemplate;
|
|
11906
|
+
lines.push(`${indent}const ${tplVar} = document.createElement('template')`);
|
|
11907
|
+
lines.push(`${indent}${tplVar}.innerHTML = \`${html}\``);
|
|
11908
|
+
}
|
|
11909
|
+
function hoistedCloneExpr(tplVar, skeletonTemplate) {
|
|
11910
|
+
return templateRootIsSvg(skeletonTemplate) ? `${tplVar}.content.firstElementChild.firstElementChild.cloneNode(true)` : `${tplVar}.content.firstElementChild.cloneNode(true)`;
|
|
11911
|
+
}
|
|
11912
|
+
function emitTemplateCloneLines(template, indent) {
|
|
11913
|
+
if (templateRootIsSvg(template)) {
|
|
11914
|
+
return [
|
|
11915
|
+
`${indent}const __tpl = document.createElement('template')`,
|
|
11916
|
+
`${indent}__tpl.innerHTML = \`<svg>${template}</svg>\``,
|
|
11917
|
+
`${indent}return __tpl.content.firstElementChild.firstElementChild.cloneNode(true)`
|
|
11918
|
+
];
|
|
11919
|
+
}
|
|
11920
|
+
return [
|
|
11921
|
+
`${indent}const __tpl = document.createElement('template')`,
|
|
11922
|
+
`${indent}__tpl.innerHTML = \`${template}\``,
|
|
11923
|
+
`${indent}return __tpl.content.firstElementChild.cloneNode(true)`
|
|
11924
|
+
];
|
|
11925
|
+
}
|
|
11926
|
+
function emitLoopItemElementSetup(lines, opts) {
|
|
11927
|
+
const { template, bodyIsMultiRoot, indent, singleRootLayout } = opts;
|
|
11928
|
+
const innerIndent = indent + " ";
|
|
11929
|
+
if (bodyIsMultiRoot) {
|
|
11930
|
+
lines.push(`${indent}let __el, __extras`);
|
|
11931
|
+
lines.push(`${indent}if (__existing) {`);
|
|
11932
|
+
lines.push(`${innerIndent}__el = __existing`);
|
|
11933
|
+
lines.push(`${indent}} else {`);
|
|
11934
|
+
for (const ln of emitMultiRootTemplateCloneLines(template, innerIndent, "__el", "__extras")) {
|
|
11935
|
+
lines.push(ln);
|
|
11936
|
+
}
|
|
11937
|
+
lines.push(`${innerIndent}__el.__bfExtras = __extras`);
|
|
11938
|
+
lines.push(`${indent}}`);
|
|
11939
|
+
return;
|
|
11940
|
+
}
|
|
11941
|
+
if (singleRootLayout === "inline") {
|
|
11942
|
+
const cloneExpr = emitTemplateCloneInline(template);
|
|
11943
|
+
lines.push(`${indent}const __el = __existing ?? (() => { ${cloneExpr} })()`);
|
|
11944
|
+
return;
|
|
11945
|
+
}
|
|
11946
|
+
lines.push(`${indent}const __el = __existing ?? (() => {`);
|
|
11947
|
+
for (const ln of emitTemplateCloneLines(template, innerIndent))
|
|
11948
|
+
lines.push(ln);
|
|
11949
|
+
lines.push(`${indent}})()`);
|
|
11950
|
+
}
|
|
11951
|
+
function emitMultiRootTemplateCloneLines(template, indent, varEl, varExtras) {
|
|
11952
|
+
const isSvg = multiRootTemplateNeedsSvgWrap(template);
|
|
11953
|
+
const innerHtmlExpr = isSvg ? `\`<svg>${template}</svg>\`` : `\`${template}\``;
|
|
11954
|
+
const parentExpr = isSvg ? `__tpl.content.firstElementChild` : `__tpl.content`;
|
|
11955
|
+
return [
|
|
11956
|
+
`${indent}const __tpl = document.createElement('template')`,
|
|
11957
|
+
`${indent}__tpl.innerHTML = ${innerHtmlExpr}`,
|
|
11958
|
+
`${indent}${varEl} = ${parentExpr}.firstElementChild.cloneNode(true)`,
|
|
11959
|
+
`${indent}${varExtras} = []`,
|
|
11960
|
+
`${indent}{ let __sib = ${parentExpr}.firstElementChild.nextElementSibling; while (__sib) { ${varExtras}.push(__sib.cloneNode(true)); __sib = __sib.nextElementSibling } }`
|
|
11961
|
+
];
|
|
11962
|
+
}
|
|
11963
|
+
|
|
11964
|
+
// src/ir-to-client-js/collect-elements.ts
|
|
11965
|
+
var EMPTY_RENDER_EXPRS = new Set(["null", "undefined", "false", "''", '""', "``"]);
|
|
11966
|
+
function domElementCount(node) {
|
|
11967
|
+
switch (node.type) {
|
|
11968
|
+
case "element":
|
|
11969
|
+
case "component":
|
|
11970
|
+
case "provider":
|
|
11971
|
+
case "async":
|
|
11972
|
+
return 1;
|
|
11973
|
+
case "text":
|
|
11974
|
+
return 0;
|
|
11975
|
+
case "expression":
|
|
11976
|
+
return EMPTY_RENDER_EXPRS.has(node.expr.trim()) ? 0 : null;
|
|
11977
|
+
case "loop":
|
|
11978
|
+
if (node.bodyIsItemConditional || node.method === "flatMap")
|
|
11979
|
+
return null;
|
|
11980
|
+
return `(${buildLoopChainExpr({
|
|
11981
|
+
base: node.array,
|
|
11982
|
+
sortComparator: node.sortComparator,
|
|
11983
|
+
filterPredicate: node.filterPredicate,
|
|
11984
|
+
chainOrder: node.chainOrder
|
|
11985
|
+
})}).length`;
|
|
11986
|
+
case "conditional": {
|
|
11987
|
+
const t = domElementCount(node.whenTrue);
|
|
11988
|
+
const f = domElementCount(node.whenFalse);
|
|
11989
|
+
if (t === null || f === null)
|
|
11990
|
+
return null;
|
|
11991
|
+
if (typeof t === "number" && typeof f === "number" && t === f)
|
|
11992
|
+
return t;
|
|
11993
|
+
return `(${node.condition} ? ${t} : ${f})`;
|
|
11994
|
+
}
|
|
11995
|
+
case "fragment":
|
|
11996
|
+
return sumElementCounts(node.children);
|
|
11997
|
+
default:
|
|
11998
|
+
return null;
|
|
11999
|
+
}
|
|
12000
|
+
}
|
|
12001
|
+
function sumElementCounts(nodes) {
|
|
12002
|
+
let staticCount = 0;
|
|
12003
|
+
const dynamic = [];
|
|
12004
|
+
for (const n of nodes) {
|
|
12005
|
+
const c = domElementCount(n);
|
|
12006
|
+
if (c === null)
|
|
12007
|
+
return null;
|
|
12008
|
+
if (typeof c === "number")
|
|
12009
|
+
staticCount += c;
|
|
12010
|
+
else
|
|
12011
|
+
dynamic.push(c);
|
|
12012
|
+
}
|
|
12013
|
+
if (dynamic.length === 0)
|
|
12014
|
+
return staticCount;
|
|
12015
|
+
const parts = staticCount > 0 ? [String(staticCount), ...dynamic] : dynamic;
|
|
12016
|
+
return parts.length === 1 ? parts[0] : `(${parts.join(" + ")})`;
|
|
12017
|
+
}
|
|
12018
|
+
function legacyElementCount(node) {
|
|
12019
|
+
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;
|
|
12020
|
+
}
|
|
12021
|
+
function computeLoopSiblingOffsets(root) {
|
|
12022
|
+
const offsets = new Map;
|
|
12023
|
+
const recordRun = (children, preceding) => {
|
|
12024
|
+
for (const child of children) {
|
|
12025
|
+
if (child.type === "loop") {
|
|
12026
|
+
if (preceding.length > 0 && !offsets.has(child)) {
|
|
12027
|
+
offsets.set(child, [...preceding]);
|
|
12028
|
+
}
|
|
12029
|
+
preceding.push(child);
|
|
12030
|
+
} else if (child.type === "fragment" || child.type === "provider" || child.type === "async") {
|
|
12031
|
+
recordRun(child.children, preceding);
|
|
12032
|
+
} else {
|
|
12033
|
+
preceding.push(child);
|
|
11629
12034
|
}
|
|
11630
12035
|
}
|
|
11631
12036
|
};
|
|
@@ -11734,6 +12139,7 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
|
|
|
11734
12139
|
arrayFreeIdentifiers: n.arrayFreeIdentifiers,
|
|
11735
12140
|
param: n.param,
|
|
11736
12141
|
paramBindings: n.paramBindings,
|
|
12142
|
+
index: n.index,
|
|
11737
12143
|
key: n.key,
|
|
11738
12144
|
markerId: n.markerId,
|
|
11739
12145
|
bodyIsMultiRoot: n.bodyIsMultiRoot,
|
|
@@ -11931,6 +12337,7 @@ function collectElements(node, ctx, siblingOffsets, insideConditional = false) {
|
|
|
11931
12337
|
let template = "";
|
|
11932
12338
|
let staticItemTemplate;
|
|
11933
12339
|
let skeletonTemplate;
|
|
12340
|
+
let skeletonPaths;
|
|
11934
12341
|
if (l.childComponent) {
|
|
11935
12342
|
template = "";
|
|
11936
12343
|
if (l.isStaticArray && l.children[0]) {
|
|
@@ -11942,10 +12349,14 @@ function collectElements(node, ctx, siblingOffsets, insideConditional = false) {
|
|
|
11942
12349
|
if (l.isStaticArray) {
|
|
11943
12350
|
staticItemTemplate = useElementReconciliation ? irToPlaceholderTemplate(l.children[0], buildRestSpreadNames(ctx), 0) : irToHtmlTemplate(l.children[0], buildRestSpreadNames(ctx), 0);
|
|
11944
12351
|
} else if (!useElementReconciliation && !l.bodyIsMultiRoot && !l.bodyIsItemConditional) {
|
|
11945
|
-
|
|
12352
|
+
const skeletonSafeSlots = {
|
|
11946
12353
|
reactiveAttrKeys: new Set(bindings.reactiveAttrs.map((a) => `${a.childSlotId}::${a.attrName}`)),
|
|
11947
12354
|
reactiveTextSlotIds: new Set(bindings.reactiveTexts.map((t) => t.slotId))
|
|
11948
|
-
}
|
|
12355
|
+
};
|
|
12356
|
+
skeletonTemplate = buildLoopSkeletonTemplate(l.children[0], skeletonSafeSlots) ?? undefined;
|
|
12357
|
+
if (skeletonTemplate && !templateRootIsSvg(skeletonTemplate)) {
|
|
12358
|
+
skeletonPaths = computeSkeletonSlotPaths(l.children[0], skeletonSafeSlots) ?? undefined;
|
|
12359
|
+
}
|
|
11949
12360
|
}
|
|
11950
12361
|
}
|
|
11951
12362
|
ctx.loopElements.push({
|
|
@@ -11965,6 +12376,7 @@ function collectElements(node, ctx, siblingOffsets, insideConditional = false) {
|
|
|
11965
12376
|
template,
|
|
11966
12377
|
staticItemTemplate,
|
|
11967
12378
|
skeletonTemplate,
|
|
12379
|
+
skeletonPaths,
|
|
11968
12380
|
childEventHandlers: childHandlers,
|
|
11969
12381
|
bindings,
|
|
11970
12382
|
childComponent: l.childComponent,
|
|
@@ -12755,6 +13167,7 @@ var RUNTIME_IMPORT_CANDIDATES = [
|
|
|
12755
13167
|
"__slot",
|
|
12756
13168
|
"__bfSlot",
|
|
12757
13169
|
"__bfText",
|
|
13170
|
+
"tAfter",
|
|
12758
13171
|
"beginTurn",
|
|
12759
13172
|
"endTurn"
|
|
12760
13173
|
];
|
|
@@ -14625,9 +15038,63 @@ import { BF_SCOPE as BF_SCOPE2, BF_HOST, BF_AT } from "@barefootjs/shared";
|
|
|
14625
15038
|
function loopKeyFn(loop) {
|
|
14626
15039
|
if (loop.key === null)
|
|
14627
15040
|
return "null";
|
|
14628
|
-
const params =
|
|
15041
|
+
const params = `${loop.param}${loop.index ? `, ${loop.index}` : ""}`;
|
|
14629
15042
|
return `(${params}) => String(${loop.key})`;
|
|
14630
15043
|
}
|
|
15044
|
+
function nestedLoopReferencesIndex(inner, comps, events) {
|
|
15045
|
+
const index = inner.index;
|
|
15046
|
+
if (!index)
|
|
15047
|
+
return false;
|
|
15048
|
+
const exprRefs = (text, precomputed) => {
|
|
15049
|
+
if (precomputed)
|
|
15050
|
+
return precomputed.has(index);
|
|
15051
|
+
if (!text)
|
|
15052
|
+
return false;
|
|
15053
|
+
return extractFreeIdentifiersFromText(text).has(index);
|
|
15054
|
+
};
|
|
15055
|
+
if (exprRefs(inner.key))
|
|
15056
|
+
return true;
|
|
15057
|
+
for (const t of inner.bindings.reactiveTexts) {
|
|
15058
|
+
if (exprRefs(t.expression, t.freeIdentifiers))
|
|
15059
|
+
return true;
|
|
15060
|
+
}
|
|
15061
|
+
for (const a of inner.bindings.reactiveAttrs) {
|
|
15062
|
+
if (exprRefs(a.expression, a.freeIdentifiers))
|
|
15063
|
+
return true;
|
|
15064
|
+
}
|
|
15065
|
+
if (inner.mapPreamble && extractFreeIdentifiersFromStatementText(inner.mapPreamble).has(index))
|
|
15066
|
+
return true;
|
|
15067
|
+
if (inner.template && extractFreeIdentifiersFromTemplateText(inner.template).has(index))
|
|
15068
|
+
return true;
|
|
15069
|
+
for (const ev of events) {
|
|
15070
|
+
if (exprRefs(ev.handler))
|
|
15071
|
+
return true;
|
|
15072
|
+
}
|
|
15073
|
+
for (const r of inner.bindings.refs) {
|
|
15074
|
+
if (exprRefs(r.callback))
|
|
15075
|
+
return true;
|
|
15076
|
+
}
|
|
15077
|
+
for (const c of comps) {
|
|
15078
|
+
for (const p of c.props) {
|
|
15079
|
+
if (exprRefs(attrValueToString(p.value)))
|
|
15080
|
+
return true;
|
|
15081
|
+
}
|
|
15082
|
+
if (c.children?.length) {
|
|
15083
|
+
const childrenExpr = irChildrenToJsExpr(c.children);
|
|
15084
|
+
if (childrenExpr && exprRefs(childrenExpr))
|
|
15085
|
+
return true;
|
|
15086
|
+
}
|
|
15087
|
+
}
|
|
15088
|
+
return false;
|
|
15089
|
+
}
|
|
15090
|
+
function nestedLoopIndexAlias(inner, syntheticIndexVar, paramHead, comps, events) {
|
|
15091
|
+
const index = inner.index;
|
|
15092
|
+
if (!index || index === paramHead)
|
|
15093
|
+
return null;
|
|
15094
|
+
if (!nestedLoopReferencesIndex(inner, comps, events))
|
|
15095
|
+
return null;
|
|
15096
|
+
return `const ${index} = ${syntheticIndexVar}`;
|
|
15097
|
+
}
|
|
14631
15098
|
function buildChildRefBindings(refs, loopParam, loopParamBindings) {
|
|
14632
15099
|
if (refs.length === 0)
|
|
14633
15100
|
return [];
|
|
@@ -14808,6 +15275,7 @@ function buildOuterNestedPlan(elem, comp) {
|
|
|
14808
15275
|
}
|
|
14809
15276
|
function buildInnerLoopNestedPlan(elem, innerLoop, innerComps) {
|
|
14810
15277
|
const outerIndexParam = elem.index || "__idx";
|
|
15278
|
+
const innerIndexParam = innerLoop.index || "__innerIdx";
|
|
14811
15279
|
const comps = innerComps.map((comp) => ({
|
|
14812
15280
|
componentName: comp.name,
|
|
14813
15281
|
selector: buildCompSelector(comp),
|
|
@@ -14824,7 +15292,8 @@ function buildInnerLoopNestedPlan(elem, innerLoop, innerComps) {
|
|
|
14824
15292
|
innerContainerSlotId: innerLoop.containerSlotId ?? null,
|
|
14825
15293
|
innerArrayExpr: innerLoop.array,
|
|
14826
15294
|
innerParam: innerLoop.param,
|
|
14827
|
-
|
|
15295
|
+
innerIndexParam,
|
|
15296
|
+
innerOffsetExpr: buildLoopChildIndexExpr(innerIndexParam, innerLoop.offset),
|
|
14828
15297
|
innerPreludeStatements: innerLoop.mapPreamble ? [innerLoop.mapPreamble] : [],
|
|
14829
15298
|
depth: innerLoop.depth,
|
|
14830
15299
|
comps
|
|
@@ -14841,9 +15310,11 @@ function buildComponentRootedInnerLoopPlan(elem, innerLoop, innerComps) {
|
|
|
14841
15310
|
containerVar: `_${varSlotId(elem.slotId)}`,
|
|
14842
15311
|
outerArrayExpr: elem.array,
|
|
14843
15312
|
outerParam: elem.param,
|
|
15313
|
+
outerIndexParam: elem.index,
|
|
14844
15314
|
outerPreludeStatements: elem.mapPreamble ? [elem.mapPreamble] : [],
|
|
14845
15315
|
innerArrayExpr: innerLoop.array,
|
|
14846
15316
|
innerParam: innerLoop.param,
|
|
15317
|
+
innerIndexParam: innerLoop.index,
|
|
14847
15318
|
innerPreludeStatements: innerLoop.mapPreamble ? [innerLoop.mapPreamble] : [],
|
|
14848
15319
|
depth: innerLoop.depth,
|
|
14849
15320
|
comps
|
|
@@ -14936,6 +15407,7 @@ function emitInnerLoopNested(lines, plan) {
|
|
|
14936
15407
|
innerContainerSlotId,
|
|
14937
15408
|
innerArrayExpr,
|
|
14938
15409
|
innerParam,
|
|
15410
|
+
innerIndexParam,
|
|
14939
15411
|
innerOffsetExpr,
|
|
14940
15412
|
innerPreludeStatements,
|
|
14941
15413
|
depth,
|
|
@@ -14954,7 +15426,7 @@ function emitInnerLoopNested(lines, plan) {
|
|
|
14954
15426
|
} else {
|
|
14955
15427
|
lines.push(` const __ic = __outerEl`);
|
|
14956
15428
|
}
|
|
14957
|
-
lines.push(` ${innerArrayExpr}.forEach((${innerParam},
|
|
15429
|
+
lines.push(` ${innerArrayExpr}.forEach((${innerParam}, ${innerIndexParam}) => {`);
|
|
14958
15430
|
lines.push(` const __innerEl = __ic.children[${innerOffsetExpr}]`);
|
|
14959
15431
|
lines.push(` if (!__innerEl) return`);
|
|
14960
15432
|
for (const stmt of innerPreludeStatements) {
|
|
@@ -14975,9 +15447,11 @@ function emitComponentRootedInnerLoop(lines, plan) {
|
|
|
14975
15447
|
containerVar,
|
|
14976
15448
|
outerArrayExpr,
|
|
14977
15449
|
outerParam,
|
|
15450
|
+
outerIndexParam,
|
|
14978
15451
|
outerPreludeStatements,
|
|
14979
15452
|
innerArrayExpr,
|
|
14980
15453
|
innerParam,
|
|
15454
|
+
innerIndexParam,
|
|
14981
15455
|
innerPreludeStatements,
|
|
14982
15456
|
depth,
|
|
14983
15457
|
comps
|
|
@@ -14991,11 +15465,11 @@ function emitComponentRootedInnerLoop(lines, plan) {
|
|
|
14991
15465
|
lines.push(` const ${scopesVar(i)} = qsaChildScopes(${containerVar}, ${comp.selector})`);
|
|
14992
15466
|
lines.push(` let ${cursorVar(i)} = 0`);
|
|
14993
15467
|
});
|
|
14994
|
-
lines.push(` ${outerArrayExpr}.forEach((${outerParam}) => {`);
|
|
15468
|
+
lines.push(` ${outerArrayExpr}.forEach((${outerParam}${outerIndexParam ? `, ${outerIndexParam}` : ""}) => {`);
|
|
14995
15469
|
for (const stmt of outerPreludeStatements) {
|
|
14996
15470
|
lines.push(` ${stmt}`);
|
|
14997
15471
|
}
|
|
14998
|
-
lines.push(` ${innerArrayExpr}.forEach((${innerParam}) => {`);
|
|
15472
|
+
lines.push(` ${innerArrayExpr}.forEach((${innerParam}${innerIndexParam ? `, ${innerIndexParam}` : ""}) => {`);
|
|
14999
15473
|
for (const stmt of innerPreludeStatements) {
|
|
15000
15474
|
lines.push(` ${stmt}`);
|
|
15001
15475
|
}
|
|
@@ -15147,6 +15621,7 @@ function buildBranchInnerLoopsPlan(args) {
|
|
|
15147
15621
|
...ev,
|
|
15148
15622
|
handler: wrapInner(ev.handler)
|
|
15149
15623
|
}));
|
|
15624
|
+
const indexAlias = nestedLoopIndexAlias(inner, `__bidxbr_${i}`, paramHead, inner.childComponents ?? [], inner.bindings.events);
|
|
15150
15625
|
const reactiveTexts = inner.bindings.reactiveTexts.map((text) => ({
|
|
15151
15626
|
slotId: text.slotId,
|
|
15152
15627
|
wrappedExpression: wrapBoth(text.expression),
|
|
@@ -15161,6 +15636,7 @@ function buildBranchInnerLoopsPlan(args) {
|
|
|
15161
15636
|
keyFn: loopKeyFn(inner),
|
|
15162
15637
|
paramHead,
|
|
15163
15638
|
paramUnwrap,
|
|
15639
|
+
indexAlias,
|
|
15164
15640
|
wrappedTemplate: inner.template,
|
|
15165
15641
|
wrappedKey,
|
|
15166
15642
|
keyDepth: 1,
|
|
@@ -15402,7 +15878,7 @@ function buildInnerLoopsPlan(args) {
|
|
|
15402
15878
|
const containerExpr = inner.containerSlotId ? `qsa(${parentElVar}, '[bf="${inner.containerSlotId}"]')` : parentElVar;
|
|
15403
15879
|
const refsParent = !!outerLoopParam && (inner.arrayFreeIdentifiers?.has(outerLoopParam) ?? false);
|
|
15404
15880
|
const useReactive = refsParent && !!inner.template;
|
|
15405
|
-
const emit = useReactive ? buildReactiveEmit(inner, level, wrapOuter) : buildStaticEmit(inner, level);
|
|
15881
|
+
const emit = useReactive ? buildReactiveEmit(inner, level, wrapOuter, uidSuffix) : buildStaticEmit(inner, level, uidSuffix);
|
|
15406
15882
|
const arrayExpr = useReactive ? wrapOuter(inner.array) : inner.array;
|
|
15407
15883
|
const childLevelsPlan = childLevels.length > 0 ? buildInnerLoopsPlan({
|
|
15408
15884
|
levels: childLevels,
|
|
@@ -15428,7 +15904,7 @@ function buildInnerLoopsPlan(args) {
|
|
|
15428
15904
|
}
|
|
15429
15905
|
return plan;
|
|
15430
15906
|
}
|
|
15431
|
-
function buildReactiveEmit(inner, level, wrapOuter) {
|
|
15907
|
+
function buildReactiveEmit(inner, level, wrapOuter, uidSuffix) {
|
|
15432
15908
|
const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
|
|
15433
15909
|
const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
|
|
15434
15910
|
const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
|
|
@@ -15475,6 +15951,9 @@ function buildReactiveEmit(inner, level, wrapOuter) {
|
|
|
15475
15951
|
};
|
|
15476
15952
|
});
|
|
15477
15953
|
const preludeStatements = [];
|
|
15954
|
+
const indexAlias = nestedLoopIndexAlias(inner, `__innerIdx${uidSuffix}`, paramHead, level.comps, level.events);
|
|
15955
|
+
if (indexAlias)
|
|
15956
|
+
preludeStatements.push(indexAlias);
|
|
15478
15957
|
if (paramUnwrap)
|
|
15479
15958
|
preludeStatements.push(paramUnwrap);
|
|
15480
15959
|
if (inner.mapPreamble)
|
|
@@ -15495,8 +15974,13 @@ function buildReactiveEmit(inner, level, wrapOuter) {
|
|
|
15495
15974
|
childRefs
|
|
15496
15975
|
};
|
|
15497
15976
|
}
|
|
15498
|
-
function buildStaticEmit(inner, level) {
|
|
15499
|
-
const preludeStatements =
|
|
15977
|
+
function buildStaticEmit(inner, level, uidSuffix) {
|
|
15978
|
+
const preludeStatements = [];
|
|
15979
|
+
const indexAlias = nestedLoopIndexAlias(inner, `__innerIdx${uidSuffix}`, inner.param, level.comps, level.events);
|
|
15980
|
+
if (indexAlias)
|
|
15981
|
+
preludeStatements.push(indexAlias);
|
|
15982
|
+
if (inner.mapPreamble)
|
|
15983
|
+
preludeStatements.push(inner.mapPreamble);
|
|
15500
15984
|
return {
|
|
15501
15985
|
mode: "static",
|
|
15502
15986
|
rawKey: inner.key ?? null,
|
|
@@ -15999,151 +16483,6 @@ function emitReactiveChildProps(lines, ctx) {
|
|
|
15999
16483
|
}
|
|
16000
16484
|
}
|
|
16001
16485
|
|
|
16002
|
-
// src/ir-to-client-js/control-flow/stringify/template-parse.ts
|
|
16003
|
-
var SVG_ROOT_TAGS = new Set([
|
|
16004
|
-
"svg",
|
|
16005
|
-
"path",
|
|
16006
|
-
"circle",
|
|
16007
|
-
"rect",
|
|
16008
|
-
"line",
|
|
16009
|
-
"polyline",
|
|
16010
|
-
"polygon",
|
|
16011
|
-
"ellipse",
|
|
16012
|
-
"text",
|
|
16013
|
-
"tspan",
|
|
16014
|
-
"textPath",
|
|
16015
|
-
"g",
|
|
16016
|
-
"defs",
|
|
16017
|
-
"use",
|
|
16018
|
-
"symbol",
|
|
16019
|
-
"switch",
|
|
16020
|
-
"clipPath",
|
|
16021
|
-
"mask",
|
|
16022
|
-
"marker",
|
|
16023
|
-
"pattern",
|
|
16024
|
-
"linearGradient",
|
|
16025
|
-
"radialGradient",
|
|
16026
|
-
"stop",
|
|
16027
|
-
"image",
|
|
16028
|
-
"foreignObject",
|
|
16029
|
-
"filter",
|
|
16030
|
-
"feBlend",
|
|
16031
|
-
"feColorMatrix",
|
|
16032
|
-
"feComposite",
|
|
16033
|
-
"feFlood",
|
|
16034
|
-
"feGaussianBlur",
|
|
16035
|
-
"feMerge",
|
|
16036
|
-
"feMergeNode",
|
|
16037
|
-
"feMorphology",
|
|
16038
|
-
"feOffset",
|
|
16039
|
-
"feTurbulence",
|
|
16040
|
-
"animate",
|
|
16041
|
-
"animateTransform",
|
|
16042
|
-
"animateMotion"
|
|
16043
|
-
]);
|
|
16044
|
-
function templateRootIsSvg(template) {
|
|
16045
|
-
const stripped = stripLeadingNonContent(template);
|
|
16046
|
-
const m = stripped.match(/^<\s*([A-Za-z][A-Za-z0-9-]*)/);
|
|
16047
|
-
if (m) {
|
|
16048
|
-
const tag = m[1];
|
|
16049
|
-
if (SVG_ROOT_TAGS.has(tag))
|
|
16050
|
-
return true;
|
|
16051
|
-
return SVG_ROOT_TAGS.has(tag.toLowerCase());
|
|
16052
|
-
}
|
|
16053
|
-
const branches = extractConditionalBranchTemplates(stripped);
|
|
16054
|
-
if (branches === null || branches.length === 0)
|
|
16055
|
-
return false;
|
|
16056
|
-
return branches.every(templateRootIsSvg);
|
|
16057
|
-
}
|
|
16058
|
-
function stripLeadingNonContent(template) {
|
|
16059
|
-
let s = template.trimStart();
|
|
16060
|
-
while (s.startsWith("<!--")) {
|
|
16061
|
-
const end = s.indexOf("-->");
|
|
16062
|
-
if (end < 0)
|
|
16063
|
-
return s;
|
|
16064
|
-
s = s.slice(end + 3).trimStart();
|
|
16065
|
-
}
|
|
16066
|
-
return s;
|
|
16067
|
-
}
|
|
16068
|
-
function extractConditionalBranchTemplates(template) {
|
|
16069
|
-
if (!template.startsWith("${"))
|
|
16070
|
-
return null;
|
|
16071
|
-
const exprEnd = findInterpolationEnd(template, 2);
|
|
16072
|
-
if (exprEnd < 0)
|
|
16073
|
-
return null;
|
|
16074
|
-
const trailing = stripLeadingNonContent(template.slice(exprEnd + 1));
|
|
16075
|
-
if (trailing.length > 0)
|
|
16076
|
-
return null;
|
|
16077
|
-
const expr = template.slice(2, exprEnd);
|
|
16078
|
-
return findTopLevelTemplateLiterals(expr);
|
|
16079
|
-
}
|
|
16080
|
-
function emitTemplateCloneInline(template) {
|
|
16081
|
-
if (templateRootIsSvg(template)) {
|
|
16082
|
-
return `const __tpl = document.createElement('template'); __tpl.innerHTML = \`<svg>${template}</svg>\`; return __tpl.content.firstElementChild.firstElementChild.cloneNode(true)`;
|
|
16083
|
-
}
|
|
16084
|
-
return `const __tpl = document.createElement('template'); __tpl.innerHTML = \`${template}\`; return __tpl.content.firstElementChild.cloneNode(true)`;
|
|
16085
|
-
}
|
|
16086
|
-
function emitHoistedTemplateDecl(lines, indent, tplVar, skeletonTemplate) {
|
|
16087
|
-
const isSvg = templateRootIsSvg(skeletonTemplate);
|
|
16088
|
-
const html = isSvg ? `<svg>${skeletonTemplate}</svg>` : skeletonTemplate;
|
|
16089
|
-
lines.push(`${indent}const ${tplVar} = document.createElement('template')`);
|
|
16090
|
-
lines.push(`${indent}${tplVar}.innerHTML = \`${html}\``);
|
|
16091
|
-
}
|
|
16092
|
-
function hoistedCloneExpr(tplVar, skeletonTemplate) {
|
|
16093
|
-
return templateRootIsSvg(skeletonTemplate) ? `${tplVar}.content.firstElementChild.firstElementChild.cloneNode(true)` : `${tplVar}.content.firstElementChild.cloneNode(true)`;
|
|
16094
|
-
}
|
|
16095
|
-
function emitTemplateCloneLines(template, indent) {
|
|
16096
|
-
if (templateRootIsSvg(template)) {
|
|
16097
|
-
return [
|
|
16098
|
-
`${indent}const __tpl = document.createElement('template')`,
|
|
16099
|
-
`${indent}__tpl.innerHTML = \`<svg>${template}</svg>\``,
|
|
16100
|
-
`${indent}return __tpl.content.firstElementChild.firstElementChild.cloneNode(true)`
|
|
16101
|
-
];
|
|
16102
|
-
}
|
|
16103
|
-
return [
|
|
16104
|
-
`${indent}const __tpl = document.createElement('template')`,
|
|
16105
|
-
`${indent}__tpl.innerHTML = \`${template}\``,
|
|
16106
|
-
`${indent}return __tpl.content.firstElementChild.cloneNode(true)`
|
|
16107
|
-
];
|
|
16108
|
-
}
|
|
16109
|
-
function emitLoopItemElementSetup(lines, opts) {
|
|
16110
|
-
const { template, bodyIsMultiRoot, indent, singleRootLayout } = opts;
|
|
16111
|
-
const innerIndent = indent + " ";
|
|
16112
|
-
if (bodyIsMultiRoot) {
|
|
16113
|
-
lines.push(`${indent}let __el, __extras`);
|
|
16114
|
-
lines.push(`${indent}if (__existing) {`);
|
|
16115
|
-
lines.push(`${innerIndent}__el = __existing`);
|
|
16116
|
-
lines.push(`${indent}} else {`);
|
|
16117
|
-
for (const ln of emitMultiRootTemplateCloneLines(template, innerIndent, "__el", "__extras")) {
|
|
16118
|
-
lines.push(ln);
|
|
16119
|
-
}
|
|
16120
|
-
lines.push(`${innerIndent}__el.__bfExtras = __extras`);
|
|
16121
|
-
lines.push(`${indent}}`);
|
|
16122
|
-
return;
|
|
16123
|
-
}
|
|
16124
|
-
if (singleRootLayout === "inline") {
|
|
16125
|
-
const cloneExpr = emitTemplateCloneInline(template);
|
|
16126
|
-
lines.push(`${indent}const __el = __existing ?? (() => { ${cloneExpr} })()`);
|
|
16127
|
-
return;
|
|
16128
|
-
}
|
|
16129
|
-
lines.push(`${indent}const __el = __existing ?? (() => {`);
|
|
16130
|
-
for (const ln of emitTemplateCloneLines(template, innerIndent))
|
|
16131
|
-
lines.push(ln);
|
|
16132
|
-
lines.push(`${indent}})()`);
|
|
16133
|
-
}
|
|
16134
|
-
function emitMultiRootTemplateCloneLines(template, indent, varEl, varExtras) {
|
|
16135
|
-
const isSvg = templateRootIsSvg(template);
|
|
16136
|
-
const innerHtmlExpr = isSvg ? `\`<svg>${template}</svg>\`` : `\`${template}\``;
|
|
16137
|
-
const parentExpr = isSvg ? `__tpl.content.firstElementChild` : `__tpl.content`;
|
|
16138
|
-
return [
|
|
16139
|
-
`${indent}const __tpl = document.createElement('template')`,
|
|
16140
|
-
`${indent}__tpl.innerHTML = ${innerHtmlExpr}`,
|
|
16141
|
-
`${indent}${varEl} = ${parentExpr}.firstElementChild.cloneNode(true)`,
|
|
16142
|
-
`${indent}${varExtras} = []`,
|
|
16143
|
-
`${indent}{ let __sib = ${parentExpr}.firstElementChild.nextElementSibling; while (__sib) { ${varExtras}.push(__sib.cloneNode(true)); __sib = __sib.nextElementSibling } }`
|
|
16144
|
-
];
|
|
16145
|
-
}
|
|
16146
|
-
|
|
16147
16486
|
// src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts
|
|
16148
16487
|
function stringifyBranchEventBindings(lines, plan, indent) {
|
|
16149
16488
|
for (const slot of plan) {
|
|
@@ -16165,6 +16504,9 @@ function stringifyBranchInnerLoops(lines, plan, indent, pc) {
|
|
|
16165
16504
|
const uid = inner.uidSuffix;
|
|
16166
16505
|
lines.push(`${indent}{ const __bic${uid} = ${inner.containerExpr}`);
|
|
16167
16506
|
lines.push(`${indent}if (__bic${uid}) mapArray(() => ${inner.arrayExpr} || [], __bic${uid}, ${inner.keyFn}, (${inner.paramHead}, __bidx${uid}, __existing) => {`);
|
|
16507
|
+
if (inner.indexAlias) {
|
|
16508
|
+
lines.push(`${indent} ${inner.indexAlias}`);
|
|
16509
|
+
}
|
|
16168
16510
|
if (inner.paramUnwrap) {
|
|
16169
16511
|
lines.push(`${indent} ${inner.paramUnwrap}`);
|
|
16170
16512
|
}
|
|
@@ -16229,13 +16571,15 @@ function stringifyLoopChildArm(lines, arm, armIndent, pc) {
|
|
|
16229
16571
|
|
|
16230
16572
|
// src/ir-to-client-js/control-flow/stringify/reactive-effects.ts
|
|
16231
16573
|
function stringifyReactiveEffects(lines, plan, opts) {
|
|
16232
|
-
const { indent, elVar, bodyIsMultiRoot } = opts;
|
|
16574
|
+
const { indent, elVar, bodyIsMultiRoot, elementIndexBySlot, textIndexBySlot } = opts;
|
|
16233
16575
|
const lookup = bodyIsMultiRoot ? "qsaItem" : "qsa";
|
|
16234
16576
|
const pc = plan.profileComponentName;
|
|
16235
16577
|
const bindingBfId = (slotId) => profileBindingId(pc, slotId);
|
|
16236
16578
|
for (const slot of plan.attrSlots) {
|
|
16237
16579
|
const varName = `__ra_${varSlotId(slot.slotId)}`;
|
|
16238
|
-
|
|
16580
|
+
const pIdx = elementIndexBySlot?.get(slot.slotId);
|
|
16581
|
+
const lookupExpr = pIdx !== undefined ? `__p ? __p[${pIdx}] : ${lookup}(${elVar}, '[bf="${slot.slotId}"]')` : `${lookup}(${elVar}, '[bf="${slot.slotId}"]')`;
|
|
16582
|
+
lines.push(`${indent}{ const ${varName} = ${lookupExpr}`);
|
|
16239
16583
|
lines.push(`${indent}if (${varName}) {`);
|
|
16240
16584
|
for (const attr of slot.attrs) {
|
|
16241
16585
|
lines.push(`${indent} createEffect(() => {`);
|
|
@@ -16247,15 +16591,19 @@ function stringifyReactiveEffects(lines, plan, opts) {
|
|
|
16247
16591
|
lines.push(`${indent}} }`);
|
|
16248
16592
|
}
|
|
16249
16593
|
for (const text of plan.outerTexts) {
|
|
16250
|
-
emitOuterText(lines, indent, elVar, text, bindingBfId(text.slotId));
|
|
16594
|
+
emitOuterText(lines, indent, elVar, text, bindingBfId(text.slotId), textIndexBySlot?.get(text.slotId));
|
|
16251
16595
|
}
|
|
16252
16596
|
for (const cond of plan.conditionals) {
|
|
16253
16597
|
emitOuterConditional(lines, indent, elVar, cond, pc);
|
|
16254
16598
|
}
|
|
16255
16599
|
}
|
|
16256
|
-
function emitOuterText(lines, indent, elVar, text, bfId = "") {
|
|
16600
|
+
function emitOuterText(lines, indent, elVar, text, bfId = "", pIdx) {
|
|
16257
16601
|
const varName = `__rt_${varSlotId(text.slotId)}`;
|
|
16258
|
-
|
|
16602
|
+
if (pIdx !== undefined) {
|
|
16603
|
+
lines.push(`${indent}{ const ${varName} = __p ? tAfter(__p[${pIdx}]) : $t(${elVar}, '${text.slotId}')[0]`);
|
|
16604
|
+
} else {
|
|
16605
|
+
lines.push(`${indent}{ const [${varName}] = $t(${elVar}, '${text.slotId}')`);
|
|
16606
|
+
}
|
|
16259
16607
|
lines.push(`${indent}if (${varName}) createEffect(() => { ${varName}.textContent = String(${text.wrappedExpression}) }${bfId}) }`);
|
|
16260
16608
|
}
|
|
16261
16609
|
function emitOuterConditional(lines, indent, elVar, cond, pc) {
|
|
@@ -16287,6 +16635,41 @@ function emitArmText(lines, indent, text, pc) {
|
|
|
16287
16635
|
lines.push(`${indent}if (${varName}) createEffect(() => { ${varName}.textContent = String(${text.wrappedExpression}) }${profileBindingId(pc, text.slotId)}) }`);
|
|
16288
16636
|
}
|
|
16289
16637
|
|
|
16638
|
+
// src/ir-to-client-js/control-flow/stringify/skeleton-paths.ts
|
|
16639
|
+
function pathExpr(base, path) {
|
|
16640
|
+
let expr = base;
|
|
16641
|
+
for (const idx of path) {
|
|
16642
|
+
expr += ".firstChild";
|
|
16643
|
+
if (idx > 0)
|
|
16644
|
+
expr += ".nextSibling".repeat(idx);
|
|
16645
|
+
}
|
|
16646
|
+
return expr;
|
|
16647
|
+
}
|
|
16648
|
+
function buildSkeletonPathPlan(skeletonPaths, elVar, opts) {
|
|
16649
|
+
const arrayElems = [];
|
|
16650
|
+
const elementIndexBySlot = new Map;
|
|
16651
|
+
const textIndexBySlot = new Map;
|
|
16652
|
+
for (const slotId of opts.elementSlotIds) {
|
|
16653
|
+
if (elementIndexBySlot.has(slotId))
|
|
16654
|
+
continue;
|
|
16655
|
+
const path = skeletonPaths.elementPaths.get(slotId);
|
|
16656
|
+
if (!path)
|
|
16657
|
+
continue;
|
|
16658
|
+
elementIndexBySlot.set(slotId, arrayElems.length);
|
|
16659
|
+
arrayElems.push(pathExpr(elVar, path));
|
|
16660
|
+
}
|
|
16661
|
+
for (const slotId of opts.textSlotIds) {
|
|
16662
|
+
if (textIndexBySlot.has(slotId))
|
|
16663
|
+
continue;
|
|
16664
|
+
const path = skeletonPaths.textMarkerPaths.get(slotId);
|
|
16665
|
+
if (!path)
|
|
16666
|
+
continue;
|
|
16667
|
+
textIndexBySlot.set(slotId, arrayElems.length);
|
|
16668
|
+
arrayElems.push(pathExpr(elVar, path));
|
|
16669
|
+
}
|
|
16670
|
+
return { arrayElems, elementIndexBySlot, textIndexBySlot };
|
|
16671
|
+
}
|
|
16672
|
+
|
|
16290
16673
|
// src/ir-to-client-js/control-flow/stringify/component-loop.ts
|
|
16291
16674
|
function stringifyComponentLoop(lines, plan) {
|
|
16292
16675
|
const {
|
|
@@ -16346,11 +16729,13 @@ function emitNestedInit(lines, indent, parentVar, nc) {
|
|
|
16346
16729
|
function emitLoopChildRefs(lines, refs, opts) {
|
|
16347
16730
|
if (refs.length === 0)
|
|
16348
16731
|
return;
|
|
16349
|
-
const { indent, elVar, bodyIsMultiRoot } = opts;
|
|
16732
|
+
const { indent, elVar, bodyIsMultiRoot, elementIndexBySlot } = opts;
|
|
16350
16733
|
const lookup = bodyIsMultiRoot ? "qsaItem" : "qsa";
|
|
16351
16734
|
for (const ref of refs) {
|
|
16352
16735
|
const varName = `__rf_${varSlotId(ref.childSlotId)}`;
|
|
16353
|
-
|
|
16736
|
+
const pIdx = elementIndexBySlot?.get(ref.childSlotId);
|
|
16737
|
+
const lookupExpr = pIdx !== undefined ? `__p ? __p[${pIdx}] : ${lookup}(${elVar}, '[bf="${ref.childSlotId}"]')` : `${lookup}(${elVar}, '[bf="${ref.childSlotId}"]')`;
|
|
16738
|
+
lines.push(`${indent}{ const ${varName} = ${lookupExpr}`);
|
|
16354
16739
|
lines.push(`${indent}if (${varName}) ${emitRefCall(ref.callback, varName)} }`);
|
|
16355
16740
|
}
|
|
16356
16741
|
}
|
|
@@ -16430,10 +16815,31 @@ function stringifyPlainLoop(lines, plan, topIndent = " ") {
|
|
|
16430
16815
|
singleRootLayout: "inline"
|
|
16431
16816
|
});
|
|
16432
16817
|
}
|
|
16818
|
+
let pathPlan = null;
|
|
16819
|
+
if (hoistedTpl && plan.skeletonPaths) {
|
|
16820
|
+
const elementSlotIds = [
|
|
16821
|
+
...reactiveEffects?.attrSlots.map((s) => s.slotId) ?? [],
|
|
16822
|
+
...childRefs.map((r) => r.childSlotId)
|
|
16823
|
+
];
|
|
16824
|
+
const textSlotIds = reactiveEffects?.outerTexts.map((t) => t.slotId) ?? [];
|
|
16825
|
+
if (elementSlotIds.length > 0 || textSlotIds.length > 0) {
|
|
16826
|
+
const built = buildSkeletonPathPlan(plan.skeletonPaths, "__el", { elementSlotIds, textSlotIds });
|
|
16827
|
+
if (built.arrayElems.length > 0) {
|
|
16828
|
+
pathPlan = built;
|
|
16829
|
+
lines.push(`${bodyIndent}const __p = __existing ? null : [${built.arrayElems.join(", ")}]`);
|
|
16830
|
+
}
|
|
16831
|
+
}
|
|
16832
|
+
}
|
|
16433
16833
|
if (reactiveEffects !== null) {
|
|
16434
|
-
stringifyReactiveEffects(lines, reactiveEffects, {
|
|
16834
|
+
stringifyReactiveEffects(lines, reactiveEffects, {
|
|
16835
|
+
indent: bodyIndent,
|
|
16836
|
+
elVar: "__el",
|
|
16837
|
+
bodyIsMultiRoot,
|
|
16838
|
+
elementIndexBySlot: pathPlan?.elementIndexBySlot,
|
|
16839
|
+
textIndexBySlot: pathPlan?.textIndexBySlot
|
|
16840
|
+
});
|
|
16435
16841
|
}
|
|
16436
|
-
emitLoopChildRefs(lines, childRefs, { indent: bodyIndent, elVar: "__el", bodyIsMultiRoot });
|
|
16842
|
+
emitLoopChildRefs(lines, childRefs, { indent: bodyIndent, elVar: "__el", bodyIsMultiRoot, elementIndexBySlot: pathPlan?.elementIndexBySlot });
|
|
16437
16843
|
lines.push(`${bodyIndent}return __el`);
|
|
16438
16844
|
lines.push(`${topIndent}}, '${markerId}'${loopBfId})`);
|
|
16439
16845
|
}
|
|
@@ -16500,12 +16906,14 @@ function stringifyStaticLoop(lines, plan) {
|
|
|
16500
16906
|
lines.push(` let __iterEl = ${containerVar}.children[${childIndexExpr}]`);
|
|
16501
16907
|
if (csrMaterialize) {
|
|
16502
16908
|
lines.push(` if (!__iterEl) {`);
|
|
16909
|
+
const isSvg = csrMaterialize.bodyIsMultiRoot ? multiRootTemplateNeedsSvgWrap(csrMaterialize.itemTemplate) : templateRootIsSvg(csrMaterialize.itemTemplate);
|
|
16910
|
+
const itemHtml = isSvg ? `<svg>${csrMaterialize.itemTemplate}</svg>` : csrMaterialize.itemTemplate;
|
|
16503
16911
|
if (csrMaterialize.bodyIsMultiRoot) {
|
|
16504
16912
|
lines.push(` const __mtpl = document.createElement('template')`);
|
|
16505
|
-
lines.push(` __mtpl.innerHTML = \`${
|
|
16913
|
+
lines.push(` __mtpl.innerHTML = \`${itemHtml}\``);
|
|
16506
16914
|
lines.push(` const __anchor = ${containerVar}.children[${childIndexExpr}] ?? null`);
|
|
16507
16915
|
lines.push(` let __first = null`);
|
|
16508
|
-
lines.push(` let __sib = __mtpl.content.firstElementChild`);
|
|
16916
|
+
lines.push(` let __sib = __mtpl.content${isSvg ? ".firstElementChild" : ""}.firstElementChild`);
|
|
16509
16917
|
lines.push(` while (__sib) {`);
|
|
16510
16918
|
lines.push(` const __next = __sib.nextElementSibling`);
|
|
16511
16919
|
lines.push(` const __cloned = __sib.cloneNode(true)`);
|
|
@@ -16516,8 +16924,8 @@ function stringifyStaticLoop(lines, plan) {
|
|
|
16516
16924
|
lines.push(` __iterEl = __first`);
|
|
16517
16925
|
} else {
|
|
16518
16926
|
lines.push(` const __tpl = document.createElement('template')`);
|
|
16519
|
-
lines.push(` __tpl.innerHTML = \`${
|
|
16520
|
-
lines.push(` const __cloned = __tpl.content.firstElementChild`);
|
|
16927
|
+
lines.push(` __tpl.innerHTML = \`${itemHtml}\``);
|
|
16928
|
+
lines.push(` const __cloned = __tpl.content${isSvg ? ".firstElementChild" : ""}.firstElementChild`);
|
|
16521
16929
|
lines.push(` if (__cloned) {`);
|
|
16522
16930
|
lines.push(` const __anchor = ${containerVar}.children[${childIndexExpr}] ?? null`);
|
|
16523
16931
|
lines.push(` ${containerVar}.insertBefore(__cloned, __anchor)`);
|
|
@@ -16584,7 +16992,10 @@ function emitReactive(lines, inner, indent, pc) {
|
|
|
16584
16992
|
lines.push(`${innerIndent} __innerEl${uid}.__bfExtras = __innerExtras${uid}`);
|
|
16585
16993
|
lines.push(`${indent} }`);
|
|
16586
16994
|
} else {
|
|
16587
|
-
|
|
16995
|
+
const isSvg = templateRootIsSvg(emit.wrappedTemplate);
|
|
16996
|
+
const innerHtml = isSvg ? `<svg>${emit.wrappedTemplate}</svg>` : emit.wrappedTemplate;
|
|
16997
|
+
const childPath = isSvg ? ".firstElementChild.firstElementChild" : ".firstElementChild";
|
|
16998
|
+
lines.push(`${indent} let __innerEl${uid} = __existing ?? (() => { const __t = document.createElement('template'); __t.innerHTML = \`${innerHtml}\`; return __t.content${childPath}.cloneNode(true) })()`);
|
|
16588
16999
|
}
|
|
16589
17000
|
if (emit.wrappedKey) {
|
|
16590
17001
|
lines.push(`${indent} __innerEl${uid}.setAttribute('${keyAttrName(inner.keyDepth)}', String(${emit.wrappedKey}))`);
|
|
@@ -17143,6 +17554,7 @@ function buildPlainLoopPlan(elem, profileComponentName) {
|
|
|
17143
17554
|
mapPreambleWrapped: elem.mapPreamble ? wrap(elem.mapPreamble) : "",
|
|
17144
17555
|
template: elem.template,
|
|
17145
17556
|
skeletonTemplate: elem.skeletonTemplate,
|
|
17557
|
+
skeletonPaths: elem.skeletonPaths,
|
|
17146
17558
|
reactiveEffects: hasReactive2 ? buildLoopReactiveEffectsPlan(elem, profileComponentName) : null,
|
|
17147
17559
|
childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
|
|
17148
17560
|
bodyIsMultiRoot: elem.bodyIsMultiRoot ?? false,
|
|
@@ -20116,6 +20528,8 @@ function isStringTypedOperand(expr, isStringName) {
|
|
|
20116
20528
|
if (expr.kind === "member" && expr.object.kind === "identifier" && expr.object.name === "props") {
|
|
20117
20529
|
return isStringName(expr.property);
|
|
20118
20530
|
}
|
|
20531
|
+
if (expr.kind === "identifier")
|
|
20532
|
+
return isStringName(expr.name);
|
|
20119
20533
|
if (expr.kind === "binary" && expr.op === "+") {
|
|
20120
20534
|
return isStringTypedOperand(expr.left, isStringName) || isStringTypedOperand(expr.right, isStringName);
|
|
20121
20535
|
}
|
|
@@ -20175,6 +20589,221 @@ function emitParsedExpr(expr, emitter) {
|
|
|
20175
20589
|
}
|
|
20176
20590
|
}
|
|
20177
20591
|
}
|
|
20592
|
+
// src/adapters/loop-bound-names.ts
|
|
20593
|
+
function collectLoopBoundNames(ir) {
|
|
20594
|
+
const names = new Set;
|
|
20595
|
+
const visit3 = (node) => {
|
|
20596
|
+
if (!node)
|
|
20597
|
+
return;
|
|
20598
|
+
switch (node.type) {
|
|
20599
|
+
case "element":
|
|
20600
|
+
case "component":
|
|
20601
|
+
case "fragment":
|
|
20602
|
+
case "provider":
|
|
20603
|
+
for (const child of node.children)
|
|
20604
|
+
visit3(child);
|
|
20605
|
+
break;
|
|
20606
|
+
case "async":
|
|
20607
|
+
visit3(node.fallback);
|
|
20608
|
+
for (const child of node.children)
|
|
20609
|
+
visit3(child);
|
|
20610
|
+
break;
|
|
20611
|
+
case "loop":
|
|
20612
|
+
names.add(node.param);
|
|
20613
|
+
if (node.index)
|
|
20614
|
+
names.add(node.index);
|
|
20615
|
+
for (const binding of node.paramBindings ?? [])
|
|
20616
|
+
names.add(binding.name);
|
|
20617
|
+
if (node.filterPredicate)
|
|
20618
|
+
names.add(node.filterPredicate.param);
|
|
20619
|
+
for (const child of node.children)
|
|
20620
|
+
visit3(child);
|
|
20621
|
+
if (node.childComponent) {
|
|
20622
|
+
for (const child of node.childComponent.children)
|
|
20623
|
+
visit3(child);
|
|
20624
|
+
}
|
|
20625
|
+
for (const nested of node.nestedComponents ?? []) {
|
|
20626
|
+
for (const child of nested.children)
|
|
20627
|
+
visit3(child);
|
|
20628
|
+
}
|
|
20629
|
+
for (const frag of node.flatMapCallback?.fragments ?? []) {
|
|
20630
|
+
visit3(frag.ir);
|
|
20631
|
+
}
|
|
20632
|
+
break;
|
|
20633
|
+
case "conditional":
|
|
20634
|
+
visit3(node.whenTrue);
|
|
20635
|
+
visit3(node.whenFalse);
|
|
20636
|
+
break;
|
|
20637
|
+
case "if-statement":
|
|
20638
|
+
visit3(node.consequent);
|
|
20639
|
+
if (node.alternate)
|
|
20640
|
+
visit3(node.alternate);
|
|
20641
|
+
break;
|
|
20642
|
+
case "text":
|
|
20643
|
+
case "expression":
|
|
20644
|
+
case "slot":
|
|
20645
|
+
break;
|
|
20646
|
+
}
|
|
20647
|
+
};
|
|
20648
|
+
visit3(ir.root);
|
|
20649
|
+
return names;
|
|
20650
|
+
}
|
|
20651
|
+
// src/signal-init-eval.ts
|
|
20652
|
+
var BLOCKED_GLOBALS = [
|
|
20653
|
+
"globalThis",
|
|
20654
|
+
"window",
|
|
20655
|
+
"document",
|
|
20656
|
+
"Date",
|
|
20657
|
+
"Math",
|
|
20658
|
+
"crypto",
|
|
20659
|
+
"performance",
|
|
20660
|
+
"fetch",
|
|
20661
|
+
"setTimeout",
|
|
20662
|
+
"setInterval",
|
|
20663
|
+
"require",
|
|
20664
|
+
"process",
|
|
20665
|
+
"Function"
|
|
20666
|
+
];
|
|
20667
|
+
function isTransportable(value, ancestors = new Set) {
|
|
20668
|
+
if (value === null)
|
|
20669
|
+
return true;
|
|
20670
|
+
const t = typeof value;
|
|
20671
|
+
if (t === "boolean" || t === "number" || t === "string")
|
|
20672
|
+
return true;
|
|
20673
|
+
if (t !== "object")
|
|
20674
|
+
return false;
|
|
20675
|
+
if (ancestors.has(value))
|
|
20676
|
+
return false;
|
|
20677
|
+
ancestors.add(value);
|
|
20678
|
+
try {
|
|
20679
|
+
if (Array.isArray(value)) {
|
|
20680
|
+
if (Object.keys(value).length !== value.length)
|
|
20681
|
+
return false;
|
|
20682
|
+
return value.every((el) => el !== undefined && isTransportable(el, ancestors));
|
|
20683
|
+
}
|
|
20684
|
+
const proto = Object.getPrototypeOf(value);
|
|
20685
|
+
if (proto !== Object.prototype && proto !== null)
|
|
20686
|
+
return false;
|
|
20687
|
+
return Object.values(value).every((v) => isTransportable(v, ancestors));
|
|
20688
|
+
} finally {
|
|
20689
|
+
ancestors.delete(value);
|
|
20690
|
+
}
|
|
20691
|
+
}
|
|
20692
|
+
function tryEvaluateSignalInit(expr, props) {
|
|
20693
|
+
const src = expr.trim();
|
|
20694
|
+
if (src === "")
|
|
20695
|
+
return { ok: false };
|
|
20696
|
+
let fn;
|
|
20697
|
+
try {
|
|
20698
|
+
fn = new Function("props", ...BLOCKED_GLOBALS, `'use strict'; return (
|
|
20699
|
+
${src}
|
|
20700
|
+
);`);
|
|
20701
|
+
} catch {
|
|
20702
|
+
return { ok: false };
|
|
20703
|
+
}
|
|
20704
|
+
try {
|
|
20705
|
+
const value = fn(props ?? {});
|
|
20706
|
+
if (value === undefined)
|
|
20707
|
+
return { ok: true, value: undefined };
|
|
20708
|
+
return isTransportable(value) ? { ok: true, value } : { ok: false };
|
|
20709
|
+
} catch {
|
|
20710
|
+
return { ok: false };
|
|
20711
|
+
}
|
|
20712
|
+
}
|
|
20713
|
+
function evaluateSignalInit(expr, props) {
|
|
20714
|
+
const result = tryEvaluateSignalInit(expr, props);
|
|
20715
|
+
return result.ok && result.value !== undefined ? result.value : null;
|
|
20716
|
+
}
|
|
20717
|
+
// src/static-literal.ts
|
|
20718
|
+
function evaluateStaticLiteral(expr, bindings) {
|
|
20719
|
+
switch (expr.kind) {
|
|
20720
|
+
case "literal":
|
|
20721
|
+
return { value: expr.value };
|
|
20722
|
+
case "template-literal": {
|
|
20723
|
+
let out = "";
|
|
20724
|
+
for (const part of expr.parts) {
|
|
20725
|
+
if (part.type === "string") {
|
|
20726
|
+
out += part.value;
|
|
20727
|
+
continue;
|
|
20728
|
+
}
|
|
20729
|
+
const resolved = evaluateStaticLiteral(part.expr, bindings);
|
|
20730
|
+
if (!resolved)
|
|
20731
|
+
return null;
|
|
20732
|
+
out += String(resolved.value);
|
|
20733
|
+
}
|
|
20734
|
+
return { value: out };
|
|
20735
|
+
}
|
|
20736
|
+
case "array-literal": {
|
|
20737
|
+
const values = [];
|
|
20738
|
+
for (const element of expr.elements) {
|
|
20739
|
+
const resolved = evaluateStaticLiteral(element, bindings);
|
|
20740
|
+
if (!resolved)
|
|
20741
|
+
return null;
|
|
20742
|
+
values.push(resolved.value);
|
|
20743
|
+
}
|
|
20744
|
+
return { value: values };
|
|
20745
|
+
}
|
|
20746
|
+
case "object-literal": {
|
|
20747
|
+
const out = {};
|
|
20748
|
+
for (const prop of expr.properties) {
|
|
20749
|
+
const resolved = evaluateStaticLiteral(prop.value, bindings);
|
|
20750
|
+
if (!resolved)
|
|
20751
|
+
return null;
|
|
20752
|
+
out[prop.key] = resolved.value;
|
|
20753
|
+
}
|
|
20754
|
+
return { value: out };
|
|
20755
|
+
}
|
|
20756
|
+
case "unary": {
|
|
20757
|
+
const resolved = evaluateStaticLiteral(expr.argument, bindings);
|
|
20758
|
+
if (!resolved)
|
|
20759
|
+
return null;
|
|
20760
|
+
if (expr.op === "-")
|
|
20761
|
+
return typeof resolved.value === "number" ? { value: -resolved.value } : null;
|
|
20762
|
+
if (expr.op === "+")
|
|
20763
|
+
return typeof resolved.value === "number" ? { value: +resolved.value } : null;
|
|
20764
|
+
if (expr.op === "!")
|
|
20765
|
+
return { value: !resolved.value };
|
|
20766
|
+
return null;
|
|
20767
|
+
}
|
|
20768
|
+
case "identifier":
|
|
20769
|
+
return bindings?.has(expr.name) ? { value: bindings.get(expr.name) } : null;
|
|
20770
|
+
case "member": {
|
|
20771
|
+
const base = evaluateStaticLiteral(expr.object, bindings);
|
|
20772
|
+
if (!base || base.value === null || typeof base.value !== "object")
|
|
20773
|
+
return null;
|
|
20774
|
+
return { value: base.value[expr.property] };
|
|
20775
|
+
}
|
|
20776
|
+
case "index-access": {
|
|
20777
|
+
const base = evaluateStaticLiteral(expr.object, bindings);
|
|
20778
|
+
const index = evaluateStaticLiteral(expr.index, bindings);
|
|
20779
|
+
if (!base || !index || !Array.isArray(base.value) || typeof index.value !== "number")
|
|
20780
|
+
return null;
|
|
20781
|
+
return { value: base.value[index.value] };
|
|
20782
|
+
}
|
|
20783
|
+
default:
|
|
20784
|
+
return null;
|
|
20785
|
+
}
|
|
20786
|
+
}
|
|
20787
|
+
function isFullyStaticLiteral(expr) {
|
|
20788
|
+
return evaluateStaticLiteral(expr) !== null;
|
|
20789
|
+
}
|
|
20790
|
+
function resolveStaticLoopSource(arrayParsed, localConstants, opts) {
|
|
20791
|
+
if (!arrayParsed)
|
|
20792
|
+
return null;
|
|
20793
|
+
let target = arrayParsed;
|
|
20794
|
+
if (arrayParsed.kind === "identifier") {
|
|
20795
|
+
if (opts?.isNameShadowed?.(arrayParsed.name))
|
|
20796
|
+
return null;
|
|
20797
|
+
const local = localConstants?.find((c) => c.name === arrayParsed.name);
|
|
20798
|
+
if (!local || local.isModule || !local.parsed)
|
|
20799
|
+
return null;
|
|
20800
|
+
target = local.parsed;
|
|
20801
|
+
}
|
|
20802
|
+
const resolved = evaluateStaticLiteral(target);
|
|
20803
|
+
if (!resolved || !Array.isArray(resolved.value))
|
|
20804
|
+
return null;
|
|
20805
|
+
return resolved.value;
|
|
20806
|
+
}
|
|
20178
20807
|
// src/query-href-lowering.ts
|
|
20179
20808
|
function matchQueryHrefCall(callee, args, localNames) {
|
|
20180
20809
|
if (callee.kind !== "identifier" || !localNames.has(callee.name))
|
|
@@ -20310,6 +20939,71 @@ function emitAttrValue(value, emitter, name) {
|
|
|
20310
20939
|
}
|
|
20311
20940
|
}
|
|
20312
20941
|
}
|
|
20942
|
+
// src/adapters/dangerous-inner-html.ts
|
|
20943
|
+
var DANGEROUS_INNER_HTML_ATTR = "dangerouslySetInnerHTML";
|
|
20944
|
+
function isDangerousInnerHtmlAttr(attr) {
|
|
20945
|
+
return attr.name === DANGEROUS_INNER_HTML_ATTR;
|
|
20946
|
+
}
|
|
20947
|
+
function resolveDangerousInnerHtml(element) {
|
|
20948
|
+
const attr = element.attrs.find(isDangerousInnerHtmlAttr);
|
|
20949
|
+
if (!attr)
|
|
20950
|
+
return null;
|
|
20951
|
+
if (attr.clientOnly)
|
|
20952
|
+
return null;
|
|
20953
|
+
if (attr.value.kind !== "expression") {
|
|
20954
|
+
return { kind: "dynamic", expr: "", loc: attr.loc };
|
|
20955
|
+
}
|
|
20956
|
+
const parsed = attr.value.parsed ?? parseExpression(attr.value.expr.trim());
|
|
20957
|
+
const html = staticHtmlLiteral(parsed);
|
|
20958
|
+
if (html !== null)
|
|
20959
|
+
return { kind: "static", html };
|
|
20960
|
+
return { kind: "dynamic", expr: attr.value.expr, loc: attr.loc };
|
|
20961
|
+
}
|
|
20962
|
+
function staticHtmlLiteral(parsed) {
|
|
20963
|
+
if (parsed.kind !== "object-literal")
|
|
20964
|
+
return null;
|
|
20965
|
+
if (parsed.properties.length !== 1)
|
|
20966
|
+
return null;
|
|
20967
|
+
const [prop] = parsed.properties;
|
|
20968
|
+
if (prop.shorthand)
|
|
20969
|
+
return null;
|
|
20970
|
+
if (prop.key !== "__html")
|
|
20971
|
+
return null;
|
|
20972
|
+
if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
|
|
20973
|
+
return null;
|
|
20974
|
+
return prop.value.value;
|
|
20975
|
+
}
|
|
20976
|
+
var TEMPLATE_METACHAR_PATTERNS = {
|
|
20977
|
+
blade: /\{\{|\{!!|<\?|@\w|<\/?\s*x[-:]/,
|
|
20978
|
+
erb: /<%/,
|
|
20979
|
+
"go-template": /\{\{/,
|
|
20980
|
+
jinja: /\{\{|\{%|\{#/,
|
|
20981
|
+
minijinja: /\{\{|\{%|\{#/,
|
|
20982
|
+
mojolicious: /<%|^\s*%/m,
|
|
20983
|
+
twig: /\{\{|\{%|\{#/,
|
|
20984
|
+
xslate: /<:|^\s*:/m
|
|
20985
|
+
};
|
|
20986
|
+
function dangerousInnerHtmlMetacharViolation(html, adapterId) {
|
|
20987
|
+
const pattern = TEMPLATE_METACHAR_PATTERNS[adapterId];
|
|
20988
|
+
if (!pattern) {
|
|
20989
|
+
return `no template-metacharacter guard is defined for adapter '${adapterId}' — refusing rather than splicing unguarded`;
|
|
20990
|
+
}
|
|
20991
|
+
if (!pattern.test(html))
|
|
20992
|
+
return null;
|
|
20993
|
+
return `the literal HTML contains a sequence ${adapterId}'s own template compiler would interpret (not inert text once spliced into the template)`;
|
|
20994
|
+
}
|
|
20995
|
+
function dangerousInnerHtmlDiagnostic(expr, loc, reason) {
|
|
20996
|
+
const detail = reason ? ` — ${reason}.` : "";
|
|
20997
|
+
return {
|
|
20998
|
+
code: "BF101",
|
|
20999
|
+
severity: "error",
|
|
21000
|
+
message: `dangerouslySetInnerHTML requires a compile-time string literal __html value on template adapters (e.g. { __html: '...' })${expr ? `: ${expr.trim()}` : ""}${detail}`,
|
|
21001
|
+
loc,
|
|
21002
|
+
suggestion: {
|
|
21003
|
+
message: "Dynamic or signal-derived HTML for dangerouslySetInnerHTML is only supported on Hono/CSR today (tracked separately: https://github.com/piconic-ai/barefootjs/issues/2215). Use an inline string literal, or defer it to the client with /* @client */ (e.g. dangerouslySetInnerHTML={/* @client */ { __html: expr }}) so hydration sets it instead of SSR."
|
|
21004
|
+
}
|
|
21005
|
+
};
|
|
21006
|
+
}
|
|
20313
21007
|
// src/combine-client-js.ts
|
|
20314
21008
|
import ts19 from "typescript";
|
|
20315
21009
|
var CHILD_PLACEHOLDER_RE = /import '\/\* @bf-child:(\w+) \*\/'/g;
|
|
@@ -23151,6 +23845,7 @@ function profileToJSON(profile) {
|
|
|
23151
23845
|
registerBuiltinLoweringPlugins();
|
|
23152
23846
|
export {
|
|
23153
23847
|
tsNodeToParsedExpr,
|
|
23848
|
+
tryEvaluateSignalInit,
|
|
23154
23849
|
traceUpdatePath,
|
|
23155
23850
|
testAdapter,
|
|
23156
23851
|
stringifyParsedExpr,
|
|
@@ -23158,7 +23853,9 @@ export {
|
|
|
23158
23853
|
serializeParsedExpr,
|
|
23159
23854
|
searchParamsLocalNames,
|
|
23160
23855
|
rewriteImportsForTemplate,
|
|
23856
|
+
resolveStaticLoopSource,
|
|
23161
23857
|
resolveSetters,
|
|
23858
|
+
resolveDangerousInnerHtml,
|
|
23162
23859
|
resetCompilerCounters,
|
|
23163
23860
|
renderImportMapHtml,
|
|
23164
23861
|
registerLoweringPlugin,
|
|
@@ -23193,6 +23890,8 @@ export {
|
|
|
23193
23890
|
isStringConcatBinary,
|
|
23194
23891
|
isLowerableObjectRestDestructure,
|
|
23195
23892
|
isLowerableLoopDestructure,
|
|
23893
|
+
isFullyStaticLiteral,
|
|
23894
|
+
isDangerousInnerHtmlAttr,
|
|
23196
23895
|
isBooleanAttr,
|
|
23197
23896
|
importsSearchParams,
|
|
23198
23897
|
identifierPath,
|
|
@@ -23233,6 +23932,8 @@ export {
|
|
|
23233
23932
|
extractFunctionParams,
|
|
23234
23933
|
extractArrowBodyExpression,
|
|
23235
23934
|
exprToString,
|
|
23935
|
+
evaluateStaticLiteral,
|
|
23936
|
+
evaluateSignalInit,
|
|
23236
23937
|
evaluateProfileGates,
|
|
23237
23938
|
evalStringArrayJoin,
|
|
23238
23939
|
envSignalReaderFor,
|
|
@@ -23245,6 +23946,8 @@ export {
|
|
|
23245
23946
|
diffStaticBudget,
|
|
23246
23947
|
diffProfiles,
|
|
23247
23948
|
describeFallback,
|
|
23949
|
+
dangerousInnerHtmlMetacharViolation,
|
|
23950
|
+
dangerousInnerHtmlDiagnostic,
|
|
23248
23951
|
createProgramForFile,
|
|
23249
23952
|
createProgramForCorpus,
|
|
23250
23953
|
createError,
|
|
@@ -23253,6 +23956,7 @@ export {
|
|
|
23253
23956
|
compileJSX,
|
|
23254
23957
|
combineParentChildClientJs,
|
|
23255
23958
|
collectModuleStringConsts,
|
|
23959
|
+
collectLoopBoundNames,
|
|
23256
23960
|
collectContextConsumers,
|
|
23257
23961
|
buildWhyUpdate,
|
|
23258
23962
|
buildStaticBudget,
|