@typed/template 0.14.0 → 1.0.0-beta.1

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 (452) hide show
  1. package/README.md +121 -2
  2. package/dist/EventHandler.d.ts +273 -0
  3. package/dist/EventHandler.d.ts.map +1 -0
  4. package/dist/EventHandler.js +261 -0
  5. package/dist/EventSource.d.ts +82 -0
  6. package/dist/EventSource.d.ts.map +1 -0
  7. package/dist/EventSource.js +127 -0
  8. package/dist/Html.d.ts +122 -0
  9. package/dist/Html.d.ts.map +1 -0
  10. package/dist/Html.js +250 -0
  11. package/dist/HtmlChunk.d.ts +118 -0
  12. package/dist/HtmlChunk.d.ts.map +1 -0
  13. package/dist/HtmlChunk.js +211 -0
  14. package/dist/HydrateContext.d.ts +28 -0
  15. package/dist/HydrateContext.d.ts.map +1 -0
  16. package/dist/HydrateContext.js +25 -0
  17. package/dist/Parser.d.ts +35 -0
  18. package/dist/Parser.d.ts.map +1 -0
  19. package/dist/Parser.js +437 -0
  20. package/dist/Render.d.ts +195 -0
  21. package/dist/Render.d.ts.map +1 -0
  22. package/dist/Render.js +609 -0
  23. package/dist/RenderEvent.d.ts +179 -0
  24. package/dist/RenderEvent.d.ts.map +1 -0
  25. package/dist/RenderEvent.js +102 -0
  26. package/dist/RenderQueue.d.ts +167 -0
  27. package/dist/RenderQueue.d.ts.map +1 -0
  28. package/dist/RenderQueue.js +298 -0
  29. package/dist/RenderTemplate.d.ts +90 -0
  30. package/dist/RenderTemplate.d.ts.map +1 -0
  31. package/dist/RenderTemplate.js +87 -0
  32. package/dist/Renderable.d.ts +88 -0
  33. package/dist/Renderable.d.ts.map +1 -0
  34. package/dist/Renderable.js +3 -0
  35. package/dist/{dts/Template.d.ts → Template.d.ts} +109 -74
  36. package/dist/Template.d.ts.map +1 -0
  37. package/dist/{esm/Template.js → Template.js} +96 -56
  38. package/dist/Wire.d.ts +169 -0
  39. package/dist/Wire.d.ts.map +1 -0
  40. package/dist/Wire.js +217 -0
  41. package/dist/errors.d.ts +145 -0
  42. package/dist/errors.d.ts.map +1 -0
  43. package/dist/errors.js +159 -0
  44. package/dist/index.d.ts +15 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +14 -0
  47. package/dist/internal/IndexRefCounter.d.ts +11 -0
  48. package/dist/internal/IndexRefCounter.d.ts.map +1 -0
  49. package/dist/internal/IndexRefCounter.js +42 -0
  50. package/dist/internal/ParentChildNodes.d.ts +6 -0
  51. package/dist/internal/ParentChildNodes.d.ts.map +1 -0
  52. package/dist/internal/ParentChildNodes.js +1 -0
  53. package/dist/internal/PathStack.d.ts +9 -0
  54. package/dist/internal/PathStack.d.ts.map +1 -0
  55. package/dist/internal/PathStack.js +18 -0
  56. package/dist/internal/buildTemplateFragement.d.ts +3 -0
  57. package/dist/internal/buildTemplateFragement.d.ts.map +1 -0
  58. package/dist/internal/buildTemplateFragement.js +61 -0
  59. package/dist/internal/diff.d.ts +2 -0
  60. package/dist/internal/diff.d.ts.map +1 -0
  61. package/dist/internal/diff.js +119 -0
  62. package/dist/internal/dom.d.ts +45 -0
  63. package/dist/internal/dom.d.ts.map +1 -0
  64. package/dist/internal/dom.js +304 -0
  65. package/dist/internal/encoding.d.ts +7 -0
  66. package/dist/internal/encoding.d.ts.map +1 -0
  67. package/dist/internal/encoding.js +134 -0
  68. package/dist/{dts/internal/v2/hydration-template.d.ts → internal/hydration.d.ts} +10 -7
  69. package/dist/internal/hydration.d.ts.map +1 -0
  70. package/dist/{esm/internal/v2/hydration-template.js → internal/hydration.js} +80 -26
  71. package/dist/internal/keyToPartType.d.ts +2 -0
  72. package/dist/internal/keyToPartType.d.ts.map +1 -0
  73. package/dist/internal/keyToPartType.js +110 -0
  74. package/dist/internal/meta.d.ts +17 -0
  75. package/dist/internal/meta.d.ts.map +1 -0
  76. package/dist/internal/meta.js +14 -0
  77. package/dist/internal/takeOneIfNotRenderEvent.d.ts +4 -0
  78. package/dist/internal/takeOneIfNotRenderEvent.d.ts.map +1 -0
  79. package/dist/internal/takeOneIfNotRenderEvent.js +10 -0
  80. package/dist/internal/templateHash.d.ts +2 -0
  81. package/dist/internal/templateHash.d.ts.map +1 -0
  82. package/dist/internal/templateHash.js +14 -0
  83. package/dist/many.d.ts +68 -0
  84. package/dist/many.d.ts.map +1 -0
  85. package/dist/many.js +107 -0
  86. package/package.json +29 -227
  87. package/src/EventHandler.ts +318 -86
  88. package/src/EventSource.ts +202 -0
  89. package/src/Html.test.ts +490 -0
  90. package/src/Html.ts +292 -333
  91. package/src/HtmlChunk.ts +290 -332
  92. package/src/HydrateContext.ts +40 -0
  93. package/src/Hydration.test.ts +408 -0
  94. package/src/Parser.test.ts +923 -0
  95. package/src/Parser.ts +598 -10
  96. package/src/Render.test.ts +337 -0
  97. package/src/Render.ts +878 -63
  98. package/src/RenderEvent.ts +169 -40
  99. package/src/RenderQueue.ts +291 -385
  100. package/src/RenderTemplate.ts +98 -31
  101. package/src/Renderable.ts +122 -24
  102. package/src/Template.ts +246 -145
  103. package/src/Wire.ts +309 -0
  104. package/src/errors.ts +173 -0
  105. package/src/index.ts +14 -66
  106. package/src/internal/IndexRefCounter.ts +53 -0
  107. package/src/internal/ParentChildNodes.ts +7 -0
  108. package/src/internal/PathStack.ts +23 -0
  109. package/src/internal/buildTemplateFragement.ts +82 -0
  110. package/src/internal/diff.ts +127 -0
  111. package/src/internal/dom.ts +357 -0
  112. package/src/internal/encoding.ts +147 -0
  113. package/src/internal/hydration.ts +406 -0
  114. package/src/internal/keyToPartType.ts +113 -0
  115. package/src/internal/meta.ts +25 -0
  116. package/src/internal/takeOneIfNotRenderEvent.ts +19 -0
  117. package/src/internal/templateHash.ts +18 -0
  118. package/src/many.ts +148 -0
  119. package/Directive/package.json +0 -6
  120. package/ElementRef/package.json +0 -6
  121. package/ElementSource/package.json +0 -6
  122. package/Entry/package.json +0 -6
  123. package/EventHandler/package.json +0 -6
  124. package/Html/package.json +0 -6
  125. package/HtmlChunk/package.json +0 -6
  126. package/Hydrate/package.json +0 -6
  127. package/LICENSE +0 -21
  128. package/Many/package.json +0 -6
  129. package/Meta/package.json +0 -6
  130. package/Parser/package.json +0 -6
  131. package/Part/package.json +0 -6
  132. package/Placeholder/package.json +0 -6
  133. package/Platform/package.json +0 -6
  134. package/Render/package.json +0 -6
  135. package/RenderContext/package.json +0 -6
  136. package/RenderEvent/package.json +0 -6
  137. package/RenderQueue/package.json +0 -6
  138. package/RenderTemplate/package.json +0 -6
  139. package/Renderable/package.json +0 -6
  140. package/Template/package.json +0 -6
  141. package/Test/package.json +0 -6
  142. package/Vitest/package.json +0 -6
  143. package/compiler-tools/package.json +0 -6
  144. package/dist/cjs/Directive.js +0 -76
  145. package/dist/cjs/Directive.js.map +0 -1
  146. package/dist/cjs/ElementRef.js +0 -92
  147. package/dist/cjs/ElementRef.js.map +0 -1
  148. package/dist/cjs/ElementSource.js +0 -246
  149. package/dist/cjs/ElementSource.js.map +0 -1
  150. package/dist/cjs/Entry.js +0 -6
  151. package/dist/cjs/Entry.js.map +0 -1
  152. package/dist/cjs/EventHandler.js +0 -76
  153. package/dist/cjs/EventHandler.js.map +0 -1
  154. package/dist/cjs/Html.js +0 -224
  155. package/dist/cjs/Html.js.map +0 -1
  156. package/dist/cjs/HtmlChunk.js +0 -306
  157. package/dist/cjs/HtmlChunk.js.map +0 -1
  158. package/dist/cjs/Hydrate.js +0 -43
  159. package/dist/cjs/Hydrate.js.map +0 -1
  160. package/dist/cjs/Many.js +0 -66
  161. package/dist/cjs/Many.js.map +0 -1
  162. package/dist/cjs/Meta.js +0 -50
  163. package/dist/cjs/Meta.js.map +0 -1
  164. package/dist/cjs/Parser.js +0 -19
  165. package/dist/cjs/Parser.js.map +0 -1
  166. package/dist/cjs/Part.js +0 -6
  167. package/dist/cjs/Part.js.map +0 -1
  168. package/dist/cjs/Placeholder.js +0 -34
  169. package/dist/cjs/Placeholder.js.map +0 -1
  170. package/dist/cjs/Platform.js +0 -65
  171. package/dist/cjs/Platform.js.map +0 -1
  172. package/dist/cjs/Render.js +0 -50
  173. package/dist/cjs/Render.js.map +0 -1
  174. package/dist/cjs/RenderContext.js +0 -67
  175. package/dist/cjs/RenderContext.js.map +0 -1
  176. package/dist/cjs/RenderEvent.js +0 -52
  177. package/dist/cjs/RenderEvent.js.map +0 -1
  178. package/dist/cjs/RenderQueue.js +0 -343
  179. package/dist/cjs/RenderQueue.js.map +0 -1
  180. package/dist/cjs/RenderTemplate.js +0 -26
  181. package/dist/cjs/RenderTemplate.js.map +0 -1
  182. package/dist/cjs/Renderable.js +0 -6
  183. package/dist/cjs/Renderable.js.map +0 -1
  184. package/dist/cjs/Template.js +0 -305
  185. package/dist/cjs/Template.js.map +0 -1
  186. package/dist/cjs/Test.js +0 -184
  187. package/dist/cjs/Test.js.map +0 -1
  188. package/dist/cjs/Vitest.js +0 -52
  189. package/dist/cjs/Vitest.js.map +0 -1
  190. package/dist/cjs/compiler-tools.js +0 -100
  191. package/dist/cjs/compiler-tools.js.map +0 -1
  192. package/dist/cjs/index.js +0 -138
  193. package/dist/cjs/index.js.map +0 -1
  194. package/dist/cjs/internal/EventSource.js +0 -129
  195. package/dist/cjs/internal/EventSource.js.map +0 -1
  196. package/dist/cjs/internal/HydrateContext.js +0 -13
  197. package/dist/cjs/internal/HydrateContext.js.map +0 -1
  198. package/dist/cjs/internal/browser.js +0 -110
  199. package/dist/cjs/internal/browser.js.map +0 -1
  200. package/dist/cjs/internal/character-entities.js +0 -2141
  201. package/dist/cjs/internal/character-entities.js.map +0 -1
  202. package/dist/cjs/internal/chunks.js +0 -68
  203. package/dist/cjs/internal/chunks.js.map +0 -1
  204. package/dist/cjs/internal/errors.js +0 -52
  205. package/dist/cjs/internal/errors.js.map +0 -1
  206. package/dist/cjs/internal/indexRefCounter.js +0 -52
  207. package/dist/cjs/internal/indexRefCounter.js.map +0 -1
  208. package/dist/cjs/internal/module-augmentation.js +0 -6
  209. package/dist/cjs/internal/module-augmentation.js.map +0 -1
  210. package/dist/cjs/internal/parser.js +0 -568
  211. package/dist/cjs/internal/parser.js.map +0 -1
  212. package/dist/cjs/internal/parser2.js +0 -382
  213. package/dist/cjs/internal/parser2.js.map +0 -1
  214. package/dist/cjs/internal/server-parts.js +0 -124
  215. package/dist/cjs/internal/server-parts.js.map +0 -1
  216. package/dist/cjs/internal/server.js +0 -48
  217. package/dist/cjs/internal/server.js.map +0 -1
  218. package/dist/cjs/internal/utils.js +0 -136
  219. package/dist/cjs/internal/utils.js.map +0 -1
  220. package/dist/cjs/internal/v2/SyncPart.js +0 -6
  221. package/dist/cjs/internal/v2/SyncPart.js.map +0 -1
  222. package/dist/cjs/internal/v2/helpers.js +0 -15
  223. package/dist/cjs/internal/v2/helpers.js.map +0 -1
  224. package/dist/cjs/internal/v2/hydration-template.js +0 -269
  225. package/dist/cjs/internal/v2/hydration-template.js.map +0 -1
  226. package/dist/cjs/internal/v2/parts.js +0 -169
  227. package/dist/cjs/internal/v2/parts.js.map +0 -1
  228. package/dist/cjs/internal/v2/render-entry.js +0 -110
  229. package/dist/cjs/internal/v2/render-entry.js.map +0 -1
  230. package/dist/cjs/internal/v2/render-sync-parts.js +0 -318
  231. package/dist/cjs/internal/v2/render-sync-parts.js.map +0 -1
  232. package/dist/cjs/internal/v2/render.js +0 -592
  233. package/dist/cjs/internal/v2/render.js.map +0 -1
  234. package/dist/cjs/internal/v2/sync-parts.js +0 -115
  235. package/dist/cjs/internal/v2/sync-parts.js.map +0 -1
  236. package/dist/dts/Directive.d.ts +0 -70
  237. package/dist/dts/Directive.d.ts.map +0 -1
  238. package/dist/dts/ElementRef.d.ts +0 -42
  239. package/dist/dts/ElementRef.d.ts.map +0 -1
  240. package/dist/dts/ElementSource.d.ts +0 -79
  241. package/dist/dts/ElementSource.d.ts.map +0 -1
  242. package/dist/dts/Entry.d.ts +0 -26
  243. package/dist/dts/Entry.d.ts.map +0 -1
  244. package/dist/dts/EventHandler.d.ts +0 -73
  245. package/dist/dts/EventHandler.d.ts.map +0 -1
  246. package/dist/dts/Html.d.ts +0 -35
  247. package/dist/dts/Html.d.ts.map +0 -1
  248. package/dist/dts/HtmlChunk.d.ts +0 -56
  249. package/dist/dts/HtmlChunk.d.ts.map +0 -1
  250. package/dist/dts/Hydrate.d.ts +0 -19
  251. package/dist/dts/Hydrate.d.ts.map +0 -1
  252. package/dist/dts/Many.d.ts +0 -32
  253. package/dist/dts/Many.d.ts.map +0 -1
  254. package/dist/dts/Meta.d.ts +0 -33
  255. package/dist/dts/Meta.d.ts.map +0 -1
  256. package/dist/dts/Parser.d.ts +0 -13
  257. package/dist/dts/Parser.d.ts.map +0 -1
  258. package/dist/dts/Part.d.ts +0 -121
  259. package/dist/dts/Part.d.ts.map +0 -1
  260. package/dist/dts/Placeholder.d.ts +0 -48
  261. package/dist/dts/Placeholder.d.ts.map +0 -1
  262. package/dist/dts/Platform.d.ts +0 -21
  263. package/dist/dts/Platform.d.ts.map +0 -1
  264. package/dist/dts/Render.d.ts +0 -31
  265. package/dist/dts/Render.d.ts.map +0 -1
  266. package/dist/dts/RenderContext.d.ts +0 -70
  267. package/dist/dts/RenderContext.d.ts.map +0 -1
  268. package/dist/dts/RenderEvent.d.ts +0 -42
  269. package/dist/dts/RenderEvent.d.ts.map +0 -1
  270. package/dist/dts/RenderQueue.d.ts +0 -103
  271. package/dist/dts/RenderQueue.d.ts.map +0 -1
  272. package/dist/dts/RenderTemplate.d.ts +0 -25
  273. package/dist/dts/RenderTemplate.d.ts.map +0 -1
  274. package/dist/dts/Renderable.d.ts +0 -28
  275. package/dist/dts/Renderable.d.ts.map +0 -1
  276. package/dist/dts/Template.d.ts.map +0 -1
  277. package/dist/dts/Test.d.ts +0 -85
  278. package/dist/dts/Test.d.ts.map +0 -1
  279. package/dist/dts/Vitest.d.ts +0 -43
  280. package/dist/dts/Vitest.d.ts.map +0 -1
  281. package/dist/dts/compiler-tools.d.ts +0 -143
  282. package/dist/dts/compiler-tools.d.ts.map +0 -1
  283. package/dist/dts/index.d.ts +0 -65
  284. package/dist/dts/index.d.ts.map +0 -1
  285. package/dist/dts/internal/EventSource.d.ts +0 -13
  286. package/dist/dts/internal/EventSource.d.ts.map +0 -1
  287. package/dist/dts/internal/HydrateContext.d.ts +0 -2
  288. package/dist/dts/internal/HydrateContext.d.ts.map +0 -1
  289. package/dist/dts/internal/browser.d.ts +0 -8
  290. package/dist/dts/internal/browser.d.ts.map +0 -1
  291. package/dist/dts/internal/character-entities.d.ts +0 -2133
  292. package/dist/dts/internal/character-entities.d.ts.map +0 -1
  293. package/dist/dts/internal/chunks.d.ts +0 -23
  294. package/dist/dts/internal/chunks.d.ts.map +0 -1
  295. package/dist/dts/internal/errors.d.ts +0 -22
  296. package/dist/dts/internal/errors.d.ts.map +0 -1
  297. package/dist/dts/internal/indexRefCounter.d.ts +0 -7
  298. package/dist/dts/internal/indexRefCounter.d.ts.map +0 -1
  299. package/dist/dts/internal/module-augmentation.d.ts +0 -32
  300. package/dist/dts/internal/module-augmentation.d.ts.map +0 -1
  301. package/dist/dts/internal/parser.d.ts +0 -33
  302. package/dist/dts/internal/parser.d.ts.map +0 -1
  303. package/dist/dts/internal/parser2.d.ts +0 -12
  304. package/dist/dts/internal/parser2.d.ts.map +0 -1
  305. package/dist/dts/internal/server-parts.d.ts +0 -223
  306. package/dist/dts/internal/server-parts.d.ts.map +0 -1
  307. package/dist/dts/internal/server.d.ts +0 -5
  308. package/dist/dts/internal/server.d.ts.map +0 -1
  309. package/dist/dts/internal/utils.d.ts +0 -19
  310. package/dist/dts/internal/utils.d.ts.map +0 -1
  311. package/dist/dts/internal/v2/SyncPart.d.ts +0 -87
  312. package/dist/dts/internal/v2/SyncPart.d.ts.map +0 -1
  313. package/dist/dts/internal/v2/helpers.d.ts +0 -3
  314. package/dist/dts/internal/v2/helpers.d.ts.map +0 -1
  315. package/dist/dts/internal/v2/hydration-template.d.ts.map +0 -1
  316. package/dist/dts/internal/v2/parts.d.ts +0 -245
  317. package/dist/dts/internal/v2/parts.d.ts.map +0 -1
  318. package/dist/dts/internal/v2/render-entry.d.ts +0 -6
  319. package/dist/dts/internal/v2/render-entry.d.ts.map +0 -1
  320. package/dist/dts/internal/v2/render-sync-parts.d.ts +0 -22
  321. package/dist/dts/internal/v2/render-sync-parts.d.ts.map +0 -1
  322. package/dist/dts/internal/v2/render.d.ts +0 -83
  323. package/dist/dts/internal/v2/render.d.ts.map +0 -1
  324. package/dist/dts/internal/v2/sync-parts.d.ts +0 -129
  325. package/dist/dts/internal/v2/sync-parts.d.ts.map +0 -1
  326. package/dist/esm/Directive.js +0 -64
  327. package/dist/esm/Directive.js.map +0 -1
  328. package/dist/esm/ElementRef.js +0 -76
  329. package/dist/esm/ElementRef.js.map +0 -1
  330. package/dist/esm/ElementSource.js +0 -246
  331. package/dist/esm/ElementSource.js.map +0 -1
  332. package/dist/esm/Entry.js +0 -2
  333. package/dist/esm/Entry.js.map +0 -1
  334. package/dist/esm/EventHandler.js +0 -68
  335. package/dist/esm/EventHandler.js.map +0 -1
  336. package/dist/esm/Html.js +0 -230
  337. package/dist/esm/Html.js.map +0 -1
  338. package/dist/esm/HtmlChunk.js +0 -330
  339. package/dist/esm/HtmlChunk.js.map +0 -1
  340. package/dist/esm/Hydrate.js +0 -31
  341. package/dist/esm/Hydrate.js.map +0 -1
  342. package/dist/esm/Many.js +0 -54
  343. package/dist/esm/Many.js.map +0 -1
  344. package/dist/esm/Meta.js +0 -40
  345. package/dist/esm/Meta.js.map +0 -1
  346. package/dist/esm/Parser.js +0 -13
  347. package/dist/esm/Parser.js.map +0 -1
  348. package/dist/esm/Part.js +0 -5
  349. package/dist/esm/Part.js.map +0 -1
  350. package/dist/esm/Placeholder.js +0 -26
  351. package/dist/esm/Placeholder.js.map +0 -1
  352. package/dist/esm/Platform.js +0 -42
  353. package/dist/esm/Platform.js.map +0 -1
  354. package/dist/esm/Render.js +0 -36
  355. package/dist/esm/Render.js.map +0 -1
  356. package/dist/esm/RenderContext.js +0 -54
  357. package/dist/esm/RenderContext.js.map +0 -1
  358. package/dist/esm/RenderEvent.js +0 -43
  359. package/dist/esm/RenderEvent.js.map +0 -1
  360. package/dist/esm/RenderQueue.js +0 -338
  361. package/dist/esm/RenderQueue.js.map +0 -1
  362. package/dist/esm/RenderTemplate.js +0 -16
  363. package/dist/esm/RenderTemplate.js.map +0 -1
  364. package/dist/esm/Renderable.js +0 -2
  365. package/dist/esm/Renderable.js.map +0 -1
  366. package/dist/esm/Template.js.map +0 -1
  367. package/dist/esm/Test.js +0 -167
  368. package/dist/esm/Test.js.map +0 -1
  369. package/dist/esm/Vitest.js +0 -44
  370. package/dist/esm/Vitest.js.map +0 -1
  371. package/dist/esm/compiler-tools.js +0 -91
  372. package/dist/esm/compiler-tools.js.map +0 -1
  373. package/dist/esm/index.js +0 -65
  374. package/dist/esm/index.js.map +0 -1
  375. package/dist/esm/internal/EventSource.js +0 -126
  376. package/dist/esm/internal/EventSource.js.map +0 -1
  377. package/dist/esm/internal/HydrateContext.js +0 -7
  378. package/dist/esm/internal/HydrateContext.js.map +0 -1
  379. package/dist/esm/internal/browser.js +0 -103
  380. package/dist/esm/internal/browser.js.map +0 -1
  381. package/dist/esm/internal/character-entities.js +0 -2134
  382. package/dist/esm/internal/character-entities.js.map +0 -1
  383. package/dist/esm/internal/chunks.js +0 -60
  384. package/dist/esm/internal/chunks.js.map +0 -1
  385. package/dist/esm/internal/errors.js +0 -46
  386. package/dist/esm/internal/errors.js.map +0 -1
  387. package/dist/esm/internal/indexRefCounter.js +0 -47
  388. package/dist/esm/internal/indexRefCounter.js.map +0 -1
  389. package/dist/esm/internal/module-augmentation.js +0 -2
  390. package/dist/esm/internal/module-augmentation.js.map +0 -1
  391. package/dist/esm/internal/parser.js +0 -596
  392. package/dist/esm/internal/parser.js.map +0 -1
  393. package/dist/esm/internal/parser2.js +0 -393
  394. package/dist/esm/internal/parser2.js.map +0 -1
  395. package/dist/esm/internal/server-parts.js +0 -109
  396. package/dist/esm/internal/server-parts.js.map +0 -1
  397. package/dist/esm/internal/server.js +0 -22
  398. package/dist/esm/internal/server.js.map +0 -1
  399. package/dist/esm/internal/utils.js +0 -119
  400. package/dist/esm/internal/utils.js.map +0 -1
  401. package/dist/esm/internal/v2/SyncPart.js +0 -5
  402. package/dist/esm/internal/v2/SyncPart.js.map +0 -1
  403. package/dist/esm/internal/v2/helpers.js +0 -12
  404. package/dist/esm/internal/v2/helpers.js.map +0 -1
  405. package/dist/esm/internal/v2/hydration-template.js.map +0 -1
  406. package/dist/esm/internal/v2/parts.js +0 -150
  407. package/dist/esm/internal/v2/parts.js.map +0 -1
  408. package/dist/esm/internal/v2/render-entry.js +0 -102
  409. package/dist/esm/internal/v2/render-entry.js.map +0 -1
  410. package/dist/esm/internal/v2/render-sync-parts.js +0 -265
  411. package/dist/esm/internal/v2/render-sync-parts.js.map +0 -1
  412. package/dist/esm/internal/v2/render.js +0 -521
  413. package/dist/esm/internal/v2/render.js.map +0 -1
  414. package/dist/esm/internal/v2/sync-parts.js +0 -102
  415. package/dist/esm/internal/v2/sync-parts.js.map +0 -1
  416. package/dist/esm/package.json +0 -4
  417. package/src/Directive.ts +0 -114
  418. package/src/ElementRef.ts +0 -148
  419. package/src/ElementSource.ts +0 -510
  420. package/src/Entry.ts +0 -28
  421. package/src/Hydrate.ts +0 -51
  422. package/src/Many.ts +0 -161
  423. package/src/Meta.ts +0 -45
  424. package/src/Part.ts +0 -154
  425. package/src/Placeholder.ts +0 -78
  426. package/src/Platform.ts +0 -70
  427. package/src/RenderContext.ts +0 -121
  428. package/src/Test.ts +0 -354
  429. package/src/Vitest.ts +0 -141
  430. package/src/compiler-tools.ts +0 -250
  431. package/src/internal/EventSource.ts +0 -188
  432. package/src/internal/HydrateContext.ts +0 -22
  433. package/src/internal/browser.ts +0 -138
  434. package/src/internal/character-entities.ts +0 -2136
  435. package/src/internal/chunks.ts +0 -89
  436. package/src/internal/errors.ts +0 -49
  437. package/src/internal/external.d.ts +0 -11
  438. package/src/internal/indexRefCounter.ts +0 -54
  439. package/src/internal/module-augmentation.ts +0 -44
  440. package/src/internal/parser.ts +0 -757
  441. package/src/internal/parser2.ts +0 -468
  442. package/src/internal/server-parts.ts +0 -161
  443. package/src/internal/server.ts +0 -37
  444. package/src/internal/utils.ts +0 -153
  445. package/src/internal/v2/SyncPart.ts +0 -112
  446. package/src/internal/v2/helpers.ts +0 -13
  447. package/src/internal/v2/hydration-template.ts +0 -308
  448. package/src/internal/v2/parts.ts +0 -254
  449. package/src/internal/v2/render-entry.ts +0 -131
  450. package/src/internal/v2/render-sync-parts.ts +0 -440
  451. package/src/internal/v2/render.ts +0 -813
  452. package/src/internal/v2/sync-parts.ts +0 -133
