@askrjs/askr 0.0.48 → 0.0.50

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 (401) hide show
  1. package/dist/benchmark.js +6 -6
  2. package/dist/benchmark.js.map +1 -1
  3. package/dist/boot/hydration.js +140 -0
  4. package/dist/boot/hydration.js.map +1 -0
  5. package/dist/boot/index.d.ts +3 -56
  6. package/dist/boot/index.d.ts.map +1 -1
  7. package/dist/boot/index.js +62 -410
  8. package/dist/boot/index.js.map +1 -1
  9. package/dist/boot/root-lifecycle.d.ts +15 -0
  10. package/dist/boot/root-lifecycle.d.ts.map +1 -0
  11. package/dist/boot/root-lifecycle.js +205 -0
  12. package/dist/boot/root-lifecycle.js.map +1 -0
  13. package/dist/boot/route-startup.js +45 -0
  14. package/dist/boot/route-startup.js.map +1 -0
  15. package/dist/boot/types.d.ts +62 -0
  16. package/dist/boot/types.d.ts.map +1 -0
  17. package/dist/common/component.d.ts +3 -1
  18. package/dist/common/component.d.ts.map +1 -1
  19. package/dist/common/jsx.d.ts +6 -2
  20. package/dist/common/jsx.d.ts.map +1 -1
  21. package/dist/common/jsx.js.map +1 -1
  22. package/dist/common/props.d.ts +1 -1
  23. package/dist/common/render-context.js +55 -0
  24. package/dist/common/render-context.js.map +1 -0
  25. package/dist/common/router.d.ts +5 -1
  26. package/dist/common/router.d.ts.map +1 -1
  27. package/dist/common/ssr.d.ts +1 -1
  28. package/dist/common/ssr.js.map +1 -1
  29. package/dist/common/vnode.d.ts +5 -4
  30. package/dist/common/vnode.d.ts.map +1 -1
  31. package/dist/common/vnode.js.map +1 -1
  32. package/dist/components/error-boundary.d.ts +1 -1
  33. package/dist/components/error-boundary.js +2 -1
  34. package/dist/components/error-boundary.js.map +1 -1
  35. package/dist/components/link.js.map +1 -1
  36. package/dist/control/for.js +2 -1
  37. package/dist/control/for.js.map +1 -1
  38. package/dist/data/data-runtime.d.ts +28 -0
  39. package/dist/data/data-runtime.d.ts.map +1 -0
  40. package/dist/data/data-runtime.js +114 -0
  41. package/dist/data/data-runtime.js.map +1 -0
  42. package/dist/data/index.d.ts +6 -142
  43. package/dist/data/index.js +5 -539
  44. package/dist/data/invalidation.d.ts +9 -0
  45. package/dist/data/invalidation.d.ts.map +1 -0
  46. package/dist/data/invalidation.js +27 -0
  47. package/dist/data/invalidation.js.map +1 -0
  48. package/dist/data/mutation-cell.d.ts +28 -0
  49. package/dist/data/mutation-cell.d.ts.map +1 -0
  50. package/dist/data/mutation-cell.js +132 -0
  51. package/dist/data/mutation-cell.js.map +1 -0
  52. package/dist/data/query-cell.d.ts +46 -0
  53. package/dist/data/query-cell.d.ts.map +1 -0
  54. package/dist/data/query-cell.js +290 -0
  55. package/dist/data/query-cell.js.map +1 -0
  56. package/dist/data/query-key.js +42 -0
  57. package/dist/data/query-key.js.map +1 -0
  58. package/dist/data/shared.js +20 -0
  59. package/dist/data/shared.js.map +1 -0
  60. package/dist/data/types.d.ts +161 -0
  61. package/dist/data/types.d.ts.map +1 -0
  62. package/dist/foundations/icon/icon.d.ts.map +1 -1
  63. package/dist/foundations/icon/icon.js.map +1 -1
  64. package/dist/foundations/structures/portal.d.ts +1 -1
  65. package/dist/foundations/structures/portal.d.ts.map +1 -1
  66. package/dist/foundations/structures/portal.js +2 -1
  67. package/dist/foundations/structures/portal.js.map +1 -1
  68. package/dist/fx/fx.d.ts +1 -1
  69. package/dist/fx/fx.js +5 -4
  70. package/dist/fx/fx.js.map +1 -1
  71. package/dist/fx/timing.d.ts.map +1 -1
  72. package/dist/fx/timing.js +10 -6
  73. package/dist/fx/timing.js.map +1 -1
  74. package/dist/index.d.ts +3 -2
  75. package/dist/index.js +4 -2
  76. package/dist/index.js.map +1 -1
  77. package/dist/jsx/index.d.ts +2 -1
  78. package/dist/jsx/index.js +3 -2
  79. package/dist/jsx/types.d.ts +3 -1
  80. package/dist/jsx/types.d.ts.map +1 -1
  81. package/dist/jsx/types.js +2 -1
  82. package/dist/jsx-dev-runtime.d.ts +2 -2
  83. package/dist/jsx-dev-runtime.d.ts.map +1 -1
  84. package/dist/jsx-dev-runtime.js.map +1 -1
  85. package/dist/jsx-runtime.d.ts +2 -2
  86. package/dist/jsx-runtime.d.ts.map +1 -1
  87. package/dist/jsx-runtime.js.map +1 -1
  88. package/dist/jsx-runtime2.d.ts +3 -2
  89. package/dist/jsx-runtime2.js +3 -2
  90. package/dist/renderer/attributes.js +231 -0
  91. package/dist/renderer/attributes.js.map +1 -0
  92. package/dist/renderer/boundaries.js +266 -0
  93. package/dist/renderer/boundaries.js.map +1 -0
  94. package/dist/renderer/child-shape.js +85 -0
  95. package/dist/renderer/child-shape.js.map +1 -0
  96. package/dist/renderer/children.js +3 -2
  97. package/dist/renderer/children.js.map +1 -1
  98. package/dist/renderer/cleanup.js +2 -1
  99. package/dist/renderer/cleanup.js.map +1 -1
  100. package/dist/renderer/component-host-cleanup.js +68 -0
  101. package/dist/renderer/component-host-cleanup.js.map +1 -0
  102. package/dist/renderer/component-host-instances.js +65 -0
  103. package/dist/renderer/component-host-instances.js.map +1 -0
  104. package/dist/renderer/component-host.js +247 -0
  105. package/dist/renderer/component-host.js.map +1 -0
  106. package/dist/renderer/dom-host.js +13 -0
  107. package/dist/renderer/dom-host.js.map +1 -0
  108. package/dist/renderer/dom-internal.js +185 -0
  109. package/dist/renderer/dom-internal.js.map +1 -0
  110. package/dist/renderer/dom.js +9 -2356
  111. package/dist/renderer/element-children.js +279 -0
  112. package/dist/renderer/element-children.js.map +1 -0
  113. package/dist/renderer/env.js +2 -1
  114. package/dist/renderer/error-boundary-dom.js +29 -0
  115. package/dist/renderer/error-boundary-dom.js.map +1 -0
  116. package/dist/renderer/evaluate-dom-range.js +85 -0
  117. package/dist/renderer/evaluate-dom-range.js.map +1 -0
  118. package/dist/renderer/evaluate-reconcile.js +281 -0
  119. package/dist/renderer/evaluate-reconcile.js.map +1 -0
  120. package/dist/renderer/evaluate.js +13 -399
  121. package/dist/renderer/evaluate.js.map +1 -1
  122. package/dist/renderer/fastpath.js +6 -5
  123. package/dist/renderer/fastpath.js.map +1 -1
  124. package/dist/renderer/for-commit-dom-map.js +83 -0
  125. package/dist/renderer/for-commit-dom-map.js.map +1 -0
  126. package/dist/renderer/for-commit-removal.js +36 -0
  127. package/dist/renderer/for-commit-removal.js.map +1 -0
  128. package/dist/renderer/for-commit-reorder.js +89 -0
  129. package/dist/renderer/for-commit-reorder.js.map +1 -0
  130. package/dist/renderer/for-commit.js +6 -188
  131. package/dist/renderer/for-commit.js.map +1 -1
  132. package/dist/renderer/index.js +28 -16
  133. package/dist/renderer/index.js.map +1 -1
  134. package/dist/renderer/keyed-children.js +32 -0
  135. package/dist/renderer/keyed-children.js.map +1 -0
  136. package/dist/renderer/keyed.js +2 -15
  137. package/dist/renderer/keyed.js.map +1 -1
  138. package/dist/renderer/namespaces.js +23 -0
  139. package/dist/renderer/namespaces.js.map +1 -0
  140. package/dist/renderer/prop-bindings.js +280 -0
  141. package/dist/renderer/prop-bindings.js.map +1 -0
  142. package/dist/renderer/reactive-child-dom.js +133 -0
  143. package/dist/renderer/reactive-child-dom.js.map +1 -0
  144. package/dist/renderer/reactive-child-sources.js +184 -0
  145. package/dist/renderer/reactive-child-sources.js.map +1 -0
  146. package/dist/renderer/reactive-children.js +294 -0
  147. package/dist/renderer/reactive-children.js.map +1 -0
  148. package/dist/renderer/reconcile-commit.js +38 -0
  149. package/dist/renderer/reconcile-commit.js.map +1 -0
  150. package/dist/renderer/reconcile-fastpaths.js +106 -0
  151. package/dist/renderer/reconcile-fastpaths.js.map +1 -0
  152. package/dist/renderer/reconcile-resolution.js +187 -0
  153. package/dist/renderer/reconcile-resolution.js.map +1 -0
  154. package/dist/renderer/reconcile.js +9 -371
  155. package/dist/renderer/reconcile.js.map +1 -1
  156. package/dist/renderer/retained-element-rollback.js +276 -0
  157. package/dist/renderer/retained-element-rollback.js.map +1 -0
  158. package/dist/renderer/stable-patch.js +82 -0
  159. package/dist/renderer/stable-patch.js.map +1 -0
  160. package/dist/renderer/static-reuse.js +96 -0
  161. package/dist/renderer/static-reuse.js.map +1 -0
  162. package/dist/renderer/types.js +2 -1
  163. package/dist/renderer/utils.js +4 -4
  164. package/dist/renderer/utils.js.map +1 -1
  165. package/dist/resources/index.d.ts +3 -2
  166. package/dist/resources/index.js +5 -2
  167. package/dist/router/access.js +36 -0
  168. package/dist/router/access.js.map +1 -0
  169. package/dist/router/activity.d.ts +10 -0
  170. package/dist/router/activity.d.ts.map +1 -0
  171. package/dist/router/activity.js +89 -0
  172. package/dist/router/activity.js.map +1 -0
  173. package/dist/router/authoring.d.ts +22 -0
  174. package/dist/router/authoring.d.ts.map +1 -0
  175. package/dist/router/authoring.js +198 -0
  176. package/dist/router/authoring.js.map +1 -0
  177. package/dist/router/index.d.ts +12 -4
  178. package/dist/router/index.js +10 -3
  179. package/dist/router/internal-types.d.ts +31 -0
  180. package/dist/router/internal-types.d.ts.map +1 -0
  181. package/dist/router/lazy.d.ts +19 -0
  182. package/dist/router/lazy.d.ts.map +1 -0
  183. package/dist/router/lazy.js +52 -0
  184. package/dist/router/lazy.js.map +1 -0
  185. package/dist/router/manifest.d.ts +10 -0
  186. package/dist/router/manifest.d.ts.map +1 -0
  187. package/dist/router/manifest.js +49 -0
  188. package/dist/router/manifest.js.map +1 -0
  189. package/dist/router/navigate.d.ts +4 -51
  190. package/dist/router/navigate.d.ts.map +1 -1
  191. package/dist/router/navigate.js +16 -459
  192. package/dist/router/navigate.js.map +1 -1
  193. package/dist/router/navigation-registry.d.ts +32 -0
  194. package/dist/router/navigation-registry.d.ts.map +1 -0
  195. package/dist/router/navigation-registry.js +105 -0
  196. package/dist/router/navigation-registry.js.map +1 -0
  197. package/dist/router/navigation-scroll.d.ts +14 -0
  198. package/dist/router/navigation-scroll.d.ts.map +1 -0
  199. package/dist/router/navigation-scroll.js +93 -0
  200. package/dist/router/navigation-scroll.js.map +1 -0
  201. package/dist/router/navigation-targets.d.ts +31 -0
  202. package/dist/router/navigation-targets.d.ts.map +1 -0
  203. package/dist/router/navigation-targets.js +253 -0
  204. package/dist/router/navigation-targets.js.map +1 -0
  205. package/dist/router/policy.d.ts +7 -1
  206. package/dist/router/policy.d.ts.map +1 -1
  207. package/dist/router/policy.js +27 -9
  208. package/dist/router/policy.js.map +1 -1
  209. package/dist/router/rendering.d.ts +10 -0
  210. package/dist/router/rendering.d.ts.map +1 -0
  211. package/dist/router/rendering.js +45 -0
  212. package/dist/router/rendering.js.map +1 -0
  213. package/dist/router/resolution.d.ts +17 -0
  214. package/dist/router/resolution.d.ts.map +1 -0
  215. package/dist/router/resolution.js +253 -0
  216. package/dist/router/resolution.js.map +1 -0
  217. package/dist/router/route-query.d.ts +17 -0
  218. package/dist/router/route-query.d.ts.map +1 -0
  219. package/dist/router/route-query.js +47 -0
  220. package/dist/router/route-query.js.map +1 -0
  221. package/dist/router/route.d.ts +8 -149
  222. package/dist/router/route.js +8 -854
  223. package/dist/router/store.d.ts +50 -0
  224. package/dist/router/store.d.ts.map +1 -0
  225. package/dist/router/store.js +171 -0
  226. package/dist/router/store.js.map +1 -0
  227. package/dist/runtime/access.js +45 -0
  228. package/dist/runtime/access.js.map +1 -0
  229. package/dist/runtime/child-scope.d.ts +1 -1
  230. package/dist/runtime/child-scope.js +4 -1
  231. package/dist/runtime/child-scope.js.map +1 -1
  232. package/dist/runtime/component-cleanup.d.ts +16 -0
  233. package/dist/runtime/component-cleanup.d.ts.map +1 -0
  234. package/dist/runtime/component-cleanup.js +70 -0
  235. package/dist/runtime/component-cleanup.js.map +1 -0
  236. package/dist/runtime/component-commit.js +165 -0
  237. package/dist/runtime/component-commit.js.map +1 -0
  238. package/dist/runtime/component-contracts.js +5 -0
  239. package/dist/runtime/component-facade.d.ts +5 -0
  240. package/dist/runtime/component-facade.js +4 -0
  241. package/dist/runtime/component-internal.d.ts +100 -0
  242. package/dist/runtime/component-internal.d.ts.map +1 -0
  243. package/dist/runtime/component-internal.js +219 -0
  244. package/dist/runtime/component-internal.js.map +1 -0
  245. package/dist/runtime/component-lifecycle.d.ts +49 -0
  246. package/dist/runtime/component-lifecycle.d.ts.map +1 -0
  247. package/dist/runtime/component-lifecycle.js +176 -0
  248. package/dist/runtime/component-lifecycle.js.map +1 -0
  249. package/dist/runtime/component-scope.d.ts +55 -0
  250. package/dist/runtime/component-scope.d.ts.map +1 -0
  251. package/dist/runtime/component-scope.js +154 -0
  252. package/dist/runtime/component-scope.js.map +1 -0
  253. package/dist/runtime/component.d.ts +4 -152
  254. package/dist/runtime/component.js +4 -692
  255. package/dist/runtime/context.d.ts +1 -1
  256. package/dist/runtime/context.js +6 -4
  257. package/dist/runtime/context.js.map +1 -1
  258. package/dist/runtime/control.d.ts +3 -3
  259. package/dist/runtime/control.js +2 -1
  260. package/dist/runtime/control.js.map +1 -1
  261. package/dist/runtime/derive.d.ts.map +1 -1
  262. package/dist/runtime/derive.js +6 -5
  263. package/dist/runtime/derive.js.map +1 -1
  264. package/dist/runtime/effect.d.ts +1 -1
  265. package/dist/runtime/effect.d.ts.map +1 -1
  266. package/dist/runtime/effect.js +2 -2
  267. package/dist/runtime/effect.js.map +1 -1
  268. package/dist/runtime/events.js +3 -3
  269. package/dist/runtime/events.js.map +1 -1
  270. package/dist/runtime/fastlane.js +13 -27
  271. package/dist/runtime/fastlane.js.map +1 -1
  272. package/dist/runtime/for-bench.d.ts +1 -1
  273. package/dist/runtime/for-bench.js +1 -4
  274. package/dist/runtime/for-bench.js.map +1 -1
  275. package/dist/runtime/for-internal.d.ts +43 -0
  276. package/dist/runtime/for-internal.d.ts.map +1 -0
  277. package/dist/runtime/for-internal.js +98 -0
  278. package/dist/runtime/for-internal.js.map +1 -0
  279. package/dist/runtime/for-reconcile.d.ts +8 -0
  280. package/dist/runtime/for-reconcile.d.ts.map +1 -0
  281. package/dist/runtime/for-reconcile.js +389 -0
  282. package/dist/runtime/for-reconcile.js.map +1 -0
  283. package/dist/runtime/for-scopes.d.ts +26 -0
  284. package/dist/runtime/for-scopes.d.ts.map +1 -0
  285. package/dist/runtime/for-scopes.js +160 -0
  286. package/dist/runtime/for-scopes.js.map +1 -0
  287. package/dist/runtime/for-signals.d.ts +30 -0
  288. package/dist/runtime/for-signals.d.ts.map +1 -0
  289. package/dist/runtime/for-signals.js +139 -0
  290. package/dist/runtime/for-signals.js.map +1 -0
  291. package/dist/runtime/for.d.ts +4 -66
  292. package/dist/runtime/for.js +5 -773
  293. package/dist/runtime/lifecycle-operations.d.ts +31 -0
  294. package/dist/runtime/lifecycle-operations.d.ts.map +1 -0
  295. package/dist/runtime/lifecycle-operations.js +195 -0
  296. package/dist/runtime/lifecycle-operations.js.map +1 -0
  297. package/dist/runtime/operations.d.ts +3 -40
  298. package/dist/runtime/operations.js +2 -357
  299. package/dist/runtime/readable.d.ts +2 -3
  300. package/dist/runtime/readable.d.ts.map +1 -1
  301. package/dist/runtime/readable.js +6 -5
  302. package/dist/runtime/readable.js.map +1 -1
  303. package/dist/runtime/resource-cell.js +2 -2
  304. package/dist/runtime/resource-cell.js.map +1 -1
  305. package/dist/runtime/resource-operation.d.ts +13 -0
  306. package/dist/runtime/resource-operation.d.ts.map +1 -0
  307. package/dist/runtime/resource-operation.js +170 -0
  308. package/dist/runtime/resource-operation.js.map +1 -0
  309. package/dist/runtime/runtime.d.ts +42 -0
  310. package/dist/runtime/runtime.d.ts.map +1 -0
  311. package/dist/runtime/runtime.js +59 -0
  312. package/dist/runtime/runtime.js.map +1 -0
  313. package/dist/runtime/scheduler.d.ts +5 -1
  314. package/dist/runtime/scheduler.d.ts.map +1 -1
  315. package/dist/runtime/scheduler.js +17 -17
  316. package/dist/runtime/scheduler.js.map +1 -1
  317. package/dist/runtime/selector.js +4 -3
  318. package/dist/runtime/selector.js.map +1 -1
  319. package/dist/runtime/snapshot-source.d.ts +1 -1
  320. package/dist/runtime/snapshot-source.js +1 -1
  321. package/dist/runtime/state.js +2 -1
  322. package/dist/runtime/state.js.map +1 -1
  323. package/dist/ssg/batch-render.js +2 -1
  324. package/dist/ssg/batch-render.js.map +1 -1
  325. package/dist/ssg/create-static-gen.d.ts +9 -3
  326. package/dist/ssg/create-static-gen.d.ts.map +1 -1
  327. package/dist/ssg/create-static-gen.js +12 -99
  328. package/dist/ssg/create-static-gen.js.map +1 -1
  329. package/dist/ssg/generation-plan.js +70 -0
  330. package/dist/ssg/generation-plan.js.map +1 -0
  331. package/dist/ssg/incremental-manifest.js +1 -1
  332. package/dist/ssg/static-routes.js +101 -0
  333. package/dist/ssg/static-routes.js.map +1 -0
  334. package/dist/ssg/types.d.ts +15 -7
  335. package/dist/ssg/types.d.ts.map +1 -1
  336. package/dist/ssr/boundaries.js +113 -0
  337. package/dist/ssr/boundaries.js.map +1 -0
  338. package/dist/ssr/component-runtime.js +111 -0
  339. package/dist/ssr/component-runtime.js.map +1 -0
  340. package/dist/ssr/context.d.ts +3 -1
  341. package/dist/ssr/context.d.ts.map +1 -1
  342. package/dist/ssr/context.js +9 -2
  343. package/dist/ssr/context.js.map +1 -1
  344. package/dist/ssr/errors.d.ts +2 -0
  345. package/dist/ssr/errors.js +11 -1
  346. package/dist/ssr/errors.js.map +1 -1
  347. package/dist/ssr/escape.js +3 -3
  348. package/dist/ssr/escape.js.map +1 -1
  349. package/dist/ssr/hydration-data.js +10 -0
  350. package/dist/ssr/hydration-data.js.map +1 -0
  351. package/dist/ssr/hydration-verify.d.ts +12 -0
  352. package/dist/ssr/hydration-verify.d.ts.map +1 -0
  353. package/dist/ssr/hydration-verify.js +144 -0
  354. package/dist/ssr/hydration-verify.js.map +1 -0
  355. package/dist/ssr/index-internal.d.ts +15 -0
  356. package/dist/ssr/index-internal.d.ts.map +1 -0
  357. package/dist/ssr/index-internal.js +19 -0
  358. package/dist/ssr/index-internal.js.map +1 -0
  359. package/dist/ssr/index.d.ts +5 -57
  360. package/dist/ssr/index.js +3 -738
  361. package/dist/ssr/render-keys.js +9 -32
  362. package/dist/ssr/render-keys.js.map +1 -1
  363. package/dist/ssr/render-resolved.d.ts +1 -1
  364. package/dist/ssr/render-resolved.d.ts.map +1 -1
  365. package/dist/ssr/render-resolved.js +4 -2
  366. package/dist/ssr/render-resolved.js.map +1 -1
  367. package/dist/ssr/render-sync.d.ts +21 -0
  368. package/dist/ssr/render-sync.d.ts.map +1 -0
  369. package/dist/ssr/render-sync.js +275 -0
  370. package/dist/ssr/render-sync.js.map +1 -0
  371. package/dist/ssr/route-policy-resolution.js +77 -0
  372. package/dist/ssr/route-policy-resolution.js.map +1 -0
  373. package/dist/ssr/route-render.d.ts +77 -0
  374. package/dist/ssr/route-render.d.ts.map +1 -0
  375. package/dist/ssr/route-render.js +119 -0
  376. package/dist/ssr/route-render.js.map +1 -0
  377. package/dist/ssr/sink.d.ts +26 -0
  378. package/dist/ssr/sink.d.ts.map +1 -0
  379. package/dist/ssr/types.d.ts +1 -0
  380. package/dist/ssr/types.d.ts.map +1 -1
  381. package/dist/ssr/verify-hydration.js.map +1 -1
  382. package/dist/testing/index.d.ts +1 -2
  383. package/dist/testing/index.d.ts.map +1 -1
  384. package/dist/testing/index.js +2 -1
  385. package/dist/testing/index.js.map +1 -1
  386. package/package.json +4 -3
  387. package/dist/data/index.d.ts.map +0 -1
  388. package/dist/data/index.js.map +0 -1
  389. package/dist/renderer/dom.js.map +0 -1
  390. package/dist/router/route.d.ts.map +0 -1
  391. package/dist/router/route.js.map +0 -1
  392. package/dist/runtime/component.d.ts.map +0 -1
  393. package/dist/runtime/component.js.map +0 -1
  394. package/dist/runtime/for.d.ts.map +0 -1
  395. package/dist/runtime/for.js.map +0 -1
  396. package/dist/runtime/operations.d.ts.map +0 -1
  397. package/dist/runtime/operations.js.map +0 -1
  398. package/dist/runtime/ssr-bridge.js +0 -24
  399. package/dist/runtime/ssr-bridge.js.map +0 -1
  400. package/dist/ssr/index.d.ts.map +0 -1
  401. package/dist/ssr/index.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boundaries.js","names":[],"sources":["../../src/renderer/boundaries.ts"],"sourcesContent":["import { __FOR_BOUNDARY__ } from '../common/vnode';\nimport { logger } from '../dev/logger';\nimport { enqueueRuntimeTask } from '../runtime/access';\nimport type { ChildScope } from '../runtime/child-scope';\nimport type {\n ComponentFunction,\n ComponentInstance,\n} from '../runtime/component-contracts';\nimport {\n clearCaseDomUpdateState,\n clearShowDomUpdateState,\n evaluateCaseState,\n evaluateShowState,\n type ControlBoundaryState,\n} from '../runtime/control';\nimport {\n clearForDomUpdateState,\n evaluateForState,\n recordBenchEvent,\n} from '../runtime/for';\nimport { teardownNodeSubtree } from './cleanup';\nimport { getRuntimeEnv } from './env';\nimport { commitForStateBoundaryChildren } from './for-commit';\nimport { keyedElements } from './keyed';\nimport { getParentNamespace } from './namespaces';\nimport { _isDOMElement, type DOMElement, type VNode } from './types';\nimport { tagNamesEqualIgnoreCase } from './utils';\n\ntype ElementWithContext = DOMElement & {\n __instance?: ComponentInstance;\n};\n\ntype BoundaryCommitOwnerState = ControlBoundaryState & {\n _commitOwner?: Element | null;\n};\n\nexport interface BoundaryDOMHost {\n createDOMNode(vnode: unknown, parentNamespace?: string): Node | null;\n syncComponentElement(\n currentDom: Node | null,\n node: ElementWithContext,\n type: ComponentFunction,\n props: Record<string, unknown>,\n parentNamespace?: string,\n forceChildrenUpdate?: boolean,\n retainedHostInstances?: Iterable<ComponentInstance>\n ): Node | null;\n updateElementFromVnode(\n el: Element,\n vnode: VNode,\n updateChildren?: boolean,\n forceChildrenUpdate?: boolean\n ): void;\n tryPatchStableForDirtyItem(scope: { dom?: Node; vnode?: VNode }): boolean;\n}\n\nlet boundaryDOMHost: BoundaryDOMHost | null = null;\nconst controlBoundaryOwners = new WeakMap<Element, ControlBoundaryState>();\n\nexport function configureBoundaryDOMHost(host: BoundaryDOMHost): void {\n boundaryDOMHost = host;\n}\n\nfunction getBoundaryDOMHost(): BoundaryDOMHost {\n if (!boundaryDOMHost) {\n throw new Error('[askr] Control boundary DOM host is not configured.');\n }\n return boundaryDOMHost;\n}\n\nfunction checkVNodeShapeChanged(dom: Node, vnode: VNode): boolean {\n if (!_isDOMElement(vnode)) return true;\n if (!(dom instanceof Element)) return true;\n const vnodeType = (vnode as DOMElement).type;\n if (typeof vnodeType !== 'string') return true;\n return dom.tagName.toLowerCase() !== vnodeType.toLowerCase();\n}\n\nfunction materializeChildScopeDom(\n vnode: VNode,\n parentNamespace?: string\n): Node | null {\n if (vnode === null || vnode === undefined || vnode === false) {\n return document.createComment('');\n }\n\n const dom = getBoundaryDOMHost().createDOMNode(vnode, parentNamespace);\n if (!(dom instanceof DocumentFragment)) {\n return dom;\n }\n\n const firstChild = dom.firstChild;\n const secondChild = firstChild?.nextSibling ?? null;\n if (!firstChild) {\n return document.createComment('');\n }\n if (secondChild) {\n throw new Error('[askr] Child scopes must render a single DOM root node.');\n }\n return firstChild;\n}\n\nexport function evaluateControlBoundaryState(\n controlState: ControlBoundaryState\n): VNode[] {\n if (controlState.kind === 'for') {\n return evaluateForState(controlState);\n }\n if (controlState.kind === 'show') {\n return evaluateShowState(controlState);\n }\n return evaluateCaseState(controlState);\n}\n\nfunction clearControlBoundaryDomUpdateState(\n controlState: ControlBoundaryState\n): void {\n if (controlState.kind === 'for') {\n clearForDomUpdateState(controlState);\n return;\n }\n if (controlState.kind === 'show') {\n clearShowDomUpdateState(controlState);\n return;\n }\n clearCaseDomUpdateState(controlState);\n}\n\nexport function getControlBoundaryState(\n node: DOMElement\n): ControlBoundaryState | null {\n return (\n node._controlState ??\n (node._forState as ControlBoundaryState | undefined) ??\n null\n );\n}\n\nexport function getDirectControlBoundaryVNode(\n children: unknown\n): DOMElement | null {\n if (\n !Array.isArray(children) &&\n _isDOMElement(children) &&\n (children as DOMElement).type === __FOR_BOUNDARY__\n ) {\n return children as DOMElement;\n }\n\n if (\n Array.isArray(children) &&\n children.length === 1 &&\n _isDOMElement(children[0]) &&\n (children[0] as DOMElement).type === __FOR_BOUNDARY__\n ) {\n return children[0] as DOMElement;\n }\n\n return null;\n}\n\nfunction getControlBoundaryCommitChildren(\n controlState: ControlBoundaryState\n): VNode[] {\n if (controlState.kind === 'for' && controlState._needsSourceReconcile) {\n return evaluateForState(controlState);\n }\n\n if (controlState.kind !== 'for') {\n const activeVNode = controlState.activeScope?.vnode;\n return activeVNode == null || activeVNode === false ? [] : [activeVNode];\n }\n\n if (controlState.orderedKeys.length === 0) {\n const fallbackVNode = controlState.fallbackScope?.vnode;\n return fallbackVNode == null || fallbackVNode === false\n ? []\n : [fallbackVNode];\n }\n\n const childrenVNodes: VNode[] = [];\n for (let index = 0; index < controlState.orderedKeys.length; index += 1) {\n const itemKey = controlState.orderedKeys[index];\n const itemInstance = controlState.items.get(itemKey);\n childrenVNodes.push((itemInstance?.scope.vnode ?? null) as VNode);\n }\n\n return childrenVNodes;\n}\n\nexport function clearControlBoundaryCommitOwner(parent: Element): void {\n const owner = controlBoundaryOwners.get(parent) as\n | BoundaryCommitOwnerState\n | undefined;\n if (owner) {\n owner._enqueueBoundaryCommit = null;\n owner._hasPendingBoundaryCommit = false;\n if (owner._commitOwner === parent) {\n owner._commitOwner = null;\n }\n }\n\n controlBoundaryOwners.delete(parent);\n}\n\nexport function registerControlBoundaryCommitOwner(\n parent: Element,\n controlState: ControlBoundaryState\n): void {\n const ownerState = controlState as BoundaryCommitOwnerState;\n const previousParent = ownerState._commitOwner;\n if (\n previousParent &&\n previousParent !== parent &&\n controlBoundaryOwners.get(previousParent) === controlState\n ) {\n controlBoundaryOwners.delete(previousParent);\n }\n\n const previousOwner = controlBoundaryOwners.get(parent) as\n | BoundaryCommitOwnerState\n | undefined;\n if (previousOwner && previousOwner !== controlState) {\n previousOwner._enqueueBoundaryCommit = null;\n previousOwner._hasPendingBoundaryCommit = false;\n if (previousOwner._commitOwner === parent) {\n previousOwner._commitOwner = null;\n }\n }\n\n controlBoundaryOwners.set(parent, controlState);\n ownerState._commitOwner = parent;\n controlState._enqueueBoundaryCommit = () => {\n if (controlState._hasPendingBoundaryCommit) {\n return;\n }\n\n controlState._hasPendingBoundaryCommit = true;\n enqueueRuntimeTask(() => {\n controlState._hasPendingBoundaryCommit = false;\n\n if (controlBoundaryOwners.get(parent) !== controlState) {\n return;\n }\n\n const childrenVNodes = getControlBoundaryCommitChildren(controlState);\n commitForBoundaryChildren(parent, controlState, childrenVNodes);\n });\n };\n}\n\n/**\n * Create DOM from For/Show/Case control boundaries.\n *\n * DOM order is reconstructed from the current vnode list on every render.\n * Reusing DOM nodes never implies preserving their position; appending an\n * existing node to the fragment expresses reordering per the DOM spec.\n */\nexport function createForBoundary(\n node: DOMElement,\n props: Record<string, unknown>,\n parentNamespace?: string\n): DocumentFragment {\n void props;\n const controlState = getControlBoundaryState(node);\n\n if (!controlState) {\n if (getRuntimeEnv().NODE_ENV !== 'production') {\n logger.warn('[Askr] Control boundary missing state');\n }\n return document.createDocumentFragment();\n }\n\n const childrenVNodes = evaluateControlBoundaryState(controlState);\n const fragment = document.createDocumentFragment();\n\n if (controlState.kind !== 'for') {\n const activeScope = controlState.activeScope;\n const vnode = childrenVNodes[0];\n if (activeScope && vnode !== undefined) {\n const dom = materializeChildScopeDom(vnode, parentNamespace);\n activeScope.dom = dom ?? undefined;\n if (dom) {\n fragment.appendChild(dom);\n }\n }\n clearControlBoundaryDomUpdateState(controlState);\n return fragment;\n }\n\n const forState = controlState;\n if (forState.orderedKeys.length === 0) {\n const fallbackScope = forState.fallbackScope;\n const fallbackVNode = childrenVNodes[0];\n if (fallbackScope && fallbackVNode !== undefined) {\n const dom = materializeChildScopeDom(fallbackVNode, parentNamespace);\n fallbackScope.dom = dom ?? undefined;\n if (dom) {\n fragment.appendChild(dom);\n }\n }\n clearControlBoundaryDomUpdateState(controlState);\n return fragment;\n }\n\n for (let i = 0; i < childrenVNodes.length; i++) {\n const childVNode = childrenVNodes[i];\n const itemKey = forState.orderedKeys[i];\n const itemInstance = itemKey != null ? forState.items.get(itemKey) : null;\n\n let dom: Node | null = null;\n\n if (itemInstance && itemInstance.scope.dom) {\n const cachedDom = itemInstance.scope.dom;\n if (!checkVNodeShapeChanged(cachedDom, childVNode)) {\n dom = cachedDom;\n }\n }\n\n if (!dom) {\n dom = materializeChildScopeDom(childVNode, parentNamespace);\n if (itemInstance) {\n itemInstance.scope.dom = dom ?? undefined;\n }\n }\n\n if (dom) {\n fragment.appendChild(dom);\n }\n }\n\n clearControlBoundaryDomUpdateState(controlState);\n return fragment;\n}\n\nexport function syncControlBoundaryScopeDom(\n parent: Element,\n scope: ChildScope,\n vnode: VNode\n): Node | null {\n let dom = scope.dom ?? null;\n const parentNamespace = getParentNamespace(parent);\n const host = getBoundaryDOMHost();\n\n if (_isDOMElement(vnode) && typeof vnode.type === 'function') {\n const syncedComponentDom = host.syncComponentElement(\n dom,\n vnode as ElementWithContext,\n vnode.type as ComponentFunction,\n ((vnode as DOMElement).props ?? {}) as Record<string, unknown>,\n parentNamespace\n );\n if (syncedComponentDom) {\n scope.dom = syncedComponentDom ?? undefined;\n return syncedComponentDom;\n }\n }\n\n if (!dom) {\n dom = materializeChildScopeDom(vnode, parentNamespace);\n scope.dom = dom ?? undefined;\n return dom;\n }\n\n if (\n dom.nodeType === 3 &&\n (typeof vnode === 'string' || typeof vnode === 'number')\n ) {\n (dom as Text).data = String(vnode);\n return dom;\n }\n\n if (\n dom.nodeType === 8 &&\n (vnode === null || vnode === undefined || vnode === false)\n ) {\n return dom;\n }\n\n if (\n dom instanceof Element &&\n _isDOMElement(vnode) &&\n typeof vnode.type === 'string' &&\n tagNamesEqualIgnoreCase(dom.tagName, vnode.type)\n ) {\n host.updateElementFromVnode(dom, vnode, true);\n return dom;\n }\n\n const nextDom = materializeChildScopeDom(vnode, parentNamespace);\n if (!nextDom) {\n if (dom.parentNode === parent) {\n teardownNodeSubtree(dom);\n dom.parentNode.removeChild(dom);\n }\n scope.dom = undefined;\n return null;\n }\n\n if (dom.parentNode === parent) {\n parent.replaceChild(nextDom, dom);\n }\n\n teardownNodeSubtree(dom);\n\n scope.dom = nextDom;\n return nextDom;\n}\n\nexport function commitForBoundaryChildren(\n parent: Element,\n controlState: ControlBoundaryState,\n childrenVNodes: VNode[]\n): void {\n if (controlState.kind !== 'for') {\n const activeScope = controlState.activeScope;\n const activeVNode = childrenVNodes[0];\n const nextDom =\n activeScope && activeVNode !== undefined\n ? syncControlBoundaryScopeDom(parent, activeScope, activeVNode)\n : null;\n\n for (let i = 0; i < controlState.lastRemovedNodes.length; i++) {\n const removedNode = controlState.lastRemovedNodes[i];\n if (removedNode instanceof Element) {\n teardownNodeSubtree(removedNode);\n }\n if (removedNode.parentNode === parent) {\n recordBenchEvent('domRemove');\n parent.removeChild(removedNode);\n }\n }\n\n if (nextDom) {\n if (\n parent.childNodes.length !== 1 ||\n parent.firstChild !== nextDom ||\n controlState.lastRemovedNodes.length > 0\n ) {\n parent.replaceChildren(nextDom);\n }\n } else if (parent.firstChild) {\n parent.textContent = '';\n }\n\n keyedElements.delete(parent);\n clearControlBoundaryDomUpdateState(controlState);\n return;\n }\n\n commitForStateBoundaryChildren(parent, controlState, childrenVNodes, {\n isProduction: () => getRuntimeEnv().NODE_ENV === 'production',\n syncForItemDom: syncControlBoundaryScopeDom,\n tryPatchStableForDirtyItem: (scope) =>\n getBoundaryDOMHost().tryPatchStableForDirtyItem(scope),\n });\n}\n\nexport function trySyncControlBoundaryChild(\n parent: Element,\n currentNode: Node | null,\n next: DOMElement\n): boolean {\n if (next.type !== __FOR_BOUNDARY__) {\n return false;\n }\n\n const controlState = getControlBoundaryState(next);\n if (!controlState || controlState.kind === 'for') {\n return false;\n }\n\n const childrenVNodes = evaluateControlBoundaryState(controlState);\n const activeScope = controlState.activeScope;\n const activeVNode = childrenVNodes[0];\n const nextDom =\n activeScope && activeVNode !== undefined\n ? syncControlBoundaryScopeDom(parent, activeScope, activeVNode)\n : null;\n\n for (let i = 0; i < controlState.lastRemovedNodes.length; i++) {\n const removedNode = controlState.lastRemovedNodes[i];\n if (removedNode.parentNode !== parent) {\n continue;\n }\n\n teardownNodeSubtree(removedNode);\n if (nextDom && nextDom !== removedNode && !nextDom.parentNode) {\n parent.replaceChild(nextDom, removedNode);\n } else {\n parent.removeChild(removedNode);\n }\n }\n\n if (nextDom && !nextDom.parentNode) {\n if (currentNode?.parentNode === parent) {\n teardownNodeSubtree(currentNode);\n parent.replaceChild(nextDom, currentNode);\n } else {\n parent.appendChild(nextDom);\n }\n } else if (!nextDom && currentNode?.parentNode === parent) {\n teardownNodeSubtree(currentNode);\n parent.removeChild(currentNode);\n }\n\n clearControlBoundaryDomUpdateState(controlState);\n return true;\n}\n"],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { __FOR_BOUNDARY__, _isDOMElement } from "../common/vnode.js";
