@barefootjs/jsx 0.26.4 → 0.28.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/compiler.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +941 -130
- package/dist/ir-to-client-js/client-only-elision.d.ts +103 -0
- package/dist/ir-to-client-js/client-only-elision.d.ts.map +1 -0
- package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts +6 -0
- package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts +2 -1
- package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts +7 -0
- package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts +107 -0
- package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts +9 -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/lazy-row-eligibility.d.ts +203 -0
- package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/plan/loop.d.ts +10 -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 +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/branch-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/claim-plan.d.ts +54 -0
- package/dist/ir-to-client-js/control-flow/stringify/claim-plan.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/stringify/inner-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/insert.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts +98 -0
- package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -0
- package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts +5 -0
- 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 +17 -20
- 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 +63 -4
- package/dist/ir-to-client-js/control-flow/stringify/reactive-effects.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow.d.ts +1 -1
- package/dist/ir-to-client-js/control-flow.d.ts.map +1 -1
- package/dist/ir-to-client-js/element-refs.d.ts +8 -3
- package/dist/ir-to-client-js/element-refs.d.ts.map +1 -1
- package/dist/ir-to-client-js/emit-reactive.d.ts +8 -1
- package/dist/ir-to-client-js/emit-reactive.d.ts.map +1 -1
- package/dist/ir-to-client-js/html-template.d.ts +24 -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/reactivity.d.ts.map +1 -1
- package/dist/ir-to-client-js/types.d.ts +9 -1
- package/dist/ir-to-client-js/types.d.ts.map +1 -1
- package/dist/ir-to-client-js/utils.d.ts +1 -1
- package/dist/types.d.ts +25 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +542 -689
- package/src/__tests__/child-components-in-map.test.ts +4 -4
- package/src/__tests__/client-js-generation.test.ts +23 -12
- package/src/__tests__/composite-branch-loop.test.ts +14 -5
- package/src/__tests__/conditional-mapArray-key.test.ts +7 -1
- package/src/__tests__/create-selector.test.ts +21 -7
- package/src/__tests__/cross-file-client-signal.test.ts +5 -1
- package/src/__tests__/early-return-scope-var-ref.test.ts +10 -11
- package/src/__tests__/inline-jsx-callback.test.ts +6 -4
- package/src/__tests__/ir-jsx-props.test.ts +6 -5
- package/src/__tests__/lazy-row-eligibility.test.ts +692 -0
- package/src/__tests__/loop-branch-bare-expression-reactive-text.test.ts +98 -0
- package/src/__tests__/loop-fallback-wrap.test.ts +34 -16
- package/src/__tests__/loop-hoisted-template.test.ts +10 -6
- package/src/__tests__/module-level-signal.audit.test.ts +7 -2
- package/src/__tests__/nested-loop-conditional.test.ts +9 -7
- package/src/__tests__/nested-loop-reactive-attrs.test.ts +2 -2
- package/src/__tests__/preamble-region-patch.test.ts +18 -12
- package/src/__tests__/profile-cond-binding-ids.test.ts +3 -2
- package/src/__tests__/profile-loop-binding-ids.test.ts +4 -3
- package/src/__tests__/profile-nested-binding-ids.test.ts +11 -6
- package/src/__tests__/reactive-attrs-in-map.test.ts +6 -4
- package/src/__tests__/static-loop-csr-materialize.test.ts +6 -1
- package/src/__tests__/template-closure.test.ts +1 -1
- package/src/compiler.ts +11 -0
- package/src/index.ts +1 -0
- package/src/ir-to-client-js/client-only-elision.ts +273 -0
- package/src/ir-to-client-js/collect-elements.ts +56 -17
- package/src/ir-to-client-js/control-flow/plan/branch-loop.ts +6 -0
- package/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts +35 -12
- package/src/ir-to-client-js/control-flow/plan/build-insert.ts +9 -2
- package/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts +305 -0
- package/src/ir-to-client-js/control-flow/plan/build-loop.ts +44 -12
- package/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts +440 -0
- package/src/ir-to-client-js/control-flow/plan/loop.ts +10 -0
- package/src/ir-to-client-js/control-flow/shared.ts +1 -1
- package/src/ir-to-client-js/control-flow/stringify/branch-loop.ts +34 -4
- package/src/ir-to-client-js/control-flow/stringify/claim-plan.ts +68 -0
- package/src/ir-to-client-js/control-flow/stringify/inner-loop.ts +18 -9
- package/src/ir-to-client-js/control-flow/stringify/insert.ts +17 -11
- package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +478 -0
- package/src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts +41 -17
- package/src/ir-to-client-js/control-flow/stringify/loop.ts +71 -46
- package/src/ir-to-client-js/control-flow/stringify/reactive-effects.ts +241 -31
- package/src/ir-to-client-js/control-flow.ts +8 -3
- package/src/ir-to-client-js/element-refs.ts +9 -11
- package/src/ir-to-client-js/emit-reactive.ts +50 -14
- package/src/ir-to-client-js/html-template.ts +29 -9
- package/src/ir-to-client-js/imports.ts +13 -4
- package/src/ir-to-client-js/reactivity.ts +3 -2
- package/src/ir-to-client-js/types.ts +10 -2
- package/src/ir-to-client-js/utils.ts +1 -1
- package/src/jsx-to-ir.ts +26 -8
- package/src/types.ts +25 -2
package/dist/index.js
CHANGED
|
@@ -3505,6 +3505,10 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
|
|
|
3505
3505
|
case "expression": {
|
|
3506
3506
|
if (node.expr === "null" || node.expr === "undefined")
|
|
3507
3507
|
return "";
|
|
3508
|
+
if (node.markerless) {
|
|
3509
|
+
const bare = wrapInterpolation(wrapExpr(node.expr));
|
|
3510
|
+
return `\${${bare}}`;
|
|
3511
|
+
}
|
|
3508
3512
|
const inner = wrapInterpolation(wrapExpr(node.expr));
|
|
3509
3513
|
const valueExpr = node.joinArrayChild ? `Array.isArray(${inner}) ? ${inner}.join('') : (${inner} ?? '')` : inner;
|
|
3510
3514
|
if (node.slotId) {
|
|
@@ -4380,7 +4384,7 @@ function generateCsrTemplateWithOpts(node, opts) {
|
|
|
4380
4384
|
if (node.expr === "null" || node.expr === "undefined")
|
|
4381
4385
|
return "";
|
|
4382
4386
|
if (node.clientOnly && node.slotId) {
|
|
4383
|
-
return `<!--bf
|
|
4387
|
+
return `<!--bf:${node.slotId}--><!--/-->`;
|
|
4384
4388
|
}
|
|
4385
4389
|
{
|
|
4386
4390
|
const transformed = transformExpr(node.expr, node.templateExpr);
|
|
@@ -11233,7 +11237,8 @@ function transformConditionalBranch(node, ctx) {
|
|
|
11233
11237
|
const callsReactive = exprCallsReactiveGetters(node, ctx);
|
|
11234
11238
|
const hasCalls = exprHasFunctionCalls(node);
|
|
11235
11239
|
const reactive = isReactiveExpression(exprText, ctx, node) || isReactiveOrigin(branchOrigin);
|
|
11236
|
-
const
|
|
11240
|
+
const refsLoopParam = branchOrigin.freeRefs?.some((r) => r.kind === "render-item") ?? false;
|
|
11241
|
+
const needsSlot = reactive || callsReactive || refsLoopParam;
|
|
11237
11242
|
const slotId = needsSlot ? generateSlotId(ctx) : null;
|
|
11238
11243
|
return {
|
|
11239
11244
|
type: "expression",
|
|
@@ -14402,7 +14407,11 @@ function collectElements(node, ctx, siblingOffsets, insideConditional = false) {
|
|
|
14402
14407
|
},
|
|
14403
14408
|
expression: ({ node: ex, scope: inCond }) => {
|
|
14404
14409
|
if (ex.clientOnly && ex.slotId) {
|
|
14405
|
-
ctx.clientOnlyElements.push({
|
|
14410
|
+
ctx.clientOnlyElements.push({
|
|
14411
|
+
slotId: ex.slotId,
|
|
14412
|
+
expression: ex.expr,
|
|
14413
|
+
elidedPath: ex.markerless ? ex.elidedPath : undefined
|
|
14414
|
+
});
|
|
14406
14415
|
return;
|
|
14407
14416
|
}
|
|
14408
14417
|
if (!ex.slotId || inCond)
|
|
@@ -14824,7 +14833,7 @@ function summarizeLoopChildBranch(node, ctx, siblingOffsets, loopParam, loopPara
|
|
|
14824
14833
|
conditionals: collectLoopChildConditionals(node, ctx, siblingOffsets, loopParam, loopParamBindings),
|
|
14825
14834
|
events: collectConditionalBranchEvents(node),
|
|
14826
14835
|
reactiveAttrs: collectLoopChildReactiveAttrs(node, ctx, loopParam, loopParamBindings, true),
|
|
14827
|
-
reactiveTexts: node.type === "expression" ? [] : collectLoopChildReactiveTexts(node, ctx, loopParam, loopParamBindings, true)
|
|
14836
|
+
reactiveTexts: node.type === "expression" && node.hasFunctionCalls ? [] : collectLoopChildReactiveTexts(node, ctx, loopParam, loopParamBindings, true)
|
|
14828
14837
|
};
|
|
14829
14838
|
}
|
|
14830
14839
|
|
|
@@ -15279,13 +15288,12 @@ var RUNTIME_IMPORT_CANDIDATES = [
|
|
|
15279
15288
|
"onMount",
|
|
15280
15289
|
"hydrate",
|
|
15281
15290
|
"insert",
|
|
15282
|
-
"reconcileElements",
|
|
15283
15291
|
"getLoopChildren",
|
|
15284
15292
|
"getLoopNodes",
|
|
15285
15293
|
"mapArray",
|
|
15286
15294
|
"mapArrayAnchored",
|
|
15295
|
+
"mapArrayLazy",
|
|
15287
15296
|
"patchLeaf",
|
|
15288
|
-
"patchSlotRange",
|
|
15289
15297
|
"createDisposableEffect",
|
|
15290
15298
|
"createComponent",
|
|
15291
15299
|
"renderChild",
|
|
@@ -15293,7 +15301,6 @@ var RUNTIME_IMPORT_CANDIDATES = [
|
|
|
15293
15301
|
"registerTemplate",
|
|
15294
15302
|
"initChild",
|
|
15295
15303
|
"upsertChild",
|
|
15296
|
-
"updateClientMarker",
|
|
15297
15304
|
"createPortal",
|
|
15298
15305
|
"provideContext",
|
|
15299
15306
|
"createContext",
|
|
@@ -15305,6 +15312,7 @@ var RUNTIME_IMPORT_CANDIDATES = [
|
|
|
15305
15312
|
"styleToCss",
|
|
15306
15313
|
"escapeAttr",
|
|
15307
15314
|
"escapeText",
|
|
15315
|
+
"escapeTextOrNode",
|
|
15308
15316
|
"qsa",
|
|
15309
15317
|
"qsaItem",
|
|
15310
15318
|
"qsaChildScope",
|
|
@@ -15313,7 +15321,10 @@ var RUNTIME_IMPORT_CANDIDATES = [
|
|
|
15313
15321
|
"__slot",
|
|
15314
15322
|
"__bfSlot",
|
|
15315
15323
|
"__bfText",
|
|
15316
|
-
"
|
|
15324
|
+
"claimSlots",
|
|
15325
|
+
"lazySlots",
|
|
15326
|
+
"lazyClaimSlots",
|
|
15327
|
+
"textOrNode",
|
|
15317
15328
|
"beginTurn",
|
|
15318
15329
|
"endTurn",
|
|
15319
15330
|
"date",
|
|
@@ -18382,8 +18393,352 @@ function buildKeyedOrIndexLookup(args) {
|
|
|
18382
18393
|
};
|
|
18383
18394
|
}
|
|
18384
18395
|
|
|
18396
|
+
// src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts
|
|
18397
|
+
var PURE_SOURCE_GLOBALS = new Set([
|
|
18398
|
+
"Object",
|
|
18399
|
+
"Array",
|
|
18400
|
+
"JSON",
|
|
18401
|
+
"Number",
|
|
18402
|
+
"String",
|
|
18403
|
+
"Boolean"
|
|
18404
|
+
]);
|
|
18405
|
+
var INERT_BINDING_GLOBALS = new Set([
|
|
18406
|
+
"Object",
|
|
18407
|
+
"Array",
|
|
18408
|
+
"JSON",
|
|
18409
|
+
"Number",
|
|
18410
|
+
"String",
|
|
18411
|
+
"Boolean",
|
|
18412
|
+
"Math",
|
|
18413
|
+
"Date",
|
|
18414
|
+
"Intl",
|
|
18415
|
+
"Symbol",
|
|
18416
|
+
"Map",
|
|
18417
|
+
"Set",
|
|
18418
|
+
"WeakMap",
|
|
18419
|
+
"WeakSet",
|
|
18420
|
+
"Promise",
|
|
18421
|
+
"RegExp",
|
|
18422
|
+
"Error",
|
|
18423
|
+
"BigInt",
|
|
18424
|
+
"console",
|
|
18425
|
+
"undefined",
|
|
18426
|
+
"NaN",
|
|
18427
|
+
"Infinity",
|
|
18428
|
+
"globalThis",
|
|
18429
|
+
"parseInt",
|
|
18430
|
+
"parseFloat",
|
|
18431
|
+
"isNaN",
|
|
18432
|
+
"isFinite",
|
|
18433
|
+
"encodeURIComponent",
|
|
18434
|
+
"decodeURIComponent",
|
|
18435
|
+
"encodeURI",
|
|
18436
|
+
"decodeURI"
|
|
18437
|
+
]);
|
|
18438
|
+
var UNKNOWN_IDENTIFIERS = "<unknown>";
|
|
18439
|
+
var NO = (reason) => ({ eligible: false, reason });
|
|
18440
|
+
function lazyRowEligibility(args) {
|
|
18441
|
+
const { shape, bindings, arraySourceIdentifiers, scope } = args;
|
|
18442
|
+
if (scope.profile)
|
|
18443
|
+
return NO("profile mode keeps the granular eager emission");
|
|
18444
|
+
if (shape.callSite !== "plain" && shape.callSite !== "branch-plain") {
|
|
18445
|
+
return NO(`call site '${shape.callSite}' is not a plain loop row`);
|
|
18446
|
+
}
|
|
18447
|
+
if (shape.flatMapLeafItem)
|
|
18448
|
+
return NO("flatMap descriptor loop (build-or-patch renderItem)");
|
|
18449
|
+
if (shape.anchored)
|
|
18450
|
+
return NO("anchored whole-item-conditional loop");
|
|
18451
|
+
if (shape.bodyIsMultiRoot)
|
|
18452
|
+
return NO("multi-root (Fragment) row");
|
|
18453
|
+
if (!shape.hasExplicitKey)
|
|
18454
|
+
return NO("index-keyed loop (no explicit key)");
|
|
18455
|
+
if (shape.conditionalCount > 0)
|
|
18456
|
+
return NO("row contains a reactive conditional");
|
|
18457
|
+
if (shape.childRefCount > 0)
|
|
18458
|
+
return NO("row has imperative child refs");
|
|
18459
|
+
if (shape.hasChildComponent)
|
|
18460
|
+
return NO("row body is a child component");
|
|
18461
|
+
if (shape.nestedComponentCount > 0)
|
|
18462
|
+
return NO("row contains nested child components");
|
|
18463
|
+
if (shape.innerLoopCount > 0)
|
|
18464
|
+
return NO("row contains an inner loop");
|
|
18465
|
+
if (shape.hasMapPreamble)
|
|
18466
|
+
return NO("row has a map-callback preamble (may declare row-local reactivity)");
|
|
18467
|
+
if (shape.preambleRegionCount > 0)
|
|
18468
|
+
return NO("row has preamble-patched regions");
|
|
18469
|
+
if (shape.hasParamUnwrap)
|
|
18470
|
+
return NO("destructured loop param without param bindings");
|
|
18471
|
+
for (const b of bindings) {
|
|
18472
|
+
if (b.referencesIndex) {
|
|
18473
|
+
return NO(`binding on slot ${b.slotId} references the loop index parameter`);
|
|
18474
|
+
}
|
|
18475
|
+
if (b.opaqueOuterNames.includes(UNKNOWN_IDENTIFIERS)) {
|
|
18476
|
+
return NO(`binding on slot ${b.slotId} has no analyzable identifier set`);
|
|
18477
|
+
}
|
|
18478
|
+
}
|
|
18479
|
+
if (!arraySourceIdentifiers)
|
|
18480
|
+
return NO("loop source free identifiers unavailable");
|
|
18481
|
+
const sourceGate = checkSourceConsistency(arraySourceIdentifiers, scope);
|
|
18482
|
+
if (sourceGate)
|
|
18483
|
+
return NO(`loop source is not provably hydration-consistent: ${sourceGate}`);
|
|
18484
|
+
return { eligible: true };
|
|
18485
|
+
}
|
|
18486
|
+
function checkSourceConsistency(names, scope) {
|
|
18487
|
+
const seen = new Set;
|
|
18488
|
+
const resolve2 = (name) => {
|
|
18489
|
+
if (seen.has(name))
|
|
18490
|
+
return null;
|
|
18491
|
+
seen.add(name);
|
|
18492
|
+
if (scope.props.has(name))
|
|
18493
|
+
return null;
|
|
18494
|
+
if (PURE_SOURCE_GLOBALS.has(name))
|
|
18495
|
+
return null;
|
|
18496
|
+
const constFree = scope.constants.get(name);
|
|
18497
|
+
if (constFree !== undefined) {
|
|
18498
|
+
if (constFree === null)
|
|
18499
|
+
return `constant '${name}' has no analyzable value`;
|
|
18500
|
+
for (const inner of constFree) {
|
|
18501
|
+
const failure = resolve2(inner);
|
|
18502
|
+
if (failure)
|
|
18503
|
+
return failure;
|
|
18504
|
+
}
|
|
18505
|
+
return null;
|
|
18506
|
+
}
|
|
18507
|
+
const signal = scope.signals.get(name);
|
|
18508
|
+
if (signal !== undefined) {
|
|
18509
|
+
if (signal.initializerFreeIdentifiers === null) {
|
|
18510
|
+
return `signal '${name}' has no structured initializer to prove props/literal derivation`;
|
|
18511
|
+
}
|
|
18512
|
+
for (const inner of signal.initializerFreeIdentifiers) {
|
|
18513
|
+
const failure = resolve2(inner);
|
|
18514
|
+
if (failure)
|
|
18515
|
+
return failure;
|
|
18516
|
+
}
|
|
18517
|
+
return null;
|
|
18518
|
+
}
|
|
18519
|
+
if (scope.memos.has(name))
|
|
18520
|
+
return `memo '${name}' initializer is not analyzed by the v1 gate`;
|
|
18521
|
+
if (scope.inert.has(name))
|
|
18522
|
+
return `'${name}' is an import or local function`;
|
|
18523
|
+
return `'${name}' does not resolve to a prop, literal-derived const, or props/literal-derived signal`;
|
|
18524
|
+
};
|
|
18525
|
+
for (const name of names) {
|
|
18526
|
+
const failure = resolve2(name);
|
|
18527
|
+
if (failure)
|
|
18528
|
+
return failure;
|
|
18529
|
+
}
|
|
18530
|
+
return null;
|
|
18531
|
+
}
|
|
18532
|
+
function classifyLazyBinding(args) {
|
|
18533
|
+
const { kind, slotId, free, rowLocalNames, indexParam, scope } = args;
|
|
18534
|
+
if (free === null) {
|
|
18535
|
+
return {
|
|
18536
|
+
kind,
|
|
18537
|
+
slotId,
|
|
18538
|
+
readsItem: true,
|
|
18539
|
+
readsOuter: true,
|
|
18540
|
+
reactiveOuterNames: [],
|
|
18541
|
+
opaqueOuterNames: [UNKNOWN_IDENTIFIERS],
|
|
18542
|
+
referencesIndex: false
|
|
18543
|
+
};
|
|
18544
|
+
}
|
|
18545
|
+
let readsItem = false;
|
|
18546
|
+
let referencesIndex = false;
|
|
18547
|
+
const reactiveOuterNames = [];
|
|
18548
|
+
const opaqueOuterNames = [];
|
|
18549
|
+
for (const name of free) {
|
|
18550
|
+
if (rowLocalNames.has(name)) {
|
|
18551
|
+
readsItem = true;
|
|
18552
|
+
continue;
|
|
18553
|
+
}
|
|
18554
|
+
if (name === indexParam) {
|
|
18555
|
+
referencesIndex = true;
|
|
18556
|
+
continue;
|
|
18557
|
+
}
|
|
18558
|
+
if (INERT_BINDING_GLOBALS.has(name))
|
|
18559
|
+
continue;
|
|
18560
|
+
if (scope.signals.has(name) || scope.memos.has(name)) {
|
|
18561
|
+
if (!reactiveOuterNames.includes(name))
|
|
18562
|
+
reactiveOuterNames.push(name);
|
|
18563
|
+
continue;
|
|
18564
|
+
}
|
|
18565
|
+
const constFree = scope.constants.get(name);
|
|
18566
|
+
if (constFree !== undefined && constFree !== null && constFree.size === 0)
|
|
18567
|
+
continue;
|
|
18568
|
+
opaqueOuterNames.push(name);
|
|
18569
|
+
}
|
|
18570
|
+
return {
|
|
18571
|
+
kind,
|
|
18572
|
+
slotId,
|
|
18573
|
+
readsItem,
|
|
18574
|
+
readsOuter: reactiveOuterNames.length > 0 || opaqueOuterNames.length > 0,
|
|
18575
|
+
reactiveOuterNames,
|
|
18576
|
+
opaqueOuterNames,
|
|
18577
|
+
referencesIndex
|
|
18578
|
+
};
|
|
18579
|
+
}
|
|
18580
|
+
|
|
18581
|
+
// src/ir-to-client-js/control-flow/plan/build-lazy-row.ts
|
|
18582
|
+
function buildLazyRowPlan(args) {
|
|
18583
|
+
return decideLazyRow(args).plan;
|
|
18584
|
+
}
|
|
18585
|
+
function decideLazyRow(args) {
|
|
18586
|
+
const { loop, scope } = args;
|
|
18587
|
+
if (!scope) {
|
|
18588
|
+
return { plan: null, decision: { eligible: false, reason: "no component scope info supplied" } };
|
|
18589
|
+
}
|
|
18590
|
+
const wrap = (expr) => wrapLoopParamAsAccessor(expr, loop.param, loop.paramBindings);
|
|
18591
|
+
const rowLocalNames = new Set([loop.param]);
|
|
18592
|
+
for (const b of loop.paramBindings ?? [])
|
|
18593
|
+
rowLocalNames.add(b.name);
|
|
18594
|
+
const classified = [];
|
|
18595
|
+
const attrClass = new Map;
|
|
18596
|
+
loop.bindings.reactiveAttrs.forEach((attr, i) => {
|
|
18597
|
+
const c = classifyLazyBinding({
|
|
18598
|
+
kind: "attr",
|
|
18599
|
+
slotId: attr.childSlotId,
|
|
18600
|
+
free: attrFreeIdentifiers2(attr.expression),
|
|
18601
|
+
rowLocalNames,
|
|
18602
|
+
indexParam: args.indexParam,
|
|
18603
|
+
scope
|
|
18604
|
+
});
|
|
18605
|
+
attrClass.set(i, c);
|
|
18606
|
+
classified.push(c);
|
|
18607
|
+
});
|
|
18608
|
+
const textClass = new Map;
|
|
18609
|
+
loop.bindings.reactiveTexts.forEach((text, i) => {
|
|
18610
|
+
const c = classifyLazyBinding({
|
|
18611
|
+
kind: "text",
|
|
18612
|
+
slotId: text.slotId,
|
|
18613
|
+
free: text.freeIdentifiers ?? null,
|
|
18614
|
+
rowLocalNames,
|
|
18615
|
+
indexParam: args.indexParam,
|
|
18616
|
+
scope
|
|
18617
|
+
});
|
|
18618
|
+
textClass.set(i, c);
|
|
18619
|
+
classified.push(c);
|
|
18620
|
+
});
|
|
18621
|
+
const shape = {
|
|
18622
|
+
callSite: args.callSite,
|
|
18623
|
+
flatMapLeafItem: args.flatMapLeafItem,
|
|
18624
|
+
anchored: args.anchored,
|
|
18625
|
+
bodyIsMultiRoot: loop.bodyIsMultiRoot ?? false,
|
|
18626
|
+
hasExplicitKey: loop.key != null,
|
|
18627
|
+
conditionalCount: loop.bindings.conditionals?.length ?? 0,
|
|
18628
|
+
childRefCount: loop.bindings.refs?.length ?? 0,
|
|
18629
|
+
nestedComponentCount: loop.nestedComponents?.length ?? 0,
|
|
18630
|
+
innerLoopCount: loop.innerLoops?.length ?? 0,
|
|
18631
|
+
hasChildComponent: "childComponent" in loop && loop.childComponent != null,
|
|
18632
|
+
hasMapPreamble: args.mapPreambleWrapped.length > 0,
|
|
18633
|
+
preambleRegionCount: args.preambleRegionCount,
|
|
18634
|
+
hasParamUnwrap: args.paramUnwrap.length > 0
|
|
18635
|
+
};
|
|
18636
|
+
const decision = lazyRowEligibility({
|
|
18637
|
+
shape,
|
|
18638
|
+
bindings: classified,
|
|
18639
|
+
arraySourceIdentifiers: loopSourceIdentifiers(loop, args.arrayExpr),
|
|
18640
|
+
scope
|
|
18641
|
+
});
|
|
18642
|
+
if (!decision.eligible)
|
|
18643
|
+
return { plan: null, decision };
|
|
18644
|
+
const attrSlotIds = [];
|
|
18645
|
+
for (const attr of loop.bindings.reactiveAttrs) {
|
|
18646
|
+
if (!attrSlotIds.includes(attr.childSlotId))
|
|
18647
|
+
attrSlotIds.push(attr.childSlotId);
|
|
18648
|
+
}
|
|
18649
|
+
let ordinal = 0;
|
|
18650
|
+
const attrs = loop.bindings.reactiveAttrs.map((attr, i) => {
|
|
18651
|
+
const c = attrClass.get(i);
|
|
18652
|
+
return {
|
|
18653
|
+
slotId: attr.childSlotId,
|
|
18654
|
+
attrName: attr.attrName,
|
|
18655
|
+
wrappedExpression: wrap(attr.expression),
|
|
18656
|
+
meta: pickAttrMeta(attr),
|
|
18657
|
+
refIndex: attrSlotIds.indexOf(attr.childSlotId),
|
|
18658
|
+
ordinal: ordinal++,
|
|
18659
|
+
readsItem: c.readsItem,
|
|
18660
|
+
readsOuter: c.readsOuter
|
|
18661
|
+
};
|
|
18662
|
+
});
|
|
18663
|
+
const texts = loop.bindings.reactiveTexts.map((text, i) => {
|
|
18664
|
+
const c = textClass.get(i);
|
|
18665
|
+
return {
|
|
18666
|
+
slotId: text.slotId,
|
|
18667
|
+
wrappedExpression: wrap(text.expression),
|
|
18668
|
+
ordinal: ordinal++,
|
|
18669
|
+
readsItem: c.readsItem || !c.readsOuter,
|
|
18670
|
+
readsOuter: c.readsOuter
|
|
18671
|
+
};
|
|
18672
|
+
});
|
|
18673
|
+
const outerPrimeGetters = [];
|
|
18674
|
+
for (const c of classified) {
|
|
18675
|
+
for (const name of c.reactiveOuterNames) {
|
|
18676
|
+
if (!outerPrimeGetters.includes(name))
|
|
18677
|
+
outerPrimeGetters.push(name);
|
|
18678
|
+
}
|
|
18679
|
+
}
|
|
18680
|
+
return {
|
|
18681
|
+
plan: {
|
|
18682
|
+
attrSlotIds,
|
|
18683
|
+
attrs,
|
|
18684
|
+
texts,
|
|
18685
|
+
writerIndex: texts.length > 0 ? attrSlotIds.length : -1,
|
|
18686
|
+
textNeedsRead: texts.some((t) => t.readsOuter),
|
|
18687
|
+
lastCount: ordinal,
|
|
18688
|
+
outerPrimeGetters,
|
|
18689
|
+
hasOuter: attrs.some((a) => a.readsOuter) || texts.some((t) => t.readsOuter)
|
|
18690
|
+
},
|
|
18691
|
+
decision
|
|
18692
|
+
};
|
|
18693
|
+
}
|
|
18694
|
+
function buildLazyRowScopeInfo(ctx) {
|
|
18695
|
+
const signals = new Map;
|
|
18696
|
+
for (const s of ctx.signals) {
|
|
18697
|
+
signals.set(s.getter, {
|
|
18698
|
+
initializerFreeIdentifiers: s.parsed ? freeIdentifiers(s.parsed) : null
|
|
18699
|
+
});
|
|
18700
|
+
}
|
|
18701
|
+
const memos = new Set(ctx.memos.map((m) => m.name));
|
|
18702
|
+
const props = new Set([PROPS_PARAM]);
|
|
18703
|
+
if (ctx.propsObjectName)
|
|
18704
|
+
props.add(ctx.propsObjectName);
|
|
18705
|
+
for (const p of ctx.propsParams)
|
|
18706
|
+
props.add(p.name);
|
|
18707
|
+
const constants = new Map;
|
|
18708
|
+
for (const c of ctx.localConstants) {
|
|
18709
|
+
constants.set(c.name, c.freeIdentifiers ?? null);
|
|
18710
|
+
}
|
|
18711
|
+
const inert = new Set;
|
|
18712
|
+
for (const f of ctx.localFunctions)
|
|
18713
|
+
inert.add(f.name);
|
|
18714
|
+
for (const imp of ctx.imports) {
|
|
18715
|
+
if (imp.isTypeOnly)
|
|
18716
|
+
continue;
|
|
18717
|
+
for (const spec of imp.specifiers)
|
|
18718
|
+
inert.add(spec.alias || spec.name);
|
|
18719
|
+
}
|
|
18720
|
+
return { signals, memos, props, constants, inert, profile: ctx.profile };
|
|
18721
|
+
}
|
|
18722
|
+
function attrFreeIdentifiers2(expression) {
|
|
18723
|
+
if (!expression || expression.trim().length === 0)
|
|
18724
|
+
return new Set;
|
|
18725
|
+
try {
|
|
18726
|
+
return freeIdentifiers(parseExpression(expression));
|
|
18727
|
+
} catch {
|
|
18728
|
+
return null;
|
|
18729
|
+
}
|
|
18730
|
+
}
|
|
18731
|
+
function loopSourceIdentifiers(loop, arrayExpr) {
|
|
18732
|
+
if (!loop.arrayFreeIdentifiers)
|
|
18733
|
+
return null;
|
|
18734
|
+
const names = new Set(loop.arrayFreeIdentifiers);
|
|
18735
|
+
for (const name of extractFreeIdentifiersFromText(arrayExpr))
|
|
18736
|
+
names.add(name);
|
|
18737
|
+
return names;
|
|
18738
|
+
}
|
|
18739
|
+
|
|
18385
18740
|
// src/ir-to-client-js/control-flow/plan/build-branch-loop.ts
|
|
18386
|
-
function buildBranchLoopPlan(loop, profileComponentName) {
|
|
18741
|
+
function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
|
|
18387
18742
|
const containerSlotId = loop.containerSlotId;
|
|
18388
18743
|
const cv = varSlotId(containerSlotId);
|
|
18389
18744
|
const containerVar = `__loop_${cv}`;
|
|
@@ -18399,6 +18754,13 @@ function buildBranchLoopPlan(loop, profileComponentName) {
|
|
|
18399
18754
|
const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(loop.param, loop.paramBindings);
|
|
18400
18755
|
const hasReactiveEffects = loop.bindings.reactiveAttrs.length > 0 || loop.bindings.reactiveTexts.length > 0 || loop.bindings.conditionals.length > 0;
|
|
18401
18756
|
const fm = loop.flatMapClient;
|
|
18757
|
+
const arrayExpr = fm ? `(${buildChainedArrayExpr(loop)}).flatMap(${fm.params} => ${fm.body})` : buildChainedArrayExpr(loop);
|
|
18758
|
+
const indexParam = loop.index || "__idx";
|
|
18759
|
+
const mapPreambleWrapped = loop.preamble ? renderPreamble(loop.preamble, {
|
|
18760
|
+
transformJs: (t) => wrapLoopParamAsAccessor(t, loop.param, loop.paramBindings),
|
|
18761
|
+
renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: loop.param, bindings: loop.paramBindings }], undefined, true)
|
|
18762
|
+
}) : "";
|
|
18763
|
+
const preambleRegions = buildPreambleRegionPlans(loop.preambleRegions, loop.param, loop.paramBindings);
|
|
18402
18764
|
const plan = {
|
|
18403
18765
|
kind: "plain",
|
|
18404
18766
|
rowConstruction: "string-template",
|
|
@@ -18406,15 +18768,24 @@ function buildBranchLoopPlan(loop, profileComponentName) {
|
|
|
18406
18768
|
containerVar,
|
|
18407
18769
|
markerId: loop.markerId,
|
|
18408
18770
|
flatMapLeafItem: fm ? true : undefined,
|
|
18409
|
-
arrayExpr
|
|
18771
|
+
arrayExpr,
|
|
18410
18772
|
keyFn: fm ? fm.keyed ? "(__bfD, __bfI) => String(__bfD.k ?? __bfI)" : "null" : loopKeyFn(loop),
|
|
18411
18773
|
paramHead,
|
|
18412
18774
|
paramUnwrap,
|
|
18413
|
-
indexParam
|
|
18414
|
-
mapPreambleWrapped
|
|
18415
|
-
|
|
18416
|
-
|
|
18417
|
-
|
|
18775
|
+
indexParam,
|
|
18776
|
+
mapPreambleWrapped,
|
|
18777
|
+
lazyRow: buildLazyRowPlan({
|
|
18778
|
+
loop,
|
|
18779
|
+
arrayExpr,
|
|
18780
|
+
indexParam,
|
|
18781
|
+
paramUnwrap,
|
|
18782
|
+
mapPreambleWrapped,
|
|
18783
|
+
preambleRegionCount: preambleRegions.length,
|
|
18784
|
+
callSite: "branch-plain",
|
|
18785
|
+
flatMapLeafItem: Boolean(fm),
|
|
18786
|
+
anchored: false,
|
|
18787
|
+
scope: lazyScope
|
|
18788
|
+
}) ?? undefined,
|
|
18418
18789
|
template: loop.template,
|
|
18419
18790
|
reactiveEffects: hasReactiveEffects ? buildReactiveEffectsPlan({
|
|
18420
18791
|
attrs: loop.bindings.reactiveAttrs,
|
|
@@ -18426,7 +18797,7 @@ function buildBranchLoopPlan(loop, profileComponentName) {
|
|
|
18426
18797
|
}) : null,
|
|
18427
18798
|
eventDelegation: buildBranchLoopDelegationPlan(loop, cv, profileComponentName),
|
|
18428
18799
|
childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings),
|
|
18429
|
-
preambleRegions
|
|
18800
|
+
preambleRegions,
|
|
18430
18801
|
bodyIsMultiRoot: loop.bodyIsMultiRoot ?? false,
|
|
18431
18802
|
profileLoopId: profileComponentName ? `${profileComponentName}#binding:${containerSlotId}` : undefined
|
|
18432
18803
|
};
|
|
@@ -18477,13 +18848,29 @@ function buildArmBody(branch, options) {
|
|
|
18477
18848
|
slotId: t.slotId,
|
|
18478
18849
|
expression: t.expression
|
|
18479
18850
|
})),
|
|
18480
|
-
loops: branch.loops.map((l) => buildBranchLoopPlan(l, pc)),
|
|
18481
|
-
conditionals: branch.conditionals.map((c) => buildInsertPlan(c, { scope: { kind: "branchScope" }, eventNameMode: options.eventNameMode, profileComponentName: pc }))
|
|
18851
|
+
loops: branch.loops.map((l) => buildBranchLoopPlan(l, pc, options.lazyScope)),
|
|
18852
|
+
conditionals: branch.conditionals.map((c) => buildInsertPlan(c, { scope: { kind: "branchScope" }, eventNameMode: options.eventNameMode, profileComponentName: pc, lazyScope: options.lazyScope }))
|
|
18482
18853
|
};
|
|
18483
18854
|
}
|
|
18484
18855
|
|
|
18485
18856
|
// src/ir-to-client-js/emit-reactive.ts
|
|
18486
18857
|
import ts14 from "typescript";
|
|
18858
|
+
|
|
18859
|
+
// src/ir-to-client-js/control-flow/stringify/claim-plan.ts
|
|
18860
|
+
function slotSpecLiteral(slot) {
|
|
18861
|
+
const pathSrc = slot.pathExpr ?? `[${slot.path.join(", ")}]`;
|
|
18862
|
+
const markerlessSrc = slot.markerless ? ", markerless: true" : "";
|
|
18863
|
+
return `{ id: '${slot.id}', kind: '${slot.kind}', path: ${pathSrc}${markerlessSrc} }`;
|
|
18864
|
+
}
|
|
18865
|
+
function claimPlanLiteral(slots) {
|
|
18866
|
+
return `[${slots.map(slotSpecLiteral).join(", ")}]`;
|
|
18867
|
+
}
|
|
18868
|
+
function claimWriterVarName(slots, sanitize) {
|
|
18869
|
+
const first = slots[0]?.id ?? "0";
|
|
18870
|
+
return `__bfw_${sanitize(first)}`;
|
|
18871
|
+
}
|
|
18872
|
+
|
|
18873
|
+
// src/ir-to-client-js/emit-reactive.ts
|
|
18487
18874
|
function bindingIdArg(ctx, slotId) {
|
|
18488
18875
|
if (!ctx.profile || !slotId)
|
|
18489
18876
|
return "";
|
|
@@ -18667,17 +19054,18 @@ function emitDynamicTextUpdates(lines, ctx) {
|
|
|
18667
19054
|
const conditionalElems = elems.filter((e) => e.insideConditional);
|
|
18668
19055
|
const normalElems = elems.filter((e) => !e.insideConditional);
|
|
18669
19056
|
if (normalElems.length > 0 || conditionalElems.length > 0) {
|
|
18670
|
-
for (const elem of normalElems) {
|
|
18671
|
-
const v = varSlotId(elem.slotId);
|
|
18672
|
-
lines.push(` let __anchor_${v} = _${v}`);
|
|
18673
|
-
}
|
|
18674
19057
|
const __textSlot = (normalElems[0] ?? conditionalElems[0])?.slotId;
|
|
19058
|
+
let writer = "";
|
|
19059
|
+
if (normalElems.length > 0) {
|
|
19060
|
+
const slots = normalElems.map((elem) => ({ id: elem.slotId, kind: "markup", path: [] }));
|
|
19061
|
+
writer = claimWriterVarName(slots, varSlotId);
|
|
19062
|
+
lines.push(` const ${writer} = lazySlots(__scope, ${claimPlanLiteral(slots)})`);
|
|
19063
|
+
}
|
|
18675
19064
|
lines.push(` createEffect(() => {`);
|
|
18676
19065
|
if (normalElems.length > 0) {
|
|
18677
19066
|
lines.push(` const __val = ${expr}`);
|
|
18678
19067
|
for (const elem of normalElems) {
|
|
18679
|
-
|
|
18680
|
-
lines.push(` __anchor_${v} = __bfText(__anchor_${v}, __val)`);
|
|
19068
|
+
lines.push(` ${writer}('${elem.slotId}', escapeTextOrNode(__val))`);
|
|
18681
19069
|
}
|
|
18682
19070
|
for (const elem of conditionalElems) {
|
|
18683
19071
|
const v = varSlotId(elem.slotId);
|
|
@@ -18700,10 +19088,13 @@ function emitDynamicTextUpdates(lines, ctx) {
|
|
|
18700
19088
|
}
|
|
18701
19089
|
function emitClientOnlyExpressions(lines, ctx) {
|
|
18702
19090
|
for (const elem of ctx.clientOnlyElements) {
|
|
19091
|
+
const slots = elem.elidedPath ? [{ id: elem.slotId, kind: "text", path: elem.elidedPath, markerless: true }] : [{ id: elem.slotId, kind: "text", path: [] }];
|
|
19092
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
18703
19093
|
lines.push(` // @client: ${elem.slotId}`);
|
|
19094
|
+
lines.push(` { const ${writer} = lazySlots(__scope, ${claimPlanLiteral(slots)})`);
|
|
18704
19095
|
lines.push(` createEffect(() => {`);
|
|
18705
|
-
lines.push(`
|
|
18706
|
-
lines.push(` }${bindingIdArg(ctx, elem.slotId)})`);
|
|
19096
|
+
lines.push(` ${writer}('${elem.slotId}', ${elem.expression})`);
|
|
19097
|
+
lines.push(` }${bindingIdArg(ctx, elem.slotId)}) }`);
|
|
18707
19098
|
lines.push("");
|
|
18708
19099
|
}
|
|
18709
19100
|
}
|
|
@@ -18835,7 +19226,7 @@ function stringifyBranchEventBindings(lines, plan, indent) {
|
|
|
18835
19226
|
}
|
|
18836
19227
|
function stringifyBranchChildComponentInits(lines, plan, indent) {
|
|
18837
19228
|
for (const init of plan) {
|
|
18838
|
-
lines.push(`${indent}{ let __c = qsa(__branchScope, ${init.selector}); if (!__c) { const __ph = __branchScope.querySelector('[${DATA_BF_PH}="${init.placeholderId}"]'); if (__ph) { __c = createComponent('${nameForRegistryRef(init.name)}', ${init.propsExpr}
|
|
19229
|
+
lines.push(`${indent}{ let __c = qsa(__branchScope, ${init.selector}); if (!__c) { const __ph = __branchScope.querySelector('[${DATA_BF_PH}="${init.placeholderId}"]'); if (__ph) { __c = createComponent('${nameForRegistryRef(init.name)}', ${init.propsExpr}, undefined, undefined, __ph) } } if (__c) initChild('${nameForRegistryRef(init.name)}', __c, ${init.propsExpr}) }`);
|
|
18839
19230
|
}
|
|
18840
19231
|
}
|
|
18841
19232
|
function stringifyBranchInnerLoops(lines, plan, indent, pc) {
|
|
@@ -18861,13 +19252,18 @@ function stringifyBranchInnerLoops(lines, plan, indent, pc) {
|
|
|
18861
19252
|
if (inner.legacyComponents.length > 0 || inner.legacyEvents.length > 0) {
|
|
18862
19253
|
emitComponentAndEventSetup(lines, `${indent} `, `__bel${uid}`, [...inner.legacyComponents], [...inner.legacyEvents], inner.outerLoopParam, inner.outerLoopParamBindings);
|
|
18863
19254
|
}
|
|
18864
|
-
|
|
19255
|
+
const conditionalTexts = inner.reactiveTexts.filter((t) => t.insideConditional);
|
|
19256
|
+
const plainTexts = inner.reactiveTexts.filter((t) => !t.insideConditional);
|
|
19257
|
+
for (const text of conditionalTexts) {
|
|
18865
19258
|
const bf = profileBindingId(pc, text.slotId);
|
|
18866
|
-
|
|
18867
|
-
|
|
18868
|
-
|
|
18869
|
-
|
|
18870
|
-
|
|
19259
|
+
lines.push(`${indent} createEffect(() => { claimSlots(__bel${uid}, [{ id: '${text.slotId}', kind: 'text', path: [] }]).write('${text.slotId}', String(${text.wrappedExpression})) }${bf})`);
|
|
19260
|
+
}
|
|
19261
|
+
if (plainTexts.length > 0) {
|
|
19262
|
+
const slots = plainTexts.map((t) => ({ id: t.slotId, kind: "text", path: [] }));
|
|
19263
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
19264
|
+
lines.push(`${indent} const ${writer} = lazySlots(__bel${uid}, ${claimPlanLiteral(slots)})`);
|
|
19265
|
+
for (const text of plainTexts) {
|
|
19266
|
+
lines.push(`${indent} createEffect(() => { ${writer}('${text.slotId}', String(${text.wrappedExpression})) }${profileBindingId(pc, text.slotId)})`);
|
|
18871
19267
|
}
|
|
18872
19268
|
}
|
|
18873
19269
|
if (inner.nestedConditionals.length > 0) {
|
|
@@ -18910,24 +19306,41 @@ function stringifyLoopChildArm(lines, arm, armIndent, pc) {
|
|
|
18910
19306
|
stringifyLoopChildConditional(lines, cond, `${armIndent} `, pc);
|
|
18911
19307
|
lines.push(`${armIndent}}))`);
|
|
18912
19308
|
}
|
|
18913
|
-
|
|
18914
|
-
const
|
|
18915
|
-
|
|
18916
|
-
lines.push(`${armIndent}
|
|
19309
|
+
if (arm.texts.length > 0) {
|
|
19310
|
+
const slots = arm.texts.map((t) => ({ id: t.slotId, kind: "markup", path: [] }));
|
|
19311
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
19312
|
+
lines.push(`${armIndent}const ${writer} = lazySlots(__branchScope, ${claimPlanLiteral(slots)})`);
|
|
19313
|
+
for (const text of arm.texts) {
|
|
19314
|
+
lines.push(`${armIndent}__disposers.push(createDisposableEffect(() => { ${writer}('${text.slotId}', escapeTextOrNode(${text.wrappedExpression})) }${profileBindingId(pc, text.slotId)}))`);
|
|
19315
|
+
}
|
|
18917
19316
|
}
|
|
18918
19317
|
lines.push(`${armIndent}return () => __disposers.forEach(d => d())`);
|
|
18919
19318
|
}
|
|
18920
19319
|
|
|
18921
19320
|
// src/ir-to-client-js/control-flow/stringify/reactive-effects.ts
|
|
18922
19321
|
function stringifyReactiveEffects(lines, plan, opts) {
|
|
18923
|
-
const { indent, elVar, bodyIsMultiRoot, elementIndexBySlot,
|
|
19322
|
+
const { indent, elVar, bodyIsMultiRoot, elementIndexBySlot, textClaimPathExprs, preambleRegions = [], mapPreambleWrapped } = opts;
|
|
18924
19323
|
const lookup = bodyIsMultiRoot ? "qsaItem" : "qsa";
|
|
18925
|
-
const pc = plan
|
|
19324
|
+
const pc = plan?.profileComponentName;
|
|
18926
19325
|
const bindingBfId = (slotId) => profileBindingId(pc, slotId);
|
|
18927
|
-
|
|
19326
|
+
const attrSlots = plan?.attrSlots ?? [];
|
|
19327
|
+
const outerTexts = plan?.outerTexts ?? [];
|
|
19328
|
+
const conditionals = plan?.conditionals ?? [];
|
|
19329
|
+
if (pc) {
|
|
19330
|
+
emitAttrSlotsGranular(lines, indent, elVar, lookup, attrSlots, elementIndexBySlot, bindingBfId);
|
|
19331
|
+
emitOuterTexts(lines, indent, elVar, outerTexts, bindingBfId, textClaimPathExprs);
|
|
19332
|
+
emitPreambleRegionsEffect(lines, indent, elVar, preambleRegions, mapPreambleWrapped);
|
|
19333
|
+
} else {
|
|
19334
|
+
emitConsolidatedRowEffect(lines, indent, elVar, lookup, attrSlots, outerTexts, elementIndexBySlot, textClaimPathExprs, preambleRegions, mapPreambleWrapped);
|
|
19335
|
+
}
|
|
19336
|
+
for (const cond of conditionals) {
|
|
19337
|
+
emitOuterConditional(lines, indent, elVar, cond, pc);
|
|
19338
|
+
}
|
|
19339
|
+
}
|
|
19340
|
+
function emitAttrSlotsGranular(lines, indent, elVar, lookup, attrSlots, elementIndexBySlot, bindingBfId) {
|
|
19341
|
+
for (const slot of attrSlots) {
|
|
18928
19342
|
const varName = `__ra_${varSlotId(slot.slotId)}`;
|
|
18929
|
-
const
|
|
18930
|
-
const lookupExpr = pIdx !== undefined ? `__p ? __p[${pIdx}] : ${lookup}(${elVar}, '[bf="${slot.slotId}"]')` : `${lookup}(${elVar}, '[bf="${slot.slotId}"]')`;
|
|
19343
|
+
const lookupExpr = attrLookupExpr(slot.slotId, varName, elVar, lookup, elementIndexBySlot);
|
|
18931
19344
|
lines.push(`${indent}{ const ${varName} = ${lookupExpr}`);
|
|
18932
19345
|
lines.push(`${indent}if (${varName}) {`);
|
|
18933
19346
|
for (const attr of slot.attrs) {
|
|
@@ -18939,21 +19352,83 @@ function stringifyReactiveEffects(lines, plan, opts) {
|
|
|
18939
19352
|
}
|
|
18940
19353
|
lines.push(`${indent}} }`);
|
|
18941
19354
|
}
|
|
18942
|
-
|
|
18943
|
-
|
|
19355
|
+
}
|
|
19356
|
+
function emitPreambleRegionsEffect(lines, indent, elVar, preambleRegions, mapPreambleWrapped) {
|
|
19357
|
+
if (preambleRegions.length === 0)
|
|
19358
|
+
return;
|
|
19359
|
+
const slots = preambleRegions.map((r) => ({ id: r.slotId, kind: "markup", path: [] }));
|
|
19360
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
19361
|
+
lines.push(`${indent}const ${writer} = lazySlots(${elVar}, ${claimPlanLiteral(slots)})`);
|
|
19362
|
+
lines.push(`${indent}createEffect(() => {`);
|
|
19363
|
+
if (mapPreambleWrapped)
|
|
19364
|
+
lines.push(`${indent} ${mapPreambleWrapped}`);
|
|
19365
|
+
for (const region of preambleRegions) {
|
|
19366
|
+
lines.push(`${indent} ${writer}('${region.slotId}', ${region.valueExpr})`);
|
|
18944
19367
|
}
|
|
18945
|
-
|
|
18946
|
-
|
|
19368
|
+
lines.push(`${indent}})`);
|
|
19369
|
+
}
|
|
19370
|
+
function attrLookupExpr(slotId, varName, elVar, lookup, elementIndexBySlot) {
|
|
19371
|
+
const pIdx = elementIndexBySlot?.get(slotId);
|
|
19372
|
+
return pIdx !== undefined ? `__p ? __p[${pIdx}] : ${lookup}(${elVar}, '[bf="${slotId}"]')` : `${lookup}(${elVar}, '[bf="${slotId}"]')`;
|
|
19373
|
+
}
|
|
19374
|
+
function emitConsolidatedRowEffect(lines, indent, elVar, lookup, attrSlots, outerTexts, elementIndexBySlot, textClaimPathExprs, preambleRegions, mapPreambleWrapped) {
|
|
19375
|
+
if (attrSlots.length === 0 && outerTexts.length === 0 && preambleRegions.length === 0)
|
|
19376
|
+
return;
|
|
19377
|
+
for (const slot of attrSlots) {
|
|
19378
|
+
const varName = `__ra_${varSlotId(slot.slotId)}`;
|
|
19379
|
+
lines.push(`${indent}const ${varName} = ${attrLookupExpr(slot.slotId, varName, elVar, lookup, elementIndexBySlot)}`);
|
|
19380
|
+
}
|
|
19381
|
+
const claimSlots = [
|
|
19382
|
+
...outerTexts.map((t) => ({ id: t.slotId, kind: "text", path: [], pathExpr: textClaimPathExprs?.get(t.slotId) })),
|
|
19383
|
+
...preambleRegions.map((r) => ({ id: r.slotId, kind: "markup", path: [] }))
|
|
19384
|
+
];
|
|
19385
|
+
const writer = claimSlots.length > 0 ? claimWriterVarName(claimSlots, varSlotId) : null;
|
|
19386
|
+
if (writer) {
|
|
19387
|
+
lines.push(`${indent}const ${writer} = lazySlots(${elVar}, ${claimPlanLiteral(claimSlots)})`);
|
|
19388
|
+
}
|
|
19389
|
+
if (attrSlots.length === 0 && preambleRegions.length === 0 && outerTexts.length === 1) {
|
|
19390
|
+
const text = outerTexts[0];
|
|
19391
|
+
lines.push(`${indent}createEffect(() => { ${writer}('${text.slotId}', String(${text.wrappedExpression})) })`);
|
|
19392
|
+
return;
|
|
19393
|
+
}
|
|
19394
|
+
lines.push(`${indent}createEffect(() => {`);
|
|
19395
|
+
for (const slot of attrSlots) {
|
|
19396
|
+
const varName = `__ra_${varSlotId(slot.slotId)}`;
|
|
19397
|
+
lines.push(`${indent} if (${varName}) {`);
|
|
19398
|
+
for (const attr of slot.attrs) {
|
|
19399
|
+
lines.push(`${indent} {`);
|
|
19400
|
+
for (const stmt of emitAttrUpdate(varName, attr.attrName, attr.wrappedExpression, attr.meta)) {
|
|
19401
|
+
lines.push(`${indent} ${stmt}`);
|
|
19402
|
+
}
|
|
19403
|
+
lines.push(`${indent} }`);
|
|
19404
|
+
}
|
|
19405
|
+
lines.push(`${indent} }`);
|
|
19406
|
+
}
|
|
19407
|
+
if (preambleRegions.length > 0 && mapPreambleWrapped) {
|
|
19408
|
+
lines.push(`${indent} ${mapPreambleWrapped}`);
|
|
18947
19409
|
}
|
|
19410
|
+
for (const text of outerTexts) {
|
|
19411
|
+
lines.push(`${indent} ${writer}('${text.slotId}', String(${text.wrappedExpression}))`);
|
|
19412
|
+
}
|
|
19413
|
+
for (const region of preambleRegions) {
|
|
19414
|
+
lines.push(`${indent} ${writer}('${region.slotId}', ${region.valueExpr})`);
|
|
19415
|
+
}
|
|
19416
|
+
lines.push(`${indent}})`);
|
|
18948
19417
|
}
|
|
18949
|
-
function
|
|
18950
|
-
|
|
18951
|
-
|
|
18952
|
-
|
|
18953
|
-
|
|
18954
|
-
|
|
19418
|
+
function emitOuterTexts(lines, indent, elVar, texts, bindingBfId, textClaimPathExprs) {
|
|
19419
|
+
if (texts.length === 0)
|
|
19420
|
+
return;
|
|
19421
|
+
const slots = texts.map((t) => ({
|
|
19422
|
+
id: t.slotId,
|
|
19423
|
+
kind: "text",
|
|
19424
|
+
path: [],
|
|
19425
|
+
pathExpr: textClaimPathExprs?.get(t.slotId)
|
|
19426
|
+
}));
|
|
19427
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
19428
|
+
lines.push(`${indent}const ${writer} = lazySlots(${elVar}, ${claimPlanLiteral(slots)})`);
|
|
19429
|
+
for (const text of texts) {
|
|
19430
|
+
lines.push(`${indent}createEffect(() => { ${writer}('${text.slotId}', String(${text.wrappedExpression})) }${bindingBfId(text.slotId)})`);
|
|
18955
19431
|
}
|
|
18956
|
-
lines.push(`${indent}if (${varName}) createEffect(() => { ${varName}.textContent = String(${text.wrappedExpression}) }${bfId}) }`);
|
|
18957
19432
|
}
|
|
18958
19433
|
function emitOuterConditional(lines, indent, elVar, cond, pc) {
|
|
18959
19434
|
const armIndent = `${indent} `;
|
|
@@ -19060,6 +19535,184 @@ function emitNestedInit(lines, indent, parentVar, nc) {
|
|
|
19060
19535
|
}
|
|
19061
19536
|
}
|
|
19062
19537
|
|
|
19538
|
+
// src/ir-to-client-js/control-flow/stringify/lazy-row.ts
|
|
19539
|
+
function stringifyLazyRowLoop(lines, o) {
|
|
19540
|
+
const { indent, lazyRow, paramHead } = o;
|
|
19541
|
+
const mid = o.markerId.replace(/[^A-Za-z0-9_$]/g, "_");
|
|
19542
|
+
const tplVar = `__tpl_${mid}`;
|
|
19543
|
+
const claimVar = `__lzc_${mid}`;
|
|
19544
|
+
const hasRefs = lazyRow.attrSlotIds.length > 0 || lazyRow.texts.length > 0;
|
|
19545
|
+
const hasBindings = lazyRow.attrs.length > 0 || lazyRow.texts.length > 0;
|
|
19546
|
+
const rwDoor = lazyRow.textNeedsRead;
|
|
19547
|
+
const paths = o.skeletonPaths;
|
|
19548
|
+
const useHoisted = Boolean(o.skeletonTemplate);
|
|
19549
|
+
if (useHoisted)
|
|
19550
|
+
emitHoistedTemplateDecl(lines, indent, tplVar, o.skeletonTemplate);
|
|
19551
|
+
const textPathVar = useHoisted && paths && lazyRow.texts.length > 0 ? `__lzp_${mid}` : null;
|
|
19552
|
+
if (textPathVar) {
|
|
19553
|
+
const arrays = lazyRow.texts.map((t) => `[${(paths.textMarkerPaths.get(t.slotId) ?? []).join(", ")}]`);
|
|
19554
|
+
lines.push(`${indent}const ${textPathVar} = [${arrays.join(", ")}]`);
|
|
19555
|
+
}
|
|
19556
|
+
let adoptedPlanVar = null;
|
|
19557
|
+
let freshPlanVar = null;
|
|
19558
|
+
if (lazyRow.texts.length > 0) {
|
|
19559
|
+
adoptedPlanVar = `__lzs_${mid}`;
|
|
19560
|
+
const adoptedSlots = lazyRow.texts.map((t) => ({ id: t.slotId, kind: "text", path: [] }));
|
|
19561
|
+
lines.push(`${indent}const ${adoptedPlanVar} = ${claimPlanLiteral(adoptedSlots)}`);
|
|
19562
|
+
if (textPathVar) {
|
|
19563
|
+
freshPlanVar = `__lzsc_${mid}`;
|
|
19564
|
+
const freshSlots = lazyRow.texts.map((t, i) => ({
|
|
19565
|
+
id: t.slotId,
|
|
19566
|
+
kind: "text",
|
|
19567
|
+
path: [],
|
|
19568
|
+
pathExpr: `${textPathVar}[${i}]`
|
|
19569
|
+
}));
|
|
19570
|
+
lines.push(`${indent}const ${freshPlanVar} = ${claimPlanLiteral(freshSlots)}`);
|
|
19571
|
+
} else {
|
|
19572
|
+
freshPlanVar = adoptedPlanVar;
|
|
19573
|
+
}
|
|
19574
|
+
}
|
|
19575
|
+
if (hasRefs) {
|
|
19576
|
+
const parts = refParts(lazyRow, "__el", null, adoptedPlanVar, true);
|
|
19577
|
+
lines.push(`${indent}const ${claimVar} = (__e) => {`);
|
|
19578
|
+
if (parts.some((p) => p.includes("__el")))
|
|
19579
|
+
lines.push(`${indent} const __el = __e.primaryEl`);
|
|
19580
|
+
lines.push(`${indent} return [${parts.join(", ")}]`);
|
|
19581
|
+
lines.push(`${indent}}`);
|
|
19582
|
+
}
|
|
19583
|
+
const call = `mapArrayLazy(() => ${o.arrayExpr}, ${o.containerVar}, ${o.keyFn}, {`;
|
|
19584
|
+
lines.push(`${indent}${o.guardContainer ? `if (${o.containerVar}) ` : ""}${call}`);
|
|
19585
|
+
const b1 = `${indent} `;
|
|
19586
|
+
const b2 = `${indent} `;
|
|
19587
|
+
lines.push(`${b1}createRow: (__e, ${o.indexParam}) => {`);
|
|
19588
|
+
lines.push(`${b2}const ${paramHead} = () => __e.item`);
|
|
19589
|
+
const cloneExpr = useHoisted ? hoistedCloneExpr(tplVar, o.skeletonTemplate) : `(() => { ${emitTemplateCloneInline(o.template)} })()`;
|
|
19590
|
+
lines.push(`${b2}const __el = ${cloneExpr}`);
|
|
19591
|
+
if (hasRefs) {
|
|
19592
|
+
lines.push(`${b2}const __r = __e.refs = [${refParts(lazyRow, "__el", useHoisted ? paths ?? null : null, freshPlanVar).join(", ")}]`);
|
|
19593
|
+
}
|
|
19594
|
+
if (hasBindings) {
|
|
19595
|
+
lines.push(`${b2}const __l = __e.last = []`);
|
|
19596
|
+
for (const a of lazyRow.attrs)
|
|
19597
|
+
emitAttrBinding(lines, b2, a, "create");
|
|
19598
|
+
const createDoor = `__r[${lazyRow.writerIndex}]`;
|
|
19599
|
+
for (const t of lazyRow.texts)
|
|
19600
|
+
emitTextBinding(lines, b2, t, createDoor, "create", rwDoor);
|
|
19601
|
+
}
|
|
19602
|
+
lines.push(`${b2}return __el`);
|
|
19603
|
+
lines.push(`${b1}},`);
|
|
19604
|
+
const itemAttrs = lazyRow.attrs.filter((a) => a.readsItem);
|
|
19605
|
+
const itemTexts = lazyRow.texts.filter((t) => t.readsItem);
|
|
19606
|
+
if (itemAttrs.length === 0 && itemTexts.length === 0) {
|
|
19607
|
+
lines.push(`${b1}applyItem: () => {},`);
|
|
19608
|
+
} else {
|
|
19609
|
+
lines.push(`${b1}applyItem: (__e) => {`);
|
|
19610
|
+
lines.push(`${b2}const ${paramHead} = () => __e.item`);
|
|
19611
|
+
lines.push(`${b2}const __r = __e.refs ?? (__e.refs = ${claimVar}(__e))`);
|
|
19612
|
+
lines.push(`${b2}const __l = __e.last ?? (__e.last = [])`);
|
|
19613
|
+
for (const a of itemAttrs)
|
|
19614
|
+
emitAttrBinding(lines, b2, a, "item");
|
|
19615
|
+
if (itemTexts.length > 0) {
|
|
19616
|
+
lines.push(`${b2}const __d = ${doorAccess(lazyRow, lazyRow.writerIndex, adoptedPlanVar)}`);
|
|
19617
|
+
for (const t of itemTexts)
|
|
19618
|
+
emitTextBinding(lines, b2, t, "__d", "item", rwDoor);
|
|
19619
|
+
}
|
|
19620
|
+
lines.push(`${b1}},`);
|
|
19621
|
+
}
|
|
19622
|
+
const outerAttrs = lazyRow.attrs.filter((a) => a.readsOuter);
|
|
19623
|
+
const outerTexts = lazyRow.texts.filter((t) => t.readsOuter);
|
|
19624
|
+
if (outerAttrs.length > 0 || outerTexts.length > 0) {
|
|
19625
|
+
const b3 = `${indent} `;
|
|
19626
|
+
lines.push(`${b1}applyOuter: (__es, __seed) => {`);
|
|
19627
|
+
for (const g of lazyRow.outerPrimeGetters)
|
|
19628
|
+
lines.push(`${b2}${g}()`);
|
|
19629
|
+
lines.push(`${b2}for (const __e of __es) {`);
|
|
19630
|
+
lines.push(`${b3}const ${paramHead} = () => __e.item`);
|
|
19631
|
+
lines.push(`${b3}const __r = __e.refs ?? (__e.refs = ${claimVar}(__e))`);
|
|
19632
|
+
lines.push(`${b3}const __l = __e.last ?? (__e.last = [])`);
|
|
19633
|
+
for (const a of outerAttrs)
|
|
19634
|
+
emitAttrBinding(lines, b3, a, "outer");
|
|
19635
|
+
if (outerTexts.length > 0) {
|
|
19636
|
+
lines.push(`${b3}const __d = ${doorAccess(lazyRow, lazyRow.writerIndex, adoptedPlanVar)}`);
|
|
19637
|
+
for (const t of outerTexts)
|
|
19638
|
+
emitTextBinding(lines, b3, t, "__d", "outer", rwDoor);
|
|
19639
|
+
}
|
|
19640
|
+
lines.push(`${b2}}`);
|
|
19641
|
+
lines.push(`${b1}},`);
|
|
19642
|
+
}
|
|
19643
|
+
lines.push(`${indent}}, '${o.markerId}')`);
|
|
19644
|
+
}
|
|
19645
|
+
function refParts(lazyRow, elVar, skeletonPaths, planVar, deferDoor = false) {
|
|
19646
|
+
const parts = [];
|
|
19647
|
+
for (const slotId of lazyRow.attrSlotIds) {
|
|
19648
|
+
const path = skeletonPaths?.elementPaths.get(slotId);
|
|
19649
|
+
parts.push(path ? pathExpr(elVar, path) : `qsa(${elVar}, '[bf="${slotId}"]')`);
|
|
19650
|
+
}
|
|
19651
|
+
if (lazyRow.texts.length > 0) {
|
|
19652
|
+
parts.push(deferDoor ? "null" : `${doorCtor(lazyRow)}(${elVar}, ${planVar})`);
|
|
19653
|
+
}
|
|
19654
|
+
return parts;
|
|
19655
|
+
}
|
|
19656
|
+
function doorCtor(lazyRow) {
|
|
19657
|
+
return lazyRow.textNeedsRead ? "lazyClaimSlots" : "lazySlots";
|
|
19658
|
+
}
|
|
19659
|
+
function doorAccess(lazyRow, writerIndex, adoptedPlanVar) {
|
|
19660
|
+
const slot = `__r[${writerIndex}]`;
|
|
19661
|
+
return `${slot} ?? (${slot} = ${doorCtor(lazyRow)}(__e.primaryEl, ${adoptedPlanVar}))`;
|
|
19662
|
+
}
|
|
19663
|
+
function dedupGuard(ordinal) {
|
|
19664
|
+
return `!(${ordinal} in __l) || !Object.is(__l[${ordinal}], __x)`;
|
|
19665
|
+
}
|
|
19666
|
+
function emitAttrBinding(lines, ind, a, mode) {
|
|
19667
|
+
lines.push(`${ind}{ const __t = __r[${a.refIndex}]`);
|
|
19668
|
+
lines.push(`${ind}if (__t) {`);
|
|
19669
|
+
lines.push(`${ind} const __x = ${a.wrappedExpression}`);
|
|
19670
|
+
const guard = mode === "create" ? null : mode === "item" ? dedupGuard(a.ordinal) : `__seed ? (${seedDiffersExpr("__t", a)}) : (${dedupGuard(a.ordinal)})`;
|
|
19671
|
+
const writeIndent = guard ? `${ind} ` : `${ind} `;
|
|
19672
|
+
if (guard)
|
|
19673
|
+
lines.push(`${ind} if (${guard}) {`);
|
|
19674
|
+
for (const stmt of emitAttrUpdate("__t", a.attrName, "__x", a.meta)) {
|
|
19675
|
+
lines.push(`${writeIndent}${stmt}`);
|
|
19676
|
+
}
|
|
19677
|
+
if (guard)
|
|
19678
|
+
lines.push(`${ind} }`);
|
|
19679
|
+
lines.push(`${ind} __l[${a.ordinal}] = __x`);
|
|
19680
|
+
lines.push(`${ind}} }`);
|
|
19681
|
+
}
|
|
19682
|
+
function emitTextBinding(lines, ind, t, doorExpr, mode, rwDoor) {
|
|
19683
|
+
lines.push(`${ind}{ const __x = ${t.wrappedExpression}`);
|
|
19684
|
+
const writeOf = (valueExpr) => rwDoor ? `${doorExpr}.write('${t.slotId}', ${valueExpr})` : `${doorExpr}('${t.slotId}', ${valueExpr})`;
|
|
19685
|
+
if (mode === "outer") {
|
|
19686
|
+
lines.push(`${ind}if (__seed) {`);
|
|
19687
|
+
lines.push(`${ind} const __s = textOrNode(__x)`);
|
|
19688
|
+
lines.push(`${ind} if (${doorExpr}.read('${t.slotId}') !== __s) ${writeOf("__s")}`);
|
|
19689
|
+
lines.push(`${ind}} else if (${dedupGuard(t.ordinal)}) ${writeOf("textOrNode(__x)")}`);
|
|
19690
|
+
} else if (mode === "item") {
|
|
19691
|
+
lines.push(`${ind}if (${dedupGuard(t.ordinal)}) ${writeOf("textOrNode(__x)")}`);
|
|
19692
|
+
} else {
|
|
19693
|
+
lines.push(`${ind}${writeOf("textOrNode(__x)")}`);
|
|
19694
|
+
}
|
|
19695
|
+
lines.push(`${ind}__l[${t.ordinal}] = __x }`);
|
|
19696
|
+
}
|
|
19697
|
+
function seedDiffersExpr(target, a) {
|
|
19698
|
+
const html = toHtmlAttrName(a.attrName);
|
|
19699
|
+
if (a.attrName === "dangerouslySetInnerHTML" || html === "dangerouslySetInnerHTML")
|
|
19700
|
+
return "true";
|
|
19701
|
+
if (html === "style")
|
|
19702
|
+
return `${target}.getAttribute('style') !== styleToCss(__x)`;
|
|
19703
|
+
if (html === "class")
|
|
19704
|
+
return `${target}.getAttribute('class') !== (__x != null ? String(__x) : null)`;
|
|
19705
|
+
if (html === "value")
|
|
19706
|
+
return `${target}.value !== String(__x)`;
|
|
19707
|
+
if (isBooleanAttr(html))
|
|
19708
|
+
return `${target}.${html} !== !!(__x)`;
|
|
19709
|
+
if (a.meta.presenceOrUndefined) {
|
|
19710
|
+
const written = html.startsWith("aria-") ? "true" : "";
|
|
19711
|
+
return `${target}.getAttribute('${html}') !== (__x ? '${written}' : null)`;
|
|
19712
|
+
}
|
|
19713
|
+
return `${target}.getAttribute('${html}') !== (__x != null ? String(__x) : null)`;
|
|
19714
|
+
}
|
|
19715
|
+
|
|
19063
19716
|
// src/ir-to-client-js/control-flow/stringify/loop.ts
|
|
19064
19717
|
function emitLoopChildRefs(lines, refs, opts) {
|
|
19065
19718
|
if (refs.length === 0)
|
|
@@ -19074,22 +19727,6 @@ function emitLoopChildRefs(lines, refs, opts) {
|
|
|
19074
19727
|
lines.push(`${indent}if (${varName}) ${emitRefCall(ref.callback, varName)} }`);
|
|
19075
19728
|
}
|
|
19076
19729
|
}
|
|
19077
|
-
function emitPreambleRegionEffects(lines, regions, mapPreambleWrapped, opts) {
|
|
19078
|
-
if (regions.length === 0)
|
|
19079
|
-
return;
|
|
19080
|
-
const { indent, elVar } = opts;
|
|
19081
|
-
for (const region of regions) {
|
|
19082
|
-
const v = varSlotId(region.slotId);
|
|
19083
|
-
lines.push(`${indent}{ let __last_${v}`);
|
|
19084
|
-
lines.push(`${indent}createEffect(() => {`);
|
|
19085
|
-
if (mapPreambleWrapped)
|
|
19086
|
-
lines.push(`${indent} ${mapPreambleWrapped}`);
|
|
19087
|
-
lines.push(`${indent} const __html_${v} = ${region.valueExpr}`);
|
|
19088
|
-
lines.push(`${indent} if (__last_${v} === undefined) { __last_${v} = __html_${v}; return }`);
|
|
19089
|
-
lines.push(`${indent} if (__html_${v} !== __last_${v}) { __last_${v} = __html_${v}; patchSlotRange(${elVar}, '${region.slotId}', __html_${v}) }`);
|
|
19090
|
-
lines.push(`${indent}}) }`);
|
|
19091
|
-
}
|
|
19092
|
-
}
|
|
19093
19730
|
function stringifyLoop(lines, plan) {
|
|
19094
19731
|
switch (plan.kind) {
|
|
19095
19732
|
case "static":
|
|
@@ -19153,6 +19790,23 @@ function stringifyPlainLoop(lines, plan, topIndent = " ") {
|
|
|
19153
19790
|
stringifyAnchoredLoop(lines, plan, topIndent, anchorKeyExpr);
|
|
19154
19791
|
return;
|
|
19155
19792
|
}
|
|
19793
|
+
if (plan.lazyRow) {
|
|
19794
|
+
stringifyLazyRowLoop(lines, {
|
|
19795
|
+
indent: topIndent,
|
|
19796
|
+
containerVar,
|
|
19797
|
+
guardContainer: false,
|
|
19798
|
+
markerId,
|
|
19799
|
+
arrayExpr,
|
|
19800
|
+
keyFn,
|
|
19801
|
+
paramHead,
|
|
19802
|
+
indexParam,
|
|
19803
|
+
template,
|
|
19804
|
+
skeletonTemplate,
|
|
19805
|
+
skeletonPaths: plan.skeletonPaths,
|
|
19806
|
+
lazyRow: plan.lazyRow
|
|
19807
|
+
});
|
|
19808
|
+
return;
|
|
19809
|
+
}
|
|
19156
19810
|
const hoistedTpl = !bodyIsMultiRoot && skeletonTemplate ? skeletonTemplate : null;
|
|
19157
19811
|
const tplVar = `__tpl_${markerId.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
19158
19812
|
if (hoistedTpl) {
|
|
@@ -19188,26 +19842,34 @@ function stringifyPlainLoop(lines, plan, topIndent = " ") {
|
|
|
19188
19842
|
...reactiveEffects?.attrSlots.map((s) => s.slotId) ?? [],
|
|
19189
19843
|
...childRefs.map((r) => r.childSlotId)
|
|
19190
19844
|
];
|
|
19191
|
-
|
|
19192
|
-
|
|
19193
|
-
const built = buildSkeletonPathPlan(plan.skeletonPaths, "__el", { elementSlotIds, textSlotIds });
|
|
19845
|
+
if (elementSlotIds.length > 0) {
|
|
19846
|
+
const built = buildSkeletonPathPlan(plan.skeletonPaths, "__el", { elementSlotIds, textSlotIds: [] });
|
|
19194
19847
|
if (built.arrayElems.length > 0) {
|
|
19195
19848
|
pathPlan = built;
|
|
19196
19849
|
lines.push(`${bodyIndent}const __p = __existing ? null : [${built.arrayElems.join(", ")}]`);
|
|
19197
19850
|
}
|
|
19198
19851
|
}
|
|
19199
19852
|
}
|
|
19200
|
-
|
|
19853
|
+
const textClaimPathExprs = new Map;
|
|
19854
|
+
if (hoistedTpl && plan.skeletonPaths) {
|
|
19855
|
+
for (const text of reactiveEffects?.outerTexts ?? []) {
|
|
19856
|
+
const path = plan.skeletonPaths.textMarkerPaths.get(text.slotId);
|
|
19857
|
+
if (path)
|
|
19858
|
+
textClaimPathExprs.set(text.slotId, `__existing ? [] : [${path.join(", ")}]`);
|
|
19859
|
+
}
|
|
19860
|
+
}
|
|
19861
|
+
if (reactiveEffects !== null || preambleRegions.length > 0) {
|
|
19201
19862
|
stringifyReactiveEffects(lines, reactiveEffects, {
|
|
19202
19863
|
indent: bodyIndent,
|
|
19203
19864
|
elVar: "__el",
|
|
19204
19865
|
bodyIsMultiRoot,
|
|
19205
19866
|
elementIndexBySlot: pathPlan?.elementIndexBySlot,
|
|
19206
|
-
|
|
19867
|
+
textClaimPathExprs,
|
|
19868
|
+
preambleRegions,
|
|
19869
|
+
mapPreambleWrapped
|
|
19207
19870
|
});
|
|
19208
19871
|
}
|
|
19209
19872
|
emitLoopChildRefs(lines, childRefs, { indent: bodyIndent, elVar: "__el", bodyIsMultiRoot, elementIndexBySlot: pathPlan?.elementIndexBySlot });
|
|
19210
|
-
emitPreambleRegionEffects(lines, preambleRegions, mapPreambleWrapped, { indent: bodyIndent, elVar: "__el" });
|
|
19211
19873
|
lines.push(`${bodyIndent}return __el`);
|
|
19212
19874
|
lines.push(`${topIndent}}, '${markerId}'${loopBfId})`);
|
|
19213
19875
|
}
|
|
@@ -19316,10 +19978,13 @@ function stringifyStaticLoop(lines, plan) {
|
|
|
19316
19978
|
}
|
|
19317
19979
|
lines.push(` }`);
|
|
19318
19980
|
}
|
|
19319
|
-
|
|
19320
|
-
const
|
|
19321
|
-
|
|
19322
|
-
lines.push(`
|
|
19981
|
+
if (texts.length > 0) {
|
|
19982
|
+
const slots = texts.map((t) => ({ id: t.slotId, kind: "text", path: [] }));
|
|
19983
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
19984
|
+
lines.push(` const ${writer} = lazySlots(__iterEl, ${claimPlanLiteral(slots)})`);
|
|
19985
|
+
for (const text of texts) {
|
|
19986
|
+
lines.push(` createEffect(() => { ${writer}('${text.slotId}', String(${text.expression})) }${profileBindingId(pc, text.slotId)})`);
|
|
19987
|
+
}
|
|
19323
19988
|
}
|
|
19324
19989
|
emitLoopChildRefs(lines, childRefs, { indent: " ", elVar: "__iterEl", bodyIsMultiRoot: false });
|
|
19325
19990
|
lines.push(` }`);
|
|
@@ -19374,13 +20039,18 @@ function emitReactive(lines, inner, indent, pc) {
|
|
|
19374
20039
|
if (inner.childLevels.length > 0) {
|
|
19375
20040
|
stringifyInnerLoops(lines, inner.childLevels, `${indent} `, pc);
|
|
19376
20041
|
}
|
|
19377
|
-
|
|
20042
|
+
const conditionalTexts = emit.reactiveTexts.filter((t) => t.insideConditional);
|
|
20043
|
+
const plainTexts = emit.reactiveTexts.filter((t) => !t.insideConditional);
|
|
20044
|
+
for (const text of conditionalTexts) {
|
|
19378
20045
|
const bf = profileBindingId(pc, text.slotId);
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
|
|
19382
|
-
|
|
19383
|
-
|
|
20046
|
+
lines.push(`${indent} createEffect(() => { claimSlots(__innerEl${uid}, [{ id: '${text.slotId}', kind: 'text', path: [] }]).write('${text.slotId}', String(${text.wrappedExpression})) }${bf})`);
|
|
20047
|
+
}
|
|
20048
|
+
if (plainTexts.length > 0) {
|
|
20049
|
+
const slots = plainTexts.map((t) => ({ id: t.slotId, kind: "text", path: [] }));
|
|
20050
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
20051
|
+
lines.push(`${indent} const ${writer} = lazySlots(__innerEl${uid}, ${claimPlanLiteral(slots)})`);
|
|
20052
|
+
for (const text of plainTexts) {
|
|
20053
|
+
lines.push(`${indent} createEffect(() => { ${writer}('${text.slotId}', String(${text.wrappedExpression})) }${profileBindingId(pc, text.slotId)})`);
|
|
19384
20054
|
}
|
|
19385
20055
|
}
|
|
19386
20056
|
for (const attr of emit.reactiveAttrs) {
|
|
@@ -19730,6 +20400,23 @@ function emitPlain(lines, plan) {
|
|
|
19730
20400
|
stringifyEventDelegation(lines, eventDelegation);
|
|
19731
20401
|
return;
|
|
19732
20402
|
}
|
|
20403
|
+
if (plan.lazyRow) {
|
|
20404
|
+
stringifyLazyRowLoop(lines, {
|
|
20405
|
+
indent: " ",
|
|
20406
|
+
containerVar,
|
|
20407
|
+
guardContainer: true,
|
|
20408
|
+
markerId,
|
|
20409
|
+
arrayExpr,
|
|
20410
|
+
keyFn,
|
|
20411
|
+
paramHead,
|
|
20412
|
+
indexParam,
|
|
20413
|
+
template,
|
|
20414
|
+
lazyRow: plan.lazyRow
|
|
20415
|
+
});
|
|
20416
|
+
lines.push(` }))`);
|
|
20417
|
+
stringifyEventDelegation(lines, eventDelegation);
|
|
20418
|
+
return;
|
|
20419
|
+
}
|
|
19733
20420
|
if (reactiveEffects === null && !bodyIsMultiRoot && childRefs.length === 0 && preambleRegions.length === 0) {
|
|
19734
20421
|
const cloneExpr = emitTemplateCloneInline(template);
|
|
19735
20422
|
if (mapPreambleWrapped) {
|
|
@@ -19751,11 +20438,16 @@ function emitPlain(lines, plan) {
|
|
|
19751
20438
|
indent: " ",
|
|
19752
20439
|
singleRootLayout: "inline"
|
|
19753
20440
|
});
|
|
19754
|
-
if (reactiveEffects !== null) {
|
|
19755
|
-
stringifyReactiveEffects(lines, reactiveEffects, {
|
|
20441
|
+
if (reactiveEffects !== null || preambleRegions.length > 0) {
|
|
20442
|
+
stringifyReactiveEffects(lines, reactiveEffects, {
|
|
20443
|
+
indent: " ",
|
|
20444
|
+
elVar: "__el",
|
|
20445
|
+
bodyIsMultiRoot,
|
|
20446
|
+
preambleRegions,
|
|
20447
|
+
mapPreambleWrapped
|
|
20448
|
+
});
|
|
19756
20449
|
}
|
|
19757
20450
|
emitLoopChildRefs(lines, childRefs, { indent: " ", elVar: "__el", bodyIsMultiRoot });
|
|
19758
|
-
emitPreambleRegionEffects(lines, preambleRegions, mapPreambleWrapped, { indent: " ", elVar: "__el" });
|
|
19759
20451
|
lines.push(` return __el`);
|
|
19760
20452
|
lines.push(` }, '${markerId}'${loopBfId})`);
|
|
19761
20453
|
}
|
|
@@ -19841,13 +20533,13 @@ function emitArmBody(lines, body, mode, indent, profileComponentName) {
|
|
|
19841
20533
|
}
|
|
19842
20534
|
lines.push(`${indent}} }`);
|
|
19843
20535
|
}
|
|
19844
|
-
|
|
19845
|
-
const
|
|
19846
|
-
|
|
19847
|
-
lines.push(`${indent}
|
|
19848
|
-
|
|
19849
|
-
|
|
19850
|
-
|
|
20536
|
+
if (body.textEffects.length > 0) {
|
|
20537
|
+
const slots = body.textEffects.map((te) => ({ id: te.slotId, kind: "markup", path: [] }));
|
|
20538
|
+
const writer = claimWriterVarName(slots, varSlotId);
|
|
20539
|
+
lines.push(`${indent}const ${writer} = lazySlots(__branchScope, ${claimPlanLiteral(slots)})`);
|
|
20540
|
+
for (const te of body.textEffects) {
|
|
20541
|
+
lines.push(`${indent}__disposers.push(createDisposableEffect(() => { ${writer}('${te.slotId}', escapeTextOrNode(${te.expression})) }${bindingBfId(te.slotId)}))`);
|
|
20542
|
+
}
|
|
19851
20543
|
}
|
|
19852
20544
|
if (body.loops.length > 0) {
|
|
19853
20545
|
stringifyBranchLoops(lines, body.loops);
|
|
@@ -19923,7 +20615,7 @@ function buildComponentLoopPlan(elem, profileComponentName) {
|
|
|
19923
20615
|
// src/ir-to-client-js/control-flow/plan/build-loop.ts
|
|
19924
20616
|
function buildLoopPlan(elem, opts) {
|
|
19925
20617
|
if (elem.bodyIsItemConditional) {
|
|
19926
|
-
return buildPlainLoopPlan(elem, opts.profileComponentName);
|
|
20618
|
+
return buildPlainLoopPlan(elem, opts.profileComponentName, opts.lazyScope);
|
|
19927
20619
|
}
|
|
19928
20620
|
if (elem.isStaticArray) {
|
|
19929
20621
|
return buildStaticLoopPlan(elem, opts.unsafeLocalNames, opts.profileComponentName);
|
|
@@ -19935,9 +20627,9 @@ function buildLoopPlan(elem, opts) {
|
|
|
19935
20627
|
if (elem.childComponent) {
|
|
19936
20628
|
return buildComponentLoopPlan(elem, opts.profileComponentName);
|
|
19937
20629
|
}
|
|
19938
|
-
return buildPlainLoopPlan(elem, opts.profileComponentName);
|
|
20630
|
+
return buildPlainLoopPlan(elem, opts.profileComponentName, opts.lazyScope);
|
|
19939
20631
|
}
|
|
19940
|
-
function buildPlainLoopPlan(elem, profileComponentName) {
|
|
20632
|
+
function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
|
|
19941
20633
|
const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings);
|
|
19942
20634
|
const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
|
|
19943
20635
|
const hasReactive2 = elem.bindings.reactiveAttrs.length > 0 || elem.bindings.reactiveTexts.length > 0 || elem.bindings.conditionals.length > 0;
|
|
@@ -19964,27 +20656,43 @@ function buildPlainLoopPlan(elem, profileComponentName) {
|
|
|
19964
20656
|
preambleRegions: []
|
|
19965
20657
|
};
|
|
19966
20658
|
}
|
|
20659
|
+
const arrayExpr = buildChainedArrayExpr(elem);
|
|
20660
|
+
const indexParam = elem.index || "__idx";
|
|
20661
|
+
const mapPreambleWrapped = elem.preamble ? renderPreamble(elem.preamble, {
|
|
20662
|
+
transformJs: wrap,
|
|
20663
|
+
renderLeaf: (ir) => irToHtmlTemplate(ir, undefined, 1, [{ param: elem.param, bindings: elem.paramBindings }], undefined, true)
|
|
20664
|
+
}) : "";
|
|
20665
|
+
const preambleRegions = buildPreambleRegionPlans(elem.preambleRegions, elem.param, elem.paramBindings);
|
|
19967
20666
|
return {
|
|
19968
20667
|
kind: "plain",
|
|
19969
20668
|
rowConstruction: "string-template",
|
|
19970
20669
|
containerVar: `_${varSlotId(elem.slotId)}`,
|
|
19971
20670
|
markerId: elem.markerId,
|
|
19972
20671
|
profileLoopId: profileComponentName ? `${profileComponentName}#binding:${elem.slotId}` : undefined,
|
|
19973
|
-
arrayExpr
|
|
20672
|
+
arrayExpr,
|
|
19974
20673
|
keyFn: loopKeyFn(elem),
|
|
19975
20674
|
paramHead,
|
|
19976
20675
|
paramUnwrap,
|
|
19977
|
-
indexParam
|
|
19978
|
-
|
|
19979
|
-
|
|
19980
|
-
|
|
19981
|
-
|
|
20676
|
+
indexParam,
|
|
20677
|
+
lazyRow: buildLazyRowPlan({
|
|
20678
|
+
loop: elem,
|
|
20679
|
+
arrayExpr,
|
|
20680
|
+
indexParam,
|
|
20681
|
+
paramUnwrap,
|
|
20682
|
+
mapPreambleWrapped,
|
|
20683
|
+
preambleRegionCount: preambleRegions.length,
|
|
20684
|
+
callSite: "plain",
|
|
20685
|
+
flatMapLeafItem: false,
|
|
20686
|
+
anchored: elem.bodyIsItemConditional ?? false,
|
|
20687
|
+
scope: lazyScope
|
|
20688
|
+
}) ?? undefined,
|
|
20689
|
+
mapPreambleWrapped,
|
|
19982
20690
|
template: elem.template,
|
|
19983
20691
|
skeletonTemplate: elem.skeletonTemplate,
|
|
19984
20692
|
skeletonPaths: elem.skeletonPaths,
|
|
19985
20693
|
reactiveEffects: hasReactive2 ? buildLoopReactiveEffectsPlan(elem, profileComponentName) : null,
|
|
19986
20694
|
childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
|
|
19987
|
-
preambleRegions
|
|
20695
|
+
preambleRegions,
|
|
19988
20696
|
bodyIsMultiRoot: elem.bodyIsMultiRoot ?? false,
|
|
19989
20697
|
anchored: elem.bodyIsItemConditional ?? false,
|
|
19990
20698
|
anchorKeyExpr: elem.key ? wrap(elem.key) : elem.index || "__idx"
|
|
@@ -20039,7 +20747,7 @@ function buildStaticLoopMaterialize(elem, unsafeLocalNames) {
|
|
|
20039
20747
|
function emitConditionalUpdates(lines, ctx) {
|
|
20040
20748
|
const profileComponentName = ctx.profile ? ctx.componentName : undefined;
|
|
20041
20749
|
for (const elem of ctx.conditionalElements) {
|
|
20042
|
-
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "dom", profileComponentName });
|
|
20750
|
+
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "dom", profileComponentName, lazyScope: buildLazyRowScopeInfo(ctx) });
|
|
20043
20751
|
stringifyInsert(lines, plan, { leadingIndent: " ", bodyIndent: " " });
|
|
20044
20752
|
lines.push("");
|
|
20045
20753
|
}
|
|
@@ -20047,17 +20755,19 @@ function emitConditionalUpdates(lines, ctx) {
|
|
|
20047
20755
|
function emitClientOnlyConditionals(lines, ctx) {
|
|
20048
20756
|
const profileComponentName = ctx.profile ? ctx.componentName : undefined;
|
|
20049
20757
|
for (const elem of ctx.clientOnlyConditionals) {
|
|
20050
|
-
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "raw", profileComponentName });
|
|
20758
|
+
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "raw", profileComponentName, lazyScope: buildLazyRowScopeInfo(ctx) });
|
|
20051
20759
|
lines.push(` // @client conditional: ${elem.slotId}`);
|
|
20052
20760
|
stringifyInsert(lines, plan, { leadingIndent: " ", bodyIndent: " " });
|
|
20053
20761
|
lines.push("");
|
|
20054
20762
|
}
|
|
20055
20763
|
}
|
|
20056
20764
|
function emitLoopUpdates(lines, ctx, unsafeLocalNames) {
|
|
20765
|
+
const lazyScope = buildLazyRowScopeInfo(ctx);
|
|
20057
20766
|
for (const elem of ctx.loopElements) {
|
|
20058
20767
|
const plan = buildLoopPlan(elem, {
|
|
20059
20768
|
unsafeLocalNames,
|
|
20060
|
-
profileComponentName: ctx.profile ? ctx.componentName : undefined
|
|
20769
|
+
profileComponentName: ctx.profile ? ctx.componentName : undefined,
|
|
20770
|
+
lazyScope
|
|
20061
20771
|
});
|
|
20062
20772
|
internalInvariant(!(elem.preamble && elem.preamble.builderNames.length > 0 && plan.rowConstruction === "dom-ops"), `loop variant '${plan.kind}' declares dom-ops row construction but received a JSX-bearing preamble — add a Phase-1 refusal (or wire renderPreamble support) for this shape`);
|
|
20063
20773
|
stringifyLoop(lines, plan);
|
|
@@ -20079,7 +20789,6 @@ function emitLoopEventDelegation(lines, elem, kind, profileComponentName) {
|
|
|
20079
20789
|
// src/ir-to-client-js/element-refs.ts
|
|
20080
20790
|
function generateElementRefs(ctx) {
|
|
20081
20791
|
const regularSlots = new Set;
|
|
20082
|
-
const textSlots = new Set;
|
|
20083
20792
|
const componentSlots = new Set;
|
|
20084
20793
|
const conditionalSlotIds = collectConditionalSlotIds(ctx);
|
|
20085
20794
|
for (const elem of ctx.interactiveElements) {
|
|
@@ -20087,11 +20796,6 @@ function generateElementRefs(ctx) {
|
|
|
20087
20796
|
regularSlots.add(elem.slotId);
|
|
20088
20797
|
}
|
|
20089
20798
|
}
|
|
20090
|
-
for (const elem of ctx.dynamicElements) {
|
|
20091
|
-
if (!elem.insideConditional) {
|
|
20092
|
-
textSlots.add(elem.slotId);
|
|
20093
|
-
}
|
|
20094
|
-
}
|
|
20095
20799
|
for (const elem of ctx.conditionalElements) {
|
|
20096
20800
|
regularSlots.add(elem.slotId);
|
|
20097
20801
|
}
|
|
@@ -20120,11 +20824,10 @@ function generateElementRefs(ctx) {
|
|
|
20120
20824
|
for (const slotId of componentSlots) {
|
|
20121
20825
|
regularSlots.delete(slotId);
|
|
20122
20826
|
}
|
|
20123
|
-
if (regularSlots.size === 0 &&
|
|
20827
|
+
if (regularSlots.size === 0 && componentSlots.size === 0)
|
|
20124
20828
|
return "";
|
|
20125
20829
|
const refLines = [];
|
|
20126
20830
|
emitSlotRefs(refLines, [...regularSlots], "$");
|
|
20127
|
-
emitSlotRefs(refLines, [...textSlots], "$t");
|
|
20128
20831
|
emitSlotRefs(refLines, [...componentSlots], "$c");
|
|
20129
20832
|
return refLines.join(`
|
|
20130
20833
|
`);
|
|
@@ -20680,6 +21383,111 @@ ${externalImports.join(`
|
|
|
20680
21383
|
return generatedCode.replace(IMPORT_PLACEHOLDER, allImports);
|
|
20681
21384
|
}
|
|
20682
21385
|
|
|
21386
|
+
// src/ir-to-client-js/client-only-elision.ts
|
|
21387
|
+
function decideClientOnlyElision(root) {
|
|
21388
|
+
walkNode(root, [], new Set, { bailed: false });
|
|
21389
|
+
}
|
|
21390
|
+
function walkNode(node, path, forceCloseAncestors, state) {
|
|
21391
|
+
if (state.bailed)
|
|
21392
|
+
return;
|
|
21393
|
+
if (node.type === "element") {
|
|
21394
|
+
if (!elementIsPathSafe(node.tag, flattenSkeletonChildren(node.children))) {
|
|
21395
|
+
state.bailed = true;
|
|
21396
|
+
return;
|
|
21397
|
+
}
|
|
21398
|
+
const groupIdx = skeletonForceCloseGroup(node.tag);
|
|
21399
|
+
if (groupIdx >= 0 && forceCloseAncestors.has(groupIdx)) {
|
|
21400
|
+
state.bailed = true;
|
|
21401
|
+
return;
|
|
21402
|
+
}
|
|
21403
|
+
const nextAncestors = groupIdx >= 0 ? new Set([...forceCloseAncestors, groupIdx]) : forceCloseAncestors;
|
|
21404
|
+
walkChildren(flattenSkeletonChildren(node.children), path, nextAncestors, state);
|
|
21405
|
+
} else if (node.type === "fragment") {
|
|
21406
|
+
walkChildren(flattenSkeletonChildren(node.children), path, forceCloseAncestors, state);
|
|
21407
|
+
}
|
|
21408
|
+
}
|
|
21409
|
+
function walkChildren(children, parentPath, forceCloseAncestors, state) {
|
|
21410
|
+
let frozen = false;
|
|
21411
|
+
let idx = 0;
|
|
21412
|
+
let pendingText = false;
|
|
21413
|
+
for (let i = 0;i < children.length; i++) {
|
|
21414
|
+
if (state.bailed)
|
|
21415
|
+
return;
|
|
21416
|
+
const child = children[i];
|
|
21417
|
+
switch (child.type) {
|
|
21418
|
+
case "text": {
|
|
21419
|
+
if (child.value === "")
|
|
21420
|
+
continue;
|
|
21421
|
+
if (!pendingText)
|
|
21422
|
+
idx += 1;
|
|
21423
|
+
pendingText = true;
|
|
21424
|
+
continue;
|
|
21425
|
+
}
|
|
21426
|
+
case "expression": {
|
|
21427
|
+
if (child.expr === "null" || child.expr === "undefined")
|
|
21428
|
+
continue;
|
|
21429
|
+
if (child.clientOnly && child.slotId) {
|
|
21430
|
+
const adjacent = isTextLike(children[i - 1]) || isTextLike(children[i + 1]);
|
|
21431
|
+
if (!frozen && !adjacent) {
|
|
21432
|
+
markElided(child, [...parentPath, idx]);
|
|
21433
|
+
frozen = true;
|
|
21434
|
+
} else {
|
|
21435
|
+
frozen = true;
|
|
21436
|
+
}
|
|
21437
|
+
idx += 1;
|
|
21438
|
+
pendingText = false;
|
|
21439
|
+
continue;
|
|
21440
|
+
}
|
|
21441
|
+
frozen = true;
|
|
21442
|
+
idx += 1;
|
|
21443
|
+
pendingText = false;
|
|
21444
|
+
continue;
|
|
21445
|
+
}
|
|
21446
|
+
case "element": {
|
|
21447
|
+
if (!elementIsPathSafe(child.tag, flattenSkeletonChildren(child.children))) {
|
|
21448
|
+
state.bailed = true;
|
|
21449
|
+
return;
|
|
21450
|
+
}
|
|
21451
|
+
if (!frozen) {
|
|
21452
|
+
walkNode(child, [...parentPath, idx], forceCloseAncestors, state);
|
|
21453
|
+
}
|
|
21454
|
+
idx += 1;
|
|
21455
|
+
pendingText = false;
|
|
21456
|
+
continue;
|
|
21457
|
+
}
|
|
21458
|
+
case "fragment":
|
|
21459
|
+
continue;
|
|
21460
|
+
default:
|
|
21461
|
+
frozen = true;
|
|
21462
|
+
idx += 1;
|
|
21463
|
+
pendingText = false;
|
|
21464
|
+
continue;
|
|
21465
|
+
}
|
|
21466
|
+
}
|
|
21467
|
+
}
|
|
21468
|
+
function isTextLike(node) {
|
|
21469
|
+
if (!node)
|
|
21470
|
+
return false;
|
|
21471
|
+
if (node.type === "text")
|
|
21472
|
+
return node.value !== "";
|
|
21473
|
+
if (node.type === "expression")
|
|
21474
|
+
return node.expr !== "null" && node.expr !== "undefined";
|
|
21475
|
+
return false;
|
|
21476
|
+
}
|
|
21477
|
+
function markElided(expr, path) {
|
|
21478
|
+
expr.markerless = true;
|
|
21479
|
+
expr.elidedPath = path;
|
|
21480
|
+
}
|
|
21481
|
+
function elementIsPathSafe(tag, flatChildren) {
|
|
21482
|
+
if (SKELETON_PATH_HAZARD_TAGS.has(tag))
|
|
21483
|
+
return false;
|
|
21484
|
+
if (VOID_ELEMENTS.has(tag) && flatChildren.length > 0)
|
|
21485
|
+
return false;
|
|
21486
|
+
if (tag === "tr" && hasForeignTableRowContent(flatChildren))
|
|
21487
|
+
return false;
|
|
21488
|
+
return true;
|
|
21489
|
+
}
|
|
21490
|
+
|
|
20683
21491
|
// src/css-layer-prefixer.ts
|
|
20684
21492
|
function prefixClass(cls, layerName) {
|
|
20685
21493
|
if (!cls || cls.startsWith("layer-"))
|
|
@@ -21972,7 +22780,7 @@ function checkRichTypeMethodCalls(root, metadata, errors) {
|
|
|
21972
22780
|
return;
|
|
21973
22781
|
const matchers = prepareLoweringMatchers(metadata);
|
|
21974
22782
|
const seen = new Set;
|
|
21975
|
-
|
|
22783
|
+
walkNode2(root, metadata, EMPTY_BINDINGS2, matchers, errors, seen);
|
|
21976
22784
|
}
|
|
21977
22785
|
function isLoweringClaimed(matchers, callee, args) {
|
|
21978
22786
|
return matchers.some((m) => m(callee, args) !== null);
|
|
@@ -22109,7 +22917,7 @@ function walkAttrValue(value, clientOnly, loc, meta, bindings, matchers, errors,
|
|
|
22109
22917
|
walkTemplateParts(value.parts, loc, meta, bindings, matchers, errors, seen);
|
|
22110
22918
|
}
|
|
22111
22919
|
}
|
|
22112
|
-
function
|
|
22920
|
+
function walkNode2(node, meta, bindings, matchers, errors, seen) {
|
|
22113
22921
|
if (node.type === "expression") {
|
|
22114
22922
|
if (!node.clientOnly && node.parsed)
|
|
22115
22923
|
checkExpr(node.parsed, node.loc, meta, bindings, matchers, errors, seen);
|
|
@@ -22135,12 +22943,12 @@ function walkNode(node, meta, bindings, matchers, errors, seen) {
|
|
|
22135
22943
|
case "fragment":
|
|
22136
22944
|
case "provider":
|
|
22137
22945
|
for (const child of node.children)
|
|
22138
|
-
|
|
22946
|
+
walkNode2(child, meta, bindings, matchers, errors, seen);
|
|
22139
22947
|
break;
|
|
22140
22948
|
case "async":
|
|
22141
|
-
|
|
22949
|
+
walkNode2(node.fallback, meta, bindings, matchers, errors, seen);
|
|
22142
22950
|
for (const child of node.children)
|
|
22143
|
-
|
|
22951
|
+
walkNode2(child, meta, bindings, matchers, errors, seen);
|
|
22144
22952
|
break;
|
|
22145
22953
|
case "loop": {
|
|
22146
22954
|
if (node.clientOnly)
|
|
@@ -22153,35 +22961,35 @@ function walkNode(node, meta, bindings, matchers, errors, seen) {
|
|
|
22153
22961
|
if (node.index)
|
|
22154
22962
|
loopBindings.set(node.index, null);
|
|
22155
22963
|
for (const child of node.children)
|
|
22156
|
-
|
|
22964
|
+
walkNode2(child, meta, loopBindings, matchers, errors, seen);
|
|
22157
22965
|
if (node.childComponent) {
|
|
22158
22966
|
for (const child of node.childComponent.children)
|
|
22159
|
-
|
|
22967
|
+
walkNode2(child, meta, loopBindings, matchers, errors, seen);
|
|
22160
22968
|
}
|
|
22161
22969
|
for (const nested of node.nestedComponents ?? []) {
|
|
22162
22970
|
for (const child of nested.children)
|
|
22163
|
-
|
|
22971
|
+
walkNode2(child, meta, loopBindings, matchers, errors, seen);
|
|
22164
22972
|
}
|
|
22165
22973
|
for (const seg of node.flatMapCallback?.segments ?? []) {
|
|
22166
22974
|
if (seg.kind === "jsx")
|
|
22167
|
-
|
|
22975
|
+
walkNode2(seg.ir, meta, loopBindings, matchers, errors, seen);
|
|
22168
22976
|
}
|
|
22169
22977
|
for (const seg of node.preamble?.segments ?? []) {
|
|
22170
22978
|
if (seg.kind === "jsx")
|
|
22171
|
-
|
|
22979
|
+
walkNode2(seg.ir, meta, loopBindings, matchers, errors, seen);
|
|
22172
22980
|
}
|
|
22173
22981
|
break;
|
|
22174
22982
|
}
|
|
22175
22983
|
case "conditional":
|
|
22176
22984
|
if (node.clientOnly)
|
|
22177
22985
|
break;
|
|
22178
|
-
|
|
22179
|
-
|
|
22986
|
+
walkNode2(node.whenTrue, meta, bindings, matchers, errors, seen);
|
|
22987
|
+
walkNode2(node.whenFalse, meta, bindings, matchers, errors, seen);
|
|
22180
22988
|
break;
|
|
22181
22989
|
case "if-statement":
|
|
22182
|
-
|
|
22990
|
+
walkNode2(node.consequent, meta, bindings, matchers, errors, seen);
|
|
22183
22991
|
if (node.alternate)
|
|
22184
|
-
|
|
22992
|
+
walkNode2(node.alternate, meta, bindings, matchers, errors, seen);
|
|
22185
22993
|
break;
|
|
22186
22994
|
}
|
|
22187
22995
|
}
|
|
@@ -22247,6 +23055,7 @@ function compileMultipleComponents(source, filePath, componentNames, options) {
|
|
|
22247
23055
|
};
|
|
22248
23056
|
componentIR.metadata.clientAnalysis = analyzeClientNeeds(componentIR);
|
|
22249
23057
|
checkRichTypeMethodCalls(componentIR.root, componentIR.metadata, errors);
|
|
23058
|
+
decideClientOnlyElision(componentIR.root);
|
|
22250
23059
|
if (options.cssLayerPrefix) {
|
|
22251
23060
|
applyCssLayerPrefix(componentIR, options.cssLayerPrefix);
|
|
22252
23061
|
}
|
|
@@ -22586,6 +23395,7 @@ function compileJSX(source, filePath, options) {
|
|
|
22586
23395
|
};
|
|
22587
23396
|
componentIR.metadata.clientAnalysis = analyzeClientNeeds(componentIR);
|
|
22588
23397
|
checkRichTypeMethodCalls(componentIR.root, componentIR.metadata, errors);
|
|
23398
|
+
decideClientOnlyElision(componentIR.root);
|
|
22589
23399
|
if (ctx.importedClientSignalNames.size > 0) {
|
|
22590
23400
|
const sources = new Set;
|
|
22591
23401
|
for (const imp of ctx.imports) {
|
|
@@ -26653,6 +27463,7 @@ export {
|
|
|
26653
27463
|
diffStaticBudget,
|
|
26654
27464
|
diffProfiles,
|
|
26655
27465
|
describeFallback,
|
|
27466
|
+
decideClientOnlyElision,
|
|
26656
27467
|
dangerousInnerHtmlMetacharViolation,
|
|
26657
27468
|
dangerousInnerHtmlDiagnostic,
|
|
26658
27469
|
createProgramForFile,
|