@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 @@
1
+ {"version":3,"file":"template-index.js","sourceRoot":"","sources":["../../../src/eta/template-index.ts"],"names":[],"mappings":"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","sourcesContent":["// src/eta/template-index.ts\n\nimport type {\n EtaTemplateSourceRegistry\n} from './source-registry.js';\nimport {\n createEtaTemplateSourceRegistry\n} from './source-registry.js';\nimport type {\n EtaTemplateIndexOptions,\n TemplateIndexMutation,\n TemplateIndexSink,\n TemplateOperation,\n TemplateOperationFactory\n} from './types.js';\n\n/**\n * The EtaTemplateIndex maintains the set of renderable operations for a\n * scoped boundary.\n *\n * It is Eta-agnostic. Discovery is delegated to a TemplateOperationFactory\n * which returns either an operation or `undefined`. The index simply stores\n * whatever the factory produces and looks it up by node for incremental\n * updates.\n *\n * Three views of the data are kept in sync:\n *\n * - `operations` — a flat Set of operations iterated during render.\n * - `nodeIndex` — a WeakMap from owning node (Element or Text) to the\n * operations that own it, used for O(1) removal.\n * - `attrOps` — a WeakMap from Element to a Map of `attributeName` to the\n * single operation that targets that attribute. Needed because Attr\n * identity is unstable across `setAttribute` calls — looking up by the\n * current Attr reference would never find the previous operation.\n *\n * Boundary handling is configurable through an injected predicate\n * (`EtaTemplateIndexOptions.isBoundaryElement`). The index itself does\n * not own boundary semantics — it asks the host/controller for a\n * decision. That makes boundary detection work consistently across\n * controllers that share the same root but own different indices.\n *\n * Source preservation is delegated to an\n * `EtaTemplateSourceRegistry` so the factory can re-read original\n * template sources after a render has overwritten the DOM value.\n *\n * **Cross-scope source registry limitation.** Each `EtaTemplateIndex`\n * owns the source registry it created in its constructor\n * (`createEtaTemplateSourceRegistry()`). Moving a rendered\n * template node from one scope to another loses the original\n * template source — the destination index's registry has no\n * record of it, so the factory falls back to the live DOM value,\n * which now holds the rendered string rather than the template\n * literal. The destination index cannot recreate the operation\n * without discovering the new template content externally.\n *\n * Applications that need to reparent rendered template nodes\n * across scopes should share a single\n * `EtaTemplateSourceRegistry` between the affected indices.\n * Because the factory is stateless at the call site (the\n * registry is threaded through every call via\n * `TemplateOperationContext`), two indices can share one factory\n * safely — each just passes the shared registry as the\n * `sources` field on every call. The v4 review recommends\n * keeping this limitation documented unless cross-scope DOM\n * moves become a real use case — at which point the\n * index/controller can grow a `sourceRegistry` option that\n * overrides the per-index `createEtaTemplateSourceRegistry()`\n * default.\n */\nexport class EtaTemplateIndex<TContext = object>\nimplements\n Iterable<TemplateOperation<TContext>>,\n TemplateIndexSink\n{\n private readonly _operations = new Set<\n TemplateOperation<TContext>\n >();\n\n /**\n * Per-node operation lookup.\n *\n * Reassignable so `clear()` can fully reset the index even though\n * `WeakMap` cannot be cleared. The old map is reclaimed by the GC\n * as soon as no caller holds it.\n */\n private _nodeIndex = new WeakMap<\n Node,\n Set<TemplateOperation<TContext>>\n >();\n\n /**\n * Per-element, per-attribute-name operation lookup.\n *\n * `Attr` identity is not stable across DOM mutations (`setAttribute`\n * removes the old Attr and inserts a new one), so we cannot key attribute\n * operations by their Attr reference. Instead we key by the owning\n * element + the attribute's qualified name. Each (element, name) pair\n * owns at most one operation because the factory only ever produces one\n * AttributeOperation per attribute.\n */\n private _attrOps = new WeakMap<\n Element,\n Map<string, TemplateOperation<TContext>>\n >();\n\n /**\n * Tracks nodes that have at least one operation associated with them.\n *\n * `WeakSet` cannot be iterated and cannot be cleared, so it is\n * reassigned by `clear()`. It only needs `add` / `has` / `delete`,\n * which `WeakSet` supports.\n */\n private _indexedNodes = new WeakSet<Node>();\n\n private readonly factory:\n TemplateOperationFactory<TContext>;\n private readonly options: EtaTemplateIndexOptions;\n private readonly sources: EtaTemplateSourceRegistry;\n\n constructor(\n factory: TemplateOperationFactory<TContext>,\n options: EtaTemplateIndexOptions = {}\n ) {\n this.factory = factory;\n this.options = options;\n this.sources = createEtaTemplateSourceRegistry();\n\n // The source registry is threaded through every factory call\n // via the `TemplateOperationContext` parameter, NOT wired into\n // the factory itself. That keeps the factory stateless at the\n // call site and makes factory reuse across indices safe — the\n // last constructor to call a registry setter no longer wins,\n // because there is no setter to call. See `_addNode`,\n // `_collectAttributes`, `_updateAttribute`, and `_updateText`\n // for the call sites that pass `{ sources: this.sources }`.\n }\n\n /**\n * Walks the subtree of `root` and indexes every node that contains a\n * template.\n *\n * The walk is implemented by `_addNode`, which descends into\n * descendants and respects the `isBoundaryElement` predicate. The\n * root element is added first so a root element's own attribute\n * templates are indexed even when it has no child nodes.\n *\n * Boundary semantics:\n *\n * - If `root` itself matches `isBoundaryElement`, it is still\n * indexed as the local boundary. Its own attribute templates and\n * its owned descendants are collected.\n * - If a nested element matches `isBoundaryElement`, the walk\n * neither collects the foreign boundary's own attributes nor\n * descends into the foreign boundary's subtree. Outer\n * controllers leave that subtree entirely to the boundary's\n * own controller.\n *\n * ⚠️ **Stable-on-raw-DOM invariant for nested boundaries.**\n * When `initialize` encounters a nested boundary element, the\n * `isBoundaryElement` predicate MUST classify it as a foreign\n * boundary **without** relying on prototype-side state such as\n * `instanceof BdScopedElement` or a runtime brand. The parent\n * index may scan a subtree before a nested custom element has\n * upgraded; in that window the nested element has not yet been\n * augmented with the brand, and a brand-only predicate would\n * fail to classify it as a boundary. No DOM mutation fires when\n * the upgrade completes, so the parent index would keep the\n * wrong operations for the lifetime of the page. Prefer\n * tag-name or marker-attribute checks so the classification is\n * stable from the moment the element is parsed. See\n * `EtaTemplateIndexOptions.isBoundaryElement` for full\n * rationale and example patterns.\n *\n * ⚠️ **Source preservation trust boundary.** `initialize()`\n * assumes external DOM edits have been observed while the\n * index was online. During normal operation the\n * `MutationObserver` keeps the `EtaTemplateSourceRegistry` in\n * sync via `syncTextSource()` / `syncAttributeSource()`. If\n * external code mutates already-rendered template nodes while\n * the controller is disconnected or the index has been cleared\n * (for example between two `clear()` / `initialize()` cycles),\n * the registry can hand back a stale preserved source and the\n * next render will re-emit the old template literal instead of\n * the new DOM value. Callers in that situation should `reset()`\n * (which also clears the source registry) before\n * re-initializing, or otherwise clear the registry themselves.\n */\n initialize(root: ParentNode): void {\n this.clear();\n\n this._addNode(root as Node);\n }\n\n /**\n * Applies a single mutation to the index.\n *\n * Returns `true` when the index actually changed as a result of\n * the mutation (an operation was added, replaced, or removed);\n * `false` when the mutation was a no-op for this index because\n * the node was outside the root, inside a foreign boundary, or\n * did not contain a template.\n *\n * Mutation semantics:\n *\n * - `add` walks the node and its descendants.\n * - `remove` drops every operation whose owner is the node or one of its\n * descendants.\n * - `attribute` re-runs attribute discovery on a single attribute of an\n * element that is already part of the index.\n * - `text` re-runs text discovery on a text node that is already part\n * of the index.\n */\n apply(mutation: TemplateIndexMutation): boolean {\n switch (mutation.type) {\n case 'add':\n return this._addNode(mutation.node);\n\n case 'remove':\n return this._removeNode(mutation.node);\n\n case 'attribute':\n return this._updateAttribute(\n mutation.element,\n mutation.attribute\n );\n\n case 'text':\n return this._updateText(mutation.node);\n\n // Exhaustive guard: if a new mutation variant is added,\n // TypeScript flags this `_exhaustive` assignment as a\n // type error until the new variant is handled here.\n default: {\n const _exhaustive: never = mutation;\n return _exhaustive;\n }\n }\n }\n\n /**\n * Drops every operation from the index and forgets every node.\n *\n * Every internal structure — including the `WeakMap` / `WeakSet`\n * instances — is reassigned so the index returns to a fully empty\n * state. The old `WeakMap` / `WeakSet` references become unreachable\n * as soon as `clear()` returns and the GC reclaims them.\n *\n * **Source registry is intentionally preserved.** The\n * `EtaTemplateSourceRegistry` keeps the original template source\n * strings for the live DOM nodes so the factory can re-render the\n * same nodes after a render has overwritten their text / attribute\n * values. Clearing the registry here would make\n * `clear()` + `initialize()` destructive on already-rendered\n * DOM — the next render would see plain text instead of the\n * original template literal. Callers that explicitly want a\n * fully destructive reset should use `reset()` instead, which\n * also clears the source registry.\n */\n clear(): void {\n for (const op of this._operations) {\n op.dispose();\n }\n\n this._operations.clear();\n this._nodeIndex = new WeakMap();\n this._attrOps = new WeakMap();\n this._indexedNodes = new WeakSet();\n }\n\n /**\n * Fully destructive reset — equivalent to `clear()` plus clearing\n * the `EtaTemplateSourceRegistry`.\n *\n * Use this when the live DOM no longer reflects the original\n * template sources (for example, because external code mutated\n * already-rendered nodes while the index was offline, or the\n * caller is switching to a completely different template set).\n *\n * After `reset()`, the next `initialize(root)` walks the subtree\n * from scratch using whatever is in the DOM at that moment —\n * the registry will not serve a stale preserved source.\n *\n * For normal `clear()` + `initialize()` cycles where the source\n * strings are still valid, prefer `clear()` so the registry\n * survives re-indexing.\n */\n reset(): void {\n this.clear();\n this.sources.clear();\n }\n\n [Symbol.iterator](): Iterator<\n TemplateOperation<TContext>\n > {\n return this._operations.values();\n }\n\n /**\n * Number of operations currently held by the index.\n *\n * Useful for tests and diagnostics. The renderer iterates operations\n * directly and does not need this.\n */\n get size(): number {\n return this._operations.size;\n }\n\n /**\n * Whether the given node has any operation associated with it.\n *\n * Used by the controller to decide if a mutation is interesting.\n *\n * For text nodes this checks whether any operation is keyed on the node.\n * For elements this returns true if the element owns any operation\n * directly (e.g. its attributes) — `hasNode(element)` does NOT imply\n * \"this element has been fully indexed\", only \"this element owns at\n * least one operation\".\n */\n hasNode(node: Node): boolean {\n if (this._indexedNodes.has(node)) {\n return true;\n }\n\n if (node.nodeType === Node.ELEMENT_NODE) {\n return this._attrOps.has(node as Element);\n }\n\n return false;\n }\n\n /**\n * Disposes every operation currently held by the index.\n *\n * The default operations are no-ops for dispose, but custom\n * operations may need to release observers. Calling this from the\n * controller's teardown keeps the lifecycle clean.\n *\n * Delegates to `clear()` so disposal and reset happen through one\n * well-defined code path; this also avoids disposing each\n * operation twice.\n */\n disposeAll(): void {\n this.clear();\n }\n\n /**\n * Returns `true` when `element` matches the configured\n * `isBoundaryElement` predicate AND is a foreign boundary (i.e. is\n * not the index's own root).\n *\n * The root itself is always walked; only nested boundaries stop the\n * traversal.\n */\n private _isForeignBoundary(element: Element): boolean {\n if (\n this.options.root !== undefined &&\n element === this.options.root\n ) {\n return false;\n }\n\n return (\n this.options.isBoundaryElement?.(element) === true\n );\n }\n\n /**\n * Returns `true` when `node` belongs to this index's root.\n *\n * The walk climbs ancestors looking for either `root` or a foreign\n * boundary. If the walk reaches `root` without hitting a foreign\n * boundary, the node is owned. If the walk hits a foreign boundary\n * first, the node is not owned.\n *\n * When `root` is not configured, the index accepts every mutation\n * it receives — callers that wire a parent observer MUST set\n * `root` to prevent nested-scope leakage.\n *\n * Foreign-boundary element itself: when the target `node` is a\n * boundary element other than the index's own `root`, it is owned\n * by another controller. The check is performed up-front so the\n * ancestor loop only handles descendants and the `current !==\n * node` guard it used to need can go away.\n */\n private _ownsNode(node: Node): boolean {\n const root = this.options.root;\n\n if (root === undefined) {\n return true;\n }\n\n // Shadow-DOM index: a node belongs to this index when the\n // ancestor chain reaches the configured shadow root before\n // climbing out at the shadow host.\n //\n // `getRootNode()` alone is not sufficient because a foreign\n // boundary element nested deeper inside the shadow can sit\n // between `node` and the shadow root — the foreign boundary\n // belongs to a different controller, so this index must not\n // claim it. Walking `parentNode` upward also catches the\n // shadow-host case: the host's `parentNode` chain leaves the\n // shadow tree entirely, so the walk terminates at `null`\n // without ever reaching `root`.\n //\n // Foreign-boundary predicates are also consulted at each\n // step so a nested element whose `getRootNode()` is still\n // `root` but which `isBoundaryElement` classifies as a\n // foreign boundary is correctly excluded — matching the\n // light-DOM branch's behaviour below.\n if (root instanceof ShadowRoot) {\n let current: Node | null = node;\n\n while (current !== null) {\n if (current === root) {\n return true;\n }\n\n // Foreign boundary nested inside this shadow — owned by\n // another controller even though `getRootNode()` still\n // returns this shadow root. `current` is narrowed to\n // `Element` here and `root` is a `ShadowRoot` (we are in\n // the `root instanceof ShadowRoot` branch), so the two\n // are disjoint types — the explicit `current !== root`\n // check is unnecessary and would be flagged as\n // unintentional.\n if (\n current instanceof Element &&\n this.options.isBoundaryElement?.(current) === true\n ) {\n return false;\n }\n\n current = current.parentNode;\n }\n\n return false;\n }\n\n if (\n node instanceof Element &&\n node !== root &&\n this.options.isBoundaryElement?.(node) === true\n ) {\n return false;\n }\n\n let current: Node | null = node;\n\n while (current) {\n if (current === root) {\n return true;\n }\n\n if (\n current instanceof Element &&\n current !== root &&\n this.options.isBoundaryElement?.(current) === true\n ) {\n return false;\n }\n\n current = current.parentNode;\n }\n\n return false;\n }\n\n private _addNode(node: Node): boolean {\n // Refuse to walk into nodes that are not part of the root's owned\n // subtree. Observer feedback can deliver `add` mutations for\n // nested scope elements or sibling trees that the parent index\n // does not own — the index must ignore them.\n if (!this._ownsNode(node)) {\n return false;\n }\n\n if (this._isIndexed(node)) {\n // Already indexed. Avoid double-processing the same node.\n return false;\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n const op = this.factory.createTextOperation(\n node as Text,\n { sources: this.sources }\n );\n\n if (op) {\n this._addTextOperation(node as Text, op);\n return true;\n }\n\n return false;\n }\n\n // `ShadowRoot` (and any `DocumentFragment`-shaped root passed\n // to `initialize()`) is not itself a template target — it is\n // a container. Descend into its children and index each one.\n if (node instanceof DocumentFragment) {\n for (const child of Array.from(node.childNodes)) {\n this._addNode(child);\n }\n return false;\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return false;\n }\n\n const element = node as Element;\n\n // Foreign-boundary check happens BEFORE attribute collection so a\n // nested boundary element is fully skipped. The boundary's own\n // controller owns both its attributes and its descendants — a\n // parent index must not collect either.\n if (this._isForeignBoundary(element)) {\n return false;\n }\n\n const beforeSize = this._operations.size;\n\n this._collectAttributes(element);\n\n for (const child of Array.from(\n element.childNodes\n )) {\n this._addNode(child);\n }\n\n return this._operations.size !== beforeSize;\n }\n\n private _isIndexed(node: Node): boolean {\n if (this._indexedNodes.has(node)) {\n return true;\n }\n\n if (node.nodeType === Node.ELEMENT_NODE) {\n return this._attrOps.has(node as Element);\n }\n\n return false;\n }\n\n private _collectAttributes(\n element: Element\n ): void {\n const context = { sources: this.sources };\n\n for (const attr of Array.from(element.attributes)) {\n const op =\n this.factory.createAttributeOperation(\n element,\n attr,\n context\n );\n\n if (!op) {\n continue;\n }\n\n this._addAttributeOperation(\n element,\n attr.name,\n op\n );\n }\n }\n\n /**\n * Removes every operation that targets `node` or one of its descendants.\n *\n * The walk mirrors `_addNode` but does not need to consult the factory.\n * Returns `true` when at least one operation was disposed by the\n * call.\n */\n private _removeNode(node: Node): boolean {\n let removed = false;\n const owned = this._nodeIndex.get(node);\n\n if (owned) {\n for (const op of owned) {\n if (this._deleteOperation(op)) {\n removed = true;\n }\n }\n\n this._nodeIndex.delete(node);\n }\n\n this._indexedNodes.delete(node);\n\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as Element;\n\n // Drop any attribute operations owned by this element. The\n // per-attribute map is authoritative for attribute lookup, so we\n // must clear it here.\n const byName = this._attrOps.get(element);\n\n if (byName) {\n for (const op of byName.values()) {\n if (this._deleteOperation(op)) {\n removed = true;\n }\n }\n\n this._attrOps.delete(element);\n }\n\n for (const child of Array.from(\n element.childNodes\n )) {\n if (this._removeNode(child)) {\n removed = true;\n }\n }\n }\n\n return removed;\n }\n\n private _updateAttribute(\n element: Element,\n attribute: string\n ): boolean {\n if (!this._ownsNode(element)) {\n return false;\n }\n\n // Sync the registry with the current DOM value before re-running\n // discovery so an external mutation that turned a template into\n // plain text is reflected (the registry must not serve a stale\n // preserved source).\n this.sources.syncAttributeSource(element, attribute);\n\n // Drop the previous operation for this (element, name) pair. The\n // Attr reference is unstable across mutations, so we key by element\n // + name via `_attrOps` rather than by Attr. We capture the return\n // value because the contract for `apply()` requires this method\n // to report the index actually changed — even if no replacement\n // attribute is found, removing the old operation IS a change.\n const removed =\n this._removeAttributeOperation(element, attribute);\n\n // Resolve the current Attr for the new value. If the attribute was\n // removed entirely there is nothing to re-create.\n const attr = element.attributes.getNamedItem(\n attribute\n );\n\n if (!attr) {\n return removed;\n }\n\n const op =\n this.factory.createAttributeOperation(\n element,\n attr,\n { sources: this.sources }\n );\n\n if (!op) {\n // The new attribute value is not a template (e.g. external\n // code replaced `{{ url }}` with plain text). The old\n // operation, if any, was already removed above — return\n // whether that removal actually happened so callers see an\n // accurate dirty signal.\n return removed;\n }\n\n this._addAttributeOperation(\n element,\n attribute,\n op\n );\n return true;\n }\n\n private _updateText(node: Text): boolean {\n if (!this._ownsNode(node)) {\n return false;\n }\n\n // Sync the registry with the current DOM value before re-running\n // discovery. External mutations that turn a template into plain\n // text must not leave the registry holding a stale preserved\n // source.\n this.sources.syncTextSource(node);\n\n // Capture whether the previous text operation was actually\n // removed. The contract for `apply()` requires this method to\n // report the index actually changed — even if no replacement\n // text operation is created, dropping the old one IS a change.\n let removed = false;\n\n const owned = this._nodeIndex.get(node);\n\n if (owned) {\n for (const op of owned) {\n if (op.kind === 'text') {\n if (this._deleteOperation(op)) {\n removed = true;\n }\n }\n }\n\n const remaining = new Set<\n TemplateOperation<TContext>\n >();\n\n for (const op of owned) {\n if (this._operations.has(op)) {\n remaining.add(op);\n }\n }\n\n if (remaining.size === 0) {\n this._nodeIndex.delete(node);\n this._indexedNodes.delete(node);\n } else {\n this._nodeIndex.set(node, remaining);\n }\n }\n\n const op = this.factory.createTextOperation(\n node,\n { sources: this.sources }\n );\n\n if (!op) {\n // The new value is not a template (e.g. external code replaced\n // `{{ name }}` with plain text). The previous text operation,\n // if any, was already removed above — return whether that\n // removal actually happened so callers see an accurate dirty\n // signal.\n return removed;\n }\n\n this._addTextOperation(node, op);\n return true;\n }\n\n private _addTextOperation(\n node: Text,\n operation: TemplateOperation<TContext>\n ): void {\n this._operations.add(operation);\n\n const owned =\n this._nodeIndex.get(node) ??\n new Set<TemplateOperation<TContext>>();\n\n owned.add(operation);\n this._nodeIndex.set(node, owned);\n this._indexedNodes.add(node);\n }\n\n private _addAttributeOperation(\n element: Element,\n name: string,\n operation: TemplateOperation<TContext>\n ): void {\n this._operations.add(operation);\n\n // Register the operation under both the element and the\n // (element, name) pair. `_nodeIndex` lets `hasNode(element)` and\n // `_removeNode(element)` find the operation via element identity;\n // `_attrOps` lets `_updateAttribute` find the previous op by name\n // even after the Attr reference changes.\n const owned =\n this._nodeIndex.get(element) ??\n new Set<TemplateOperation<TContext>>();\n\n owned.add(operation);\n this._nodeIndex.set(element, owned);\n this._indexedNodes.add(element);\n\n let byName = this._attrOps.get(element);\n\n if (!byName) {\n byName = new Map<\n string,\n TemplateOperation<TContext>\n >();\n this._attrOps.set(element, byName);\n }\n\n byName.set(name, operation);\n }\n\n private _removeAttributeOperation(\n element: Element,\n name: string\n ): boolean {\n const byName = this._attrOps.get(element);\n\n if (!byName) {\n return false;\n }\n\n const op = byName.get(name);\n\n if (!op) {\n return false;\n }\n\n this._deleteOperation(op);\n\n byName.delete(name);\n\n if (byName.size === 0) {\n this._attrOps.delete(element);\n }\n\n const owned = this._nodeIndex.get(element);\n\n if (owned) {\n owned.delete(op);\n\n if (owned.size === 0) {\n this._nodeIndex.delete(element);\n this._indexedNodes.delete(element);\n }\n }\n\n return true;\n }\n\n /**\n * Removes `operation` from the live `_operations` set and calls its\n * `dispose()` hook.\n *\n * Returns `true` when the operation was actually present and\n * removed, `false` when it had already been removed by a previous\n * path (idempotent removal).\n *\n * Single entry point used by every removal path so the disposal\n * contract is honoured uniformly.\n */\n private _deleteOperation(\n operation: TemplateOperation<TContext>\n ): boolean {\n if (!this._operations.delete(operation)) {\n return false;\n }\n\n operation.dispose();\n return true;\n }\n}\n"]}
@@ -0,0 +1,529 @@
1
+ /**
2
+ * Shared type definitions for the Eta template subsystem.
3
+ *
4
+ * The subsystem is split into small, single-responsibility pieces:
5
+ *
6
+ * MutationObserver
7
+ * -> translates DOM mutations into TemplateIndexMutation values
8
+ *
9
+ * EtaTemplateIndex
10
+ * -> maintains the operation index for a scoped boundary
11
+ *
12
+ * TemplateOperationFactory
13
+ * -> discovers templates and compiles them via EtaTemplateCache
14
+ *
15
+ * TextOperation / AttributeOperation
16
+ * -> render a single DOM target against a context
17
+ *
18
+ * EtaTemplateController
19
+ * -> owns lifecycle, the Task schedule, and the context builder
20
+ *
21
+ * EtaMutationBatcher
22
+ * -> coalesces MutationRecord batches into a single
23
+ * index flush per scheduled tick (round 6)
24
+ *
25
+ * Most of these layers are Eta-agnostic. Only the cache and factory know how
26
+ * to talk to Eta. Everything else works on plain DOM nodes.
27
+ */
28
+ /**
29
+ * Schedule mode for `EtaMutationBatcher` flushes.
30
+ *
31
+ * Defined here (rather than in `batcher.ts`) so consumers can
32
+ * import the type without pulling the batcher module into a
33
+ * type-only import cycle. The batcher re-exports the type for
34
+ * direct importers.
35
+ *
36
+ * - `microtask` — flush via `queueMicrotask`. Lowest latency.
37
+ * - `animation-frame` — flush via `requestAnimationFrame`.
38
+ * Recommended default for browser hosts.
39
+ * - `idle` — flush via `requestIdleCallback` (with a `setTimeout`
40
+ * fallback). Lowest priority.
41
+ * - `manual` — never auto-flush; the host owns the lifecycle.
42
+ */
43
+ export type EtaMutationBatchSchedule = 'microtask' | 'animation-frame' | 'idle' | 'manual';
44
+ export type EtaMutationBatchScheduleResolver = () => EtaMutationBatchSchedule | undefined;
45
+ export type EtaMutationBatchScheduleOption = EtaMutationBatchSchedule | EtaMutationBatchScheduleResolver;
46
+ /**
47
+ * A precompiled Eta template function.
48
+ *
49
+ * `data` is the rendering context. The function returns a string. Eta exposes
50
+ * `compile` as a member of the Eta class, so the function signature is
51
+ * `(data?) => string`.
52
+ */
53
+ export type EtaCompiledTemplate = (data?: object) => string;
54
+ /**
55
+ * Discriminated union describing a single change that should be reflected
56
+ * in the template index.
57
+ *
58
+ * - `add` introduces a node that has not been seen before
59
+ * - `remove` drops a node and all of its descendants
60
+ * - `attribute` re-runs attribute discovery for a single attribute on an
61
+ * element that is already part of the index
62
+ * - `text` re-runs text discovery for a text node that is already part of
63
+ * the index
64
+ */
65
+ export type TemplateIndexMutation = {
66
+ readonly type: 'add';
67
+ readonly node: Node;
68
+ } | {
69
+ readonly type: 'remove';
70
+ readonly node: Node;
71
+ } | {
72
+ readonly type: 'attribute';
73
+ readonly element: Element;
74
+ readonly attribute: string;
75
+ } | {
76
+ readonly type: 'text';
77
+ readonly node: Text;
78
+ };
79
+ /**
80
+ * Anything that can absorb a TemplateIndexMutation.
81
+ *
82
+ * EtaMutationObserver and EtaTemplateIndex both satisfy this interface so
83
+ * that they can be swapped in tests or composed by other layers.
84
+ *
85
+ * `apply` returns `true` only when the sink actually changed its
86
+ * index as a result of the mutation. Returning `false` signals that
87
+ * the mutation was ignored (the node was outside the index's root,
88
+ * the attribute had no template, the boundary skipped the subtree,
89
+ * etc.). The observer uses this signal to decide whether a render
90
+ * pass needs to be scheduled, so returning the wrong value directly
91
+ * causes either stale renders or unnecessary work.
92
+ */
93
+ export interface TemplateIndexSink {
94
+ apply(mutation: TemplateIndexMutation): boolean;
95
+ }
96
+ /**
97
+ * A single immutable rendering operation.
98
+ *
99
+ * Operations are owned by a single DOM target (a text node or an attribute
100
+ * of an element) and know nothing about template discovery, the index, or
101
+ * the controller. They simply render their target against a context.
102
+ *
103
+ * The `dispose` method is currently a no-op for the built-in operations but
104
+ * exists as an extension point for future implementations that may hold
105
+ * observers, event listeners, or other resources.
106
+ */
107
+ export interface TemplateOperation<TContext = object> {
108
+ readonly owner: Node;
109
+ readonly kind: 'text' | 'attribute';
110
+ execute(context: TContext): void;
111
+ dispose(): void;
112
+ }
113
+ /**
114
+ * Structural surface used by `TemplateOperationContext.sources`.
115
+ *
116
+ * Defined here (rather than imported from `source-registry.ts`) so
117
+ * `types.ts` stays a leaf module per the eta subsystem layout.
118
+ * Any object that satisfies these four methods can stand in for
119
+ * the real `EtaTemplateSourceRegistry` — tests can pass mocks
120
+ * without pulling the registry module into a type-only cycle.
121
+ */
122
+ export interface TemplateOperationSourceRegistry {
123
+ readTextSource(node: Text): string | undefined;
124
+ replaceTextSource(node: Text, source: string | undefined): void;
125
+ readAttributeSource(element: Element, name: string): string | undefined;
126
+ setAttributeSource(element: Element, name: string, source: string): void;
127
+ }
128
+ /**
129
+ * Per-call context passed into `TemplateOperationFactory.create*`
130
+ * methods.
131
+ *
132
+ * Carries dependencies that the factory needs at discovery time
133
+ * but does not own. Today the only such dependency is the
134
+ * `EtaTemplateSourceRegistry`, which preserves original template
135
+ * sources across renders. By threading the registry through every
136
+ * factory call (rather than storing it on the factory instance)
137
+ * the factory stays stateless at the call site and can safely be
138
+ * shared across multiple indices — the registry is always the
139
+ * one owned by the calling index.
140
+ *
141
+ * The context is optional: factory implementations that do not
142
+ * need preserved sources can simply ignore it. Test fakes can
143
+ * pass `undefined`.
144
+ */
145
+ export interface TemplateOperationContext {
146
+ /** Source registry for preserved original template sources. */
147
+ readonly sources?: TemplateOperationSourceRegistry;
148
+ }
149
+ /**
150
+ * Factory contract for producing TemplateOperation instances from DOM nodes.
151
+ *
152
+ * The factory is the only Eta-aware discovery layer. The collector simply
153
+ * forwards raw DOM nodes to the factory and stores whatever comes back.
154
+ *
155
+ * A factory returns `undefined` when a node does not contain a template,
156
+ * which lets the index skip irrelevant subtrees.
157
+ *
158
+ * The optional `context` parameter carries dependencies that the
159
+ * factory needs at discovery time but does not own — currently
160
+ * the source registry. The factory treats it as advisory: a
161
+ * missing context means the factory does not have access to
162
+ * preserved sources, so post-render reads fall back to the live
163
+ * DOM value.
164
+ */
165
+ export interface TemplateOperationFactory<TContext = object> {
166
+ createTextOperation(node: Text, context?: TemplateOperationContext): TemplateOperation<TContext> | undefined;
167
+ createAttributeOperation(element: Element, attribute: Attr, context?: TemplateOperationContext): TemplateOperation<TContext> | undefined;
168
+ }
169
+ /**
170
+ * Cache for compiled Eta templates.
171
+ *
172
+ * Keys are the original template strings. The cache is the single owner of
173
+ * template compilation. Neither the factory nor operations compile templates
174
+ * directly.
175
+ */
176
+ export interface EtaTemplateCache {
177
+ get(source: string): EtaCompiledTemplate;
178
+ clear(): void;
179
+ /**
180
+ * Number of compiled templates currently held in the cache.
181
+ *
182
+ * Optional because the structural minimum only describes what the
183
+ * controller and factory need to drive a render pass. The
184
+ * default `DefaultEtaTemplateCache` exposes `size`; tests and
185
+ * diagnostics that read `cache.size` rely on this hook being
186
+ * present, so the optional property documents the convention.
187
+ *
188
+ * `EtaTemplateController.#cache` is now a true ECMAScript
189
+ * private field and cannot be observed from outside the
190
+ * controller, but the host can still construct the cache
191
+ * directly and read `size` for diagnostics.
192
+ */
193
+ readonly size?: number;
194
+ }
195
+ /**
196
+ * Result type returned by Eta when compiling a template source.
197
+ *
198
+ * Some Eta configurations (async, plugins, custom tags) can change the
199
+ * function shape; we keep the contract minimal and let EtaTemplateCache
200
+ * implementation choose the actual compiler.
201
+ */
202
+ export type EtaCompileFn = (source: string) => EtaCompiledTemplate;
203
+ /**
204
+ * Minimal surface required by `EtaTemplateController` on its host.
205
+ *
206
+ * The controller reads the root element and may register local async
207
+ * work with the host so the render pass participates in the host's
208
+ * `updateComplete` contract.
209
+ *
210
+ * Anything else — the current scope, compute revision, the compute
211
+ * controller — is read by the host-supplied `args` / `context`
212
+ * callbacks inside `EtaTemplateControllerOptions`, NOT by the
213
+ * controller. That keeps the controller reusable outside
214
+ * `BdScopedElement`.
215
+ */
216
+ export interface EtaTemplateHost {
217
+ /**
218
+ * Owning boundary. Must be an `Element` because the controller marks
219
+ * it as a traversal boundary (only elements own attributes and
220
+ * children — text/document roots cannot act as Eta boundaries).
221
+ */
222
+ readonly root: Element;
223
+ /**
224
+ * Track local async work — when provided, the controller registers
225
+ * the render pass under its own instance as the key so the host's
226
+ * `updateComplete` waits for the render to finish before resolving.
227
+ *
228
+ * Mirrors the signature used by `BdNodeElement.trackLocalWork`.
229
+ */
230
+ trackLocalWork?<T>(key: unknown, work: PromiseLike<T>): Promise<T>;
231
+ }
232
+ /**
233
+ * Options accepted by `EtaTemplateController`.
234
+ *
235
+ * The controller is scope-agnostic. Everything reactive is funnelled
236
+ * through `args`, `enabled`, and `context` callbacks so the controller
237
+ * stays usable outside `BdScopedElement`.
238
+ */
239
+ export interface EtaTemplateControllerOptions<TArgs extends readonly unknown[] = readonly unknown[], TContext extends object = object> {
240
+ /**
241
+ * Args the controller reacts to. The Task re-runs whenever the
242
+ * returned tuple changes; the default comparison is `@lit/task`'s
243
+ * `shallowArrayEquals`. Override via `argsEqual` for custom
244
+ * equality (e.g. structural compare on a single object argument).
245
+ *
246
+ * Hosts typically return reactive properties of their own state:
247
+ *
248
+ * ```ts
249
+ * args: () => [
250
+ * this.currentScope,
251
+ * this.compute.revision,
252
+ * this.isComputeEnabled
253
+ * ] as const
254
+ * ```
255
+ */
256
+ args: () => TArgs;
257
+ /**
258
+ * Optional equality check for `args`. Forwarded to the underlying
259
+ * `@lit/task` so the controller re-runs only when the returned
260
+ * tuple actually changes by the host's definition.
261
+ *
262
+ * Return `true` when the old tuple and the new tuple should be
263
+ * treated as equal (no rerun); return `false` to force a rerun.
264
+ * When omitted, `@lit/task` uses its built-in
265
+ * `shallowArrayEquals` which compares tuple elements by reference
266
+ * (object identity for non-primitives).
267
+ */
268
+ argsEqual?: (oldArgs: TArgs, newArgs: TArgs) => boolean;
269
+ /**
270
+ * Optional gate. When `enabled` returns `false` the controller skips
271
+ * the render pass. When enabled returns false, the task completes
272
+ * with undefined.
273
+ *
274
+ * The default is "always enabled".
275
+ */
276
+ enabled?: (args: TArgs) => boolean;
277
+ /**
278
+ * Context builder. Returns the value handed to each
279
+ * `TemplateOperation.execute()` call.
280
+ *
281
+ * Returning `undefined` short-circuits the render pass for the
282
+ * current args — the index keeps its operations but the renderer
283
+ * does not invoke them. This is the right behaviour when the args
284
+ * describe a state where rendering would produce invalid output
285
+ * (for example, a scope that has not yet been published).
286
+ *
287
+ * Hosts that want the recommended `$scope` / `$compute` shape can
288
+ * spread the scope entry, then attach `$scope` and `$compute`
289
+ * fields to the returned context object. The controller does NOT
290
+ * build that shape for the host — see `DefaultEtaContext` for the
291
+ * documented shape.
292
+ */
293
+ context: (args: TArgs) => TContext | undefined;
294
+ /**
295
+ * Optional override used by tests to inject a deterministic index.
296
+ *
297
+ * The callback receives the resolved factory so the index can be
298
+ * constructed with the same factory the controller will use. The
299
+ * returned object must:
300
+ *
301
+ * - implement `TemplateIndexSink` so the observer can feed it
302
+ * mutations;
303
+ * - be iterable so the controller can render every operation;
304
+ * - expose `disposeAll()` so the controller can clean up on
305
+ * disconnect.
306
+ *
307
+ * `EtaTemplateIndex` satisfies this shape; tests may return a fake.
308
+ */
309
+ createIndex?: (factory: TemplateOperationFactory<TContext>) => EtaTemplateIndexLike<TContext>;
310
+ /**
311
+ * Optional allowlist of attribute names the factory should
312
+ * consider. When provided, attributes outside the list are skipped.
313
+ *
314
+ * When omitted, the factory defaults to observing every attribute.
315
+ */
316
+ attributeNames?: readonly string[];
317
+ /**
318
+ * When `true`, the controller tells the factory to ignore any
319
+ * attribute allowlist and observe every attribute. Useful when
320
+ * templates use non-standard attribute names (e.g. plain `href`
321
+ * with a template literal).
322
+ *
323
+ * The controller owns its default factory privately; this option
324
+ * controls the factory and observer that the controller builds.
325
+ */
326
+ observeAllAttributes?: boolean;
327
+ /**
328
+ * Optional predicate evaluated by the controller to decide whether
329
+ * an `Element` is a topology boundary (i.e. owned by a different
330
+ * controller).
331
+ *
332
+ * Threaded through to the index so the index's traversal and the
333
+ * host's own child accounting share a single rule. Without this
334
+ * predicate the index still walks the host's subtree but cannot
335
+ * tell apart foreign boundaries.
336
+ *
337
+ * ⚠️ **Stable-on-raw-DOM.** The predicate MUST work on raw DOM
338
+ * shape (tag names, marker attributes) rather than prototype-side
339
+ * state such as `instanceof BdScopedElement` or runtime brands
340
+ * set in custom-element classes. The parent index may scan a
341
+ * subtree before a nested custom element upgrades; without a
342
+ * stable raw-DOM check the parent index will silently absorb the
343
+ * nested scope's templates. See `EtaTemplateIndexOptions.
344
+ * isBoundaryElement` for full rationale and example patterns.
345
+ *
346
+ * Example pattern (tag-name based, stable before upgrade):
347
+ *
348
+ * ```ts
349
+ * isBoundaryElement: (element) => {
350
+ * const name = element.localName;
351
+ * return (
352
+ * name === 'bd-context' ||
353
+ * name === 'bd-product' ||
354
+ * name === 'bd-option'
355
+ * );
356
+ * }
357
+ * ```
358
+ */
359
+ isBoundaryElement?: (element: Element) => boolean;
360
+ /**
361
+ * Optional per-operation error handler.
362
+ *
363
+ * **Continue vs. throw behaviour:**
364
+ *
365
+ * - When this handler is provided, the render loop catches errors
366
+ * thrown by individual operations and continues with the next
367
+ * operation. The render pass is considered successful and the
368
+ * Task resolves normally with the most recent context. This is
369
+ * the right behaviour when callers want to observe partial
370
+ * failures (e.g. telemetry, fallback rendering) without aborting
371
+ * the whole render.
372
+ * - When omitted, the first error thrown by an operation propagates
373
+ * out of the render loop, the Task transitions to its error
374
+ * state, and `updateComplete` rejects. The previous successful
375
+ * render's output stays in the DOM because no later operation
376
+ * overwrites it.
377
+ *
378
+ * Mixing both modes is not supported — there is no way to observe
379
+ * the error AND propagate it in a single render pass. If both are
380
+ * needed, use the handler here and re-throw explicitly from inside
381
+ * it.
382
+ */
383
+ onRenderError?: (error: unknown, operation: TemplateOperation<TContext>) => void;
384
+ /**
385
+ * Optional schedule for `EtaMutationBatcher` flushes (round 6).
386
+ *
387
+ * Controls how the controller coalesces DOM mutations before
388
+ * forwarding them to the index. Defaults to `'animation-frame'`
389
+ * when omitted, which matches the design doc's recommended
390
+ * production default for AEM / SPA-style bursty DOM updates.
391
+ *
392
+ * Schedules:
393
+ *
394
+ * - `'microtask'` — lowest latency. The flush runs on the next
395
+ * microtask. Useful for tests that want deterministic flushes
396
+ * via `await new Promise<void>(r => queueMicrotask(r))`.
397
+ * - `'animation-frame'` — flush via `requestAnimationFrame`.
398
+ * Recommended default; coalesces DOM churn before paint.
399
+ * - `'idle'` — flush via `requestIdleCallback` (with a
400
+ * `setTimeout` fallback). Lowest priority.
401
+ * - `'manual'` — never auto-flush. The host owns the lifecycle
402
+ * and must call `controller.flushMutations()` /
403
+ * `controller.flushAndRender()` itself. Intended for
404
+ * host-driven lifecycles (for example, AEM block decoration
405
+ * flows where the host knows exactly when a decoration phase
406
+ * ends).
407
+ *
408
+ * **Has no effect on tests that bypass the controller.** Tests
409
+ * that drive the observer directly still observe records through
410
+ * the legacy `TemplateIndexSink` path because they construct
411
+ * the observer with an explicit `sink` rather than relying on
412
+ * the controller's batcher wiring.
413
+ *
414
+ * **Has no effect when a custom observer is injected.** The
415
+ * controller owns the batcher; consumers that want a different
416
+ * forwarding destination should construct their own observer
417
+ * and skip the controller's batcher.
418
+ */
419
+ mutationBatchSchedule?: EtaMutationBatchScheduleOption;
420
+ }
421
+ /**
422
+ * Options accepted by `EtaTemplateIndex`.
423
+ *
424
+ * The controller passes these through to the index it constructs. The
425
+ * index is otherwise opaque; boundary detection and ownership rules
426
+ * live here so the index does not need to know about products,
427
+ * options, or scoped elements.
428
+ */
429
+ export interface EtaTemplateIndexOptions {
430
+ /**
431
+ * Predicate that decides whether an `Element` should be treated as a
432
+ * traversal boundary.
433
+ *
434
+ * When the predicate returns `true` for an element:
435
+ *
436
+ * - If the element is this index's own root, it is still indexed as
437
+ * the local boundary. Its own attributes and owned descendants are
438
+ * collected.
439
+ * - If the element is not this index's root, it is a foreign
440
+ * boundary. The index does not collect the foreign boundary's
441
+ * attributes and does not descend into its subtree.
442
+ *
443
+ * The predicate is also consulted during mutation entry points: an
444
+ * attribute or text mutation on a foreign boundary element or its
445
+ * descendants is ignored.
446
+ *
447
+ * ⚠️ **Stable-on-raw-DOM invariant.** The predicate MUST work on
448
+ * raw DOM shape (e.g. `element.localName`, `element.tagName`,
449
+ * marker attributes) rather than on prototype-side state such as
450
+ * `element instanceof BdScopedElement` or a runtime brand set in
451
+ * a custom-element class. The reason: the parent index may scan
452
+ * a subtree before a nested custom element upgrades, in which
453
+ * case the nested element has not yet been augmented with the
454
+ * brand and the parent index would accidentally collect its
455
+ * templates. No DOM mutation necessarily fires later when the
456
+ * upgrade completes, so the parent index may keep the wrong
457
+ * operations. Prefer tag-name or marker-attribute checks so the
458
+ * classification is stable from the moment the element is
459
+ * parsed.
460
+ *
461
+ * Example patterns:
462
+ *
463
+ * ```ts
464
+ * // Tag-name based — works on raw DOM, no upgrade required.
465
+ * isBoundaryElement: (element) => {
466
+ * const name = element.localName;
467
+ * return (
468
+ * name === 'bd-context' ||
469
+ * name === 'bd-product' ||
470
+ * name === 'bd-option'
471
+ * );
472
+ * }
473
+ * ```
474
+ *
475
+ * ```ts
476
+ * // Marker-attribute based — also stable before upgrade.
477
+ * isBoundaryElement: (element) =>
478
+ * element.hasAttribute('bd-scope') ||
479
+ * element.matches('bd-context,bd-product,bd-option')
480
+ * ```
481
+ *
482
+ * ```ts
483
+ * // Brand + tag-name fallback — keep the runtime brand as a fast
484
+ * path for already-upgraded hosts, but always fall back to a
485
+ // stable raw-DOM check so the parent index stays correct while
486
+ // the subtree is upgrading.
487
+ * isBoundaryElement: (element) =>
488
+ * isBdScopedElement(element) ||
489
+ * element.matches('bd-context,bd-product,bd-option')
490
+ * ```
491
+ */
492
+ readonly isBoundaryElement?: (element: Element) => boolean;
493
+ /**
494
+ * Root owned by this index.
495
+ *
496
+ * Mutations received by the index that target nodes outside the
497
+ * subtree rooted at `root` are dropped. Without `root`, the index
498
+ * accepts every mutation it receives — callers that wire a
499
+ * parent observer must set `root` to prevent nested-scope leakage.
500
+ *
501
+ * The root is an `Element` for light-DOM indices and a
502
+ * `ShadowRoot` for shadow-DOM indices. The controller walks
503
+ * the host's light subtree during `hostConnected` looking for
504
+ * attached open shadow roots and creates a per-root index for
505
+ * each one. Tests may pass either kind.
506
+ */
507
+ readonly root?: Element | ShadowRoot;
508
+ }
509
+ /**
510
+ * Structural minimum required for an Eta template index.
511
+ *
512
+ * The real `EtaTemplateIndex` (in `./template-index.js`) implements this
513
+ * shape. Splitting the contract out lets `types.ts` stay free of the
514
+ * index implementation, avoiding a circular import.
515
+ */
516
+ export interface EtaTemplateIndexLike<TContext = object> extends TemplateIndexSink, Iterable<TemplateOperation<TContext>> {
517
+ disposeAll(): void;
518
+ initialize(root: ParentNode): void;
519
+ /**
520
+ * Number of operations currently held by the index.
521
+ *
522
+ * The real `EtaTemplateIndex` (in `./template-index.js`) is the
523
+ * sole intended implementer; the field is required because
524
+ * diagnostics and tests read it directly without an
525
+ * `?? 0` fallback. Fake indices used in tests must provide
526
+ * `get size(): number { return 0; }` (or equivalent).
527
+ */
528
+ readonly size: number;
529
+ }
@@ -0,0 +1,2 @@
1
+ // src/eta/types.ts
2
+ //# sourceMappingURL=types.js.map