package/src/Render.ts CHANGED
@@ -1,84 +1,899 @@
1
+ import * as Cause from "effect/Cause";
2
+ import * as Effect from "effect/Effect";
3
+ import { constVoid, dual, flow, identity } from "effect/Function";
4
+ import * as Layer from "effect/Layer";
5
+ import { getOrUndefined, isNone, isOption, type Some } from "effect/Option";
6
+ import { isFunction, isNullish, isObject } from "effect/Predicate";
7
+ import { map as mapRecord } from "effect/Record";
8
+ import * as Scope from "effect/Scope";
9
+ import * as ServiceMap from "effect/ServiceMap";
10
+ import { isStream } from "effect/Stream";
11
+ import { Fx, Sink } from "@typed/fx";
12
+ import { CouldNotFindCommentError, isHydrationError } from "./errors.js";
13
+ import * as EventHandler from "./EventHandler.js";
14
+ import { type EventSource, makeEventSource } from "./EventSource.js";
15
+ import { HydrateContext, makeHydrateContext } from "./HydrateContext.js";
16
+ import { buildTemplateFragment } from "./internal/buildTemplateFragement.js";
17
+ import {
18
+ findNodePartEndComment,
19
+ getClassList,
20
+ makeAttributeValueUpdater,
21
+ makeBooleanUpdater,
22
+ makeClassListUpdater,
23
+ makeDatasetUpdater,
24
+ makeNodeUpdater,
25
+ makeTextContentUpdater,
26
+ } from "./internal/dom.js";
27
+ import { renderToString } from "./internal/encoding.js";
28
+ import type { HydrationHole, HydrationNode, HydrationTemplate } from "./internal/hydration.js";
29
+ import {
30
+ findHydratePath,
31
+ findHydrationHole,
32
+ findHydrationTemplateByHash,
33
+ getChildNodes,
34
+ getRendered,
35
+ } from "./internal/hydration.js";
36
+ import { type IndexRefCounter, makeRefCounter } from "./internal/IndexRefCounter.js";
37
+ import { keyToPartType } from "./internal/keyToPartType.js";
38
+ import { findPath } from "./internal/ParentChildNodes.js";
39
+ import { parse } from "./Parser.js";
40
+ import type { Renderable } from "./Renderable.js";
41
+ import { DomRenderEvent, type RenderEvent } from "./RenderEvent.js";
42
+ import * as RQ from "./RenderQueue.js";
43
+ import { RenderTemplate } from "./RenderTemplate.js";
44
+ import * as Template from "./Template.js";
45
+ import { getAllSiblingsBetween, isText, persistent, type Rendered } from "./Wire.js";
46
+
47
+ // Can be utilized to override the document for rendering
1
48
  /**
49
+ * A service that provides the `Document` interface for rendering.
50
+ *
51
+ * Defaults to the global `document` object. This can be overridden for testing
52
+ * or environments where the global document is not available or desired.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * import { CurrentRenderDocument } from "@typed/template/Render"
57
+ * import { Layer } from "effect"
58
+ *
59
+ * // Override document for testing
60
+ * const testDocument = new Document()
61
+ * const testLayer = Layer.succeed(CurrentRenderDocument, testDocument)
62
+ * ```
63
+ *
2
64
  * @since 1.0.0
65
+ * @category services
3
66
  */
