@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
package/src/Renderable.ts CHANGED
@@ -10,7 +10,7 @@ import type { RenderEvent } from "./RenderEvent.js"
10
10
  /**
11
11
  * @since 1.0.0
12
12
  */
13
- export type Renderable<R = never, E = never> =
13
+ export type Renderable<E = never, R = never> =
14
14
  | Renderable.Value
15
15
  | Placeholder<any, E, R>
16
16
  | { readonly [key: string]: Renderable<E, R> | Placeholder<any, E, R> | unknown } // TODO: Should we manage data attributes this way?
package/src/Template.ts CHANGED
@@ -2,11 +2,12 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
  import type { Chunk } from "effect/Chunk"
5
+ import { type Inspectable, NodeInspectSymbol } from "effect/Inspectable"
5
6
 
6
7
  /**
7
8
  * @since 1.0.0
8
9
  */
9
- export class Template {
10
+ export class Template implements Inspectable {
10
11
  readonly _tag = "template"
11
12
 
12
13
  constructor(
@@ -16,6 +17,19 @@ export class Template {
16
17
  /// any nodes/elements into the template.
17
18
  readonly parts: ReadonlyArray<readonly [part: PartNode | SparsePartNode, path: Chunk<number>]>
18
19
  ) {}
20
+
21
+ toJSON() {
22
+ return {
23
+ _tag: "template",
24
+ nodes: this.nodes,
25
+ hash: this.hash,
26
+ parts: this.parts.map(([part, path]) => [part, path.toJSON()])
27
+ }
28
+ }
29
+
30
+ [NodeInspectSymbol]() {
31
+ return this.toJSON()
32
+ }
19
33
  }
20
34
 
21
35
  /**
package/src/Test.ts CHANGED
@@ -10,22 +10,23 @@ import * as Fx from "@typed/fx/Fx"
10
10
  import * as RefArray from "@typed/fx/RefArray"
11
11
  import * as RefSubject from "@typed/fx/RefSubject"
12
12
  import * as Sink from "@typed/fx/Sink"
13
- import { type Rendered } from "@typed/wire"
14
- import { Layer } from "effect"
13
+ import { isComment, type Rendered } from "@typed/wire"
15
14
  import * as Cause from "effect/Cause"
16
15
  import type { DurationInput } from "effect/Duration"
17
16
  import * as Effect from "effect/Effect"
18
17
  import * as Either from "effect/Either"
19
18
  import * as Fiber from "effect/Fiber"
19
+ import * as Layer from "effect/Layer"
20
20
  import type * as Scope from "effect/Scope"
21
21
  import * as ElementRef from "./ElementRef.js"
22
22
  import { ROOT_CSS_SELECTOR } from "./ElementSource.js"
23
- import { renderToHtmlString, serverLayer } from "./Html.js"
23
+ import { renderToHtml, renderToHtmlString, serverLayer, staticLayer } from "./Html.js"
24
24
  import { hydrate, hydrateLayer } from "./Hydrate.js"
25
25
  import { adjustTime } from "./internal/utils.js"
26
26
  import { render, renderLayer } from "./Render.js"
27
27
  import type * as RenderContext from "./RenderContext.js"
28
28
  import type { RenderEvent } from "./RenderEvent.js"
29
+ import * as RenderQueue from "./RenderQueue.js"
29
30
  import type { RenderTemplate } from "./RenderTemplate.js"
30
31
 
31
32
  // TODO: Instrument RenderTemplate to log info about when specific values are hanging for too long
@@ -65,14 +66,17 @@ export function testRender<E, R>(
65
66
  ): Effect.Effect<
66
67
  TestRender<E>,
67
68
  never,
68
- Scope.Scope | Exclude<R, RenderTemplate | RenderContext.RenderContext | CurrentEnvironment | DomServices>
69
+ | Scope.Scope
70
+ | Exclude<
71
+ R,
72
+ RenderTemplate | RenderContext.RenderContext | CurrentEnvironment | DomServices
73
+ >
69
74
  > {
70
- return Effect.gen(function*(_) {
71
- const window = yield* _(getOrMakeWindow(options))
72
- const elementRef = yield* _(ElementRef.make())
73
- const errors = yield* _(RefSubject.make<ReadonlyArray<E>>(Effect.succeed([])))
74
- const fiber = yield* _(
75
- fx,
75
+ return Effect.gen(function*() {
76
+ const window = yield* getOrMakeWindow(options)
77
+ const elementRef = yield* ElementRef.make()
78
+ const errors = yield* RefSubject.make<ReadonlyArray<E>>(Effect.succeed([]))
79
+ const fiber = yield* fx.pipe(
76
80
  render,
77
81
  (x) =>
78
82
  x.run(Sink.make(
@@ -86,7 +90,7 @@ export function testRender<E, R>(
86
90
  (rendered) => ElementRef.set(elementRef, rendered)
87
91
  )),
88
92
  Effect.forkScoped,
89
- Effect.provide(renderLayer(window, { skipRenderScheduling: true }))
93
+ Effect.provide(Layer.mergeAll(renderLayer(window)))
90
94
  )
91
95
 
92
96
  const test: TestRender<E> = {
@@ -103,17 +107,20 @@ export function testRender<E, R>(
103
107
  }
104
108
 
105
109
  // Allow our fibers to start
106
- yield* _(adjustTime(1))
107
- yield* _(adjustTime(1))
110
+ yield* adjustTime(1)
111
+ yield* adjustTime(1)
108
112
 
109
113
  // Await the first render
110
- yield* _(
114
+ yield* Effect.race(
111
115
  Fx.first(elementRef),
112
- Effect.race(Effect.delay(Effect.dieMessage(`Rendering taking too long`), options?.renderTimeout ?? 1000))
116
+ Effect.flatMap(
117
+ Effect.sleep(options?.renderTimeout ?? 1000),
118
+ (_) => Effect.dieMessage(`Rendering taking too long`)
119
+ )
113
120
  )
114
121
 
115
122
  return test
116
- })
123
+ }).pipe(Effect.provide(RenderQueue.sync))
117
124
  }
118
125
 
119
126
  /**
@@ -126,7 +133,15 @@ export type EventOptions = {
126
133
  }
127
134
 
128
135
  // TODO: Find more events to add here
129
- const NON_BUBBLING_EVENTS = new Set(["focus", "blur"])
136
+ const NON_BUBBLING_EVENTS = new Set([
137
+ "focus",
138
+ "blur",
139
+ "loadstart",
140
+ "progress",
141
+ "error",
142
+ "load",
143
+ "loadend"
144
+ ])
130
145
 
131
146
  /**
132
147
  * @since 1.0.0
@@ -159,19 +174,19 @@ export function click<E>(
159
174
 
160
175
  // internals
161
176
 
162
- function getOrMakeWindow(
177
+ export function getOrMakeWindow(
163
178
  options?: HappyDOMOptions
164
179
  ): Effect.Effect<Window & GlobalThis, never, Scope.Scope> {
165
180
  if (typeof window !== "undefined" && typeof document !== "undefined") {
166
- return Effect.gen(function*(_) {
181
+ return Effect.gen(function*() {
167
182
  window.document.head.innerHTML = ""
168
183
  window.document.body.innerHTML = ""
169
- yield* _(Effect.addFinalizer(() =>
184
+ yield* Effect.addFinalizer(() =>
170
185
  Effect.sync(() => {
171
186
  window.document.head.innerHTML = ""
172
187
  window.document.body.innerHTML = ""
173
188
  })
174
- ))
189
+ )
175
190
 
176
191
  return window
177
192
  })
@@ -201,30 +216,34 @@ export function testHydrate<R, E, Elements>(
201
216
  ): Effect.Effect<
202
217
  TestHydrate<E, Elements>,
203
218
  E,
204
- Scope.Scope | Exclude<R, RenderTemplate | RenderContext.RenderContext | CurrentEnvironment | DomServices>
219
+ | Scope.Scope
220
+ | Exclude<
221
+ R,
222
+ RenderContext.RenderContext | RenderQueue.RenderQueue | RenderTemplate | CurrentEnvironment | DomServices
223
+ >
224
+ | Exclude<R, RenderContext.RenderContext | RenderTemplate | CurrentEnvironment | DomServices>
205
225
  > {
206
- return Effect.gen(function*(_) {
207
- const window = yield* _(getOrMakeWindow(options))
226
+ return Effect.gen(function*() {
227
+ const window = yield* getOrMakeWindow(options)
208
228
  const { body } = window.document
209
229
 
210
- const html = yield* _(
230
+ const html = yield* Effect.provide(
211
231
  renderToHtmlString(fx),
212
- Effect.provide(serverLayer.pipe(
232
+ serverLayer.pipe(
213
233
  // Add DomServices to the layer for the types
214
234
  Layer.provideMerge(domServices()),
215
235
  Layer.provideMerge(Window.layer(window)),
216
236
  Layer.provideMerge(GlobalThis.layer(window))
217
- ))
237
+ )
218
238
  )
219
239
 
220
240
  body.innerHTML = html
221
241
 
222
242
  const rendered = Array.from(body.childNodes)
223
- const elements = f(rendered.length === 1 ? rendered[0] : rendered, window)
224
- const elementRef = yield* _(ElementRef.make())
225
- const errors = yield* _(RefSubject.make<ReadonlyArray<E>>(Effect.succeed([])))
226
- const fiber = yield* _(
227
- fx,
243
+ const elements = f(fromRendered(rendered), window)
244
+ const elementRef = yield* ElementRef.make()
245
+ const errors = yield* RefSubject.make<ReadonlyArray<E>>(Effect.succeed([]))
246
+ const fiber = yield* fx.pipe(
228
247
  hydrate,
229
248
  (x) =>
230
249
  x.run(Sink.make(
@@ -234,13 +253,17 @@ export function testHydrate<R, E, Elements>(
234
253
  Cause.failureOrCause(cause).pipe(
235
254
  Either.match({
236
255
  onLeft: (error) => RefArray.append(errors, error),
237
- onRight: (cause) => errors.onFailure(cause)
256
+ onRight: (cause) => elementRef[ElementRef.ElementRefTypeId].onFailure(cause)
238
257
  })
239
258
  )
240
259
  ),
241
- (rendered) => ElementRef.set(elementRef, rendered)
260
+ (rendered) =>
261
+ ElementRef.set(
262
+ elementRef,
263
+ fromRendered(rendered)
264
+ )
242
265
  )),
243
- Effect.provide(hydrateLayer(window, { skipRenderScheduling: true })),
266
+ Effect.provide(hydrateLayer(window)),
244
267
  Effect.forkScoped
245
268
  )
246
269
 
@@ -259,12 +282,73 @@ export function testHydrate<R, E, Elements>(
259
282
  }
260
283
 
261
284
  // Allow our fibers to start
262
- yield* _(adjustTime(1))
263
- yield* _(adjustTime(1))
285
+ yield* adjustTime(1)
286
+ yield* adjustTime(1)
264
287
 
265
288
  // Await the first render
266
- yield* _(Fx.first(elementRef), Effect.race(Effect.delay(Effect.dieMessage(`Rendering taking too long`), 1000)))
289
+ yield* Effect.race(Fx.first(elementRef), Effect.delay(Effect.dieMessage(`Rendering taking too long`), 1000))
267
290
 
268
291
  return test
269
292
  })
270
293
  }
294
+
295
+ function fromRendered(rendered: Rendered) {
296
+ const elements = Array.isArray(rendered)
297
+ ? rendered.filter((x) => isComment(x) ? !(x.data.startsWith("typed") || x.data.startsWith("/typed")) : true)
298
+ : rendered
299
+
300
+ return Array.isArray(elements) && elements.length === 1
301
+ ? elements[0]
302
+ : elements
303
+ }
304
+
305
+ const typedTemplateStartCommentRegex =
306
+ /<!--typed-((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}={2}))-->/g
307
+ const typedTemplateEndCommentRegex =
308
+ /<!--\/typed-((?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}={2}))-->/g
309
+
310
+ export function isTemplateStartComment(comment: Comment) {
311
+ return typedTemplateStartCommentRegex.test(`${comment.nodeValue}`)
312
+ }
313
+
314
+ export function isTemplateEndComment(comment: Comment) {
315
+ return typedTemplateEndCommentRegex.test(`${comment.nodeValue}`)
316
+ }
317
+
318
+ export function stripTypedTemplateComments(html: string) {
319
+ return html.replace(typedTemplateStartCommentRegex, "").replace(typedTemplateEndCommentRegex, "")
320
+ }
321
+
322
+ /**
323
+ * @since 1.0.0
324
+ */
325
+ export function testHtmlString<E, R>(
326
+ fx: Fx.Fx<RenderEvent, E, R>
327
+ ): Effect.Effect<
328
+ string,
329
+ E,
330
+ | Scope.Scope
331
+ | Exclude<
332
+ R,
333
+ RenderContext.RenderContext | RenderQueue.RenderQueue | RenderTemplate | CurrentEnvironment
334
+ >
335
+ > {
336
+ return Effect.provide(renderToHtmlString(fx), staticLayer)
337
+ }
338
+
339
+ /**
340
+ * @since 1.0.0
341
+ */
342
+ export function testHtmlChunks<E, R>(
343
+ fx: Fx.Fx<RenderEvent, E, R>
344
+ ): Effect.Effect<
345
+ ReadonlyArray<string>,
346
+ E,
347
+ | Scope.Scope
348
+ | Exclude<
349
+ R,
350
+ RenderContext.RenderContext | RenderQueue.RenderQueue | RenderTemplate | CurrentEnvironment
351
+ >
352
+ > {
353
+ return Fx.toReadonlyArray(Fx.provide(Fx.map(renderToHtml(fx), stripTypedTemplateComments), serverLayer))
354
+ }
package/src/Vitest.ts CHANGED
@@ -7,30 +7,35 @@ import * as TestClock from "effect/TestClock"
7
7
  import * as TestContext from "effect/TestContext"
8
8
  import type * as TestServices from "effect/TestServices"
9
9
  import * as vitest from "vitest"
10
+ import * as RenderQueue from "./RenderQueue.js"
11
+
12
+ const describeConcurrent = vitest.describe.concurrent
13
+ const expect = vitest.expect
10
14
 
11
15
  export {
12
16
  /**
13
17
  * @since 1.0.0
14
18
  */
15
- describe,
19
+ describeConcurrent as describe,
16
20
  /**
17
21
  * @since 1.0.0
18
22
  */
19
23
  expect
20
- } from "vitest"
24
+ }
21
25
 
22
26
  /**
23
27
  * @since 1.0.0
24
28
  */
25
29
  export function it<E, A>(
26
30
  name: string,
27
- test: () => Effect.Effect<A, E, Scope>,
31
+ test: () => Effect.Effect<A, E, Scope | RenderQueue.RenderQueue>,
28
32
  options?: vitest.TestOptions
29
33
  ) {
30
- return vitest.it(
34
+ return vitest.it.concurrent(
31
35
  name,
32
36
  () =>
33
37
  test().pipe(
38
+ Effect.provide(RenderQueue.sync),
34
39
  Effect.scoped,
35
40
  Effect.runPromise
36
41
  ),
@@ -40,13 +45,14 @@ export function it<E, A>(
40
45
 
41
46
  it.only = function it<E, A>(
42
47
  name: string,
43
- test: () => Effect.Effect<A, E, Scope>,
48
+ test: () => Effect.Effect<A, E, Scope | RenderQueue.RenderQueue>,
44
49
  options?: vitest.TestOptions
45
50
  ) {
46
51
  return vitest.it.only(
47
52
  name,
48
53
  () =>
49
54
  test().pipe(
55
+ Effect.provide(RenderQueue.sync),
50
56
  Effect.scoped,
51
57
  Effect.runPromise
52
58
  ),
@@ -56,13 +62,14 @@ it.only = function it<E, A>(
56
62
 
57
63
  it.skip = function it<E, A>(
58
64
  name: string,
59
- test: () => Effect.Effect<A, E, Scope>,
65
+ test: () => Effect.Effect<A, E, Scope | RenderQueue.RenderQueue>,
60
66
  options?: vitest.TestOptions
61
67
  ) {
62
68
  return vitest.it.skip(
63
69
  name,
64
70
  () =>
65
71
  test().pipe(
72
+ Effect.provide(RenderQueue.sync),
66
73
  Effect.scoped,
67
74
  Effect.runPromise
68
75
  ),
@@ -77,13 +84,14 @@ export function test<E, A>(
77
84
  name: string,
78
85
  test: (options: {
79
86
  readonly clock: TestClock.TestClock
80
- }) => Effect.Effect<A, E, Scope | TestServices.TestServices>,
87
+ }) => Effect.Effect<A, E, Scope | RenderQueue.RenderQueue | TestServices.TestServices>,
81
88
  options?: vitest.TestOptions
82
89
  ) {
83
- return vitest.it(
90
+ return vitest.it.concurrent(
84
91
  name,
85
92
  () =>
86
93
  TestClock.testClockWith((clock) => test({ clock })).pipe(
94
+ Effect.provide(RenderQueue.sync),
87
95
  Effect.provide(TestContext.TestContext),
88
96
  Effect.scoped,
89
97
  Effect.runPromise
@@ -96,13 +104,14 @@ test.only = function test<E, A>(
96
104
  name: string,
97
105
  test: (options: {
98
106
  readonly clock: TestClock.TestClock
99
- }) => Effect.Effect<A, E, Scope | TestServices.TestServices>,
107
+ }) => Effect.Effect<A, E, Scope | RenderQueue.RenderQueue | TestServices.TestServices>,
100
108
  options?: vitest.TestOptions
101
109
  ) {
102
110
  return vitest.it.only(
103
111
  name,
104
112
  () =>
105
113
  TestClock.testClockWith((clock) => test({ clock })).pipe(
114
+ Effect.provide(RenderQueue.sync),
106
115
  Effect.provide(TestContext.TestContext),
107
116
  Effect.scoped,
108
117
  Effect.runPromise
@@ -115,13 +124,14 @@ test.skip = function test<E, A>(
115
124
  name: string,
116
125
  test: (options: {
117
126
  readonly clock: TestClock.TestClock
118
- }) => Effect.Effect<A, E, Scope | TestServices.TestServices>,
127
+ }) => Effect.Effect<A, E, Scope | RenderQueue.RenderQueue | TestServices.TestServices>,
119
128
  options?: vitest.TestOptions
120
129
  ) {
121
130
  return vitest.it.skip(
122
131
  name,
123
132
  () =>
124
133
  TestClock.testClockWith((clock) => test({ clock })).pipe(
134
+ Effect.provide(RenderQueue.sync),
125
135
  Effect.provide(TestContext.TestContext),
126
136
  Effect.scoped,
127
137
  Effect.runPromise
package/src/index.ts CHANGED
@@ -52,6 +52,10 @@ export * from "./Renderable.js"
52
52
  * @since 1.0.0
53
53
  */
54
54
  export * as RenderContext from "./RenderContext.js"
55
+ /**
56
+ * @since 1.0.0
57
+ */
58
+ export * as RenderQueue from "./RenderQueue.js"
55
59
  /**
56
60
  * @since 1.0.0
57
61
  */
@@ -1,7 +1,8 @@
1
1
  import type { Rendered } from "@typed/wire"
2
- import { Effect, Scope } from "effect"
2
+ import * as Effect from "effect/Effect"
3
3
  import * as Fiber from "effect/Fiber"
4
4
  import * as Runtime from "effect/Runtime"
5
+ import * as Scope from "effect/Scope"
5
6
  import { getElements } from "../ElementSource.js"
6
7
  import type { EventHandler } from "../EventHandler.js"
7
8
 
@@ -84,11 +85,15 @@ export function makeEventSource(): EventSource {
84
85
 
85
86
  for (const [event, sets] of bubbleListeners) {
86
87
  for (const handlers of sets) {
88
+ if (handlers.size === 0) continue
87
89
  const listener = (ev: Event) =>
88
90
  run(
89
- Effect.forEach(handlers, ([el, handler]) =>
90
- ev.target === el || el.contains(ev.target as Node) ? handler.handler(ev) : Effect.unit)
91
+ Effect.forEach(
92
+ handlers,
93
+ ([el, { handler }]) => ev.target === el || el.contains(ev.target as Node) ? handler(ev) : Effect.void
94
+ )
91
95
  )
96
+
92
97
  element.addEventListener(event, listener, getDerivedAddEventListenerOptions(handlers))
93
98
  disposables.push(disposable(() => element.removeEventListener(event, listener)))
94
99
  }
@@ -102,12 +107,13 @@ export function makeEventSource(): EventSource {
102
107
 
103
108
  for (const [event, sets] of captureListeners) {
104
109
  for (const handlers of sets) {
110
+ if (handlers.size === 0) continue
105
111
  const listener = (ev: Event) =>
106
112
  run(
107
- Effect.forEach(handlers, ([el, handler]) =>
113
+ Effect.forEach(handlers, ([el, { handler }]) =>
108
114
  ev.target === el || el.contains(ev.target as Node)
109
- ? handler.handler(proxyCurrentTargetForCaptureEvents(ev, el))
110
- : Effect.unit)
115
+ ? handler(proxyCurrentTargetForCaptureEvents(ev, el))
116
+ : Effect.void)
111
117
  )
112
118
  element.addEventListener(event, listener, getDerivedAddEventListenerOptions(handlers))
113
119
  disposables.push(disposable(() => element.removeEventListener(event, listener)))
@@ -123,7 +129,7 @@ export function makeEventSource(): EventSource {
123
129
  const elements = getElements(rendered)
124
130
 
125
131
  if (elements.length === 0 || (!hasBubbleListeners && !hasCaptureListeners)) {
126
- return Effect.unit
132
+ return Effect.void
127
133
  }
128
134
 
129
135
  return Effect.flatMap(Effect.runtime<never>(), (runtime) => {
@@ -150,7 +156,7 @@ export function makeEventSource(): EventSource {
150
156
  scope,
151
157
  Effect.suspend(() => {
152
158
  disposables.forEach(dispose)
153
- if (fibers.size === 0) return Effect.unit
159
+ if (fibers.size === 0) return Effect.void
154
160
  return Fiber.interruptAll(fibers.values())
155
161
  })
156
162
  )
@@ -1,18 +1,17 @@
1
1
  import { Tagged } from "@typed/context"
2
2
  import type { Template } from "../Template.js"
3
- import type { ParentChildNodes } from "./utils.js"
3
+ import type { HydrationNode } from "./v2/hydration-template.js"
4
4
 
5
5
  /**
6
6
  * Used Internally to pass context down to components for hydration
7
7
  * @internal
8
8
  */
9
9
  export type HydrateContext = {
10
- readonly where: ParentChildNodes
11
- readonly rootIndex: number
10
+ readonly where: HydrationNode
12
11
  readonly parentTemplate: Template | null
13
12
 
14
13
  // Used to match sibling components using many() to the correct elements
15
- readonly manyIndex?: string
14
+ readonly manyKey?: string
16
15
 
17
16
  /**@internal */
18
17
  hydrate: boolean
@@ -1,38 +1,43 @@
1
1
  import { diffable, isComment } from "@typed/wire"
2
2
  import udomdiff from "udomdiff"
3
- import type { RenderContext } from "../RenderContext.js"
4
3
  import { isRenderEvent } from "../RenderEvent.js"
5
- import { NodePartImpl } from "./parts.js"
4
+ import type { RenderQueue } from "../RenderQueue.js"
5
+ import { convertCharacterEntities } from "./character-entities.js"
6
+ import { NodePartImpl } from "./server-parts.js"
6
7
  import { findHoleComment, isCommentWithValue } from "./utils.js"
7
8
 
8
9
  export function makeRenderNodePart(
9
10
  index: number,
10
11
  parent: HTMLElement | SVGElement,
11
- ctx: RenderContext,
12
+ queue: RenderQueue,
12
13
  document: Document,
13
14
  isHydrating: boolean
14
15
  ) {
15
16
  const comment = findHoleComment(parent, index)
16
- let text: Text
17
+ let text: Text | null = isHydrating ? getPreviousTextSibling(comment) : null
17
18
  let nodes = isHydrating ? findPreviousNodes(comment, index) : []
18
19
 
19
- return new NodePartImpl(index, ({ part, value }) => {
20
- return ctx.queue.add(part, () => {
21
- matchValue(
22
- value,
23
- (content) => {
24
- if (text === undefined) {
25
- text = document.createTextNode("")
20
+ return new NodePartImpl(index, ({ part, value }, priority) => {
21
+ return queue.add(
22
+ part,
23
+ () => {
24
+ matchValue(
25
+ value,
26
+ (content) => {
27
+ if (text === null) {
28
+ text = document.createTextNode("")
29
+ }
30
+ text.textContent = convertCharacterEntities(content)
31
+
32
+ nodes = diffChildren(comment, nodes, [text], document)
33
+ },
34
+ (updatedNodes) => {
35
+ nodes = diffChildren(comment, nodes, updatedNodes, document)
26
36
  }
27
- text.textContent = content
28
-
29
- nodes = diffChildren(comment, nodes, [text], document)
30
- },
31
- (updatedNodes) => {
32
- nodes = diffChildren(comment, nodes, updatedNodes, document)
33
- }
34
- )
35
- })
37
+ )
38
+ },
39
+ priority
40
+ )
36
41
  }, nodes)
37
42
  }
38
43
 
@@ -54,7 +59,7 @@ export function getPreviousTextSibling(node: Node | null) {
54
59
  }
55
60
 
56
61
  export function notIsEmptyTextNode(node: Node) {
57
- if (node.nodeType === node.COMMENT_NODE) {
62
+ if (node.nodeType === node.TEXT_NODE) {
58
63
  return node.nodeValue?.trim() === ""
59
64
  }
60
65