@typed/template 0.9.6 → 0.10.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 (300) hide show
  1. package/RenderQueue/package.json +6 -0
  2. package/dist/cjs/Directive.js +1 -1
  3. package/dist/cjs/Directive.js.map +1 -1
  4. package/dist/cjs/ElementRef.js +1 -1
  5. package/dist/cjs/ElementRef.js.map +1 -1
  6. package/dist/cjs/ElementSource.js +1 -1
  7. package/dist/cjs/ElementSource.js.map +1 -1
  8. package/dist/cjs/EventHandler.js +11 -4
  9. package/dist/cjs/EventHandler.js.map +1 -1
  10. package/dist/cjs/Html.js +84 -44
  11. package/dist/cjs/Html.js.map +1 -1
  12. package/dist/cjs/HtmlChunk.js +67 -21
  13. package/dist/cjs/HtmlChunk.js.map +1 -1
  14. package/dist/cjs/Hydrate.js +6 -6
  15. package/dist/cjs/Hydrate.js.map +1 -1
  16. package/dist/cjs/Many.js +4 -4
  17. package/dist/cjs/Many.js.map +1 -1
  18. package/dist/cjs/Meta.js +10 -3
  19. package/dist/cjs/Meta.js.map +1 -1
  20. package/dist/cjs/Parser.js +1 -1
  21. package/dist/cjs/Placeholder.js +5 -9
  22. package/dist/cjs/Placeholder.js.map +1 -1
  23. package/dist/cjs/Platform.js +7 -5
  24. package/dist/cjs/Platform.js.map +1 -1
  25. package/dist/cjs/Render.js +8 -7
  26. package/dist/cjs/Render.js.map +1 -1
  27. package/dist/cjs/RenderContext.js +8 -92
  28. package/dist/cjs/RenderContext.js.map +1 -1
  29. package/dist/cjs/RenderEvent.js +9 -1
  30. package/dist/cjs/RenderEvent.js.map +1 -1
  31. package/dist/cjs/RenderQueue.js +341 -0
  32. package/dist/cjs/RenderQueue.js.map +1 -0
  33. package/dist/cjs/RenderTemplate.js +1 -1
  34. package/dist/cjs/RenderTemplate.js.map +1 -1
  35. package/dist/cjs/Template.js +12 -0
  36. package/dist/cjs/Template.js.map +1 -1
  37. package/dist/cjs/Test.js +64 -33
  38. package/dist/cjs/Test.js.map +1 -1
  39. package/dist/cjs/Vitest.js +12 -20
  40. package/dist/cjs/Vitest.js.map +1 -1
  41. package/dist/cjs/index.js +6 -3
  42. package/dist/cjs/index.js.map +1 -1
  43. package/dist/cjs/internal/EventSource.js +16 -9
  44. package/dist/cjs/internal/EventSource.js.map +1 -1
  45. package/dist/cjs/internal/HydrateContext.js.map +1 -1
  46. package/dist/cjs/internal/browser.js +11 -10
  47. package/dist/cjs/internal/browser.js.map +1 -1
  48. package/dist/cjs/internal/character-entities.js +2141 -0
  49. package/dist/cjs/internal/character-entities.js.map +1 -0
  50. package/dist/cjs/internal/errors.js +19 -2
  51. package/dist/cjs/internal/errors.js.map +1 -1
  52. package/dist/cjs/internal/indexRefCounter.js +36 -63
  53. package/dist/cjs/internal/indexRefCounter.js.map +1 -1
  54. package/dist/cjs/internal/parser.js +18 -17
  55. package/dist/cjs/internal/parser.js.map +1 -1
  56. package/dist/cjs/internal/parser2.js +382 -0
  57. package/dist/cjs/internal/parser2.js.map +1 -0
  58. package/dist/cjs/internal/server-parts.js +124 -0
  59. package/dist/cjs/internal/server-parts.js.map +1 -0
  60. package/dist/cjs/internal/server.js +15 -185
  61. package/dist/cjs/internal/server.js.map +1 -1
  62. package/dist/cjs/internal/utils.js +73 -9
  63. package/dist/cjs/internal/utils.js.map +1 -1
  64. package/dist/cjs/internal/v2/SyncPart.js +6 -0
  65. package/dist/cjs/internal/v2/SyncPart.js.map +1 -0
  66. package/dist/cjs/internal/v2/helpers.js +15 -0
  67. package/dist/cjs/internal/v2/helpers.js.map +1 -0
  68. package/dist/cjs/internal/v2/hydrate.js +202 -0
  69. package/dist/cjs/internal/v2/hydrate.js.map +1 -0
  70. package/dist/cjs/internal/v2/hydration-template.js +269 -0
  71. package/dist/cjs/internal/v2/hydration-template.js.map +1 -0
  72. package/dist/cjs/internal/v2/parts.js +169 -0
  73. package/dist/cjs/internal/v2/parts.js.map +1 -0
  74. package/dist/cjs/internal/v2/render-entry.js +110 -0
  75. package/dist/cjs/internal/v2/render-entry.js.map +1 -0
  76. package/dist/cjs/internal/v2/render-sync-parts.js +318 -0
  77. package/dist/cjs/internal/v2/render-sync-parts.js.map +1 -0
  78. package/dist/cjs/internal/v2/render.js +417 -0
  79. package/dist/cjs/internal/v2/render.js.map +1 -0
  80. package/dist/cjs/internal/v2/sync-parts.js +115 -0
  81. package/dist/cjs/internal/v2/sync-parts.js.map +1 -0
  82. package/dist/dts/ElementRef.d.ts +1 -1
  83. package/dist/dts/ElementRef.d.ts.map +1 -1
  84. package/dist/dts/ElementSource.d.ts +1 -1
  85. package/dist/dts/ElementSource.d.ts.map +1 -1
  86. package/dist/dts/EventHandler.d.ts +12 -8
  87. package/dist/dts/EventHandler.d.ts.map +1 -1
  88. package/dist/dts/Html.d.ts +6 -5
  89. package/dist/dts/Html.d.ts.map +1 -1
  90. package/dist/dts/HtmlChunk.d.ts.map +1 -1
  91. package/dist/dts/Hydrate.d.ts +1 -3
  92. package/dist/dts/Hydrate.d.ts.map +1 -1
  93. package/dist/dts/Many.d.ts +9 -11
  94. package/dist/dts/Many.d.ts.map +1 -1
  95. package/dist/dts/Meta.d.ts +5 -1
  96. package/dist/dts/Meta.d.ts.map +1 -1
  97. package/dist/dts/Parser.d.ts +1 -1
  98. package/dist/dts/Parser.d.ts.map +1 -1
  99. package/dist/dts/Part.d.ts +20 -56
  100. package/dist/dts/Part.d.ts.map +1 -1
  101. package/dist/dts/Placeholder.d.ts +6 -10
  102. package/dist/dts/Placeholder.d.ts.map +1 -1
  103. package/dist/dts/Platform.d.ts +2 -4
  104. package/dist/dts/Platform.d.ts.map +1 -1
  105. package/dist/dts/Render.d.ts +4 -8
  106. package/dist/dts/Render.d.ts.map +1 -1
  107. package/dist/dts/RenderContext.d.ts +3 -22
  108. package/dist/dts/RenderContext.d.ts.map +1 -1
  109. package/dist/dts/RenderEvent.d.ts +6 -1
  110. package/dist/dts/RenderEvent.d.ts.map +1 -1
  111. package/dist/dts/RenderQueue.d.ts +103 -0
  112. package/dist/dts/RenderQueue.d.ts.map +1 -0
  113. package/dist/dts/RenderTemplate.d.ts +3 -2
  114. package/dist/dts/RenderTemplate.d.ts.map +1 -1
  115. package/dist/dts/Renderable.d.ts +1 -1
  116. package/dist/dts/Template.d.ts +14 -1
  117. package/dist/dts/Template.d.ts.map +1 -1
  118. package/dist/dts/Test.d.ts +14 -1
  119. package/dist/dts/Test.d.ts.map +1 -1
  120. package/dist/dts/Vitest.d.ts +11 -8
  121. package/dist/dts/Vitest.d.ts.map +1 -1
  122. package/dist/dts/index.d.ts +4 -0
  123. package/dist/dts/index.d.ts.map +1 -1
  124. package/dist/dts/internal/EventSource.d.ts +2 -1
  125. package/dist/dts/internal/EventSource.d.ts.map +1 -1
  126. package/dist/dts/internal/browser.d.ts +3 -3
  127. package/dist/dts/internal/browser.d.ts.map +1 -1
  128. package/dist/dts/internal/character-entities.d.ts +2133 -0
  129. package/dist/dts/internal/character-entities.d.ts.map +1 -0
  130. package/dist/dts/internal/errors.d.ts +9 -1
  131. package/dist/dts/internal/errors.d.ts.map +1 -1
  132. package/dist/dts/internal/indexRefCounter.d.ts +0 -4
  133. package/dist/dts/internal/indexRefCounter.d.ts.map +1 -1
  134. package/dist/dts/internal/parser.d.ts +13 -0
  135. package/dist/dts/internal/parser.d.ts.map +1 -1
  136. package/dist/dts/internal/parser2.d.ts +12 -0
  137. package/dist/dts/internal/parser2.d.ts.map +1 -0
  138. package/dist/dts/internal/server-parts.d.ts +223 -0
  139. package/dist/dts/internal/server-parts.d.ts.map +1 -0
  140. package/dist/dts/internal/server.d.ts +2 -28
  141. package/dist/dts/internal/server.d.ts.map +1 -1
  142. package/dist/dts/internal/utils.d.ts +4 -1
  143. package/dist/dts/internal/utils.d.ts.map +1 -1
  144. package/dist/dts/internal/v2/SyncPart.d.ts +87 -0
  145. package/dist/dts/internal/v2/SyncPart.d.ts.map +1 -0
  146. package/dist/dts/internal/v2/helpers.d.ts +3 -0
  147. package/dist/dts/internal/v2/helpers.d.ts.map +1 -0
  148. package/dist/dts/internal/v2/hydrate.d.ts +7 -0
  149. package/dist/dts/internal/v2/hydrate.d.ts.map +1 -0
  150. package/dist/dts/internal/v2/hydration-template.d.ts +54 -0
  151. package/dist/dts/internal/v2/hydration-template.d.ts.map +1 -0
  152. package/dist/dts/internal/v2/parts.d.ts +245 -0
  153. package/dist/dts/internal/v2/parts.d.ts.map +1 -0
  154. package/dist/dts/internal/v2/render-entry.d.ts +6 -0
  155. package/dist/dts/internal/v2/render-entry.d.ts.map +1 -0
  156. package/dist/dts/internal/v2/render-sync-parts.d.ts +22 -0
  157. package/dist/dts/internal/v2/render-sync-parts.d.ts.map +1 -0
  158. package/dist/dts/internal/v2/render.d.ts +62 -0
  159. package/dist/dts/internal/v2/render.d.ts.map +1 -0
  160. package/dist/dts/internal/v2/sync-parts.d.ts +129 -0
  161. package/dist/dts/internal/v2/sync-parts.d.ts.map +1 -0
  162. package/dist/esm/ElementRef.js.map +1 -1
  163. package/dist/esm/EventHandler.js +14 -4
  164. package/dist/esm/EventHandler.js.map +1 -1
  165. package/dist/esm/Html.js +91 -50
  166. package/dist/esm/Html.js.map +1 -1
  167. package/dist/esm/HtmlChunk.js +75 -24
  168. package/dist/esm/HtmlChunk.js.map +1 -1
  169. package/dist/esm/Hydrate.js +5 -5
  170. package/dist/esm/Hydrate.js.map +1 -1
  171. package/dist/esm/Many.js +3 -3
  172. package/dist/esm/Many.js.map +1 -1
  173. package/dist/esm/Meta.js +7 -1
  174. package/dist/esm/Meta.js.map +1 -1
  175. package/dist/esm/Parser.js +1 -1
  176. package/dist/esm/Parser.js.map +1 -1
  177. package/dist/esm/Placeholder.js +4 -8
  178. package/dist/esm/Placeholder.js.map +1 -1
  179. package/dist/esm/Platform.js +3 -1
  180. package/dist/esm/Platform.js.map +1 -1
  181. package/dist/esm/Render.js +6 -5
  182. package/dist/esm/Render.js.map +1 -1
  183. package/dist/esm/RenderContext.js +5 -85
  184. package/dist/esm/RenderContext.js.map +1 -1
  185. package/dist/esm/RenderEvent.js +8 -1
  186. package/dist/esm/RenderEvent.js.map +1 -1
  187. package/dist/esm/RenderQueue.js +336 -0
  188. package/dist/esm/RenderQueue.js.map +1 -0
  189. package/dist/esm/RenderTemplate.js.map +1 -1
  190. package/dist/esm/Template.js +12 -0
  191. package/dist/esm/Template.js.map +1 -1
  192. package/dist/esm/Test.js +71 -30
  193. package/dist/esm/Test.js.map +1 -1
  194. package/dist/esm/Vitest.js +11 -8
  195. package/dist/esm/Vitest.js.map +1 -1
  196. package/dist/esm/index.js +4 -0
  197. package/dist/esm/index.js.map +1 -1
  198. package/dist/esm/internal/EventSource.js +12 -7
  199. package/dist/esm/internal/EventSource.js.map +1 -1
  200. package/dist/esm/internal/HydrateContext.js.map +1 -1
  201. package/dist/esm/internal/browser.js +10 -9
  202. package/dist/esm/internal/browser.js.map +1 -1
  203. package/dist/esm/internal/character-entities.js +2134 -0
  204. package/dist/esm/internal/character-entities.js.map +1 -0
  205. package/dist/esm/internal/errors.js +22 -2
  206. package/dist/esm/internal/errors.js.map +1 -1
  207. package/dist/esm/internal/indexRefCounter.js +36 -61
  208. package/dist/esm/internal/indexRefCounter.js.map +1 -1
  209. package/dist/esm/internal/parser.js +18 -18
  210. package/dist/esm/internal/parser.js.map +1 -1
  211. package/dist/esm/internal/parser2.js +393 -0
  212. package/dist/esm/internal/parser2.js.map +1 -0
  213. package/dist/esm/internal/server-parts.js +109 -0
  214. package/dist/esm/internal/server-parts.js.map +1 -0
  215. package/dist/esm/internal/server.js +12 -161
  216. package/dist/esm/internal/server.js.map +1 -1
  217. package/dist/esm/internal/utils.js +71 -7
  218. package/dist/esm/internal/utils.js.map +1 -1
  219. package/dist/esm/internal/v2/SyncPart.js +5 -0
  220. package/dist/esm/internal/v2/SyncPart.js.map +1 -0
  221. package/dist/esm/internal/v2/helpers.js +12 -0
  222. package/dist/esm/internal/v2/helpers.js.map +1 -0
  223. package/dist/esm/internal/v2/hydrate.js +195 -0
  224. package/dist/esm/internal/v2/hydrate.js.map +1 -0
  225. package/dist/esm/internal/v2/hydration-template.js +265 -0
  226. package/dist/esm/internal/v2/hydration-template.js.map +1 -0
  227. package/dist/esm/internal/v2/parts.js +150 -0
  228. package/dist/esm/internal/v2/parts.js.map +1 -0
  229. package/dist/esm/internal/v2/render-entry.js +102 -0
  230. package/dist/esm/internal/v2/render-entry.js.map +1 -0
  231. package/dist/esm/internal/v2/render-sync-parts.js +265 -0
  232. package/dist/esm/internal/v2/render-sync-parts.js.map +1 -0
  233. package/dist/esm/internal/v2/render.js +353 -0
  234. package/dist/esm/internal/v2/render.js.map +1 -0
  235. package/dist/esm/internal/v2/sync-parts.js +102 -0
  236. package/dist/esm/internal/v2/sync-parts.js.map +1 -0
  237. package/package.json +20 -13
  238. package/src/ElementRef.ts +1 -1
  239. package/src/ElementSource.ts +1 -1
  240. package/src/EventHandler.ts +29 -11
  241. package/src/Html.ts +199 -90
  242. package/src/HtmlChunk.ts +77 -30
  243. package/src/Hydrate.ts +20 -14
  244. package/src/Many.ts +17 -14
  245. package/src/Meta.ts +8 -1
  246. package/src/Parser.ts +1 -1
  247. package/src/Part.ts +22 -66
  248. package/src/Placeholder.ts +17 -15
  249. package/src/Platform.ts +5 -5
  250. package/src/Render.ts +23 -26
  251. package/src/RenderContext.ts +14 -142
  252. package/src/RenderEvent.ts +10 -1
  253. package/src/RenderQueue.ts +445 -0
  254. package/src/RenderTemplate.ts +7 -2
  255. package/src/Renderable.ts +1 -1
  256. package/src/Template.ts +15 -1
  257. package/src/Test.ts +122 -38
  258. package/src/Vitest.ts +20 -10
  259. package/src/index.ts +4 -0
  260. package/src/internal/EventSource.ts +14 -8
  261. package/src/internal/HydrateContext.ts +3 -4
  262. package/src/internal/browser.ts +26 -21
  263. package/src/internal/character-entities.ts +2136 -0
  264. package/src/internal/errors.ts +30 -3
  265. package/src/internal/indexRefCounter.ts +38 -70
  266. package/src/internal/parser.ts +19 -19
  267. package/src/internal/parser2.ts +468 -0
  268. package/src/internal/server-parts.ts +161 -0
  269. package/src/internal/server.ts +16 -272
  270. package/src/internal/utils.ts +83 -7
  271. package/src/internal/v2/SyncPart.ts +112 -0
  272. package/src/internal/v2/helpers.ts +13 -0
  273. package/src/internal/v2/hydrate.ts +289 -0
  274. package/src/internal/v2/hydration-template.ts +308 -0
  275. package/src/internal/v2/parts.ts +254 -0
  276. package/src/internal/v2/render-entry.ts +131 -0
  277. package/src/internal/v2/render-sync-parts.ts +440 -0
  278. package/src/internal/v2/render.ts +588 -0
  279. package/src/internal/v2/sync-parts.ts +133 -0
  280. package/dist/cjs/internal/hydrate.js +0 -274
  281. package/dist/cjs/internal/hydrate.js.map +0 -1
  282. package/dist/cjs/internal/parts.js +0 -451
  283. package/dist/cjs/internal/parts.js.map +0 -1
  284. package/dist/cjs/internal/render.js +0 -704
  285. package/dist/cjs/internal/render.js.map +0 -1
  286. package/dist/dts/internal/hydrate.d.ts +0 -33
  287. package/dist/dts/internal/hydrate.d.ts.map +0 -1
  288. package/dist/dts/internal/parts.d.ts +0 -314
  289. package/dist/dts/internal/parts.d.ts.map +0 -1
  290. package/dist/dts/internal/render.d.ts +0 -16
  291. package/dist/dts/internal/render.d.ts.map +0 -1
  292. package/dist/esm/internal/hydrate.js +0 -239
  293. package/dist/esm/internal/hydrate.js.map +0 -1
  294. package/dist/esm/internal/parts.js +0 -373
  295. package/dist/esm/internal/parts.js.map +0 -1
  296. package/dist/esm/internal/render.js +0 -689
  297. package/dist/esm/internal/render.js.map +0 -1
  298. package/src/internal/hydrate.ts +0 -366
  299. package/src/internal/parts.ts +0 -609
  300. package/src/internal/render.ts +0 -971