4
-
5
- import * as Context from "@typed/context"
6
- import { Document } from "@typed/dom/Document"
7
- import type { DomServices, DomServicesElementParams } from "@typed/dom/DomServices"
8
- import type { GlobalThis } from "@typed/dom/GlobalThis"
9
- import { RootElement } from "@typed/dom/RootElement"
10
- import type { CurrentEnvironment } from "@typed/environment"
11
- import * as Fx from "@typed/fx/Fx"
12
- import { type Rendered } from "@typed/wire"
13
- import * as Effect from "effect/Effect"
14
- import { pipe } from "effect/Function"
15
- import * as Layer from "effect/Layer"
16
- import type * as Scope from "effect/Scope"
17
- import { attachRoot, renderTemplate } from "./internal/v2/render.js"
18
- import * as RenderContext from "./RenderContext.js"
19
- import { type RenderEvent } from "./RenderEvent.js"
20
- import { RenderTemplate } from "./RenderTemplate.js"
67
+ export const CurrentRenderDocument = ServiceMap.Reference<Document>("RenderDocument", {
68
+ defaultValue: () => document,
69
+ });
21
70
 
22
71
  /**
72
+ * A service that manages the queue of DOM updates.
73
+ *
74
+ * It ensures that DOM updates are batched and executed efficiently, often coordinating
75
+ * with browser painting cycles (e.g., via `requestAnimationFrame`).
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * import { CurrentRenderQueue } from "@typed/template/Render"
80
+ * import { MixedRenderQueue } from "@typed/template/RenderQueue"
81
+ * import { Layer } from "effect"
82
+ *
83
+ * // Use a custom render queue
84
+ * const customQueue = new MixedRenderQueue()
85
+ * const queueLayer = Layer.succeed(CurrentRenderQueue, customQueue)
86
+ * ```
87
+ *
23
88
  * @since 1.0.0
89
+ * @category services
24
90
  */