2
+ import "./types.js";
3
+ import { getRuntimeEnv } from "../common/env.js";
4
+ import { logger } from "../dev/logger.js";
5
+ import { Fragment, STATIC_CHILDREN } from "../common/jsx.js";
6
+ import { getCurrentInstance } from "../runtime/component-scope.js";
7
+ import "../runtime/component-contracts.js";
8
+ import "./env.js";
9
+ import { isSkippedProp, parseEventName } from "./utils.js";
10
+ import "../jsx-runtime.js";
11
+ //#region src/renderer/child-shape.ts
12
+ function isFragmentVNode(node) {
13
+ return _isDOMElement(node) && typeof node.type === "symbol" && (node.type === Fragment || String(node.type) === "Symbol(askr.fragment)");
14
+ }
15
+ function normalizeComponentChildren(result) {
16
+ if (result === null || result === void 0 || result === false) return [];
17
+ if (Array.isArray(result)) {
18
+ const children = [];
19
+ for (const child of result) children.push(...normalizeComponentChildren(child));
20
+ return children;
21
+ }
22
+ if (isFragmentVNode(result)) return normalizeComponentChildren(result.props?.children ?? result.children ?? []);
23
+ return [result];
24
+ }
25
+ function warnMissingKeys(children) {
26
+ if (getRuntimeEnv().NODE_ENV === "production") return;
27
+ let hasElements = false;
28
+ let hasKeys = false;
29
+ for (const item of children) if (typeof item === "object" && item !== null && "type" in item) {
30
+ if (item.type === __FOR_BOUNDARY__) continue;
31
+ hasElements = true;
32
+ if ((item.key ?? item.props?.key) !== void 0) {
33
+ hasKeys = true;
34
+ break;
35
+ }
36
+ }
37
+ if (hasElements && !hasKeys) {
38
+ const inst = getCurrentInstance();
39
+ const warnings = inst ? inst.devWarningsEmitted ??= /* @__PURE__ */ new Set() : null;
40
+ if (warnings?.has("missing-keys")) return;
41
+ warnings?.add("missing-keys");
42
+ try {
43
+ const name = inst?.fn?.name || "<anonymous>";
44
+ logger.warn(`Missing keys on dynamic lists in ${name}. Each child in a list should have a unique "key" prop.`);
45
+ } catch {
46
+ logger.warn("Missing keys on dynamic lists. Each child in a list should have a unique \"key\" prop.");
47
+ }
48
+ }
49
+ }
50
+ function hasStaticChildrenMarker(children) {
51
+ return children[STATIC_CHILDREN] === true;
52
+ }
53
+ function maybeWarnMissingKeys(children) {
54
+ if (!hasStaticChildrenMarker(children)) warnMissingKeys(children);
55
+ }
56
+ function tryGetStaticCreateChildShape(children) {
57
+ if (children === null || children === void 0 || children === false) return { textContent: null };
58
+ if (typeof children === "string" || typeof children === "number") return { textContent: String(children) };
59
+ if (Array.isArray(children) && children.length === 1) {
60
+ const child = children[0];
61
+ if (child === null || child === void 0 || child === false) return { textContent: null };
62
+ if (typeof child === "string" || typeof child === "number") return { textContent: String(child) };
63
+ }
64
+ return null;
65
+ }
66
+ function isStaticCreateScalarValue(value) {
67
+ const valueType = typeof value;
68
+ return valueType === "string" || valueType === "number" || valueType === "boolean";
69
+ }
70
+ function tryGetStaticCreateFastPathShape(props, children) {
71
+ const childShape = tryGetStaticCreateChildShape(children);
72
+ if (!childShape) return null;
73
+ for (const key in props) {
74
+ if (key === "ref") return null;
75
+ if (isSkippedProp(key)) continue;
76
+ const value = props[key];
77
+ if (value === void 0 || value === null || value === false) continue;
78
+ if (parseEventName(key) || !isStaticCreateScalarValue(value)) return null;
79
+ }
80
+ return childShape;
81
+ }
82
+ //#endregion
83
+ export { isFragmentVNode, maybeWarnMissingKeys, normalizeComponentChildren, tryGetStaticCreateFastPathShape };
84
+
85
+ //# sourceMappingURL=child-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-shape.js","names":[],"sources":["../../src/renderer/child-shape.ts"],"sourcesContent":["import { STATIC_CHILDREN } from '../common/jsx';\nimport { __FOR_BOUNDARY__ } from '../common/vnode';\nimport { logger } from '../dev/logger';\nimport { Fragment } from '../jsx/jsx-runtime';\nimport { getCurrentInstance } from '../runtime/component-contracts';\nimport { getRuntimeEnv } from './env';\nimport { _isDOMElement, type DOMElement } from './types';\nimport { isSkippedProp, parseEventName } from './utils';\n\nexport type StaticCreateChildShape = {\n textContent: string | null;\n};\n\nexport function isFragmentVNode(node: unknown): node is DOMElement {\n return (\n _isDOMElement(node) &&\n typeof (node as DOMElement).type === 'symbol' &&\n ((node as DOMElement).type === Fragment ||\n String((node as DOMElement).type) === 'Symbol(askr.fragment)')\n );\n}\n\nexport function normalizeComponentChildren(result: unknown): unknown[] {\n if (result === null || result === undefined || result === false) {\n return [];\n }\n\n if (Array.isArray(result)) {\n const children: unknown[] = [];\n for (const child of result) {\n children.push(...normalizeComponentChildren(child));\n }\n return children;\n }\n\n if (isFragmentVNode(result)) {\n const children = result.props?.children ?? result.children ?? [];\n return normalizeComponentChildren(children);\n }\n\n return [result];\n}\n\nfunction warnMissingKeys(children: unknown[]): void {\n if (getRuntimeEnv().NODE_ENV === 'production') return;\n\n let hasElements = false;\n let hasKeys = false;\n\n for (const item of children) {\n if (typeof item === 'object' && item !== null && 'type' in item) {\n if ((item as DOMElement).type === __FOR_BOUNDARY__) continue;\n hasElements = true;\n const rawKey =\n (item as DOMElement).key ??\n ((item as DOMElement).props as Record<string, unknown> | undefined)\n ?.key;\n if (rawKey !== undefined) {\n hasKeys = true;\n break;\n }\n }\n }\n\n if (hasElements && !hasKeys) {\n const inst = getCurrentInstance();\n const warnings = inst ? (inst.devWarningsEmitted ??= new Set()) : null;\n if (warnings?.has('missing-keys')) return;\n warnings?.add('missing-keys');\n try {\n const name = inst?.fn?.name || '<anonymous>';\n logger.warn(\n `Missing keys on dynamic lists in ${name}. Each child in a list should have a unique \"key\" prop.`\n );\n } catch {\n logger.warn(\n 'Missing keys on dynamic lists. Each child in a list should have a unique \"key\" prop.'\n );\n }\n }\n}\n\nfunction hasStaticChildrenMarker(children: unknown[]): boolean {\n return (\n (\n children as unknown as {\n [STATIC_CHILDREN]?: boolean;\n }\n )[STATIC_CHILDREN] === true\n );\n}\n\nexport function maybeWarnMissingKeys(children: unknown[]): void {\n if (!hasStaticChildrenMarker(children)) {\n warnMissingKeys(children);\n }\n}\n\nfunction tryGetStaticCreateChildShape(\n children: unknown\n): StaticCreateChildShape | null {\n if (children === null || children === undefined || children === false) {\n return { textContent: null };\n }\n\n if (typeof children === 'string' || typeof children === 'number') {\n return { textContent: String(children) };\n }\n\n if (Array.isArray(children) && children.length === 1) {\n const child = children[0];\n if (child === null || child === undefined || child === false) {\n return { textContent: null };\n }\n if (typeof child === 'string' || typeof child === 'number') {\n return { textContent: String(child) };\n }\n }\n\n return null;\n}\n\nfunction isStaticCreateScalarValue(value: unknown): boolean {\n const valueType = typeof value;\n return (\n valueType === 'string' || valueType === 'number' || valueType === 'boolean'\n );\n}\n\nexport function tryGetStaticCreateFastPathShape(\n props: Record<string, unknown>,\n children: unknown\n): StaticCreateChildShape | null {\n const childShape = tryGetStaticCreateChildShape(children);\n if (!childShape) {\n return null;\n }\n\n for (const key in props) {\n if (key === 'ref') {\n return null;\n }\n if (isSkippedProp(key)) {\n continue;\n }\n\n const value = props[key];\n if (value === undefined || value === null || value === false) {\n continue;\n }\n\n if (parseEventName(key) || !isStaticCreateScalarValue(value)) {\n return null;\n }\n }\n\n return childShape;\n}\n"],"mappings":";;;;;;;;;;;AAaA,SAAgB,gBAAgB,MAAmC;CACjE,OACE,cAAc,IAAI,KAClB,OAAQ,KAAoB,SAAS,aACnC,KAAoB,SAAS,YAC7B,OAAQ,KAAoB,IAAI,MAAM;AAE5C;AAEA,SAAgB,2BAA2B,QAA4B;CACrE,IAAI,WAAW,QAAQ,WAAW,UAAa,WAAW,OACxD,OAAO,CAAC;CAGV,IAAI,MAAM,QAAQ,MAAM,GAAG;EACzB,MAAM,WAAsB,CAAC;EAC7B,KAAK,MAAM,SAAS,QAClB,SAAS,KAAK,GAAG,2BAA2B,KAAK,CAAC;EAEpD,OAAO;CACT;CAEA,IAAI,gBAAgB,MAAM,GAExB,OAAO,2BADU,OAAO,OAAO,YAAY,OAAO,YAAY,CAAC,CACrB;CAG5C,OAAO,CAAC,MAAM;AAChB;AAEA,SAAS,gBAAgB,UAA2B;CAClD,IAAI,cAAc,CAAC,CAAC,aAAa,cAAc;CAE/C,IAAI,cAAc;CAClB,IAAI,UAAU;CAEd,KAAK,MAAM,QAAQ,UACjB,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU,MAAM;EAC/D,IAAK,KAAoB,SAAS,kBAAkB;EACpD,cAAc;EAKd,KAHG,KAAoB,OACnB,KAAoB,OAClB,SACS,QAAW;GACxB,UAAU;GACV;EACF;CACF;CAGF,IAAI,eAAe,CAAC,SAAS;EAC3B,MAAM,OAAO,mBAAmB;EAChC,MAAM,WAAW,OAAQ,KAAK,uCAAuB,IAAI,IAAI,IAAK;EAClE,IAAI,UAAU,IAAI,cAAc,GAAG;EACnC,UAAU,IAAI,cAAc;EAC5B,IAAI;GACF,MAAM,OAAO,MAAM,IAAI,QAAQ;GAC/B,OAAO,KACL,oCAAoC,KAAK,wDAC3C;EACF,QAAQ;GACN,OAAO,KACL,wFACF;EACF;CACF;AACF;AAEA,SAAS,wBAAwB,UAA8B;CAC7D,OAEI,SAGA,qBAAqB;AAE3B;AAEA,SAAgB,qBAAqB,UAA2B;CAC9D,IAAI,CAAC,wBAAwB,QAAQ,GACnC,gBAAgB,QAAQ;AAE5B;AAEA,SAAS,6BACP,UAC+B;CAC/B,IAAI,aAAa,QAAQ,aAAa,UAAa,aAAa,OAC9D,OAAO,EAAE,aAAa,KAAK;CAG7B,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UACtD,OAAO,EAAE,aAAa,OAAO,QAAQ,EAAE;CAGzC,IAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,GAAG;EACpD,MAAM,QAAQ,SAAS;EACvB,IAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,OACrD,OAAO,EAAE,aAAa,KAAK;EAE7B,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAChD,OAAO,EAAE,aAAa,OAAO,KAAK,EAAE;CAExC;CAEA,OAAO;AACT;AAEA,SAAS,0BAA0B,OAAyB;CAC1D,MAAM,YAAY,OAAO;CACzB,OACE,cAAc,YAAY,cAAc,YAAY,cAAc;AAEtE;AAEA,SAAgB,gCACd,OACA,UAC+B;CAC/B,MAAM,aAAa,6BAA6B,QAAQ;CACxD,IAAI,CAAC,YACH,OAAO;CAGT,KAAK,MAAM,OAAO,OAAO;EACvB,IAAI,QAAQ,OACV,OAAO;EAET,IAAI,cAAc,GAAG,GACnB;EAGF,MAAM,QAAQ,MAAM;EACpB,IAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,OACrD;EAGF,IAAI,eAAe,GAAG,KAAK,CAAC,0BAA0B,KAAK,GACzD,OAAO;CAEX;CAEA,OAAO;AACT"}
@@ -2,11 +2,12 @@ import { _isDOMElement } from "../common/vnode.js";
2
2
  import "./types.js";
