@barefootjs/cli 0.27.0 → 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/index.js +664 -38
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -11161,7 +11161,8 @@ function transformConditionalBranch(node, ctx2) {
|
|
|
11161
11161
|
const callsReactive = exprCallsReactiveGetters(node, ctx2);
|
|
11162
11162
|
const hasCalls = exprHasFunctionCalls(node);
|
|
11163
11163
|
const reactive = isReactiveExpression(exprText, ctx2, node) || isReactiveOrigin(branchOrigin);
|
|
11164
|
-
const
|
|
11164
|
+
const refsLoopParam = branchOrigin.freeRefs?.some((r2) => r2.kind === "render-item") ?? false;
|
|
11165
|
+
const needsSlot = reactive || callsReactive || refsLoopParam;
|
|
11165
11166
|
const slotId = needsSlot ? generateSlotId(ctx2) : null;
|
|
11166
11167
|
return {
|
|
11167
11168
|
type: "expression",
|
|
@@ -14761,19 +14762,54 @@ function summarizeLoopChildBranch(node, ctx2, siblingOffsets, loopParam, loopPar
|
|
|
14761
14762
|
// on the branch root yields exactly this branch's direct bindings
|
|
14762
14763
|
// without re-collecting what a nested arm already owns (#2347).
|
|
14763
14764
|
reactiveAttrs: collectLoopChildReactiveAttrs(node, ctx2, loopParam, loopParamBindings, true),
|
|
14764
|
-
// Skip when the branch's
|
|
14765
|
-
// (no wrapping element)
|
|
14766
|
-
//
|
|
14767
|
-
//
|
|
14768
|
-
//
|
|
14769
|
-
//
|
|
14770
|
-
//
|
|
14771
|
-
// and the
|
|
14772
|
-
//
|
|
14773
|
-
//
|
|
14774
|
-
//
|
|
14775
|
-
//
|
|
14776
|
-
|
|
14765
|
+
// Skip ONLY when the branch's entire content is a single bare
|
|
14766
|
+
// `expression` (no wrapping element) that MAY yield a live DOM node —
|
|
14767
|
+
// i.e. it contains a call anywhere (`node.hasFunctionCalls`, computed
|
|
14768
|
+
// by the AST walk in `exprHasFunctionCalls`/jsx-to-ir.ts, recursively —
|
|
14769
|
+
// catches a call nested in a template literal or a nested ternary, not
|
|
14770
|
+
// just a top-level call). A call can return an Element (a hoisted
|
|
14771
|
+
// `renderNode={(n) => <Pill/>}` callback lowered to a component call,
|
|
14772
|
+
// #1211/#1213) and the compiler cannot tell from syntax whether it does
|
|
14773
|
+
// — both `renderChild(...)` and `_p.renderCell(...)` are a
|
|
14774
|
+
// `CallExpression` — so this stays conservative for ANY call, not just
|
|
14775
|
+
// ones known to return JSX. Re-evaluating a non-idempotent call inside
|
|
14776
|
+
// an *additional* nested createEffect (on top of the eval already done
|
|
14777
|
+
// for the `__bfSlot`-wrapped splice whenever `insert()` (re-)mounts this
|
|
14778
|
+
// branch) would call it again on every unrelated tick and discard the
|
|
14779
|
+
// previous element's listeners/state.
|
|
14780
|
+
//
|
|
14781
|
+
// Everything else — a property access (`row.label`), an identifier, a
|
|
14782
|
+
// literal, a template literal, string concatenation, or a nested
|
|
14783
|
+
// ternary of those — cannot itself construct a DOM node (only a JSX
|
|
14784
|
+
// literal or a call can, and a JSX literal branch is never `type:
|
|
14785
|
+
// 'expression'` in the first place — see `transformJsxExpression`), so
|
|
14786
|
+
// it is safe to collect. This is the fix for the loop-branch-stale-text
|
|
14787
|
+
// defect: a keyed loop row whose branch is e.g. `row.done ? row.label :
|
|
14788
|
+
// 'pending'` previously had NO update path at all when `row.label`
|
|
14789
|
+
// changed without `row.done` flipping — `insert()` (runtime/insert.ts)
|
|
14790
|
+
// correctly no-ops when its condition is unchanged (branch-internal
|
|
14791
|
+
// updates are deliberately the effect system's job, not DOM
|
|
14792
|
+
// replacement's), but with reactiveTexts always `[]` for this shape,
|
|
14793
|
+
// no effect existed either, so the branch was frozen at its mount-time
|
|
14794
|
+
// value. The stale rationale in a prior version of this comment blamed
|
|
14795
|
+
// "the loop-child arm's `$t()`-based anchor lookup", but `$t()` no
|
|
14796
|
+
// longer exists — it was one of four content mechanisms deleted by the
|
|
14797
|
+
// slot-unification work. The current claim door
|
|
14798
|
+
// (`stringifyLoopChildArm` → `lazySlots(..., kind: 'markup')` →
|
|
14799
|
+
// `writeMarkup`, runtime/claim-slots.ts) clears the claimed range and
|
|
14800
|
+
// splices the Node by identity, so "lands beside the first" cannot
|
|
14801
|
+
// happen through it; only the call's non-idempotence still applies, and
|
|
14802
|
+
// that alone is why the skip narrows rather than disappears.
|
|
14803
|
+
//
|
|
14804
|
+
// Collecting here is necessary but not sufficient: `n.slotId` must also
|
|
14805
|
+
// be set for `collectLoopChildReactiveTexts` (ir-to-client-js/
|
|
14806
|
+
// reactivity.ts) to do anything — see `transformConditionalBranch`'s
|
|
14807
|
+
// `refsLoopParam` check (jsx-to-ir.ts) for the matching half of this fix
|
|
14808
|
+
// that gives a bare loop-item-reading branch a slotId at all, which also
|
|
14809
|
+
// makes `irToHtmlTemplate` emit its `<!--bf:sN-->…<!--/-->` marker (the
|
|
14810
|
+
// same call builds both the SSR and the CSR/hydration template, so the
|
|
14811
|
+
// two can't disagree on shape).
|
|
14812
|
+
reactiveTexts: node.type === "expression" && node.hasFunctionCalls ? [] : collectLoopChildReactiveTexts(node, ctx2, loopParam, loopParamBindings, true)
|
|
14777
14813
|
};
|
|
14778
14814
|
}
|
|
14779
14815
|
var EMPTY_RENDER_EXPRS, branchInnerLoopOptions;
|
|
@@ -15339,6 +15375,7 @@ var init_imports = __esm({
|
|
|
15339
15375
|
"getLoopNodes",
|
|
15340
15376
|
"mapArray",
|
|
15341
15377
|
"mapArrayAnchored",
|
|
15378
|
+
"mapArrayLazy",
|
|
15342
15379
|
"patchLeaf",
|
|
15343
15380
|
"createDisposableEffect",
|
|
15344
15381
|
"createComponent",
|
|
@@ -15370,8 +15407,16 @@ var init_imports = __esm({
|
|
|
15370
15407
|
// Claim-plan interpreter (slot unification A2/A3, spec/slot-unification.md)
|
|
15371
15408
|
// — the "one claim mechanism" that replaced `patchSlotRange` and
|
|
15372
15409
|
// `updateClientMarker` (both deleted) as the content-slot update door.
|
|
15410
|
+
// `lazyClaimSlots` is the read-capable twin of `lazySlots` over the same
|
|
15411
|
+
// claim — emitted only by lazy loops that seed an outer-involving TEXT
|
|
15412
|
+
// binding by read-compare-write (§9.3(1)).
|
|
15413
|
+
// `textOrNode` is the 'text' door's Node guard: a child-position value that
|
|
15414
|
+
// turns out to be a live Node must reach the writer as a Node so the claim
|
|
15415
|
+
// can promote to 'markup', never as `String(node)`.
|
|
15373
15416
|
"claimSlots",
|
|
15374
15417
|
"lazySlots",
|
|
15418
|
+
"lazyClaimSlots",
|
|
15419
|
+
"textOrNode",
|
|
15375
15420
|
// Profile mode (#1690, SR3) — turn-boundary markers around event handlers.
|
|
15376
15421
|
"beginTurn",
|
|
15377
15422
|
"endTurn",
|
|
@@ -18494,8 +18539,340 @@ var init_build_event_delegation = __esm({
|
|
|
18494
18539
|
}
|
|
18495
18540
|
});
|
|
18496
18541
|
|
|
18542
|
+
// ../jsx/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts
|
|
18543
|
+
function lazyRowEligibility(args2) {
|
|
18544
|
+
const { shape, bindings, arraySourceIdentifiers, scope } = args2;
|
|
18545
|
+
if (scope.profile) return NO("profile mode keeps the granular eager emission");
|
|
18546
|
+
if (shape.callSite !== "plain" && shape.callSite !== "branch-plain") {
|
|
18547
|
+
return NO(`call site '${shape.callSite}' is not a plain loop row`);
|
|
18548
|
+
}
|
|
18549
|
+
if (shape.flatMapLeafItem) return NO("flatMap descriptor loop (build-or-patch renderItem)");
|
|
18550
|
+
if (shape.anchored) return NO("anchored whole-item-conditional loop");
|
|
18551
|
+
if (shape.bodyIsMultiRoot) return NO("multi-root (Fragment) row");
|
|
18552
|
+
if (!shape.hasExplicitKey) return NO("index-keyed loop (no explicit key)");
|
|
18553
|
+
if (shape.conditionalCount > 0) return NO("row contains a reactive conditional");
|
|
18554
|
+
if (shape.childRefCount > 0) return NO("row has imperative child refs");
|
|
18555
|
+
if (shape.hasChildComponent) return NO("row body is a child component");
|
|
18556
|
+
if (shape.nestedComponentCount > 0) return NO("row contains nested child components");
|
|
18557
|
+
if (shape.innerLoopCount > 0) return NO("row contains an inner loop");
|
|
18558
|
+
if (shape.hasMapPreamble) return NO("row has a map-callback preamble (may declare row-local reactivity)");
|
|
18559
|
+
if (shape.preambleRegionCount > 0) return NO("row has preamble-patched regions");
|
|
18560
|
+
if (shape.hasParamUnwrap) return NO("destructured loop param without param bindings");
|
|
18561
|
+
for (const b of bindings) {
|
|
18562
|
+
if (b.referencesIndex) {
|
|
18563
|
+
return NO(`binding on slot ${b.slotId} references the loop index parameter`);
|
|
18564
|
+
}
|
|
18565
|
+
if (b.opaqueOuterNames.includes(UNKNOWN_IDENTIFIERS)) {
|
|
18566
|
+
return NO(`binding on slot ${b.slotId} has no analyzable identifier set`);
|
|
18567
|
+
}
|
|
18568
|
+
}
|
|
18569
|
+
if (!arraySourceIdentifiers) return NO("loop source free identifiers unavailable");
|
|
18570
|
+
const sourceGate = checkSourceConsistency(arraySourceIdentifiers, scope);
|
|
18571
|
+
if (sourceGate) return NO(`loop source is not provably hydration-consistent: ${sourceGate}`);
|
|
18572
|
+
return { eligible: true };
|
|
18573
|
+
}
|
|
18574
|
+
function checkSourceConsistency(names, scope) {
|
|
18575
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18576
|
+
const resolve12 = (name2) => {
|
|
18577
|
+
if (seen.has(name2)) return null;
|
|
18578
|
+
seen.add(name2);
|
|
18579
|
+
if (scope.props.has(name2)) return null;
|
|
18580
|
+
if (PURE_SOURCE_GLOBALS.has(name2)) return null;
|
|
18581
|
+
const constFree = scope.constants.get(name2);
|
|
18582
|
+
if (constFree !== void 0) {
|
|
18583
|
+
if (constFree === null) return `constant '${name2}' has no analyzable value`;
|
|
18584
|
+
for (const inner of constFree) {
|
|
18585
|
+
const failure = resolve12(inner);
|
|
18586
|
+
if (failure) return failure;
|
|
18587
|
+
}
|
|
18588
|
+
return null;
|
|
18589
|
+
}
|
|
18590
|
+
const signal2 = scope.signals.get(name2);
|
|
18591
|
+
if (signal2 !== void 0) {
|
|
18592
|
+
if (signal2.initializerFreeIdentifiers === null) {
|
|
18593
|
+
return `signal '${name2}' has no structured initializer to prove props/literal derivation`;
|
|
18594
|
+
}
|
|
18595
|
+
for (const inner of signal2.initializerFreeIdentifiers) {
|
|
18596
|
+
const failure = resolve12(inner);
|
|
18597
|
+
if (failure) return failure;
|
|
18598
|
+
}
|
|
18599
|
+
return null;
|
|
18600
|
+
}
|
|
18601
|
+
if (scope.memos.has(name2)) return `memo '${name2}' initializer is not analyzed by the v1 gate`;
|
|
18602
|
+
if (scope.inert.has(name2)) return `'${name2}' is an import or local function`;
|
|
18603
|
+
return `'${name2}' does not resolve to a prop, literal-derived const, or props/literal-derived signal`;
|
|
18604
|
+
};
|
|
18605
|
+
for (const name2 of names) {
|
|
18606
|
+
const failure = resolve12(name2);
|
|
18607
|
+
if (failure) return failure;
|
|
18608
|
+
}
|
|
18609
|
+
return null;
|
|
18610
|
+
}
|
|
18611
|
+
function classifyLazyBinding(args2) {
|
|
18612
|
+
const { kind: kind2, slotId, free, rowLocalNames, indexParam, scope } = args2;
|
|
18613
|
+
if (free === null) {
|
|
18614
|
+
return {
|
|
18615
|
+
kind: kind2,
|
|
18616
|
+
slotId,
|
|
18617
|
+
readsItem: true,
|
|
18618
|
+
readsOuter: true,
|
|
18619
|
+
reactiveOuterNames: [],
|
|
18620
|
+
opaqueOuterNames: [UNKNOWN_IDENTIFIERS],
|
|
18621
|
+
// An ASSUMPTION, not knowledge — which is precisely why
|
|
18622
|
+
// `UNKNOWN_IDENTIFIERS` must keep refusing the loop: with no
|
|
18623
|
+
// identifier set we cannot rule out an index read either, and
|
|
18624
|
+
// `applyItem` / `applyOuter` have no index parameter to give it.
|
|
18625
|
+
referencesIndex: false
|
|
18626
|
+
};
|
|
18627
|
+
}
|
|
18628
|
+
let readsItem = false;
|
|
18629
|
+
let referencesIndex = false;
|
|
18630
|
+
const reactiveOuterNames = [];
|
|
18631
|
+
const opaqueOuterNames = [];
|
|
18632
|
+
for (const name2 of free) {
|
|
18633
|
+
if (rowLocalNames.has(name2)) {
|
|
18634
|
+
readsItem = true;
|
|
18635
|
+
continue;
|
|
18636
|
+
}
|
|
18637
|
+
if (name2 === indexParam) {
|
|
18638
|
+
referencesIndex = true;
|
|
18639
|
+
continue;
|
|
18640
|
+
}
|
|
18641
|
+
if (INERT_BINDING_GLOBALS.has(name2)) continue;
|
|
18642
|
+
if (scope.signals.has(name2) || scope.memos.has(name2)) {
|
|
18643
|
+
if (!reactiveOuterNames.includes(name2)) reactiveOuterNames.push(name2);
|
|
18644
|
+
continue;
|
|
18645
|
+
}
|
|
18646
|
+
const constFree = scope.constants.get(name2);
|
|
18647
|
+
if (constFree !== void 0 && constFree !== null && constFree.size === 0) continue;
|
|
18648
|
+
opaqueOuterNames.push(name2);
|
|
18649
|
+
}
|
|
18650
|
+
return {
|
|
18651
|
+
kind: kind2,
|
|
18652
|
+
slotId,
|
|
18653
|
+
readsItem,
|
|
18654
|
+
readsOuter: reactiveOuterNames.length > 0 || opaqueOuterNames.length > 0,
|
|
18655
|
+
reactiveOuterNames,
|
|
18656
|
+
opaqueOuterNames,
|
|
18657
|
+
referencesIndex
|
|
18658
|
+
};
|
|
18659
|
+
}
|
|
18660
|
+
var PURE_SOURCE_GLOBALS, INERT_BINDING_GLOBALS, UNKNOWN_IDENTIFIERS, NO;
|
|
18661
|
+
var init_lazy_row_eligibility = __esm({
|
|
18662
|
+
"../jsx/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts"() {
|
|
18663
|
+
"use strict";
|
|
18664
|
+
PURE_SOURCE_GLOBALS = /* @__PURE__ */ new Set([
|
|
18665
|
+
"Object",
|
|
18666
|
+
"Array",
|
|
18667
|
+
"JSON",
|
|
18668
|
+
"Number",
|
|
18669
|
+
"String",
|
|
18670
|
+
"Boolean"
|
|
18671
|
+
]);
|
|
18672
|
+
INERT_BINDING_GLOBALS = /* @__PURE__ */ new Set([
|
|
18673
|
+
"Object",
|
|
18674
|
+
"Array",
|
|
18675
|
+
"JSON",
|
|
18676
|
+
"Number",
|
|
18677
|
+
"String",
|
|
18678
|
+
"Boolean",
|
|
18679
|
+
"Math",
|
|
18680
|
+
"Date",
|
|
18681
|
+
"Intl",
|
|
18682
|
+
"Symbol",
|
|
18683
|
+
"Map",
|
|
18684
|
+
"Set",
|
|
18685
|
+
"WeakMap",
|
|
18686
|
+
"WeakSet",
|
|
18687
|
+
"Promise",
|
|
18688
|
+
"RegExp",
|
|
18689
|
+
"Error",
|
|
18690
|
+
"BigInt",
|
|
18691
|
+
"console",
|
|
18692
|
+
"undefined",
|
|
18693
|
+
"NaN",
|
|
18694
|
+
"Infinity",
|
|
18695
|
+
"globalThis",
|
|
18696
|
+
"parseInt",
|
|
18697
|
+
"parseFloat",
|
|
18698
|
+
"isNaN",
|
|
18699
|
+
"isFinite",
|
|
18700
|
+
"encodeURIComponent",
|
|
18701
|
+
"decodeURIComponent",
|
|
18702
|
+
"encodeURI",
|
|
18703
|
+
"decodeURI"
|
|
18704
|
+
]);
|
|
18705
|
+
UNKNOWN_IDENTIFIERS = "<unknown>";
|
|
18706
|
+
NO = (reason2) => ({ eligible: false, reason: reason2 });
|
|
18707
|
+
}
|
|
18708
|
+
});
|
|
18709
|
+
|
|
18710
|
+
// ../jsx/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts
|
|
18711
|
+
function buildLazyRowPlan(args2) {
|
|
18712
|
+
return decideLazyRow(args2).plan;
|
|
18713
|
+
}
|
|
18714
|
+
function decideLazyRow(args2) {
|
|
18715
|
+
const { loop, scope } = args2;
|
|
18716
|
+
if (!scope) {
|
|
18717
|
+
return { plan: null, decision: { eligible: false, reason: "no component scope info supplied" } };
|
|
18718
|
+
}
|
|
18719
|
+
const wrap = (expr) => wrapLoopParamAsAccessor(expr, loop.param, loop.paramBindings);
|
|
18720
|
+
const rowLocalNames = /* @__PURE__ */ new Set([loop.param]);
|
|
18721
|
+
for (const b of loop.paramBindings ?? []) rowLocalNames.add(b.name);
|
|
18722
|
+
const classified = [];
|
|
18723
|
+
const attrClass = /* @__PURE__ */ new Map();
|
|
18724
|
+
loop.bindings.reactiveAttrs.forEach((attr, i) => {
|
|
18725
|
+
const c = classifyLazyBinding({
|
|
18726
|
+
kind: "attr",
|
|
18727
|
+
slotId: attr.childSlotId,
|
|
18728
|
+
free: attrFreeIdentifiers2(attr.expression),
|
|
18729
|
+
rowLocalNames,
|
|
18730
|
+
indexParam: args2.indexParam,
|
|
18731
|
+
scope
|
|
18732
|
+
});
|
|
18733
|
+
attrClass.set(i, c);
|
|
18734
|
+
classified.push(c);
|
|
18735
|
+
});
|
|
18736
|
+
const textClass = /* @__PURE__ */ new Map();
|
|
18737
|
+
loop.bindings.reactiveTexts.forEach((text, i) => {
|
|
18738
|
+
const c = classifyLazyBinding({
|
|
18739
|
+
kind: "text",
|
|
18740
|
+
slotId: text.slotId,
|
|
18741
|
+
free: text.freeIdentifiers ?? null,
|
|
18742
|
+
rowLocalNames,
|
|
18743
|
+
indexParam: args2.indexParam,
|
|
18744
|
+
scope
|
|
18745
|
+
});
|
|
18746
|
+
textClass.set(i, c);
|
|
18747
|
+
classified.push(c);
|
|
18748
|
+
});
|
|
18749
|
+
const shape = {
|
|
18750
|
+
callSite: args2.callSite,
|
|
18751
|
+
flatMapLeafItem: args2.flatMapLeafItem,
|
|
18752
|
+
anchored: args2.anchored,
|
|
18753
|
+
bodyIsMultiRoot: loop.bodyIsMultiRoot ?? false,
|
|
18754
|
+
hasExplicitKey: loop.key != null,
|
|
18755
|
+
conditionalCount: loop.bindings.conditionals?.length ?? 0,
|
|
18756
|
+
childRefCount: loop.bindings.refs?.length ?? 0,
|
|
18757
|
+
nestedComponentCount: loop.nestedComponents?.length ?? 0,
|
|
18758
|
+
innerLoopCount: loop.innerLoops?.length ?? 0,
|
|
18759
|
+
hasChildComponent: "childComponent" in loop && loop.childComponent != null,
|
|
18760
|
+
hasMapPreamble: args2.mapPreambleWrapped.length > 0,
|
|
18761
|
+
preambleRegionCount: args2.preambleRegionCount,
|
|
18762
|
+
hasParamUnwrap: args2.paramUnwrap.length > 0
|
|
18763
|
+
};
|
|
18764
|
+
const decision = lazyRowEligibility({
|
|
18765
|
+
shape,
|
|
18766
|
+
bindings: classified,
|
|
18767
|
+
arraySourceIdentifiers: loopSourceIdentifiers(loop, args2.arrayExpr),
|
|
18768
|
+
scope
|
|
18769
|
+
});
|
|
18770
|
+
if (!decision.eligible) return { plan: null, decision };
|
|
18771
|
+
const attrSlotIds = [];
|
|
18772
|
+
for (const attr of loop.bindings.reactiveAttrs) {
|
|
18773
|
+
if (!attrSlotIds.includes(attr.childSlotId)) attrSlotIds.push(attr.childSlotId);
|
|
18774
|
+
}
|
|
18775
|
+
let ordinal = 0;
|
|
18776
|
+
const attrs = loop.bindings.reactiveAttrs.map((attr, i) => {
|
|
18777
|
+
const c = attrClass.get(i);
|
|
18778
|
+
return {
|
|
18779
|
+
slotId: attr.childSlotId,
|
|
18780
|
+
attrName: attr.attrName,
|
|
18781
|
+
wrappedExpression: wrap(attr.expression),
|
|
18782
|
+
meta: pickAttrMeta(attr),
|
|
18783
|
+
refIndex: attrSlotIds.indexOf(attr.childSlotId),
|
|
18784
|
+
ordinal: ordinal++,
|
|
18785
|
+
readsItem: c.readsItem,
|
|
18786
|
+
readsOuter: c.readsOuter
|
|
18787
|
+
};
|
|
18788
|
+
});
|
|
18789
|
+
const texts = loop.bindings.reactiveTexts.map((text, i) => {
|
|
18790
|
+
const c = textClass.get(i);
|
|
18791
|
+
return {
|
|
18792
|
+
slotId: text.slotId,
|
|
18793
|
+
wrappedExpression: wrap(text.expression),
|
|
18794
|
+
ordinal: ordinal++,
|
|
18795
|
+
// A text that classified as NEITHER item- nor outer-driven still gets
|
|
18796
|
+
// applied on item change (harmless, dedup-guarded) rather than
|
|
18797
|
+
// silently never being written. Anything the classifier did place in
|
|
18798
|
+
// a list keeps exactly the classifier's answer.
|
|
18799
|
+
readsItem: c.readsItem || !c.readsOuter,
|
|
18800
|
+
readsOuter: c.readsOuter
|
|
18801
|
+
};
|
|
18802
|
+
});
|
|
18803
|
+
const outerPrimeGetters = [];
|
|
18804
|
+
for (const c of classified) {
|
|
18805
|
+
for (const name2 of c.reactiveOuterNames) {
|
|
18806
|
+
if (!outerPrimeGetters.includes(name2)) outerPrimeGetters.push(name2);
|
|
18807
|
+
}
|
|
18808
|
+
}
|
|
18809
|
+
return {
|
|
18810
|
+
plan: {
|
|
18811
|
+
attrSlotIds,
|
|
18812
|
+
attrs,
|
|
18813
|
+
texts,
|
|
18814
|
+
writerIndex: texts.length > 0 ? attrSlotIds.length : -1,
|
|
18815
|
+
textNeedsRead: texts.some((t) => t.readsOuter),
|
|
18816
|
+
lastCount: ordinal,
|
|
18817
|
+
outerPrimeGetters,
|
|
18818
|
+
hasOuter: attrs.some((a) => a.readsOuter) || texts.some((t) => t.readsOuter)
|
|
18819
|
+
},
|
|
18820
|
+
decision
|
|
18821
|
+
};
|
|
18822
|
+
}
|
|
18823
|
+
function buildLazyRowScopeInfo(ctx2) {
|
|
18824
|
+
const signals = /* @__PURE__ */ new Map();
|
|
18825
|
+
for (const s of ctx2.signals) {
|
|
18826
|
+
signals.set(s.getter, {
|
|
18827
|
+
// `parsed` is the analyzer's structured initializer. Absent (or
|
|
18828
|
+
// refused by `freeIdentifiers`) ⇒ unprovable, which the source gate
|
|
18829
|
+
// treats as a hard stop rather than an assumption.
|
|
18830
|
+
initializerFreeIdentifiers: s.parsed ? freeIdentifiers(s.parsed) : null
|
|
18831
|
+
});
|
|
18832
|
+
}
|
|
18833
|
+
const memos = new Set(ctx2.memos.map((m) => m.name));
|
|
18834
|
+
const props = /* @__PURE__ */ new Set([PROPS_PARAM]);
|
|
18835
|
+
if (ctx2.propsObjectName) props.add(ctx2.propsObjectName);
|
|
18836
|
+
for (const p of ctx2.propsParams) props.add(p.name);
|
|
18837
|
+
const constants = /* @__PURE__ */ new Map();
|
|
18838
|
+
for (const c of ctx2.localConstants) {
|
|
18839
|
+
constants.set(c.name, c.freeIdentifiers ?? null);
|
|
18840
|
+
}
|
|
18841
|
+
const inert = /* @__PURE__ */ new Set();
|
|
18842
|
+
for (const f of ctx2.localFunctions) inert.add(f.name);
|
|
18843
|
+
for (const imp of ctx2.imports) {
|
|
18844
|
+
if (imp.isTypeOnly) continue;
|
|
18845
|
+
for (const spec of imp.specifiers) inert.add(spec.alias || spec.name);
|
|
18846
|
+
}
|
|
18847
|
+
return { signals, memos, props, constants, inert, profile: ctx2.profile };
|
|
18848
|
+
}
|
|
18849
|
+
function attrFreeIdentifiers2(expression) {
|
|
18850
|
+
if (!expression || expression.trim().length === 0) return /* @__PURE__ */ new Set();
|
|
18851
|
+
try {
|
|
18852
|
+
return freeIdentifiers(parseExpression(expression));
|
|
18853
|
+
} catch {
|
|
18854
|
+
return null;
|
|
18855
|
+
}
|
|
18856
|
+
}
|
|
18857
|
+
function loopSourceIdentifiers(loop, arrayExpr) {
|
|
18858
|
+
if (!loop.arrayFreeIdentifiers) return null;
|
|
18859
|
+
const names = new Set(loop.arrayFreeIdentifiers);
|
|
18860
|
+
for (const name2 of extractFreeIdentifiersFromText(arrayExpr)) names.add(name2);
|
|
18861
|
+
return names;
|
|
18862
|
+
}
|
|
18863
|
+
var init_build_lazy_row = __esm({
|
|
18864
|
+
"../jsx/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts"() {
|
|
18865
|
+
"use strict";
|
|
18866
|
+
init_expression_parser();
|
|
18867
|
+
init_types();
|
|
18868
|
+
init_csr_substitute();
|
|
18869
|
+
init_utils();
|
|
18870
|
+
init_lazy_row_eligibility();
|
|
18871
|
+
}
|
|
18872
|
+
});
|
|
18873
|
+
|
|
18497
18874
|
// ../jsx/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts
|
|
18498
|
-
function buildBranchLoopPlan(loop, profileComponentName) {
|
|
18875
|
+
function buildBranchLoopPlan(loop, profileComponentName, lazyScope) {
|
|
18499
18876
|
const containerSlotId = loop.containerSlotId;
|
|
18500
18877
|
const cv = varSlotId(containerSlotId);
|
|
18501
18878
|
const containerVar = `__loop_${cv}`;
|
|
@@ -18511,6 +18888,13 @@ function buildBranchLoopPlan(loop, profileComponentName) {
|
|
|
18511
18888
|
const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(loop.param, loop.paramBindings);
|
|
18512
18889
|
const hasReactiveEffects = loop.bindings.reactiveAttrs.length > 0 || loop.bindings.reactiveTexts.length > 0 || loop.bindings.conditionals.length > 0;
|
|
18513
18890
|
const fm = loop.flatMapClient;
|
|
18891
|
+
const arrayExpr = fm ? `(${buildChainedArrayExpr(loop)}).flatMap(${fm.params} => ${fm.body})` : buildChainedArrayExpr(loop);
|
|
18892
|
+
const indexParam = loop.index || "__idx";
|
|
18893
|
+
const mapPreambleWrapped = loop.preamble ? renderPreamble(loop.preamble, {
|
|
18894
|
+
transformJs: (t) => wrapLoopParamAsAccessor(t, loop.param, loop.paramBindings),
|
|
18895
|
+
renderLeaf: (ir) => irToHtmlTemplate(ir, void 0, 1, [{ param: loop.param, bindings: loop.paramBindings }], void 0, true)
|
|
18896
|
+
}) : "";
|
|
18897
|
+
const preambleRegions = buildPreambleRegionPlans(loop.preambleRegions, loop.param, loop.paramBindings);
|
|
18514
18898
|
const plan = {
|
|
18515
18899
|
kind: "plain",
|
|
18516
18900
|
rowConstruction: "string-template",
|
|
@@ -18518,17 +18902,27 @@ function buildBranchLoopPlan(loop, profileComponentName) {
|
|
|
18518
18902
|
containerVar,
|
|
18519
18903
|
markerId: loop.markerId,
|
|
18520
18904
|
flatMapLeafItem: fm ? true : void 0,
|
|
18521
|
-
arrayExpr
|
|
18905
|
+
arrayExpr,
|
|
18522
18906
|
keyFn: fm ? fm.keyed ? "(__bfD, __bfI) => String(__bfD.k ?? __bfI)" : "null" : loopKeyFn(loop),
|
|
18523
18907
|
paramHead,
|
|
18524
18908
|
paramUnwrap,
|
|
18525
|
-
indexParam
|
|
18909
|
+
indexParam,
|
|
18526
18910
|
// Wrap loop-param references to signal-accessor form so the preamble
|
|
18527
18911
|
// matches the template literal's already-wrapped reads (#1065).
|
|
18528
|
-
mapPreambleWrapped
|
|
18529
|
-
|
|
18530
|
-
|
|
18531
|
-
|
|
18912
|
+
mapPreambleWrapped,
|
|
18913
|
+
// Lazy row graph (§9, L3) — undefined for every ineligible loop.
|
|
18914
|
+
lazyRow: buildLazyRowPlan({
|
|
18915
|
+
loop,
|
|
18916
|
+
arrayExpr,
|
|
18917
|
+
indexParam,
|
|
18918
|
+
paramUnwrap,
|
|
18919
|
+
mapPreambleWrapped,
|
|
18920
|
+
preambleRegionCount: preambleRegions.length,
|
|
18921
|
+
callSite: "branch-plain",
|
|
18922
|
+
flatMapLeafItem: Boolean(fm),
|
|
18923
|
+
anchored: false,
|
|
18924
|
+
scope: lazyScope
|
|
18925
|
+
}) ?? void 0,
|
|
18532
18926
|
template: loop.template,
|
|
18533
18927
|
reactiveEffects: hasReactiveEffects ? buildReactiveEffectsPlan({
|
|
18534
18928
|
attrs: loop.bindings.reactiveAttrs,
|
|
@@ -18540,7 +18934,7 @@ function buildBranchLoopPlan(loop, profileComponentName) {
|
|
|
18540
18934
|
}) : null,
|
|
18541
18935
|
eventDelegation: buildBranchLoopDelegationPlan(loop, cv, profileComponentName),
|
|
18542
18936
|
childRefs: buildChildRefBindings(loop.bindings.refs, loop.param, loop.paramBindings),
|
|
18543
|
-
preambleRegions
|
|
18937
|
+
preambleRegions,
|
|
18544
18938
|
bodyIsMultiRoot: loop.bodyIsMultiRoot ?? false,
|
|
18545
18939
|
profileLoopId: profileComponentName ? `${profileComponentName}#binding:${containerSlotId}` : void 0
|
|
18546
18940
|
};
|
|
@@ -18553,6 +18947,7 @@ var init_build_branch_loop = __esm({
|
|
|
18553
18947
|
init_build_composite_loop();
|
|
18554
18948
|
init_build_event_delegation();
|
|
18555
18949
|
init_build_reactive_effects();
|
|
18950
|
+
init_build_lazy_row();
|
|
18556
18951
|
init_shared();
|
|
18557
18952
|
init_html_template();
|
|
18558
18953
|
}
|
|
@@ -18609,13 +19004,13 @@ function buildArmBody(branch, options2) {
|
|
|
18609
19004
|
expression: t.expression
|
|
18610
19005
|
})),
|
|
18611
19006
|
// Branch-scoped loops, fully Plan-built (Item 2 final migration).
|
|
18612
|
-
loops: branch.loops.map((l) => buildBranchLoopPlan(l, pc)),
|
|
19007
|
+
loops: branch.loops.map((l) => buildBranchLoopPlan(l, pc, options2.lazyScope)),
|
|
18613
19008
|
// Nested conditionals are themselves InsertPlans — built recursively so
|
|
18614
19009
|
// the same stringifier handles arbitrary depth. Their scope is always
|
|
18615
19010
|
// `__branchScope` (the parent arm's bindEvents argument), regardless of
|
|
18616
19011
|
// the outer scope; only the eventNameMode is inherited.
|
|
18617
19012
|
conditionals: branch.conditionals.map(
|
|
18618
|
-
(c) => buildInsertPlan(c, { scope: { kind: "branchScope" }, eventNameMode: options2.eventNameMode, profileComponentName: pc })
|
|
19013
|
+
(c) => buildInsertPlan(c, { scope: { kind: "branchScope" }, eventNameMode: options2.eventNameMode, profileComponentName: pc, lazyScope: options2.lazyScope })
|
|
18619
19014
|
)
|
|
18620
19015
|
};
|
|
18621
19016
|
}
|
|
@@ -19008,7 +19403,7 @@ function stringifyBranchEventBindings(lines, plan, indent) {
|
|
|
19008
19403
|
}
|
|
19009
19404
|
function stringifyBranchChildComponentInits(lines, plan, indent) {
|
|
19010
19405
|
for (const init of plan) {
|
|
19011
|
-
lines.push(`${indent}{ let __c = qsa(__branchScope, ${init.selector}); if (!__c) { const __ph = __branchScope.querySelector('[${BF_PLACEHOLDER}="${init.placeholderId}"]'); if (__ph) { __c = createComponent('${nameForRegistryRef(init.name)}', ${init.propsExpr}
|
|
19406
|
+
lines.push(`${indent}{ let __c = qsa(__branchScope, ${init.selector}); if (!__c) { const __ph = __branchScope.querySelector('[${BF_PLACEHOLDER}="${init.placeholderId}"]'); if (__ph) { __c = createComponent('${nameForRegistryRef(init.name)}', ${init.propsExpr}, undefined, undefined, __ph) } } if (__c) initChild('${nameForRegistryRef(init.name)}', __c, ${init.propsExpr}) }`);
|
|
19012
19407
|
}
|
|
19013
19408
|
}
|
|
19014
19409
|
function stringifyBranchInnerLoops(lines, plan, indent, pc) {
|
|
@@ -19356,6 +19751,179 @@ var init_component_loop = __esm({
|
|
|
19356
19751
|
}
|
|
19357
19752
|
});
|
|
19358
19753
|
|
|
19754
|
+
// ../jsx/src/ir-to-client-js/control-flow/stringify/lazy-row.ts
|
|
19755
|
+
function stringifyLazyRowLoop(lines, o) {
|
|
19756
|
+
const { indent, lazyRow, paramHead } = o;
|
|
19757
|
+
const mid = o.markerId.replace(/[^A-Za-z0-9_$]/g, "_");
|
|
19758
|
+
const tplVar = `__tpl_${mid}`;
|
|
19759
|
+
const claimVar = `__lzc_${mid}`;
|
|
19760
|
+
const hasRefs = lazyRow.attrSlotIds.length > 0 || lazyRow.texts.length > 0;
|
|
19761
|
+
const hasBindings = lazyRow.attrs.length > 0 || lazyRow.texts.length > 0;
|
|
19762
|
+
const rwDoor = lazyRow.textNeedsRead;
|
|
19763
|
+
const paths = o.skeletonPaths;
|
|
19764
|
+
const useHoisted = Boolean(o.skeletonTemplate);
|
|
19765
|
+
if (useHoisted) emitHoistedTemplateDecl(lines, indent, tplVar, o.skeletonTemplate);
|
|
19766
|
+
const textPathVar = useHoisted && paths && lazyRow.texts.length > 0 ? `__lzp_${mid}` : null;
|
|
19767
|
+
if (textPathVar) {
|
|
19768
|
+
const arrays = lazyRow.texts.map((t) => `[${(paths.textMarkerPaths.get(t.slotId) ?? []).join(", ")}]`);
|
|
19769
|
+
lines.push(`${indent}const ${textPathVar} = [${arrays.join(", ")}]`);
|
|
19770
|
+
}
|
|
19771
|
+
let adoptedPlanVar = null;
|
|
19772
|
+
let freshPlanVar = null;
|
|
19773
|
+
if (lazyRow.texts.length > 0) {
|
|
19774
|
+
adoptedPlanVar = `__lzs_${mid}`;
|
|
19775
|
+
const adoptedSlots = lazyRow.texts.map((t) => ({ id: t.slotId, kind: "text", path: [] }));
|
|
19776
|
+
lines.push(`${indent}const ${adoptedPlanVar} = ${claimPlanLiteral(adoptedSlots)}`);
|
|
19777
|
+
if (textPathVar) {
|
|
19778
|
+
freshPlanVar = `__lzsc_${mid}`;
|
|
19779
|
+
const freshSlots = lazyRow.texts.map((t, i) => ({
|
|
19780
|
+
id: t.slotId,
|
|
19781
|
+
kind: "text",
|
|
19782
|
+
path: [],
|
|
19783
|
+
pathExpr: `${textPathVar}[${i}]`
|
|
19784
|
+
}));
|
|
19785
|
+
lines.push(`${indent}const ${freshPlanVar} = ${claimPlanLiteral(freshSlots)}`);
|
|
19786
|
+
} else {
|
|
19787
|
+
freshPlanVar = adoptedPlanVar;
|
|
19788
|
+
}
|
|
19789
|
+
}
|
|
19790
|
+
if (hasRefs) {
|
|
19791
|
+
const parts = refParts(lazyRow, "__el", null, adoptedPlanVar, true);
|
|
19792
|
+
lines.push(`${indent}const ${claimVar} = (__e) => {`);
|
|
19793
|
+
if (parts.some((p) => p.includes("__el"))) lines.push(`${indent} const __el = __e.primaryEl`);
|
|
19794
|
+
lines.push(`${indent} return [${parts.join(", ")}]`);
|
|
19795
|
+
lines.push(`${indent}}`);
|
|
19796
|
+
}
|
|
19797
|
+
const call = `mapArrayLazy(() => ${o.arrayExpr}, ${o.containerVar}, ${o.keyFn}, {`;
|
|
19798
|
+
lines.push(`${indent}${o.guardContainer ? `if (${o.containerVar}) ` : ""}${call}`);
|
|
19799
|
+
const b1 = `${indent} `;
|
|
19800
|
+
const b2 = `${indent} `;
|
|
19801
|
+
lines.push(`${b1}createRow: (__e, ${o.indexParam}) => {`);
|
|
19802
|
+
lines.push(`${b2}const ${paramHead} = () => __e.item`);
|
|
19803
|
+
const cloneExpr = useHoisted ? hoistedCloneExpr(tplVar, o.skeletonTemplate) : `(() => { ${emitTemplateCloneInline(o.template)} })()`;
|
|
19804
|
+
lines.push(`${b2}const __el = ${cloneExpr}`);
|
|
19805
|
+
if (hasRefs) {
|
|
19806
|
+
lines.push(`${b2}const __r = __e.refs = [${refParts(lazyRow, "__el", useHoisted ? paths ?? null : null, freshPlanVar).join(", ")}]`);
|
|
19807
|
+
}
|
|
19808
|
+
if (hasBindings) {
|
|
19809
|
+
lines.push(`${b2}const __l = __e.last = []`);
|
|
19810
|
+
for (const a of lazyRow.attrs) emitAttrBinding(lines, b2, a, "create");
|
|
19811
|
+
const createDoor = `__r[${lazyRow.writerIndex}]`;
|
|
19812
|
+
for (const t of lazyRow.texts) emitTextBinding(lines, b2, t, createDoor, "create", rwDoor);
|
|
19813
|
+
}
|
|
19814
|
+
lines.push(`${b2}return __el`);
|
|
19815
|
+
lines.push(`${b1}},`);
|
|
19816
|
+
const itemAttrs = lazyRow.attrs.filter((a) => a.readsItem);
|
|
19817
|
+
const itemTexts = lazyRow.texts.filter((t) => t.readsItem);
|
|
19818
|
+
if (itemAttrs.length === 0 && itemTexts.length === 0) {
|
|
19819
|
+
lines.push(`${b1}applyItem: () => {},`);
|
|
19820
|
+
} else {
|
|
19821
|
+
lines.push(`${b1}applyItem: (__e) => {`);
|
|
19822
|
+
lines.push(`${b2}const ${paramHead} = () => __e.item`);
|
|
19823
|
+
lines.push(`${b2}const __r = __e.refs ?? (__e.refs = ${claimVar}(__e))`);
|
|
19824
|
+
lines.push(`${b2}const __l = __e.last ?? (__e.last = [])`);
|
|
19825
|
+
for (const a of itemAttrs) emitAttrBinding(lines, b2, a, "item");
|
|
19826
|
+
if (itemTexts.length > 0) {
|
|
19827
|
+
lines.push(`${b2}const __d = ${doorAccess(lazyRow, lazyRow.writerIndex, adoptedPlanVar)}`);
|
|
19828
|
+
for (const t of itemTexts) emitTextBinding(lines, b2, t, "__d", "item", rwDoor);
|
|
19829
|
+
}
|
|
19830
|
+
lines.push(`${b1}},`);
|
|
19831
|
+
}
|
|
19832
|
+
const outerAttrs = lazyRow.attrs.filter((a) => a.readsOuter);
|
|
19833
|
+
const outerTexts = lazyRow.texts.filter((t) => t.readsOuter);
|
|
19834
|
+
if (outerAttrs.length > 0 || outerTexts.length > 0) {
|
|
19835
|
+
const b3 = `${indent} `;
|
|
19836
|
+
lines.push(`${b1}applyOuter: (__es, __seed) => {`);
|
|
19837
|
+
for (const g of lazyRow.outerPrimeGetters) lines.push(`${b2}${g}()`);
|
|
19838
|
+
lines.push(`${b2}for (const __e of __es) {`);
|
|
19839
|
+
lines.push(`${b3}const ${paramHead} = () => __e.item`);
|
|
19840
|
+
lines.push(`${b3}const __r = __e.refs ?? (__e.refs = ${claimVar}(__e))`);
|
|
19841
|
+
lines.push(`${b3}const __l = __e.last ?? (__e.last = [])`);
|
|
19842
|
+
for (const a of outerAttrs) emitAttrBinding(lines, b3, a, "outer");
|
|
19843
|
+
if (outerTexts.length > 0) {
|
|
19844
|
+
lines.push(`${b3}const __d = ${doorAccess(lazyRow, lazyRow.writerIndex, adoptedPlanVar)}`);
|
|
19845
|
+
for (const t of outerTexts) emitTextBinding(lines, b3, t, "__d", "outer", rwDoor);
|
|
19846
|
+
}
|
|
19847
|
+
lines.push(`${b2}}`);
|
|
19848
|
+
lines.push(`${b1}},`);
|
|
19849
|
+
}
|
|
19850
|
+
lines.push(`${indent}}, '${o.markerId}')`);
|
|
19851
|
+
}
|
|
19852
|
+
function refParts(lazyRow, elVar, skeletonPaths, planVar, deferDoor = false) {
|
|
19853
|
+
const parts = [];
|
|
19854
|
+
for (const slotId of lazyRow.attrSlotIds) {
|
|
19855
|
+
const path25 = skeletonPaths?.elementPaths.get(slotId);
|
|
19856
|
+
parts.push(path25 ? pathExpr(elVar, path25) : `qsa(${elVar}, '[bf="${slotId}"]')`);
|
|
19857
|
+
}
|
|
19858
|
+
if (lazyRow.texts.length > 0) {
|
|
19859
|
+
parts.push(deferDoor ? "null" : `${doorCtor(lazyRow)}(${elVar}, ${planVar})`);
|
|
19860
|
+
}
|
|
19861
|
+
return parts;
|
|
19862
|
+
}
|
|
19863
|
+
function doorCtor(lazyRow) {
|
|
19864
|
+
return lazyRow.textNeedsRead ? "lazyClaimSlots" : "lazySlots";
|
|
19865
|
+
}
|
|
19866
|
+
function doorAccess(lazyRow, writerIndex, adoptedPlanVar) {
|
|
19867
|
+
const slot = `__r[${writerIndex}]`;
|
|
19868
|
+
return `${slot} ?? (${slot} = ${doorCtor(lazyRow)}(__e.primaryEl, ${adoptedPlanVar}))`;
|
|
19869
|
+
}
|
|
19870
|
+
function dedupGuard(ordinal) {
|
|
19871
|
+
return `!(${ordinal} in __l) || !Object.is(__l[${ordinal}], __x)`;
|
|
19872
|
+
}
|
|
19873
|
+
function emitAttrBinding(lines, ind, a, mode2) {
|
|
19874
|
+
lines.push(`${ind}{ const __t = __r[${a.refIndex}]`);
|
|
19875
|
+
lines.push(`${ind}if (__t) {`);
|
|
19876
|
+
lines.push(`${ind} const __x = ${a.wrappedExpression}`);
|
|
19877
|
+
const guard = mode2 === "create" ? null : mode2 === "item" ? dedupGuard(a.ordinal) : `__seed ? (${seedDiffersExpr("__t", a)}) : (${dedupGuard(a.ordinal)})`;
|
|
19878
|
+
const writeIndent = guard ? `${ind} ` : `${ind} `;
|
|
19879
|
+
if (guard) lines.push(`${ind} if (${guard}) {`);
|
|
19880
|
+
for (const stmt of emitAttrUpdate("__t", a.attrName, "__x", a.meta)) {
|
|
19881
|
+
lines.push(`${writeIndent}${stmt}`);
|
|
19882
|
+
}
|
|
19883
|
+
if (guard) lines.push(`${ind} }`);
|
|
19884
|
+
lines.push(`${ind} __l[${a.ordinal}] = __x`);
|
|
19885
|
+
lines.push(`${ind}} }`);
|
|
19886
|
+
}
|
|
19887
|
+
function emitTextBinding(lines, ind, t, doorExpr, mode2, rwDoor) {
|
|
19888
|
+
lines.push(`${ind}{ const __x = ${t.wrappedExpression}`);
|
|
19889
|
+
const writeOf = (valueExpr) => rwDoor ? `${doorExpr}.write('${t.slotId}', ${valueExpr})` : `${doorExpr}('${t.slotId}', ${valueExpr})`;
|
|
19890
|
+
if (mode2 === "outer") {
|
|
19891
|
+
lines.push(`${ind}if (__seed) {`);
|
|
19892
|
+
lines.push(`${ind} const __s = textOrNode(__x)`);
|
|
19893
|
+
lines.push(`${ind} if (${doorExpr}.read('${t.slotId}') !== __s) ${writeOf("__s")}`);
|
|
19894
|
+
lines.push(`${ind}} else if (${dedupGuard(t.ordinal)}) ${writeOf("textOrNode(__x)")}`);
|
|
19895
|
+
} else if (mode2 === "item") {
|
|
19896
|
+
lines.push(`${ind}if (${dedupGuard(t.ordinal)}) ${writeOf("textOrNode(__x)")}`);
|
|
19897
|
+
} else {
|
|
19898
|
+
lines.push(`${ind}${writeOf("textOrNode(__x)")}`);
|
|
19899
|
+
}
|
|
19900
|
+
lines.push(`${ind}__l[${t.ordinal}] = __x }`);
|
|
19901
|
+
}
|
|
19902
|
+
function seedDiffersExpr(target2, a) {
|
|
19903
|
+
const html = toHTMLAttrName(a.attrName);
|
|
19904
|
+
if (a.attrName === "dangerouslySetInnerHTML" || html === "dangerouslySetInnerHTML") return "true";
|
|
19905
|
+
if (html === "style") return `${target2}.getAttribute('style') !== styleToCss(__x)`;
|
|
19906
|
+
if (html === "class") return `${target2}.getAttribute('class') !== (__x != null ? String(__x) : null)`;
|
|
19907
|
+
if (html === "value") return `${target2}.value !== String(__x)`;
|
|
19908
|
+
if (isBooleanAttr(html)) return `${target2}.${html} !== !!(__x)`;
|
|
19909
|
+
if (a.meta.presenceOrUndefined) {
|
|
19910
|
+
const written = html.startsWith("aria-") ? "true" : "";
|
|
19911
|
+
return `${target2}.getAttribute('${html}') !== (__x ? '${written}' : null)`;
|
|
19912
|
+
}
|
|
19913
|
+
return `${target2}.getAttribute('${html}') !== (__x != null ? String(__x) : null)`;
|
|
19914
|
+
}
|
|
19915
|
+
var init_lazy_row = __esm({
|
|
19916
|
+
"../jsx/src/ir-to-client-js/control-flow/stringify/lazy-row.ts"() {
|
|
19917
|
+
"use strict";
|
|
19918
|
+
init_html_constants();
|
|
19919
|
+
init_emit_reactive();
|
|
19920
|
+
init_utils();
|
|
19921
|
+
init_claim_plan();
|
|
19922
|
+
init_skeleton_paths();
|
|
19923
|
+
init_template_parse();
|
|
19924
|
+
}
|
|
19925
|
+
});
|
|
19926
|
+
|
|
19359
19927
|
// ../jsx/src/ir-to-client-js/control-flow/stringify/loop.ts
|
|
19360
19928
|
function emitLoopChildRefs(lines, refs, opts) {
|
|
19361
19929
|
if (refs.length === 0) return;
|
|
@@ -19432,6 +20000,23 @@ function stringifyPlainLoop(lines, plan, topIndent = " ") {
|
|
|
19432
20000
|
stringifyAnchoredLoop(lines, plan, topIndent, anchorKeyExpr);
|
|
19433
20001
|
return;
|
|
19434
20002
|
}
|
|
20003
|
+
if (plan.lazyRow) {
|
|
20004
|
+
stringifyLazyRowLoop(lines, {
|
|
20005
|
+
indent: topIndent,
|
|
20006
|
+
containerVar,
|
|
20007
|
+
guardContainer: false,
|
|
20008
|
+
markerId,
|
|
20009
|
+
arrayExpr,
|
|
20010
|
+
keyFn,
|
|
20011
|
+
paramHead,
|
|
20012
|
+
indexParam,
|
|
20013
|
+
template,
|
|
20014
|
+
skeletonTemplate,
|
|
20015
|
+
skeletonPaths: plan.skeletonPaths,
|
|
20016
|
+
lazyRow: plan.lazyRow
|
|
20017
|
+
});
|
|
20018
|
+
return;
|
|
20019
|
+
}
|
|
19435
20020
|
const hoistedTpl = !bodyIsMultiRoot && skeletonTemplate ? skeletonTemplate : null;
|
|
19436
20021
|
const tplVar = `__tpl_${markerId.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
19437
20022
|
if (hoistedTpl) {
|
|
@@ -19619,6 +20204,7 @@ var init_loop = __esm({
|
|
|
19619
20204
|
init_component_loop();
|
|
19620
20205
|
init_composite_loop();
|
|
19621
20206
|
init_claim_plan();
|
|
20207
|
+
init_lazy_row();
|
|
19622
20208
|
}
|
|
19623
20209
|
});
|
|
19624
20210
|
|
|
@@ -20052,6 +20638,23 @@ function emitPlain(lines, plan) {
|
|
|
20052
20638
|
stringifyEventDelegation(lines, eventDelegation);
|
|
20053
20639
|
return;
|
|
20054
20640
|
}
|
|
20641
|
+
if (plan.lazyRow) {
|
|
20642
|
+
stringifyLazyRowLoop(lines, {
|
|
20643
|
+
indent: " ",
|
|
20644
|
+
containerVar,
|
|
20645
|
+
guardContainer: true,
|
|
20646
|
+
markerId,
|
|
20647
|
+
arrayExpr,
|
|
20648
|
+
keyFn,
|
|
20649
|
+
paramHead,
|
|
20650
|
+
indexParam,
|
|
20651
|
+
template,
|
|
20652
|
+
lazyRow: plan.lazyRow
|
|
20653
|
+
});
|
|
20654
|
+
lines.push(` }))`);
|
|
20655
|
+
stringifyEventDelegation(lines, eventDelegation);
|
|
20656
|
+
return;
|
|
20657
|
+
}
|
|
20055
20658
|
if (reactiveEffects === null && !bodyIsMultiRoot && childRefs.length === 0 && preambleRegions.length === 0) {
|
|
20056
20659
|
const cloneExpr = emitTemplateCloneInline(template);
|
|
20057
20660
|
if (mapPreambleWrapped) {
|
|
@@ -20097,6 +20700,7 @@ var init_branch_loop = __esm({
|
|
|
20097
20700
|
init_reactive_effects();
|
|
20098
20701
|
init_template_parse();
|
|
20099
20702
|
init_loop();
|
|
20703
|
+
init_lazy_row();
|
|
20100
20704
|
}
|
|
20101
20705
|
});
|
|
20102
20706
|
|
|
@@ -20283,7 +20887,7 @@ var init_build_component_loop = __esm({
|
|
|
20283
20887
|
// ../jsx/src/ir-to-client-js/control-flow/plan/build-loop.ts
|
|
20284
20888
|
function buildLoopPlan(elem, opts) {
|
|
20285
20889
|
if (elem.bodyIsItemConditional) {
|
|
20286
|
-
return buildPlainLoopPlan(elem, opts.profileComponentName);
|
|
20890
|
+
return buildPlainLoopPlan(elem, opts.profileComponentName, opts.lazyScope);
|
|
20287
20891
|
}
|
|
20288
20892
|
if (elem.isStaticArray) {
|
|
20289
20893
|
return buildStaticLoopPlan(elem, opts.unsafeLocalNames, opts.profileComponentName);
|
|
@@ -20295,9 +20899,9 @@ function buildLoopPlan(elem, opts) {
|
|
|
20295
20899
|
if (elem.childComponent) {
|
|
20296
20900
|
return buildComponentLoopPlan(elem, opts.profileComponentName);
|
|
20297
20901
|
}
|
|
20298
|
-
return buildPlainLoopPlan(elem, opts.profileComponentName);
|
|
20902
|
+
return buildPlainLoopPlan(elem, opts.profileComponentName, opts.lazyScope);
|
|
20299
20903
|
}
|
|
20300
|
-
function buildPlainLoopPlan(elem, profileComponentName) {
|
|
20904
|
+
function buildPlainLoopPlan(elem, profileComponentName, lazyScope) {
|
|
20301
20905
|
const wrap = (expr) => wrapLoopParamAsAccessor(expr, elem.param, elem.paramBindings);
|
|
20302
20906
|
const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
|
|
20303
20907
|
const hasReactive2 = elem.bindings.reactiveAttrs.length > 0 || elem.bindings.reactiveTexts.length > 0 || elem.bindings.conditionals.length > 0;
|
|
@@ -20326,30 +20930,48 @@ function buildPlainLoopPlan(elem, profileComponentName) {
|
|
|
20326
20930
|
preambleRegions: []
|
|
20327
20931
|
};
|
|
20328
20932
|
}
|
|
20933
|
+
const arrayExpr = buildChainedArrayExpr(elem);
|
|
20934
|
+
const indexParam = elem.index || "__idx";
|
|
20935
|
+
const mapPreambleWrapped = elem.preamble ? renderPreamble(elem.preamble, {
|
|
20936
|
+
transformJs: wrap,
|
|
20937
|
+
renderLeaf: (ir) => irToHtmlTemplate(ir, void 0, 1, [{ param: elem.param, bindings: elem.paramBindings }], void 0, true)
|
|
20938
|
+
}) : "";
|
|
20939
|
+
const preambleRegions = buildPreambleRegionPlans(elem.preambleRegions, elem.param, elem.paramBindings);
|
|
20329
20940
|
return {
|
|
20330
20941
|
kind: "plain",
|
|
20331
20942
|
rowConstruction: "string-template",
|
|
20332
20943
|
containerVar: `_${varSlotId(elem.slotId)}`,
|
|
20333
20944
|
markerId: elem.markerId,
|
|
20334
20945
|
profileLoopId: profileComponentName ? `${profileComponentName}#binding:${elem.slotId}` : void 0,
|
|
20335
|
-
arrayExpr
|
|
20946
|
+
arrayExpr,
|
|
20336
20947
|
keyFn: loopKeyFn(elem),
|
|
20337
20948
|
paramHead,
|
|
20338
20949
|
paramUnwrap,
|
|
20339
|
-
indexParam
|
|
20950
|
+
indexParam,
|
|
20951
|
+
// Lazy row graph (§9, L3). `null` for every ineligible loop, which then
|
|
20952
|
+
// keeps the eager emission below byte-for-byte.
|
|
20953
|
+
lazyRow: buildLazyRowPlan({
|
|
20954
|
+
loop: elem,
|
|
20955
|
+
arrayExpr,
|
|
20956
|
+
indexParam,
|
|
20957
|
+
paramUnwrap,
|
|
20958
|
+
mapPreambleWrapped,
|
|
20959
|
+
preambleRegionCount: preambleRegions.length,
|
|
20960
|
+
callSite: "plain",
|
|
20961
|
+
flatMapLeafItem: false,
|
|
20962
|
+
anchored: elem.bodyIsItemConditional ?? false,
|
|
20963
|
+
scope: lazyScope
|
|
20964
|
+
}) ?? void 0,
|
|
20340
20965
|
// Stage 3 / D4 — js segments get the loop-param accessor wrap; jsx leaves
|
|
20341
20966
|
// render as HTML-string templates under this loop's param context so a
|
|
20342
20967
|
// leaf that reads the item (`r`) becomes `r()`.
|
|
20343
|
-
mapPreambleWrapped
|
|
20344
|
-
transformJs: wrap,
|
|
20345
|
-
renderLeaf: (ir) => irToHtmlTemplate(ir, void 0, 1, [{ param: elem.param, bindings: elem.paramBindings }], void 0, true)
|
|
20346
|
-
}) : "",
|
|
20968
|
+
mapPreambleWrapped,
|
|
20347
20969
|
template: elem.template,
|
|
20348
20970
|
skeletonTemplate: elem.skeletonTemplate,
|
|
20349
20971
|
skeletonPaths: elem.skeletonPaths,
|
|
20350
20972
|
reactiveEffects: hasReactive2 ? buildLoopReactiveEffectsPlan(elem, profileComponentName) : null,
|
|
20351
20973
|
childRefs: buildChildRefBindings(elem.bindings.refs, elem.param, elem.paramBindings),
|
|
20352
|
-
preambleRegions
|
|
20974
|
+
preambleRegions,
|
|
20353
20975
|
bodyIsMultiRoot: elem.bodyIsMultiRoot ?? false,
|
|
20354
20976
|
anchored: elem.bodyIsItemConditional ?? false,
|
|
20355
20977
|
// Fall back to the iteration index when the loop has no key. A whole-item
|
|
@@ -20411,6 +21033,7 @@ var init_build_loop = __esm({
|
|
|
20411
21033
|
init_utils();
|
|
20412
21034
|
init_shared();
|
|
20413
21035
|
init_build_reactive_effects();
|
|
21036
|
+
init_build_lazy_row();
|
|
20414
21037
|
init_build_component_loop();
|
|
20415
21038
|
init_build_composite_loop();
|
|
20416
21039
|
init_html_template();
|
|
@@ -20421,7 +21044,7 @@ var init_build_loop = __esm({
|
|
|
20421
21044
|
function emitConditionalUpdates(lines, ctx2) {
|
|
20422
21045
|
const profileComponentName = ctx2.profile ? ctx2.componentName : void 0;
|
|
20423
21046
|
for (const elem of ctx2.conditionalElements) {
|
|
20424
|
-
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "dom", profileComponentName });
|
|
21047
|
+
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "dom", profileComponentName, lazyScope: buildLazyRowScopeInfo(ctx2) });
|
|
20425
21048
|
stringifyInsert(lines, plan, { leadingIndent: " ", bodyIndent: " " });
|
|
20426
21049
|
lines.push("");
|
|
20427
21050
|
}
|
|
@@ -20429,17 +21052,19 @@ function emitConditionalUpdates(lines, ctx2) {
|
|
|
20429
21052
|
function emitClientOnlyConditionals(lines, ctx2) {
|
|
20430
21053
|
const profileComponentName = ctx2.profile ? ctx2.componentName : void 0;
|
|
20431
21054
|
for (const elem of ctx2.clientOnlyConditionals) {
|
|
20432
|
-
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "raw", profileComponentName });
|
|
21055
|
+
const plan = buildInsertPlan(elem, { scope: { kind: "top" }, eventNameMode: "raw", profileComponentName, lazyScope: buildLazyRowScopeInfo(ctx2) });
|
|
20433
21056
|
lines.push(` // @client conditional: ${elem.slotId}`);
|
|
20434
21057
|
stringifyInsert(lines, plan, { leadingIndent: " ", bodyIndent: " " });
|
|
20435
21058
|
lines.push("");
|
|
20436
21059
|
}
|
|
20437
21060
|
}
|
|
20438
21061
|
function emitLoopUpdates(lines, ctx2, unsafeLocalNames) {
|
|
21062
|
+
const lazyScope = buildLazyRowScopeInfo(ctx2);
|
|
20439
21063
|
for (const elem of ctx2.loopElements) {
|
|
20440
21064
|
const plan = buildLoopPlan(elem, {
|
|
20441
21065
|
unsafeLocalNames,
|
|
20442
|
-
profileComponentName: ctx2.profile ? ctx2.componentName : void 0
|
|
21066
|
+
profileComponentName: ctx2.profile ? ctx2.componentName : void 0,
|
|
21067
|
+
lazyScope
|
|
20443
21068
|
});
|
|
20444
21069
|
internalInvariant(
|
|
20445
21070
|
!(elem.preamble && elem.preamble.builderNames.length > 0 && plan.rowConstruction === "dom-ops"),
|
|
@@ -20467,6 +21092,7 @@ var init_control_flow = __esm({
|
|
|
20467
21092
|
init_build_insert();
|
|
20468
21093
|
init_insert();
|
|
20469
21094
|
init_build_loop();
|
|
21095
|
+
init_build_lazy_row();
|
|
20470
21096
|
init_loop();
|
|
20471
21097
|
init_build_event_delegation();
|
|
20472
21098
|
init_event_delegation();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "CLI for agent-driven UI component discovery and scaffolding",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"esbuild": "^0.25.0",
|
|
31
31
|
"typescript": "^5.0.0",
|
|
32
|
-
"@barefootjs/client": "0.
|
|
33
|
-
"@barefootjs/shared": "0.
|
|
32
|
+
"@barefootjs/client": "0.28.0",
|
|
33
|
+
"@barefootjs/shared": "0.28.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@barefootjs/jsx": "0.
|
|
36
|
+
"@barefootjs/jsx": "0.28.0",
|
|
37
37
|
"@types/node": "^22.0.0",
|
|
38
38
|
"@happy-dom/global-registrator": "^20.0.11",
|
|
39
39
|
"happy-dom": "^20.0.11"
|