25
- export type ToRendered<T extends RenderEvent | null> = T extends null ? Rendered | null : Rendered
91
+ export const CurrentRenderQueue = ServiceMap.Reference<RQ.RenderQueue>("RenderQueue", {
92
+ defaultValue: () => new RQ.MixedRenderQueue(),
93
+ });
26
94
 
27
95
  /**
96
+ * A service that provides the default priority for rendering tasks.
97
+ *
98
+ * The default value is `RenderPriority.Raf(10)`, which typically schedules updates
99
+ * to occur before the next repaint.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { CurrentRenderPriority } from "@typed/template/Render"
104
+ * import { RenderPriority } from "@typed/template/RenderQueue"
105
+ * import { Layer } from "effect"
106
+ *
107
+ * // Use synchronous priority for immediate updates
108
+ * const syncLayer = Layer.succeed(CurrentRenderPriority, RenderPriority.Sync)
109
+ * ```
110
+ *
28
111
  * @since 1.0.0
112
+ * @category services
29
113
  */
30
- export const renderLayer = (
31
- window: Window & GlobalThis,
32
- options?: DomServicesElementParams
33
- ): Layer.Layer<
34
- | RenderTemplate
35
- | RenderContext.RenderContext
36
- | CurrentEnvironment
37
- | DomServices
38
- > =>
39
- Layer.provideMerge(
40
- RenderTemplate.layer(
41
- Effect.contextWith(
42
- (context: Context.Context<Document | RenderContext.RenderContext>) => {
43
- const [document, ctx] = pipe(
44
- context,
45
- Context.getMany(
46
- Document,
47
- RenderContext.RenderContext
48
- )
49
- )
50
-
51
- return renderTemplate(document, ctx)
52
- }
53
- )
54
- ),
55
- RenderContext.dom(window, options)
56
- )
114
+ export const CurrentRenderPriority = ServiceMap.Reference<number>("CurrentRenderPriority", {
115
+ defaultValue: () => RQ.RenderPriority.Raf(10),
116
+ });
57
117
 
