@askrjs/askr 0.0.39 → 0.0.40

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 (250) hide show
  1. package/dist/bench/components/benchmark-row.d.ts.map +1 -1
  2. package/dist/bench/components/benchmark-row.js.map +1 -1
  3. package/dist/bench/components/benchmark-table.js.map +1 -1
  4. package/dist/benchmark.d.ts.map +1 -1
  5. package/dist/benchmark.js +2 -2
  6. package/dist/benchmark.js.map +1 -1
  7. package/dist/bin/askr-ssg.d.ts.map +1 -1
  8. package/dist/bin/askr-ssg.js.map +1 -1
  9. package/dist/boot/index.d.ts +9 -6
  10. package/dist/boot/index.d.ts.map +1 -1
  11. package/dist/boot/index.js +210 -75
  12. package/dist/boot/index.js.map +1 -1
  13. package/dist/common/attr-names.js +17 -0
  14. package/dist/common/attr-names.js.map +1 -0
  15. package/dist/common/component.d.ts.map +1 -1
  16. package/dist/common/control.d.ts.map +1 -1
  17. package/dist/common/control.js.map +1 -1
  18. package/dist/common/env.js.map +1 -1
  19. package/dist/common/jsx.d.ts.map +1 -1
  20. package/dist/common/jsx.js.map +1 -1
  21. package/dist/common/promise.js +8 -0
  22. package/dist/common/promise.js.map +1 -0
  23. package/dist/common/props.d.ts +286 -1
  24. package/dist/common/props.d.ts.map +1 -1
  25. package/dist/common/router-internal.js +6 -0
  26. package/dist/common/router-internal.js.map +1 -0
  27. package/dist/common/router.d.ts +45 -36
  28. package/dist/common/router.d.ts.map +1 -1
  29. package/dist/common/ssr-errors.d.ts.map +1 -1
  30. package/dist/common/ssr-errors.js.map +1 -1
  31. package/dist/common/ssr.d.ts +1 -0
  32. package/dist/common/ssr.d.ts.map +1 -1
  33. package/dist/common/ssr.js +6 -0
  34. package/dist/common/ssr.js.map +1 -0
  35. package/dist/common/vnode.d.ts +2 -1
  36. package/dist/common/vnode.d.ts.map +1 -1
  37. package/dist/common/vnode.js.map +1 -1
  38. package/dist/components/error-boundary.d.ts +7 -4
  39. package/dist/components/error-boundary.d.ts.map +1 -1
  40. package/dist/components/error-boundary.js.map +1 -1
  41. package/dist/components/link.d.ts +2 -1
  42. package/dist/components/link.d.ts.map +1 -1
  43. package/dist/components/link.js +10 -1
  44. package/dist/components/link.js.map +1 -1
  45. package/dist/control/case.d.ts +4 -2
  46. package/dist/control/case.d.ts.map +1 -1
  47. package/dist/control/case.js.map +1 -1
  48. package/dist/control/for.d.ts +2 -1
  49. package/dist/control/for.d.ts.map +1 -1
  50. package/dist/control/for.js.map +1 -1
  51. package/dist/control/shared.d.ts +9 -0
  52. package/dist/control/shared.d.ts.map +1 -0
  53. package/dist/control/shared.js.map +1 -1
  54. package/dist/control/show.d.ts +4 -3
  55. package/dist/control/show.d.ts.map +1 -1
  56. package/dist/control/show.js.map +1 -1
  57. package/dist/data/index.d.ts +94 -14
  58. package/dist/data/index.d.ts.map +1 -1
  59. package/dist/data/index.js +65 -14
  60. package/dist/data/index.js.map +1 -1
  61. package/dist/dev/invariant.js.map +1 -1
  62. package/dist/dev/logger.js.map +1 -1
  63. package/dist/foundations/icon/icon.d.ts.map +1 -1
  64. package/dist/foundations/icon/icon.js.map +1 -1
  65. package/dist/foundations/icon/icon.types.d.ts.map +1 -1
  66. package/dist/foundations/interactions/dismissable.d.ts +9 -3
  67. package/dist/foundations/interactions/dismissable.d.ts.map +1 -1
  68. package/dist/foundations/interactions/dismissable.js.map +1 -1
  69. package/dist/foundations/interactions/focusable.d.ts.map +1 -1
  70. package/dist/foundations/interactions/focusable.js.map +1 -1
  71. package/dist/foundations/interactions/hoverable.d.ts.map +1 -1
  72. package/dist/foundations/interactions/hoverable.js.map +1 -1
  73. package/dist/foundations/interactions/interaction-policy.d.ts +1 -1
  74. package/dist/foundations/interactions/interaction-policy.d.ts.map +1 -1
  75. package/dist/foundations/interactions/interaction-policy.js +3 -3
  76. package/dist/foundations/interactions/interaction-policy.js.map +1 -1
  77. package/dist/foundations/interactions/pressable.d.ts.map +1 -1
  78. package/dist/foundations/interactions/pressable.js.map +1 -1
  79. package/dist/foundations/interactions/roving-focus.d.ts.map +1 -1
  80. package/dist/foundations/interactions/roving-focus.js +8 -8
  81. package/dist/foundations/interactions/roving-focus.js.map +1 -1
  82. package/dist/foundations/state/controllable.d.ts.map +1 -1
  83. package/dist/foundations/state/controllable.js.map +1 -1
  84. package/dist/foundations/structures/collection.d.ts.map +1 -1
  85. package/dist/foundations/structures/collection.js.map +1 -1
  86. package/dist/foundations/structures/layer.d.ts.map +1 -1
  87. package/dist/foundations/structures/layer.js.map +1 -1
  88. package/dist/foundations/structures/layout.d.ts +4 -2
  89. package/dist/foundations/structures/layout.d.ts.map +1 -1
  90. package/dist/foundations/structures/layout.js.map +1 -1
  91. package/dist/foundations/structures/portal.d.ts +9 -25
  92. package/dist/foundations/structures/portal.d.ts.map +1 -1
  93. package/dist/foundations/structures/portal.js +98 -17
  94. package/dist/foundations/structures/portal.js.map +1 -1
  95. package/dist/foundations/structures/presence.d.ts +4 -3
  96. package/dist/foundations/structures/presence.d.ts.map +1 -1
  97. package/dist/foundations/structures/presence.js +2 -2
  98. package/dist/foundations/structures/presence.js.map +1 -1
  99. package/dist/foundations/structures/slot.d.ts +2 -1
  100. package/dist/foundations/structures/slot.d.ts.map +1 -1
  101. package/dist/foundations/structures/slot.js.map +1 -1
  102. package/dist/foundations/utilities/aria.d.ts.map +1 -1
  103. package/dist/foundations/utilities/aria.js.map +1 -1
  104. package/dist/foundations/utilities/compose-handlers.d.ts.map +1 -1
  105. package/dist/foundations/utilities/compose-handlers.js.map +1 -1
  106. package/dist/foundations/utilities/compose-ref.d.ts.map +1 -1
  107. package/dist/foundations/utilities/compose-ref.js.map +1 -1
  108. package/dist/foundations/utilities/event-types.d.ts.map +1 -1
  109. package/dist/foundations/utilities/merge-props.js.map +1 -1
  110. package/dist/foundations/utilities/use-id.d.ts.map +1 -1
  111. package/dist/foundations/utilities/use-id.js.map +1 -1
  112. package/dist/fx/fx.d.ts.map +1 -1
  113. package/dist/fx/fx.js.map +1 -1
  114. package/dist/fx/noop.js.map +1 -1
  115. package/dist/fx/timing.d.ts +5 -4
  116. package/dist/fx/timing.d.ts.map +1 -1
  117. package/dist/fx/timing.js +7 -4
  118. package/dist/fx/timing.js.map +1 -1
  119. package/dist/index.js.map +1 -1
  120. package/dist/jsx/types.d.ts +3 -3
  121. package/dist/jsx/types.d.ts.map +1 -1
  122. package/dist/jsx/utils.d.ts.map +1 -1
  123. package/dist/jsx/utils.js.map +1 -1
  124. package/dist/jsx-dev-runtime.d.ts +6 -2
  125. package/dist/jsx-dev-runtime.d.ts.map +1 -1
  126. package/dist/jsx-dev-runtime.js.map +1 -1
  127. package/dist/jsx-runtime.d.ts +16 -6
  128. package/dist/jsx-runtime.d.ts.map +1 -1
  129. package/dist/jsx-runtime.js.map +1 -1
  130. package/dist/renderer/children.js.map +1 -1
  131. package/dist/renderer/cleanup.js +40 -13
  132. package/dist/renderer/cleanup.js.map +1 -1
  133. package/dist/renderer/dom.js +163 -63
  134. package/dist/renderer/dom.js.map +1 -1
  135. package/dist/renderer/evaluate.js +9 -6
  136. package/dist/renderer/evaluate.js.map +1 -1
  137. package/dist/renderer/fastpath.js.map +1 -1
  138. package/dist/renderer/for-commit.js +1 -0
  139. package/dist/renderer/for-commit.js.map +1 -1
  140. package/dist/renderer/index.js.map +1 -1
  141. package/dist/renderer/keyed.js.map +1 -1
  142. package/dist/renderer/reconcile.js +34 -0
  143. package/dist/renderer/reconcile.js.map +1 -1
  144. package/dist/renderer/utils.js +34 -3
  145. package/dist/renderer/utils.js.map +1 -1
  146. package/dist/router/index.d.ts +2 -2
  147. package/dist/router/match.js +16 -2
  148. package/dist/router/match.js.map +1 -1
  149. package/dist/router/navigate.d.ts +9 -1
  150. package/dist/router/navigate.d.ts.map +1 -1
  151. package/dist/router/navigate.js +235 -81
  152. package/dist/router/navigate.js.map +1 -1
  153. package/dist/router/policy.d.ts +7 -7
  154. package/dist/router/policy.d.ts.map +1 -1
  155. package/dist/router/policy.js +5 -7
  156. package/dist/router/policy.js.map +1 -1
  157. package/dist/router/route-context.js.map +1 -1
  158. package/dist/router/route.d.ts +20 -9
  159. package/dist/router/route.d.ts.map +1 -1
  160. package/dist/router/route.js +95 -29
  161. package/dist/router/route.js.map +1 -1
  162. package/dist/runtime/child-scope.d.ts.map +1 -1
  163. package/dist/runtime/child-scope.js +5 -1
  164. package/dist/runtime/child-scope.js.map +1 -1
  165. package/dist/runtime/component.d.ts +5 -2
  166. package/dist/runtime/component.d.ts.map +1 -1
  167. package/dist/runtime/component.js +85 -25
  168. package/dist/runtime/component.js.map +1 -1
  169. package/dist/runtime/context.d.ts +5 -2
  170. package/dist/runtime/context.d.ts.map +1 -1
  171. package/dist/runtime/context.js +5 -2
  172. package/dist/runtime/context.js.map +1 -1
  173. package/dist/runtime/control.d.ts.map +1 -1
  174. package/dist/runtime/control.js.map +1 -1
  175. package/dist/runtime/derive.d.ts.map +1 -1
  176. package/dist/runtime/derive.js +3 -1
  177. package/dist/runtime/derive.js.map +1 -1
  178. package/dist/runtime/dev-namespace.js.map +1 -1
  179. package/dist/runtime/effect.d.ts.map +1 -1
  180. package/dist/runtime/effect.js +17 -11
  181. package/dist/runtime/effect.js.map +1 -1
  182. package/dist/runtime/events.js +43 -1
  183. package/dist/runtime/events.js.map +1 -1
  184. package/dist/runtime/execution-model.js.map +1 -1
  185. package/dist/runtime/fastlane.js +2 -23
  186. package/dist/runtime/fastlane.js.map +1 -1
  187. package/dist/runtime/for-bench.d.ts.map +1 -1
  188. package/dist/runtime/for-bench.js.map +1 -1
  189. package/dist/runtime/for.d.ts +1 -1
  190. package/dist/runtime/for.d.ts.map +1 -1
  191. package/dist/runtime/for.js +36 -12
  192. package/dist/runtime/for.js.map +1 -1
  193. package/dist/runtime/operations.d.ts +3 -13
  194. package/dist/runtime/operations.d.ts.map +1 -1
  195. package/dist/runtime/operations.js +47 -39
  196. package/dist/runtime/operations.js.map +1 -1
  197. package/dist/runtime/perf-metrics.js.map +1 -1
  198. package/dist/runtime/readable.d.ts +1 -0
  199. package/dist/runtime/readable.d.ts.map +1 -1
  200. package/dist/runtime/readable.js +6 -1
  201. package/dist/runtime/readable.js.map +1 -1
  202. package/dist/runtime/resource-cell.js +13 -2
  203. package/dist/runtime/resource-cell.js.map +1 -1
  204. package/dist/runtime/scheduler.d.ts.map +1 -1
  205. package/dist/runtime/scheduler.js +8 -4
  206. package/dist/runtime/scheduler.js.map +1 -1
  207. package/dist/runtime/selector.d.ts.map +1 -1
  208. package/dist/runtime/selector.js +8 -2
  209. package/dist/runtime/selector.js.map +1 -1
  210. package/dist/runtime/snapshot-source.d.ts.map +1 -1
  211. package/dist/runtime/snapshot-source.js.map +1 -1
  212. package/dist/runtime/ssr-bridge.js.map +1 -1
  213. package/dist/runtime/state.d.ts +4 -3
  214. package/dist/runtime/state.d.ts.map +1 -1
  215. package/dist/runtime/state.js.map +1 -1
  216. package/dist/ssg/batch-render.js +4 -8
  217. package/dist/ssg/batch-render.js.map +1 -1
  218. package/dist/ssg/create-static-gen.d.ts +10 -2
  219. package/dist/ssg/create-static-gen.d.ts.map +1 -1
  220. package/dist/ssg/create-static-gen.js +5 -4
  221. package/dist/ssg/create-static-gen.js.map +1 -1
  222. package/dist/ssg/generate-metadata.js.map +1 -1
  223. package/dist/ssg/incremental-manifest.js.map +1 -1
  224. package/dist/ssg/resolve-ssg-data.js +54 -12
  225. package/dist/ssg/resolve-ssg-data.js.map +1 -1
  226. package/dist/ssg/route-utils.js.map +1 -1
  227. package/dist/ssg/types.d.ts +8 -7
  228. package/dist/ssg/types.d.ts.map +1 -1
  229. package/dist/ssg/write-static-files.js.map +1 -1
  230. package/dist/ssr/attrs.js +3 -2
  231. package/dist/ssr/attrs.js.map +1 -1
  232. package/dist/ssr/context.d.ts +1 -0
  233. package/dist/ssr/context.d.ts.map +1 -1
  234. package/dist/ssr/context.js +1 -0
  235. package/dist/ssr/context.js.map +1 -1
  236. package/dist/ssr/errors.d.ts.map +1 -1
  237. package/dist/ssr/escape.js.map +1 -1
  238. package/dist/ssr/index.d.ts +8 -12
  239. package/dist/ssr/index.d.ts.map +1 -1
  240. package/dist/ssr/index.js +55 -30
  241. package/dist/ssr/index.js.map +1 -1
  242. package/dist/ssr/render-keys.js +15 -4
  243. package/dist/ssr/render-keys.js.map +1 -1
  244. package/dist/ssr/render-resolved.js +33 -0
  245. package/dist/ssr/render-resolved.js.map +1 -0
  246. package/dist/ssr/sink.js.map +1 -1
  247. package/dist/ssr/types.d.ts.map +1 -1
  248. package/dist/ssr/verify-hydration.js +5 -6
  249. package/dist/ssr/verify-hydration.js.map +1 -1
  250. package/package.json +12 -4
