@barefootjs/jsx 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.
Files changed (50) hide show
  1. package/dist/index.js +620 -26
  2. package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts +6 -0
  3. package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts.map +1 -1
  4. package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts +2 -1
  5. package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts.map +1 -1
  6. package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts +7 -0
  7. package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts.map +1 -1
  8. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts +107 -0
  9. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts.map +1 -0
  10. package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts +9 -1
  11. package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts.map +1 -1
  12. package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts +203 -0
  13. package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts.map +1 -0
  14. package/dist/ir-to-client-js/control-flow/plan/loop.d.ts +10 -0
  15. package/dist/ir-to-client-js/control-flow/plan/loop.d.ts.map +1 -1
  16. package/dist/ir-to-client-js/control-flow/stringify/branch-loop.d.ts.map +1 -1
  17. package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts +98 -0
  18. package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -0
  19. package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts +5 -0
  20. package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts.map +1 -1
  21. package/dist/ir-to-client-js/control-flow/stringify/loop.d.ts.map +1 -1
  22. package/dist/ir-to-client-js/control-flow.d.ts.map +1 -1
  23. package/dist/ir-to-client-js/imports.d.ts +2 -2
  24. package/dist/ir-to-client-js/imports.d.ts.map +1 -1
  25. package/package.json +2 -2
  26. package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +162 -36
  27. package/src/__tests__/client-js-generation.test.ts +4 -1
  28. package/src/__tests__/composite-branch-loop.test.ts +12 -3
  29. package/src/__tests__/conditional-mapArray-key.test.ts +7 -1
  30. package/src/__tests__/create-selector.test.ts +21 -7
  31. package/src/__tests__/lazy-row-eligibility.test.ts +692 -0
  32. package/src/__tests__/loop-branch-bare-expression-reactive-text.test.ts +98 -0
  33. package/src/__tests__/loop-fallback-wrap.test.ts +31 -12
  34. package/src/__tests__/loop-hoisted-template.test.ts +10 -6
  35. package/src/__tests__/static-loop-csr-materialize.test.ts +6 -1
  36. package/src/ir-to-client-js/collect-elements.ts +48 -13
  37. package/src/ir-to-client-js/control-flow/plan/branch-loop.ts +6 -0
  38. package/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts +35 -12
  39. package/src/ir-to-client-js/control-flow/plan/build-insert.ts +9 -2
  40. package/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts +305 -0
  41. package/src/ir-to-client-js/control-flow/plan/build-loop.ts +44 -12
  42. package/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts +440 -0
  43. package/src/ir-to-client-js/control-flow/plan/loop.ts +10 -0
  44. package/src/ir-to-client-js/control-flow/stringify/branch-loop.ts +22 -0
  45. package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +478 -0
  46. package/src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts +6 -1
  47. package/src/ir-to-client-js/control-flow/stringify/loop.ts +23 -0
  48. package/src/ir-to-client-js/control-flow.ts +7 -2
  49. package/src/ir-to-client-js/imports.ts +8 -2
  50. package/src/jsx-to-ir.ts +18 -1
@@ -17,6 +17,7 @@
17
17
  import type { CompositeLoopPlan, LoopChildRefBinding, PreambleRegionPlan } from './loop.ts';
18
18
  import type { EventDelegationPlan } from './event-delegation.ts';
19
19
  import type { ReactiveEffectsPlan } from './reactive-effects.ts';
20
+ import type { LazyRowPlanData } from './build-lazy-row.ts';
20
21
  export interface BranchPlainLoopPlan {
21
22
  /**
22
23
  * flatMap descriptor mode — see `PlainLoopVariant.flatMapLeafItem`
@@ -87,6 +88,11 @@ export interface BranchPlainLoopPlan {
87
88
  * renderItem layout, mirroring the top-level plain plan.
88
89
  */
89
90
  preambleRegions: readonly PreambleRegionPlan[];
91
+ /**
92
+ * Lazy row graph plan (`spec/slot-unification.md` §9, L3) — see
93
+ * `PlainLoopVariant.lazyRow`. Undefined ⇒ today's eager emission.
94
+ */
95
+ lazyRow?: LazyRowPlanData;
90
96
  }
