@typed/template 0.13.0 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. package/README.md +108 -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 +297 -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 +22 -223
  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 +409 -0
  94. package/src/Parser.test.ts +924 -0
  95. package/src/Parser.ts +598 -10
  96. package/src/Render.test.ts +338 -0
  97. package/src/Render.ts +878 -63
  98. package/src/RenderEvent.ts +169 -40
  99. package/src/RenderQueue.ts +290 -383
  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/tsconfig.json +6 -0
  120. package/Directive/package.json +0 -6
  121. package/ElementRef/package.json +0 -6
  122. package/ElementSource/package.json +0 -6
  123. package/Entry/package.json +0 -6
  124. package/EventHandler/package.json +0 -6
  125. package/Html/package.json +0 -6
  126. package/HtmlChunk/package.json +0 -6
  127. package/Hydrate/package.json +0 -6
  128. package/LICENSE +0 -21
  129. package/Many/package.json +0 -6
  130. package/Meta/package.json +0 -6
  131. package/Parser/package.json +0 -6
  132. package/Part/package.json +0 -6
  133. package/Placeholder/package.json +0 -6
  134. package/Platform/package.json +0 -6
  135. package/Render/package.json +0 -6
  136. package/RenderContext/package.json +0 -6
  137. package/RenderEvent/package.json +0 -6
  138. package/RenderQueue/package.json +0 -6
  139. package/RenderTemplate/package.json +0 -6
  140. package/Renderable/package.json +0 -6
  141. package/Template/package.json +0 -6
  142. package/Test/package.json +0 -6
  143. package/Vitest/package.json +0 -6
  144. package/compiler-tools/package.json +0 -6
  145. package/dist/cjs/Directive.js +0 -76
  146. package/dist/cjs/Directive.js.map +0 -1
  147. package/dist/cjs/ElementRef.js +0 -92
  148. package/dist/cjs/ElementRef.js.map +0 -1
  149. package/dist/cjs/ElementSource.js +0 -242
  150. package/dist/cjs/ElementSource.js.map +0 -1
  151. package/dist/cjs/Entry.js +0 -6
  152. package/dist/cjs/Entry.js.map +0 -1
  153. package/dist/cjs/EventHandler.js +0 -76
  154. package/dist/cjs/EventHandler.js.map +0 -1
  155. package/dist/cjs/Html.js +0 -224
  156. package/dist/cjs/Html.js.map +0 -1
  157. package/dist/cjs/HtmlChunk.js +0 -306
  158. package/dist/cjs/HtmlChunk.js.map +0 -1
  159. package/dist/cjs/Hydrate.js +0 -43
  160. package/dist/cjs/Hydrate.js.map +0 -1
  161. package/dist/cjs/Many.js +0 -66
  162. package/dist/cjs/Many.js.map +0 -1
  163. package/dist/cjs/Meta.js +0 -50
  164. package/dist/cjs/Meta.js.map +0 -1
  165. package/dist/cjs/Parser.js +0 -19
  166. package/dist/cjs/Parser.js.map +0 -1
  167. package/dist/cjs/Part.js +0 -6
  168. package/dist/cjs/Part.js.map +0 -1
  169. package/dist/cjs/Placeholder.js +0 -34
  170. package/dist/cjs/Placeholder.js.map +0 -1
  171. package/dist/cjs/Platform.js +0 -66
  172. package/dist/cjs/Platform.js.map +0 -1
  173. package/dist/cjs/Render.js +0 -50
  174. package/dist/cjs/Render.js.map +0 -1
  175. package/dist/cjs/RenderContext.js +0 -67
  176. package/dist/cjs/RenderContext.js.map +0 -1
  177. package/dist/cjs/RenderEvent.js +0 -52
  178. package/dist/cjs/RenderEvent.js.map +0 -1
  179. package/dist/cjs/RenderQueue.js +0 -341
  180. package/dist/cjs/RenderQueue.js.map +0 -1
  181. package/dist/cjs/RenderTemplate.js +0 -26
  182. package/dist/cjs/RenderTemplate.js.map +0 -1
  183. package/dist/cjs/Renderable.js +0 -6
  184. package/dist/cjs/Renderable.js.map +0 -1
  185. package/dist/cjs/Template.js +0 -305
  186. package/dist/cjs/Template.js.map +0 -1
  187. package/dist/cjs/Test.js +0 -184
  188. package/dist/cjs/Test.js.map +0 -1
  189. package/dist/cjs/Vitest.js +0 -52
  190. package/dist/cjs/Vitest.js.map +0 -1
  191. package/dist/cjs/compiler-tools.js +0 -100
  192. package/dist/cjs/compiler-tools.js.map +0 -1
  193. package/dist/cjs/index.js +0 -138
  194. package/dist/cjs/index.js.map +0 -1
  195. package/dist/cjs/internal/EventSource.js +0 -129
  196. package/dist/cjs/internal/EventSource.js.map +0 -1
  197. package/dist/cjs/internal/HydrateContext.js +0 -13
  198. package/dist/cjs/internal/HydrateContext.js.map +0 -1
  199. package/dist/cjs/internal/browser.js +0 -110
  200. package/dist/cjs/internal/browser.js.map +0 -1
  201. package/dist/cjs/internal/character-entities.js +0 -2141
  202. package/dist/cjs/internal/character-entities.js.map +0 -1
  203. package/dist/cjs/internal/chunks.js +0 -68
  204. package/dist/cjs/internal/chunks.js.map +0 -1
  205. package/dist/cjs/internal/errors.js +0 -52
  206. package/dist/cjs/internal/errors.js.map +0 -1
  207. package/dist/cjs/internal/indexRefCounter.js +0 -52
  208. package/dist/cjs/internal/indexRefCounter.js.map +0 -1
  209. package/dist/cjs/internal/module-augmentation.js +0 -6
  210. package/dist/cjs/internal/module-augmentation.js.map +0 -1
  211. package/dist/cjs/internal/parser.js +0 -568
  212. package/dist/cjs/internal/parser.js.map +0 -1
  213. package/dist/cjs/internal/parser2.js +0 -382
  214. package/dist/cjs/internal/parser2.js.map +0 -1
  215. package/dist/cjs/internal/server-parts.js +0 -124
  216. package/dist/cjs/internal/server-parts.js.map +0 -1
  217. package/dist/cjs/internal/server.js +0 -48
  218. package/dist/cjs/internal/server.js.map +0 -1
  219. package/dist/cjs/internal/utils.js +0 -136
  220. package/dist/cjs/internal/utils.js.map +0 -1
  221. package/dist/cjs/internal/v2/SyncPart.js +0 -6
  222. package/dist/cjs/internal/v2/SyncPart.js.map +0 -1
  223. package/dist/cjs/internal/v2/helpers.js +0 -15
  224. package/dist/cjs/internal/v2/helpers.js.map +0 -1
  225. package/dist/cjs/internal/v2/hydration-template.js +0 -269
  226. package/dist/cjs/internal/v2/hydration-template.js.map +0 -1
  227. package/dist/cjs/internal/v2/parts.js +0 -169
  228. package/dist/cjs/internal/v2/parts.js.map +0 -1
  229. package/dist/cjs/internal/v2/render-entry.js +0 -110
  230. package/dist/cjs/internal/v2/render-entry.js.map +0 -1
  231. package/dist/cjs/internal/v2/render-sync-parts.js +0 -318
  232. package/dist/cjs/internal/v2/render-sync-parts.js.map +0 -1
  233. package/dist/cjs/internal/v2/render.js +0 -592
  234. package/dist/cjs/internal/v2/render.js.map +0 -1
  235. package/dist/cjs/internal/v2/sync-parts.js +0 -115
  236. package/dist/cjs/internal/v2/sync-parts.js.map +0 -1
  237. package/dist/dts/Directive.d.ts +0 -70
  238. package/dist/dts/Directive.d.ts.map +0 -1
  239. package/dist/dts/ElementRef.d.ts +0 -42
  240. package/dist/dts/ElementRef.d.ts.map +0 -1
  241. package/dist/dts/ElementSource.d.ts +0 -77
  242. package/dist/dts/ElementSource.d.ts.map +0 -1
  243. package/dist/dts/Entry.d.ts +0 -26
  244. package/dist/dts/Entry.d.ts.map +0 -1
  245. package/dist/dts/EventHandler.d.ts +0 -73
  246. package/dist/dts/EventHandler.d.ts.map +0 -1
  247. package/dist/dts/Html.d.ts +0 -35
  248. package/dist/dts/Html.d.ts.map +0 -1
  249. package/dist/dts/HtmlChunk.d.ts +0 -56
  250. package/dist/dts/HtmlChunk.d.ts.map +0 -1
  251. package/dist/dts/Hydrate.d.ts +0 -19
  252. package/dist/dts/Hydrate.d.ts.map +0 -1
  253. package/dist/dts/Many.d.ts +0 -32
  254. package/dist/dts/Many.d.ts.map +0 -1
  255. package/dist/dts/Meta.d.ts +0 -33
  256. package/dist/dts/Meta.d.ts.map +0 -1
  257. package/dist/dts/Parser.d.ts +0 -13
  258. package/dist/dts/Parser.d.ts.map +0 -1
  259. package/dist/dts/Part.d.ts +0 -121
  260. package/dist/dts/Part.d.ts.map +0 -1
  261. package/dist/dts/Placeholder.d.ts +0 -48
  262. package/dist/dts/Placeholder.d.ts.map +0 -1
  263. package/dist/dts/Platform.d.ts +0 -21
  264. package/dist/dts/Platform.d.ts.map +0 -1
  265. package/dist/dts/Render.d.ts +0 -31
  266. package/dist/dts/Render.d.ts.map +0 -1
  267. package/dist/dts/RenderContext.d.ts +0 -70
  268. package/dist/dts/RenderContext.d.ts.map +0 -1
  269. package/dist/dts/RenderEvent.d.ts +0 -42
  270. package/dist/dts/RenderEvent.d.ts.map +0 -1
  271. package/dist/dts/RenderQueue.d.ts +0 -103
  272. package/dist/dts/RenderQueue.d.ts.map +0 -1
  273. package/dist/dts/RenderTemplate.d.ts +0 -25
  274. package/dist/dts/RenderTemplate.d.ts.map +0 -1
  275. package/dist/dts/Renderable.d.ts +0 -28
  276. package/dist/dts/Renderable.d.ts.map +0 -1
  277. package/dist/dts/Template.d.ts.map +0 -1
  278. package/dist/dts/Test.d.ts +0 -85
  279. package/dist/dts/Test.d.ts.map +0 -1
  280. package/dist/dts/Vitest.d.ts +0 -43
  281. package/dist/dts/Vitest.d.ts.map +0 -1
  282. package/dist/dts/compiler-tools.d.ts +0 -143
  283. package/dist/dts/compiler-tools.d.ts.map +0 -1
  284. package/dist/dts/index.d.ts +0 -65
  285. package/dist/dts/index.d.ts.map +0 -1
  286. package/dist/dts/internal/EventSource.d.ts +0 -13
  287. package/dist/dts/internal/EventSource.d.ts.map +0 -1
  288. package/dist/dts/internal/HydrateContext.d.ts +0 -2
  289. package/dist/dts/internal/HydrateContext.d.ts.map +0 -1
  290. package/dist/dts/internal/browser.d.ts +0 -8
  291. package/dist/dts/internal/browser.d.ts.map +0 -1
  292. package/dist/dts/internal/character-entities.d.ts +0 -2133
  293. package/dist/dts/internal/character-entities.d.ts.map +0 -1
  294. package/dist/dts/internal/chunks.d.ts +0 -23
  295. package/dist/dts/internal/chunks.d.ts.map +0 -1
  296. package/dist/dts/internal/errors.d.ts +0 -22
  297. package/dist/dts/internal/errors.d.ts.map +0 -1
  298. package/dist/dts/internal/indexRefCounter.d.ts +0 -7
  299. package/dist/dts/internal/indexRefCounter.d.ts.map +0 -1
  300. package/dist/dts/internal/module-augmentation.d.ts +0 -32
  301. package/dist/dts/internal/module-augmentation.d.ts.map +0 -1
  302. package/dist/dts/internal/parser.d.ts +0 -33
  303. package/dist/dts/internal/parser.d.ts.map +0 -1
  304. package/dist/dts/internal/parser2.d.ts +0 -12
  305. package/dist/dts/internal/parser2.d.ts.map +0 -1
  306. package/dist/dts/internal/server-parts.d.ts +0 -223
  307. package/dist/dts/internal/server-parts.d.ts.map +0 -1
  308. package/dist/dts/internal/server.d.ts +0 -5
  309. package/dist/dts/internal/server.d.ts.map +0 -1
  310. package/dist/dts/internal/utils.d.ts +0 -19
  311. package/dist/dts/internal/utils.d.ts.map +0 -1
  312. package/dist/dts/internal/v2/SyncPart.d.ts +0 -87
  313. package/dist/dts/internal/v2/SyncPart.d.ts.map +0 -1
  314. package/dist/dts/internal/v2/helpers.d.ts +0 -3
  315. package/dist/dts/internal/v2/helpers.d.ts.map +0 -1
  316. package/dist/dts/internal/v2/hydration-template.d.ts.map +0 -1
  317. package/dist/dts/internal/v2/parts.d.ts +0 -245
  318. package/dist/dts/internal/v2/parts.d.ts.map +0 -1
  319. package/dist/dts/internal/v2/render-entry.d.ts +0 -6
  320. package/dist/dts/internal/v2/render-entry.d.ts.map +0 -1
  321. package/dist/dts/internal/v2/render-sync-parts.d.ts +0 -22
  322. package/dist/dts/internal/v2/render-sync-parts.d.ts.map +0 -1
  323. package/dist/dts/internal/v2/render.d.ts +0 -83
  324. package/dist/dts/internal/v2/render.d.ts.map +0 -1
  325. package/dist/dts/internal/v2/sync-parts.d.ts +0 -129
  326. package/dist/dts/internal/v2/sync-parts.d.ts.map +0 -1
  327. package/dist/esm/Directive.js +0 -64
  328. package/dist/esm/Directive.js.map +0 -1
  329. package/dist/esm/ElementRef.js +0 -76
  330. package/dist/esm/ElementRef.js.map +0 -1
  331. package/dist/esm/ElementSource.js +0 -240
  332. package/dist/esm/ElementSource.js.map +0 -1
  333. package/dist/esm/Entry.js +0 -2
  334. package/dist/esm/Entry.js.map +0 -1
  335. package/dist/esm/EventHandler.js +0 -68
  336. package/dist/esm/EventHandler.js.map +0 -1
  337. package/dist/esm/Html.js +0 -230
  338. package/dist/esm/Html.js.map +0 -1
  339. package/dist/esm/HtmlChunk.js +0 -330
  340. package/dist/esm/HtmlChunk.js.map +0 -1
  341. package/dist/esm/Hydrate.js +0 -31
  342. package/dist/esm/Hydrate.js.map +0 -1
  343. package/dist/esm/Many.js +0 -54
  344. package/dist/esm/Many.js.map +0 -1
  345. package/dist/esm/Meta.js +0 -40
  346. package/dist/esm/Meta.js.map +0 -1
  347. package/dist/esm/Parser.js +0 -13
  348. package/dist/esm/Parser.js.map +0 -1
  349. package/dist/esm/Part.js +0 -5
  350. package/dist/esm/Part.js.map +0 -1
  351. package/dist/esm/Placeholder.js +0 -26
  352. package/dist/esm/Placeholder.js.map +0 -1
  353. package/dist/esm/Platform.js +0 -43
  354. package/dist/esm/Platform.js.map +0 -1
  355. package/dist/esm/Render.js +0 -36
  356. package/dist/esm/Render.js.map +0 -1
  357. package/dist/esm/RenderContext.js +0 -54
  358. package/dist/esm/RenderContext.js.map +0 -1
  359. package/dist/esm/RenderEvent.js +0 -43
  360. package/dist/esm/RenderEvent.js.map +0 -1
  361. package/dist/esm/RenderQueue.js +0 -336
  362. package/dist/esm/RenderQueue.js.map +0 -1
  363. package/dist/esm/RenderTemplate.js +0 -16
  364. package/dist/esm/RenderTemplate.js.map +0 -1
  365. package/dist/esm/Renderable.js +0 -2
  366. package/dist/esm/Renderable.js.map +0 -1
  367. package/dist/esm/Template.js.map +0 -1
  368. package/dist/esm/Test.js +0 -167
  369. package/dist/esm/Test.js.map +0 -1
  370. package/dist/esm/Vitest.js +0 -44
  371. package/dist/esm/Vitest.js.map +0 -1
  372. package/dist/esm/compiler-tools.js +0 -91
  373. package/dist/esm/compiler-tools.js.map +0 -1
  374. package/dist/esm/index.js +0 -65
  375. package/dist/esm/index.js.map +0 -1
  376. package/dist/esm/internal/EventSource.js +0 -126
  377. package/dist/esm/internal/EventSource.js.map +0 -1
  378. package/dist/esm/internal/HydrateContext.js +0 -7
  379. package/dist/esm/internal/HydrateContext.js.map +0 -1
  380. package/dist/esm/internal/browser.js +0 -103
  381. package/dist/esm/internal/browser.js.map +0 -1
  382. package/dist/esm/internal/character-entities.js +0 -2134
  383. package/dist/esm/internal/character-entities.js.map +0 -1
  384. package/dist/esm/internal/chunks.js +0 -60
  385. package/dist/esm/internal/chunks.js.map +0 -1
  386. package/dist/esm/internal/errors.js +0 -46
  387. package/dist/esm/internal/errors.js.map +0 -1
  388. package/dist/esm/internal/indexRefCounter.js +0 -47
  389. package/dist/esm/internal/indexRefCounter.js.map +0 -1
  390. package/dist/esm/internal/module-augmentation.js +0 -2
  391. package/dist/esm/internal/module-augmentation.js.map +0 -1
  392. package/dist/esm/internal/parser.js +0 -596
  393. package/dist/esm/internal/parser.js.map +0 -1
  394. package/dist/esm/internal/parser2.js +0 -393
  395. package/dist/esm/internal/parser2.js.map +0 -1
  396. package/dist/esm/internal/server-parts.js +0 -109
  397. package/dist/esm/internal/server-parts.js.map +0 -1
  398. package/dist/esm/internal/server.js +0 -22
  399. package/dist/esm/internal/server.js.map +0 -1
  400. package/dist/esm/internal/utils.js +0 -119
  401. package/dist/esm/internal/utils.js.map +0 -1
  402. package/dist/esm/internal/v2/SyncPart.js +0 -5
  403. package/dist/esm/internal/v2/SyncPart.js.map +0 -1
  404. package/dist/esm/internal/v2/helpers.js +0 -12
  405. package/dist/esm/internal/v2/helpers.js.map +0 -1
  406. package/dist/esm/internal/v2/hydration-template.js.map +0 -1
  407. package/dist/esm/internal/v2/parts.js +0 -150
  408. package/dist/esm/internal/v2/parts.js.map +0 -1
  409. package/dist/esm/internal/v2/render-entry.js +0 -102
  410. package/dist/esm/internal/v2/render-entry.js.map +0 -1
  411. package/dist/esm/internal/v2/render-sync-parts.js +0 -265
  412. package/dist/esm/internal/v2/render-sync-parts.js.map +0 -1
  413. package/dist/esm/internal/v2/render.js +0 -521
  414. package/dist/esm/internal/v2/render.js.map +0 -1
  415. package/dist/esm/internal/v2/sync-parts.js +0 -102
  416. package/dist/esm/internal/v2/sync-parts.js.map +0 -1
  417. package/dist/esm/package.json +0 -4
  418. package/src/Directive.ts +0 -114
  419. package/src/ElementRef.ts +0 -126
  420. package/src/ElementSource.ts +0 -432
  421. package/src/Entry.ts +0 -28
  422. package/src/Hydrate.ts +0 -51
  423. package/src/Many.ts +0 -161
  424. package/src/Meta.ts +0 -45
  425. package/src/Part.ts +0 -154
  426. package/src/Placeholder.ts +0 -78
  427. package/src/Platform.ts +0 -71
  428. package/src/RenderContext.ts +0 -121
  429. package/src/Test.ts +0 -354
  430. package/src/Vitest.ts +0 -141
  431. package/src/compiler-tools.ts +0 -250
  432. package/src/internal/EventSource.ts +0 -188
  433. package/src/internal/HydrateContext.ts +0 -22
  434. package/src/internal/browser.ts +0 -138
  435. package/src/internal/character-entities.ts +0 -2136
  436. package/src/internal/chunks.ts +0 -89
  437. package/src/internal/errors.ts +0 -49
  438. package/src/internal/external.d.ts +0 -11
  439. package/src/internal/indexRefCounter.ts +0 -54
  440. package/src/internal/module-augmentation.ts +0 -44
  441. package/src/internal/parser.ts +0 -757
  442. package/src/internal/parser2.ts +0 -468
  443. package/src/internal/server-parts.ts +0 -161
  444. package/src/internal/server.ts +0 -37
  445. package/src/internal/utils.ts +0 -153
  446. package/src/internal/v2/SyncPart.ts +0 -112
  447. package/src/internal/v2/helpers.ts +0 -13
  448. package/src/internal/v2/hydration-template.ts +0 -308
  449. package/src/internal/v2/parts.ts +0 -254
  450. package/src/internal/v2/render-entry.ts +0 -131
  451. package/src/internal/v2/render-sync-parts.ts +0 -440
  452. package/src/internal/v2/render.ts +0 -813
  453. package/src/internal/v2/sync-parts.ts +0 -133