58
118
  /**
119
+ * A Layer that provides the `RenderTemplate` service implemented for DOM rendering.
120
+ *
121
+ * This layer enables templates to be rendered as actual DOM nodes. It handles:
122
+ * - Parsing templates into DOM fragments.
123
+ * - Caching parsed templates.
124
+ * - Hydrating from existing DOM (if applicable).
125
+ * - Setting up event listeners.
126
+ * - Managing fine-grained updates to DOM nodes via `Fx` streams.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * import { Effect, Layer } from "effect"
131
+ * import { html } from "@typed/template"
132
+ * import { DomRenderTemplate, render } from "@typed/template/Render"
133
+ * import { Fx } from "@typed/fx"
134
+ *
135
+ * const program = Effect.gen(function* () {
136
+ * const template = html`<div>Hello, world!</div>`
137
+ *
138
+ * yield* render(template, document.body).pipe(
139
+ * Fx.drainLayer,
140
+ * Layer.provide(DomRenderTemplate),
141
+ * Layer.launch
142
+ * )
143
+ * })
144
+ * ```
145
+ *
59
146
  * @since 1.0.0
147
+ * @category layers
60
148
  */
61
- export function render<R, E, T extends RenderEvent | null>(
62
- rendered: Fx.Fx<T, E, R>
63
- ): Fx.Fx<ToRendered<T>, E, R | RenderTemplate | RenderContext.RenderContext | RootElement> {
64
- return Fx.fromFxEffect(Effect.contextWith((context) => {
65
- const [ctx, { rootElement }] = Context.getMany(
66
- context,
67
- RenderContext.RenderContext,
68
- RootElement
69
- )
149
+ export const DomRenderTemplate = Object.assign(
150
+ Layer.effect(
151
+ RenderTemplate,
152
+ Effect.gen(function* () {
153
+ const document = yield* CurrentRenderDocument;
154
+ const templateCache = new WeakMap<TemplateStringsArray, Template.Template>();
155
+ const getTemplate = (templateStrings: TemplateStringsArray) => {
156
+ let template = templateCache.get(templateStrings);
157
+ if (template === undefined) {
158
+ template = parse(templateStrings);
159
+ templateCache.set(templateStrings, template);
160
+ }
161
+ return template;
162
+ };
163
+ const entries = new WeakMap<
164
+ TemplateStringsArray,
165
+ {
166
+ template: Template.Template;
167
+ fragment: DocumentFragment;
168
+ }
169
+ >();
170
+ const getEntry = (templateStrings: TemplateStringsArray) => {
171
+ let entry = entries.get(templateStrings);
172
+ if (entry === undefined) {
173
+ const template = getTemplate(templateStrings);
174
+ const fragment = buildTemplateFragment(document, template);
175
+ entry = { template, fragment };
176
+ entries.set(templateStrings, entry);
177
+ }
178
+ return entry;
179
+ };
70
180
 
71
- return Fx.mapEffect(rendered, (what) => attachRoot(ctx.renderCache, rootElement, what))
72
- }))
73
- }
181
+ return <const Values extends ArrayLike<Renderable.Any>>(
182
+ templateStrings: TemplateStringsArray,
183
+ values: Values,
184
+ ): Fx.Fx<
185
+ RenderEvent,
186
+ Renderable.Error<Values[number]>,
187
+ Renderable.Services<Values[number]> | Scope.Scope
188
+ > =>
189
+ Fx.make<
190
+ RenderEvent,
191
+ Renderable.Error<Values[number]>,
192
+ Renderable.Services<Values[number]> | Scope.Scope
193
+ >(function render<RSink = never>(
194
+ sink: Sink.Sink<RenderEvent, Renderable.Error<Values[number]>, RSink>,
195
+ ): Effect.Effect<
196
+ unknown,
197
+ never,
198
+ Renderable.Services<Values[number]> | Scope.Scope | RSink
199
+ > {
200
+ return Effect.gen(function* () {
201
+ const entry = getEntry(templateStrings);
202
+ const template = entry.template;
203
+ const fragment = document.importNode(entry.fragment, true);
204
+ const ctx = yield* makeTemplateContext<Values, RSink>(document, values, sink.onFailure);
205
+
206
+ return yield* Effect.gen(function* () {
207
+ const hydration = attemptHydration(ctx, template.hash);
208
+
209
+ let effects: Array<Effect.Effect<void, any, any>>;
210
+ let rendered: Rendered | undefined;
211
+
212
+ if (hydration) {
213
+ effects = setupHydrationParts(template.parts, {
214
+ ...ctx,
215
+ ...hydration,
216
+ makeHydrateContext: (where: HydrationNode): HydrateContext => ({
217
+ where,
218
+ hydrate: true,
219
+ }),
220
+ });
221
+
222
+ rendered = getRendered(hydration.where);
223
+ } else {
224
+ effects = setupRenderParts(template.parts, fragment, ctx);
225
+ }
226
+
227
+ if (effects.length > 0) {
228
+ yield* Effect.all(
229
+ effects.map(flow(Effect.catchCause(ctx.onCause), Effect.forkIn(ctx.scope))),
230
+ );
231
+
232
+ if (ctx.expected > 0 && ctx.refCounter.expect(ctx.expected)) {
233
+ yield* ctx.refCounter.wait;
234
+ }
235
+ }
236
+
237
+ if (rendered === undefined) {
238
+ // If we have more than one child, we need to wrap them in a PersistentDocumentFragment
239
+ // so they can be diffed within other templates more than once.
240
+ rendered = persistent(document, template.hash, fragment);
241
+ }
242
+
243
+ // Setup our event listeners for our rendered content.
244
+ yield* ctx.eventSource.setup(rendered, ctx.scope);
245
+
246
+ // If we're hydrating, we need to mark this part of the stack as hydrated
247
+ if (hydration !== undefined) {
248
+ hydration.hydrateCtx.hydrate = false;
249
+ }
250
+
251
+ // Emit just once
252
+ yield* sink.onSuccess(DomRenderEvent(rendered));
253
+
254
+ // Ensure our templates last forever in the DOM environment
255
+ // so event listeners are kept attached to the current Scope.
256
+ return yield* Effect.never.pipe(
257
+ // Close our scope whenever the current Fiber is interrupted
258
+ Effect.onExit((exit) => Scope.close(ctx.scope, exit)),
259
+ );
260
+ }).pipe(
261
+ Effect.catchDefect((defect) => {
262
+ // If we are hydrating and we have a hydration error, we need to re-render the template without hydration
263
+ if (ctx.hydrateContext && ctx.hydrateContext.hydrate && isHydrationError(defect)) {
264
+ ctx.hydrateContext.hydrate = false;
265
+ return render(sink);
266
+ }
267
+ return sink.onFailure(Cause.die(defect));
268
+ }),
269
+ );
270
+ });
271
+ });
272
+ }),
273
+ ),
274
+ {
275
+ using: (document: Document) =>
276
+ DomRenderTemplate.pipe(Layer.provide(Layer.succeed(CurrentRenderDocument, document))),
277
+ } as const,
278
+ );
74
279
 