3
3
  import { getRuntimeEnv } from "../common/env.js";
4
4
  import { incDevCounter, setDevValue } from "../runtime/dev-namespace.js";
5
+ import { teardownNodeSubtree } from "./cleanup.js";
5
6
  import "./env.js";
6
7
  import { hasNonTrivialProps, logFastPathDebug, now, recordDOMReplace, recordFastPathStats, tagNamesEqualIgnoreCase } from "./utils.js";
7
8
  import { keyedElements } from "./keyed.js";
8
- import { teardownNodeSubtree } from "./cleanup.js";
9
- import { createDOMNode, updateElementFromVnode } from "./dom.js";
9
+ import { createDOMNode, updateElementFromVnode } from "./dom-internal.js";
10
+ import "./dom.js";
10
11
  //#region src/renderer/children.ts
11
12
  function upperCommonTagName(tag) {
12
13
  switch (tag) {
@@ -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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"}
@@ -1,6 +1,7 @@
1
1
  import { logger } from "../dev/logger.js";
2
2
  import { incDevCounter } from "../runtime/dev-namespace.js";
3
- import { cleanupComponent } from "../runtime/component.js";
3
+ import { cleanupComponent } from "../runtime/component-cleanup.js";
4
+ import "../runtime/component-contracts.js";
4
5
  import { clearDelegatedHandlersForElement, removeDelegatedListener } from "../runtime/events.js";
5
6
  //#region src/renderer/cleanup.ts
6
7
  const elementRefs = /* @__PURE__ */ new WeakMap();
@@ -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 & {\n __ASKR_INSTANCE?: unknown;\n __ASKR_INSTANCES?: unknown[];\n};\n\ntype Ref<T> =\n | ((value: T | null) => void)\n | { current: T | null }\n | null\n | undefined;\n\nexport const elementRefs = new WeakMap<Element, unknown>();\n\nfunction applyRefValue<T>(ref: unknown, value: T | null): void {\n const resolvedRef = ref as Ref<T>;\n\n if (!resolvedRef) {\n return;\n }\n\n if (typeof resolvedRef === 'function') {\n resolvedRef(value);\n return;\n }\n\n if (Object.isExtensible(resolvedRef)) {\n (resolvedRef as { current: T | null }).current = value;\n }\n}\n\nexport function updateElementRef<T extends Element>(\n element: T,\n ref: unknown\n): void {\n const previousRef = elementRefs.get(element);\n\n if (previousRef === ref) {\n return;\n }\n\n if (previousRef) {\n applyRefValue(previousRef, null);\n }\n\n if (ref) {\n applyRefValue(ref, element);\n elementRefs.set(element, ref);\n } else {\n elementRefs.delete(element);\n }\n}\n\nexport function removeElementRef(element: Element): void {\n const ref = elementRefs.get(element);\n\n if (!ref) {\n return;\n }\n\n applyRefValue(ref, null);\n elementRefs.delete(element);\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 removeElementRef(element);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] removeElementRef failed:', err);\n }\n\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 removeElementRef(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 {\n cleanupComponent,\n type ComponentInstance,\n} from '../runtime/component-contracts';\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\ntype Ref<T> =\n | ((value: T | null) => void)\n | { current: T | null }\n | null\n | undefined;\n\nexport const elementRefs = new WeakMap<Element, unknown>();\n\nfunction applyRefValue<T>(ref: unknown, value: T | null): void {\n const resolvedRef = ref as Ref<T>;\n\n if (!resolvedRef) {\n return;\n }\n\n if (typeof resolvedRef === 'function') {\n resolvedRef(value);\n return;\n }\n\n if (Object.isExtensible(resolvedRef)) {\n (resolvedRef as { current: T | null }).current = value;\n }\n}\n\nexport function updateElementRef<T extends Element>(\n element: T,\n ref: unknown\n): void {\n const previousRef = elementRefs.get(element);\n\n if (previousRef === ref) {\n return;\n }\n\n if (previousRef) {\n applyRefValue(previousRef, null);\n }\n\n if (ref) {\n applyRefValue(ref, element);\n elementRefs.set(element, ref);\n } else {\n elementRefs.delete(element);\n }\n}\n\nexport function removeElementRef(element: Element): void {\n const ref = elementRefs.get(element);\n\n if (!ref) {\n return;\n }\n\n applyRefValue(ref, null);\n elementRefs.delete(element);\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 removeElementRef(element);\n } catch (err) {\n if (strict) errors!.push(err);\n else logger.warn('[Askr] removeElementRef failed:', err);\n }\n\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 restoreFn?: (nextValue: unknown) => ReactivePropCleanupEntry;\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 removeElementRef(el);\n removeElementListeners(el);\n removeElementReactiveProps(el);\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { cleanupComponent } from "../runtime/component-cleanup.js";
2
+ import "../runtime/component-contracts.js";
3
+ import { removeElementListeners, removeElementReactiveProps } from "./cleanup.js";
4
+ //#region src/renderer/component-host-cleanup.ts
5
+ function cleanupDetachedComponentHost(host, retainedInstance) {
6
+ removeElementListeners(host);
7
+ removeElementReactiveProps(host);
8
+ const hostInstances = host.__ASKR_INSTANCES;
9
+ if (hostInstances && hostInstances.length > 0) for (const instance of hostInstances) {
10
+ if (instance === retainedInstance) continue;
11
+ cleanupComponent(instance);
12
+ }
13
+ else if (host.__ASKR_INSTANCE && host.__ASKR_INSTANCE !== retainedInstance) cleanupComponent(host.__ASKR_INSTANCE);
14
+ const descendants = host.querySelectorAll("*");
15
+ for (let index = 0; index < descendants.length; index += 1) {
16
+ const descendant = descendants[index];
17
+ removeElementListeners(descendant);
18
+ removeElementReactiveProps(descendant);
19
+ if (descendant.__ASKR_INSTANCES?.length) {
20
+ for (const instance of descendant.__ASKR_INSTANCES) {
21
+ if (instance === retainedInstance) continue;
22
+ cleanupComponent(instance);
23
+ }
24
+ try {
25
+ delete descendant.__ASKR_INSTANCES;
26
+ } catch {}
27
+ } else if (descendant.__ASKR_INSTANCE && descendant.__ASKR_INSTANCE !== retainedInstance) {
28
+ cleanupComponent(descendant.__ASKR_INSTANCE);
29
+ try {
30
+ delete descendant.__ASKR_INSTANCE;
31
+ } catch {}
32
+ }
33
+ }
34
+ try {
35
+ delete host.__ASKR_INSTANCE;
36
+ delete host.__ASKR_INSTANCES;
37
+ delete host.__ASKR_WRAPPER_HOST;
38
+ } catch {}
39
+ }
40
+ function pruneComponentHostInstances(host, retainedInstances) {
41
+ const retained = new Set(retainedInstances);
42
+ const nextInstances = [];
43
+ const staleInstances = /* @__PURE__ */ new Set();
44
+ const retainOrMarkStale = (instance) => {
45
+ if (!instance) return;
46
+ if (retained.has(instance)) {
47
+ if (!nextInstances.includes(instance)) nextInstances.push(instance);
48
+ return;
49
+ }
50
+ staleInstances.add(instance);
51
+ };
52
+ for (const instance of host.__ASKR_INSTANCES ?? []) retainOrMarkStale(instance);
53
+ retainOrMarkStale(host.__ASKR_INSTANCE);
54
+ for (const instance of staleInstances) cleanupComponent(instance);
55
+ try {
56
+ if (nextInstances.length > 0) {
57
+ host.__ASKR_INSTANCES = nextInstances;
58
+ host.__ASKR_INSTANCE = nextInstances[0];
59
+ } else {
60
+ delete host.__ASKR_INSTANCES;
61
+ delete host.__ASKR_INSTANCE;
62
+ }
63
+ } catch {}
64
+ }
65
+ //#endregion
66
+ export { cleanupDetachedComponentHost, pruneComponentHostInstances };
67
+
68
+ //# sourceMappingURL=component-host-cleanup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-host-cleanup.js","names":[],"sources":["../../src/renderer/component-host-cleanup.ts"],"sourcesContent":["import { cleanupComponent } from '../runtime/component-contracts';\nimport type { ComponentInstance } from '../runtime/component-contracts';\nimport { removeElementListeners, removeElementReactiveProps } from './cleanup';\nimport type { InstanceHostElement } from './dom-host';\n\nexport function cleanupDetachedComponentHost(\n host: InstanceHostElement,\n retainedInstance: ComponentInstance\n): void {\n removeElementListeners(host);\n removeElementReactiveProps(host);\n\n const hostInstances = host.__ASKR_INSTANCES;\n if (hostInstances && hostInstances.length > 0) {\n for (const instance of hostInstances) {\n if (instance === retainedInstance) continue;\n cleanupComponent(instance);\n }\n } else if (\n host.__ASKR_INSTANCE &&\n host.__ASKR_INSTANCE !== retainedInstance\n ) {\n cleanupComponent(host.__ASKR_INSTANCE);\n }\n\n const descendants = host.querySelectorAll('*');\n for (let index = 0; index < descendants.length; index += 1) {\n const descendant = descendants[index] as InstanceHostElement;\n removeElementListeners(descendant);\n removeElementReactiveProps(descendant);\n\n if (descendant.__ASKR_INSTANCES?.length) {\n for (const instance of descendant.__ASKR_INSTANCES) {\n if (instance === retainedInstance) continue;\n cleanupComponent(instance);\n }\n try {\n delete descendant.__ASKR_INSTANCES;\n } catch {\n // Ignore host cleanup failures.\n }\n } else if (\n descendant.__ASKR_INSTANCE &&\n descendant.__ASKR_INSTANCE !== retainedInstance\n ) {\n cleanupComponent(descendant.__ASKR_INSTANCE);\n try {\n delete descendant.__ASKR_INSTANCE;\n } catch {\n // Ignore host cleanup failures.\n }\n }\n }\n\n try {\n delete host.__ASKR_INSTANCE;\n delete host.__ASKR_INSTANCES;\n delete host.__ASKR_WRAPPER_HOST;\n } catch {\n // Ignore host cleanup failures.\n }\n}\n\nexport function pruneComponentHostInstances(\n host: InstanceHostElement,\n retainedInstances: Iterable<ComponentInstance>\n): void {\n const retained = new Set(retainedInstances);\n const nextInstances: ComponentInstance[] = [];\n const staleInstances = new Set<ComponentInstance>();\n\n const retainOrMarkStale = (instance: ComponentInstance | undefined) => {\n if (!instance) {\n return;\n }\n\n if (retained.has(instance)) {\n if (!nextInstances.includes(instance)) {\n nextInstances.push(instance);\n }\n return;\n }\n\n staleInstances.add(instance);\n };\n\n for (const instance of host.__ASKR_INSTANCES ?? []) {\n retainOrMarkStale(instance);\n }\n retainOrMarkStale(host.__ASKR_INSTANCE);\n\n for (const instance of staleInstances) {\n cleanupComponent(instance);\n }\n\n try {\n if (nextInstances.length > 0) {\n host.__ASKR_INSTANCES = nextInstances;\n host.__ASKR_INSTANCE = nextInstances[0];\n } else {\n delete host.__ASKR_INSTANCES;\n delete host.__ASKR_INSTANCE;\n }\n } catch {\n // Ignore host metadata cleanup failures.\n }\n}\n"],"mappings":";;;;AAKA,SAAgB,6BACd,MACA,kBACM;CACN,uBAAuB,IAAI;CAC3B,2BAA2B,IAAI;CAE/B,MAAM,gBAAgB,KAAK;CAC3B,IAAI,iBAAiB,cAAc,SAAS,GAC1C,KAAK,MAAM,YAAY,eAAe;EACpC,IAAI,aAAa,kBAAkB;EACnC,iBAAiB,QAAQ;CAC3B;MACK,IACL,KAAK,mBACL,KAAK,oBAAoB,kBAEzB,iBAAiB,KAAK,eAAe;CAGvC,MAAM,cAAc,KAAK,iBAAiB,GAAG;CAC7C,KAAK,IAAI,QAAQ,GAAG,QAAQ,YAAY,QAAQ,SAAS,GAAG;EAC1D,MAAM,aAAa,YAAY;EAC/B,uBAAuB,UAAU;EACjC,2BAA2B,UAAU;EAErC,IAAI,WAAW,kBAAkB,QAAQ;GACvC,KAAK,MAAM,YAAY,WAAW,kBAAkB;IAClD,IAAI,aAAa,kBAAkB;IACnC,iBAAiB,QAAQ;GAC3B;GACA,IAAI;IACF,OAAO,WAAW;GACpB,QAAQ,CAER;EACF,OAAO,IACL,WAAW,mBACX,WAAW,oBAAoB,kBAC/B;GACA,iBAAiB,WAAW,eAAe;GAC3C,IAAI;IACF,OAAO,WAAW;GACpB,QAAQ,CAER;EACF;CACF;CAEA,IAAI;EACF,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,OAAO,KAAK;CACd,QAAQ,CAER;AACF;AAEA,SAAgB,4BACd,MACA,mBACM;CACN,MAAM,WAAW,IAAI,IAAI,iBAAiB;CAC1C,MAAM,gBAAqC,CAAC;CAC5C,MAAM,iCAAiB,IAAI,IAAuB;CAElD,MAAM,qBAAqB,aAA4C;EACrE,IAAI,CAAC,UACH;EAGF,IAAI,SAAS,IAAI,QAAQ,GAAG;GAC1B,IAAI,CAAC,cAAc,SAAS,QAAQ,GAClC,cAAc,KAAK,QAAQ;GAE7B;EACF;EAEA,eAAe,IAAI,QAAQ;CAC7B;CAEA,KAAK,MAAM,YAAY,KAAK,oBAAoB,CAAC,GAC/C,kBAAkB,QAAQ;CAE5B,kBAAkB,KAAK,eAAe;CAEtC,KAAK,MAAM,YAAY,gBACrB,iBAAiB,QAAQ;CAG3B,IAAI;EACF,IAAI,cAAc,SAAS,GAAG;GAC5B,KAAK,mBAAmB;GACxB,KAAK,kBAAkB,cAAc;EACvC,OAAO;GACL,OAAO,KAAK;GACZ,OAAO,KAAK;EACd;CACF,QAAQ,CAER;AACF"}
@@ -0,0 +1,65 @@
1
+ import { getDevValue, incDevCounter } from "../runtime/dev-namespace.js";
2
+ import { getCurrentInstance } from "../runtime/component-scope.js";
3
+ import "../runtime/component-contracts.js";
4
+ import { extractKey } from "./utils.js";
5
+ import { ROUTE_ROOT_COMPONENT } from "../common/router-internal.js";
6
+ //#region src/renderer/component-host-instances.ts
7
+ function isRouteRootComponentVNode(node) {
8
+ return typeof node === "object" && node !== null && node[ROUTE_ROOT_COMPONENT] === true;
9
+ }
10
+ function inheritComponentCleanupStrict(instance) {
11
+ const owner = getCurrentInstance();
12
+ if (owner) instance.cleanupStrict = owner.cleanupStrict;
13
+ }
14
+ const vnodeComponentInstances = /* @__PURE__ */ new WeakMap();
15
+ function getVNodeComponentInstance(node) {
16
+ if (typeof node !== "object" || node === null) return;
17
+ return vnodeComponentInstances.get(node) ?? node.__instance;
18
+ }
19
+ function setVNodeComponentInstance(node, instance) {
20
+ if (typeof node !== "object" || node === null) return;
21
+ const objectNode = node;
22
+ if (Object.prototype.hasOwnProperty.call(objectNode, "__instance")) try {
23
+ objectNode.__instance = instance;
24
+ return;
25
+ } catch {}
26
+ if (Object.isExtensible(objectNode)) try {
27
+ objectNode.__instance = instance;
28
+ return;
29
+ } catch {}
30
+ vnodeComponentInstances.set(objectNode, instance);
31
+ }
32
+ let fallbackComponentInstanceId = 0;
33
+ function nextComponentInstanceId() {
34
+ const key = "__COMPONENT_INSTANCE_ID";
35
+ try {
36
+ incDevCounter(key);
37
+ const n = getDevValue(key);
38
+ if (typeof n === "number" && Number.isFinite(n)) return `comp-${n}`;
39
+ } catch {}
40
+ fallbackComponentInstanceId++;
41
+ return `comp-${fallbackComponentInstanceId}`;
42
+ }
43
+ function inheritComponentKey(target, source) {
44
+ const inheritedKey = extractKey(source);
45
+ if (inheritedKey === void 0 || extractKey(target) !== void 0) return target;
46
+ target.key = inheritedKey;
47
+ if (typeof target.type === "string") {
48
+ if (!target.props) target.props = {};
49
+ const props = target.props;
50
+ if (props["data-key"] === void 0) props["data-key"] = String(inheritedKey);
51
+ }
52
+ return target;
53
+ }
54
+ function findHostInstanceByType(host, type) {
55
+ const instances = host.__ASKR_INSTANCES;
56
+ if (instances && instances.length > 0) for (let index = instances.length - 1; index >= 0; index -= 1) {
57
+ const instance = instances[index];
58
+ if (instance.fn === type) return instance;
59
+ }
60
+ return host.__ASKR_INSTANCE?.fn === type ? host.__ASKR_INSTANCE : null;
61
+ }
62
+ //#endregion
63
+ export { findHostInstanceByType, getVNodeComponentInstance, inheritComponentCleanupStrict, inheritComponentKey, isRouteRootComponentVNode, nextComponentInstanceId, setVNodeComponentInstance };
64
+
65
+ //# sourceMappingURL=component-host-instances.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-host-instances.js","names":[],"sources":["../../src/renderer/component-host-instances.ts"],"sourcesContent":["import { ROUTE_ROOT_COMPONENT } from '../common/router-internal';\nimport type { Props } from '../common/props';\nimport {\n getCurrentInstance,\n type ComponentInstance,\n} from '../runtime/component-contracts';\nimport { getDevValue, incDevCounter } from '../runtime/dev-namespace';\nimport type { InstanceHostElement } from './dom-host';\nimport type { DOMElement } from './types';\nimport { extractKey } from './utils';\n\nexport function isRouteRootComponentVNode(node: unknown): boolean {\n return (\n typeof node === 'object' &&\n node !== null &&\n (node as { [ROUTE_ROOT_COMPONENT]?: boolean })[ROUTE_ROOT_COMPONENT] ===\n true\n );\n}\n\nexport function inheritComponentCleanupStrict(\n instance: ComponentInstance\n): void {\n const owner = getCurrentInstance();\n if (owner) {\n instance.cleanupStrict = owner.cleanupStrict;\n }\n}\n\nconst vnodeComponentInstances = new WeakMap<object, ComponentInstance>();\n\nexport function getVNodeComponentInstance(\n node: unknown\n): ComponentInstance | undefined {\n if (typeof node !== 'object' || node === null) {\n return undefined;\n }\n\n return (\n vnodeComponentInstances.get(node) ??\n (node as { __instance?: ComponentInstance }).__instance\n );\n}\n\nexport function setVNodeComponentInstance(\n node: unknown,\n instance: ComponentInstance\n): void {\n if (typeof node !== 'object' || node === null) {\n return;\n }\n\n const objectNode = node as { __instance?: ComponentInstance };\n\n if (Object.prototype.hasOwnProperty.call(objectNode, '__instance')) {\n try {\n objectNode.__instance = instance;\n return;\n } catch {\n // Fall back to WeakMap for readonly vnode metadata.\n }\n }\n\n if (Object.isExtensible(objectNode)) {\n try {\n objectNode.__instance = instance;\n return;\n } catch {\n // Fall back to WeakMap for frozen/proxied objects.\n }\n }\n\n vnodeComponentInstances.set(objectNode, instance);\n}\n\nlet fallbackComponentInstanceId = 0;\n\nexport function nextComponentInstanceId(): string {\n const key = '__COMPONENT_INSTANCE_ID';\n try {\n incDevCounter(key);\n const n = getDevValue<number>(key);\n if (typeof n === 'number' && Number.isFinite(n)) return `comp-${n}`;\n } catch {\n // Fall through to local counter\n }\n fallbackComponentInstanceId++;\n return `comp-${fallbackComponentInstanceId}`;\n}\n\nexport function inheritComponentKey(\n target: DOMElement,\n source: DOMElement\n): DOMElement {\n const inheritedKey = extractKey(source);\n if (inheritedKey === undefined || extractKey(target) !== undefined) {\n return target;\n }\n\n target.key = inheritedKey;\n\n if (typeof target.type === 'string') {\n if (!target.props) {\n target.props = {};\n }\n\n const props = target.props as Record<string, unknown>;\n if (props['data-key'] === undefined) {\n props['data-key'] = String(inheritedKey);\n }\n }\n\n return target;\n}\n\nexport function findHostInstanceByType(\n host: InstanceHostElement,\n type: (props: Props) => unknown\n): ComponentInstance | null {\n const instances = host.__ASKR_INSTANCES;\n if (instances && instances.length > 0) {\n for (let index = instances.length - 1; index >= 0; index -= 1) {\n const instance = instances[index]!;\n if (instance.fn === type) {\n return instance;\n }\n }\n }\n\n return host.__ASKR_INSTANCE?.fn === type ? host.__ASKR_INSTANCE : null;\n}\n"],"mappings":";;;;;;AAWA,SAAgB,0BAA0B,MAAwB;CAChE,OACE,OAAO,SAAS,YAChB,SAAS,QACR,KAA8C,0BAC7C;AAEN;AAEA,SAAgB,8BACd,UACM;CACN,MAAM,QAAQ,mBAAmB;CACjC,IAAI,OACF,SAAS,gBAAgB,MAAM;AAEnC;AAEA,MAAM,0CAA0B,IAAI,QAAmC;AAEvE,SAAgB,0BACd,MAC+B;CAC/B,IAAI,OAAO,SAAS,YAAY,SAAS,MACvC;CAGF,OACE,wBAAwB,IAAI,IAAI,KAC/B,KAA4C;AAEjD;AAEA,SAAgB,0BACd,MACA,UACM;CACN,IAAI,OAAO,SAAS,YAAY,SAAS,MACvC;CAGF,MAAM,aAAa;CAEnB,IAAI,OAAO,UAAU,eAAe,KAAK,YAAY,YAAY,GAC/D,IAAI;EACF,WAAW,aAAa;EACxB;CACF,QAAQ,CAER;CAGF,IAAI,OAAO,aAAa,UAAU,GAChC,IAAI;EACF,WAAW,aAAa;EACxB;CACF,QAAQ,CAER;CAGF,wBAAwB,IAAI,YAAY,QAAQ;AAClD;AAEA,IAAI,8BAA8B;AAElC,SAAgB,0BAAkC;CAChD,MAAM,MAAM;CACZ,IAAI;EACF,cAAc,GAAG;EACjB,MAAM,IAAI,YAAoB,GAAG;EACjC,IAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,GAAG,OAAO,QAAQ;CAClE,QAAQ,CAER;CACA;CACA,OAAO,QAAQ;AACjB;AAEA,SAAgB,oBACd,QACA,QACY;CACZ,MAAM,eAAe,WAAW,MAAM;CACtC,IAAI,iBAAiB,UAAa,WAAW,MAAM,MAAM,QACvD,OAAO;CAGT,OAAO,MAAM;CAEb,IAAI,OAAO,OAAO,SAAS,UAAU;EACnC,IAAI,CAAC,OAAO,OACV,OAAO,QAAQ,CAAC;EAGlB,MAAM,QAAQ,OAAO;EACrB,IAAI,MAAM,gBAAgB,QACxB,MAAM,cAAc,OAAO,YAAY;CAE3C;CAEA,OAAO;AACT;AAEA,SAAgB,uBACd,MACA,MAC0B;CAC1B,MAAM,YAAY,KAAK;CACvB,IAAI,aAAa,UAAU,SAAS,GAClC,KAAK,IAAI,QAAQ,UAAU,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;EAC7D,MAAM,WAAW,UAAU;EAC3B,IAAI,SAAS,OAAO,MAClB,OAAO;CAEX;CAGF,OAAO,KAAK,iBAAiB,OAAO,OAAO,KAAK,kBAAkB;AACpE"}