@@ -1,112 +1,7 @@
1
- import * as Effect from "effect/Effect"
2
- import type { HtmlChunk, PartChunk, SparsePartChunk } from "../HtmlChunk.js"
3
- import type {
4
- AttributePart,
5
- ClassNamePart,
6
- CommentPart,
7
- Part,
8
- SparseAttributePart,
9
- SparseClassNamePart,
10
- SparseCommentPart,
11
- SparsePart,
12
- StaticText
13
- } from "../Part.js"
14
- import type { Renderable } from "../Renderable.js"
15
- import type { PartNode, SparseAttrNode, SparseClassNameNode, SparseCommentNode, SparsePartNode } from "../Template.js"
16
- import {
17
- AttributePartImpl,
18
- BooleanPartImpl,
19
- ClassNamePartImpl,
20
- CommentPartImpl,
21
- DataPartImpl,
22
- NodePartImpl,
23
- PropertiesPartImpl,
24
- PropertyPartImpl,
25
- SparseAttributePartImpl,
26
- SparseClassNamePartImpl,
27
- SparseCommentPartImpl,
28
- StaticTextImpl,
29
- TextPartImpl
30
- } from "./parts.js"
31
-
32
- export type RenderChunk<R, E> =
33
- | TextRenderChunk
34
- | PartRenderChunk<R, E>
35
- | SparsePartRenderChunk<R, E>
36
-
37
- export class TextRenderChunk {
38
- readonly type = "text"
39
-
40
- constructor(
41
- readonly index: number,
42
- readonly value: string
43
- ) {}
44
- }
45
-
46
- export class PartRenderChunk<R, E> {
47
- readonly type = "part"
48
-
49
- constructor(
50
- readonly index: number,
51
- readonly chunk: PartChunk,
52
- readonly part: Part,
53
- readonly renderable: Renderable<R, E>
54
- ) {}
55
- }
56
-
57
- export class SparsePartRenderChunk<R, E> {
58
- readonly type = "sparse-part"
59
-
60
- constructor(
61
- readonly index: number,
62
- readonly chunk: SparsePartChunk,
63
- readonly part: SparsePart,
64
- readonly renderables: Array<Renderable<R, E>>
65
- ) {}
66
- }
67
-
68
- type RenderChunkMap = {
69
- readonly [K in HtmlChunk["_tag"]]: <R, E>(
70
- chunk: Extract<HtmlChunk, { _tag: K }>,
71
- index: number,
72
- values: ReadonlyArray<Renderable<any, any>>,
73
- onChunk: (index: number, value: string) => Effect.Effect<void>
74
- ) => RenderChunk<R, E>
75
- }
76
-
77
- const renderChunkMap: RenderChunkMap = {
78
- text: (chunk, index) => new TextRenderChunk(index, chunk.value),
79
- part: (chunk, index, values, onChunk) =>
80
- new PartRenderChunk(
81
- index,
82
- chunk,
83
- partNodeToPart(chunk.node, (v) => onChunk(index, chunk.render(v))),
84
- values[chunk.node.index]
85
- ),
86
- "sparse-part": (chunk, index, values, onChunk) =>
87
- new SparsePartRenderChunk(
88
- index,
89
- chunk,
90
- sparsePartNodeToPart(chunk.node, (v) => onChunk(index, chunk.render(v))),
91
- // @ts-ignore Type Instantiation is excessively deep and possibly infinite
92
- chunk.node.nodes.map((n) => (n._tag === "text" ? n.value : values[n.index]))
93
- )
94
- }
95
-
96
- export function htmlChunksToRenderChunks<R, E>(
97
- chunks: ReadonlyArray<HtmlChunk>,
98
- values: ReadonlyArray<Renderable<R, E>>,
99
- onChunk: (index: number, value: string) => Effect.Effect<void>
100
- ) {
101
- const output: Array<RenderChunk<R, E>> = Array(chunks.length)
102
-
103
- for (let i = 0; i < chunks.length; i++) {
104
- // @ts-ignore Type Instantiation is excessively deep and possibly infinite
105
- output[i] = renderChunkMap[chunks[i]._tag](chunks[i] as any, i, values, onChunk)
106
- }
107
-
108
- return output
109
- }
1
+ import type * as Effect from "effect/Effect"
2
+ import type { Part } from "../Part.js"
3
+ import type { PartNode } from "../Template.js"
4
+ import * as impls from "./server-parts.js"
110
5
 
