@typed/template 0.9.6 → 0.11.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 +15 -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 +20 -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 +20 -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 +50 -12
- package/src/Html.ts +207 -98
- 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/Html.ts
CHANGED
|
@@ -6,51 +6,62 @@ import type { CurrentEnvironment } from "@typed/environment"
|
|
|
6
6
|
import * as Fx from "@typed/fx/Fx"
|
|
7
7
|
import * as Sink from "@typed/fx/Sink"
|
|
8
8
|
import { TypeId } from "@typed/fx/TypeId"
|
|
9
|
+
import { join } from "effect/Array"
|
|
9
10
|
import * as Effect from "effect/Effect"
|
|
10
11
|
import * as Layer from "effect/Layer"
|
|
11
12
|
import * as Option from "effect/Option"
|
|
12
|
-
import
|
|
13
|
+
import type * as Record from "effect/Record"
|
|
13
14
|
import type * as Scope from "effect/Scope"
|
|
14
15
|
import { isDirective } from "./Directive.js"
|
|
15
16
|
import type { ServerEntry } from "./Entry.js"
|
|
16
17
|
import type { HtmlChunk, PartChunk, SparsePartChunk, TextChunk } from "./HtmlChunk.js"
|
|
17
18
|
import { templateToHtmlChunks } from "./HtmlChunk.js"
|
|
18
|
-
import { parse } from "./internal/
|
|
19
|
+
import { parse } from "./internal/parser2.js"
|
|
19
20
|
import { partNodeToPart } from "./internal/server.js"
|
|
20
|
-
import {
|
|
21
|
+
import { isNullOrUndefined } from "./internal/v2/helpers.js"
|
|
22
|
+
import { TEXT_START, TYPED_HOLE_END, TYPED_HOLE_START } from "./Meta.js"
|
|
21
23
|
import type { Placeholder } from "./Placeholder.js"
|
|
22
24
|
import type { Renderable } from "./Renderable.js"
|
|
23
25
|
import * as RenderContext from "./RenderContext.js"
|
|
24
|
-
import { HtmlRenderEvent,
|
|
26
|
+
import { HtmlRenderEvent, isHtmlRenderEvent } from "./RenderEvent.js"
|
|
25
27
|
import type { RenderEvent } from "./RenderEvent.js"
|
|
28
|
+
import * as RenderQueue from "./RenderQueue.js"
|
|
26
29
|
import { RenderTemplate } from "./RenderTemplate.js"
|
|
27
30
|
|
|
28
|
-
const toHtml = (r: RenderEvent) => (r as HtmlRenderEvent).html
|
|
31
|
+
const toHtml = (r: RenderEvent | null) => r === null ? "" : (r as HtmlRenderEvent).html
|
|
29
32
|
|
|
30
33
|
/**
|
|
31
34
|
* @since 1.0.0
|
|
32
35
|
*/
|
|
33
|
-
export const serverLayer: Layer.Layer<
|
|
34
|
-
.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
export const serverLayer: Layer.Layer<
|
|
37
|
+
| RenderContext.RenderContext
|
|
38
|
+
| RenderQueue.RenderQueue
|
|
39
|
+
| RenderTemplate
|
|
40
|
+
| CurrentEnvironment
|
|
41
|
+
> = Layer.provideMerge(
|
|
42
|
+
RenderTemplate.layer(RenderContext.RenderContext.with(renderHtmlTemplate)),
|
|
43
|
+
RenderContext.server
|
|
44
|
+
).pipe(Layer.provideMerge(RenderQueue.sync))
|
|
38
45
|
|
|
39
46
|
/**
|
|
40
47
|
* @since 1.0.0
|
|
41
48
|
*/
|
|
42
|
-
export const staticLayer: Layer.Layer<
|
|
43
|
-
.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
export const staticLayer: Layer.Layer<
|
|
50
|
+
| RenderContext.RenderContext
|
|
51
|
+
| RenderQueue.RenderQueue
|
|
52
|
+
| RenderTemplate
|
|
53
|
+
| CurrentEnvironment
|
|
54
|
+
> = Layer.provideMerge(
|
|
55
|
+
RenderTemplate.layer(RenderContext.RenderContext.with(renderHtmlTemplate)),
|
|
56
|
+
RenderContext.static
|
|
57
|
+
).pipe(Layer.provideMerge(RenderQueue.sync))
|
|
47
58
|
|
|
48
59
|
/**
|
|
49
60
|
* @since 1.0.0
|
|
50
61
|
*/
|
|
51
62
|
export function renderToHtml<E, R>(
|
|
52
|
-
fx: Fx.Fx<RenderEvent, E, R>
|
|
53
|
-
): Fx.Fx<string, E, R
|
|
63
|
+
fx: Fx.Fx<RenderEvent | null, E, R>
|
|
64
|
+
): Fx.Fx<string, E, R> {
|
|
54
65
|
return Fx.map(fx, toHtml)
|
|
55
66
|
}
|
|
56
67
|
|
|
@@ -58,8 +69,8 @@ export function renderToHtml<E, R>(
|
|
|
58
69
|
* @since 1.0.0
|
|
59
70
|
*/
|
|
60
71
|
export function renderToHtmlString<E, R>(
|
|
61
|
-
fx: Fx.Fx<RenderEvent, E, R>
|
|
62
|
-
): Effect.Effect<string, E, R
|
|
72
|
+
fx: Fx.Fx<RenderEvent | null, E, R>
|
|
73
|
+
): Effect.Effect<string, E, R> {
|
|
63
74
|
return Effect.map(Fx.toReadonlyArray(renderToHtml(fx)), join(""))
|
|
64
75
|
}
|
|
65
76
|
|
|
@@ -73,24 +84,28 @@ export function renderHtmlTemplate(ctx: RenderContext.RenderContext) {
|
|
|
73
84
|
): Fx.Fx<
|
|
74
85
|
RenderEvent,
|
|
75
86
|
Placeholder.Error<Values[number]>,
|
|
76
|
-
Scope.Scope
|
|
87
|
+
| Scope.Scope
|
|
88
|
+
| Placeholder.Context<Values[number]>
|
|
77
89
|
> => {
|
|
78
90
|
const isStatic = ctx.environment === "static" || ctx.environment === "test:static"
|
|
79
91
|
const entry = getServerEntry(templateStrings, ctx.templateCache, isStatic)
|
|
80
92
|
|
|
81
93
|
if (values.length === 0) {
|
|
82
|
-
return Fx.succeed(
|
|
94
|
+
return Fx.succeed(
|
|
95
|
+
HtmlRenderEvent((entry.chunks[0] as TextChunk).value, true)
|
|
96
|
+
)
|
|
83
97
|
} else {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
(x) =>
|
|
98
|
+
const lastIndex = entry.chunks.length - 1
|
|
99
|
+
return Fx.mergeOrdered(
|
|
100
|
+
entry.chunks.map((chunk, i) =>
|
|
101
|
+
renderChunk<
|
|
102
|
+
Placeholder.Error<Values[number]>,
|
|
103
|
+
Placeholder.Context<Values[number]>
|
|
104
|
+
>(chunk, values, isStatic, i === lastIndex)
|
|
105
|
+
)
|
|
106
|
+
).pipe(
|
|
107
|
+
Fx.filter((x) => x.html.length > 0),
|
|
108
|
+
Fx.dropAfter((x) => x.done)
|
|
94
109
|
)
|
|
95
110
|
}
|
|
96
111
|
}
|
|
@@ -99,47 +114,70 @@ export function renderHtmlTemplate(ctx: RenderContext.RenderContext) {
|
|
|
99
114
|
function renderChunk<E, R>(
|
|
100
115
|
chunk: HtmlChunk,
|
|
101
116
|
values: ReadonlyArray<Renderable<any, any>>,
|
|
102
|
-
isStatic: boolean
|
|
103
|
-
|
|
117
|
+
isStatic: boolean,
|
|
118
|
+
done: boolean
|
|
119
|
+
): Fx.Fx<HtmlRenderEvent, E, R | Scope.Scope> {
|
|
104
120
|
if (chunk._tag === "text") {
|
|
105
|
-
return Fx.succeed(HtmlRenderEvent(chunk.value))
|
|
121
|
+
return Fx.succeed(HtmlRenderEvent(chunk.value, done))
|
|
106
122
|
} else if (chunk._tag === "part") {
|
|
107
|
-
return renderPart<E, R>(chunk, values, isStatic)
|
|
123
|
+
return renderPart<E, R>(chunk, values, isStatic, done)
|
|
108
124
|
} else {
|
|
109
|
-
return renderSparsePart<E, R>(chunk, values) as Fx.Fx<
|
|
125
|
+
return renderSparsePart<E, R>(chunk, values, done) as Fx.Fx<
|
|
126
|
+
HtmlRenderEvent,
|
|
127
|
+
E,
|
|
128
|
+
R
|
|
129
|
+
>
|
|
110
130
|
}
|
|
111
131
|
}
|
|
112
132
|
|
|
113
|
-
function renderNode<E, R>(
|
|
133
|
+
function renderNode<E, R>(
|
|
134
|
+
renderable: Renderable<any, any>,
|
|
135
|
+
isStatic: boolean,
|
|
136
|
+
done: boolean
|
|
137
|
+
): Fx.Fx<HtmlRenderEvent, E, R | Scope.Scope> {
|
|
114
138
|
switch (typeof renderable) {
|
|
115
139
|
case "string":
|
|
116
140
|
case "number":
|
|
117
141
|
case "boolean":
|
|
118
142
|
case "bigint":
|
|
119
|
-
return Fx.succeed(
|
|
143
|
+
return Fx.succeed(
|
|
144
|
+
HtmlRenderEvent(
|
|
145
|
+
(isStatic ? "" : TEXT_START) + renderable.toString(),
|
|
146
|
+
done
|
|
147
|
+
)
|
|
148
|
+
)
|
|
120
149
|
case "undefined":
|
|
121
150
|
case "object":
|
|
122
|
-
return renderObject(renderable, isStatic)
|
|
151
|
+
return renderObject(renderable, isStatic, done)
|
|
123
152
|
default:
|
|
124
153
|
return Fx.empty
|
|
125
154
|
}
|
|
126
155
|
}
|
|
127
156
|
|
|
128
|
-
function renderObject<E, R>(
|
|
129
|
-
|
|
130
|
-
|
|
157
|
+
function renderObject<E, R>(
|
|
158
|
+
renderable: object | null | undefined,
|
|
159
|
+
isStatic: boolean,
|
|
160
|
+
done: boolean
|
|
161
|
+
): Fx.Fx<HtmlRenderEvent, E, R | Scope.Scope> {
|
|
162
|
+
if (isNullOrUndefined(renderable)) {
|
|
163
|
+
return isStatic ? Fx.empty : Fx.succeed(HtmlRenderEvent(TEXT_START, done))
|
|
131
164
|
} else if (Array.isArray(renderable)) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
165
|
+
const lastIndex = renderable.length - 1
|
|
166
|
+
return Fx.mergeOrdered(
|
|
167
|
+
renderable.map((r, i) => renderNode(r, isStatic, done && i === lastIndex))
|
|
168
|
+
) as any
|
|
136
169
|
} else if (Effect.isEffect(renderable)) {
|
|
137
|
-
return Fx.
|
|
138
|
-
|
|
139
|
-
(r) => renderNode<E, R>(r, isStatic)
|
|
170
|
+
return Fx.fromFxEffect(
|
|
171
|
+
Effect.map(renderable as Effect.Effect<Renderable, E, R>, (r) => renderNode<E, R>(r, isStatic, done))
|
|
140
172
|
)
|
|
141
|
-
} else if (
|
|
142
|
-
return
|
|
173
|
+
} else if (Fx.isFx<RenderEvent, E, R>(renderable)) {
|
|
174
|
+
return takeOneIfNotRenderEvent(renderable, isStatic, done)
|
|
175
|
+
} else if (isHtmlRenderEvent(renderable)) {
|
|
176
|
+
if (done) {
|
|
177
|
+
return Fx.succeed(renderable)
|
|
178
|
+
} else {
|
|
179
|
+
return Fx.succeed(HtmlRenderEvent(renderable.html, done))
|
|
180
|
+
}
|
|
143
181
|
} else {
|
|
144
182
|
return Fx.empty
|
|
145
183
|
}
|
|
@@ -148,55 +186,95 @@ function renderObject<E, R>(renderable: object | null | undefined, isStatic: boo
|
|
|
148
186
|
function renderPart<E, R>(
|
|
149
187
|
chunk: PartChunk,
|
|
150
188
|
values: ReadonlyArray<Renderable<any, any>>,
|
|
151
|
-
isStatic: boolean
|
|
152
|
-
|
|
189
|
+
isStatic: boolean,
|
|
190
|
+
done: boolean
|
|
191
|
+
): Fx.Fx<HtmlRenderEvent, E, R | Scope.Scope> {
|
|
153
192
|
const { node, render } = chunk
|
|
154
193
|
const renderable: Renderable<any, any> = values[node.index]
|
|
155
194
|
|
|
156
195
|
// Refs and events are not rendered into HTML
|
|
157
196
|
if (isDirective<E, R>(renderable)) {
|
|
158
|
-
return Fx.make<
|
|
159
|
-
|
|
160
|
-
node,
|
|
161
|
-
(value) => sink.onSuccess(HtmlRenderEvent(render(value)))
|
|
162
|
-
)
|
|
197
|
+
return Fx.make<HtmlRenderEvent, E, R>(
|
|
198
|
+
(sink: Sink.Sink<HtmlRenderEvent, E>) => {
|
|
199
|
+
const part = partNodeToPart(node, (value) => sink.onSuccess(HtmlRenderEvent(render(value), done)))
|
|
163
200
|
|
|
164
|
-
|
|
165
|
-
|
|
201
|
+
return Effect.catchAllCause(renderable(part), sink.onFailure)
|
|
202
|
+
}
|
|
203
|
+
)
|
|
166
204
|
} else if (node._tag === "node") {
|
|
167
|
-
if (isStatic) return renderNode<E, R>(renderable, isStatic)
|
|
168
|
-
|
|
205
|
+
if (isStatic) return renderNode<E, R>(renderable, isStatic, done)
|
|
206
|
+
let first = true
|
|
207
|
+
return Fx.continueWith(
|
|
208
|
+
Fx.map(renderNode<E, R>(renderable, isStatic, true), (x) => {
|
|
209
|
+
if (x.done) {
|
|
210
|
+
const y = HtmlRenderEvent(
|
|
211
|
+
(first ? TYPED_HOLE_START(node.index) : "") +
|
|
212
|
+
x.html +
|
|
213
|
+
TYPED_HOLE_END(node.index),
|
|
214
|
+
done
|
|
215
|
+
)
|
|
216
|
+
first = false
|
|
217
|
+
return y
|
|
218
|
+
} else {
|
|
219
|
+
if (first) {
|
|
220
|
+
first = false
|
|
221
|
+
return HtmlRenderEvent(
|
|
222
|
+
TYPED_HOLE_START(node.index) + x.html,
|
|
223
|
+
false
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
return x
|
|
227
|
+
}
|
|
228
|
+
}),
|
|
229
|
+
() =>
|
|
230
|
+
first
|
|
231
|
+
? Fx.succeed(
|
|
232
|
+
HtmlRenderEvent(
|
|
233
|
+
TYPED_HOLE_START(node.index) + TYPED_HOLE_END(node.index),
|
|
234
|
+
done
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
: Fx.empty
|
|
238
|
+
)
|
|
169
239
|
} else if (node._tag === "properties") {
|
|
170
240
|
if (renderable == null) return Fx.empty
|
|
171
|
-
return Fx.map(
|
|
172
|
-
Fx.take(
|
|
173
|
-
Fx.struct(
|
|
174
|
-
Object.fromEntries(Object.entries(renderable).map(([k, v]) => [k, unwrapRenderable(v)] as const))
|
|
175
|
-
),
|
|
176
|
-
1
|
|
177
|
-
),
|
|
178
|
-
render
|
|
179
|
-
) as any
|
|
180
|
-
} else {
|
|
181
|
-
if (renderable === null) return Fx.succeed(HtmlRenderEvent(render(renderable)))
|
|
182
241
|
|
|
183
|
-
|
|
184
|
-
|
|
242
|
+
return Fx.mergeAll(
|
|
243
|
+
Object.entries(renderable as Record<string, Renderable<any, any>>).map(
|
|
244
|
+
([key, renderable]) => {
|
|
245
|
+
return Fx.filterMap(
|
|
246
|
+
Fx.take(unwrapRenderable<E, R>(renderable), 1),
|
|
247
|
+
(value) => {
|
|
248
|
+
const s = render({ [key]: value })
|
|
185
249
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
250
|
+
return s ? Option.some(HtmlRenderEvent(s, done)) : Option.none()
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
} else {
|
|
257
|
+
if (renderable === null) {
|
|
258
|
+
return Fx.succeed(HtmlRenderEvent(render(renderable), done))
|
|
191
259
|
}
|
|
192
260
|
|
|
261
|
+
const html = Fx.filterMap(
|
|
262
|
+
Fx.take(unwrapRenderable<E, R>(renderable), 1),
|
|
263
|
+
(value) => {
|
|
264
|
+
const s = render(value)
|
|
265
|
+
|
|
266
|
+
return s ? Option.some(HtmlRenderEvent(s, done)) : Option.none()
|
|
267
|
+
}
|
|
268
|
+
)
|
|
269
|
+
|
|
193
270
|
return html
|
|
194
271
|
}
|
|
195
272
|
}
|
|
196
273
|
|
|
197
274
|
function renderSparsePart<E, R>(
|
|
198
275
|
chunk: SparsePartChunk,
|
|
199
|
-
values: ReadonlyArray<Renderable<any, any
|
|
276
|
+
values: ReadonlyArray<Renderable<any, any>>,
|
|
277
|
+
done: boolean
|
|
200
278
|
): Fx.Fx<RenderEvent, E, R> {
|
|
201
279
|
const { node, render } = chunk
|
|
202
280
|
|
|
@@ -211,7 +289,9 @@ function renderSparsePart<E, R>(
|
|
|
211
289
|
if (isDirective<E, R>(renderable)) {
|
|
212
290
|
return Fx.make<unknown, E, R>((sink: Sink.Sink<unknown, E>) =>
|
|
213
291
|
Effect.catchAllCause(
|
|
214
|
-
renderable(
|
|
292
|
+
renderable(
|
|
293
|
+
partNodeToPart(node, (value) => sink.onSuccess(value))
|
|
294
|
+
),
|
|
215
295
|
sink.onFailure
|
|
216
296
|
)
|
|
217
297
|
)
|
|
@@ -222,20 +302,42 @@ function renderSparsePart<E, R>(
|
|
|
222
302
|
),
|
|
223
303
|
1
|
|
224
304
|
),
|
|
225
|
-
(value) => HtmlRenderEvent(render(value))
|
|
305
|
+
(value) => HtmlRenderEvent(render(value), done)
|
|
226
306
|
)
|
|
227
307
|
}
|
|
228
308
|
|
|
229
|
-
function takeOneIfNotRenderEvent<A, E, R>(
|
|
230
|
-
|
|
231
|
-
|
|
309
|
+
function takeOneIfNotRenderEvent<A, E, R>(
|
|
310
|
+
fx: Fx.Fx<A, E, R>,
|
|
311
|
+
isStatic: boolean,
|
|
312
|
+
done: boolean
|
|
313
|
+
): Fx.Fx<HtmlRenderEvent, E, R> {
|
|
314
|
+
return Fx.make<HtmlRenderEvent, E, R>((sink) =>
|
|
315
|
+
Effect.uninterruptible(Sink.withEarlyExit(sink, (sink) =>
|
|
232
316
|
fx.run(
|
|
233
|
-
Sink.make(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
317
|
+
Sink.make(sink.onFailure, (event) => {
|
|
318
|
+
if (isHtmlRenderEvent(event)) {
|
|
319
|
+
if (done) {
|
|
320
|
+
return sink.onSuccess(event)
|
|
321
|
+
} else {
|
|
322
|
+
return sink.onSuccess(HtmlRenderEvent(event.html, false))
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (isNullOrUndefined(event)) {
|
|
327
|
+
return sink.earlyExit
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return Effect.zipRight(
|
|
331
|
+
sink.onSuccess(
|
|
332
|
+
HtmlRenderEvent(
|
|
333
|
+
(isStatic ? "" : TEXT_START) + String(event),
|
|
334
|
+
done
|
|
335
|
+
)
|
|
336
|
+
),
|
|
337
|
+
sink.earlyExit
|
|
338
|
+
)
|
|
339
|
+
})
|
|
340
|
+
)))
|
|
239
341
|
)
|
|
240
342
|
}
|
|
241
343
|
|
|
@@ -262,17 +364,24 @@ function getServerEntry(
|
|
|
262
364
|
}
|
|
263
365
|
}
|
|
264
366
|
|
|
265
|
-
function unwrapRenderable<E, R>(
|
|
367
|
+
function unwrapRenderable<E, R>(
|
|
368
|
+
renderable: Renderable<any, any>
|
|
369
|
+
): Fx.Fx<any, E, R> {
|
|
266
370
|
switch (typeof renderable) {
|
|
267
371
|
case "undefined":
|
|
268
372
|
case "object": {
|
|
269
|
-
if (renderable
|
|
270
|
-
|
|
271
|
-
|
|
373
|
+
if (isNullOrUndefined(renderable)) {
|
|
374
|
+
return Fx.null
|
|
375
|
+
} else if (Array.isArray(renderable)) {
|
|
376
|
+
return Fx.mergeOrdered(
|
|
377
|
+
renderable.map((r) => takeOneIfNotRenderEvent(unwrapRenderable(r), true, false))
|
|
378
|
+
) as any
|
|
379
|
+
} else if (Effect.EffectTypeId in renderable) {
|
|
380
|
+
return Fx.fromFxEffect(
|
|
381
|
+
Effect.map(renderable as any, unwrapRenderable<any, any>)
|
|
382
|
+
)
|
|
272
383
|
} else if (TypeId in renderable) {
|
|
273
384
|
return renderable as any
|
|
274
|
-
} else if (Effect.EffectTypeId in renderable) {
|
|
275
|
-
return Fx.fromFxEffect(Effect.map(renderable as any, unwrapRenderable<any, any>))
|
|
276
385
|
} else return Fx.succeed(renderable as any)
|
|
277
386
|
}
|
|
278
387
|
default:
|
package/src/HtmlChunk.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { keyToPartType } from "./internal/utils.js"
|
|
5
|
+
import { isNullOrUndefined } from "./internal/v2/helpers.js"
|
|
5
6
|
import type {
|
|
6
7
|
Attribute,
|
|
7
8
|
ElementNode,
|
|
@@ -64,11 +65,27 @@ export type AttrValue = string | null | undefined | ReadonlyArray<AttrValue>
|
|
|
64
65
|
* @since 1.0.0
|
|
65
66
|
*/
|
|
66
67
|
export function templateToHtmlChunks({ hash, nodes }: Template, isStatic: boolean) {
|
|
67
|
-
|
|
68
|
+
if (isStatic) {
|
|
69
|
+
return fuseTextChunks(nodes.flatMap((node) => nodeToHtmlChunk(node)))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const chunks = fuseTextChunks([
|
|
73
|
+
templateStart(hash),
|
|
74
|
+
...nodes.flatMap((node) => nodeToHtmlChunk(node, hash)),
|
|
75
|
+
templateEnd(hash)
|
|
76
|
+
])
|
|
68
77
|
|
|
69
78
|
return chunks
|
|
70
79
|
}
|
|
71
80
|
|
|
81
|
+
function templateStart(hash: string): HtmlChunk {
|
|
82
|
+
return new TextChunk(`<!--typed-${hash}-->`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function templateEnd(hash: string): HtmlChunk {
|
|
86
|
+
return new TextChunk(`<!--/typed-${hash}-->`)
|
|
87
|
+
}
|
|
88
|
+
|
|
72
89
|
function fuseTextChunks(chunks: Array<HtmlChunk>): ReadonlyArray<HtmlChunk> {
|
|
73
90
|
const output: Array<HtmlChunk> = []
|
|
74
91
|
|
|
@@ -124,19 +141,18 @@ function nodeToHtmlChunk(node: Node, hash?: string): Array<HtmlChunk> {
|
|
|
124
141
|
}
|
|
125
142
|
|
|
126
143
|
function elementToHtmlChunks(
|
|
127
|
-
{ attributes, children, tagName }: ElementNode
|
|
128
|
-
hash?: string
|
|
144
|
+
{ attributes, children, tagName }: ElementNode
|
|
129
145
|
): Array<HtmlChunk> {
|
|
130
146
|
if (attributes.length === 0) {
|
|
131
147
|
return [
|
|
132
|
-
new TextChunk(openTag(tagName
|
|
148
|
+
new TextChunk(openTag(tagName) + ">"),
|
|
133
149
|
...children.flatMap((c) => nodeToHtmlChunk(c)),
|
|
134
150
|
new TextChunk(closeTag(tagName))
|
|
135
151
|
]
|
|
136
152
|
}
|
|
137
153
|
|
|
138
154
|
const chunks: Array<HtmlChunk> = [
|
|
139
|
-
new TextChunk(openTag(tagName
|
|
155
|
+
new TextChunk(openTag(tagName)),
|
|
140
156
|
...attributes.map((a) => attributeToHtmlChunk(a)),
|
|
141
157
|
new TextChunk(">"),
|
|
142
158
|
...children.flatMap((c) => nodeToHtmlChunk(c)),
|
|
@@ -147,15 +163,14 @@ function elementToHtmlChunks(
|
|
|
147
163
|
}
|
|
148
164
|
|
|
149
165
|
function selfClosingElementToHtmlChunks(
|
|
150
|
-
{ attributes, tagName }: SelfClosingElementNode
|
|
151
|
-
hash?: string
|
|
166
|
+
{ attributes, tagName }: SelfClosingElementNode
|
|
152
167
|
): Array<HtmlChunk> {
|
|
153
168
|
if (attributes.length === 0) {
|
|
154
|
-
return [new TextChunk(openTag(tagName
|
|
169
|
+
return [new TextChunk(openTag(tagName) + " />")]
|
|
155
170
|
}
|
|
156
171
|
|
|
157
172
|
const chunks: Array<HtmlChunk> = [
|
|
158
|
-
new TextChunk(openTag(tagName
|
|
173
|
+
new TextChunk(openTag(tagName)),
|
|
159
174
|
...attributes.map((a) => attributeToHtmlChunk(a)),
|
|
160
175
|
new TextChunk(`/>`)
|
|
161
176
|
]
|
|
@@ -168,19 +183,18 @@ function textToHtmlChunks(text: Text): HtmlChunk {
|
|
|
168
183
|
}
|
|
169
184
|
|
|
170
185
|
function textOnlyElementToHtmlChunks(
|
|
171
|
-
{ attributes, children, tagName }: TextOnlyElement
|
|
172
|
-
hash?: string
|
|
186
|
+
{ attributes, children, tagName }: TextOnlyElement
|
|
173
187
|
): Array<HtmlChunk> {
|
|
174
188
|
if (attributes.length === 0) {
|
|
175
189
|
return [
|
|
176
|
-
new TextChunk(openTag(tagName
|
|
190
|
+
new TextChunk(openTag(tagName) + ">"),
|
|
177
191
|
...children.map((c) => textToHtmlChunks(c)),
|
|
178
192
|
new TextChunk(closeTag(tagName))
|
|
179
193
|
]
|
|
180
194
|
}
|
|
181
195
|
|
|
182
196
|
const chunks: Array<HtmlChunk> = [
|
|
183
|
-
new TextChunk(openTag(tagName
|
|
197
|
+
new TextChunk(openTag(tagName)),
|
|
184
198
|
...attributes.map((a) => attributeToHtmlChunk(a)),
|
|
185
199
|
new TextChunk(">"),
|
|
186
200
|
...children.map((c) => textToHtmlChunks(c)),
|
|
@@ -195,11 +209,11 @@ type AttrMap = {
|
|
|
195
209
|
}
|
|
196
210
|
|
|
197
211
|
const attrMap: AttrMap = {
|
|
198
|
-
attribute: (attr) => new TextChunk(` ${attr.name}="${attr.value}"`),
|
|
199
|
-
attr: (attr) => new PartChunk(attr, (value) => (value == null ? `` : ` ${attr.name}="${value}"`)),
|
|
212
|
+
attribute: (attr) => new TextChunk(` ${attr.name}="${escape(attr.value)}"`),
|
|
213
|
+
attr: (attr) => new PartChunk(attr, (value) => (value == null ? `` : ` ${attr.name}="${escape(value)}"`)),
|
|
200
214
|
boolean: (attr) => new TextChunk(" " + attr.name),
|
|
201
215
|
"boolean-part": (attr) => new PartChunk(attr, (value) => (value ? ` ${attr.name}` : "")),
|
|
202
|
-
"className-part": (attr) => new PartChunk(attr, (value) => (value ? ` class="${value}"` : "")),
|
|
216
|
+
"className-part": (attr) => new PartChunk(attr, (value) => (value ? ` class="${escape(value)}"` : "")),
|
|
203
217
|
data: (attr) =>
|
|
204
218
|
new PartChunk(attr, (value) => value == null ? `` : datasetToString(value as Readonly<Record<string, string>>)),
|
|
205
219
|
event: () => new TextChunk(""),
|
|
@@ -209,24 +223,45 @@ const attrMap: AttrMap = {
|
|
|
209
223
|
attr,
|
|
210
224
|
(
|
|
211
225
|
value
|
|
212
|
-
) =>
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
226
|
+
) => {
|
|
227
|
+
if (value == null) return ""
|
|
228
|
+
|
|
229
|
+
// Each call has only 1 key-value pair
|
|
230
|
+
const [k, v] = Object.entries(value)[0]
|
|
231
|
+
|
|
232
|
+
if (value == null) return ""
|
|
233
|
+
|
|
234
|
+
const [type, key] = keyToPartType(k)
|
|
235
|
+
|
|
236
|
+
switch (type) {
|
|
237
|
+
case "attr":
|
|
238
|
+
case "property":
|
|
239
|
+
return v == null ? "" : ` ${key}="${escape(v)}"`
|
|
240
|
+
case "boolean":
|
|
241
|
+
return v ? key : ""
|
|
242
|
+
case "class":
|
|
243
|
+
return ` class="${escape(v)}"`
|
|
244
|
+
case "data": {
|
|
245
|
+
const d = datasetToString(v)
|
|
246
|
+
return d.length === 0 ? "" : ` ${d}`
|
|
247
|
+
}
|
|
248
|
+
default:
|
|
249
|
+
return ""
|
|
250
|
+
}
|
|
251
|
+
}
|
|
217
252
|
),
|
|
218
253
|
ref: () => new TextChunk(""),
|
|
219
254
|
"sparse-attr": (attr) =>
|
|
220
255
|
new SparsePartChunk(attr, (values) => {
|
|
221
256
|
return values == null
|
|
222
257
|
? ``
|
|
223
|
-
: ` ${attr.name}="${Array.isArray(values) ? values.filter(isString).join("") : values}"`
|
|
258
|
+
: ` ${attr.name}="${Array.isArray(values) ? escape(values.filter(isString).join("")) : escape(values)}"`
|
|
224
259
|
}),
|
|
225
260
|
"sparse-class-name": (attr) =>
|
|
226
261
|
new SparsePartChunk(attr, (values) => {
|
|
227
262
|
return values == null
|
|
228
263
|
? ``
|
|
229
|
-
: ` class="${Array.isArray(values) ? values.filter(isString).join("
|
|
264
|
+
: ` class="${Array.isArray(values) ? escape(values.filter(isString).join("")) : escape(values)}"`
|
|
230
265
|
}),
|
|
231
266
|
text: (attr) => new TextChunk(attr.value)
|
|
232
267
|
}
|
|
@@ -241,16 +276,14 @@ function isString(value: unknown): value is string {
|
|
|
241
276
|
|
|
242
277
|
function datasetToString(dataset: Readonly<Record<string, string | undefined>>) {
|
|
243
278
|
const s = Object.entries(dataset)
|
|
244
|
-
.map(([key, value]) => (value === undefined ? `data-${key}` : `data-${key}="${value}"`))
|
|
279
|
+
.map(([key, value]) => (value === undefined ? `data-${key}` : `data-${key}="${escape(value)}"`))
|
|
245
280
|
.join(" ")
|
|
246
281
|
|
|
247
282
|
return s.length === 0 ? "" : " " + s
|
|
248
283
|
}
|
|
249
284
|
|
|
250
|
-
function openTag(tagName: string
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return `<${tagName} ${TYPED_HASH(hash)}`
|
|
285
|
+
function openTag(tagName: string): string {
|
|
286
|
+
return `<${tagName}`
|
|
254
287
|
}
|
|
255
288
|
|
|
256
289
|
function closeTag(tagName: string): string {
|
|
@@ -260,12 +293,26 @@ function closeTag(tagName: string): string {
|
|
|
260
293
|
/**
|
|
261
294
|
* @since 1.0.0
|
|
262
295
|
*/
|
|
263
|
-
export function escape(s: unknown) {
|
|
296
|
+
export function escape(s: unknown): string {
|
|
264
297
|
switch (typeof s) {
|
|
265
298
|
case "string":
|
|
266
299
|
case "number":
|
|
267
300
|
case "boolean":
|
|
301
|
+
case "bigint":
|
|
268
302
|
return escapeHtml(String(s))
|
|
303
|
+
case "object": {
|
|
304
|
+
if (isNullOrUndefined(s)) {
|
|
305
|
+
return ""
|
|
306
|
+
} else if (Array.isArray(s)) {
|
|
307
|
+
return s.map(escape).join("")
|
|
308
|
+
} else if (s instanceof Date) {
|
|
309
|
+
return escapeHtml(s.toISOString())
|
|
310
|
+
} else if (s instanceof RegExp) {
|
|
311
|
+
return escapeHtml(s.toString())
|
|
312
|
+
} else {
|
|
313
|
+
return escapeHtml(JSON.stringify(s))
|
|
314
|
+
}
|
|
315
|
+
}
|
|
269
316
|
default:
|
|
270
317
|
return escapeHtml(JSON.stringify(s))
|
|
271
318
|
}
|