package/src/HtmlChunk.ts CHANGED
@@ -1,407 +1,365 @@
1
+ import type * as Template from "./Template.js";
2
+ import * as Array from "effect/Array";
3
+ import { constVoid } from "effect/Function";
4
+ import * as Order from "effect/Order";
5
+ import * as Predicate from "effect/Predicate";
6
+ import { renderToEscapedString, renderToString } from "./internal/encoding.js";
7
+ import { TEMPLATE_END_COMMENT, TEMPLATE_START_COMMENT } from "./internal/meta.js";
8
+
1
9
  /**
10
+ * Represents a piece of a pre-compiled HTML template.
11
+ *
12
+ * Chunks allow the renderer to stream static parts of the HTML immediately
13
+ * while waiting for dynamic parts to be resolved.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import type { HtmlChunk } from "@typed/template/HtmlChunk"
18
+ * import { templateToHtmlChunks } from "@typed/template/HtmlChunk"
19
+ * import { parse } from "@typed/template/Parser"
20
+ *
21
+ * const template = parse`<div>Hello ${"world"}</div>`
22
+ * const chunks = templateToHtmlChunks(template)
23
+ *
24
+ * // chunks will contain:
25
+ * // - HtmlTextChunk with text "<div>Hello "
26
+ * // - HtmlPartChunk for the dynamic part
27
+ * // - HtmlTextChunk with text "</div>"
28
+ * ```
29
+ *
2
30
  * @since 1.0.0
31
+ * @category models
3
32
  */
