@repobit/dex-store-elements 1.7.2 → 2.0.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 (227) hide show
  1. package/CHANGELOG.md +5 -905
  2. package/README.md +9 -7
  3. package/dist/src/actions/action.adapter.d.ts +36 -0
  4. package/dist/src/actions/action.adapter.js +183 -0
  5. package/dist/src/actions/action.adapter.js.map +1 -0
  6. package/dist/src/actions/action.attributes.d.ts +15 -0
  7. package/dist/src/actions/action.attributes.js +137 -0
  8. package/dist/src/actions/action.attributes.js.map +1 -0
  9. package/dist/src/actions/action.registry.d.ts +4 -0
  10. package/dist/src/actions/action.registry.js +119 -0
  11. package/dist/src/actions/action.registry.js.map +1 -0
  12. package/dist/src/actions/index.d.ts +3 -2
  13. package/dist/src/actions/index.js +3 -80
  14. package/dist/src/actions/index.js.map +1 -1
  15. package/dist/src/compute/compute.expand.d.ts +70 -0
  16. package/dist/src/compute/compute.expand.js +319 -0
  17. package/dist/src/compute/compute.expand.js.map +1 -0
  18. package/dist/src/compute/compute.scan.d.ts +54 -0
  19. package/dist/src/compute/compute.scan.js +160 -0
  20. package/dist/src/compute/compute.scan.js.map +1 -0
  21. package/dist/src/compute/option-resolver.d.ts +31 -0
  22. package/dist/src/compute/option-resolver.js +147 -0
  23. package/dist/src/compute/option-resolver.js.map +1 -0
  24. package/dist/src/contexts/context.compute.d.ts +12 -0
  25. package/dist/src/contexts/context.compute.js +4 -0
  26. package/dist/src/contexts/context.compute.js.map +1 -0
  27. package/dist/src/contexts/context.scope.d.ts +139 -0
  28. package/dist/src/contexts/context.scope.js +48 -0
  29. package/dist/src/contexts/context.scope.js.map +1 -0
  30. package/dist/src/controllers/controller.action-resolve.d.ts +110 -0
  31. package/dist/src/controllers/controller.action-resolve.js +203 -0
  32. package/dist/src/controllers/controller.action-resolve.js.map +1 -0
  33. package/dist/src/controllers/controller.action-topology.d.ts +59 -0
  34. package/dist/src/controllers/controller.action-topology.js +130 -0
  35. package/dist/src/controllers/controller.action-topology.js.map +1 -0
  36. package/dist/src/controllers/controller.compute.d.ts +72 -0
  37. package/dist/src/controllers/controller.compute.js +110 -0
  38. package/dist/src/controllers/controller.compute.js.map +1 -0
  39. package/dist/src/controllers/controller.resolve.d.ts +78 -0
  40. package/dist/src/controllers/controller.resolve.js +205 -0
  41. package/dist/src/controllers/controller.resolve.js.map +1 -0
  42. package/dist/src/core/action-topology.d.ts +62 -0
  43. package/dist/src/core/action-topology.js +67 -0
  44. package/dist/src/core/action-topology.js.map +1 -0
  45. package/dist/src/core/actions.d.ts +64 -0
  46. package/dist/src/core/actions.js +47 -0
  47. package/dist/src/core/actions.js.map +1 -0
  48. package/dist/src/core/node.element.d.ts +179 -0
  49. package/dist/src/core/node.element.js +573 -0
  50. package/dist/src/core/node.element.js.map +1 -0
  51. package/dist/src/core/node.scope.d.ts +374 -0
  52. package/dist/src/core/node.scope.js +558 -0
  53. package/dist/src/core/node.scope.js.map +1 -0
  54. package/dist/src/core/option-update.d.ts +11 -0
  55. package/dist/src/core/option-update.js +59 -0
  56. package/dist/src/core/option-update.js.map +1 -0
  57. package/dist/src/dsl/compilers/array/compiler.js +13 -14
  58. package/dist/src/dsl/compilers/array/compiler.js.map +1 -1
  59. package/dist/src/dsl/compilers/boolean/compiler.d.ts +1 -1
  60. package/dist/src/dsl/compilers/boolean/compiler.js +14 -27
  61. package/dist/src/dsl/compilers/boolean/compiler.js.map +1 -1
  62. package/dist/src/dsl/compilers/enum/compiler.js +7 -10
  63. package/dist/src/dsl/compilers/enum/compiler.js.map +1 -1
  64. package/dist/src/dsl/compilers/index.d.ts +1 -1
  65. package/dist/src/dsl/compilers/index.js +5 -5
  66. package/dist/src/dsl/compilers/index.js.map +1 -1
  67. package/dist/src/dsl/utilty.d.ts +0 -4
  68. package/dist/src/dsl/utilty.js +3 -30
  69. package/dist/src/dsl/utilty.js.map +1 -1
  70. package/dist/src/eta/batch.d.ts +123 -0
  71. package/dist/src/eta/batch.js +162 -0
  72. package/dist/src/eta/batch.js.map +1 -0
  73. package/dist/src/eta/batcher.d.ts +184 -0
  74. package/dist/src/eta/batcher.js +335 -0
  75. package/dist/src/eta/batcher.js.map +1 -0
  76. package/dist/src/eta/cache.d.ts +36 -0
  77. package/dist/src/eta/cache.js +56 -0
  78. package/dist/src/eta/cache.js.map +1 -0
  79. package/dist/src/eta/controller.d.ts +608 -0
  80. package/dist/src/eta/controller.js +1036 -0
  81. package/dist/src/eta/controller.js.map +1 -0
  82. package/dist/src/eta/factory.d.ts +74 -0
  83. package/dist/src/eta/factory.js +121 -0
  84. package/dist/src/eta/factory.js.map +1 -0
  85. package/dist/src/eta/idle.d.ts +39 -0
  86. package/dist/src/eta/idle.js +52 -0
  87. package/dist/src/eta/idle.js.map +1 -0
  88. package/dist/src/eta/index.d.ts +52 -0
  89. package/dist/src/eta/index.js +13 -0
  90. package/dist/src/eta/index.js.map +1 -0
  91. package/dist/src/eta/observer.d.ts +263 -0
  92. package/dist/src/eta/observer.js +263 -0
  93. package/dist/src/eta/observer.js.map +1 -0
  94. package/dist/src/eta/operations.d.ts +41 -0
  95. package/dist/src/eta/operations.js +59 -0
  96. package/dist/src/eta/operations.js.map +1 -0
  97. package/dist/src/eta/source-registry.d.ts +198 -0
  98. package/dist/src/eta/source-registry.js +267 -0
  99. package/dist/src/eta/source-registry.js.map +1 -0
  100. package/dist/src/eta/template-index.d.ts +285 -0
  101. package/dist/src/eta/template-index.js +642 -0
  102. package/dist/src/eta/template-index.js.map +1 -0
  103. package/dist/src/eta/types.d.ts +529 -0
  104. package/dist/src/eta/types.js +2 -0
  105. package/dist/src/eta/types.js.map +1 -0
  106. package/dist/src/index.d.ts +21 -9
  107. package/dist/src/index.js +22 -11
  108. package/dist/src/index.js.map +1 -1
  109. package/dist/src/nodes/node.context.d.ts +5 -3
  110. package/dist/src/nodes/node.context.js +48 -3
  111. package/dist/src/nodes/node.context.js.map +1 -1
  112. package/dist/src/nodes/node.option.d.ts +11 -31
  113. package/dist/src/nodes/node.option.js +158 -222
  114. package/dist/src/nodes/node.option.js.map +1 -1
  115. package/dist/src/nodes/node.product.d.ts +7 -11
  116. package/dist/src/nodes/node.product.js +85 -64
  117. package/dist/src/nodes/node.product.js.map +1 -1
  118. package/dist/src/renders/attributes/buyLink.d.ts +2 -2
  119. package/dist/src/renders/attributes/buyLink.js +14 -11
  120. package/dist/src/renders/attributes/buyLink.js.map +1 -1
  121. package/dist/src/renders/attributes/devices.d.ts +2 -2
  122. package/dist/src/renders/attributes/devices.js +9 -19
  123. package/dist/src/renders/attributes/devices.js.map +1 -1
  124. package/dist/src/renders/attributes/discount.d.ts +2 -2
  125. package/dist/src/renders/attributes/discount.js +56 -44
  126. package/dist/src/renders/attributes/discount.js.map +1 -1
  127. package/dist/src/renders/attributes/hide.d.ts +2 -2
  128. package/dist/src/renders/attributes/hide.js +49 -14
  129. package/dist/src/renders/attributes/hide.js.map +1 -1
  130. package/dist/src/renders/attributes/index.d.ts +3 -3
  131. package/dist/src/renders/attributes/index.js +2 -4
  132. package/dist/src/renders/attributes/index.js.map +1 -1
  133. package/dist/src/renders/attributes/price.d.ts +2 -2
  134. package/dist/src/renders/attributes/price.js +30 -44
  135. package/dist/src/renders/attributes/price.js.map +1 -1
  136. package/dist/src/renders/attributes/subscription.d.ts +2 -2
  137. package/dist/src/renders/attributes/subscription.js +14 -20
  138. package/dist/src/renders/attributes/subscription.js.map +1 -1
  139. package/dist/src/renders/attributes/utilty.d.ts +2 -0
  140. package/dist/src/renders/attributes/utilty.js +17 -4
  141. package/dist/src/renders/attributes/utilty.js.map +1 -1
  142. package/dist/src/renders/context.d.ts +122 -10
  143. package/dist/src/renders/context.js +140 -80
  144. package/dist/src/renders/context.js.map +1 -1
  145. package/dist/src/renders/format.js +2 -2
  146. package/dist/src/renders/format.js.map +1 -1
  147. package/dist/src/renders/index.d.ts +6 -2
  148. package/dist/src/renders/index.js +67 -29
  149. package/dist/src/renders/index.js.map +1 -1
  150. package/dist/src/renders/observe.d.ts +1 -4
  151. package/dist/src/renders/observe.js +10 -24
  152. package/dist/src/renders/observe.js.map +1 -1
  153. package/dist/src/renders/render.wrapper.d.ts +37 -0
  154. package/dist/src/renders/render.wrapper.js +147 -0
  155. package/dist/src/renders/render.wrapper.js.map +1 -0
  156. package/dist/src/templating/eta.js +1 -4
  157. package/dist/src/templating/eta.js.map +1 -1
  158. package/package.json +4 -5
  159. package/dist/src/actions/action.button.d.ts +0 -2
  160. package/dist/src/actions/action.button.js +0 -8
  161. package/dist/src/actions/action.button.js.map +0 -1
  162. package/dist/src/actions/action.input.d.ts +0 -2
  163. package/dist/src/actions/action.input.js +0 -43
  164. package/dist/src/actions/action.input.js.map +0 -1
  165. package/dist/src/actions/action.select.d.ts +0 -2
  166. package/dist/src/actions/action.select.js +0 -14
  167. package/dist/src/actions/action.select.js.map +0 -1
  168. package/dist/src/actions/utilty.d.ts +0 -16
  169. package/dist/src/actions/utilty.js +0 -149
  170. package/dist/src/actions/utilty.js.map +0 -1
  171. package/dist/src/contexts/context.datalayer.d.ts +0 -9
  172. package/dist/src/contexts/context.datalayer.js +0 -3
  173. package/dist/src/contexts/context.datalayer.js.map +0 -1
  174. package/dist/src/contexts/context.derived.d.ts +0 -12
  175. package/dist/src/contexts/context.derived.js +0 -3
  176. package/dist/src/contexts/context.derived.js.map +0 -1
  177. package/dist/src/contexts/context.option.d.ts +0 -5
  178. package/dist/src/contexts/context.option.js +0 -3
  179. package/dist/src/contexts/context.option.js.map +0 -1
  180. package/dist/src/contexts/context.product.d.ts +0 -5
  181. package/dist/src/contexts/context.product.js +0 -3
  182. package/dist/src/contexts/context.product.js.map +0 -1
  183. package/dist/src/contexts/context.state.d.ts +0 -28
  184. package/dist/src/contexts/context.state.js +0 -3
  185. package/dist/src/contexts/context.state.js.map +0 -1
  186. package/dist/src/contexts/context.store.d.ts +0 -5
  187. package/dist/src/contexts/context.store.js +0 -3
  188. package/dist/src/contexts/context.store.js.map +0 -1
  189. package/dist/src/controllers/collect-controller.d.ts +0 -39
  190. package/dist/src/controllers/collect-controller.js +0 -161
  191. package/dist/src/controllers/collect-controller.js.map +0 -1
  192. package/dist/src/controllers/compute-controller.d.ts +0 -55
  193. package/dist/src/controllers/compute-controller.js +0 -350
  194. package/dist/src/controllers/compute-controller.js.map +0 -1
  195. package/dist/src/controllers/eta-renderer/eta-dom-renderer.d.ts +0 -25
  196. package/dist/src/controllers/eta-renderer/eta-dom-renderer.js +0 -192
  197. package/dist/src/controllers/eta-renderer/eta-dom-renderer.js.map +0 -1
  198. package/dist/src/controllers/eta-renderer/eta-mutation-observer.d.ts +0 -28
  199. package/dist/src/controllers/eta-renderer/eta-mutation-observer.js +0 -206
  200. package/dist/src/controllers/eta-renderer/eta-mutation-observer.js.map +0 -1
  201. package/dist/src/controllers/eta-renderer/eta-renderer.d.ts +0 -21
  202. package/dist/src/controllers/eta-renderer/eta-renderer.js +0 -77
  203. package/dist/src/controllers/eta-renderer/eta-renderer.js.map +0 -1
  204. package/dist/src/controllers/eta-renderer/eta-template-cache.d.ts +0 -24
  205. package/dist/src/controllers/eta-renderer/eta-template-cache.js +0 -61
  206. package/dist/src/controllers/eta-renderer/eta-template-cache.js.map +0 -1
  207. package/dist/src/controllers/eta-renderer/eta-types.d.ts +0 -11
  208. package/dist/src/controllers/eta-renderer/eta-types.js +0 -1
  209. package/dist/src/controllers/eta-renderer/eta-types.js.map +0 -1
  210. package/dist/src/controllers/eta-renderer/index.d.ts +0 -2
  211. package/dist/src/controllers/eta-renderer/index.js +0 -2
  212. package/dist/src/controllers/eta-renderer/index.js.map +0 -1
  213. package/dist/src/controllers/event-pipeline-controller.d.ts +0 -28
  214. package/dist/src/controllers/event-pipeline-controller.js +0 -72
  215. package/dist/src/controllers/event-pipeline-controller.js.map +0 -1
  216. package/dist/src/events/events.d.ts +0 -75
  217. package/dist/src/events/events.js +0 -78
  218. package/dist/src/events/events.js.map +0 -1
  219. package/dist/src/nodes/node.root.d.ts +0 -16
  220. package/dist/src/nodes/node.root.js +0 -49
  221. package/dist/src/nodes/node.root.js.map +0 -1
  222. package/dist/src/nodes/node.state.d.ts +0 -88
  223. package/dist/src/nodes/node.state.js +0 -330
  224. package/dist/src/nodes/node.state.js.map +0 -1
  225. package/dist/src/renders/utility.d.ts +0 -32
  226. package/dist/src/renders/utility.js +0 -191
  227. package/dist/src/renders/utility.js.map +0 -1
