@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.
- package/RenderQueue/package.json +6 -0
- package/dist/cjs/Directive.js +1 -1
- package/dist/cjs/Directive.js.map +1 -1
- package/dist/cjs/ElementRef.js +1 -1
- package/dist/cjs/ElementRef.js.map +1 -1
- package/dist/cjs/ElementSource.js +1 -1
- package/dist/cjs/ElementSource.js.map +1 -1
- package/dist/cjs/EventHandler.js +11 -4
- package/dist/cjs/EventHandler.js.map +1 -1
- package/dist/cjs/Html.js +84 -44
- package/dist/cjs/Html.js.map +1 -1
- package/dist/cjs/HtmlChunk.js +67 -21
- package/dist/cjs/HtmlChunk.js.map +1 -1
- package/dist/cjs/Hydrate.js +6 -6
- package/dist/cjs/Hydrate.js.map +1 -1
- package/dist/cjs/Many.js +4 -4
- package/dist/cjs/Many.js.map +1 -1
- package/dist/cjs/Meta.js +10 -3
- package/dist/cjs/Meta.js.map +1 -1
- package/dist/cjs/Parser.js +1 -1
- package/dist/cjs/Placeholder.js +5 -9
- package/dist/cjs/Placeholder.js.map +1 -1
- package/dist/cjs/Platform.js +7 -5
- package/dist/cjs/Platform.js.map +1 -1
- package/dist/cjs/Render.js +8 -7
- package/dist/cjs/Render.js.map +1 -1
- package/dist/cjs/RenderContext.js +8 -92
- package/dist/cjs/RenderContext.js.map +1 -1
- package/dist/cjs/RenderEvent.js +9 -1
- package/dist/cjs/RenderEvent.js.map +1 -1
- package/dist/cjs/RenderQueue.js +341 -0
- package/dist/cjs/RenderQueue.js.map +1 -0
- package/dist/cjs/RenderTemplate.js +1 -1
- package/dist/cjs/RenderTemplate.js.map +1 -1
- package/dist/cjs/Template.js +12 -0
- package/dist/cjs/Template.js.map +1 -1
- package/dist/cjs/Test.js +64 -33
- package/dist/cjs/Test.js.map +1 -1
- package/dist/cjs/Vitest.js +12 -20
- package/dist/cjs/Vitest.js.map +1 -1
- package/dist/cjs/index.js +6 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/EventSource.js +16 -9
- package/dist/cjs/internal/EventSource.js.map +1 -1
- package/dist/cjs/internal/HydrateContext.js.map +1 -1
- package/dist/cjs/internal/browser.js +11 -10
- package/dist/cjs/internal/browser.js.map +1 -1
- package/dist/cjs/internal/character-entities.js +2141 -0
- package/dist/cjs/internal/character-entities.js.map +1 -0
- package/dist/cjs/internal/errors.js +19 -2
- package/dist/cjs/internal/errors.js.map +1 -1
- package/dist/cjs/internal/indexRefCounter.js +36 -63
- package/dist/cjs/internal/indexRefCounter.js.map +1 -1
- package/dist/cjs/internal/parser.js +18 -17
- package/dist/cjs/internal/parser.js.map +1 -1
- package/dist/cjs/internal/parser2.js +382 -0
- package/dist/cjs/internal/parser2.js.map +1 -0
- package/dist/cjs/internal/server-parts.js +124 -0
- package/dist/cjs/internal/server-parts.js.map +1 -0
- package/dist/cjs/internal/server.js +15 -185
- package/dist/cjs/internal/server.js.map +1 -1
- package/dist/cjs/internal/utils.js +73 -9
- package/dist/cjs/internal/utils.js.map +1 -1
- package/dist/cjs/internal/v2/SyncPart.js +6 -0
- package/dist/cjs/internal/v2/SyncPart.js.map +1 -0
- package/dist/cjs/internal/v2/helpers.js +15 -0
- package/dist/cjs/internal/v2/helpers.js.map +1 -0
- package/dist/cjs/internal/v2/hydrate.js +202 -0
- package/dist/cjs/internal/v2/hydrate.js.map +1 -0
- package/dist/cjs/internal/v2/hydration-template.js +269 -0
- package/dist/cjs/internal/v2/hydration-template.js.map +1 -0
- package/dist/cjs/internal/v2/parts.js +169 -0
- package/dist/cjs/internal/v2/parts.js.map +1 -0
- package/dist/cjs/internal/v2/render-entry.js +110 -0
- package/dist/cjs/internal/v2/render-entry.js.map +1 -0
- package/dist/cjs/internal/v2/render-sync-parts.js +318 -0
- package/dist/cjs/internal/v2/render-sync-parts.js.map +1 -0
- package/dist/cjs/internal/v2/render.js +417 -0
- package/dist/cjs/internal/v2/render.js.map +1 -0
- package/dist/cjs/internal/v2/sync-parts.js +115 -0
- package/dist/cjs/internal/v2/sync-parts.js.map +1 -0
- package/dist/dts/ElementRef.d.ts +1 -1
- package/dist/dts/ElementRef.d.ts.map +1 -1
- package/dist/dts/ElementSource.d.ts +1 -1
- package/dist/dts/ElementSource.d.ts.map +1 -1
- package/dist/dts/EventHandler.d.ts +12 -8
- package/dist/dts/EventHandler.d.ts.map +1 -1
- package/dist/dts/Html.d.ts +6 -5
- package/dist/dts/Html.d.ts.map +1 -1
- package/dist/dts/HtmlChunk.d.ts.map +1 -1
- package/dist/dts/Hydrate.d.ts +1 -3
- package/dist/dts/Hydrate.d.ts.map +1 -1
- package/dist/dts/Many.d.ts +9 -11
- package/dist/dts/Many.d.ts.map +1 -1
- package/dist/dts/Meta.d.ts +5 -1
- package/dist/dts/Meta.d.ts.map +1 -1
- package/dist/dts/Parser.d.ts +1 -1
- package/dist/dts/Parser.d.ts.map +1 -1
- package/dist/dts/Part.d.ts +20 -56
- package/dist/dts/Part.d.ts.map +1 -1
- package/dist/dts/Placeholder.d.ts +6 -10
- package/dist/dts/Placeholder.d.ts.map +1 -1
- package/dist/dts/Platform.d.ts +2 -4
- package/dist/dts/Platform.d.ts.map +1 -1
- package/dist/dts/Render.d.ts +4 -8
- package/dist/dts/Render.d.ts.map +1 -1
- package/dist/dts/RenderContext.d.ts +3 -22
- package/dist/dts/RenderContext.d.ts.map +1 -1
- package/dist/dts/RenderEvent.d.ts +6 -1
- package/dist/dts/RenderEvent.d.ts.map +1 -1
- package/dist/dts/RenderQueue.d.ts +103 -0
- package/dist/dts/RenderQueue.d.ts.map +1 -0
- package/dist/dts/RenderTemplate.d.ts +3 -2
- package/dist/dts/RenderTemplate.d.ts.map +1 -1
- package/dist/dts/Renderable.d.ts +1 -1
- package/dist/dts/Template.d.ts +14 -1
- package/dist/dts/Template.d.ts.map +1 -1
- package/dist/dts/Test.d.ts +14 -1
- package/dist/dts/Test.d.ts.map +1 -1
- package/dist/dts/Vitest.d.ts +11 -8
- package/dist/dts/Vitest.d.ts.map +1 -1
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/EventSource.d.ts +2 -1
- package/dist/dts/internal/EventSource.d.ts.map +1 -1
- package/dist/dts/internal/browser.d.ts +3 -3
- package/dist/dts/internal/browser.d.ts.map +1 -1
- package/dist/dts/internal/character-entities.d.ts +2133 -0
- package/dist/dts/internal/character-entities.d.ts.map +1 -0
- package/dist/dts/internal/errors.d.ts +9 -1
- package/dist/dts/internal/errors.d.ts.map +1 -1
- package/dist/dts/internal/indexRefCounter.d.ts +0 -4
- package/dist/dts/internal/indexRefCounter.d.ts.map +1 -1
- package/dist/dts/internal/parser.d.ts +13 -0
- package/dist/dts/internal/parser.d.ts.map +1 -1
- package/dist/dts/internal/parser2.d.ts +12 -0
- package/dist/dts/internal/parser2.d.ts.map +1 -0
- package/dist/dts/internal/server-parts.d.ts +223 -0
- package/dist/dts/internal/server-parts.d.ts.map +1 -0
- package/dist/dts/internal/server.d.ts +2 -28
- package/dist/dts/internal/server.d.ts.map +1 -1
- package/dist/dts/internal/utils.d.ts +4 -1
- package/dist/dts/internal/utils.d.ts.map +1 -1
- package/dist/dts/internal/v2/SyncPart.d.ts +87 -0
- package/dist/dts/internal/v2/SyncPart.d.ts.map +1 -0
- package/dist/dts/internal/v2/helpers.d.ts +3 -0
- package/dist/dts/internal/v2/helpers.d.ts.map +1 -0
- package/dist/dts/internal/v2/hydrate.d.ts +7 -0
- package/dist/dts/internal/v2/hydrate.d.ts.map +1 -0
- package/dist/dts/internal/v2/hydration-template.d.ts +54 -0
- package/dist/dts/internal/v2/hydration-template.d.ts.map +1 -0
- package/dist/dts/internal/v2/parts.d.ts +245 -0
- package/dist/dts/internal/v2/parts.d.ts.map +1 -0
- package/dist/dts/internal/v2/render-entry.d.ts +6 -0
- package/dist/dts/internal/v2/render-entry.d.ts.map +1 -0
- package/dist/dts/internal/v2/render-sync-parts.d.ts +22 -0
- package/dist/dts/internal/v2/render-sync-parts.d.ts.map +1 -0
- package/dist/dts/internal/v2/render.d.ts +62 -0
- package/dist/dts/internal/v2/render.d.ts.map +1 -0
- package/dist/dts/internal/v2/sync-parts.d.ts +129 -0
- package/dist/dts/internal/v2/sync-parts.d.ts.map +1 -0
- package/dist/esm/ElementRef.js.map +1 -1
- package/dist/esm/EventHandler.js +14 -4
- package/dist/esm/EventHandler.js.map +1 -1
- package/dist/esm/Html.js +91 -50
- package/dist/esm/Html.js.map +1 -1
- package/dist/esm/HtmlChunk.js +75 -24
- package/dist/esm/HtmlChunk.js.map +1 -1
- package/dist/esm/Hydrate.js +5 -5
- package/dist/esm/Hydrate.js.map +1 -1
- package/dist/esm/Many.js +3 -3
- package/dist/esm/Many.js.map +1 -1
- package/dist/esm/Meta.js +7 -1
- package/dist/esm/Meta.js.map +1 -1
- package/dist/esm/Parser.js +1 -1
- package/dist/esm/Parser.js.map +1 -1
- package/dist/esm/Placeholder.js +4 -8
- package/dist/esm/Placeholder.js.map +1 -1
- package/dist/esm/Platform.js +3 -1
- package/dist/esm/Platform.js.map +1 -1
- package/dist/esm/Render.js +6 -5
- package/dist/esm/Render.js.map +1 -1
- package/dist/esm/RenderContext.js +5 -85
- package/dist/esm/RenderContext.js.map +1 -1
- package/dist/esm/RenderEvent.js +8 -1
- package/dist/esm/RenderEvent.js.map +1 -1
- package/dist/esm/RenderQueue.js +336 -0
- package/dist/esm/RenderQueue.js.map +1 -0
- package/dist/esm/RenderTemplate.js.map +1 -1
- package/dist/esm/Template.js +12 -0
- package/dist/esm/Template.js.map +1 -1
- package/dist/esm/Test.js +71 -30
- package/dist/esm/Test.js.map +1 -1
- package/dist/esm/Vitest.js +11 -8
- package/dist/esm/Vitest.js.map +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/EventSource.js +12 -7
- package/dist/esm/internal/EventSource.js.map +1 -1
- package/dist/esm/internal/HydrateContext.js.map +1 -1
- package/dist/esm/internal/browser.js +10 -9
- package/dist/esm/internal/browser.js.map +1 -1
- package/dist/esm/internal/character-entities.js +2134 -0
- package/dist/esm/internal/character-entities.js.map +1 -0
- package/dist/esm/internal/errors.js +22 -2
- package/dist/esm/internal/errors.js.map +1 -1
- package/dist/esm/internal/indexRefCounter.js +36 -61
- package/dist/esm/internal/indexRefCounter.js.map +1 -1
- package/dist/esm/internal/parser.js +18 -18
- package/dist/esm/internal/parser.js.map +1 -1
- package/dist/esm/internal/parser2.js +393 -0
- package/dist/esm/internal/parser2.js.map +1 -0
- package/dist/esm/internal/server-parts.js +109 -0
- package/dist/esm/internal/server-parts.js.map +1 -0
- package/dist/esm/internal/server.js +12 -161
- package/dist/esm/internal/server.js.map +1 -1
- package/dist/esm/internal/utils.js +71 -7
- package/dist/esm/internal/utils.js.map +1 -1
- package/dist/esm/internal/v2/SyncPart.js +5 -0
- package/dist/esm/internal/v2/SyncPart.js.map +1 -0
- package/dist/esm/internal/v2/helpers.js +12 -0
- package/dist/esm/internal/v2/helpers.js.map +1 -0
- package/dist/esm/internal/v2/hydrate.js +195 -0
- package/dist/esm/internal/v2/hydrate.js.map +1 -0
- package/dist/esm/internal/v2/hydration-template.js +265 -0
- package/dist/esm/internal/v2/hydration-template.js.map +1 -0
- package/dist/esm/internal/v2/parts.js +150 -0
- package/dist/esm/internal/v2/parts.js.map +1 -0
- package/dist/esm/internal/v2/render-entry.js +102 -0
- package/dist/esm/internal/v2/render-entry.js.map +1 -0
- package/dist/esm/internal/v2/render-sync-parts.js +265 -0
- package/dist/esm/internal/v2/render-sync-parts.js.map +1 -0
- package/dist/esm/internal/v2/render.js +353 -0
- package/dist/esm/internal/v2/render.js.map +1 -0
- package/dist/esm/internal/v2/sync-parts.js +102 -0
- package/dist/esm/internal/v2/sync-parts.js.map +1 -0
- package/package.json +20 -13
- package/src/ElementRef.ts +1 -1
- package/src/ElementSource.ts +1 -1
- package/src/EventHandler.ts +29 -11
- package/src/Html.ts +199 -90
- package/src/HtmlChunk.ts +77 -30
- package/src/Hydrate.ts +20 -14
- package/src/Many.ts +17 -14
- package/src/Meta.ts +8 -1
- package/src/Parser.ts +1 -1
- package/src/Part.ts +22 -66
- package/src/Placeholder.ts +17 -15
- package/src/Platform.ts +5 -5
- package/src/Render.ts +23 -26
- package/src/RenderContext.ts +14 -142
- package/src/RenderEvent.ts +10 -1
- package/src/RenderQueue.ts +445 -0
- package/src/RenderTemplate.ts +7 -2
- package/src/Renderable.ts +1 -1
- package/src/Template.ts +15 -1
- package/src/Test.ts +122 -38
- package/src/Vitest.ts +20 -10
- package/src/index.ts +4 -0
- package/src/internal/EventSource.ts +14 -8
- package/src/internal/HydrateContext.ts +3 -4
- package/src/internal/browser.ts +26 -21
- package/src/internal/character-entities.ts +2136 -0
- package/src/internal/errors.ts +30 -3
- package/src/internal/indexRefCounter.ts +38 -70
- package/src/internal/parser.ts +19 -19
- package/src/internal/parser2.ts +468 -0
- package/src/internal/server-parts.ts +161 -0
- package/src/internal/server.ts +16 -272
- package/src/internal/utils.ts +83 -7
- package/src/internal/v2/SyncPart.ts +112 -0
- package/src/internal/v2/helpers.ts +13 -0
- package/src/internal/v2/hydrate.ts +289 -0
- package/src/internal/v2/hydration-template.ts +308 -0
- package/src/internal/v2/parts.ts +254 -0
- package/src/internal/v2/render-entry.ts +131 -0
- package/src/internal/v2/render-sync-parts.ts +440 -0
- package/src/internal/v2/render.ts +588 -0
- package/src/internal/v2/sync-parts.ts +133 -0
- package/dist/cjs/internal/hydrate.js +0 -274
- package/dist/cjs/internal/hydrate.js.map +0 -1
- package/dist/cjs/internal/parts.js +0 -451
- package/dist/cjs/internal/parts.js.map +0 -1
- package/dist/cjs/internal/render.js +0 -704
- package/dist/cjs/internal/render.js.map +0 -1
- package/dist/dts/internal/hydrate.d.ts +0 -33
- package/dist/dts/internal/hydrate.d.ts.map +0 -1
- package/dist/dts/internal/parts.d.ts +0 -314
- package/dist/dts/internal/parts.d.ts.map +0 -1
- package/dist/dts/internal/render.d.ts +0 -16
- package/dist/dts/internal/render.d.ts.map +0 -1
- package/dist/esm/internal/hydrate.js +0 -239
- package/dist/esm/internal/hydrate.js.map +0 -1
- package/dist/esm/internal/parts.js +0 -373
- package/dist/esm/internal/parts.js.map +0 -1
- package/dist/esm/internal/render.js +0 -689
- package/dist/esm/internal/render.js.map +0 -1
- package/src/internal/hydrate.ts +0 -366
- package/src/internal/parts.ts +0 -609
- 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<
|
|
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
|
|
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*
|
|
72
|
-
const elementRef = yield*
|
|
73
|
-
const errors = yield*
|
|
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
|
|
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*
|
|
107
|
-
yield*
|
|
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.
|
|
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([
|
|
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*
|
|
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
|
|
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*
|
|
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
|
-
|
|
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
|
|
224
|
-
const elementRef = yield*
|
|
225
|
-
const errors = yield*
|
|
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) =>
|
|
256
|
+
onRight: (cause) => elementRef[ElementRef.ElementRefTypeId].onFailure(cause)
|
|
238
257
|
})
|
|
239
258
|
)
|
|
240
259
|
),
|
|
241
|
-
(rendered) =>
|
|
260
|
+
(rendered) =>
|
|
261
|
+
ElementRef.set(
|
|
262
|
+
elementRef,
|
|
263
|
+
fromRendered(rendered)
|
|
264
|
+
)
|
|
242
265
|
)),
|
|
243
|
-
Effect.provide(hydrateLayer(window
|
|
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*
|
|
263
|
-
yield*
|
|
285
|
+
yield* adjustTime(1)
|
|
286
|
+
yield* adjustTime(1)
|
|
264
287
|
|
|
265
288
|
// Await the first render
|
|
266
|
-
yield*
|
|
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
|
-
}
|
|
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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Rendered } from "@typed/wire"
|
|
2
|
-
import
|
|
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(
|
|
90
|
-
|
|
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
|
|
110
|
-
: Effect.
|
|
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.
|
|
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.
|
|
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 {
|
|
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:
|
|
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
|
|
14
|
+
readonly manyKey?: string
|
|
16
15
|
|
|
17
16
|
/**@internal */
|
|
18
17
|
hydrate: boolean
|
package/src/internal/browser.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
(
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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.
|
|
62
|
+
if (node.nodeType === node.TEXT_NODE) {
|
|
58
63
|
return node.nodeValue?.trim() === ""
|
|
59
64
|
}
|
|
60
65
|
|