@typed/template 0.3.0 → 0.3.2
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/dist/cjs/internal/EventSource.js +46 -19
- package/dist/cjs/internal/EventSource.js.map +1 -1
- package/dist/cjs/internal/chunks.js +15 -1
- package/dist/cjs/internal/chunks.js.map +1 -1
- package/dist/cjs/internal/errors.js +4 -0
- package/dist/cjs/internal/errors.js.map +1 -1
- package/dist/cjs/internal/hydrate.js +92 -58
- package/dist/cjs/internal/hydrate.js.map +1 -1
- package/dist/cjs/internal/parser.js +14 -6
- package/dist/cjs/internal/parser.js.map +1 -1
- package/dist/cjs/internal/render.js +17 -151
- package/dist/cjs/internal/render.js.map +1 -1
- package/dist/dts/internal/EventSource.d.ts.map +1 -1
- package/dist/dts/internal/chunks.d.ts +1 -0
- package/dist/dts/internal/chunks.d.ts.map +1 -1
- package/dist/dts/internal/errors.d.ts +1 -0
- package/dist/dts/internal/errors.d.ts.map +1 -1
- package/dist/dts/internal/hydrate.d.ts +9 -16
- package/dist/dts/internal/hydrate.d.ts.map +1 -1
- package/dist/dts/internal/parser.d.ts.map +1 -1
- package/dist/dts/internal/render.d.ts +0 -14
- package/dist/dts/internal/render.d.ts.map +1 -1
- package/dist/esm/internal/EventSource.js +51 -21
- package/dist/esm/internal/EventSource.js.map +1 -1
- package/dist/esm/internal/chunks.js +13 -0
- package/dist/esm/internal/chunks.js.map +1 -1
- package/dist/esm/internal/errors.js +3 -0
- package/dist/esm/internal/errors.js.map +1 -1
- package/dist/esm/internal/hydrate.js +94 -56
- package/dist/esm/internal/hydrate.js.map +1 -1
- package/dist/esm/internal/parser.js +16 -7
- package/dist/esm/internal/parser.js.map +1 -1
- package/dist/esm/internal/render.js +18 -147
- package/dist/esm/internal/render.js.map +1 -1
- package/package.json +2 -2
- package/src/internal/EventSource.ts +63 -34
- package/src/internal/chunks.ts +16 -0
- package/src/internal/errors.ts +4 -0
- package/src/internal/hydrate.ts +124 -77
- package/src/internal/parser.ts +17 -8
- package/src/internal/render.ts +30 -293
package/src/internal/render.ts
CHANGED
|
@@ -4,8 +4,8 @@ import type { Rendered } from "@typed/wire"
|
|
|
4
4
|
import { persistent } from "@typed/wire"
|
|
5
5
|
import { Effect } from "effect"
|
|
6
6
|
import type { Cause } from "effect/Cause"
|
|
7
|
+
import type { Chunk } from "effect/Chunk"
|
|
7
8
|
import * as Context from "effect/Context"
|
|
8
|
-
import { replace } from "effect/ReadonlyArray"
|
|
9
9
|
import { Scope } from "effect/Scope"
|
|
10
10
|
import type { Directive } from "../Directive.js"
|
|
11
11
|
import { isDirective } from "../Directive.js"
|
|
@@ -13,16 +13,7 @@ import * as ElementRef from "../ElementRef.js"
|
|
|
13
13
|
import * as ElementSource from "../ElementSource.js"
|
|
14
14
|
import type { BrowserEntry } from "../Entry.js"
|
|
15
15
|
import * as EventHandler from "../EventHandler.js"
|
|
16
|
-
import type {
|
|
17
|
-
AttributePart,
|
|
18
|
-
ClassNamePart,
|
|
19
|
-
CommentPart,
|
|
20
|
-
Part,
|
|
21
|
-
Parts,
|
|
22
|
-
PropertiesPart,
|
|
23
|
-
SparsePart,
|
|
24
|
-
StaticText
|
|
25
|
-
} from "../Part.js"
|
|
16
|
+
import type { Part } from "../Part.js"
|
|
26
17
|
import type { Placeholder } from "../Placeholder.js"
|
|
27
18
|
import type { ToRendered } from "../Render.js"
|
|
28
19
|
import type { Renderable } from "../Renderable.js"
|
|
@@ -34,7 +25,7 @@ import type * as Template from "../Template.js"
|
|
|
34
25
|
import { makeRenderNodePart } from "./browser.js"
|
|
35
26
|
import { type EventSource, makeEventSource } from "./EventSource.js"
|
|
36
27
|
import { HydrateContext } from "./HydrateContext.js"
|
|
37
|
-
import type {
|
|
28
|
+
import type { IndexRefCounter2 } from "./indexRefCounter.js"
|
|
38
29
|
import { indexRefCounter2 } from "./indexRefCounter.js"
|
|
39
30
|
import { parse } from "./parser.js"
|
|
40
31
|
import {
|
|
@@ -43,14 +34,8 @@ import {
|
|
|
43
34
|
ClassNamePartImpl,
|
|
44
35
|
CommentPartImpl,
|
|
45
36
|
DataPartImpl,
|
|
46
|
-
EventPartImpl,
|
|
47
|
-
PropertiesPartImpl,
|
|
48
37
|
PropertyPartImpl,
|
|
49
38
|
RefPartImpl,
|
|
50
|
-
SparseAttributePartImpl,
|
|
51
|
-
SparseClassNamePartImpl,
|
|
52
|
-
SparseCommentPartImpl,
|
|
53
|
-
StaticTextImpl,
|
|
54
39
|
TextPartImpl
|
|
55
40
|
} from "./parts.js"
|
|
56
41
|
import type { ParentChildNodes } from "./utils.js"
|
|
@@ -63,14 +48,16 @@ import { findHoleComment, findPath } from "./utils.js"
|
|
|
63
48
|
/**
|
|
64
49
|
* @internal
|
|
65
50
|
*/
|
|
66
|
-
type RenderPartContext = {
|
|
51
|
+
export type RenderPartContext = {
|
|
67
52
|
readonly context: Context.Context<Scope>
|
|
68
53
|
readonly document: Document
|
|
69
54
|
readonly eventSource: EventSource
|
|
70
55
|
readonly refCounter: IndexRefCounter2
|
|
71
56
|
readonly renderContext: RenderContext
|
|
72
57
|
readonly values: ReadonlyArray<Renderable<any, any>>
|
|
73
|
-
readonly onCause: (cause: Cause<
|
|
58
|
+
readonly onCause: (cause: Cause<any>) => Effect.Effect<never, never, void>
|
|
59
|
+
|
|
60
|
+
readonly makeHydrateContext?: (index: number) => HydrateContext
|
|
74
61
|
|
|
75
62
|
expected: number
|
|
76
63
|
}
|
|
@@ -219,20 +206,27 @@ const RenderPartMap: RenderPartMap = {
|
|
|
219
206
|
return null
|
|
220
207
|
},
|
|
221
208
|
"node": (templatePart, node, ctx) => {
|
|
209
|
+
const makeHydrateContext = ctx.makeHydrateContext
|
|
222
210
|
const part = makeRenderNodePart(
|
|
223
211
|
templatePart.index,
|
|
224
212
|
node as HTMLElement | SVGElement,
|
|
225
213
|
ctx.renderContext,
|
|
226
214
|
ctx.document,
|
|
227
|
-
|
|
215
|
+
!!makeHydrateContext
|
|
228
216
|
)
|
|
229
217
|
|
|
230
218
|
ctx.expected++
|
|
231
219
|
|
|
232
|
-
|
|
220
|
+
const handle = handlePart(
|
|
233
221
|
ctx.values[templatePart.index],
|
|
234
222
|
(value) => Effect.zipRight(part.update(value as any), ctx.refCounter.release(templatePart.index))
|
|
235
223
|
)
|
|
224
|
+
|
|
225
|
+
if (makeHydrateContext) {
|
|
226
|
+
return Effect.provideService(handle, HydrateContext, makeHydrateContext(templatePart.index))
|
|
227
|
+
} else {
|
|
228
|
+
return handle
|
|
229
|
+
}
|
|
236
230
|
},
|
|
237
231
|
"property": (templatePart, node, ctx) => {
|
|
238
232
|
const element = node as HTMLElement | SVGElement
|
|
@@ -517,6 +511,18 @@ function diffClassNames(oldClassNames: Set<string>, newClassNames: Set<string>)
|
|
|
517
511
|
return { added, removed }
|
|
518
512
|
}
|
|
519
513
|
|
|
514
|
+
/**
|
|
515
|
+
* @internal
|
|
516
|
+
*/
|
|
517
|
+
export function renderPart2(
|
|
518
|
+
part: Template.PartNode | Template.SparsePartNode,
|
|
519
|
+
content: ParentChildNodes,
|
|
520
|
+
path: Chunk<number>,
|
|
521
|
+
ctx: RenderPartContext
|
|
522
|
+
): Effect.Effect<any, any, void> | Array<Effect.Effect<any, any, void>> | null {
|
|
523
|
+
return RenderPartMap[part._tag](part as any, findPath(content, path), ctx)
|
|
524
|
+
}
|
|
525
|
+
|
|
520
526
|
/**
|
|
521
527
|
* Here for "standard" browser rendering, a TemplateInstance is effectively a live
|
|
522
528
|
* view into the contents rendered by the Template.
|
|
@@ -553,7 +559,7 @@ export const renderTemplate: (document: Document, renderContext: RenderContext)
|
|
|
553
559
|
// Connect our interpolated values to our template parts
|
|
554
560
|
const effects: Array<Effect.Effect<Scope | Placeholder.Context<Values[number]>, never, void>> = []
|
|
555
561
|
for (const [part, path] of entry.template.parts) {
|
|
556
|
-
const eff =
|
|
562
|
+
const eff = renderPart2(part, content, path, ctx)
|
|
557
563
|
if (eff !== null) {
|
|
558
564
|
effects.push(
|
|
559
565
|
...(Array.isArray(eff) ? eff : [eff]) as Array<
|
|
@@ -580,7 +586,7 @@ export const renderTemplate: (document: Document, renderContext: RenderContext)
|
|
|
580
586
|
// Set the element when it is ready
|
|
581
587
|
yield* _(ctx.eventSource.setup(wire, Context.get(context, Scope)))
|
|
582
588
|
|
|
583
|
-
//
|
|
589
|
+
// Emit our DomRenderEvent
|
|
584
590
|
yield* _(sink.onSuccess(DomRenderEvent(wire)))
|
|
585
591
|
|
|
586
592
|
// Ensure our templates last forever in the DOM environment
|
|
@@ -590,109 +596,6 @@ export const renderTemplate: (document: Document, renderContext: RenderContext)
|
|
|
590
596
|
})
|
|
591
597
|
}
|
|
592
598
|
|
|
593
|
-
export function renderValues<Values extends ReadonlyArray<Renderable<any, any>>>(
|
|
594
|
-
values: Values,
|
|
595
|
-
parts: Parts,
|
|
596
|
-
refCounter: IndexRefCounter,
|
|
597
|
-
ctx: Context.Context<any> | Context.Context<never>,
|
|
598
|
-
makeHydrateContext?: (index: number) => HydrateContext
|
|
599
|
-
): Effect.Effect<Placeholder.Context<Values[number]> | Scope, never, void> {
|
|
600
|
-
return Effect.all(parts.map((part, index) => {
|
|
601
|
-
switch (part._tag) {
|
|
602
|
-
case "sparse/attribute":
|
|
603
|
-
case "sparse/className":
|
|
604
|
-
case "sparse/comment": {
|
|
605
|
-
return renderSparsePart(values, part, refCounter)
|
|
606
|
-
}
|
|
607
|
-
default:
|
|
608
|
-
return renderPart(
|
|
609
|
-
values,
|
|
610
|
-
part,
|
|
611
|
-
refCounter,
|
|
612
|
-
ctx,
|
|
613
|
-
makeHydrateContext ? () => makeHydrateContext(index) : undefined
|
|
614
|
-
)
|
|
615
|
-
}
|
|
616
|
-
}))
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
export function renderSparsePart(
|
|
620
|
-
values: ReadonlyArray<Renderable<any, any>>,
|
|
621
|
-
part: SparsePart,
|
|
622
|
-
refCounter: IndexRefCounter
|
|
623
|
-
) {
|
|
624
|
-
const indexes = part.parts.flatMap((p) => p._tag === "static/text" ? [] : [p.index])
|
|
625
|
-
|
|
626
|
-
return Effect.forkScoped(
|
|
627
|
-
Fx.observe(
|
|
628
|
-
unwrapSparsePartRenderables(
|
|
629
|
-
part.parts.map((p) => p._tag === "static/text" ? Fx.succeed(p.value) : values[p.index]),
|
|
630
|
-
part
|
|
631
|
-
),
|
|
632
|
-
(value) => Effect.tap(part.update(value as any), () => Effect.forEach(indexes, (a) => refCounter.release(a)))
|
|
633
|
-
)
|
|
634
|
-
)
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
export function renderPart<Values extends ReadonlyArray<Renderable<any, any>>>(
|
|
638
|
-
values: Values,
|
|
639
|
-
part: Part,
|
|
640
|
-
refCounter: IndexRefCounter,
|
|
641
|
-
ctx: Context.Context<any> | Context.Context<never>,
|
|
642
|
-
hydrateCtx?: () => HydrateContext
|
|
643
|
-
): Effect.Effect<any, never, void> {
|
|
644
|
-
const partIndex = part.index
|
|
645
|
-
const renderable = values[partIndex]
|
|
646
|
-
|
|
647
|
-
if (renderable === null || renderable === undefined) return refCounter.release(partIndex)
|
|
648
|
-
|
|
649
|
-
if (isDirective(renderable)) {
|
|
650
|
-
return renderable(part).pipe(
|
|
651
|
-
Effect.flatMap(() => refCounter.release(partIndex)),
|
|
652
|
-
Effect.forkScoped
|
|
653
|
-
)
|
|
654
|
-
} else if (part._tag === "ref") {
|
|
655
|
-
return refCounter.release(partIndex)
|
|
656
|
-
} else if (part._tag === "event") {
|
|
657
|
-
const handler = getEventHandler(renderable, ctx, part.onCause)
|
|
658
|
-
if (handler) {
|
|
659
|
-
part.addEventListener(handler)
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
return refCounter.release(partIndex)
|
|
663
|
-
} else if (part._tag === "node" && hydrateCtx) {
|
|
664
|
-
return handlePart(
|
|
665
|
-
renderable,
|
|
666
|
-
(value) => Effect.flatMap(part.update(value), () => refCounter.release(partIndex))
|
|
667
|
-
).pipe(
|
|
668
|
-
HydrateContext.provide(hydrateCtx()),
|
|
669
|
-
Effect.forkScoped
|
|
670
|
-
)
|
|
671
|
-
} else if (part._tag === "properties") {
|
|
672
|
-
return handlePropertiesPart(renderable, part, refCounter)
|
|
673
|
-
} else {
|
|
674
|
-
return handlePart(
|
|
675
|
-
renderable,
|
|
676
|
-
(value) => Effect.flatMap(part.update(value as any), () => refCounter.release(partIndex))
|
|
677
|
-
)
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
function handlePropertiesPart<R, E>(
|
|
682
|
-
renderable: unknown,
|
|
683
|
-
part: PropertiesPart,
|
|
684
|
-
refCounter: IndexRefCounter
|
|
685
|
-
): Effect.Effect<R | Scope, E, void> {
|
|
686
|
-
if (renderable && typeof renderable === "object") {
|
|
687
|
-
return handlePart(
|
|
688
|
-
Fx.struct(Object.fromEntries(Object.entries(renderable).map(([k, v]) => [k, unwrapRenderable(v)] as const))),
|
|
689
|
-
(value) => Effect.tap(part.update(value as any), () => refCounter.release(part.index))
|
|
690
|
-
)
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
return Effect.succeed(void 0)
|
|
694
|
-
}
|
|
695
|
-
|
|
696
599
|
function getEventHandler<R, E>(
|
|
697
600
|
renderable: any,
|
|
698
601
|
ctx: Context.Context<any> | Context.Context<never>,
|
|
@@ -757,31 +660,6 @@ function unwrapRenderable<R, E>(renderable: unknown): Fx.Fx<R, E, any> {
|
|
|
757
660
|
}
|
|
758
661
|
}
|
|
759
662
|
|
|
760
|
-
function unwrapSparsePartRenderables(
|
|
761
|
-
renderables: ReadonlyArray<Renderable<any, any>>,
|
|
762
|
-
part: SparsePart
|
|
763
|
-
) {
|
|
764
|
-
return Fx.tuple(
|
|
765
|
-
// @ts-ignore type too deep
|
|
766
|
-
renderables.map((renderable, i) => {
|
|
767
|
-
const p = part.parts[i]
|
|
768
|
-
|
|
769
|
-
if (p._tag === "static/text") {
|
|
770
|
-
return Fx.succeed(p.value)
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
if (isDirective(renderable)) {
|
|
774
|
-
return Fx.fromEffect(Effect.map(renderable(p), () => p.value))
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
return Fx.mapEffect(
|
|
778
|
-
unwrapRenderable(renderable),
|
|
779
|
-
(u) => Effect.map(p.update(u), () => p.value)
|
|
780
|
-
)
|
|
781
|
-
})
|
|
782
|
-
) as any
|
|
783
|
-
}
|
|
784
|
-
|
|
785
663
|
export function attachRoot<T extends RenderEvent | null>(
|
|
786
664
|
cache: RenderContext["renderCache"],
|
|
787
665
|
where: HTMLElement,
|
|
@@ -844,147 +722,6 @@ export function getBrowserEntry(
|
|
|
844
722
|
}
|
|
845
723
|
}
|
|
846
724
|
|
|
847
|
-
export function buildParts<E>(
|
|
848
|
-
document: Document,
|
|
849
|
-
ctx: RenderContext,
|
|
850
|
-
template: Template.Template,
|
|
851
|
-
content: ParentChildNodes,
|
|
852
|
-
eventSource: EventSource,
|
|
853
|
-
onCause: (cause: Cause<E>) => Effect.Effect<never, never, void>,
|
|
854
|
-
isHydrating: boolean
|
|
855
|
-
): Parts {
|
|
856
|
-
return template.parts.map(([part, path]) =>
|
|
857
|
-
buildPartWithNode(document, ctx, part, findPath(content, path), eventSource, onCause, isHydrating)
|
|
858
|
-
)
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
function buildPartWithNode<E>(
|
|
862
|
-
document: Document,
|
|
863
|
-
ctx: RenderContext,
|
|
864
|
-
part: Template.PartNode | Template.SparsePartNode,
|
|
865
|
-
node: Node,
|
|
866
|
-
eventSource: EventSource,
|
|
867
|
-
onCause: (cause: Cause<E>) => Effect.Effect<never, never, void>,
|
|
868
|
-
isHydrating: boolean
|
|
869
|
-
): Part | SparsePart {
|
|
870
|
-
switch (part._tag) {
|
|
871
|
-
case "attr":
|
|
872
|
-
return AttributePartImpl.browser(part.index, node as Element, part.name, ctx)
|
|
873
|
-
case "boolean-part":
|
|
874
|
-
return BooleanPartImpl.browser(part.index, node as Element, part.name, ctx)
|
|
875
|
-
case "className-part":
|
|
876
|
-
return ClassNamePartImpl.browser(part.index, node as Element, ctx)
|
|
877
|
-
case "comment-part":
|
|
878
|
-
return CommentPartImpl.browser(part.index, node as Comment, ctx)
|
|
879
|
-
case "data":
|
|
880
|
-
return DataPartImpl.browser(part.index, node as HTMLElement | SVGElement, ctx)
|
|
881
|
-
case "event":
|
|
882
|
-
return new EventPartImpl(
|
|
883
|
-
part.name,
|
|
884
|
-
part.index,
|
|
885
|
-
ElementSource.fromElement(node as Element),
|
|
886
|
-
onCause as any,
|
|
887
|
-
(handler) => eventSource.addEventListener(node as Element, part.name, handler)
|
|
888
|
-
)
|
|
889
|
-
case "node":
|
|
890
|
-
return makeRenderNodePart(part.index, node as HTMLElement | SVGElement, ctx, document, isHydrating)
|
|
891
|
-
case "property":
|
|
892
|
-
return PropertyPartImpl.browser(part.index, node, part.name, ctx)
|
|
893
|
-
case "properties":
|
|
894
|
-
return PropertiesPartImpl.browser(part.index, node as HTMLElement | SVGElement, ctx)
|
|
895
|
-
case "ref":
|
|
896
|
-
return new RefPartImpl(ElementSource.fromElement(node as Element), part.index) as any
|
|
897
|
-
case "sparse-attr": {
|
|
898
|
-
const parts: Array<AttributePart | StaticText> = Array(part.nodes.length)
|
|
899
|
-
const sparse = SparseAttributePartImpl.browser(
|
|
900
|
-
part.name,
|
|
901
|
-
parts,
|
|
902
|
-
node as HTMLElement | SVGElement,
|
|
903
|
-
ctx
|
|
904
|
-
)
|
|
905
|
-
|
|
906
|
-
for (let i = 0; i < part.nodes.length; ++i) {
|
|
907
|
-
const node = part.nodes[i]
|
|
908
|
-
|
|
909
|
-
if (node._tag === "text") {
|
|
910
|
-
parts.push(new StaticTextImpl(node.value))
|
|
911
|
-
;(sparse as any).value[i] = node.value
|
|
912
|
-
} else {
|
|
913
|
-
parts.push(
|
|
914
|
-
new AttributePartImpl(
|
|
915
|
-
node.name,
|
|
916
|
-
node.index,
|
|
917
|
-
({ value }) => sparse.update(replace(sparse.value, i, value || "")),
|
|
918
|
-
sparse.value[i]
|
|
919
|
-
)
|
|
920
|
-
)
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
return sparse
|
|
925
|
-
}
|
|
926
|
-
case "sparse-class-name": {
|
|
927
|
-
const parts: Array<ClassNamePart | StaticText> = []
|
|
928
|
-
const values: Array<string | Array<string>> = [] // TODO: Do this for all other sparse attrs
|
|
929
|
-
const sparse = SparseClassNamePartImpl.browser(
|
|
930
|
-
parts,
|
|
931
|
-
node as HTMLElement | SVGElement,
|
|
932
|
-
ctx,
|
|
933
|
-
values
|
|
934
|
-
)
|
|
935
|
-
|
|
936
|
-
for (let i = 0; i < part.nodes.length; ++i) {
|
|
937
|
-
const node = part.nodes[i]
|
|
938
|
-
|
|
939
|
-
if (node._tag === "text") {
|
|
940
|
-
parts.push(new StaticTextImpl(node.value))
|
|
941
|
-
values.push(node.value)
|
|
942
|
-
} else {
|
|
943
|
-
values.push([])
|
|
944
|
-
parts.push(
|
|
945
|
-
new ClassNamePartImpl(
|
|
946
|
-
node.index,
|
|
947
|
-
({ value }) => sparse.update(replace(sparse.value, i, value || "")),
|
|
948
|
-
[]
|
|
949
|
-
)
|
|
950
|
-
)
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
return sparse
|
|
955
|
-
}
|
|
956
|
-
case "sparse-comment": {
|
|
957
|
-
const parts: Array<CommentPart | StaticText> = Array(part.nodes.length)
|
|
958
|
-
const sparse = SparseCommentPartImpl.browser(
|
|
959
|
-
node as Comment,
|
|
960
|
-
parts,
|
|
961
|
-
ctx
|
|
962
|
-
)
|
|
963
|
-
|
|
964
|
-
for (let i = 0; i < part.nodes.length; ++i) {
|
|
965
|
-
const node = part.nodes[i]
|
|
966
|
-
|
|
967
|
-
if (node._tag === "text") {
|
|
968
|
-
parts.push(new StaticTextImpl(node.value))
|
|
969
|
-
;(sparse as any).value[i] = node.value
|
|
970
|
-
} else {
|
|
971
|
-
parts.push(
|
|
972
|
-
new CommentPartImpl(
|
|
973
|
-
node.index,
|
|
974
|
-
({ value }) => sparse.update(replace(sparse.value, i, value || "")),
|
|
975
|
-
sparse.value[i]
|
|
976
|
-
)
|
|
977
|
-
)
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
return sparse
|
|
982
|
-
}
|
|
983
|
-
case "text-part":
|
|
984
|
-
return TextPartImpl.browser(document, part.index, node as Element, ctx)
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
|
|
988
725
|
export function buildTemplate(document: Document, { nodes }: Template.Template): DocumentFragment {
|
|
989
726
|
const fragment = document.createDocumentFragment()
|
|
990
727
|
|