@@ -1 +1 @@
1
- {"version":3,"file":"children.js","names":[],"sources":["../../src/renderer/children.ts"],"sourcesContent":["import { setDevValue, incDevCounter } from '../runtime/dev-namespace';\nimport { getRuntimeEnv } from './env';\nimport { keyedElements } from './keyed';\nimport { teardownNodeSubtree } from './cleanup';\nimport { createDOMNode, updateElementFromVnode } from './dom';\nimport { _isDOMElement, type DOMElement, type VNode } from './types';\nimport {\n hasNonTrivialProps,\n logFastPathDebug,\n now,\n recordDOMReplace,\n recordFastPathStats,\n tagNamesEqualIgnoreCase,\n} from './utils';\n\nfunction upperCommonTagName(tag: string): string | null {\n switch (tag) {\n case 'div':\n return 'DIV';\n case 'span':\n return 'SPAN';\n case 'p':\n return 'P';\n case 'a':\n return 'A';\n case 'button':\n return 'BUTTON';\n case 'input':\n return 'INPUT';\n case 'ul':\n return 'UL';\n case 'ol':\n return 'OL';\n case 'li':\n return 'LI';\n default:\n return null;\n }\n}\n\nfunction tagsEqualIgnoreCase(\n elementTagName: string,\n vnodeType: string\n): boolean {\n if (elementTagName === vnodeType) return true;\n\n const upperCommon = upperCommonTagName(vnodeType);\n if (upperCommon !== null && elementTagName === upperCommon) return true;\n\n return tagNamesEqualIgnoreCase(elementTagName, vnodeType);\n}\n\nexport function performBulkPositionalKeyedTextUpdate(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n) {\n const total = keyedVnodes.length;\n let reused = 0;\n let updatedKeys = 0;\n const start = now();\n const env = getRuntimeEnv();\n const debugFastPath =\n env.ASKR_FASTPATH_DEBUG === '1' || env.ASKR_FASTPATH_DEBUG === 'true';\n\n for (let index = 0; index < total; index += 1) {\n const { key, vnode } = keyedVnodes[index];\n const child = parent.children[index] as Element | undefined;\n\n if (\n child &&\n _isDOMElement(vnode) &&\n typeof (vnode as DOMElement).type === 'string'\n ) {\n const vnodeType = (vnode as DOMElement).type as string;\n\n if (tagsEqualIgnoreCase(child.tagName, vnodeType)) {\n const children =\n (vnode as DOMElement).children ||\n (vnode as DOMElement).props?.children;\n\n if (debugFastPath) {\n logFastPathDebug('positional idx', index, {\n chTag: child.tagName,\n vnodeType,\n chChildNodes: child.childNodes.length,\n childrenType: Array.isArray(children) ? 'array' : typeof children,\n });\n }\n\n updateTextContent(child, children, vnode as DOMElement);\n setDataKey(child, key, () => (updatedKeys += 1));\n reused += 1;\n continue;\n }\n\n if (debugFastPath) {\n logFastPathDebug('positional tag mismatch', index, {\n chTag: child.tagName,\n vnodeType,\n });\n }\n } else if (debugFastPath) {\n logFastPathDebug('positional missing or invalid', index, { ch: !!child });\n }\n\n replaceNodeAtPosition(parent, index, vnode);\n }\n\n const elapsed = now() - start;\n updateKeyedElementsMap(parent, keyedVnodes);\n\n const stats = { n: total, reused, updatedKeys, t: elapsed } as const;\n recordFastPathStats(stats, 'bulkKeyedPositionalHits');\n\n return stats;\n}\n\nfunction updateTextContent(\n el: Element,\n children: unknown,\n vnode: DOMElement\n): void {\n if (typeof children === 'string' || typeof children === 'number') {\n setTextNodeData(el, String(children));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n setTextNodeData(el, String(children[0]));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (!tryUpdateTwoChildTextPattern(el, vnode)) {\n updateElementFromVnode(el, vnode);\n }\n}\n\nfunction tryUpdateTwoChildTextPattern(\n parentEl: Element,\n vnode: DOMElement\n): boolean {\n const vnodeChildren = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(vnodeChildren) || vnodeChildren.length !== 2) return false;\n\n const firstChild = vnodeChildren[0];\n const secondChild = vnodeChildren[1];\n if (!_isDOMElement(firstChild) || !_isDOMElement(secondChild)) return false;\n if (\n typeof firstChild.type !== 'string' ||\n typeof secondChild.type !== 'string'\n ) {\n return false;\n }\n\n const firstElement = parentEl.children[0] as Element | undefined;\n const secondElement = parentEl.children[1] as Element | undefined;\n if (!firstElement || !secondElement) return false;\n if (parentEl.children.length !== 2 || parentEl.childNodes.length !== 2) {\n return false;\n }\n\n if (!tagsEqualIgnoreCase(firstElement.tagName, firstChild.type)) return false;\n if (!tagsEqualIgnoreCase(secondElement.tagName, secondChild.type))\n return false;\n\n const firstText = (firstChild.children ||\n firstChild.props?.children) as unknown;\n const secondText = (secondChild.children ||\n secondChild.props?.children) as unknown;\n\n if (typeof firstText === 'string' || typeof firstText === 'number') {\n setTextNodeData(firstElement, String(firstText));\n } else if (\n Array.isArray(firstText) &&\n firstText.length === 1 &&\n (typeof firstText[0] === 'string' || typeof firstText[0] === 'number')\n ) {\n setTextNodeData(firstElement, String(firstText[0]));\n } else {\n return false;\n }\n\n if (typeof secondText === 'string' || typeof secondText === 'number') {\n setTextNodeData(secondElement, String(secondText));\n } else if (\n Array.isArray(secondText) &&\n secondText.length === 1 &&\n (typeof secondText[0] === 'string' || typeof secondText[0] === 'number')\n ) {\n setTextNodeData(secondElement, String(secondText[0]));\n } else {\n return false;\n }\n\n return true;\n}\n\nfunction setTextNodeData(el: Element, text: string): void {\n if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {\n const textNode = el.firstChild as Text;\n if (textNode.data !== text) textNode.data = text;\n } else {\n el.textContent = text;\n }\n}\n\nfunction setDataKey(\n el: Element,\n key: string | number,\n onSet: () => void\n): void {\n try {\n const next = String(key);\n if (el.getAttribute('data-key') === next) return;\n el.setAttribute('data-key', next);\n onSet();\n } catch {\n // Ignore errors setting data-key\n }\n}\n\nfunction replaceNodeAtPosition(\n parent: Element,\n index: number,\n vnode: VNode\n): void {\n const dom = createDOMNode(vnode);\n if (dom) {\n const existing = parent.children[index];\n if (existing) {\n teardownNodeSubtree(existing);\n parent.replaceChild(dom, existing);\n } else {\n parent.appendChild(dom);\n }\n }\n}\n\nfunction updateKeyedElementsMap(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): void {\n try {\n const existing = keyedElements.get(parent);\n const newKeyMap = existing\n ? (existing.clear(), existing)\n : new Map<string | number, Element>();\n\n for (let index = 0; index < keyedVnodes.length; index += 1) {\n const key = keyedVnodes[index].key;\n const child = parent.children[index] as Element | undefined;\n if (child) newKeyMap.set(key, child);\n }\n\n keyedElements.set(parent, newKeyMap);\n } catch {\n // Ignore errors updating key map\n }\n}\n\nexport function performBulkTextReplace(parent: Element, newChildren: VNode[]) {\n const start = now();\n const existing = Array.from(parent.childNodes);\n const finalNodes: Node[] = [];\n let reused = 0;\n let created = 0;\n\n for (let index = 0; index < newChildren.length; index += 1) {\n const result = processChildNode(\n newChildren[index],\n existing[index],\n finalNodes\n );\n if (result === 'reused') reused += 1;\n else if (result === 'created') created += 1;\n }\n\n const tBuild = now() - start;\n const tCommit = commitBulkReplace(parent, finalNodes);\n\n keyedElements.delete(parent);\n\n const stats = {\n n: newChildren.length,\n reused,\n created,\n tBuild,\n tCommit,\n } as const;\n recordBulkTextStats(stats);\n\n return stats;\n}\n\nfunction processChildNode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n if (typeof vnode === 'string' || typeof vnode === 'number') {\n return processTextVnode(String(vnode), existingNode, finalNodes);\n }\n\n if (typeof vnode === 'object' && vnode !== null && 'type' in vnode) {\n return processElementVnode(vnode, existingNode, finalNodes);\n }\n\n return 'skipped';\n}\n\nfunction processTextVnode(\n text: string,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' {\n if (existingNode && existingNode.nodeType === 3) {\n (existingNode as Text).data = text;\n finalNodes.push(existingNode);\n return 'reused';\n }\n\n finalNodes.push(document.createTextNode(text));\n return 'created';\n}\n\nfunction processElementVnode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n const vnodeObj = vnode as unknown as { type?: unknown };\n\n if (typeof vnodeObj.type === 'string') {\n const tag = vnodeObj.type;\n if (\n existingNode &&\n existingNode.nodeType === 1 &&\n tagsEqualIgnoreCase((existingNode as Element).tagName, tag)\n ) {\n updateElementFromVnode(existingNode as Element, vnode);\n finalNodes.push(existingNode);\n return 'reused';\n }\n }\n\n const dom = createDOMNode(vnode);\n if (dom) {\n finalNodes.push(dom);\n return 'created';\n }\n\n return 'skipped';\n}\n\nfunction commitBulkReplace(parent: Element, nodes: Node[]): number {\n const startedAt = Date.now();\n const fragment = document.createDocumentFragment();\n\n for (let index = 0; index < nodes.length; index += 1) {\n fragment.appendChild(nodes[index]);\n }\n\n try {\n for (let node = parent.firstChild; node; ) {\n const next = node.nextSibling;\n teardownNodeSubtree(node);\n node = next;\n }\n } catch {\n // SLOW PATH: cleanup failure\n }\n\n recordDOMReplace('bulk-text-replace');\n parent.replaceChildren(fragment);\n return Date.now() - startedAt;\n}\n\nfunction recordBulkTextStats(stats: {\n n: number;\n reused: number;\n created: number;\n tBuild: number;\n tCommit: number;\n}): void {\n try {\n setDevValue('__LAST_BULK_TEXT_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 1);\n incDevCounter('bulkTextFastpathHits');\n } catch {\n // Ignore stats errors\n }\n}\n\nexport function isBulkTextFastPathEligible(\n parent: Element,\n newChildren: VNode[]\n) {\n const env = getRuntimeEnv();\n const threshold = Number(env.ASKR_BULK_TEXT_THRESHOLD) || 1024;\n const requiredFraction = 0.8;\n\n const total = Array.isArray(newChildren) ? newChildren.length : 0;\n\n if (total < threshold) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'too-small',\n total,\n threshold,\n });\n return false;\n }\n\n const result = countSimpleChildren(newChildren);\n if (result.componentFound !== undefined) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'component-child',\n index: result.componentFound,\n });\n return false;\n }\n\n const fraction = result.simple / total;\n const eligible =\n fraction >= requiredFraction && parent.childNodes.length >= total;\n\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n total,\n simple: result.simple,\n fraction,\n requiredFraction,\n eligible,\n });\n\n return eligible;\n}\n\nfunction countSimpleChildren(children: VNode[]): {\n simple: number;\n componentFound?: number;\n} {\n let simple = 0;\n\n for (let index = 0; index < children.length; index += 1) {\n const child = children[index];\n\n if (typeof child === 'string' || typeof child === 'number') {\n simple += 1;\n continue;\n }\n\n if (typeof child === 'object' && child !== null && 'type' in child) {\n const dom = child as DOMElement;\n\n if (typeof dom.type === 'function') {\n return { simple, componentFound: index };\n }\n\n if (typeof dom.type === 'string' && isSimpleElement(dom)) {\n simple += 1;\n }\n }\n }\n\n return { simple };\n}\n\nfunction isSimpleElement(dom: DOMElement): boolean {\n const children = dom.props?.children ?? dom.children;\n\n if (children === null || children === undefined) return true;\n\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction recordBulkDiag(data: Record<string, unknown>): void {\n const env = getRuntimeEnv();\n if (env.NODE_ENV !== 'production' || env.ASKR_FASTPATH_DEBUG === '1') {\n try {\n setDevValue('__BULK_DIAG', data);\n } catch {\n // Ignore\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"children.js","names":[],"sources":["../../src/renderer/children.ts"],"sourcesContent":["import { setDevValue, incDevCounter } from '../runtime/dev-namespace';\nimport { getRuntimeEnv } from './env';\nimport { keyedElements } from './keyed';\nimport { teardownNodeSubtree } from './cleanup';\nimport { createDOMNode, updateElementFromVnode } from './dom';\nimport { _isDOMElement, type DOMElement, type VNode } from './types';\nimport {\n hasNonTrivialProps,\n logFastPathDebug,\n now,\n recordDOMReplace,\n recordFastPathStats,\n tagNamesEqualIgnoreCase,\n} from './utils';\n\nfunction upperCommonTagName(tag: string): string | null {\n switch (tag) {\n case 'div':\n return 'DIV';\n case 'span':\n return 'SPAN';\n case 'p':\n return 'P';\n case 'a':\n return 'A';\n case 'button':\n return 'BUTTON';\n case 'input':\n return 'INPUT';\n case 'ul':\n return 'UL';\n case 'ol':\n return 'OL';\n case 'li':\n return 'LI';\n default:\n return null;\n }\n}\n\nfunction tagsEqualIgnoreCase(\n elementTagName: string,\n vnodeType: string\n): boolean {\n if (elementTagName === vnodeType) return true;\n\n const upperCommon = upperCommonTagName(vnodeType);\n if (upperCommon !== null && elementTagName === upperCommon) return true;\n\n return tagNamesEqualIgnoreCase(elementTagName, vnodeType);\n}\n\nexport function performBulkPositionalKeyedTextUpdate(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n) {\n const total = keyedVnodes.length;\n let reused = 0;\n let updatedKeys = 0;\n const start = now();\n const env = getRuntimeEnv();\n const debugFastPath =\n env.ASKR_FASTPATH_DEBUG === '1' || env.ASKR_FASTPATH_DEBUG === 'true';\n\n for (let index = 0; index < total; index += 1) {\n const { key, vnode } = keyedVnodes[index];\n const child = parent.children[index] as Element | undefined;\n\n if (\n child &&\n _isDOMElement(vnode) &&\n typeof (vnode as DOMElement).type === 'string'\n ) {\n const vnodeType = (vnode as DOMElement).type as string;\n\n if (tagsEqualIgnoreCase(child.tagName, vnodeType)) {\n const children =\n (vnode as DOMElement).children ||\n (vnode as DOMElement).props?.children;\n\n if (debugFastPath) {\n logFastPathDebug('positional idx', index, {\n chTag: child.tagName,\n vnodeType,\n chChildNodes: child.childNodes.length,\n childrenType: Array.isArray(children) ? 'array' : typeof children,\n });\n }\n\n updateTextContent(child, children, vnode as DOMElement);\n setDataKey(child, key, () => (updatedKeys += 1));\n reused += 1;\n continue;\n }\n\n if (debugFastPath) {\n logFastPathDebug('positional tag mismatch', index, {\n chTag: child.tagName,\n vnodeType,\n });\n }\n } else if (debugFastPath) {\n logFastPathDebug('positional missing or invalid', index, { ch: !!child });\n }\n\n replaceNodeAtPosition(parent, index, vnode);\n }\n\n const elapsed = now() - start;\n updateKeyedElementsMap(parent, keyedVnodes);\n\n const stats = { n: total, reused, updatedKeys, t: elapsed } as const;\n recordFastPathStats(stats, 'bulkKeyedPositionalHits');\n\n return stats;\n}\n\nfunction updateTextContent(\n el: Element,\n children: unknown,\n vnode: DOMElement\n): void {\n if (typeof children === 'string' || typeof children === 'number') {\n setTextNodeData(el, String(children));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n setTextNodeData(el, String(children[0]));\n if (vnode.props && hasNonTrivialProps(vnode.props)) {\n updateElementFromVnode(el, vnode, false);\n }\n return;\n }\n\n if (!tryUpdateTwoChildTextPattern(el, vnode)) {\n updateElementFromVnode(el, vnode);\n }\n}\n\nfunction tryUpdateTwoChildTextPattern(\n parentEl: Element,\n vnode: DOMElement\n): boolean {\n const vnodeChildren = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(vnodeChildren) || vnodeChildren.length !== 2) return false;\n\n const firstChild = vnodeChildren[0];\n const secondChild = vnodeChildren[1];\n if (!_isDOMElement(firstChild) || !_isDOMElement(secondChild)) return false;\n if (\n typeof firstChild.type !== 'string' ||\n typeof secondChild.type !== 'string'\n ) {\n return false;\n }\n\n const firstElement = parentEl.children[0] as Element | undefined;\n const secondElement = parentEl.children[1] as Element | undefined;\n if (!firstElement || !secondElement) return false;\n if (parentEl.children.length !== 2 || parentEl.childNodes.length !== 2) {\n return false;\n }\n\n if (!tagsEqualIgnoreCase(firstElement.tagName, firstChild.type)) return false;\n if (!tagsEqualIgnoreCase(secondElement.tagName, secondChild.type))\n return false;\n\n const firstText = (firstChild.children ||\n firstChild.props?.children) as unknown;\n const secondText = (secondChild.children ||\n secondChild.props?.children) as unknown;\n\n if (typeof firstText === 'string' || typeof firstText === 'number') {\n setTextNodeData(firstElement, String(firstText));\n } else if (\n Array.isArray(firstText) &&\n firstText.length === 1 &&\n (typeof firstText[0] === 'string' || typeof firstText[0] === 'number')\n ) {\n setTextNodeData(firstElement, String(firstText[0]));\n } else {\n return false;\n }\n\n if (typeof secondText === 'string' || typeof secondText === 'number') {\n setTextNodeData(secondElement, String(secondText));\n } else if (\n Array.isArray(secondText) &&\n secondText.length === 1 &&\n (typeof secondText[0] === 'string' || typeof secondText[0] === 'number')\n ) {\n setTextNodeData(secondElement, String(secondText[0]));\n } else {\n return false;\n }\n\n return true;\n}\n\nfunction setTextNodeData(el: Element, text: string): void {\n if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {\n const textNode = el.firstChild as Text;\n if (textNode.data !== text) textNode.data = text;\n } else {\n el.textContent = text;\n }\n}\n\nfunction setDataKey(\n el: Element,\n key: string | number,\n onSet: () => void\n): void {\n try {\n const next = String(key);\n if (el.getAttribute('data-key') === next) return;\n el.setAttribute('data-key', next);\n onSet();\n } catch {\n // Ignore errors setting data-key\n }\n}\n\nfunction replaceNodeAtPosition(\n parent: Element,\n index: number,\n vnode: VNode\n): void {\n const dom = createDOMNode(vnode);\n if (dom) {\n const existing = parent.children[index];\n if (existing) {\n teardownNodeSubtree(existing);\n parent.replaceChild(dom, existing);\n } else {\n parent.appendChild(dom);\n }\n }\n}\n\nfunction updateKeyedElementsMap(\n parent: Element,\n keyedVnodes: Array<{ key: string | number; vnode: VNode }>\n): void {\n try {\n const existing = keyedElements.get(parent);\n const newKeyMap = existing\n ? (existing.clear(), existing)\n : new Map<string | number, Element>();\n\n for (let index = 0; index < keyedVnodes.length; index += 1) {\n const key = keyedVnodes[index].key;\n const child = parent.children[index] as Element | undefined;\n if (child) newKeyMap.set(key, child);\n }\n\n keyedElements.set(parent, newKeyMap);\n } catch {\n // Ignore errors updating key map\n }\n}\n\nexport function performBulkTextReplace(parent: Element, newChildren: VNode[]) {\n const start = now();\n const existing = Array.from(parent.childNodes);\n const finalNodes: Node[] = [];\n let reused = 0;\n let created = 0;\n\n for (let index = 0; index < newChildren.length; index += 1) {\n const result = processChildNode(\n newChildren[index],\n existing[index],\n finalNodes\n );\n if (result === 'reused') reused += 1;\n else if (result === 'created') created += 1;\n }\n\n const tBuild = now() - start;\n const tCommit = commitBulkReplace(parent, finalNodes);\n\n keyedElements.delete(parent);\n\n const stats = {\n n: newChildren.length,\n reused,\n created,\n tBuild,\n tCommit,\n } as const;\n recordBulkTextStats(stats);\n\n return stats;\n}\n\nfunction processChildNode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n if (typeof vnode === 'string' || typeof vnode === 'number') {\n return processTextVnode(String(vnode), existingNode, finalNodes);\n }\n\n if (typeof vnode === 'object' && vnode !== null && 'type' in vnode) {\n return processElementVnode(vnode, existingNode, finalNodes);\n }\n\n return 'skipped';\n}\n\nfunction processTextVnode(\n text: string,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' {\n if (existingNode && existingNode.nodeType === 3) {\n (existingNode as Text).data = text;\n finalNodes.push(existingNode);\n return 'reused';\n }\n\n finalNodes.push(document.createTextNode(text));\n return 'created';\n}\n\nfunction processElementVnode(\n vnode: VNode,\n existingNode: ChildNode | undefined,\n finalNodes: Node[]\n): 'reused' | 'created' | 'skipped' {\n const vnodeObj = vnode as unknown as { type?: unknown };\n\n if (typeof vnodeObj.type === 'string') {\n const tag = vnodeObj.type;\n if (\n existingNode &&\n existingNode.nodeType === 1 &&\n tagsEqualIgnoreCase((existingNode as Element).tagName, tag)\n ) {\n updateElementFromVnode(existingNode as Element, vnode);\n finalNodes.push(existingNode);\n return 'reused';\n }\n }\n\n const dom = createDOMNode(vnode);\n if (dom) {\n finalNodes.push(dom);\n return 'created';\n }\n\n return 'skipped';\n}\n\nfunction commitBulkReplace(parent: Element, nodes: Node[]): number {\n const startedAt = Date.now();\n const fragment = document.createDocumentFragment();\n\n for (let index = 0; index < nodes.length; index += 1) {\n fragment.appendChild(nodes[index]);\n }\n\n try {\n for (let node = parent.firstChild; node; ) {\n const next = node.nextSibling;\n teardownNodeSubtree(node);\n node = next;\n }\n } catch {\n // SLOW PATH: cleanup failure\n }\n\n recordDOMReplace('bulk-text-replace');\n parent.replaceChildren(fragment);\n return Date.now() - startedAt;\n}\n\nfunction recordBulkTextStats(stats: {\n n: number;\n reused: number;\n created: number;\n tBuild: number;\n tCommit: number;\n}): void {\n try {\n setDevValue('__LAST_BULK_TEXT_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_STATS', stats);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 1);\n incDevCounter('bulkTextFastpathHits');\n } catch {\n // Ignore stats errors\n }\n}\n\nexport function isBulkTextFastPathEligible(\n parent: Element,\n newChildren: VNode[]\n) {\n const env = getRuntimeEnv();\n const threshold = Number(env.ASKR_BULK_TEXT_THRESHOLD) || 1024;\n const requiredFraction = 0.8;\n\n const total = Array.isArray(newChildren) ? newChildren.length : 0;\n\n if (total < threshold) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'too-small',\n total,\n threshold,\n });\n return false;\n }\n\n const result = countSimpleChildren(newChildren);\n if (result.componentFound !== undefined) {\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n reason: 'component-child',\n index: result.componentFound,\n });\n return false;\n }\n\n const fraction = result.simple / total;\n const eligible =\n fraction >= requiredFraction && parent.childNodes.length >= total;\n\n recordBulkDiag({\n phase: 'bulk-unkeyed-eligible',\n total,\n simple: result.simple,\n fraction,\n requiredFraction,\n eligible,\n });\n\n return eligible;\n}\n\nfunction countSimpleChildren(children: VNode[]): {\n simple: number;\n componentFound?: number;\n} {\n let simple = 0;\n\n for (let index = 0; index < children.length; index += 1) {\n const child = children[index];\n\n if (typeof child === 'string' || typeof child === 'number') {\n simple += 1;\n continue;\n }\n\n if (typeof child === 'object' && child !== null && 'type' in child) {\n const dom = child as DOMElement;\n\n if (typeof dom.type === 'function') {\n return { simple, componentFound: index };\n }\n\n if (typeof dom.type === 'string' && isSimpleElement(dom)) {\n simple += 1;\n }\n }\n }\n\n return { simple };\n}\n\nfunction isSimpleElement(dom: DOMElement): boolean {\n const children = dom.props?.children ?? dom.children;\n\n if (children === null || children === undefined) return true;\n\n if (typeof children === 'string' || typeof children === 'number') {\n return true;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n (typeof children[0] === 'string' || typeof children[0] === 'number')\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction recordBulkDiag(data: Record<string, unknown>): void {\n const env = getRuntimeEnv();\n if (env.NODE_ENV !== 'production' || env.ASKR_FASTPATH_DEBUG === '1') {\n try {\n setDevValue('__BULK_DIAG', data);\n } catch {\n // Ignore\n }\n }\n}\n"],"mappings":"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"}
@@ -4,16 +4,20 @@ import { cleanupComponent } from "../runtime/component.js";
4
4
  import { clearDelegatedHandlersForElement, removeDelegatedListener } from "../runtime/events.js";
5
5
  //#region src/renderer/cleanup.ts
6
6
  function cleanupSingleInstance(node, errors, strict) {
7
- const inst = node.__ASKR_INSTANCE;
8
- if (!inst) return;
9
- try {
10
- cleanupComponent(inst);
7
+ const instances = /* @__PURE__ */ new Set();
8
+ if (Array.isArray(node.__ASKR_INSTANCES)) {
9
+ for (const instance of node.__ASKR_INSTANCES) if (instance) instances.add(instance);
10
+ }
11
+ if (node.__ASKR_INSTANCE) instances.add(node.__ASKR_INSTANCE);
12
+ for (const instance of instances) try {
13
+ cleanupComponent(instance);
11
14
  } catch (err) {
12
15
  if (strict) errors.push(err);
13
16
  else logger.warn("[Askr] cleanupComponent failed:", err);
14
17
  }
15
18
  try {
16
19
  delete node.__ASKR_INSTANCE;
20
+ delete node.__ASKR_INSTANCES;
17
21
  } catch (e) {
18
22
  if (strict) errors.push(e);
19
23
  }
@@ -55,6 +59,27 @@ function forEachDescendantElement(root, visit) {
55
59
  const descendants = root.querySelectorAll("*");
56
60
  for (let i = 0; i < descendants.length; i++) visit(descendants[i]);
57
61
  }
62
+ function forEachDescendantNode(root, visit) {
63
+ try {
64
+ const doc = root.ownerDocument;
65
+ const createTreeWalker = doc?.createTreeWalker;
66
+ if (typeof createTreeWalker === "function") {
67
+ const walker = createTreeWalker.call(doc, root, 4294967295);
68
+ let node = walker.nextNode();
69
+ while (node) {
70
+ visit(node);
71
+ node = walker.nextNode();
72
+ }
73
+ return;
74
+ }
75
+ } catch {}
76
+ const stack = Array.from(root.childNodes).reverse();
77
+ while (stack.length > 0) {
78
+ const node = stack.pop();
79
+ visit(node);
80
+ for (let child = node.lastChild; child; child = child.previousSibling) stack.push(child);
81
+ }
82
+ }
58
83
  function forEachElementInSubtree(root, visit) {
59
84
  visit(root);
60
85
  forEachDescendantElement(root, visit);
@@ -74,10 +99,10 @@ function cleanupInstanceIfPresent(node, opts) {
74
99
  if (strict) errors.push(err);
75
100
  else logger.warn("[Askr] cleanupInstanceIfPresent failed:", err);
76
101
  }
77
- if (node instanceof Element) try {
78
- forEachDescendantElement(node, (d) => {
102
+ try {
103
+ forEachDescendantNode(node, (descendant) => {
79
104
  try {
80
- cleanupSingleInstance(d, errors, strict);
105
+ cleanupSingleInstance(descendant, errors, strict);
81
106
  } catch (err) {
82
107
  if (strict) errors.push(err);
83
108
  else logger.warn("[Askr] cleanupInstanceIfPresent descendant cleanup failed:", err);
@@ -102,8 +127,10 @@ function teardownNodeSubtree(node, opts) {
102
127
  return;
103
128
  }
104
129
  try {
105
- forEachElementInSubtree(node, (element) => {
106
- teardownSingleElement(element, errors, strict);
130
+ teardownSingleElement(node, errors, strict);
131
+ forEachDescendantNode(node, (descendant) => {
132
+ if (descendant instanceof Element) teardownSingleElement(descendant, errors, strict);
133
+ else cleanupSingleInstance(descendant, errors, strict);
107
134
  });
108
135
  } catch (err) {
109
136
  if (strict) errors.push(err);
@@ -127,11 +154,11 @@ function removeElementReactiveProps(element) {
127
154
  function removeElementListeners(element) {
128
155
  const map = elementListeners.get(element);
129
156
  if (map) {
130
- for (const [eventName, entry] of map) {
157
+ for (const entry of map.values()) {
131
158
  incDevCounter("listenerRemoves");
132
- if (entry.isDelegated) removeDelegatedListener(element, eventName);
133
- else if (entry.options !== void 0) element.removeEventListener(eventName, entry.handler, entry.options);
134
- else element.removeEventListener(eventName, entry.handler);
159
+ if (entry.isDelegated) removeDelegatedListener(element, entry.eventName);
160
+ else if (entry.options !== void 0) element.removeEventListener(entry.eventName, entry.handler, entry.options);
161
+ else element.removeEventListener(entry.eventName, entry.handler);
135
162
  }
136
163
  elementListeners.delete(element);
137
164
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cleanup.js","names":[],"sources":["../../src/renderer/cleanup.ts"],"sourcesContent":["import { cleanupComponent } from '../runtime/component';\nimport type { ComponentInstance } from '../runtime/component';\nimport { logger } from '../dev/logger';\nimport { incDevCounter } from '../runtime/dev-namespace';\nimport {\n clearDelegatedHandlersForElement,\n removeDelegatedListener,\n} from '../runtime/events';\n\ntype InstanceHost = Node & { __ASKR_INSTANCE?: unknown };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Instance Cleanup Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction cleanupSingleInstance(\n node: InstanceHost,\n errors: unknown[] | null,\n strict: boolean\n): void {\n const inst = node.__ASKR_INSTANCE;\n if (!inst) return;\n\n try {\n cleanupComponent(inst as ComponentInstance);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] cleanupComponent failed:', err);\n }\n\n try {\n delete node.__ASKR_INSTANCE;\n } catch (e) {\n if (strict) errors!.push(e);\n }\n}\n\nfunction teardownSingleElement(\n element: Element,\n errors: unknown[] | null,\n strict: boolean\n): void {\n try {\n removeElementListeners(element);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] removeElementListeners failed:', err);\n }\n\n try {\n removeElementReactiveProps(element);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] removeElementReactiveProps failed:', err);\n }\n\n try {\n cleanupSingleInstance(element as InstanceHost, errors, strict);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] cleanupSingleInstance failed:', err);\n }\n}\n\n// Walk descendant elements with minimal allocations.\n// HOT PATH: used during subtree teardown (replace/unmount).\nfunction forEachDescendantElement(root: Element, visit: (el: Element) => void) {\n // Prefer TreeWalker when available; it avoids allocating a NodeList.\n try {\n const doc = root.ownerDocument;\n const createTreeWalker = doc?.createTreeWalker;\n if (typeof createTreeWalker === 'function') {\n // NodeFilter.SHOW_ELEMENT === 1\n const walker = createTreeWalker.call(doc, root, 1);\n let n = walker.firstChild();\n while (n) {\n visit(n as Element);\n n = walker.nextNode();\n }\n return;\n }\n } catch {\n // SLOW PATH: TreeWalker unavailable\n }\n\n // Fallback: querySelectorAll\n const descendants = root.querySelectorAll('*');\n for (let i = 0; i < descendants.length; i++) {\n visit(descendants[i]);\n }\n}\n\nfunction forEachElementInSubtree(root: Element, visit: (el: Element) => void) {\n visit(root);\n forEachDescendantElement(root, visit);\n}\n\n// Track listeners so we can remove them on cleanup\nexport interface ListenerMapEntry {\n handler: EventListener;\n original: EventListener;\n options?: boolean | AddEventListenerOptions;\n isDelegated?: boolean;\n updateHandler?: (nextHandler: EventListener) => void;\n}\nexport const elementListeners = new WeakMap<\n Element,\n Map<string, ListenerMapEntry>\n>();\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Clean up component instance attached to a DOM node\n * Accepts an optional `opts.strict` flag to surface errors instead of swallowing them.\n */\nexport function cleanupInstanceIfPresent(\n node: Node | null,\n opts?: { strict?: boolean }\n): void {\n if (!node) return;\n\n const strict = opts?.strict ?? false;\n const errors: unknown[] | null = strict ? [] : null;\n\n // Clean up the node itself\n try {\n cleanupSingleInstance(node as InstanceHost, errors, strict);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] cleanupInstanceIfPresent failed:', err);\n }\n\n if (node instanceof Element) {\n // Clean up any nested instances on descendants\n try {\n forEachDescendantElement(node, (d) => {\n try {\n cleanupSingleInstance(d as InstanceHost, errors, strict);\n } catch (err) {\n if (strict) errors!.push(err);\n else\n logger.warn(\n '[Askr] cleanupInstanceIfPresent descendant cleanup failed:',\n err\n );\n }\n });\n } catch (err) {\n if (strict) errors!.push(err);\n else\n logger.warn(\n '[Askr] cleanupInstanceIfPresent descendant query failed:',\n err\n );\n }\n }\n\n if (errors && errors.length > 0) {\n throw new AggregateError(errors, 'cleanupInstanceIfPresent failed');\n }\n}\n\n// Public helper to clean up any component instances under a node. Used by\n// runtime commit logic to ensure component instances are torn down when their\n// host nodes are removed during an update.\nexport function cleanupInstancesUnder(\n node: Node | null,\n opts?: { strict?: boolean }\n): void {\n cleanupInstanceIfPresent(node, opts);\n}\n\nexport function teardownNodeSubtree(\n node: Node | null,\n opts?: { strict?: boolean }\n): void {\n if (!node) return;\n\n const strict = opts?.strict ?? false;\n const errors: unknown[] | null = strict ? [] : null;\n\n if (!(node instanceof Element)) {\n cleanupSingleInstance(node as InstanceHost, errors, strict);\n if (errors && errors.length > 0) {\n throw new AggregateError(errors, 'teardownNodeSubtree failed');\n }\n return;\n }\n\n try {\n forEachElementInSubtree(node, (element) => {\n teardownSingleElement(element, errors, strict);\n });\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] teardownNodeSubtree failed:', err);\n }\n\n if (errors && errors.length > 0) {\n throw new AggregateError(errors, 'teardownNodeSubtree failed');\n }\n}\n\n// Track reactive props cleanup functions and their function references\nexport interface ReactivePropCleanupEntry {\n cleanup: () => void;\n fnRef: unknown;\n updateFn?: (nextValue: unknown) => void;\n}\n\nexport const REACTIVE_CHILDREN_KEY = '__askr_reactive_children__';\n\nexport const elementReactivePropsCleanup = new WeakMap<\n Element,\n Map<string, ReactivePropCleanupEntry>\n>();\n\nexport function removeElementReactiveProps(element: Element): void {\n const cleanupMap = elementReactivePropsCleanup.get(element);\n if (cleanupMap) {\n for (const entry of cleanupMap.values()) {\n try {\n entry.cleanup();\n } catch (err) {\n logger.warn('[Askr] reactive prop cleanup failed:', err);\n }\n }\n elementReactivePropsCleanup.delete(element);\n }\n}\n\nexport function removeElementListeners(element: Element): void {\n const map = elementListeners.get(element);\n if (map) {\n for (const [eventName, entry] of map) {\n incDevCounter('listenerRemoves');\n if (entry.isDelegated) {\n removeDelegatedListener(element, eventName);\n } else {\n if (entry.options !== undefined)\n element.removeEventListener(eventName, entry.handler, entry.options);\n else element.removeEventListener(eventName, entry.handler);\n }\n }\n elementListeners.delete(element);\n }\n\n clearDelegatedHandlersForElement(element);\n}\n\nexport function removeAllListeners(root: Element | null): void {\n if (!root) return;\n\n forEachElementInSubtree(root, (el) => {\n removeElementListeners(el);\n removeElementReactiveProps(el);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cleanup.js","names":[],"sources":["../../src/renderer/cleanup.ts"],"sourcesContent":["import { cleanupComponent } from '../runtime/component';\nimport type { ComponentInstance } from '../runtime/component';\nimport { logger } from '../dev/logger';\nimport { incDevCounter } from '../runtime/dev-namespace';\nimport {\n clearDelegatedHandlersForElement,\n removeDelegatedListener,\n} from '../runtime/events';\n\ntype InstanceHost = Node & {\n __ASKR_INSTANCE?: unknown;\n __ASKR_INSTANCES?: unknown[];\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Instance Cleanup Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction cleanupSingleInstance(\n node: InstanceHost,\n errors: unknown[] | null,\n strict: boolean\n): void {\n const instances = new Set<ComponentInstance>();\n\n if (Array.isArray(node.__ASKR_INSTANCES)) {\n for (const instance of node.__ASKR_INSTANCES) {\n if (instance) {\n instances.add(instance as ComponentInstance);\n }\n }\n }\n\n if (node.__ASKR_INSTANCE) {\n instances.add(node.__ASKR_INSTANCE as ComponentInstance);\n }\n\n for (const instance of instances) {\n try {\n cleanupComponent(instance);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] cleanupComponent failed:', err);\n }\n }\n\n try {\n delete node.__ASKR_INSTANCE;\n delete node.__ASKR_INSTANCES;\n } catch (e) {\n if (strict) errors!.push(e);\n }\n}\n\nfunction teardownSingleElement(\n element: Element,\n errors: unknown[] | null,\n strict: boolean\n): void {\n try {\n removeElementListeners(element);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] removeElementListeners failed:', err);\n }\n\n try {\n removeElementReactiveProps(element);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] removeElementReactiveProps failed:', err);\n }\n\n try {\n cleanupSingleInstance(element as InstanceHost, errors, strict);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] cleanupSingleInstance failed:', err);\n }\n}\n\n// Walk descendant elements with minimal allocations.\n// HOT PATH: used during subtree teardown (replace/unmount).\nfunction forEachDescendantElement(root: Element, visit: (el: Element) => void) {\n // Prefer TreeWalker when available; it avoids allocating a NodeList.\n try {\n const doc = root.ownerDocument;\n const createTreeWalker = doc?.createTreeWalker;\n if (typeof createTreeWalker === 'function') {\n // NodeFilter.SHOW_ELEMENT === 1\n const walker = createTreeWalker.call(doc, root, 1);\n let n = walker.firstChild();\n while (n) {\n visit(n as Element);\n n = walker.nextNode();\n }\n return;\n }\n } catch {\n // SLOW PATH: TreeWalker unavailable\n }\n\n // Fallback: querySelectorAll\n const descendants = root.querySelectorAll('*');\n for (let i = 0; i < descendants.length; i++) {\n visit(descendants[i]);\n }\n}\n\nfunction forEachDescendantNode(root: Node, visit: (node: Node) => void) {\n try {\n const doc = root.ownerDocument;\n const createTreeWalker = doc?.createTreeWalker;\n if (typeof createTreeWalker === 'function') {\n // NodeFilter.SHOW_ALL === 0xffffffff\n const walker = createTreeWalker.call(doc, root, 0xffffffff);\n let node = walker.nextNode();\n while (node) {\n visit(node);\n node = walker.nextNode();\n }\n return;\n }\n } catch {\n // SLOW PATH: TreeWalker unavailable\n }\n\n const stack = Array.from(root.childNodes).reverse();\n while (stack.length > 0) {\n const node = stack.pop()!;\n visit(node);\n for (let child = node.lastChild; child; child = child.previousSibling) {\n stack.push(child);\n }\n }\n}\n\nfunction forEachElementInSubtree(root: Element, visit: (el: Element) => void) {\n visit(root);\n forEachDescendantElement(root, visit);\n}\n\n// Track listeners so we can remove them on cleanup\nexport interface ListenerMapEntry {\n handler: EventListener;\n original: EventListener;\n eventName: string;\n options?: boolean | AddEventListenerOptions;\n isDelegated?: boolean;\n updateHandler?: (nextHandler: EventListener) => void;\n}\nexport const elementListeners = new WeakMap<\n Element,\n Map<string, ListenerMapEntry>\n>();\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Clean up component instance attached to a DOM node\n * Accepts an optional `opts.strict` flag to surface errors instead of swallowing them.\n */\nexport function cleanupInstanceIfPresent(\n node: Node | null,\n opts?: { strict?: boolean }\n): void {\n if (!node) return;\n\n const strict = opts?.strict ?? false;\n const errors: unknown[] | null = strict ? [] : null;\n\n // Clean up the node itself\n try {\n cleanupSingleInstance(node as InstanceHost, errors, strict);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] cleanupInstanceIfPresent failed:', err);\n }\n\n // Clean up any nested instances, including null-component comment hosts.\n try {\n forEachDescendantNode(node, (descendant) => {\n try {\n cleanupSingleInstance(descendant as InstanceHost, errors, strict);\n } catch (err) {\n if (strict) errors!.push(err);\n else\n logger.warn(\n '[Askr] cleanupInstanceIfPresent descendant cleanup failed:',\n err\n );\n }\n });\n } catch (err) {\n if (strict) errors!.push(err);\n else\n logger.warn(\n '[Askr] cleanupInstanceIfPresent descendant query failed:',\n err\n );\n }\n\n if (errors && errors.length > 0) {\n throw new AggregateError(errors, 'cleanupInstanceIfPresent failed');\n }\n}\n\n// Public helper to clean up any component instances under a node. Used by\n// runtime commit logic to ensure component instances are torn down when their\n// host nodes are removed during an update.\nexport function cleanupInstancesUnder(\n node: Node | null,\n opts?: { strict?: boolean }\n): void {\n cleanupInstanceIfPresent(node, opts);\n}\n\nexport function teardownNodeSubtree(\n node: Node | null,\n opts?: { strict?: boolean }\n): void {\n if (!node) return;\n\n const strict = opts?.strict ?? false;\n const errors: unknown[] | null = strict ? [] : null;\n\n if (!(node instanceof Element)) {\n cleanupSingleInstance(node as InstanceHost, errors, strict);\n if (errors && errors.length > 0) {\n throw new AggregateError(errors, 'teardownNodeSubtree failed');\n }\n return;\n }\n\n try {\n teardownSingleElement(node, errors, strict);\n forEachDescendantNode(node, (descendant) => {\n if (descendant instanceof Element) {\n teardownSingleElement(descendant, errors, strict);\n } else {\n cleanupSingleInstance(descendant as InstanceHost, errors, strict);\n }\n });\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] teardownNodeSubtree failed:', err);\n }\n\n if (errors && errors.length > 0) {\n throw new AggregateError(errors, 'teardownNodeSubtree failed');\n }\n}\n\n// Track reactive props cleanup functions and their function references\nexport interface ReactivePropCleanupEntry {\n cleanup: () => void;\n fnRef: unknown;\n updateFn?: (nextValue: unknown) => void;\n}\n\nexport const REACTIVE_CHILDREN_KEY = '__askr_reactive_children__';\n\nexport const elementReactivePropsCleanup = new WeakMap<\n Element,\n Map<string, ReactivePropCleanupEntry>\n>();\n\nexport function removeElementReactiveProps(element: Element): void {\n const cleanupMap = elementReactivePropsCleanup.get(element);\n if (cleanupMap) {\n for (const entry of cleanupMap.values()) {\n try {\n entry.cleanup();\n } catch (err) {\n logger.warn('[Askr] reactive prop cleanup failed:', err);\n }\n }\n elementReactivePropsCleanup.delete(element);\n }\n}\n\nexport function removeElementListeners(element: Element): void {\n const map = elementListeners.get(element);\n if (map) {\n for (const entry of map.values()) {\n incDevCounter('listenerRemoves');\n if (entry.isDelegated) {\n removeDelegatedListener(element, entry.eventName);\n } else {\n if (entry.options !== undefined)\n element.removeEventListener(\n entry.eventName,\n entry.handler,\n entry.options\n );\n else element.removeEventListener(entry.eventName, entry.handler);\n }\n }\n elementListeners.delete(element);\n }\n\n clearDelegatedHandlersForElement(element);\n}\n\nexport function removeAllListeners(root: Element | null): void {\n if (!root) return;\n\n forEachElementInSubtree(root, (el) => {\n removeElementListeners(el);\n removeElementReactiveProps(el);\n });\n}\n"],"mappings":"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"}