@@ -0,0 +1,573 @@
1
+ // src/core/BdNodeElement.ts
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var _a;
9
+ import { BdActionTopologyController } from '../controllers/controller.action-topology.js';
10
+ import { html, LitElement } from 'lit';
11
+ import { property } from 'lit/decorators.js';
12
+ export const BD_NODE_REGISTER_EVENT = 'bd-node-register';
13
+ export const BD_NODE_TRACK_WORK_EVENT = 'bd-node-track-work';
14
+ /**
15
+ * String brand used as a fallback in case instanceof is not enough.
16
+ * For example, this can help if the package is bundled more than once.
17
+ */
18
+ export const BD_NODE_ELEMENT_BRAND = '__bdNodeElement__';
19
+ export function dispatchBdNodeTrackWork(target, key, work) {
20
+ const event = new CustomEvent(BD_NODE_TRACK_WORK_EVENT, {
21
+ bubbles: true,
22
+ composed: true,
23
+ cancelable: true,
24
+ detail: {
25
+ key,
26
+ work
27
+ }
28
+ });
29
+ return target.dispatchEvent(event);
30
+ }
31
+ const REVISION_CHANGED = Symbol('bd-revision-changed');
32
+ export function isBdNodeElement(value) {
33
+ return (value instanceof BdNodeElement ||
34
+ (value instanceof HTMLElement &&
35
+ value[BD_NODE_ELEMENT_BRAND] === true));
36
+ }
37
+ /**
38
+ * Base class for all bd-* nodes.
39
+ *
40
+ * Responsibilities:
41
+ * - discovers the nearest logical BdNodeElement parent;
42
+ * - keeps a set of logical BdNodeElement children;
43
+ * - tracks local async work;
44
+ * - makes updateComplete wait for the whole logical subtree;
45
+ * - owns the set of native action elements in its logical subtree
46
+ * (topology), fed incrementally by BdActionElementAdapter announcements.
47
+ *
48
+ * It does NOT know about:
49
+ * - product ids;
50
+ * - price clients;
51
+ * - scope;
52
+ * - @consume / @provide;
53
+ * - binding data attributes.
54
+ *
55
+ * Those belong in BdScopedElement, controllers, or concrete nodes.
56
+ */
57
+ export class BdNodeElement extends LitElement {
58
+ constructor() {
59
+ super(...arguments);
60
+ this[_a] = true;
61
+ this.topologyBoundary = false;
62
+ this._bdChildren = new Set();
63
+ /**
64
+ * Latest local work per key.
65
+ *
66
+ * If the same key is tracked again, the new promise replaces the old one.
67
+ * This is important for @lit/task-like flows where old work can be aborted
68
+ * or made obsolete by newer args.
69
+ */
70
+ this._localWork = new Map();
71
+ this._childrenRevision = 0;
72
+ this._childrenRevisionWaiters = new Set();
73
+ this._workRevision = 0;
74
+ this._workRevisionWaiters = new Set();
75
+ this._actionTopology = new BdActionTopologyController(this);
76
+ this._onBdNodeRegister = (event) => {
77
+ const child = event.detail?.node;
78
+ if (!isBdNodeElement(child)) {
79
+ return;
80
+ }
81
+ /**
82
+ * This event is first seen by the node that dispatched it.
83
+ * Do not stop propagation for self-registration; it needs to reach the
84
+ * nearest logical parent.
85
+ */
86
+ if (child === this) {
87
+ return;
88
+ }
89
+ /**
90
+ * The first BdNodeElement ancestor that sees the event becomes the logical
91
+ * parent. Stop propagation so higher bd nodes do not also adopt it.
92
+ */
93
+ event.stopPropagation();
94
+ this._adoptBdChild(child);
95
+ };
96
+ this._onBdNodeTrackWork = (event) => {
97
+ const detail = event.detail;
98
+ if (!detail) {
99
+ return;
100
+ }
101
+ /**
102
+ * The nearest BdNodeElement owns this work.
103
+ * Do not let higher bd nodes track the same promise directly.
104
+ */
105
+ event.stopPropagation();
106
+ event.preventDefault();
107
+ this.trackLocalWork(detail.key, detail.work);
108
+ };
109
+ }
110
+ static { _a = BD_NODE_ELEMENT_BRAND; }
111
+ /**
112
+ * Default render for infrastructure bd-* nodes.
113
+ *
114
+ * Subclasses can override this if they need their own template.
115
+ */
116
+ render() {
117
+ return html `<slot></slot>`;
118
+ }
119
+ willUpdate(changedProperties) {
120
+ if (!changedProperties.has('topologyBoundary')) {
121
+ return;
122
+ }
123
+ this._actionTopology.markSubtreeChanged();
124
+ this._bdParent?._actionTopology.markSubtreeChanged();
125
+ }
126
+ connectedCallback() {
127
+ super.connectedCallback();
128
+ this.addEventListener(BD_NODE_REGISTER_EVENT, this._onBdNodeRegister);
129
+ this.addEventListener(BD_NODE_TRACK_WORK_EVENT, this._onBdNodeTrackWork);
130
+ this._registerWithNearestBdParent();
131
+ /**
132
+ * Fallback for custom-element upgrade order.
133
+ *
134
+ * Example:
135
+ * - bd-option may upgrade before bd-product.
136
+ * - its registration event may fire before bd-product has a listener.
137
+ * - when bd-product later connects, this pass adopts existing light-DOM
138
+ * descendants that are already BdNodeElement instances.
139
+ */
140
+ queueMicrotask(() => {
141
+ if (this.isConnected) {
142
+ this._adoptExistingLightDomBdChildren();
143
+ }
144
+ });
145
+ }
146
+ disconnectedCallback() {
147
+ this._bdParent?._removeBdChild(this);
148
+ this._bdParent = undefined;
149
+ this._clearBdChildren();
150
+ this.removeEventListener(BD_NODE_REGISTER_EVENT, this._onBdNodeRegister);
151
+ this.removeEventListener(BD_NODE_TRACK_WORK_EVENT, this._onBdNodeTrackWork);
152
+ super.disconnectedCallback();
153
+ }
154
+ get bdParent() {
155
+ return this._bdParent;
156
+ }
157
+ get bdChildren() {
158
+ return this._bdChildren;
159
+ }
160
+ /**
161
+ * Revision that changes whenever the set of action elements anywhere in this
162
+ * node's logical subtree changes. Use this as a compute input.
163
+ */
164
+ get actionTopologyRevision() {
165
+ return this._actionTopology.revision;
166
+ }
167
+ /**
168
+ * Action elements owned directly by this node (not descendants).
169
+ */
170
+ get localActionElements() {
171
+ return this._actionTopology.localElements;
172
+ }
173
+ /**
174
+ * All action elements reachable from this node, unioned across the logical
175
+ * bd subtree. Walks the bd tree (tiny), not arbitrary DOM.
176
+ */
177
+ collectActionElements() {
178
+ const result = [
179
+ ...this._actionTopology.localElements
180
+ ];
181
+ for (const child of this._bdChildren) {
182
+ if (child.topologyBoundary) {
183
+ continue;
184
+ }
185
+ result.push(...child.collectActionElements());
186
+ }
187
+ return result;
188
+ }
189
+ /**
190
+ * Collected compute declarations for action elements reachable from this
191
+ * node. These are owned by topology so compute does not rescan DOM actions.
192
+ */
193
+ collectActionScans() {
194
+ const result = [
195
+ ...this._actionTopology.localActionScans
196
+ ];
197
+ for (const child of this._bdChildren) {
198
+ if (child.topologyBoundary) {
199
+ continue;
200
+ }
201
+ result.push(...child.collectActionScans());
202
+ }
203
+ return result;
204
+ }
205
+ /**
206
+ * Resolved option seeds reachable from this node, unioned across the logical
207
+ * bd subtree. Each option carries its product via option.getProduct().
208
+ */
209
+ collectOptionSeeds() {
210
+ const result = [];
211
+ const optionSeed = this._actionTopology.localOptionSeed;
212
+ if (optionSeed) {
213
+ result.push(optionSeed);
214
+ }
215
+ for (const child of this._bdChildren) {
216
+ if (child.topologyBoundary) {
217
+ continue;
218
+ }
219
+ result.push(...child.collectOptionSeeds());
220
+ }
221
+ return result;
222
+ }
223
+ setLocalOptionSeed(option) {
224
+ this._actionTopology.setLocalOptionSeed(option);
225
+ }
226
+ get hasLocalWork() {
227
+ return this._localWork.size > 0;
228
+ }
229
+ get localWorkCount() {
230
+ return this._localWork.size;
231
+ }
232
+ /**
233
+ * Promise that resolves when all CURRENT local work is complete.
234
+ *
235
+ * This is intentionally separate from updateComplete.
236
+ *
237
+ * localComplete:
238
+ * current node async work only
239
+ *
240
+ * updateComplete:
241
+ * current node + local work + logical children
242
+ *
243
+ * Loops while a newer `trackLocalWork` replaces tracked work
244
+ * (`_awaitCurrentLocalWorkComplete` returns `false` on revision
245
+ * change). The mirror of `getUpdateComplete`'s contract — a
246
+ * single `await` cannot catch the replacement because the
247
+ * replacement bumps `_workRevision` and clears the existing
248
+ * slot, so the earlier await's "all stable" signal is no
249
+ * longer trustworthy.
250
+ */
251
+ get localComplete() {
252
+ return this._awaitLocalCompleteLoop();
253
+ }
254
+ async _awaitLocalCompleteLoop() {
255
+ while (true) {
256
+ const stable = await this._awaitCurrentLocalWorkComplete();
257
+ if (stable && this._localWork.size === 0) {
258
+ return;
259
+ }
260
+ }
261
+ }
262
+ /**
263
+ * Tracks local async work.
264
+ *
265
+ * Use this from Task / BdResolveController:
266
+ *
267
+ * task: (args, context) => {
268
+ * const work = this.resolveAndPublish(args, context.signal);
269
+ * return this.trackLocalWork(this._workKey, work);
270
+ * }
271
+ *
272
+ * Important:
273
+ * - the promise should include resolve + commit/publish;
274
+ * - do not await this.updateComplete inside this promise;
275
+ * - old work with the same key is replaced by newer work.
276
+ */
277
+ trackLocalWork(key, work) {
278
+ const original = Promise.resolve(work);
279
+ /**
280
+ * updateComplete should not reject for business-level async failures.
281
+ *
282
+ * The original promise still rejects, so Task / BdResolveController can
283
+ * expose the error state. The tracked promise is only used for knowing
284
+ * "is local work finished?"
285
+ */
286
+ const tracked = original.then(() => undefined, () => undefined);
287
+ this._localWork.set(key, tracked);
288
+ this._bumpWorkRevision();
289
+ this.requestUpdate();
290
+ tracked.finally(() => {
291
+ /**
292
+ * Only clear if this is still the latest work for this key.
293
+ *
294
+ * If a newer task replaced it, the older task must not clear the newer
295
+ * one when it eventually completes.
296
+ */
297
+ if (this._localWork.get(key) !== tracked) {
298
+ return;
299
+ }
300
+ this._localWork.delete(key);
301
+ this._bumpWorkRevision();
302
+ this.requestUpdate();
303
+ });
304
+ return original;
305
+ }
306
+ /**
307
+ * Hook for subclasses that need to react when a logical child is adopted.
308
+ */
309
+ onBdChildConnected(_child) {
310
+ // Optional hook.
311
+ }
312
+ /**
313
+ * Hook for subclasses that need to react when a logical child is removed.
314
+ */
315
+ onBdChildDisconnected(_child) {
316
+ // Optional hook.
317
+ }
318
+ /**
319
+ * This is the important part.
320
+ *
321
+ * Awaiting updateComplete on any bd node means:
322
+ *
323
+ * 1. this element's Lit update is complete;
324
+ * 2. this element's local async work is complete;
325
+ * 3. any update caused by local work / publishScope is complete;
326
+ * 4. all logical bd children are updateComplete;
327
+ * 5. the tree did not change while we were waiting.
328
+ */
329
+ async getUpdateComplete() {
330
+ while (true) {
331
+ /**
332
+ * Let the current Lit update complete first.
333
+ *
334
+ * This matters when local work is started by @lit/task, because Task
335
+ * observes args during the host update and runs when they change.
336
+ */
337
+ const initialSelfComplete = await super.getUpdateComplete();
338
+ /**
339
+ * Wait for this node's own async work.
340
+ *
341
+ * This work should include:
342
+ * - resolve
343
+ * - commit
344
+ * - publishScope / clearScope
345
+ */
346
+ const localStable = await this._awaitCurrentLocalWorkComplete();
347
+ /**
348
+ * Local work may have called publishScope(), clearScope(),
349
+ * requestUpdate(), or changed Task state.
350
+ *
351
+ * Wait once for that local update to flush before asking children
352
+ * whether they are complete.
353
+ */
354
+ const selfCompleteAfterLocalWork = await super.getUpdateComplete();
355
+ if (!localStable ||
356
+ this._localWork.size > 0 ||
357
+ this.isUpdatePending) {
358
+ continue;
359
+ }
360
+ /**
361
+ * Now children should see the scope published by this node.
362
+ *
363
+ * Context subscribers can receive new values when the provider has new
364
+ * data, so this is the point where child nodes can continue their own
365
+ * work.
366
+ */
367
+ const childrenComplete = await this._awaitCurrentBdChildrenComplete();
368
+ if (childrenComplete.stable &&
369
+ this._localWork.size === 0 &&
370
+ !this.isUpdatePending) {
371
+ return (initialSelfComplete &&
372
+ selfCompleteAfterLocalWork &&
373
+ childrenComplete.complete);
374
+ }
375
+ }
376
+ }
377
+ _registerWithNearestBdParent() {
378
+ this.dispatchEvent(new CustomEvent(BD_NODE_REGISTER_EVENT, {
379
+ bubbles: true,
380
+ /**
381
+ * true:
382
+ * registration can cross shadow DOM boundaries.
383
+ *
384
+ * false:
385
+ * shadow DOM becomes a hard logical boundary.
386
+ *
387
+ */
388
+ composed: true,
389
+ detail: {
390
+ node: this
391
+ }
392
+ }));
393
+ }
394
+ _adoptBdChild(child) {
395
+ if (child === this) {
396
+ return;
397
+ }
398
+ if (child._bdParent === this &&
399
+ this._bdChildren.has(child)) {
400
+ return;
401
+ }
402
+ child._bdParent?._removeBdChild(child);
403
+ child._bdParent = this;
404
+ this._bdChildren.add(child);
405
+ this._bumpChildrenRevision();
406
+ this.onBdChildConnected(child);
407
+ this._actionTopology.markSubtreeChanged();
408
+ this.requestUpdate();
409
+ }
410
+ _removeBdChild(child) {
411
+ if (!this._bdChildren.delete(child)) {
412
+ return;
413
+ }
414
+ if (child._bdParent === this) {
415
+ child._bdParent = undefined;
416
+ }
417
+ this._bumpChildrenRevision();
418
+ this.onBdChildDisconnected(child);
419
+ this._actionTopology.markSubtreeChanged();
420
+ this.requestUpdate();
421
+ }
422
+ _clearBdChildren() {
423
+ if (this._bdChildren.size === 0) {
424
+ return;
425
+ }
426
+ const children = [...this._bdChildren];
427
+ this._bdChildren.clear();
428
+ for (const child of children) {
429
+ if (child._bdParent === this) {
430
+ child._bdParent = undefined;
431
+ }
432
+ this.onBdChildDisconnected(child);
433
+ }
434
+ this._bumpChildrenRevision();
435
+ this.requestUpdate();
436
+ }
437
+ /**
438
+ * Fallback adoption for already-upgraded descendants in light DOM.
439
+ *
440
+ * This does not cross arbitrary shadow roots. The event-based registration
441
+ * handles the composed/shadow case.
442
+ */
443
+ _adoptExistingLightDomBdChildren() {
444
+ const candidates = this.querySelectorAll('*');
445
+ for (const candidate of candidates) {
446
+ if (!isBdNodeElement(candidate)) {
447
+ continue;
448
+ }
449
+ if (candidate === this) {
450
+ continue;
451
+ }
452
+ if (this._isNearestLightDomBdParentOf(candidate)) {
453
+ this._adoptBdChild(candidate);
454
+ }
455
+ }
456
+ }
457
+ _isNearestLightDomBdParentOf(candidate) {
458
+ let node = candidate.parentNode;
459
+ while (node && node !== this) {
460
+ if (isBdNodeElement(node)) {
461
+ return false;
462
+ }
463
+ node = node.parentNode;
464
+ }
465
+ return node === this;
466
+ }
467
+ async _awaitCurrentLocalWorkComplete() {
468
+ const revision = this._workRevision;
469
+ const works = [...this._localWork.values()];
470
+ if (works.length === 0) {
471
+ return this._workRevision === revision;
472
+ }
473
+ const revisionWait = this._createWorkRevisionWait(revision);
474
+ try {
475
+ const results = await Promise.all(works.map((work) => Promise.race([
476
+ work.then(() => true),
477
+ revisionWait.promise
478
+ ])));
479
+ return (this._workRevision === revision &&
480
+ results.every((value) => value === true));
481
+ }
482
+ finally {
483
+ revisionWait.cancel();
484
+ }
485
+ }
486
+ async _awaitCurrentBdChildrenComplete() {
487
+ const revision = this._childrenRevision;
488
+ const children = [...this._bdChildren];
489
+ if (children.length === 0) {
490
+ return {
491
+ stable: this._childrenRevision === revision,
492
+ complete: true
493
+ };
494
+ }
495
+ const revisionWait = this._createChildrenRevisionWait(revision);
496
+ try {
497
+ const results = await Promise.all(children.map((child) => Promise.race([
498
+ child.updateComplete,
499
+ revisionWait.promise
500
+ ])));
501
+ const stable = this._childrenRevision === revision &&
502
+ results.every((value) => value !== REVISION_CHANGED);
503
+ return {
504
+ stable,
505
+ complete: stable &&
506
+ results.every((value) => value === true)
507
+ };
508
+ }
509
+ finally {
510
+ revisionWait.cancel();
511
+ }
512
+ }
513
+ _createChildrenRevisionWait(revision) {
514
+ if (this._childrenRevision !== revision) {
515
+ return {
516
+ promise: Promise.resolve(REVISION_CHANGED),
517
+ cancel: () => undefined
518
+ };
519
+ }
520
+ let resolveWait;
521
+ const promise = new Promise((resolve) => {
522
+ resolveWait = () => resolve(REVISION_CHANGED);
523
+ });
524
+ this._childrenRevisionWaiters.add(resolveWait);
525
+ return {
526
+ promise,
527
+ cancel: () => {
528
+ this._childrenRevisionWaiters.delete(resolveWait);
529
+ }
530
+ };
531
+ }
532
+ _createWorkRevisionWait(revision) {
533
+ if (this._workRevision !== revision) {
534
+ return {
535
+ promise: Promise.resolve(REVISION_CHANGED),
536
+ cancel: () => undefined
537
+ };
538
+ }
539
+ let resolveWait;
540
+ const promise = new Promise((resolve) => {
541
+ resolveWait = () => resolve(REVISION_CHANGED);
542
+ });
543
+ this._workRevisionWaiters.add(resolveWait);
544
+ return {
545
+ promise,
546
+ cancel: () => {
547
+ this._workRevisionWaiters.delete(resolveWait);
548
+ }
549
+ };
550
+ }
551
+ _bumpChildrenRevision() {
552
+ this._childrenRevision += 1;
553
+ for (const resolve of this._childrenRevisionWaiters) {
554
+ resolve();
555
+ }
556
+ this._childrenRevisionWaiters.clear();
557
+ }
558
+ _bumpWorkRevision() {
559
+ this._workRevision += 1;
560
+ for (const resolve of this._workRevisionWaiters) {
561
+ resolve();
562
+ }
563
+ this._workRevisionWaiters.clear();
564
+ }
565
+ }
566
+ __decorate([
567
+ property({
568
+ attribute: 'topology-boundary',
569
+ type: Boolean,
570
+ reflect: true
571
+ })
572
+ ], BdNodeElement.prototype, "topologyBoundary", void 0);
573
+ //# sourceMappingURL=node.element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.element.js","sourceRoot":"","sources":["../../../src/core/node.element.ts"],"names":[],"mappings":"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","sourcesContent":["// src/core/BdNodeElement.ts\n\nimport type { BdComputeScan } from '@/compute/compute.scan.js';\nimport { BdActionTopologyController } from '@/controllers/controller.action-topology.js';\nimport type { ProductOption } from '@repobit/dex-store';\nimport {\n html,\n LitElement,\n type PropertyValues,\n type TemplateResult\n} from 'lit';\nimport { property } from 'lit/decorators.js';\n\nexport const BD_NODE_REGISTER_EVENT = 'bd-node-register' as const;\nexport const BD_NODE_TRACK_WORK_EVENT = 'bd-node-track-work' as const;\n\n/**\n * String brand used as a fallback in case instanceof is not enough.\n * For example, this can help if the package is bundled more than once.\n */\nexport const BD_NODE_ELEMENT_BRAND = '__bdNodeElement__' as const;\n\nexport interface BdNodeRegisterEventDetail {\n node: BdNodeElement;\n}\n\nexport interface BdNodeTrackWorkEventDetail<T = unknown> {\n key : unknown;\n work: PromiseLike<T>;\n}\n\nexport function dispatchBdNodeTrackWork<T>(\n target: EventTarget,\n key: unknown,\n work: PromiseLike<T>\n): boolean {\n const event =\n new CustomEvent<BdNodeTrackWorkEventDetail<T>>(\n BD_NODE_TRACK_WORK_EVENT,\n {\n bubbles : true,\n composed : true,\n cancelable: true,\n detail : {\n key,\n work\n }\n }\n );\n\n return target.dispatchEvent(event);\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n [BD_NODE_REGISTER_EVENT] : CustomEvent<BdNodeRegisterEventDetail>;\n [BD_NODE_TRACK_WORK_EVENT]: CustomEvent<BdNodeTrackWorkEventDetail>;\n }\n}\n\nconst REVISION_CHANGED = Symbol('bd-revision-changed');\n\ntype RevisionChanged = typeof REVISION_CHANGED;\n\ntype RevisionWait = {\n promise: Promise<RevisionChanged>;\n cancel : () => void;\n};\n\nexport function isBdNodeElement(\n value: unknown\n): value is BdNodeElement {\n return (\n value instanceof BdNodeElement ||\n (\n value instanceof HTMLElement &&\n (\n value as HTMLElement &\n Record<typeof BD_NODE_ELEMENT_BRAND, unknown>\n )[BD_NODE_ELEMENT_BRAND] === true\n )\n );\n}\n\n/**\n * Base class for all bd-* nodes.\n *\n * Responsibilities:\n * - discovers the nearest logical BdNodeElement parent;\n * - keeps a set of logical BdNodeElement children;\n * - tracks local async work;\n * - makes updateComplete wait for the whole logical subtree;\n * - owns the set of native action elements in its logical subtree\n * (topology), fed incrementally by BdActionElementAdapter announcements.\n *\n * It does NOT know about:\n * - product ids;\n * - price clients;\n * - scope;\n * - @consume / @provide;\n * - binding data attributes.\n *\n * Those belong in BdScopedElement, controllers, or concrete nodes.\n */\nexport abstract class BdNodeElement extends LitElement {\n readonly [BD_NODE_ELEMENT_BRAND] = true;\n\n @property({\n attribute: 'topology-boundary',\n type : Boolean,\n reflect : true\n })\n topologyBoundary = false;\n\n private readonly _bdChildren = new Set<BdNodeElement>();\n private _bdParent?: BdNodeElement;\n\n /**\n * Latest local work per key.\n *\n * If the same key is tracked again, the new promise replaces the old one.\n * This is important for @lit/task-like flows where old work can be aborted\n * or made obsolete by newer args.\n */\n private readonly _localWork = new Map<unknown, Promise<void>>();\n\n private _childrenRevision = 0;\n private readonly _childrenRevisionWaiters = new Set<() => void>();\n\n private _workRevision = 0;\n private readonly _workRevisionWaiters = new Set<() => void>();\n\n private readonly _actionTopology =\n new BdActionTopologyController(this);\n\n /**\n * Default render for infrastructure bd-* nodes.\n *\n * Subclasses can override this if they need their own template.\n */\n protected override render(): TemplateResult {\n return html`<slot></slot>`;\n }\n\n protected override willUpdate(\n changedProperties: PropertyValues<this>\n ): void {\n if (!changedProperties.has('topologyBoundary')) {\n return;\n }\n\n this._actionTopology.markSubtreeChanged();\n this._bdParent?._actionTopology.markSubtreeChanged();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n this.addEventListener(\n BD_NODE_REGISTER_EVENT,\n this._onBdNodeRegister as EventListener\n );\n\n this.addEventListener(\n BD_NODE_TRACK_WORK_EVENT,\n this._onBdNodeTrackWork as EventListener\n );\n\n this._registerWithNearestBdParent();\n\n /**\n * Fallback for custom-element upgrade order.\n *\n * Example:\n * - bd-option may upgrade before bd-product.\n * - its registration event may fire before bd-product has a listener.\n * - when bd-product later connects, this pass adopts existing light-DOM\n * descendants that are already BdNodeElement instances.\n */\n queueMicrotask(() => {\n if (this.isConnected) {\n this._adoptExistingLightDomBdChildren();\n }\n });\n }\n\n override disconnectedCallback(): void {\n this._bdParent?._removeBdChild(this);\n this._bdParent = undefined;\n\n this._clearBdChildren();\n\n this.removeEventListener(\n BD_NODE_REGISTER_EVENT,\n this._onBdNodeRegister as EventListener\n );\n\n this.removeEventListener(\n BD_NODE_TRACK_WORK_EVENT,\n this._onBdNodeTrackWork as EventListener\n );\n\n super.disconnectedCallback();\n }\n\n protected get bdParent(): BdNodeElement | undefined {\n return this._bdParent;\n }\n\n protected get bdChildren(): ReadonlySet<BdNodeElement> {\n return this._bdChildren;\n }\n\n /**\n * Revision that changes whenever the set of action elements anywhere in this\n * node's logical subtree changes. Use this as a compute input.\n */\n get actionTopologyRevision(): number {\n return this._actionTopology.revision;\n }\n\n /**\n * Action elements owned directly by this node (not descendants).\n */\n get localActionElements(): readonly HTMLElement[] {\n return this._actionTopology.localElements;\n }\n\n /**\n * All action elements reachable from this node, unioned across the logical\n * bd subtree. Walks the bd tree (tiny), not arbitrary DOM.\n */\n collectActionElements(): HTMLElement[] {\n const result: HTMLElement[] = [\n ...this._actionTopology.localElements\n ];\n\n for (const child of this._bdChildren) {\n if (child.topologyBoundary) {\n continue;\n }\n\n result.push(...child.collectActionElements());\n }\n\n return result;\n }\n\n /**\n * Collected compute declarations for action elements reachable from this\n * node. These are owned by topology so compute does not rescan DOM actions.\n */\n collectActionScans(): BdComputeScan[] {\n const result: BdComputeScan[] = [\n ...this._actionTopology.localActionScans\n ];\n\n for (const child of this._bdChildren) {\n if (child.topologyBoundary) {\n continue;\n }\n\n result.push(...child.collectActionScans());\n }\n\n return result;\n }\n\n /**\n * Resolved option seeds reachable from this node, unioned across the logical\n * bd subtree. Each option carries its product via option.getProduct().\n */\n collectOptionSeeds(): ProductOption[] {\n const result: ProductOption[] = [];\n\n const optionSeed =\n this._actionTopology.localOptionSeed;\n\n if (optionSeed) {\n result.push(optionSeed);\n }\n\n for (const child of this._bdChildren) {\n if (child.topologyBoundary) {\n continue;\n }\n\n result.push(...child.collectOptionSeeds());\n }\n\n return result;\n }\n\n protected setLocalOptionSeed(\n option: ProductOption | undefined\n ): void {\n this._actionTopology.setLocalOptionSeed(option);\n }\n\n protected get hasLocalWork(): boolean {\n return this._localWork.size > 0;\n }\n\n protected get localWorkCount(): number {\n return this._localWork.size;\n }\n\n /**\n * Promise that resolves when all CURRENT local work is complete.\n *\n * This is intentionally separate from updateComplete.\n *\n * localComplete:\n * current node async work only\n *\n * updateComplete:\n * current node + local work + logical children\n *\n * Loops while a newer `trackLocalWork` replaces tracked work\n * (`_awaitCurrentLocalWorkComplete` returns `false` on revision\n * change). The mirror of `getUpdateComplete`'s contract — a\n * single `await` cannot catch the replacement because the\n * replacement bumps `_workRevision` and clears the existing\n * slot, so the earlier await's \"all stable\" signal is no\n * longer trustworthy.\n */\n protected get localComplete(): Promise<void> {\n return this._awaitLocalCompleteLoop();\n }\n\n private async _awaitLocalCompleteLoop(): Promise<void> {\n while (true) {\n const stable =\n await this._awaitCurrentLocalWorkComplete();\n\n if (stable && this._localWork.size === 0) {\n return;\n }\n }\n }\n\n /**\n * Tracks local async work.\n *\n * Use this from Task / BdResolveController:\n *\n * task: (args, context) => {\n * const work = this.resolveAndPublish(args, context.signal);\n * return this.trackLocalWork(this._workKey, work);\n * }\n *\n * Important:\n * - the promise should include resolve + commit/publish;\n * - do not await this.updateComplete inside this promise;\n * - old work with the same key is replaced by newer work.\n */\n trackLocalWork<T>(\n key: unknown,\n work: PromiseLike<T>\n ): Promise<T> {\n const original = Promise.resolve(work);\n\n /**\n * updateComplete should not reject for business-level async failures.\n *\n * The original promise still rejects, so Task / BdResolveController can\n * expose the error state. The tracked promise is only used for knowing\n * \"is local work finished?\"\n */\n const tracked = original.then(\n () => undefined,\n () => undefined\n );\n\n this._localWork.set(key, tracked);\n this._bumpWorkRevision();\n this.requestUpdate();\n\n tracked.finally(() => {\n /**\n * Only clear if this is still the latest work for this key.\n *\n * If a newer task replaced it, the older task must not clear the newer\n * one when it eventually completes.\n */\n if (this._localWork.get(key) !== tracked) {\n return;\n }\n\n this._localWork.delete(key);\n this._bumpWorkRevision();\n this.requestUpdate();\n });\n\n return original;\n }\n\n /**\n * Hook for subclasses that need to react when a logical child is adopted.\n */\n protected onBdChildConnected(_child: BdNodeElement): void {\n // Optional hook.\n }\n\n /**\n * Hook for subclasses that need to react when a logical child is removed.\n */\n protected onBdChildDisconnected(_child: BdNodeElement): void {\n // Optional hook.\n }\n\n /**\n * This is the important part.\n *\n * Awaiting updateComplete on any bd node means:\n *\n * 1. this element's Lit update is complete;\n * 2. this element's local async work is complete;\n * 3. any update caused by local work / publishScope is complete;\n * 4. all logical bd children are updateComplete;\n * 5. the tree did not change while we were waiting.\n */\n protected override async getUpdateComplete(): Promise<boolean> {\n while (true) {\n /**\n * Let the current Lit update complete first.\n *\n * This matters when local work is started by @lit/task, because Task\n * observes args during the host update and runs when they change.\n */\n const initialSelfComplete = await super.getUpdateComplete();\n\n /**\n * Wait for this node's own async work.\n *\n * This work should include:\n * - resolve\n * - commit\n * - publishScope / clearScope\n */\n const localStable =\n await this._awaitCurrentLocalWorkComplete();\n\n /**\n * Local work may have called publishScope(), clearScope(),\n * requestUpdate(), or changed Task state.\n *\n * Wait once for that local update to flush before asking children\n * whether they are complete.\n */\n const selfCompleteAfterLocalWork =\n await super.getUpdateComplete();\n\n if (\n !localStable ||\n this._localWork.size > 0 ||\n this.isUpdatePending\n ) {\n continue;\n }\n\n /**\n * Now children should see the scope published by this node.\n *\n * Context subscribers can receive new values when the provider has new\n * data, so this is the point where child nodes can continue their own\n * work.\n */\n const childrenComplete =\n await this._awaitCurrentBdChildrenComplete();\n\n if (\n childrenComplete.stable &&\n this._localWork.size === 0 &&\n !this.isUpdatePending\n ) {\n return (\n initialSelfComplete &&\n selfCompleteAfterLocalWork &&\n childrenComplete.complete\n );\n }\n }\n }\n\n private _registerWithNearestBdParent(): void {\n this.dispatchEvent(\n new CustomEvent<BdNodeRegisterEventDetail>(\n BD_NODE_REGISTER_EVENT,\n {\n bubbles: true,\n\n /**\n * true:\n * registration can cross shadow DOM boundaries.\n *\n * false:\n * shadow DOM becomes a hard logical boundary.\n *\n */\n composed: true,\n\n detail: {\n node: this\n }\n }\n )\n );\n }\n\n private readonly _onBdNodeRegister = (\n event: CustomEvent<BdNodeRegisterEventDetail>\n ): void => {\n const child = event.detail?.node;\n\n if (!isBdNodeElement(child)) {\n return;\n }\n\n /**\n * This event is first seen by the node that dispatched it.\n * Do not stop propagation for self-registration; it needs to reach the\n * nearest logical parent.\n */\n if (child === this) {\n return;\n }\n\n /**\n * The first BdNodeElement ancestor that sees the event becomes the logical\n * parent. Stop propagation so higher bd nodes do not also adopt it.\n */\n event.stopPropagation();\n\n this._adoptBdChild(child);\n };\n\n private readonly _onBdNodeTrackWork = (\n event: CustomEvent<BdNodeTrackWorkEventDetail>\n ): void => {\n const detail = event.detail;\n\n if (!detail) {\n return;\n }\n\n /**\n * The nearest BdNodeElement owns this work.\n * Do not let higher bd nodes track the same promise directly.\n */\n event.stopPropagation();\n event.preventDefault();\n\n this.trackLocalWork(\n detail.key,\n detail.work\n );\n };\n\n private _adoptBdChild(child: BdNodeElement): void {\n if (child === this) {\n return;\n }\n\n if (\n child._bdParent === this &&\n this._bdChildren.has(child)\n ) {\n return;\n }\n\n child._bdParent?._removeBdChild(child);\n\n child._bdParent = this;\n this._bdChildren.add(child);\n\n this._bumpChildrenRevision();\n this.onBdChildConnected(child);\n this._actionTopology.markSubtreeChanged();\n this.requestUpdate();\n }\n\n private _removeBdChild(child: BdNodeElement): void {\n if (!this._bdChildren.delete(child)) {\n return;\n }\n\n if (child._bdParent === this) {\n child._bdParent = undefined;\n }\n\n this._bumpChildrenRevision();\n this.onBdChildDisconnected(child);\n this._actionTopology.markSubtreeChanged();\n this.requestUpdate();\n }\n\n private _clearBdChildren(): void {\n if (this._bdChildren.size === 0) {\n return;\n }\n\n const children = [...this._bdChildren];\n\n this._bdChildren.clear();\n\n for (const child of children) {\n if (child._bdParent === this) {\n child._bdParent = undefined;\n }\n\n this.onBdChildDisconnected(child);\n }\n\n this._bumpChildrenRevision();\n this.requestUpdate();\n }\n\n /**\n * Fallback adoption for already-upgraded descendants in light DOM.\n *\n * This does not cross arbitrary shadow roots. The event-based registration\n * handles the composed/shadow case.\n */\n private _adoptExistingLightDomBdChildren(): void {\n const candidates = this.querySelectorAll('*');\n\n for (const candidate of candidates) {\n if (!isBdNodeElement(candidate)) {\n continue;\n }\n\n if (candidate === this) {\n continue;\n }\n\n if (this._isNearestLightDomBdParentOf(candidate)) {\n this._adoptBdChild(candidate);\n }\n }\n }\n\n private _isNearestLightDomBdParentOf(\n candidate: BdNodeElement\n ): boolean {\n let node: Node | null = candidate.parentNode;\n\n while (node && node !== this) {\n if (isBdNodeElement(node)) {\n return false;\n }\n\n node = node.parentNode;\n }\n\n return node === this;\n }\n\n private async _awaitCurrentLocalWorkComplete(): Promise<boolean> {\n const revision = this._workRevision;\n const works = [...this._localWork.values()];\n\n if (works.length === 0) {\n return this._workRevision === revision;\n }\n\n const revisionWait = this._createWorkRevisionWait(revision);\n\n try {\n const results = await Promise.all(\n works.map((work) =>\n Promise.race<true | RevisionChanged>([\n work.then(() => true as const),\n revisionWait.promise\n ])\n )\n );\n\n return (\n this._workRevision === revision &&\n results.every((value) => value === true)\n );\n } finally {\n revisionWait.cancel();\n }\n }\n\n private async _awaitCurrentBdChildrenComplete(): Promise<{\n stable : boolean;\n complete: boolean;\n }> {\n const revision = this._childrenRevision;\n const children = [...this._bdChildren];\n\n if (children.length === 0) {\n return {\n stable : this._childrenRevision === revision,\n complete: true\n };\n }\n\n const revisionWait = this._createChildrenRevisionWait(revision);\n\n try {\n const results = await Promise.all(\n children.map((child) =>\n Promise.race<boolean | RevisionChanged>([\n child.updateComplete,\n revisionWait.promise\n ])\n )\n );\n\n const stable =\n this._childrenRevision === revision &&\n results.every((value) => value !== REVISION_CHANGED);\n\n return {\n stable,\n complete:\n stable &&\n results.every((value) => value === true)\n };\n } finally {\n revisionWait.cancel();\n }\n }\n\n private _createChildrenRevisionWait(\n revision: number\n ): RevisionWait {\n if (this._childrenRevision !== revision) {\n return {\n promise: Promise.resolve(REVISION_CHANGED),\n cancel : () => undefined\n };\n }\n\n let resolveWait!: () => void;\n\n const promise = new Promise<RevisionChanged>((resolve) => {\n resolveWait = () => resolve(REVISION_CHANGED);\n });\n\n this._childrenRevisionWaiters.add(resolveWait);\n\n return {\n promise,\n cancel: () => {\n this._childrenRevisionWaiters.delete(resolveWait);\n }\n };\n }\n\n private _createWorkRevisionWait(\n revision: number\n ): RevisionWait {\n if (this._workRevision !== revision) {\n return {\n promise: Promise.resolve(REVISION_CHANGED),\n cancel : () => undefined\n };\n }\n\n let resolveWait!: () => void;\n\n const promise = new Promise<RevisionChanged>((resolve) => {\n resolveWait = () => resolve(REVISION_CHANGED);\n });\n\n this._workRevisionWaiters.add(resolveWait);\n\n return {\n promise,\n cancel: () => {\n this._workRevisionWaiters.delete(resolveWait);\n }\n };\n }\n\n private _bumpChildrenRevision(): void {\n this._childrenRevision += 1;\n\n for (const resolve of this._childrenRevisionWaiters) {\n resolve();\n }\n\n this._childrenRevisionWaiters.clear();\n }\n\n private _bumpWorkRevision(): void {\n this._workRevision += 1;\n\n for (const resolve of this._workRevisionWaiters) {\n resolve();\n }\n\n this._workRevisionWaiters.clear();\n }\n}\n"]}