@barefootjs/jsx 0.26.4 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/compiler.d.ts.map +1 -1
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +941 -130
  5. package/dist/ir-to-client-js/client-only-elision.d.ts +103 -0
  6. package/dist/ir-to-client-js/client-only-elision.d.ts.map +1 -0
  7. package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
  8. package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts +6 -0
  9. package/dist/ir-to-client-js/control-flow/plan/branch-loop.d.ts.map +1 -1
  10. package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts +2 -1
  11. package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts.map +1 -1
  12. package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts +7 -0
  13. package/dist/ir-to-client-js/control-flow/plan/build-insert.d.ts.map +1 -1
  14. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts +107 -0
  15. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts.map +1 -0
  16. package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts +9 -1
  17. package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts.map +1 -1
  18. package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts +203 -0
  19. package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts.map +1 -0
  20. package/dist/ir-to-client-js/control-flow/plan/loop.d.ts +10 -0
  21. package/dist/ir-to-client-js/control-flow/plan/loop.d.ts.map +1 -1
  22. package/dist/ir-to-client-js/control-flow/shared.d.ts +1 -1
  23. package/dist/ir-to-client-js/control-flow/stringify/branch-loop.d.ts.map +1 -1
  24. package/dist/ir-to-client-js/control-flow/stringify/claim-plan.d.ts +54 -0
  25. package/dist/ir-to-client-js/control-flow/stringify/claim-plan.d.ts.map +1 -0
  26. package/dist/ir-to-client-js/control-flow/stringify/inner-loop.d.ts.map +1 -1
  27. package/dist/ir-to-client-js/control-flow/stringify/insert.d.ts.map +1 -1
  28. package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts +98 -0
  29. package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -0
  30. package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts +5 -0
  31. package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts.map +1 -1
  32. package/dist/ir-to-client-js/control-flow/stringify/loop.d.ts +17 -20
  33. package/dist/ir-to-client-js/control-flow/stringify/loop.d.ts.map +1 -1
  34. package/dist/ir-to-client-js/control-flow/stringify/reactive-effects.d.ts +63 -4
  35. package/dist/ir-to-client-js/control-flow/stringify/reactive-effects.d.ts.map +1 -1
  36. package/dist/ir-to-client-js/control-flow.d.ts +1 -1
  37. package/dist/ir-to-client-js/control-flow.d.ts.map +1 -1
  38. package/dist/ir-to-client-js/element-refs.d.ts +8 -3
  39. package/dist/ir-to-client-js/element-refs.d.ts.map +1 -1
  40. package/dist/ir-to-client-js/emit-reactive.d.ts +8 -1
  41. package/dist/ir-to-client-js/emit-reactive.d.ts.map +1 -1
  42. package/dist/ir-to-client-js/html-template.d.ts +24 -0
  43. package/dist/ir-to-client-js/html-template.d.ts.map +1 -1
  44. package/dist/ir-to-client-js/imports.d.ts +2 -2
  45. package/dist/ir-to-client-js/imports.d.ts.map +1 -1
  46. package/dist/ir-to-client-js/reactivity.d.ts.map +1 -1
  47. package/dist/ir-to-client-js/types.d.ts +9 -1
  48. package/dist/ir-to-client-js/types.d.ts.map +1 -1
  49. package/dist/ir-to-client-js/utils.d.ts +1 -1
  50. package/dist/types.d.ts +25 -2
  51. package/dist/types.d.ts.map +1 -1
  52. package/package.json +2 -2
  53. package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +542 -689
  54. package/src/__tests__/child-components-in-map.test.ts +4 -4
  55. package/src/__tests__/client-js-generation.test.ts +23 -12
  56. package/src/__tests__/composite-branch-loop.test.ts +14 -5
  57. package/src/__tests__/conditional-mapArray-key.test.ts +7 -1
  58. package/src/__tests__/create-selector.test.ts +21 -7
  59. package/src/__tests__/cross-file-client-signal.test.ts +5 -1
  60. package/src/__tests__/early-return-scope-var-ref.test.ts +10 -11
  61. package/src/__tests__/inline-jsx-callback.test.ts +6 -4
  62. package/src/__tests__/ir-jsx-props.test.ts +6 -5
  63. package/src/__tests__/lazy-row-eligibility.test.ts +692 -0
  64. package/src/__tests__/loop-branch-bare-expression-reactive-text.test.ts +98 -0
  65. package/src/__tests__/loop-fallback-wrap.test.ts +34 -16
  66. package/src/__tests__/loop-hoisted-template.test.ts +10 -6
  67. package/src/__tests__/module-level-signal.audit.test.ts +7 -2
  68. package/src/__tests__/nested-loop-conditional.test.ts +9 -7
  69. package/src/__tests__/nested-loop-reactive-attrs.test.ts +2 -2
  70. package/src/__tests__/preamble-region-patch.test.ts +18 -12
  71. package/src/__tests__/profile-cond-binding-ids.test.ts +3 -2
  72. package/src/__tests__/profile-loop-binding-ids.test.ts +4 -3
  73. package/src/__tests__/profile-nested-binding-ids.test.ts +11 -6
  74. package/src/__tests__/reactive-attrs-in-map.test.ts +6 -4
  75. package/src/__tests__/static-loop-csr-materialize.test.ts +6 -1
  76. package/src/__tests__/template-closure.test.ts +1 -1
  77. package/src/compiler.ts +11 -0
  78. package/src/index.ts +1 -0
  79. package/src/ir-to-client-js/client-only-elision.ts +273 -0
  80. package/src/ir-to-client-js/collect-elements.ts +56 -17
  81. package/src/ir-to-client-js/control-flow/plan/branch-loop.ts +6 -0
  82. package/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts +35 -12
  83. package/src/ir-to-client-js/control-flow/plan/build-insert.ts +9 -2
  84. package/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts +305 -0
  85. package/src/ir-to-client-js/control-flow/plan/build-loop.ts +44 -12
  86. package/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts +440 -0
  87. package/src/ir-to-client-js/control-flow/plan/loop.ts +10 -0
  88. package/src/ir-to-client-js/control-flow/shared.ts +1 -1
  89. package/src/ir-to-client-js/control-flow/stringify/branch-loop.ts +34 -4
  90. package/src/ir-to-client-js/control-flow/stringify/claim-plan.ts +68 -0
  91. package/src/ir-to-client-js/control-flow/stringify/inner-loop.ts +18 -9
  92. package/src/ir-to-client-js/control-flow/stringify/insert.ts +17 -11
  93. package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +478 -0
  94. package/src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts +41 -17
  95. package/src/ir-to-client-js/control-flow/stringify/loop.ts +71 -46
  96. package/src/ir-to-client-js/control-flow/stringify/reactive-effects.ts +241 -31
  97. package/src/ir-to-client-js/control-flow.ts +8 -3
  98. package/src/ir-to-client-js/element-refs.ts +9 -11
  99. package/src/ir-to-client-js/emit-reactive.ts +50 -14
  100. package/src/ir-to-client-js/html-template.ts +29 -9
  101. package/src/ir-to-client-js/imports.ts +13 -4
  102. package/src/ir-to-client-js/reactivity.ts +3 -2
  103. package/src/ir-to-client-js/types.ts +10 -2
  104. package/src/ir-to-client-js/utils.ts +1 -1
  105. package/src/jsx-to-ir.ts +26 -8
  106. package/src/types.ts +25 -2
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Slot unification Step B (`spec/slot-unification.md` §3(b), §5 "Step B —
3
+ * marker elision"): decide, EXACTLY ONCE and BEFORE either `adapter.generate`
4
+ * (SSR) or `generateClientJs` (CSR) run, which `/* @client *\/` text slots
5
+ * can drop their `<!--bf:sN-->…<!--/-->` marker pair entirely from both
6
+ * outputs. Every consumer (all nine SSR adapters' `renderExpression`, and
7
+ * the CSR emitters in `html-template.ts`) reads the single
8
+ * `IRExpression.markerless` flag this pass writes — nobody re-derives the
9
+ * decision, per CLAUDE.md's "Never add compiler options/hooks for
10
+ * tool-specific output rewriting" spirit: one door in, everyone reads it.
11
+ *
12
+ * Scope — deliberately the NARROWEST slice of §3(b)'s elision rule that is
13
+ * fully sound today, not the general case:
14
+ *
15
+ * Only `expr.clientOnly && expr.slotId` expressions OUTSIDE any loop or
16
+ * conditional branch (i.e. reachable from the component's own render tree
17
+ * by walking only `element`/`text`/`expression`/`fragment` nodes).
18
+ *
19
+ * Why THIS slice and not ordinary reactive text slots (loop rows,
20
+ * conditional branches): every other kind of slot's SSR-rendered width is
21
+ * DATA-DEPENDENT — an ordinary `{item.name}` may render empty or non-empty
22
+ * per request, so a LATER sibling's absolute child-index path would only be
23
+ * valid for the specific width THIS request happened to produce, not for
24
+ * every request the compiled function ever serves. `/* @client *\/`
25
+ * expressions are the one case free of that problem: SSR can never evaluate
26
+ * client-only JS (the whole point of the escape valve), so its rendered
27
+ * width is deterministically ZERO on every request, for every adapter, with
28
+ * no data dependence at all. That determinism is what makes computing a
29
+ * real, reusable, hydration-safe path sound here without also solving the
30
+ * general "does an earlier sibling's width vary by request" problem.
31
+ *
32
+ * Path safety within that scope — the part that generalizes A3's
33
+ * `computeSkeletonSlotPaths` (`html-template.ts`) rather than reinventing
34
+ * it: paths are root-relative child-index chains, exactly like that
35
+ * function's, walked in document order with the SAME "once we hit something
36
+ * whose contributed width isn't a compile-time constant, every remaining
37
+ * sibling AND everything nested inside it loses eligibility" rule (nested
38
+ * content reached only through an uncertain-index sibling would resolve an
39
+ * absolute path through that uncertain index — silently wrong, not loud, so
40
+ * it must never be attempted). Concretely, walking a children list left to
41
+ * right:
42
+ * - a static `element` always contributes exactly one node — recurse into
43
+ * its own children as an independent, freshly-indexed scope (its own
44
+ * internal accounting can't leak out, and nothing external can poison
45
+ * it either, since the element itself is a fixed anchor regardless of
46
+ * what's inside it);
47
+ * - static `text` contributes a node per HTML-parser text-run-merging
48
+ * rules (adjacent text/expression children collapse into ONE Text
49
+ * node — mirrors `computeSkeletonSlotPaths`'s `pendingText` tracking);
50
+ * - a `clientOnly` expression with a slotId is the one ELIGIBLE case,
51
+ * PROVIDED it is not itself part of a merged text run (rule (i) — the
52
+ * `/* @client *\/` slot must not be immediately adjacent, once markers
53
+ * are gone, to loose text or another expression, or the HTML parser
54
+ * would merge them into one Text node with no way to tell which
55
+ * content is which). Once one is elided, this level (and everything
56
+ * nested inside any later sibling) is marked ineligible for the
57
+ * remainder of the walk at this level — see the "freeze" note below;
58
+ * - any other `expression` (a real reactive/static text or markup slot),
59
+ * any `conditional`/`loop`/`component`/`async`/`provider`/
60
+ * `if-statement`/`slot` node, is data-dependent or opaque width and
61
+ * FREEZES the rest of this children list (see below) — this is
62
+ * strictly conservative: it also means a `/* @client *\/` expression
63
+ * is never eligible once any of these appears earlier at the same
64
+ * level, even though `/* @client *\/`'s own width is always zero,
65
+ * because SIBLINGS reached only via nested recursion past that point
66
+ * would otherwise resolve an absolute path through the frozen node's
67
+ * uncertain contributed width;
68
+ * - the same hazard-tag / force-close-group / void-element / `<tr>`
69
+ * foster-parenting guards `computeSkeletonSlotPaths` uses (imported,
70
+ * not re-derived) abort the ENTIRE walk (a global bail, exactly like
71
+ * that function's `state.bailed`) — a parser hazard means every index
72
+ * computed anywhere in this tree is suspect, not just the ones near
73
+ * the hazard, so "don't guess" means don't guess about the blast
74
+ * radius either.
75
+ *
76
+ * "Freeze" (the one simplification versus a maximally-precise per-branch
77
+ * eligibility tracker): once ANY `/* @client *\/` slot at a given level is
78
+ * elided — OR once anything data-dependent/opaque is seen at that level —
79
+ * that level's remaining siblings (and anything nested only through them)
80
+ * stop being assigned real paths for the rest of THIS walk, even though a
81
+ * maximally precise analysis could sometimes still find one. This caps
82
+ * elision at (at most) one `/* @client *\/` slot per static subtree —
83
+ * conservative by design, matching the elision rule's own framing, and it
84
+ * guarantees two elided slots can never end up needing an insertion whose
85
+ * reference node depends on the other's still-unresolved width. Freezing is
86
+ * PER CHILDREN-LIST (an element's own children start a fresh, unfrozen
87
+ * scope) — global-bail is reserved for hazard tags alone.
88
+ *
89
+ * Deferred (loudly, not silently): ordinary reactive text slots in loop
90
+ * rows / conditional branches keep their markers — see above for why
91
+ * widening this to data-dependent-width content needs a materially
92
+ * different (and per-adapter-verified) safety argument that this PR does
93
+ * not attempt.
94
+ */
95
+ import type { IRNode } from '../types.ts';
96
+ /**
97
+ * Entry point: mutates `root`'s `expression` nodes in place, setting
98
+ * `markerless`/`elidedPath` on every eligible `/* @client *\/` slot found.
99
+ * Safe to call on any component's render tree; a tree with none simply
100
+ * mutates nothing.
101
+ */
102
+ export declare function decideClientOnlyElision(root: IRNode): void;
103
+ //# sourceMappingURL=client-only-elision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-only-elision.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/client-only-elision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,aAAa,CAAA;AAmBvD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"collect-elements.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/collect-elements.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAoC,KAAK,MAAM,EAAmC,MAAM,aAAa,CAAA;AACzH,OAAO,KAAK,EAAE,eAAe,EAA+H,iBAAiB,EAA0B,oBAAoB,EAAc,UAAU,EAAE,MAAM,YAAY,CAAA;AAyGvQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA0C7E;AAyBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,wBAIpC,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,cAAc,CAAC,EAAE,MAAM,EACvB,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,wBAAwB,GACjC,UAAU,EAAE,CAyId;AAqKD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,iBAAiB,UAAQ,GACxB,IAAI,CA+RN;AAuYD;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,SAAS,OAAO,aAAa,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAC/E,iBAAiB,CAenB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,CAAC,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,SAAS,OAAO,aAAa,EAAE,gBAAgB,EAAE,GACpE,oBAAoB,EAAE,CA4DxB"}
1
+ {"version":3,"file":"collect-elements.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/collect-elements.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAoC,KAAK,MAAM,EAAmC,MAAM,aAAa,CAAA;AACzH,OAAO,KAAK,EAAE,eAAe,EAA+H,iBAAiB,EAA0B,oBAAoB,EAAc,UAAU,EAAE,MAAM,YAAY,CAAA;AAyGvQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA0C7E;AAyBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,wBAIpC,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,cAAc,CAAC,EAAE,MAAM,EACvB,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,wBAAwB,GACjC,UAAU,EAAE,CAyId;AAqKD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,iBAAiB,UAAQ,GACxB,IAAI,CAmSN;AAuYD;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,SAAS,OAAO,aAAa,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAC/E,iBAAiB,CAenB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,CAAC,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,SAAS,OAAO,aAAa,EAAE,gBAAgB,EAAE,GACpE,oBAAoB,EAAE,CA4DxB"}
@@ -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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"}
@@ -16,7 +16,7 @@ import type { IRLoopChildComponent, LoopParamBinding } from '../../types.ts';
16
16
  import type { LoopChildRefBinding, PreambleRegionPlan } from './plan/loop.ts';
17
17
  import type { PreambleRegionSource } from '../../types.ts';
18
18
  /**
19
- * Build the `keyFn` argument for mapArray / reconcileElements. `null` when
19
+ * Build the `keyFn` argument for mapArray / mapArrayAnchored. `null` when
20
20
  * the loop has no key expression. Every `CollectedLoop` variant (top-level /
21
21
  * branch / nested) carries an `index: string | null` field (#2218 threaded
22
22
  * it onto `NestedLoop` too), so the index param — when present — is always
@@ -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"}