4
- import { keyToPartType } from "./internal/utils.js"
5
- import { isNullOrUndefined } from "./internal/v2/helpers.js"
6
- import type {
7
- Attribute,
8
- ElementNode,
9
- Node,
10
- PartNode,
11
- SelfClosingElementNode,
12
- SparseAttrNode,
13
- SparseClassNameNode,
14
- Template,
15
- Text,
16
- TextOnlyElement
17
- } from "./Template.js"
33
+ export type HtmlChunk = HtmlTextChunk | HtmlPartChunk | HtmlSparsePartChunk;
18
34
 
19
35
  /**
36
+ * A static text chunk.
37
+ *
20
38
  * @since 1.0.0
39
+ * @category models
21
40
  */
22
- export type HtmlChunk = TextChunk | PartChunk | SparsePartChunk
41
+ export interface HtmlTextChunk {
42
+ readonly _tag: "text";
43
+ readonly text: string;
44
+ }
23
45
 
24
46
  /**
47
+ * A chunk representing a dynamic part (interpolation).
48
+ *
25
49
  * @since 1.0.0
50
+ * @category models
26
51
  */
27
- export class TextChunk {
28
- readonly _tag = "text"
29
- constructor(readonly value: string) {}
52
+ export interface HtmlPartChunk {
53
+ readonly _tag: "part";
54
+ readonly node: Template.PartNode;
55
+ /**
56
+ * Function to render the value of this part into a string.
57
+ */
58
+ readonly render: (value: unknown) => string;
30
59
  }
31
60
 
32
61
  /**
62
+ * A chunk representing a sparse part (mixed static/dynamic text).
63
+ *
33
64
  * @since 1.0.0
65
+ * @category models
34
66
  */
35
- export class PartChunk {
36
- readonly _tag = "part"
37
-
38
- constructor(
39
- readonly node: PartNode,
40
- readonly render: (value: unknown) => string
41
- ) {}
67
+ export interface HtmlSparsePartChunk {
68
+ readonly _tag: "sparse-part";
69
+ readonly node: Template.SparsePartNode;
70
+ /**
71
+ * Function to render the value of this part into a string.
72
+ */
73
+ readonly render: (value: unknown) => string;
42
74
  }
43
75
 
44
76
  /**
45
- * @since 1.0.0
77
+ * Helper class for constructing a list of `HtmlChunk`s.
78
+ * @internal
46
79
  */
47
- export class SparsePartChunk {
48
- readonly _tag = "sparse-part"
80
+ export class HtmlChunksBuilder {
81
+ private chunks: Array<HtmlChunk> = [];
82
+
83
+ text(text: string): HtmlChunksBuilder {
84
+ const lastIndex = this.chunks.length - 1;
85
+ const lastChunk = this.chunks[lastIndex];
86
+ if (lastChunk?._tag === "text") {
87
+ this.chunks[lastIndex] = { _tag: "text", text: lastChunk.text + text };
88
+ } else {
89
+ this.chunks.push({ _tag: "text", text });
90
+ }
91
+ return this;
92
+ }
93
+
94
+ part(node: Template.PartNode, render: (value: unknown) => string): HtmlChunksBuilder {
95
+ this.chunks.push({ _tag: "part", node, render });
96
+ return this;
97
+ }
98
+
99
+ sparsePart(node: Template.SparsePartNode, render: (value: unknown) => string): HtmlChunksBuilder {
100
+ this.chunks.push({ _tag: "sparse-part", node, render });
101
+ return this;
102
+ }
49
103
 
50
- constructor(
51
- readonly node: SparseAttrNode | SparseClassNameNode,
52
- readonly render: (value: AttrValue) => string
53
- ) {}
104
+ build(): ReadonlyArray<HtmlChunk> {
105
+ const chunks = this.chunks;
106
+ this.chunks = [];
107
+ return chunks;
108
+ }
54
109
  }
55
110
 
111
+ // TODO: Add support for unsafe HTML content.
112
+
56
113
  /**
114
+ * Converts a parsed `Template` into a sequence of `HtmlChunk`s.
115
+ * This optimization pre-calculates the static HTML strings to minimize work at render time.
116
+ *
117
+ * @example
118
+ * ```ts
119
+ * import { templateToHtmlChunks } from "@typed/template/HtmlChunk"
120
+ * import { parse } from "@typed/template/Parser"
121
+ *
122
+ * const template = parse`<div class="container">Hello ${"world"}</div>`
123
+ * const chunks = templateToHtmlChunks(template)
124
+ *
125
+ * // chunks is an array of HtmlChunk objects
126
+ * // Static parts are pre-rendered as text chunks
127
+ * // Dynamic parts are represented as part chunks
128
+ * ```
129
+ *
57
130
  * @since 1.0.0
131
+ * @category utilities
58
132
  */
59
- export type AttrValue = string | null | undefined | ReadonlyArray<AttrValue>
60
-
61
- // TODO: Should we escape more things?
62
- // TODO: We should manually optimize the text fusion
133
+ export function templateToHtmlChunks({ nodes }: Template.Template) {
134
+ const builder = new HtmlChunksBuilder();
135
+ for (const node of nodes) nodeToHtmlChunk(builder, node);
136
+ return builder.build();
137
+ }
63
138
 
64
139
  /**
140
+ * Wraps the HTML chunks with comments containing the template hash.
141
+ * This is crucial for hydration to identify which template rendered a section of HTML.
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * import { addTemplateHash, templateToHtmlChunks } from "@typed/template/HtmlChunk"
146
+ * import { parse } from "@typed/template/Parser"
147
+ *
148
+ * const template = parse`<div>Hello</div>`
149
+ * const chunks = templateToHtmlChunks(template)
150
+ * const chunksWithHash = addTemplateHash(chunks, template)
151
+ *
152
+ * // chunksWithHash will have template hash comments added
153
+ * // for hydration purposes
154
+ * ```
155
+ *
65
156
  * @since 1.0.0
157
+ * @category utilities
66
158
  */
67
- export function templateToHtmlChunks({ hash, nodes }: Template, isStatic: boolean) {
68
- if (isStatic) {
69
- return fuseTextChunks(nodes.flatMap((node) => nodeToHtmlChunk(node)))
70
- }
71
-
72
- const chunks = fuseTextChunks([
73
- templateStart(hash),
74
- ...nodes.flatMap((node) => nodeToHtmlChunk(node, hash)),
75
- templateEnd(hash)
76
- ])
77
-
78
- return chunks
159
+ export function addTemplateHash(
160
+ chunks: ReadonlyArray<HtmlChunk>,
161
+ { hash }: Template.Template,
162
+ ): ReadonlyArray<HtmlChunk> {
163
+ const start = TEMPLATE_START_COMMENT(hash);
164
+ const end = TEMPLATE_END_COMMENT(hash);
165
+ if (chunks.length === 0) return [{ _tag: "text", text: start + end }];
166
+ return appendTextChunk(prependTextChunk(chunks, start), end);
79
167
  }
80
168
 
81
- function templateStart(hash: string): HtmlChunk {
82
- return new TextChunk(`<!--typed-${hash}-->`)
169
+ function prependTextChunk(
170
+ chunks: ReadonlyArray<HtmlChunk>,
171
+ text: string,
172
+ ): ReadonlyArray<HtmlChunk> {
173
+ if (chunks.length === 0) return [{ _tag: "text", text }];
174
+ const firstChunk = chunks[0];
175
+ if (firstChunk._tag === "text")
176
+ return [{ _tag: "text", text: text + firstChunk.text }, ...chunks.slice(1)];
177
+ return [{ _tag: "text", text }, ...chunks];
83
178
  }
84
179
 
85
- function templateEnd(hash: string): HtmlChunk {
86
- return new TextChunk(`<!--/typed-${hash}-->`)
87
- }
88
-
89
- function fuseTextChunks(chunks: Array<HtmlChunk>): ReadonlyArray<HtmlChunk> {
90
- const output: Array<HtmlChunk> = []
91
-
92
- for (let i = 0; i < chunks.length; i++) {
93
- if (i > 0) {
94
- const prevIndex = output.length - 1
95
- const prev = output[prevIndex]
96
- const curr = chunks[i]
97
-
98
- if (prev._tag === "text" && curr._tag === "text") {
99
- output[prevIndex] = new TextChunk(prev.value + curr.value)
100
- } else {
101
- output.push(curr)
102
- }
103
- } else {
104
- output.push(chunks[i])
105
- }
106
- }
107
-
108
- return output
180
+ function appendTextChunk(chunks: ReadonlyArray<HtmlChunk>, text: string): ReadonlyArray<HtmlChunk> {
181
+ if (chunks.length === 0) return [{ _tag: "text", text }];
182
+ const lastChunk = chunks[chunks.length - 1];
183
+ if (lastChunk._tag === "text")
184
+ return [...chunks.slice(0, -1), { _tag: "text", text: lastChunk.text + text }];
185
+ return [...chunks, { _tag: "text", text }];
109
186
  }
110
187
 
111
188
  type NodeMap = {
112
- readonly [K in Node["_tag"]]: (node: Extract<Node, { _tag: K }>, hash?: string) => Array<HtmlChunk>
113
- }
189
+ readonly [K in Template.Node["_tag"]]: (
190
+ builder: HtmlChunksBuilder,
191
+ node: Extract<Template.Node, { _tag: K }>,
192
+ ) => void;
193
+ };
114
194
 
115
195
  const nodeMap: NodeMap = {
116
- doctype: (node) => [new TextChunk(`<!DOCTYPE ${node.name}>`)],
196
+ doctype: (builder, node) => builder.text(`<!DOCTYPE ${node.name}>`),
117
197
  element: elementToHtmlChunks,
118
- node: (node) => [new PartChunk(node, String)],
198
+ text: (builder, node) => builder.text(node.value),
199
+ node: (builder, part) => builder.part(part, (v) => renderToEscapedString(v, "")),
119
200
  "self-closing-element": selfClosingElementToHtmlChunks,
120
- text: (node) => [textToHtmlChunks(node)],
121
201
  "text-only-element": textOnlyElementToHtmlChunks,
122
- comment: (node) => [new TextChunk(`<!--${node.value}-->`)],
123
- "comment-part": (node) => [
124
- new PartChunk(node, (value) => `<!--${value}-->`)
125
- ],
126
- "sparse-comment": (node) => [
127
- new TextChunk("<!--"),
128
- ...node.nodes.map((node) => {
129
- if (node._tag === "text") {
130
- return textToHtmlChunks(node)
131
- } else {
132
- return new PartChunk(node, (value) => `${value}`)
133
- }
134
- }),
135
- new TextChunk("-->")
136
- ]
137
- }
202
+ comment: (builder, node) => builder.text(`<!--${node.value}-->`),
203
+ "comment-part": (builder, part) =>
204
+ builder.part(part, (v) => `<!--${renderToEscapedString(v, "")}-->`),
205
+ "sparse-comment": (builder, part) =>
206
+ builder.sparsePart(part, (v) => `<!--${renderToEscapedString(v, "")}-->`),
207
+ };
138
208
 
139
- function nodeToHtmlChunk(node: Node, hash?: string): Array<HtmlChunk> {
140
- return nodeMap[node._tag](node as any, hash)
209
+ function selfClosingElementToHtmlChunks(
210
+ builder: HtmlChunksBuilder,
211
+ node: Template.SelfClosingElementNode,
212
+ ) {
213
+ builder.text(`<${node.tagName}`);
214
+ addAttributes(builder, node.attributes);
215
+ builder.text(`/>`);
141
216
  }
142
217
 
143
- function elementToHtmlChunks(
144
- { attributes, children, tagName }: ElementNode
145
- ): Array<HtmlChunk> {
146
- if (attributes.length === 0) {
147
- return [
148
- new TextChunk(openTag(tagName) + ">"),
149
- ...children.flatMap((c) => nodeToHtmlChunk(c)),
150
- new TextChunk(closeTag(tagName))
151
- ]
218
+ function textOnlyElementToHtmlChunks(builder: HtmlChunksBuilder, node: Template.TextOnlyElement) {
219
+ builder.text(`<${node.tagName}`);
220
+ addAttributes(builder, node.attributes);
221
+ builder.text(">");
222
+ if (node.textContent !== null) {
223
+ textContentToHtml(builder, node.textContent);
152
224
  }
153
225
 
154
- const chunks: Array<HtmlChunk> = [
155
- new TextChunk(openTag(tagName)),
156
- ...attributes.map((a) => attributeToHtmlChunk(a)),
157
- new TextChunk(">"),
158
- ...children.flatMap((c) => nodeToHtmlChunk(c)),
159
- new TextChunk(closeTag(tagName))
160
- ]
161
-
162
- return chunks
226
+ builder.text(`</${node.tagName}>`);
163
227
  }
164
228
 
165
- function selfClosingElementToHtmlChunks(
166
- { attributes, tagName }: SelfClosingElementNode
167
- ): Array<HtmlChunk> {
168
- if (attributes.length === 0) {
169
- return [new TextChunk(openTag(tagName) + " />")]
229
+ function textContentToHtml(builder: HtmlChunksBuilder, textContent: Template.Text) {
230
+ switch (textContent._tag) {
231
+ case "text":
232
+ return builder.text(textContent.value);
233
+ case "text-part":
234
+ return builder.part(textContent, (v) => renderToString(v, ""));
235
+ case "sparse-text":
236
+ return builder.sparsePart(textContent, (v) => renderToString(v, ""));
170
237
  }
238
+ }
171
239
 
172
- const chunks: Array<HtmlChunk> = [
173
- new TextChunk(openTag(tagName)),
174
- ...attributes.map((a) => attributeToHtmlChunk(a)),
175
- new TextChunk(`/>`)
176
- ]
177
-
178
- return chunks
240
+ function nodeToHtmlChunk(builder: HtmlChunksBuilder, node: Template.Node) {
241
+ const handler = nodeMap[node._tag];
242
+ handler(builder, node as never);
179
243
  }
180
244
 
181
- function textToHtmlChunks(text: Text): HtmlChunk {
182
- return text._tag === "text" ? new TextChunk(text.value) : new PartChunk(text, String)
245
+ function elementToHtmlChunks(
246
+ builder: HtmlChunksBuilder,
247
+ { attributes, children, tagName }: Template.ElementNode,
248
+ ) {
249
+ builder.text(`<${tagName}`);
250
+ addAttributes(builder, attributes);
251
+ builder.text(">");
252
+ for (const child of children) nodeToHtmlChunk(builder, child);
253
+ builder.text(`</${tagName}>`);
183
254
  }
184
255
 
185
- function textOnlyElementToHtmlChunks(
186
- { attributes, children, tagName }: TextOnlyElement
187
- ): Array<HtmlChunk> {
188
- if (attributes.length === 0) {
189
- return [
190
- new TextChunk(openTag(tagName) + ">"),
191
- ...children.map((c) => textToHtmlChunks(c)),
192
- new TextChunk(closeTag(tagName))
193
- ]
256
+ function addAttributes(builder: HtmlChunksBuilder, attributes: ReadonlyArray<Template.Attribute>) {
257
+ if (attributes.length > 0) {
258
+ const lastIndex = attributes.length - 1;
259
+ for (const [index, attribute] of sortAttributes(attributes).entries()) {
260
+ attributeToHtmlChunk(builder, attribute, {
261
+ isFirst: index === 0,
262
+ isLast: index === lastIndex,
263
+ });
264
+ }
194
265
  }
195
-
196
- const chunks: Array<HtmlChunk> = [
197
- new TextChunk(openTag(tagName)),
198
- ...attributes.map((a) => attributeToHtmlChunk(a)),
199
- new TextChunk(">"),
200
- ...children.map((c) => textToHtmlChunks(c)),
201
- new TextChunk(closeTag(tagName))
202
- ]
203
-
204
- return chunks
205
266
  }
206
267
 
207
- type AttrMap = {
208
- [K in Attribute["_tag"]]: (attr: Extract<Attribute, { readonly _tag: K }>) => HtmlChunk
268
+ type Placement = {
269
+ readonly isFirst: boolean;
270
+ readonly isLast: boolean;
271
+ };
272
+
273
+ type AttributeMap = {
274
+ readonly [K in Template.Attribute["_tag"]]: (
275
+ builder: HtmlChunksBuilder,
276
+ attribute: Extract<Template.Attribute, { _tag: K }>,
277
+ placement: Placement,
278
+ ) => void;
279
+ };
280
+
281
+ function attributeToHtmlChunk(
282
+ builder: HtmlChunksBuilder,
283
+ attr: Template.Attribute,
284
+ placement: Placement,
285
+ ): void {
286
+ attributeMap[attr._tag](builder, attr as never, placement);
209
287
  }
210
288
 
211
- const attrMap: AttrMap = {
212
- attribute: (attr) => new TextChunk(` ${attr.name}="${escape(attr.value)}"`),
213
- attr: (attr) => new PartChunk(attr, (value) => (value == null ? `` : ` ${attr.name}="${escape(value)}"`)),
214
- boolean: (attr) => new TextChunk(" " + attr.name),
215
- "boolean-part": (attr) => new PartChunk(attr, (value) => (value ? ` ${attr.name}` : "")),
216
- "className-part": (attr) => new PartChunk(attr, (value) => (value ? ` class="${escape(value)}"` : "")),
217
- data: (attr) =>
218
- new PartChunk(attr, (value) => value == null ? `` : datasetToString(value as Readonly<Record<string, string>>)),
219
- event: () => new TextChunk(""),
220
- property: (attr) => new PartChunk(attr, (value) => (value == null ? `` : ` ${attr.name}="${escape(value)}"`)),
221
- properties: (attr) =>
222
- new PartChunk(
223
- attr,
224
- (
225
- value
226
- ) => {
227
- if (value == null) return ""
228
-
229
- // Each call has only 1 key-value pair
230
- const [k, v] = Object.entries(value)[0]
231
-
232
- if (value == null) return ""
233
-
234
- const [type, key] = keyToPartType(k)
235
-
236
- switch (type) {
237
- case "attr":
238
- case "property":
239
- return v == null ? "" : ` ${key}="${escape(v)}"`
240
- case "boolean":
241
- return v ? key : ""
242
- case "class":
243
- return ` class="${escape(v)}"`
244
- case "data": {
245
- const d = datasetToString(v)
246
- return d.length === 0 ? "" : ` ${d}`
247
- }
248
- default:
249
- return ""
250
- }
251
- }
289
+ const attributeMap: AttributeMap = {
290
+ attribute: (builder, attribute, placement) =>
291
+ builder.text(addAttributeSpace(`${attribute.name}="${attribute.value}"`, placement)),
292
+ boolean: (builder, attribute, placement) =>
293
+ builder.text(addAttributeSpace(`${attribute.name}`, placement)),
294
+ attr: (builder, attribute, placement) =>
295
+ builder.part(attribute, (v) =>
296
+ addAttributeSpace(`${attribute.name}="${renderToEscapedString(v, "")}"`, placement),
297
+ ),
298
+ "sparse-attr": (builder, attribute, placement) =>
299
+ builder.sparsePart(attribute, (v) =>
300
+ addAttributeSpace(`${attribute.name}="${renderToEscapedString(v, "")}"`, placement),
301
+ ),
302
+ "boolean-part": (builder, attribute, placement) =>
303
+ builder.part(attribute, (v) => addAttributeSpace(v ? `${attribute.name}` : "", placement)),
304
+ "className-part": (builder, attribute, placement) =>
305
+ builder.part(attribute, (v) =>
306
+ addAttributeSpace(`class="${renderToEscapedString(v, " ")}"`, placement),
307
+ ),
308
+ "sparse-class-name": (builder, attribute, placement) =>
309
+ builder.sparsePart(attribute, (v) =>
310
+ addAttributeSpace(`class="${renderToEscapedString(v, "")}"`, placement),
311
+ ),
312
+ data: (builder, attribute) =>
313
+ builder.part(attribute, (v) => (Predicate.isObject(v) ? recordWithPrefix(`data-`, v) : "")),
314
+ property: (builder, attribute, placement) =>
315
+ builder.part(attribute, (v) =>
316
+ addAttributeSpace(`${attribute.name}="${renderToEscapedString(v, "")}"`, placement),
317
+ ),
318
+ properties: (builder, attribute, placement) =>
319
+ builder.part(attribute, (v) =>
320
+ addAttributeSpace(Predicate.isObject(v) ? recordWithPrefix(``, v) : "", placement),
252
321
  ),
253
- ref: () => new TextChunk(""),
254
- "sparse-attr": (attr) =>
255
- new SparsePartChunk(attr, (values) => {
256
- return values == null
257
- ? ``
258
- : ` ${attr.name}="${Array.isArray(values) ? escape(values.filter(isString).join("")) : escape(values)}"`
259
- }),
260
- "sparse-class-name": (attr) =>
261
- new SparsePartChunk(attr, (values) => {
262
- return values == null
263
- ? ``
264
- : ` class="${Array.isArray(values) ? escape(values.filter(isString).join("")) : escape(values)}"`
265
- }),
266
- text: (attr) => new TextChunk(attr.value)
267
- }
268
322
 
269
- function attributeToHtmlChunk(attr: Attribute): HtmlChunk {
270
- return attrMap[attr._tag](attr as any)
271
- }
323
+ // Don't have HTML representations for these
324
+ ref: constVoid,
325
+ event: constVoid,
326
+ };
272
327
 
273
- function isString(value: unknown): value is string {
274
- return typeof value === "string"
328
+ function addAttributeSpace(str: string, placement: Placement) {
329
+ if (str.length === 0) return str;
330
+ if (placement.isFirst) return " " + str + (placement.isLast ? "" : " ");
331
+ return str + (placement.isLast ? "" : " ");
275
332
  }
276
333
 
277
- function datasetToString(dataset: Readonly<Record<string, string | undefined>>) {
278
- const s = Object.entries(dataset)
279
- .map(([key, value]) => (value === undefined ? `data-${key}` : `data-${key}="${escape(value)}"`))
280
- .join(" ")
334
+ function recordWithPrefix(prefix: string, r: {}) {
335
+ const s = Object.entries(r)
336
+ .map(([key, value]) =>
337
+ value === undefined
338
+ ? `${prefix}${key}`
339
+ : `${prefix}${key}="${renderToEscapedString(value, "")}"`,
340
+ )
341
+ .join(" ");
281
342
 
282
- return s.length === 0 ? "" : " " + s
343
+ return s.length === 0 ? "" : " " + s;
283
344
  }
284
345
 
285
- function openTag(tagName: string): string {
286
- return `<${tagName}`
287
- }
346
+ const AttributeOrder = Order.mapInput(
347
+ Order.Number,
348
+ // Order such that static attributes can be streamed out first
349
+ // and sparse attributes can be streamed out last
350
+ (attr: Template.Attribute) => (isStaticAttribute(attr) ? -1 : isSparseAttribute(attr) ? 1 : 0),
351
+ );
288
352
 
289
- function closeTag(tagName: string): string {
290
- return `</${tagName}>`
291
- }
353
+ const sortAttributes = Array.sortBy(AttributeOrder);
292
354
 
293
- /**
294
- * @since 1.0.0
295
- */
296
- export function escape(s: unknown): string {
297
- switch (typeof s) {
298
- case "string":
299
- case "number":
300
- case "boolean":
301
- case "bigint":
302
- return escapeHtml(String(s))
303
- case "object": {
304
- if (isNullOrUndefined(s)) {
305
- return ""
306
- } else if (Array.isArray(s)) {
307
- return s.map(escape).join("")
308
- } else if (s instanceof Date) {
309
- return escapeHtml(s.toISOString())
310
- } else if (s instanceof RegExp) {
311
- return escapeHtml(s.toString())
312
- } else {
313
- return escapeHtml(JSON.stringify(s))
314
- }
315
- }
316
- default:
317
- return escapeHtml(JSON.stringify(s))
318
- }
319
- }
355
+ const staticAttributes = new Set<Template.Attribute["_tag"]>(["attribute", "boolean"]);
320
356
 
321
- /**
322
- * @since 1.0.0
323
- */
324
- export function unescape(s: string) {
325
- const unescaped = unescapeHtml(s)
326
- const couldBeJson = unescaped[0] === "[" || unescaped === "{"
327
- if (couldBeJson) {
328
- try {
329
- return JSON.parse(unescaped)
330
- } catch {
331
- return unescaped
332
- }
333
- } else {
334
- return unescaped
335
- }
357
+ function isStaticAttribute(attr: Template.Attribute) {
358
+ return staticAttributes.has(attr._tag);
336
359
  }
337
360
 
338
- const unescapeHtmlRules = [
339
- [/&quot;/g, "\""],
340
- [/&#39;/g, "'"],
341
- [/&#x3A;/g, ":"],
342
- [/&lt;/g, "<"],
343
- [/&gt;/g, ">"],
344
- [/&amp;/g, "&"]
345
- ] as const
346
-
347
- const matchHtmlRegExp = /["'&<>]/
348
-
349
- /**
350
- * @since 1.0.0
351
- */
352
- export function escapeHtml(str: string): string {
353
- const match = matchHtmlRegExp.exec(str)
354
-
355
- if (!match) {
356
- return str
357
- }
358
-
359
- let escape
360
- let html = ""
361
- let index = 0
362
- let lastIndex = 0
363
-
364
- for (index = match.index; index < str.length; index++) {
365
- switch (str.charCodeAt(index)) {
366
- case 34: // "
367
- escape = "&quot;"
368
- break
369
- case 38: // &
370
- escape = "&amp;"
371
- break
372
- case 39: // '
373
- escape = "&#39;"
374
- break
375
- case 60: // <
376
- escape = "&lt;"
377
- break
378
- case 62: // >
379
- escape = "&gt;"
380
- break
381
- default:
382
- continue
383
- }
384
-
385
- if (lastIndex !== index) {
386
- html += str.substring(lastIndex, index)
387
- }
388
-
389
- lastIndex = index + 1
390
- html += escape
391
- }
392
-
393
- return lastIndex !== index
394
- ? html + str.substring(lastIndex, index)
395
- : html
396
- }
397
-
398
- /**
399
- * @since 1.0.0
400
- */
401
- export function unescapeHtml(html: string) {
402
- for (const [from, to] of unescapeHtmlRules) {
403
- html = html.replace(from, to)
404
- }
361
+ const sparseAttributes = new Set<Template.Attribute["_tag"]>(["sparse-attr", "sparse-class-name"]);
405
362
 
406
- return html
363
+ function isSparseAttribute(attr: Template.Attribute) {
364
+ return sparseAttributes.has(attr._tag);
407
365
  }