91
97
  export interface BranchCompositeLoopPlan {
92
98
  kind: 'composite';
@@ -1 +1 @@
1
- {"version":3,"file":"branch-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/branch-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAEhE,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,sEAAsE;IACtE,eAAe,EAAE,iBAAiB,GAAG,SAAS,CAAA;IAC9C;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAA;IACvB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAA;IACpB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAA;IACjB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAA;IACjB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,MAAM,CAAA;IAC1B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,eAAe,EAAE,mBAAmB,GAAG,IAAI,CAAA;IAC3C,+DAA+D;IAC/D,eAAe,EAAE,mBAAmB,CAAA;IACpC;;;;OAIG;IACH,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAA;IACzC;;;OAGG;IACH,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,eAAe,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAC/C;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,WAAW,CAAA;IACjB,4DAA4D;IAC5D,SAAS,EAAE,iBAAiB,CAAA;IAC5B,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAA;IACvB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,MAAM,cAAc,GAAG,mBAAmB,GAAG,uBAAuB,CAAA"}
1
+ {"version":3,"file":"branch-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/branch-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAE1D,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,sEAAsE;IACtE,eAAe,EAAE,iBAAiB,GAAG,SAAS,CAAA;IAC9C;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAA;IACvB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAA;IACpB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAA;IACjB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAA;IACjB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,MAAM,CAAA;IAC1B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,eAAe,EAAE,mBAAmB,GAAG,IAAI,CAAA;IAC3C,+DAA+D;IAC/D,eAAe,EAAE,mBAAmB,CAAA;IACpC;;;;OAIG;IACH,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAA;IACzC;;;OAGG;IACH,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,eAAe,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC9C;;;OAGG;IACH,OAAO,CAAC,EAAE,eAAe,CAAA;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,WAAW,CAAA;IACjB,4DAA4D;IAC5D,SAAS,EAAE,iBAAiB,CAAA;IAC5B,0DAA0D;IAC1D,eAAe,EAAE,MAAM,CAAA;IACvB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,MAAM,cAAc,GAAG,mBAAmB,GAAG,uBAAuB,CAAA"}
@@ -10,6 +10,7 @@
10
10
  * event-delegation plan.
11
11
  */
12
12
  import type { BranchLoop } from '../../types.ts';
13
+ import type { LazyRowScopeInfo } from './lazy-row-eligibility.ts';
13
14
  import type { BranchLoopPlan } from './branch-loop.ts';
14
- export declare function buildBranchLoopPlan(loop: BranchLoop, profileComponentName?: string): BranchLoopPlan;
15
+ export declare function buildBranchLoopPlan(loop: BranchLoop, profileComponentName?: string, lazyScope?: LazyRowScopeInfo): BranchLoopPlan;
15
16
  //# sourceMappingURL=build-branch-loop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-branch-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/build-branch-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAOhD,OAAO,KAAK,EAEV,cAAc,EAEf,MAAM,kBAAkB,CAAA;AAEzB,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,cAAc,CAgEnG"}
1
+ {"version":3,"file":"build-branch-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/build-branch-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAMhD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAGjE,OAAO,KAAK,EAEV,cAAc,EAEf,MAAM,kBAAkB,CAAA;AAEzB,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,UAAU,EAChB,oBAAoB,CAAC,EAAE,MAAM,EAC7B,SAAS,CAAC,EAAE,gBAAgB,GAC3B,cAAc,CAiFhB"}
@@ -8,12 +8,19 @@
8
8
  * data-to-text mapping.
9
9
  */
10
10
  import type { ConditionalElement } from '../../types.ts';
11
+ import type { LazyRowScopeInfo } from './lazy-row-eligibility.ts';
11
12
  import type { InsertPlan, ScopeRef } from './types.ts';
12
13
  export interface BuildInsertOptions {
13
14
  scope: ScopeRef;
14
15
  eventNameMode: 'dom' | 'raw';
15
16
  /** Owning component name in profile mode (#1690, SR3) — else undefined. */
16
17
  profileComponentName?: string;
18
+ /**
19
+ * Component-scope name facts for the lazy row graph gate
20
+ * (`spec/slot-unification.md` §9.4). Threaded down to branch-scoped plain
21
+ * loops; omitted → those loops keep today's eager emission.
22
+ */
23
+ lazyScope?: LazyRowScopeInfo;
17
24
  }
18
25
  export declare function buildInsertPlan(elem: ConditionalElement, options: BuildInsertOptions): InsertPlan;
19
26
  //# sourceMappingURL=build-insert.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-insert.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/build-insert.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,KAAK,EACV,UAAU,EAGV,QAAQ,EACT,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,QAAQ,CAAA;IACf,aAAa,EAAE,KAAK,GAAG,KAAK,CAAA;IAC5B,2EAA2E;IAC3E,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,kBAAkB,GAC1B,UAAU,CAaZ"}
1
+ {"version":3,"file":"build-insert.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/build-insert.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,KAAK,EACV,UAAU,EAGV,QAAQ,EACT,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,QAAQ,CAAA;IACf,aAAa,EAAE,KAAK,GAAG,KAAK,CAAA;IAC5B,2EAA2E;IAC3E,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAA;CAC7B;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,kBAAkB,GAC1B,UAAU,CAaZ"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Build the compiler-side `LazyRowPlan` payload (`spec/slot-unification.md`
3
+ * §9, L3) for one plain loop row — or `null` when the row is ineligible and
4
+ * must keep today's eager `mapArray` emission.
5
+ *
6
+ * Everything decided here is BUILD-TIME data: per-binding item/outer
7
+ * classification (`classifyLazyBinding`), ref-array and dedup-slot layout,
8
+ * and the outer-signal prime list. The stringifier
9
+ * (`stringify/lazy-row.ts`) is a deterministic walk over this plan — it
10
+ * makes no classification decision of its own.
11
+ *
12
+ * Free identifiers are never obtained by regex (repo rule). Texts carry
13
+ * `LoopChildReactiveText.freeIdentifiers` from the analyzer; attrs have no
14
+ * such field, so their expression is run through `parseExpression` +
15
+ * `freeIdentifiers` (`expression-parser.ts`) — both of which fail SAFE, the
16
+ * latter returning `null` on an `unsupported` node, which
17
+ * `classifyLazyBinding` turns into "reads both, and opaque".
18
+ */
19
+ import { type AttrMeta } from '../../../types.ts';
20
+ import type { BranchLoop, ClientJsContext, TopLevelLoop } from '../../types.ts';
21
+ import { type LazyRowEligibility, type LazyRowScopeInfo } from './lazy-row-eligibility.ts';
22
+ /** One reactive attribute of a lazy row. */
23
+ export interface LazyRowAttrBinding {
24
+ slotId: string;
25
+ attrName: string;
26
+ /** Already wrapped via `wrapLoopParamAsAccessor` — reads `<param>()`. */
27
+ wrappedExpression: string;
28
+ meta: AttrMeta;
29
+ /** Index into `entry.refs` holding this slot's element. */
30
+ refIndex: number;
31
+ /** Index into `entry.last` holding this binding's dedup value. */
32
+ ordinal: number;
33
+ readsItem: boolean;
34
+ readsOuter: boolean;
35
+ }
36
+ /** One reactive text (content slot) of a lazy row. */
37
+ export interface LazyRowTextBinding {
38
+ slotId: string;
39
+ wrappedExpression: string;
40
+ ordinal: number;
41
+ readsItem: boolean;
42
+ /**
43
+ * Reads at least one reactive outer name — emitted into `applyOuter` with
44
+ * §9.3(1) read-compare-write seeding, which needs the RW claim door
45
+ * (`LazyRowPlanData.textNeedsRead`).
46
+ */
47
+ readsOuter: boolean;
48
+ }
49
+ export interface LazyRowPlanData {
50
+ /** Distinct attr slot ids, in declaration order — `entry.refs[0..n-1]`. */
51
+ attrSlotIds: readonly string[];
52
+ attrs: readonly LazyRowAttrBinding[];
53
+ texts: readonly LazyRowTextBinding[];
54
+ /** Index into `entry.refs` holding the claimed-slot door; -1 when no texts. */
55
+ writerIndex: number;
56
+ /**
57
+ * PER-LOOP door selection (§9.3(1) content seeding): true when at least
58
+ * one text binding is outer-involving and therefore needs `read(id)` to
59
+ * seed by comparison. The emitter then claims through `lazyClaimSlots`
60
+ * (the `{ write, read }` door) and every text write becomes
61
+ * `__r[w].write(...)`; false keeps the single-closure `lazySlots` writer
62
+ * and the bare `__r[w](...)` call form. One decision for the whole loop —
63
+ * the door is a per-ROW allocation, so it must not be chosen per binding.
64
+ */
65
+ textNeedsRead: boolean;
66
+ /** Total `entry.last` slots. */
67
+ lastCount: number;
68
+ /**
69
+ * Signal / memo getters read at the top of `applyOuter` so the ONE
70
+ * loop-level effect subscribes even while the entry list is empty. Empty
71
+ * ⇒ no `applyOuter` is emitted at all (and hydration does literally
72
+ * nothing per row).
73
+ */
74
+ outerPrimeGetters: readonly string[];
75
+ /** True when at least one binding is outer-involving. */
76
+ hasOuter: boolean;
77
+ }
78
+ export interface BuildLazyRowArgs {
79
+ loop: TopLevelLoop | BranchLoop;
80
+ /** Fully-chained array expression as emitted (`buildChainedArrayExpr`). */
81
+ arrayExpr: string;
82
+ indexParam: string;
83
+ /** `destructureLoopParam(...).unwrap` — non-empty ⇒ ineligible. */
84
+ paramUnwrap: string;
85
+ mapPreambleWrapped: string;
86
+ preambleRegionCount: number;
87
+ callSite: 'plain' | 'branch-plain';
88
+ flatMapLeafItem: boolean;
89
+ anchored: boolean;
90
+ scope: LazyRowScopeInfo | undefined;
91
+ }
92
+ /**
93
+ * Returns the lazy row plan when eligible, otherwise `null` plus the
94
+ * decision (exposed for tests / diagnostics via {@link decideLazyRow}).
95
+ */
96
+ export declare function buildLazyRowPlan(args: BuildLazyRowArgs): LazyRowPlanData | null;
97
+ export declare function decideLazyRow(args: BuildLazyRowArgs): {
98
+ plan: LazyRowPlanData | null;
99
+ decision: LazyRowEligibility;
100
+ };
101
+ /**
102
+ * Project a `ClientJsContext` down to the name facts the §9.4 gate resolves
103
+ * against. Built once per component and threaded into every loop plan
104
+ * builder, so the gate never reaches back into the whole context.
105
+ */
106
+ export declare function buildLazyRowScopeInfo(ctx: ClientJsContext): LazyRowScopeInfo;
107
+ //# sourceMappingURL=build-lazy-row.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-lazy-row.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/build-lazy-row.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAG/D,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC/E,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAEtB,MAAM,2BAA2B,CAAA;AAElC,4CAA4C;AAC5C,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,iBAAiB,EAAE,MAAM,CAAA;IACzB,IAAI,EAAE,QAAQ,CAAA;IACd,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACpC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACpC,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;;;;OAQG;IACH,aAAa,EAAE,OAAO,CAAA;IACtB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,yDAAyD;IACzD,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,GAAG,UAAU,CAAA;IAC/B,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,QAAQ,EAAE,OAAO,GAAG,cAAc,CAAA;IAClC,eAAe,EAAE,OAAO,CAAA;IACxB,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAAA;CACpC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,GAAG,eAAe,GAAG,IAAI,CAE/E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG;IACrD,IAAI,EAAE,eAAe,GAAG,IAAI,CAAA;IAC5B,QAAQ,EAAE,kBAAkB,CAAA;CAC7B,CAuHA;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,GAAG,gBAAgB,CAyB5E"}
@@ -19,6 +19,7 @@
19
19
  * `TopLevelLoop`, and is reused by the branch-loop wrapper plan.
20
20
  */
21
21
  import type { TopLevelLoop } from '../../types.ts';
22
+ import type { LazyRowScopeInfo } from './lazy-row-eligibility.ts';
22
23
  import type { LoopPlan, PlainLoopPlan, StaticLoopPlan } from './types.ts';
23
24
  /** Inputs only the static-array variant consumes. */
24
25
  export interface BuildLoopPlanOptions {
@@ -26,6 +27,13 @@ export interface BuildLoopPlanOptions {
26
27
  unsafeLocalNames: Set<string>;
27
28
  /** Owning component name when compiling in profile mode (#1690) — else undefined. */
28
29
  profileComponentName?: string;
30
+ /**
31
+ * Component-scope name facts for the lazy row graph gate
32
+ * (`spec/slot-unification.md` §9.4, `buildLazyRowScopeInfo`). Omitted →
33
+ * no loop is lazy-eligible, i.e. today's emission everywhere. Optional so
34
+ * hand-built plan fixtures keep type-checking.
35
+ */
36
+ lazyScope?: LazyRowScopeInfo;
29
37
  }
30
38
  /**
31
39
  * The single public builder. Selects the variant via the decision tree
@@ -33,7 +41,7 @@ export interface BuildLoopPlanOptions {
33
41
  */
34
42
  export declare function buildLoopPlan(elem: TopLevelLoop, opts: BuildLoopPlanOptions): LoopPlan;
35
43
  /** @internal — prefer `buildLoopPlan`. Exported for the branch-loop wrapper only. */
36
- export declare function buildPlainLoopPlan(elem: TopLevelLoop, profileComponentName?: string): PlainLoopPlan;
44
+ export declare function buildPlainLoopPlan(elem: TopLevelLoop, profileComponentName?: string, lazyScope?: LazyRowScopeInfo): PlainLoopPlan;
37
45
  /** @internal — prefer `buildLoopPlan`. */
38
46
  export declare function buildStaticLoopPlan(elem: TopLevelLoop, unsafeLocalNames: Set<string>, profileComponentName?: string): StaticLoopPlan;
39
47
  //# sourceMappingURL=build-loop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/build-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,gBAAgB,CAAA;AAmBvB,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EAEb,cAAc,EACf,MAAM,YAAY,CAAA;AAEnB,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,8FAA8F;IAC9F,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC7B,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,oBAAoB,GAAG,QAAQ,CAsBtF;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,aAAa,CA6EnG;AAED,0CAA0C;AAC1C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,cAAc,CAmCpI"}
1
+ {"version":3,"file":"build-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/build-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,gBAAgB,CAAA;AAiBvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAIjE,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EAEb,cAAc,EACf,MAAM,YAAY,CAAA;AAEnB,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,8FAA8F;IAC9F,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC7B,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAA;CAC7B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,oBAAoB,GAAG,QAAQ,CAsBtF;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,YAAY,EAClB,oBAAoB,CAAC,EAAE,MAAM,EAC7B,SAAS,CAAC,EAAE,gBAAgB,GAC3B,aAAa,CAgGf;AAED,0CAA0C;AAC1C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC,EAAE,MAAM,GAAG,cAAc,CAmCpI"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Lazy row graph eligibility — `spec/slot-unification.md` §9.4 (L3).
3
+ *
4
+ * ONE explicit decision function (`lazyRowEligibility`) answering a single
5
+ * question: may this plain loop row be emitted through `mapArrayLazy`
6
+ * (a compiler-emitted `LazyRowPlan`, no per-row reactive resources) instead
7
+ * of today's A3b-consolidated eager `mapArray` emission?
8
+ *
9
+ * Sound-or-loud (§9.3): the answer is always either `{ eligible: true }` or
10
+ * `{ eligible: false, reason }`. There is no silent third path — an
11
+ * ineligible loop keeps byte-for-byte today's emission, and `reason` is a
12
+ * human-readable string so a regression is diagnosable from a unit test
13
+ * rather than by diffing generated JS.
14
+ *
15
+ * The gate is deliberately conservative. Every restriction below is a
16
+ * "widen later" decision, never a correctness compromise:
17
+ *
18
+ * 1. **Shape** (§9.4 "plain loop-row shape"): non-anchored, non-flatMap,
19
+ * single-root, keyed, conditional-free, ref-free, no nested components
20
+ * or inner loops.
21
+ * 2. **No preamble.** A `.map()` callback preamble declares row-local
22
+ * bindings (and can declare row-local signals/memos, which need per-row
23
+ * reactivity by definition). Proving "declares no signal/memo" is not
24
+ * cheap here, and every preamble-declared local would land in a
25
+ * binding's free-identifier set as an unresolvable name anyway — so the
26
+ * rule is the cheap conservative one: **any** `mapPreambleWrapped` or
27
+ * any `preambleRegions` entry makes the loop ineligible.
28
+ * 3. **Every reactive outer dependency must be primable.** `mapArrayLazy`
29
+ * creates ONE loop-level effect for `applyOuter`; that effect subscribes
30
+ * only to what its body reads, and its body must read the outer signals
31
+ * even when the entry list is momentarily EMPTY (otherwise the effect
32
+ * never subscribes and the loop goes permanently dead). The emitter
33
+ * primes those reads with `getter()` statements, which is only possible
34
+ * for names it can prove are zero-arg component signal / memo getters.
35
+ * Any other name that could change reactively — a prop accessor (props
36
+ * may be defined as getters over the parent's signals), or a name the
37
+ * compiler cannot classify at all — is `opaque` and makes the loop
38
+ * ineligible. Imports and component-local functions are opaque TOO
39
+ * (`const isSelected = createSelector(selected)` is an ordinary local
40
+ * whose CALL is the reactive read), so they refuse the loop as well —
41
+ * the `inert` set names them only so the refusal can say which one.
42
+ * Genuinely ignorable are the names that cannot carry a reactive read
43
+ * at all: literal-derived local / module constants and pure globals.
44
+ * 4. **Outer-involving TEXT bindings are ACCEPTED** (§9.5, lifted).
45
+ * §9.3(1) requires read-compare-write seeding on `applyOuter`'s first
46
+ * run: compute the value, READ the current DOM, write only on
47
+ * difference. For an attribute that read is `getAttribute` / a DOM
48
+ * property on the held element ref. For a content slot the read door is
49
+ * `lazyClaimSlots`' `read(id)` (`claim-slots.ts`), the read-capable twin
50
+ * of `lazySlots` over the SAME claim. The emitter picks the door per
51
+ * LOOP — a loop with no outer-involving text keeps the single-closure
52
+ * writer — so this widening costs nothing for loops that do not use it
53
+ * (see `refParts` in `stringify/lazy-row.ts`).
54
+ * 5. **Loop-source hydration consistency** (§9.3(2)): item-driven bindings
55
+ * are never evaluated at hydration, so the SSR rows and the first client
56
+ * `items()` read are TRUSTED to agree. That trust is only sound when
57
+ * both derive from the same data — props (identical by construction via
58
+ * the `bf-p` protocol), literals, and derivations thereof. Any name in
59
+ * the loop source that reaches an import, an environment read, or
60
+ * anything the compiler cannot resolve → ineligible.
61
+ * 6. **Profile mode is never lazy** (§9.4, same policy as A3b): a merged
62
+ * loop-level effect would make every binding on every row share one
63
+ * `#binding:<slotId>` id.
64
+ */
65
+ /** Facts about one component signal needed by the §9.3(2) source gate. */
66
+ export interface LazyRowSignalFacts {
67
+ /**
68
+ * Free identifiers of the signal's initializer, derived from its
69
+ * structured `SignalInfo.parsed` tree. `null` when `parsed` was absent or
70
+ * the tree contained an `unsupported` node — "unprovable", which the gate
71
+ * treats as a hard stop rather than an assumption.
72
+ */
73
+ initializerFreeIdentifiers: ReadonlySet<string> | null;
74
+ }
75
+ /** Component-scope facts the gate resolves names against. */
76
+ export interface LazyRowScopeInfo {
77
+ /** Signal getter name → initializer facts. */
78
+ signals: ReadonlyMap<string, LazyRowSignalFacts>;
79
+ /** Memo getter names — reactive and primable via `name()`. */
80
+ memos: ReadonlySet<string>;
81
+ /** Props emit name (`_p`), the source props object name, and every destructured prop param. */
82
+ props: ReadonlySet<string>;
83
+ /**
84
+ * Constant name → free identifiers of its value (`ConstantInfo.freeIdentifiers`).
85
+ * An entry with an EMPTY set is literal-derived. Absent free-id data is
86
+ * modelled as `null` → unprovable for the source gate (but still inert for
87
+ * the binding gate — a `const` never changes reactively).
88
+ */
89
+ constants: ReadonlyMap<string, ReadonlySet<string> | null>;
90
+ /**
91
+ * Import local names and component-local function names. Used ONLY by the
92
+ * §9.3(2) source gate (to name the failure precisely); binding
93
+ * classification treats them as OPAQUE, not inert — see
94
+ * {@link classifyLazyBinding}.
95
+ */
96
+ inert: ReadonlySet<string>;
97
+ /** Profile mode (#1690) — never lazy. */
98
+ profile: boolean;
99
+ }
100
+ /**
101
+ * Sentinel `opaqueOuterNames` entry for "free-identifier analysis produced
102
+ * nothing". Distinct from a real opaque NAME: a name means the identifier
103
+ * set is known and only its primability is not, which the re-subscribe seam
104
+ * handles; this means the set itself is unknown, which nothing can handle.
105
+ */
106
+ export declare const UNKNOWN_IDENTIFIERS = "<unknown>";
107
+ /** One reactive binding of the row, already classified at build time. */
108
+ export interface ClassifiedLazyBinding {
109
+ kind: 'attr' | 'text';
110
+ slotId: string;
111
+ /** Reads the loop param / a destructured param binding. */
112
+ readsItem: boolean;
113
+ /** Reads at least one reactive outer name (or is `opaque`). */
114
+ readsOuter: boolean;
115
+ /**
116
+ * Reactive outer names this binding depends on — signal / memo getters the
117
+ * emitter primes at the top of `applyOuter` so the loop-level effect
118
+ * subscribes even with zero rows.
119
+ */
120
+ reactiveOuterNames: readonly string[];
121
+ /**
122
+ * Outer names that are neither primable (signal/memo) nor provably inert
123
+ * — including the FAIL-SAFE case where free identifiers were unavailable
124
+ * (then `readsItem`/`readsOuter` are both forced true and this carries the
125
+ * `'<unknown>'` sentinel). Non-empty ⇒ ineligible.
126
+ */
127
+ opaqueOuterNames: readonly string[];
128
+ /** References the loop's index parameter — `applyItem`/`applyOuter` have no index. */
129
+ referencesIndex: boolean;
130
+ }
131
+ /** §9.4 shape facts, read off the loop plan / IR by the caller. */
132
+ export interface LazyRowShapeFacts {
133
+ /** Which emission site is asking. Both plain-loop-row sites are in scope. */
134
+ callSite: 'plain' | 'branch-plain';
135
+ flatMapLeafItem: boolean;
136
+ anchored: boolean;
137
+ bodyIsMultiRoot: boolean;
138
+ /** `LoopCore.key != null` — index-keyed loops are ineligible in v1 (§9.4). */
139
+ hasExplicitKey: boolean;
140
+ conditionalCount: number;
141
+ childRefCount: number;
142
+ nestedComponentCount: number;
143
+ innerLoopCount: number;
144
+ hasChildComponent: boolean;
145
+ hasMapPreamble: boolean;
146
+ preambleRegionCount: number;
147
+ /** A destructured loop param with no `paramBindings` (snapshot unwrap). */
148
+ hasParamUnwrap: boolean;
149
+ }
150
+ export interface LazyRowEligibilityArgs {
151
+ shape: LazyRowShapeFacts;
152
+ bindings: readonly ClassifiedLazyBinding[];
153
+ /**
154
+ * Free identifiers of the loop's SOURCE (`LoopCore.arrayFreeIdentifiers`
155
+ * unioned with the free identifiers of the fully-chained array expression,
156
+ * so `.filter(...)`/`.sort(...)` dependencies are covered). `null` when the
157
+ * IR carried none — ineligible, never assumed empty.
158
+ */
159
+ arraySourceIdentifiers: ReadonlySet<string> | null;
160
+ scope: LazyRowScopeInfo;
161
+ }
162
+ export type LazyRowEligibility = {
163
+ eligible: true;
164
+ } | {
165
+ eligible: false;
166
+ reason: string;
167
+ };
168
+ /**
169
+ * Decide whether one plain loop row may use the lazy row graph (§9.4).
170
+ * Pure — every input is pre-resolved data, so this is directly unit-testable
171
+ * without building a component.
172
+ */
173
+ export declare function lazyRowEligibility(args: LazyRowEligibilityArgs): LazyRowEligibility;
174
+ /**
175
+ * Classify one binding's free identifiers into the row-local / reactive-outer
176
+ * / opaque-outer partition {@link lazyRowEligibility} consumes.
177
+ *
178
+ * **FAIL-SAFE (mandatory, §9.2):** when `free` is `null` — the IR carried no
179
+ * pre-computed free identifiers, or `freeIdentifiers()` refused the parsed
180
+ * tree (an `unsupported` node) — BOTH `readsItem` and `readsOuter` are forced
181
+ * true. A binding with `readsItem` is emitted into `applyItem`; a binding with
182
+ * `readsOuter` into `applyOuter`; a binding in both is emitted in BOTH. Double
183
+ * application is idempotent because every emitted write is dedup-guarded
184
+ * against `entry.last`, so "both" is always the safe answer and never a
185
+ * correctness risk.
186
+ *
187
+ * The unknown case ALSO records an `'<unknown>'` opaque name, which makes the
188
+ * loop ineligible: an outer dependency the compiler cannot name is an outer
189
+ * dependency it cannot PRIME, and an unprimed `applyOuter` effect would never
190
+ * subscribe (see module docstring, restriction 3). So the fail-safe direction
191
+ * is preserved (maximally conservative classification) while the emission
192
+ * refuses loudly instead of shipping a dead effect.
193
+ */
194
+ export declare function classifyLazyBinding(args: {
195
+ kind: 'attr' | 'text';
196
+ slotId: string;
197
+ free: ReadonlySet<string> | null;
198
+ /** Loop param name plus every destructured `paramBindings` name. */
199
+ rowLocalNames: ReadonlySet<string>;
200
+ indexParam: string;
201
+ scope: LazyRowScopeInfo;
202
+ }): ClassifiedLazyBinding;
203
+ //# sourceMappingURL=lazy-row-eligibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-row-eligibility.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,7 @@ import type { IRLoopChildComponent } from '../../../types.ts';
20
20
  import type { SkeletonSlotPaths } from '../../html-template.ts';
21
21
  import type { ReactiveEffectsPlan } from './reactive-effects.ts';
22
22
  import type { InnerLoopsPlan } from './inner-loop.ts';
23
+ import type { LazyRowPlanData } from './build-lazy-row.ts';
23
24
  /** Fields shared by every `LoopPlan` variant. */
24
25
  interface LoopPlanCommon {
25
26
  /** Container element variable (e.g. `_s1` for top-level, `__loop_<cv>` for branch). */
@@ -163,6 +164,15 @@ interface PlainLoopVariant extends DynamicLoopCommon {
163
164
  * `__el` to query against.
164
165
  */
165
166
  preambleRegions: readonly PreambleRegionPlan[];
167
+ /**
168
+ * Lazy row graph plan (`spec/slot-unification.md` §9, L3). Non-null when
169
+ * `lazyRowEligibility` accepted this loop: the stringifier emits
170
+ * `mapArrayLazy(...)` with this row plan instead of `mapArray(...)` +
171
+ * renderItem, and the row carries NO per-row reactive resources.
172
+ * Undefined for every ineligible loop — those keep today's emission
173
+ * byte-for-byte (sound-or-loud, `plan/lazy-row-eligibility.ts`).
174
+ */
175
+ lazyRow?: LazyRowPlanData;
166
176
  }
167
177
  /**
168
178
  * Loop body is a single child component (with or without nested child
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/plan/loop.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"branch-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/stringify/branch-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAA;AAE/B,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAW/E;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,SAAS,cAAc,EAAE,GAC/B,IAAI,CAIN"}
1
+ {"version":3,"file":"branch-loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/stringify/branch-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,wBAAwB,CAAA;AAE/B,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAW/E;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,SAAS,cAAc,EAAE,GAC/B,IAAI,CAIN"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Emit a lazy row graph loop — `mapArrayLazy(...)` + a compiler-built
3
+ * `LazyRowPlan` object literal (`spec/slot-unification.md` §9, L3).
4
+ *
5
+ * This is the alternative to `stringifyPlainLoop`'s `mapArray` + renderItem
6
+ * emission, taken only when `lazyRowEligibility` said yes (see
7
+ * `plan/lazy-row-eligibility.ts`). Every ineligible loop keeps today's
8
+ * emission byte-for-byte — sound-or-loud, no silent third path.
9
+ *
10
+ * Output shape:
11
+ *
12
+ * const __tpl_<mid> = document.createElement('template') // hoisted skeleton, when usable
13
+ * __tpl_<mid>.innerHTML = `…`
14
+ * const __lzp_<mid> = [...] // hoisted fresh-clone text paths, when usable
15
+ * const __lzs_<mid> = [{ id, kind: 'text', path: [] }, …] // hoisted claim plan, ADOPTED-row form
16
+ * const __lzsc_<mid> = [{ id, kind: 'text', path: __lzp_<mid>[i] }, …] // FRESH-CLONE form, only when it differs
17
+ * const __lzc_<mid> = (__e) => { … } // lazy ref claim for ADOPTED rows (door slot empty)
18
+ * mapArrayLazy(() => <arr>, <container>, <keyFn>, {
19
+ * createRow: (__e, <idx>) => { … writes every binding, seeds refs+last … },
20
+ * applyItem: (__e) => { … item-driven bindings, dedup against __e.last … },
21
+ * applyOuter: (__es, __seed) => { … one loop-level effect body … },
22
+ * }, '<markerId>')
23
+ *
24
+ * Three shapes carry the plan's obligations (runtime docstring,
25
+ * `packages/client/src/runtime/map-array-lazy.ts`):
26
+ *
27
+ * **`createRow`** — CSR creation. Clones the row, resolves refs from KNOWN
28
+ * clone paths (the hoisted skeleton's `__p`-style child-index chains, reused
29
+ * verbatim from #2143 via `pathExpr`) with no scan, writes ALL bindings
30
+ * (item-driven and outer-involving alike) and seeds `entry.last` so the
31
+ * loop-level outer effect's dedup is correct from the row's first tick.
32
+ *
33
+ * **`applyItem`** — called by the reconciler after `entry.item` changed.
34
+ * Claims refs lazily through `__lzc_<mid>` (a `qsa` scan inside that ONE row)
35
+ * when `entry.refs` is null, materializes the content door on demand
36
+ * (`doorAccess`), then writes each item-driven binding behind a per-binding
37
+ * dedup on `entry.last`.
38
+ *
39
+ * **`applyOuter`** — the ONE loop-level effect body, emitted only when some
40
+ * binding is outer-involving. Two details matter:
41
+ *
42
+ * - **Prime reads first.** The effect subscribes to whatever its body reads.
43
+ * With an empty entry list the per-row loop reads nothing, so the effect
44
+ * would never subscribe and the loop would go permanently dead. The plan
45
+ * therefore emits a bare `getter()` statement per reactive outer name
46
+ * BEFORE the row loop. The eligibility gate guarantees every reactive
47
+ * outer name is a primable zero-arg signal/memo getter.
48
+ * - **Read-compare-write seeding (§9.3(1)).** On the first run (`__seed`)
49
+ * each binding computes its value, READS the current DOM, and writes only
50
+ * on difference — sound even when the outer state is client-only and
51
+ * diverges from SSR, with no writes on the consistent path. The DOM read
52
+ * is per attribute KIND and pairs with `emitAttrUpdate`'s dispatch
53
+ * (`emit-reactive.ts`); any kind this module does not recognise falls back
54
+ * to `true` (always write on seed), which is conservative, never wrong.
55
+ * CONTENT slots seed the same way through the claim's `read(id)` door
56
+ * (§9.5, lifted) — see `refParts` for the per-loop door choice.
57
+ *
58
+ * A loop with NO outer binding emits no `applyOuter` at all — its rows do
59
+ * literally nothing at hydration.
60
+ */
61
+ import type { SkeletonSlotPaths } from '../../html-template.ts';
62
+ import type { LazyRowAttrBinding, LazyRowPlanData } from '../plan/build-lazy-row.ts';
63
+ export interface StringifyLazyRowOptions {
64
+ /** Indent of the `mapArrayLazy(` line itself. */
65
+ indent: string;
66
+ containerVar: string;
67
+ /** Wrap the call in `if (<containerVar>) …` — branch-scoped loops do. */
68
+ guardContainer: boolean;
69
+ markerId: string;
70
+ arrayExpr: string;
71
+ keyFn: string;
72
+ paramHead: string;
73
+ indexParam: string;
74
+ /** Per-row interpolated template (the non-hoisted clone source). */
75
+ template: string;
76
+ skeletonTemplate?: string;
77
+ skeletonPaths?: SkeletonSlotPaths;
78
+ lazyRow: LazyRowPlanData;
79
+ }
80
+ export declare function stringifyLazyRowLoop(lines: string[], o: StringifyLazyRowOptions): void;
81
+ /** `entry.last`-backed dedup test. `in` (not a truthiness check) so a
82
+ * legitimately `undefined` value still records and still writes once. */
83
+ declare function dedupGuard(ordinal: number): string;
84
+ /**
85
+ * Read-compare-write seeding predicate (§9.3(1)): does the CURRENT DOM
86
+ * differ from the value `__x` this binding would write? Mirrors
87
+ * `emitAttrUpdate`'s per-kind dispatch (`emit-reactive.ts`) — the two must
88
+ * be read together. An unrecognised kind returns `true`, i.e. write on the
89
+ * seed run unconditionally: conservative, never unsound.
90
+ */
91
+ declare function seedDiffersExpr(target: string, a: LazyRowAttrBinding): string;
92
+ /** Exported for the emission-shape unit tests. */
93
+ export declare const __lazyRowInternals: {
94
+ seedDiffersExpr: typeof seedDiffersExpr;
95
+ dedupGuard: typeof dedupGuard;
96
+ };
97
+ export {};
98
+ //# sourceMappingURL=lazy-row.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-row.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/stringify/lazy-row.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAQ/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAsB,MAAM,2BAA2B,CAAA;AAExG,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,yEAAyE;IACzE,cAAc,EAAE,OAAO,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAA;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,iBAAiB,CAAA;IACjC,OAAO,EAAE,eAAe,CAAA;CACzB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAuKtF;AAiGD;0EAC0E;AAC1E,iBAAS,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3C;AAqFD;;;;;;GAMG;AACH,iBAAS,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAsBtE;AAED,kDAAkD;AAClD,eAAO,MAAM,kBAAkB;;;CAAkC,CAAA"}
@@ -45,6 +45,11 @@ export declare function stringifyBranchEventBindings(lines: string[], plan: Bran
45
45
  * SSR side: element has `bf-s` → qsa() finds it, initChild wires events.
46
46
  * CSR side: element is a `data-bf-ph` placeholder → createComponent
47
47
  * replaces it, then initChild runs against the new element.
48
+ *
49
+ * The placeholder is passed to `createComponent` as its `mountAt`
50
+ * argument so the component's own init runs connected — context resolves
51
+ * by DOM position, and a detached init falls back to the global,
52
+ * last-writer-wins context store.
48
53
  */
49
54
  export declare function stringifyBranchChildComponentInits(lines: string[], plan: BranchChildComponentInitsPlan, indent: string): void;
50
55
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"loop-child-arm.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,OAAO,KAAK,EACV,6BAA6B,EAC7B,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAEnE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,SAAS,gBAAgB,EAAE,EACjC,MAAM,EAAE,MAAM,EACd,EAAE,CAAC,EAAE,MAAM,GACV,IAAI,CAcN;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,MAAM,GACb,IAAI,CAYN;AAED;;;;;;;;GAQG;AACH,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,6BAA6B,EACnC,MAAM,EAAE,MAAM,GACb,IAAI,CAIN;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,oBAAoB,EAC1B,MAAM,EAAE,MAAM,EACd,EAAE,CAAC,EAAE,MAAM,GACV,IAAI,CA0DN;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EAAE,EACf,YAAY,EAAE,SAAS,wBAAwB,EAAE,EACjD,MAAM,EAAE,MAAM,EACd,EAAE,CAAC,EAAE,MAAM,GACV,IAAI,CAIN;AA0BD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GAAG,SAAS,GACrB,IAAI,CAiDN"}
1
+ {"version":3,"file":"loop-child-arm.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,OAAO,KAAK,EACV,6BAA6B,EAC7B,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAEnE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,SAAS,gBAAgB,EAAE,EACjC,MAAM,EAAE,MAAM,EACd,EAAE,CAAC,EAAE,MAAM,GACV,IAAI,CAcN;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,MAAM,GACb,IAAI,CAYN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,6BAA6B,EACnC,MAAM,EAAE,MAAM,GACb,IAAI,CAIN;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,oBAAoB,EAC1B,MAAM,EAAE,MAAM,EACd,EAAE,CAAC,EAAE,MAAM,GACV,IAAI,CA0DN;AAED;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EAAE,EACf,YAAY,EAAE,SAAS,wBAAwB,EAAE,EACjD,MAAM,EAAE,MAAM,EACd,EAAE,CAAC,EAAE,MAAM,GACV,IAAI,CAIN;AA0BD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EAAE,EACf,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GAAG,SAAS,GACrB,IAAI,CAiDN"}
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/stringify/loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAUH,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEpG;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,SAAS,mBAAmB,EAAE,EACpC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAClH,IAAI,CAaN;AAED;;;;;;;;;;GAUG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAoBnE;AAYD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,aAAa,EACnB,SAAS,GAAE,MAAa,GACvB,IAAI,CAyJN;AAoDD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAkH/E"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../../../src/ir-to-client-js/control-flow/stringify/loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAWH,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEpG;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,SAAS,mBAAmB,EAAE,EACpC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAClH,IAAI,CAaN;AAED;;;;;;;;;;GAUG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAoBnE;AAYD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,aAAa,EACnB,SAAS,GAAE,MAAa,GACvB,IAAI,CA+KN;AAoDD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAkH/E"}
@@ -1 +1 @@
1
- {"version":3,"file":"control-flow.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/control-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAA;AAY/D,yFAAyF;AACzF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,GAAG,IAAI,CAOlF;AAED,8EAA8E;AAC9E,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,GAAG,IAAI,CAQtF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAmB1G"}
1
+ {"version":3,"file":"control-flow.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/control-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAA;AAa/D,yFAAyF;AACzF,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,GAAG,IAAI,CAOlF;AAED,8EAA8E;AAC9E,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,GAAG,IAAI,CAQtF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAuB1G"}