111
6
  type PartNodeMap = {
112
7
  readonly [K in PartNode["_tag"]]: (
@@ -116,21 +11,22 @@ type PartNodeMap = {
116
11
  }
117
12
 
118
13
  const partNodeMap: PartNodeMap = {
119
- attr: (node, onChunk) => new AttributePartImpl(node.name, node.index, ({ value }) => onChunk(value), null),
120
- "boolean-part": (node, onChunk) => new BooleanPartImpl(node.name, node.index, ({ value }) => onChunk(value), null),
121
- "className-part": (node, onChunk) => new ClassNamePartImpl(node.index, ({ value }) => onChunk(value), null),
122
- "comment-part": (node, onChunk) => new CommentPartImpl(node.index, ({ value }) => onChunk(value), null),
123
- "data": (node, onChunk) => new DataPartImpl(node.index, ({ value }) => onChunk(value), null),
124
- "event": () => {
14
+ attr: (node, onChunk) => new impls.AttributePartImpl(node.name, node.index, ({ value }) => onChunk(value), null),
15
+ "boolean-part": (node, onChunk) =>
16
+ new impls.BooleanPartImpl(node.name, node.index, ({ value }) => onChunk(value), null),
17
+ "className-part": (node, onChunk) => new impls.ClassNamePartImpl(node.index, ({ value }) => onChunk(value), []),
18
+ "comment-part": (node, onChunk) => new impls.CommentPartImpl(node.index, ({ value }) => onChunk(value), null),
19
+ data: (node, onChunk) => new impls.DataPartImpl(node.index, ({ value }) => onChunk(value), null),
20
+ event: () => {
125
21
  throw new Error("Events are not utilized on the server")
126
22
  },
127
- "node": (node, onChunk) => new NodePartImpl(node.index, ({ value }) => onChunk(value), null),
128
- "property": (node, onChunk) => new PropertyPartImpl(node.name, node.index, ({ value }) => onChunk(value), null),
129
- "ref": () => {
23
+ node: (node, onChunk) => new impls.NodePartImpl(node.index, ({ value }) => onChunk(value), null),
24
+ property: (node, onChunk) => new impls.PropertyPartImpl(node.name, node.index, ({ value }) => onChunk(value), null),
25
+ ref: () => {
130
26
  throw new Error("Refs are not utilized on the server")
131
27
  },
132
- "text-part": (node, onChunk) => new TextPartImpl(node.index, ({ value }) => onChunk(value), null),
133
- "properties": (node, onChunk) => new PropertiesPartImpl(node.index, ({ value }) => onChunk(value), null)
28
+ "text-part": (node, onChunk) => new impls.TextPartImpl(node.index, ({ value }) => onChunk(value), null),
29
+ properties: (node, onChunk) => new impls.PropertiesPartImpl(node.index, ({ value }) => onChunk(value), [])
134
30
  }
135
31
 
136
32
  export function partNodeToPart(
@@ -139,155 +35,3 @@ export function partNodeToPart(
139
35
  ): Part {
140
36
  return partNodeMap[node._tag](node as any, onChunk)
141
37
  }
142
-
143
- function sparsePartNodeToPart(
144
- node: SparsePartNode,
145
- onChunk: (value: string | null) => Effect.Effect<void>
146
- ) {
147
- if (node._tag === "sparse-attr") {
148
- return renderSparseAttr(node, onChunk)
149
- } else if (node._tag === "sparse-class-name") {
150
- return renderSparseClassName(node, onChunk)
151
- } else {
152
- return renderSparseComment(node, onChunk)
153
- }
154
- }
155
-
156
- function renderSparseAttr(
157
- attrNode: SparseAttrNode,
158
- setAttribute: (value: string | null) => Effect.Effect<void>
159
- ): SparseAttributePart {
160
- const { nodes } = attrNode
161
- const values: Map<number, string | null> = new Map()
162
-
163
- function getValue() {
164
- return (part.value = Array.from({ length: nodes.length }, (_, i) => values.get(i) || ""))
165
- }
166
-
167
- function setValue(value: string | null, index: number) {
168
- return Effect.suspend(() => {
169
- values.set(index, value)
170
-
171
- if (values.size === nodes.length) return setAttribute(getValue().join(""))
172
-
173
- return Effect.unit
174
- })
175
- }
176
-
177
- const parts: Array<StaticText | AttributePart> = []
178
-
179
- let partIndex = 0
180
- for (let i = 0; i < nodes.length; i++) {
181
- const node = nodes[i]
182
-
183
- if (node._tag === "text") {
184
- values.set(i, node.value)
185
- parts.push(new StaticTextImpl(node.value))
186
- } else {
187
- parts.push(
188
- new AttributePartImpl(
189
- node.name,
190
- partIndex++,
191
- ({ value }) => setValue(value || "", i),
192
- null
193
- )
194
- )
195
- }
196
- }
197
-
198
- const part = new SparseAttributePartImpl(attrNode.name, parts, ({ value }) => setAttribute(value.join("")))
199
-
200
- return part
201
- }
202
-
203
- function renderSparseClassName(
204
- classNameNode: SparseClassNameNode,
205
- setClassName: (value: string | null) => Effect.Effect<void>
206
- ): SparseClassNamePart {
207
- const { nodes } = classNameNode
208
- const values: Map<number, string | null> = new Map()
209
-
210
- function getValue() {
211
- return (part.value = Array.from({ length: nodes.length }, (_, i) => values.get(i) || ""))
212
- }
213
-
214
- function setValue(value: string | null, index: number) {
215
- return Effect.suspend(() => {
216
- values.set(index, value)
217
-
218
- if (values.size === nodes.length) return setClassName(getValue().join(""))
219
-
220
- return Effect.unit
221
- })
222
- }
223
-
224
- const parts: Array<StaticText | ClassNamePart> = []
225
-
226
- let partIndex = 0
227
- for (let i = 0; i < nodes.length; i++) {
228
- const node = nodes[i]
229
-
230
- if (node._tag === "text") {
231
- values.set(i, node.value)
232
- parts.push(new StaticTextImpl(node.value))
233
- } else {
234
- parts.push(
235
- new ClassNamePartImpl(
236
- partIndex++,
237
- ({ value }) => setValue(value?.join(" ") || null, i),
238
- null
239
- )
240
- )
241
- }
242
- }
243
-
244
- const part = new SparseClassNamePartImpl(parts, ({ value }) => setClassName(value.join("")), [])
245
-
246
- return part
247
- }
248
-
249
- function renderSparseComment(
250
- commentNode: SparseCommentNode,
251
- setComment: (value: string | null) => Effect.Effect<void>
252
- ): SparseCommentPart {
253
- const { nodes } = commentNode
254
- const values: Map<number, string | null | undefined> = new Map()
255
-
256
- function getValue(): ReadonlyArray<string> {
257
- return (part.value = Array.from({ length: nodes.length }, (_, i) => values.get(i) || ""))
258
- }
259
-
260
- function setValue(value: string | null | undefined, index: number) {
261
- return Effect.suspend(() => {
262
- values.set(index, value)
263
-
264
- if (values.size === nodes.length) return setComment(getValue().join(""))
265
-
266
- return Effect.unit
267
- })
268
- }
269
-
270
- const parts: Array<StaticText | CommentPart> = []
271
-
272
- let partIndex = 0
273
- for (let i = 0; i < nodes.length; i++) {
274
- const node = nodes[i]
275
-
276
- if (node._tag === "text") {
277
- values.set(i, node.value)
278
- parts.push(new StaticTextImpl(node.value))
279
- } else {
280
- parts.push(
281
- new CommentPartImpl(
282
- partIndex++,
283
- ({ value }) => setValue(value, i),
284
- null
285
- )
286
- )
287
- }
288
- }
289
-
290
- const part = new SparseCommentPartImpl(parts, ({ value }) => setComment(value.join("")), [])
291
-
292
- return part
293
- }
@@ -3,8 +3,11 @@ import * as Chunk from "effect/Chunk"
3
3
  import type * as Duration from "effect/Duration"
4
4
  import * as Effect from "effect/Effect"
5
5
  import { isSome } from "effect/Option"
6
+ import { uncapitalize } from "effect/String"
6
7
  import { TestClock } from "effect/TestClock"
7
8
  import { TEXT_START, TYPED_START } from "../Meta.js"
9
+ import { CouldNotFindCommentError } from "./errors.js"
10
+ import { getNodesExcludingStartComment, type HydrationNode } from "./v2/hydration-template.js"
8
11
 
9
12
  export function isComment(node: Node): node is Comment {
10
13
  return node.nodeType === node.COMMENT_NODE
@@ -33,19 +36,31 @@ export function findHoleComment(parent: Element, index: number) {
33
36
  }
34
37
  }
35
38
 
36
- throw new Error(`Unable to find hole comment for index ${index}`)
39
+ throw new CouldNotFindCommentError(index)
37
40
  }
38
41
 
39
42
  const previousComments = new Set([TEXT_START, TYPED_START])
40
43
 
41
- export function getPreviousNodes(comment: Node, index: number) {
44
+ export function getPreviousNodes(comment: Node, index: number, hash?: string) {
42
45
  const nodes: Array<Node> = []
43
46
  let node = comment.previousSibling
44
47
  const previousHole = `hole${index - 1}`
48
+ const typedHash = hash ? `typed-${hash}` : ""
45
49
 
46
50
  previousComments.add(previousHole)
47
51
 
48
- while (node && !previousComments.has(String(node.nodeValue))) {
52
+ while (node) {
53
+ if (isComment(node)) {
54
+ if (previousComments.has(node.data)) {
55
+ break
56
+ }
57
+
58
+ if (node.data === typedHash) {
59
+ nodes.unshift(node)
60
+ break
61
+ }
62
+ }
63
+
49
64
  nodes.unshift(node)
50
65
  node = node.previousSibling
51
66
  }
@@ -58,20 +73,81 @@ export function getPreviousNodes(comment: Node, index: number) {
58
73
  export const findPath = (node: ParentChildNodes, path: Chunk.Chunk<number>): Node =>
59
74
  Chunk.reduce(path, node, ({ childNodes }, index) => childNodes[index]) as Node
60
75
 
76
+ export const findHydratePath = (
77
+ node: HydrationNode,
78
+ path: Chunk.Chunk<number>
79
+ ): Node => {
80
+ if (Chunk.isEmpty(path)) {
81
+ return getNodesExcludingStartComment(node)[0]
82
+ }
83
+
84
+ const [first, ...rest] = path
85
+
86
+ // Hydration adds an extra starting comment node which should not be included in the path
87
+ let current: Node = getNodesExcludingStartComment(node)[first]
88
+ for (const index of rest) {
89
+ current = Array.from(current.childNodes).filter(isNotStartComment)[index]
90
+ }
91
+
92
+ return current
93
+ }
94
+
95
+ function isNotStartComment(node: Node) {
96
+ return !isComment(node) || !node.data.startsWith("hole")
97
+ }
98
+
61
99
  export interface ParentChildNodes {
62
100
  readonly parentNode: Node | null
63
101
  readonly childNodes: ArrayLike<Node>
64
102
  }
65
103
 
66
104
  export function adjustTime(input?: Duration.DurationInput) {
67
- return Effect.gen(function*(_) {
68
- const ctx = yield* _(Effect.context<never>())
105
+ return Effect.gen(function*() {
106
+ const ctx = yield* Effect.context<never>()
69
107
  const testClock = getOption(ctx, TestClock)
70
108
 
71
109
  if (isSome(testClock)) {
72
- yield* _(testClock.value.adjust(input ?? 1))
110
+ yield* testClock.value.adjust(input ?? 1)
73
111
  } else if (input) {
74
- yield* _(Effect.sleep(input))
112
+ yield* Effect.sleep(input)
75
113
  }
76
114
  })
77
115
  }
116
+
117
+ export function keyToPartType(key: string) {
118
+ switch (key[0]) {
119
+ case "?":
120
+ return ["boolean", key.slice(1)] as const
121
+ case ".": {
122
+ const propertyName = key.slice(1)
123
+
124
+ if (propertyName === "data") {
125
+ return ["data"] as const
126
+ } else if (
127
+ propertyName === "props" || propertyName === "properties"
128
+ ) {
129
+ return ["properties"] as const
130
+ } else {
131
+ return ["property", propertyName] as const
132
+ }
133
+ }
134
+ case "@":
135
+ return ["event", uncapitalize(key.slice(1))] as const
136
+ case "o": {
137
+ if (key[1] === "n") {
138
+ const name = uncapitalize(key.slice(2))
139
+ return ["event", name] as const
140
+ }
141
+ }
142
+ }
143
+
144
+ const lower = key.toLowerCase()
145
+
146
+ if (lower === "ref") {
147
+ return ["ref"] as const
148
+ } else if (lower === "class" || lower === "classname") {
149
+ return ["class"] as const
150
+ } else {
151
+ return ["attr", key] as const
152
+ }
153
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+
5
+ /**
6
+ * @since 1.0.0
7
+ */
8
+ export type SyncPart =
9
+ | AttributeSyncPart
10
+ | BooleanSyncPart
11
+ | ClassNameSyncPart
12
+ | CommentSyncPart
13
+ | DataSyncPart
14
+ | NodeSyncPart
15
+ | PropertySyncPart
16
+ | TextSyncPart
17
+
18
+ /**
19
+ * @since 1.0.0
20
+ */
21
+ export interface AttributeSyncPart {
22
+ readonly _tag: "attribute"
23
+ readonly name: string
24
+ readonly value: string | null | undefined
25
+ readonly index: number
26
+
27
+ readonly update: (value: this["value"]) => boolean
28
+ }
29
+
30
+ /**
31
+ * @since 1.0.0
32
+ */
33
+ export interface BooleanSyncPart {
34
+ readonly _tag: "boolean"
35
+ readonly name: string
36
+ readonly value: boolean | null | undefined
37
+ readonly index: number
38
+
39
+ readonly update: (value: this["value"]) => boolean
40
+ }
41
+
42
+ /**
43
+ * @since 1.0.0
44
+ */
45
+ export interface ClassNameSyncPart {
46
+ readonly _tag: "className"
47
+ readonly value: ReadonlyArray<string>
48
+ readonly index: number
49
+
50
+ readonly update: (value: this["value"]) => boolean
51
+ }
52
+
53
+ /**
54
+ * @since 1.0.0
55
+ */
56
+ export interface DataSyncPart {
57
+ readonly _tag: "data"
58
+ readonly value: Readonly<Record<string, string | undefined>> | null | undefined
59
+ readonly index: number
60
+
61
+ readonly update: (value: this["value"]) => boolean
62
+ }
63
+
64
+ /**
65
+ * @since 1.0.0
66
+ */
67
+ export interface PropertySyncPart {
68
+ readonly _tag: "property"
69
+ readonly name: string
70
+ readonly value: unknown
71
+ readonly index: number
72
+
73
+ readonly update: (value: this["value"]) => boolean
74
+ }
75
+
76
+ /**
77
+ * @since 1.0.0
78
+ */
79
+ export interface CommentSyncPart {
80
+ readonly _tag: "comment"
81
+ readonly value: string | null | undefined
82
+ readonly index: number
83
+
84
+ readonly update: (value: this["value"]) => boolean
85
+ }
86
+
87
+ /**
88
+ * @since 1.0.0
89
+ */
90
+ export interface TextSyncPart {
91
+ readonly _tag: "text"
92
+ readonly value: string | null | undefined
93
+ readonly index: number
94
+
95
+ readonly update: (value: this["value"]) => boolean
96
+ }
97
+
98
+ /**
99
+ * @since 1.0.0
100
+ */
101
+ export interface NodeSyncPart {
102
+ readonly _tag: "node"
103
+ readonly value: unknown
104
+ readonly index: number
105
+
106
+ readonly update: (value: this["value"]) => boolean
107
+ }
108
+
109
+ /**
110
+ * @since 1.0.0
111
+ */
112
+ export type SyncParts = ReadonlyArray<SyncPart>
@@ -0,0 +1,13 @@
1
+ import { hasProperty } from "effect/Predicate"
2
+
3
+ export function isNullOrUndefined<T>(value: T | null | undefined): value is null | undefined {
4
+ return value === null || value === undefined
5
+ }
6
+
7
+ export function renderToString(value: unknown): string {
8
+ return isNullOrUndefined(value)
9
+ ? ""
10
+ : hasProperty(value, "toString") && typeof value.toString === "function"
11
+ ? value.toString()
12
+ : String(value)
13
+ }