75
280
  /**
281
+ * A helper type to determine the rendered output type.
282
+ */
283
+ export type ToRendered<T extends RenderEvent | null> = Rendered | (T extends null ? null : never);
284
+
285
+ /**
286
+ * Mounts a reactive `Fx` stream of `RenderEvent`s to a specific DOM element.
287
+ *
288
+ * This function takes a stream of render events (usually from a template) and keeps
289
+ * the target DOM element updated. It handles:
290
+ * - Mounting the initial content.
291
+ * - Updating the content as new events are emitted.
292
+ * - Hydrating the content if hydration context is provided.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * import { Effect, Layer } from "effect"
297
+ * import { html } from "@typed/template"
298
+ * import { DomRenderTemplate, render } from "@typed/template/Render"
299
+ * import { Fx } from "@typed/fx"
300
+ * import * as RefSubject from "@typed/fx/RefSubject"
301
+ *
302
+ * const program = Effect.gen(function* () {
303
+ * const count = yield* RefSubject.make(0)
304
+ *
305
+ * const template = html`<div>
306
+ * <p>Count: ${count}</p>
307
+ * <button onclick=${RefSubject.increment(count)}>Increment</button>
308
+ * </div>`
309
+ *
310
+ * // Render to document.body
311
+ * yield* render(template, document.body).pipe(
312
+ * Fx.drainLayer,
313
+ * Layer.provide(DomRenderTemplate),
314
+ * Layer.launch
315
+ * )
316
+ * })
317
+ *
318
+ * // Can also use pipe syntax
319
+ * const program2 = Effect.gen(function* () {
320
+ * const template = html`<div>Hello</div>`
321
+ *
322
+ * yield* template.pipe(
323
+ * render(document.body),
324
+ * Fx.drainLayer,
325
+ * Layer.provide(DomRenderTemplate),
326
+ * Layer.launch
327
+ * )
328
+ * })
329
+ * ```
330
+ *
331
+ * @param fx - The `Fx` stream of content to render.
332
+ * @param where - The target DOM element to render into.
333
+ * @returns An `Fx` that emits the currently rendered DOM nodes.
76
334
  * @since 1.0.0
335
+ * @category rendering
77
336
  */
78
- export function renderToLayer<R, E, T extends RenderEvent | null>(
79
- rendered: Fx.Fx<T, E, R>
80
- ): Layer.Layer<never, never, RenderContext.RenderContext | RenderTemplate | RootElement | Exclude<R, Scope.Scope>> {
81
- return Fx.drainLayer(
82
- Fx.switchMapCause(render(rendered), (e) => Fx.fromEffect(Effect.logError(`Rendering Failure`, e)))
83
- )
337
+ export const render: {
338
+ (
339
+ where: HTMLElement,
340
+ ): <A extends RenderEvent | null, E, R>(fx: Fx.Fx<A, E, R>) => Fx.Fx<ToRendered<A>, E, R>;
341
+ <A extends RenderEvent | null, E, R>(
342
+ fx: Fx.Fx<A, E, R>,
343
+ where: HTMLElement,
344
+ ): Fx.Fx<ToRendered<A>, E, R>;
345
+ } = dual(2, function render<
346
+ T extends RenderEvent | null,
347
+ R,
348
+ E,
349
+ >(rendered: Fx.Fx<T, E, R>, rootElement: HTMLElement): Fx.Fx<ToRendered<T>, E, R> {
350
+ return Fx.provide(
351
+ Fx.mapEffect(rendered, (what) => attachRoot(rootElement, what)),
352
+ Layer.syncServices(() => makeHydrateContext(rootElement)),
353
+ );
354
+ });
355
+
356
+ const renderCache = new WeakMap<HTMLElement, Rendered>();
357
+ function attachRoot<A extends RenderEvent | null>(
358
+ where: HTMLElement,
359
+ what: A, // TODO: Should we support HTML RenderEvents here too?,
360
+ ): Effect.Effect<ToRendered<A>> {
361
+ return Effect.sync(() => {
362
+ const rendered = what?.valueOf() as Rendered;
363
+ const previous = renderCache.get(where);
364
+ if (rendered !== previous) {
365
+ if (previous && !rendered) removeChildren(where, previous);
366
+ renderCache.set(where, rendered || null);
367
+ if (rendered) replaceChildren(where, rendered);
368
+ return rendered;
369
+ }
370
+
371
+ return previous;
372
+ });
373
+ }
374
+
375
+ function removeChildren(where: HTMLElement, previous: Rendered) {
376
+ for (const node of getNodesFromRendered(previous)) {
377
+ where.removeChild(node);
378
+ }
379
+ }
380
+
381
+ function replaceChildren(where: HTMLElement, wire: Rendered) {
382
+ where.replaceChildren(...getNodesFromRendered(wire));
383
+ }
384
+
385
+ function getNodesFromRendered(rendered: Rendered): Array<globalThis.Node> {
386
+ const value = rendered.valueOf() as globalThis.Node | Array<globalThis.Node>;
387
+ return Array.isArray(value) ? value : [value];
388
+ }
389
+
390
+ function setupRenderParts(
391
+ parts: Template.Template["parts"],
392
+ fragment: DocumentFragment,
393
+ ctx: TemplateContext,
394
+ ): Array<Effect.Effect<unknown>> {
395
+ const effects: Array<Effect.Effect<unknown>> = [];
396
+ for (const [part, path] of parts) {
397
+ const effect = setupRenderPart(part, findPath(fragment, path), ctx);
398
+ if (effect !== undefined) {
399
+ effects.push(effect);
400
+ }
401
+ }
402
+
403
+ return effects;
404
+ }
405
+
406
+ const withCurrentRenderPriority = (
407
+ key: unknown,
408
+ index: number,
409
+ ctx: TemplateContext,
410
+ f: () => void,
411
+ ) => {
412
+ return Effect.tap(Effect.service(CurrentRenderPriority), (priority) =>
413
+ Effect.sync(() => {
414
+ const dispose = addDisposable(
415
+ ctx,
416
+ ctx.renderQueue.add(
417
+ key,
418
+ () => {
419
+ f();
420
+ ctx.refCounter.release(index);
421
+ },
422
+ () => {
423
+ dispose();
424
+ },
425
+ priority,
426
+ ),
427
+ );
428
+ }),
429
+ );
430
+ };
431
+
432
+ function setupRenderPart<E = never, R = never>(
433
+ part: Template.PartNode | Template.SparsePartNode,
434
+ node: Node,
435
+ ctx: TemplateContext<R>,
436
+ ): Effect.Effect<unknown, E, R> | void {
437
+ switch (part._tag) {
438
+ case "node": {
439
+ return renderValue(
440
+ ctx,
441
+ part.index,
442
+ makeNodeUpdater(
443
+ ctx.document,
444
+ findNodePartEndComment(node as HTMLElement | SVGElement, part.index),
445
+ ),
446
+ );
447
+ }
448
+ case "attr": {
449
+ const element = node as HTMLElement | SVGElement;
450
+ const setAttr = makeAttributeValueUpdater(
451
+ element,
452
+ element.getAttributeNode(part.name) ?? ctx.document.createAttribute(part.name),
453
+ );
454
+ return renderValue(ctx, part.index, (value) => setAttr(renderToString(value, "")));
455
+ }
456
+ case "boolean-part": {
457
+ const updater = makeBooleanUpdater(node as HTMLElement | SVGElement, part.name);
458
+ return renderValue(ctx, part.index, (value) => updater(!!value));
459
+ }
460
+ case "className-part": {
461
+ const updater = makeClassListUpdater(node as HTMLElement | SVGElement);
462
+ return renderValue(ctx, part.index, (value) => updater(getClassList(value)));
463
+ }
464
+ case "comment-part":
465
+ return renderValue(ctx, part.index, makeTextContentUpdater(node as Comment));
466
+ case "data":
467
+ return setupDataset<E, R>(node as HTMLElement | SVGElement, ctx, part.index);
468
+ case "event":
469
+ return setupEventHandler(node as Element, ctx, part.index, part.name);
470
+ case "property":
471
+ return renderValue(
472
+ ctx,
473
+ part.index,
474
+ setupPropertSetter(node as HTMLElement | SVGElement, part.name),
475
+ );
476
+ case "properties":
477
+ return setupProperties<E, R>(node as HTMLElement | SVGElement, ctx, part.index);
478
+ case "ref":
479
+ return setupRef<R>(node as HTMLElement | SVGElement, ctx, part.index);
480
+ case "sparse-attr": {
481
+ const element = node as HTMLElement | SVGElement;
482
+ const attr = element.getAttributeNode(part.name) ?? ctx.document.createAttribute(part.name);
483
+ return renderSparseTextContent(
484
+ element,
485
+ part.nodes,
486
+ ++ctx.dynamicIndex,
487
+ ctx,
488
+ makeAttributeValueUpdater(element, attr),
489
+ );
490
+ }
491
+ case "sparse-class-name": {
492
+ const updater = makeClassListUpdater(node as HTMLElement | SVGElement);
493
+ return renderSparsePart(
494
+ part.nodes,
495
+ ++ctx.dynamicIndex,
496
+ ctx,
497
+ (classNames) => updater(getClassList(classNames)),
498
+ (value) => value,
499
+ );
500
+ }
501
+ case "sparse-comment":
502
+ return renderSparseTextContent(node as Comment, part.nodes, ++ctx.dynamicIndex, ctx);
503
+ case "text-part":
504
+ return renderValue(ctx, part.index, makeTextContentUpdater(node as HTMLElement | SVGElement));
505
+ case "sparse-text":
506
+ return renderSparseTextContent(
507
+ node as HTMLElement | SVGElement,
508
+ part.nodes,
509
+ ++ctx.dynamicIndex,
510
+ ctx,
511
+ );
512
+ }
513
+ }
514
+
515
+ type HydrateTemplateContext<R = never> = TemplateContext<R> & {
516
+ where: HydrationNode;
517
+ makeHydrateContext: (where: HydrationNode) => HydrateContext;
518
+ };
519
+
520
+ function setupHydrationParts<E, R>(
521
+ parts: Template.Template["parts"],
522
+ ctx: HydrateTemplateContext<R>,
523
+ ): Array<Effect.Effect<unknown, E, R>> {
524
+ const effects: Array<Effect.Effect<unknown, E, R>> = [];
525
+ for (const [part, path] of parts) {
526
+ const effect = setupHydrationPart<E, R>(part, path, ctx);
527
+ if (effect !== undefined) {
528
+ effects.push(effect);
529
+ }
530
+ }
531
+
532
+ return effects;
533
+ }
534
+
535
+ function setupHydrationPart<E, R>(
536
+ part: Template.PartNode | Template.SparsePartNode,
537
+ path: ReadonlyArray<number>,
538
+ ctx: HydrateTemplateContext<R>,
539
+ ): Effect.Effect<unknown, E, R> | void {
540
+ switch (part._tag) {
541
+ case "node": {
542
+ const hole = findHydrationHole(getChildNodes(ctx.where), part.index);
543
+ if (hole === null) throw new CouldNotFindCommentError(part.index);
544
+ return setupHydratedNodePart(part, hole, ctx);
545
+ }
546
+ default:
547
+ return setupRenderPart(part, findHydratePath(ctx.where, path), ctx);
548
+ }
549
+ }
550
+
551
+ function renderSparsePart<E, R, T = unknown>(
552
+ parts: Template.SparsePartNode["nodes"],
553
+ index: number,
554
+ ctx: TemplateContext<R>,
555
+ f: (value: ReadonlyArray<string | NoInfer<T>>) => void,
556
+ transformValue: (value: unknown) => T,
557
+ ): Effect.Effect<unknown, E, R> {
558
+ ctx.expected++;
559
+ return Fx.tuple(
560
+ ...parts.map((node) => {
561
+ if (node._tag === "text") return Fx.succeed(node.value);
562
+ return Fx.map(liftRenderableToFx<E, R>(ctx.values[node.index]), transformValue);
563
+ }),
564
+ ).pipe(Fx.observe((values) => withCurrentRenderPriority(f, index, ctx, () => f(values))));
565
+ }
566
+
567
+ function renderSparseTextContent<E, R>(
568
+ node: Node,
569
+ nodes: Template.SparsePartNode["nodes"],
570
+ index: number,
571
+ ctx: TemplateContext<R>,
572
+ onTextContent: (value: string) => void = makeTextContentUpdater(node),
573
+ ): Effect.Effect<unknown, E, R> {
574
+ return renderSparsePart(
575
+ nodes,
576
+ index,
577
+ ctx,
578
+ (texts) => onTextContent(texts.join("")),
579
+ (value) => renderToString(value, ""),
580
+ );
581
+ }
582
+
583
+ function renderValue<E, R, X>(
584
+ ctx: TemplateContext,
585
+ index: number,
586
+ f: (value: unknown) => X,
587
+ ): void | X | Effect.Effect<unknown, E, R> {
588
+ return matchRenderable(ctx.values[index], {
589
+ Primitive: f,
590
+ Effect: (effect) => {
591
+ ctx.expected++;
592
+ return effect.pipe(
593
+ Effect.flatMap((value) => withCurrentRenderPriority(f, index, ctx, () => f(value))),
594
+ );
595
+ },
596
+ Fx: (fx) => {
597
+ ctx.expected++;
598
+ return fx.run(
599
+ Sink.make(ctx.onCause, (value) => withCurrentRenderPriority(f, index, ctx, () => f(value))),
600
+ );
601
+ },
602
+ });
603
+ }
604
+
605
+ function matchRenderable<X, A, B, C>(
606
+ renderable: Renderable.Any,
607
+ matches: {
608
+ Primitive: (value: X) => A;
609
+ Effect: (effect: Effect.Effect<X>) => B;
610
+ Fx: (fx: Fx.Fx<X>) => C;
611
+ },
612
+ ): A | B | C | void {
613
+ if (isNullish(renderable)) return;
614
+ else if (Fx.isFx(renderable)) {
615
+ return matches.Fx(renderable as any);
616
+ } else if (isStream(renderable)) {
617
+ return matches.Fx(Fx.fromStream(renderable));
618
+ } else if (Effect.isEffect(renderable)) {
619
+ return matches.Effect(renderable as any);
620
+ } else if (Array.isArray(renderable)) {
621
+ return matches.Fx(liftRenderableToFx(renderable));
622
+ } else {
623
+ return matches.Primitive(renderable);
624
+ }
625
+ }
626
+
627
+ function setupRenderProperties<E = never, R = never>(
628
+ properties: Record<string, unknown>,
629
+ element: HTMLElement | SVGElement,
630
+ ctx: TemplateContext<R>,
631
+ ): Effect.Effect<unknown, E, R> | void {
632
+ const effects: Array<Effect.Effect<unknown, E, R>> = [];
633
+ for (const [key, value] of Object.entries(properties)) {
634
+ const index = ctx.dynamicIndex++;
635
+ const part = makePropertiesPart(keyToPartType(key), index);
636
+ const effect = setupRenderPart(part, element, { ...ctx, values: makeArrayLike(index, value) });
637
+ if (effect !== undefined) {
638
+ effects.push(effect);
639
+ }
640
+ }
641
+ if (effects.length > 0) {
642
+ ctx.expected += effects.length;
643
+ return Effect.all(effects, { concurrency: "unbounded" });
644
+ }
645
+ }
646
+
647
+ type PartType = ReturnType<typeof keyToPartType>;
648
+
649
+ function makePropertiesPart([partType, partName]: PartType, index: number) {
650
+ switch (partType) {
651
+ case "attr":
652
+ return new Template.AttrPartNode(partName, index);
653
+ case "boolean":
654
+ return new Template.BooleanPartNode(partName, index);
655
+ case "class":
656
+ return new Template.ClassNamePartNode(index);
657
+ case "data":
658
+ return new Template.DataPartNode(index);
659
+ case "event":
660
+ return new Template.EventPartNode(partName, index);
661
+ case "property":
662
+ return new Template.PropertyPartNode(partName, index);
663
+ case "properties":
664
+ return new Template.PropertiesPartNode(index);
665
+ case "ref":
666
+ return new Template.RefPartNode(index);
667
+ default:
668
+ // oxlint-disable-next-line typescript/restrict-template-expressions
669
+ throw new Error(`Unknown part type: ${partType}`);
670
+ }
671
+ }
672
+
673
+ export type TemplateContext<R = never> = {
674
+ readonly document: Document;
675
+ readonly renderQueue: RQ.RenderQueue;
676
+ readonly disposables: Set<Disposable>;
677
+ readonly eventSource: EventSource;
678
+ readonly refCounter: IndexRefCounter;
679
+ readonly scope: Scope.Closeable;
680
+ readonly values: ArrayLike<Renderable<unknown, any, any>>;
681
+ readonly services: ServiceMap.ServiceMap<R | Scope.Scope>;
682
+ readonly onCause: (cause: Cause.Cause<any>) => Effect.Effect<unknown>;
683
+
684
+ /**
685
+ * @internal
686
+ */
687
+ expected: number;
688
+ /**
689
+ * @internal
690
+ */
691
+ dynamicIndex: number;
692
+
693
+ readonly hydrateContext: HydrateContext | undefined;
694
+ };
695
+
696
+ const makeTemplateContext = Effect.fn(function* <
697
+ Values extends ArrayLike<Renderable.Any>,
698
+ RSink = never,
699
+ >(
700
+ document: Document,
701
+ values: Values,
702
+ onCause: (
703
+ cause: Cause.Cause<Renderable.Error<Values[number]>>,
704
+ ) => Effect.Effect<unknown, never, RSink>,
705
+ ) {
706
+ const renderQueue: RQ.RenderQueue = yield* CurrentRenderQueue;
707
+ const services: ServiceMap.ServiceMap<Renderable.Services<Values[number]> | RSink | Scope.Scope> =
708
+ yield* Effect.services<Renderable.Services<Values[number]> | RSink | Scope.Scope>();
709
+ const refCounter: IndexRefCounter = yield* makeRefCounter;
710
+ const scope: Scope.Closeable = yield* Scope.fork(ServiceMap.get(services, Scope.Scope));
711
+ const eventSource: EventSource = makeEventSource();
712
+ const servicesWithScope = ServiceMap.add(services, Scope.Scope, scope);
713
+ const hydrateContext = ServiceMap.getOption(services, HydrateContext);
714
+ const ctx: TemplateContext<Renderable.Services<Values[number]> | RSink | Scope.Scope> = {
715
+ services: ServiceMap.add(services, Scope.Scope, scope),
716
+ document,
717
+ renderQueue,
718
+ disposables: new Set(),
719
+ eventSource,
720
+ refCounter,
721
+ scope,
722
+ values,
723
+ onCause: flow(onCause, Effect.provideServices(servicesWithScope)),
724
+ expected: 0,
725
+ dynamicIndex: values.length,
726
+ hydrateContext: getOrUndefined(hydrateContext),
727
+ };
728
+
729
+ yield* Scope.addFinalizer(
730
+ scope,
731
+ Effect.sync(() => ctx.disposables.forEach(dispose)),
732
+ );
733
+
734
+ return ctx;
735
+ });
736
+
737
+ function liftRenderableToFx<E = never, R = never>(
738
+ renderable: Renderable<unknown, E, R>,
739
+ ): Fx.Fx<any, E, R> {
740
+ switch (typeof renderable) {
741
+ case "undefined":
742
+ case "function":
743
+ case "object": {
744
+ if (isNullish(renderable)) {
745
+ return Fx.null;
746
+ } else if (Array.isArray(renderable)) {
747
+ return Fx.tuple(...renderable.map(liftRenderableToFx<E, R>));
748
+ } else if (isOption(renderable)) {
749
+ return isNone(renderable) ? Fx.null : liftRenderableToFx((renderable as Some<any>).value);
750
+ } else if (Effect.isEffect(renderable)) {
751
+ return Fx.unwrap(Effect.map(renderable, liftRenderableToFx<E, R>));
752
+ } else if (Fx.isFx(renderable)) {
753
+ return renderable;
754
+ } else {
755
+ return Fx.struct(mapRecord(renderable, liftRenderableToFx));
756
+ }
757
+ }
758
+ default:
759
+ return Fx.succeed(renderable);
760
+ }
761
+ }
762
+
763
+ function addDisposable(ctx: TemplateContext, disposable: Disposable) {
764
+ ctx.disposables.add(disposable);
765
+ return () => ctx.disposables.delete(disposable);
766
+ }
767
+
768
+ function dispose(disposable: Disposable) {
769
+ disposable[Symbol.dispose]();
770
+ }
771
+
772
+ function makeArrayLike<A>(index: number, value: A): ArrayLike<A> {
773
+ return {
774
+ length: index + 1,
775
+ [index]: value,
776
+ };
777
+ }
778
+
779
+ export function attemptHydration(
780
+ ctx: TemplateContext,
781
+ hash: string,
782
+ ): { readonly where: HydrationTemplate; readonly hydrateCtx: HydrateContext } | undefined {
783
+ if (ctx.hydrateContext && ctx.hydrateContext.hydrate) {
784
+ const where = findHydrationTemplateByHash(ctx.hydrateContext, hash);
785
+ if (where === null) {
786
+ ctx.hydrateContext.hydrate = false;
787
+ return;
788
+ } else {
789
+ return { where, hydrateCtx: ctx.hydrateContext };
790
+ }
791
+ }
792
+ }
793
+
794
+ function setupEventHandler(element: Element, ctx: TemplateContext, index: number, name: string) {
795
+ const value = ctx.values[index];
796
+ if (isNullish(value)) return;
797
+ ctx.eventSource.addEventListener(
798
+ element,
799
+ name,
800
+ EventHandler.fromEffectOrEventHandler(
801
+ value as
802
+ | Effect.Effect<unknown, never, never>
803
+ | EventHandler.EventHandler<Event, never, never>,
804
+ ).pipe(EventHandler.provide(ctx.services), EventHandler.catchCause(ctx.onCause)),
805
+ );
806
+ }
807
+
808
+ function setupDataset<E, R>(
809
+ element: HTMLElement | SVGElement,
810
+ ctx: TemplateContext<R>,
811
+ index: number,
812
+ ): Effect.Effect<unknown, E, R> | void {
813
+ const value = ctx.values[index];
814
+ if (isNullish(value)) return;
815
+ // Special case to convert sync object to data-* attributes
816
+ if (isObject(value)) {
817
+ const effects: Array<Effect.Effect<unknown, E, R>> = [];
818
+ for (const [k, v] of Object.entries(value)) {
819
+ const index = ctx.dynamicIndex++;
820
+ const part = makePropertiesPart(["attr", `data-${k}`], index);
821
+ const effect = setupRenderPart<E, R>(part, element, {
822
+ ...ctx,
823
+ values: makeArrayLike(index, v),
824
+ });
825
+ if (effect !== undefined) {
826
+ effects.push(effect);
827
+ }
828
+ }
829
+
830
+ ctx.expected += effects.length;
831
+
832
+ return Effect.all(effects, { concurrency: "unbounded" });
833
+ }
834
+ return renderValue(ctx, index, makeDatasetUpdater(element));
835
+ }
836
+
837
+ function setupProperties<E, R>(
838
+ element: HTMLElement | SVGElement,
839
+ ctx: TemplateContext<R>,
840
+ index: number,
841
+ ) {
842
+ const setupIfObject = (props: unknown) => {
843
+ if (isObject(props)) {
844
+ return setupRenderProperties<E, R>(props as Record<string, unknown>, element, ctx);
845
+ }
846
+ };
847
+
848
+ return matchRenderable(ctx.values[index], {
849
+ Primitive: setupIfObject,
850
+ Effect: Effect.tap(flow(setupIfObject, Effect.succeed)),
851
+ Fx: flow(
852
+ Fx.switchMapEffect((props) => setupIfObject(props) || Effect.void),
853
+ Fx.drain,
854
+ Effect.provideService(Scope.Scope, ctx.scope),
855
+ ),
856
+ });
857
+ }
858
+
859
+ function setupRef<R>(element: HTMLElement | SVGElement, ctx: TemplateContext<R>, index: number) {
860
+ const renderable = ctx.values[index];
861
+ if (isNullish(renderable)) return;
862
+ if (isFunction(renderable)) {
863
+ return matchRenderable((renderable as Function)(element), {
864
+ Primitive: constVoid,
865
+ Effect: identity,
866
+ Fx: Fx.drain,
867
+ });
868
+ }
869
+ throw new Error("Invalid value provided to ref part");
870
+ }
871
+
872
+ function setupPropertSetter(element: Element, name: string) {
873
+ return (value: unknown) => {
874
+ (element as any)[name] = value;
875
+ };
876
+ }
877
+
878
+ function setupHydratedNodePart<E, R>(
879
+ part: Template.NodePart,
880
+ hole: HydrationHole,
881
+ ctx: HydrateTemplateContext<R>,
882
+ ): Effect.Effect<unknown, E, R> | void {
883
+ const nestedCtx = ctx.makeHydrateContext(hole);
884
+ const previousNodes = getAllSiblingsBetween(hole.startComment, hole.endComment);
885
+ const text = previousNodes.length === 3 && isText(previousNodes[1]) ? previousNodes[1] : null;
886
+
887
+ const effect = renderValue<E, R, void>(
888
+ ctx,
889
+ part.index,
890
+ makeNodeUpdater(
891
+ ctx.document,
892
+ hole.endComment,
893
+ text,
894
+ text === null ? previousNodes : [hole.startComment, text, hole.endComment],
895
+ ),
896
+ );
897
+ if (effect === undefined) return;
898
+ return Effect.provideService(effect, HydrateContext, nestedCtx);
84
899
  }