@typed/template 0.1.4 → 0.3.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/Directive/package.json +6 -0
- package/ElementRef/package.json +6 -0
- package/ElementSource/package.json +6 -0
- package/Entry/package.json +6 -0
- package/EventHandler/package.json +6 -0
- package/Html/package.json +6 -0
- package/HtmlChunk/package.json +6 -0
- package/Hydrate/package.json +6 -0
- package/Many/package.json +6 -0
- package/Meta/package.json +6 -0
- package/Parser/package.json +6 -0
- package/Part/package.json +6 -0
- package/Placeholder/package.json +6 -0
- package/Platform/package.json +6 -0
- package/Render/package.json +6 -0
- package/RenderContext/package.json +6 -0
- package/RenderEvent/package.json +6 -0
- package/RenderTemplate/package.json +6 -0
- package/Renderable/package.json +6 -0
- package/Template/package.json +6 -0
- package/TemplateInstance/package.json +6 -0
- package/Test/package.json +6 -0
- package/Vitest/package.json +6 -0
- package/dist/cjs/Directive.js +1 -1
- package/dist/cjs/Directive.js.map +1 -1
- package/dist/cjs/ElementRef.js +23 -13
- package/dist/cjs/ElementRef.js.map +1 -1
- package/dist/cjs/ElementSource.js +16 -18
- package/dist/cjs/ElementSource.js.map +1 -1
- package/dist/cjs/EventHandler.js +1 -1
- package/dist/cjs/EventHandler.js.map +1 -1
- package/dist/cjs/Html.js +31 -32
- package/dist/cjs/Html.js.map +1 -1
- package/dist/cjs/HtmlChunk.js +4 -1
- package/dist/cjs/HtmlChunk.js.map +1 -1
- package/dist/cjs/Hydrate.js +1 -1
- package/dist/cjs/Hydrate.js.map +1 -1
- package/dist/cjs/Many.js +14 -13
- package/dist/cjs/Many.js.map +1 -1
- package/dist/cjs/Parser.js +11 -323
- package/dist/cjs/Parser.js.map +1 -1
- package/dist/cjs/Placeholder.js +3 -3
- package/dist/cjs/Placeholder.js.map +1 -1
- package/dist/cjs/Platform.js +4 -4
- package/dist/cjs/Platform.js.map +1 -1
- package/dist/cjs/Render.js +1 -1
- package/dist/cjs/Render.js.map +1 -1
- package/dist/cjs/RenderContext.js +48 -27
- package/dist/cjs/RenderContext.js.map +1 -1
- package/dist/cjs/RenderTemplate.js +2 -17
- package/dist/cjs/RenderTemplate.js.map +1 -1
- package/dist/cjs/Template.js +27 -1
- package/dist/cjs/Template.js.map +1 -1
- package/dist/cjs/TemplateInstance.js +2 -2
- package/dist/cjs/TemplateInstance.js.map +1 -1
- package/dist/cjs/Test.js +20 -7
- package/dist/cjs/Test.js.map +1 -1
- package/dist/cjs/index.js +0 -12
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/EventSource.js +95 -0
- package/dist/cjs/internal/EventSource.js.map +1 -0
- package/dist/cjs/internal/browser.js +11 -11
- package/dist/cjs/internal/browser.js.map +1 -1
- package/dist/cjs/internal/hydrate.js +49 -50
- package/dist/cjs/internal/hydrate.js.map +1 -1
- package/dist/cjs/internal/indexRefCounter.js +49 -2
- package/dist/cjs/internal/indexRefCounter.js.map +1 -1
- package/dist/cjs/internal/parser.js +60 -17
- package/dist/cjs/internal/parser.js.map +1 -1
- package/dist/cjs/internal/parts.js +128 -28
- package/dist/cjs/internal/parts.js.map +1 -1
- package/dist/cjs/internal/render.js +486 -53
- package/dist/cjs/internal/render.js.map +1 -1
- package/dist/cjs/internal/server.js +5 -2
- package/dist/cjs/internal/server.js.map +1 -1
- package/dist/dts/Directive.d.ts.map +1 -1
- package/dist/dts/ElementRef.d.ts +4 -2
- package/dist/dts/ElementRef.d.ts.map +1 -1
- package/dist/dts/ElementSource.d.ts +10 -5
- package/dist/dts/ElementSource.d.ts.map +1 -1
- package/dist/dts/EventHandler.d.ts.map +1 -1
- package/dist/dts/Html.d.ts +1 -1
- package/dist/dts/Html.d.ts.map +1 -1
- package/dist/dts/HtmlChunk.d.ts.map +1 -1
- package/dist/dts/Many.d.ts +13 -11
- package/dist/dts/Many.d.ts.map +1 -1
- package/dist/dts/Parser.d.ts +3 -6
- package/dist/dts/Parser.d.ts.map +1 -1
- package/dist/dts/Part.d.ts +13 -3
- package/dist/dts/Part.d.ts.map +1 -1
- package/dist/dts/Placeholder.d.ts +2 -2
- package/dist/dts/Placeholder.d.ts.map +1 -1
- package/dist/dts/Render.d.ts +2 -1
- package/dist/dts/Render.d.ts.map +1 -1
- package/dist/dts/RenderContext.d.ts +5 -4
- package/dist/dts/RenderContext.d.ts.map +1 -1
- package/dist/dts/RenderTemplate.d.ts +2 -16
- package/dist/dts/RenderTemplate.d.ts.map +1 -1
- package/dist/dts/Renderable.d.ts +2 -2
- package/dist/dts/Renderable.d.ts.map +1 -1
- package/dist/dts/Template.d.ts +21 -3
- package/dist/dts/Template.d.ts.map +1 -1
- package/dist/dts/TemplateInstance.d.ts +3 -2
- package/dist/dts/TemplateInstance.d.ts.map +1 -1
- package/dist/dts/Test.d.ts +4 -6
- package/dist/dts/Test.d.ts.map +1 -1
- package/dist/dts/index.d.ts +0 -4
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/EventSource.d.ts +12 -0
- package/dist/dts/internal/EventSource.d.ts.map +1 -0
- package/dist/dts/internal/browser.d.ts.map +1 -1
- package/dist/dts/internal/hydrate.d.ts +5 -5
- package/dist/dts/internal/hydrate.d.ts.map +1 -1
- package/dist/dts/internal/indexRefCounter.d.ts +5 -0
- package/dist/dts/internal/indexRefCounter.d.ts.map +1 -1
- package/dist/dts/internal/module-augmentation.d.ts +0 -4
- package/dist/dts/internal/module-augmentation.d.ts.map +1 -1
- package/dist/dts/internal/parser.d.ts +8 -0
- package/dist/dts/internal/parser.d.ts.map +1 -1
- package/dist/dts/internal/parts.d.ts +66 -56
- package/dist/dts/internal/parts.d.ts.map +1 -1
- package/dist/dts/internal/render.d.ts +7 -7
- package/dist/dts/internal/render.d.ts.map +1 -1
- package/dist/dts/internal/server.d.ts.map +1 -1
- package/dist/esm/Directive.js +1 -1
- package/dist/esm/Directive.js.map +1 -1
- package/dist/esm/ElementRef.js +12 -7
- package/dist/esm/ElementRef.js.map +1 -1
- package/dist/esm/ElementSource.js +16 -13
- package/dist/esm/ElementSource.js.map +1 -1
- package/dist/esm/EventHandler.js +1 -1
- package/dist/esm/EventHandler.js.map +1 -1
- package/dist/esm/Html.js +29 -24
- package/dist/esm/Html.js.map +1 -1
- package/dist/esm/HtmlChunk.js +6 -1
- package/dist/esm/HtmlChunk.js.map +1 -1
- package/dist/esm/Hydrate.js +1 -1
- package/dist/esm/Hydrate.js.map +1 -1
- package/dist/esm/Many.js +14 -10
- package/dist/esm/Many.js.map +1 -1
- package/dist/esm/Parser.js +6 -335
- package/dist/esm/Parser.js.map +1 -1
- package/dist/esm/Placeholder.js +2 -2
- package/dist/esm/Placeholder.js.map +1 -1
- package/dist/esm/Platform.js +2 -2
- package/dist/esm/Platform.js.map +1 -1
- package/dist/esm/Render.js +1 -1
- package/dist/esm/Render.js.map +1 -1
- package/dist/esm/RenderContext.js +38 -17
- package/dist/esm/RenderContext.js.map +1 -1
- package/dist/esm/RenderTemplate.js +2 -12
- package/dist/esm/RenderTemplate.js.map +1 -1
- package/dist/esm/Template.js +24 -0
- package/dist/esm/Template.js.map +1 -1
- package/dist/esm/TemplateInstance.js +2 -2
- package/dist/esm/TemplateInstance.js.map +1 -1
- package/dist/esm/Test.js +20 -7
- package/dist/esm/Test.js.map +1 -1
- package/dist/esm/index.js +0 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/EventSource.js +91 -0
- package/dist/esm/internal/EventSource.js.map +1 -0
- package/dist/esm/internal/browser.js +12 -12
- package/dist/esm/internal/browser.js.map +1 -1
- package/dist/esm/internal/hydrate.js +45 -46
- package/dist/esm/internal/hydrate.js.map +1 -1
- package/dist/esm/internal/indexRefCounter.js +50 -2
- package/dist/esm/internal/indexRefCounter.js.map +1 -1
- package/dist/esm/internal/parser.js +84 -17
- package/dist/esm/internal/parser.js.map +1 -1
- package/dist/esm/internal/parts.js +110 -27
- package/dist/esm/internal/parts.js.map +1 -1
- package/dist/esm/internal/render.js +476 -58
- package/dist/esm/internal/render.js.map +1 -1
- package/dist/esm/internal/server.js +5 -4
- package/dist/esm/internal/server.js.map +1 -1
- package/package.json +10 -26
- package/src/Directive.ts +1 -1
- package/src/ElementRef.ts +18 -14
- package/src/ElementSource.ts +62 -47
- package/src/EventHandler.ts +1 -1
- package/src/Html.ts +58 -57
- package/src/HtmlChunk.ts +15 -1
- package/src/Hydrate.ts +1 -1
- package/src/Many.ts +53 -43
- package/src/Parser.ts +10 -453
- package/src/Part.ts +15 -3
- package/src/Placeholder.ts +4 -4
- package/src/Platform.ts +2 -2
- package/src/Render.ts +7 -2
- package/src/RenderContext.ts +49 -21
- package/src/RenderTemplate.ts +9 -54
- package/src/Renderable.ts +2 -1
- package/src/Template.ts +26 -0
- package/src/TemplateInstance.ts +9 -9
- package/src/Test.ts +40 -21
- package/src/index.ts +0 -4
- package/src/internal/EventSource.ts +153 -0
- package/src/internal/browser.ts +26 -25
- package/src/internal/hydrate.ts +68 -61
- package/src/internal/indexRefCounter.ts +63 -2
- package/src/internal/module-augmentation.ts +0 -4
- package/src/internal/parser.ts +92 -19
- package/src/internal/parts.ts +158 -73
- package/src/internal/render.ts +701 -89
- package/src/internal/server.ts +5 -3
- package/dist/cjs/Token.js +0 -270
- package/dist/cjs/Token.js.map +0 -1
- package/dist/cjs/Tokenizer.js +0 -18
- package/dist/cjs/Tokenizer.js.map +0 -1
- package/dist/cjs/internal/readAttribute.js +0 -34
- package/dist/cjs/internal/readAttribute.js.map +0 -1
- package/dist/cjs/internal/tokenizer.js +0 -264
- package/dist/cjs/internal/tokenizer.js.map +0 -1
- package/dist/dts/Token.d.ts +0 -202
- package/dist/dts/Token.d.ts.map +0 -1
- package/dist/dts/Tokenizer.d.ts +0 -6
- package/dist/dts/Tokenizer.d.ts.map +0 -1
- package/dist/dts/internal/readAttribute.d.ts +0 -9
- package/dist/dts/internal/readAttribute.d.ts.map +0 -1
- package/dist/dts/internal/tokenizer.d.ts +0 -3
- package/dist/dts/internal/tokenizer.d.ts.map +0 -1
- package/dist/esm/Token.js +0 -264
- package/dist/esm/Token.js.map +0 -1
- package/dist/esm/Tokenizer.js +0 -9
- package/dist/esm/Tokenizer.js.map +0 -1
- package/dist/esm/internal/readAttribute.js +0 -24
- package/dist/esm/internal/readAttribute.js.map +0 -1
- package/dist/esm/internal/tokenizer.js +0 -296
- package/dist/esm/internal/tokenizer.js.map +0 -1
- package/src/Token.ts +0 -269
- package/src/Tokenizer.ts +0 -10
- package/src/internal/readAttribute.ts +0 -28
- package/src/internal/tokenizer.ts +0 -338
package/src/internal/browser.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { diffable, isComment } from "@typed/wire"
|
|
2
2
|
import udomdiff from "udomdiff"
|
|
3
3
|
import type { RenderContext } from "../RenderContext.js"
|
|
4
|
-
import type { RenderEvent } from "../RenderEvent.js"
|
|
5
4
|
import { isRenderEvent } from "../RenderEvent.js"
|
|
6
5
|
import { NodePartImpl } from "./parts.js"
|
|
7
6
|
import { findHoleComment, isCommentWithValue } from "./utils.js"
|
|
@@ -19,16 +18,20 @@ export function makeRenderNodePart(
|
|
|
19
18
|
|
|
20
19
|
return new NodePartImpl(index, ({ part, value }) => {
|
|
21
20
|
return ctx.queue.add(part, () => {
|
|
22
|
-
matchValue(
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
matchValue(
|
|
22
|
+
value,
|
|
23
|
+
(content) => {
|
|
24
|
+
if (text === undefined) {
|
|
25
|
+
text = document.createTextNode("")
|
|
26
|
+
}
|
|
27
|
+
text.textContent = content
|
|
28
|
+
|
|
29
|
+
nodes = diffChildren(comment, nodes, [text], document)
|
|
30
|
+
},
|
|
31
|
+
(updatedNodes) => {
|
|
32
|
+
nodes = diffChildren(comment, nodes, updatedNodes, document)
|
|
25
33
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
nodes = diffChildren(comment, nodes, [text], document)
|
|
29
|
-
}, (updatedNodes) => {
|
|
30
|
-
nodes = diffChildren(comment, nodes, updatedNodes, document)
|
|
31
|
-
})
|
|
34
|
+
)
|
|
32
35
|
})
|
|
33
36
|
}, nodes)
|
|
34
37
|
}
|
|
@@ -83,22 +86,12 @@ export function diffChildren(
|
|
|
83
86
|
comment.parentNode!,
|
|
84
87
|
// Document Fragments cannot be removed, so we filter them out
|
|
85
88
|
currentNodes.filter((x) => x.nodeType !== x.DOCUMENT_FRAGMENT_NODE),
|
|
86
|
-
nextNodes
|
|
89
|
+
nextNodes,
|
|
87
90
|
diffable(document),
|
|
88
91
|
comment
|
|
89
92
|
)
|
|
90
93
|
}
|
|
91
94
|
|
|
92
|
-
function flattenRenderEvent(x: Node | RenderEvent): Array<Node> {
|
|
93
|
-
if (isRenderEvent(x)) {
|
|
94
|
-
const value = x.valueOf()
|
|
95
|
-
|
|
96
|
-
return Array.isArray(value) ? value : [value]
|
|
97
|
-
} else {
|
|
98
|
-
return [x]
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
95
|
function matchValue<A, B>(value: unknown, onText: (text: string) => A, onNodes: (nodes: Array<Node>) => B): A | B {
|
|
103
96
|
switch (typeof value) {
|
|
104
97
|
// primitives are handled as text content
|
|
@@ -117,16 +110,24 @@ function matchValue<A, B>(value: unknown, onText: (text: string) => A, onNodes:
|
|
|
117
110
|
if (value.length === 0) return onNodes([])
|
|
118
111
|
// or diffed, if these contains nodes or "wires"
|
|
119
112
|
else if (value.some((x) => typeof x === "object")) {
|
|
120
|
-
return onNodes(
|
|
121
|
-
value.flatMap((x) => (x === null ? [] : [isRenderEvent(x) ? x.valueOf() : x]))
|
|
122
|
-
)
|
|
113
|
+
return onNodes(value.flatMap(renderEventToArray))
|
|
123
114
|
} // in all other cases the content is stringified as is
|
|
124
115
|
else return onText(String(value))
|
|
125
116
|
} else {
|
|
126
|
-
return onNodes(
|
|
117
|
+
return onNodes(renderEventToArray(value))
|
|
127
118
|
}
|
|
128
119
|
}
|
|
129
120
|
case "function":
|
|
130
121
|
return onNodes([])
|
|
131
122
|
}
|
|
132
123
|
}
|
|
124
|
+
|
|
125
|
+
function renderEventToArray(x: unknown): Array<Node> {
|
|
126
|
+
if (x === null || x === undefined) return []
|
|
127
|
+
if (isRenderEvent(x)) {
|
|
128
|
+
const value = x.valueOf()
|
|
129
|
+
return Array.isArray(value) ? value : [value]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return [x as Node]
|
|
133
|
+
}
|
package/src/internal/hydrate.ts
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import * as Fx from "@typed/fx/Fx"
|
|
2
|
-
import * as Subject from "@typed/fx/Subject"
|
|
3
|
-
import type { Rendered } from "@typed/wire"
|
|
4
2
|
import type { Cause } from "effect"
|
|
5
|
-
import
|
|
6
|
-
import * as ElementRef from "../ElementRef.js"
|
|
3
|
+
import * as Effect from "effect/Effect"
|
|
7
4
|
import type { Placeholder } from "../Placeholder.js"
|
|
8
5
|
import type { Renderable } from "../Renderable.js"
|
|
9
6
|
import type { RenderContext } from "../RenderContext.js"
|
|
7
|
+
import type { RenderEvent } from "../RenderEvent.js"
|
|
10
8
|
import { DomRenderEvent } from "../RenderEvent.js"
|
|
11
9
|
import type { RenderTemplate } from "../RenderTemplate.js"
|
|
12
|
-
import { TemplateInstance } from "../TemplateInstance.js"
|
|
13
10
|
import { indexRefCounter } from "./indexRefCounter.js"
|
|
14
11
|
|
|
15
12
|
import { unsafeGet } from "@typed/context"
|
|
16
13
|
|
|
14
|
+
import { Scope } from "effect/Scope"
|
|
17
15
|
import type { Template } from "../Template.js"
|
|
18
16
|
import { CouldNotFindCommentError, CouldNotFindRootElement } from "./errors.js"
|
|
17
|
+
import { type EventSource, makeEventSource } from "./EventSource.js"
|
|
19
18
|
import { HydrateContext } from "./HydrateContext.js"
|
|
20
19
|
import { buildParts, getBrowserEntry, renderTemplate, renderValues } from "./render.js"
|
|
21
20
|
import {
|
|
@@ -33,61 +32,69 @@ import {
|
|
|
33
32
|
* Here for "standard" browser rendering, a TemplateInstance is effectively a live
|
|
34
33
|
* view into the contents rendered by the Template.
|
|
35
34
|
*/
|
|
36
|
-
export const hydrateTemplate: (document: Document, ctx: RenderContext) => RenderTemplate =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
providedRef?: ElementRef.ElementRef<T>
|
|
42
|
-
) => {
|
|
43
|
-
return Effect.gen(function*(_) {
|
|
44
|
-
const context = yield* _(Effect.context<never>())
|
|
45
|
-
const hydrateCtx = unsafeGet(context, HydrateContext)
|
|
46
|
-
|
|
47
|
-
// If we're not longer hydrating, just render normally
|
|
48
|
-
if (!hydrateCtx.hydrate) {
|
|
49
|
-
return yield* _(renderTemplate(document, renderContext)(templateStrings, values, providedRef))
|
|
50
|
-
}
|
|
35
|
+
export const hydrateTemplate: (document: Document, ctx: RenderContext) => RenderTemplate = (
|
|
36
|
+
document,
|
|
37
|
+
renderContext
|
|
38
|
+
) => {
|
|
39
|
+
const render_ = renderTemplate(document, renderContext)
|
|
51
40
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
41
|
+
return <Values extends ReadonlyArray<Renderable<any, any>>>(
|
|
42
|
+
templateStrings: TemplateStringsArray,
|
|
43
|
+
values: Values
|
|
44
|
+
): Fx.Fx<
|
|
45
|
+
Scope | Placeholder.Context<Values[number]>,
|
|
46
|
+
Placeholder.Error<Values[number]>,
|
|
47
|
+
RenderEvent
|
|
48
|
+
> => {
|
|
49
|
+
return Fx.make((sink) =>
|
|
50
|
+
Effect.gen(function*(_) {
|
|
51
|
+
const eventSource = makeEventSource()
|
|
52
|
+
const context = yield* _(Effect.context<Scope>())
|
|
53
|
+
const hydrateCtx = unsafeGet(context, HydrateContext)
|
|
54
|
+
const scope = unsafeGet(context, Scope)
|
|
55
|
+
|
|
56
|
+
// If we're not longer hydrating, just render normally
|
|
57
|
+
if (hydrateCtx.hydrate === false) {
|
|
58
|
+
return render_(templateStrings, values)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { parts, template, where, wire } = getHydrateEntry({
|
|
62
|
+
...hydrateCtx,
|
|
63
|
+
document,
|
|
64
|
+
renderContext,
|
|
65
|
+
eventSource,
|
|
66
|
+
strings: templateStrings,
|
|
67
|
+
onCause: sink.onFailure
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// If there are parts we need to render them before constructing our Wire
|
|
71
|
+
if (parts.length > 0) {
|
|
72
|
+
const refCounter = yield* _(indexRefCounter(parts.length))
|
|
73
|
+
|
|
74
|
+
// Do the work
|
|
75
|
+
yield* _(
|
|
76
|
+
renderValues(values, parts, refCounter, context, (index: number): HydrateContext => ({
|
|
77
|
+
where,
|
|
78
|
+
rootIndex: index,
|
|
79
|
+
parentTemplate: template,
|
|
80
|
+
hydrate: true
|
|
81
|
+
}))
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
// Wait for initial work to be completed
|
|
85
|
+
yield* _(refCounter.wait)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
hydrateCtx.hydrate = false
|
|
89
|
+
|
|
90
|
+
yield* _(eventSource.setup(wire, scope))
|
|
91
|
+
|
|
92
|
+
yield* _(sink.onSuccess(DomRenderEvent(wire)))
|
|
93
|
+
yield* _(Effect.never)
|
|
63
94
|
})
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// If there are parts we need to render them before constructing our Wire
|
|
67
|
-
if (parts.length > 0) {
|
|
68
|
-
const refCounter = yield* _(indexRefCounter(parts.length))
|
|
69
|
-
|
|
70
|
-
// Do the work
|
|
71
|
-
yield* _(renderValues(values, parts, refCounter, errors.onFailure, (index: number): HydrateContext => ({
|
|
72
|
-
where,
|
|
73
|
-
rootIndex: index,
|
|
74
|
-
parentTemplate: template,
|
|
75
|
-
hydrate: true
|
|
76
|
-
})))
|
|
77
|
-
|
|
78
|
-
// Wait for initial work to be completed
|
|
79
|
-
yield* _(refCounter.wait)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
hydrateCtx.hydrate = false
|
|
83
|
-
|
|
84
|
-
// Set the element when it is ready
|
|
85
|
-
yield* _(ElementRef.set(elementRef, wire as T))
|
|
86
|
-
|
|
87
|
-
// Return the Template instance
|
|
88
|
-
return TemplateInstance(Fx.merge([events, errors]), elementRef)
|
|
89
|
-
})
|
|
95
|
+
)
|
|
90
96
|
}
|
|
97
|
+
}
|
|
91
98
|
|
|
92
99
|
export function findRootParentChildNodes(where: HTMLElement): ParentChildNodes {
|
|
93
100
|
const childNodes = findRootChildNodes(where)
|
|
@@ -205,7 +212,7 @@ export function findPartComment(childNodes: ArrayLike<Node>, partIndex: number)
|
|
|
205
212
|
export function getHydrateEntry({
|
|
206
213
|
childIndex,
|
|
207
214
|
document,
|
|
208
|
-
|
|
215
|
+
eventSource,
|
|
209
216
|
onCause,
|
|
210
217
|
parentTemplate,
|
|
211
218
|
renderContext,
|
|
@@ -219,7 +226,7 @@ export function getHydrateEntry({
|
|
|
219
226
|
rootIndex: number
|
|
220
227
|
parentTemplate: Template | null
|
|
221
228
|
strings: TemplateStringsArray
|
|
222
|
-
|
|
229
|
+
eventSource: EventSource
|
|
223
230
|
onCause: (cause: Cause.Cause<any>) => Effect.Effect<never, never, void>
|
|
224
231
|
childIndex?: number
|
|
225
232
|
}) {
|
|
@@ -229,7 +236,7 @@ export function getHydrateEntry({
|
|
|
229
236
|
where = findTemplateResultPartChildNodes(where, parentTemplate, template, rootIndex, childIndex)
|
|
230
237
|
}
|
|
231
238
|
|
|
232
|
-
const
|
|
239
|
+
const parts = buildParts(document, renderContext, template, where, eventSource, onCause, true)
|
|
233
240
|
|
|
234
241
|
const wire = (() => {
|
|
235
242
|
if (!parentTemplate) {
|
|
@@ -256,7 +263,7 @@ export function getHydrateEntry({
|
|
|
256
263
|
return {
|
|
257
264
|
template,
|
|
258
265
|
wire,
|
|
259
|
-
|
|
266
|
+
parts,
|
|
260
267
|
where
|
|
261
268
|
} as const
|
|
262
269
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Deferred from "effect/Deferred"
|
|
2
2
|
import * as Effect from "effect/Effect"
|
|
3
|
+
import * as Option from "effect/Option"
|
|
3
4
|
|
|
4
5
|
export type IndexRefCounter = {
|
|
5
6
|
release: (index: number) => Effect.Effect<never, never, void>
|
|
@@ -15,13 +16,16 @@ export function indexRefCounter(expected: number): Effect.Effect<
|
|
|
15
16
|
IndexRefCounter
|
|
16
17
|
> {
|
|
17
18
|
return Effect.map(Deferred.make<never, void>(), (deferred) => {
|
|
19
|
+
const done = Deferred.succeed(deferred, undefined)
|
|
18
20
|
const indexes = new Set<number>(Array.from({ length: expected }, (_, i) => i))
|
|
19
21
|
|
|
20
22
|
function release(index: number) {
|
|
21
23
|
return Effect.suspend(() => {
|
|
22
24
|
if (indexes.delete(index) && indexes.size === 0) {
|
|
23
|
-
return
|
|
24
|
-
} else
|
|
25
|
+
return done
|
|
26
|
+
} else {
|
|
27
|
+
return Effect.unit
|
|
28
|
+
}
|
|
25
29
|
})
|
|
26
30
|
}
|
|
27
31
|
|
|
@@ -31,3 +35,60 @@ export function indexRefCounter(expected: number): Effect.Effect<
|
|
|
31
35
|
}
|
|
32
36
|
})
|
|
33
37
|
}
|
|
38
|
+
|
|
39
|
+
export type IndexRefCounter2 = {
|
|
40
|
+
release: (index: number) => Effect.Effect<never, never, void>
|
|
41
|
+
expect: (count: number) => Effect.Effect<never, never, boolean>
|
|
42
|
+
wait: Effect.Effect<never, never, void>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export function indexRefCounter2(): Effect.Effect<
|
|
49
|
+
never,
|
|
50
|
+
never,
|
|
51
|
+
IndexRefCounter2
|
|
52
|
+
> {
|
|
53
|
+
return Effect.map(Deferred.make<never, void>(), (deferred) => {
|
|
54
|
+
let expected: Option.Option<number> = Option.none<number>()
|
|
55
|
+
const done = Deferred.succeed(deferred, undefined)
|
|
56
|
+
const indexes = new Set<number>()
|
|
57
|
+
|
|
58
|
+
function isDone() {
|
|
59
|
+
if (Option.isSome(expected)) {
|
|
60
|
+
return indexes.size === expected.value
|
|
61
|
+
} else {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function release(index: number) {
|
|
67
|
+
return Effect.suspend(() => {
|
|
68
|
+
indexes.add(index)
|
|
69
|
+
if (isDone()) {
|
|
70
|
+
return done
|
|
71
|
+
} else {
|
|
72
|
+
return Effect.succeed(false)
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function expect(count: number) {
|
|
78
|
+
return Effect.suspend(() => {
|
|
79
|
+
expected = Option.some(count)
|
|
80
|
+
if (isDone()) {
|
|
81
|
+
return Effect.as(done, false)
|
|
82
|
+
} else {
|
|
83
|
+
return Effect.succeed(true)
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
release,
|
|
90
|
+
expect,
|
|
91
|
+
wait: Deferred.await(deferred)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}
|
package/src/internal/parser.ts
CHANGED
|
@@ -2,7 +2,6 @@ import * as Chunk from "effect/Chunk"
|
|
|
2
2
|
import { globalValue } from "effect/GlobalValue"
|
|
3
3
|
import * as Option from "effect/Option"
|
|
4
4
|
import * as Template from "../Template.js"
|
|
5
|
-
import { SELF_CLOSING_TAGS, TEXT_ONLY_NODES_REGEX } from "../Token.js"
|
|
6
5
|
import type { TextChunk } from "./chunks.js"
|
|
7
6
|
import {
|
|
8
7
|
getPart,
|
|
@@ -16,6 +15,40 @@ import {
|
|
|
16
15
|
// TODO: Consider ways to surface useful errors and warnings.
|
|
17
16
|
// TODO: Profile for performance optimization
|
|
18
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @since 1.0.0
|
|
20
|
+
*/
|
|
21
|
+
export const TEXT_ONLY_NODES_REGEX = new Set([
|
|
22
|
+
"textarea",
|
|
23
|
+
"script",
|
|
24
|
+
"style",
|
|
25
|
+
"title",
|
|
26
|
+
"plaintext",
|
|
27
|
+
"xmp"
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @since 1.0.0
|
|
32
|
+
*/
|
|
33
|
+
export const SELF_CLOSING_TAGS = new Set([
|
|
34
|
+
"area",
|
|
35
|
+
"base",
|
|
36
|
+
"br",
|
|
37
|
+
"col",
|
|
38
|
+
"command",
|
|
39
|
+
"embed",
|
|
40
|
+
"hr",
|
|
41
|
+
"img",
|
|
42
|
+
"input",
|
|
43
|
+
"keygen",
|
|
44
|
+
"link",
|
|
45
|
+
"meta",
|
|
46
|
+
"param",
|
|
47
|
+
"source",
|
|
48
|
+
"track",
|
|
49
|
+
"wbr"
|
|
50
|
+
])
|
|
51
|
+
|
|
19
52
|
export interface Parser {
|
|
20
53
|
parse(templateStrings: ReadonlyArray<string>): Template.Template
|
|
21
54
|
}
|
|
@@ -25,18 +58,38 @@ export function parse(templateStrings: ReadonlyArray<string>): Template.Template
|
|
|
25
58
|
}
|
|
26
59
|
|
|
27
60
|
const SPACE_REGEX = /\s/
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
61
|
+
const PART_START = "{{__PART"
|
|
62
|
+
const PART_END = "__}}"
|
|
63
|
+
const chars = {
|
|
64
|
+
openBracket: "{",
|
|
65
|
+
closeBracket: "}",
|
|
66
|
+
underscore: "_",
|
|
67
|
+
equals: "=",
|
|
68
|
+
quote: `"`,
|
|
69
|
+
singleQuote: "'",
|
|
70
|
+
slash: "/",
|
|
71
|
+
greaterThan: ">",
|
|
72
|
+
lessThan: "<",
|
|
73
|
+
hypen: "-"
|
|
74
|
+
} as const
|
|
75
|
+
|
|
76
|
+
const isPartToken: TextPredicate = (input, pos) =>
|
|
77
|
+
input[pos] === chars.openBracket && input.slice(pos, pos + 8) === PART_START
|
|
78
|
+
const isPartEndToken: TextPredicate = (input, pos) =>
|
|
79
|
+
input[pos] === chars.underscore && input.slice(pos, pos + 4) === PART_END
|
|
80
|
+
const isElementOpenToken: TextPredicate = (input, pos) =>
|
|
81
|
+
input[pos] === chars.lessThan && input[pos + 1] !== chars.slash
|
|
82
|
+
const isElementCloseToken: TextPredicate = (input, pos) =>
|
|
83
|
+
input[pos] === chars.lessThan && input[pos + 1] === chars.slash
|
|
84
|
+
const isEqualsToken: TextPredicate = (input, pos) => input[pos] === chars.equals
|
|
85
|
+
const isQuoteToken: TextPredicate = (input, pos) => input[pos] === chars.quote
|
|
86
|
+
const isSingleQuoteToken: TextPredicate = (input, pos) => input[pos] === chars.singleQuote
|
|
35
87
|
const isWhitespaceToken: TextPredicate = (input, pos) => SPACE_REGEX.test(input[pos])
|
|
36
|
-
const isOpenTagEndToken: TextPredicate = (input, pos) => input[pos] ===
|
|
37
|
-
const isSelfClosingTagEndToken: TextPredicate = (input, pos) =>
|
|
88
|
+
const isOpenTagEndToken: TextPredicate = (input, pos) => input[pos] === chars.greaterThan
|
|
89
|
+
const isSelfClosingTagEndToken: TextPredicate = (input, pos) =>
|
|
90
|
+
input[pos] === chars.slash && input[pos + 1] === chars.greaterThan
|
|
38
91
|
const isCommentEndToken: TextPredicate = (input, pos) =>
|
|
39
|
-
input[pos] ===
|
|
92
|
+
input[pos] === chars.hypen && input[pos + 1] === chars.hypen && input[pos + 2] === chars.greaterThan
|
|
40
93
|
|
|
41
94
|
type Context = "unknown" | "element"
|
|
42
95
|
|
|
@@ -154,6 +207,7 @@ class ParserImpl implements Parser {
|
|
|
154
207
|
|
|
155
208
|
while (this.pos < this.length) {
|
|
156
209
|
const node = this.parseNodeFromContext(this.context)
|
|
210
|
+
|
|
157
211
|
if (node === undefined) {
|
|
158
212
|
return nodes
|
|
159
213
|
} else {
|
|
@@ -187,9 +241,16 @@ class ParserImpl implements Parser {
|
|
|
187
241
|
const nextChar = this.nextChar()
|
|
188
242
|
|
|
189
243
|
if (nextChar === "!") { // Comment
|
|
190
|
-
this.consumeAmount(
|
|
244
|
+
this.consumeAmount(1)
|
|
245
|
+
|
|
246
|
+
const nextChar = this.nextChar()
|
|
191
247
|
|
|
192
|
-
|
|
248
|
+
if (nextChar == "-") {
|
|
249
|
+
this.consumeAmount(2)
|
|
250
|
+
return [this.parseComment()]
|
|
251
|
+
} else {
|
|
252
|
+
return [this.parseDocType()]
|
|
253
|
+
}
|
|
193
254
|
} else if (nextChar === "/") { // Self-closing tag
|
|
194
255
|
return this.selfClosingTagEnd()
|
|
195
256
|
} else { // Elements
|
|
@@ -263,6 +324,7 @@ class ParserImpl implements Parser {
|
|
|
263
324
|
|
|
264
325
|
private parseTextOnlyElement(tagName: string): Template.TextOnlyElement {
|
|
265
326
|
const attributes = this.parseAttributes()
|
|
327
|
+
|
|
266
328
|
this.path.push()
|
|
267
329
|
const children = this.parseTextChildren()
|
|
268
330
|
this.path.pop()
|
|
@@ -289,6 +351,14 @@ class ParserImpl implements Parser {
|
|
|
289
351
|
return this.addPart(new Template.SparseCommentNode(textAndParts))
|
|
290
352
|
}
|
|
291
353
|
|
|
354
|
+
private parseDocType(): Template.DocType {
|
|
355
|
+
this.parseTextUntil((char) => char === chars.greaterThan)
|
|
356
|
+
this.consumeAmount(1)
|
|
357
|
+
this.skipWhitespace()
|
|
358
|
+
|
|
359
|
+
return new Template.DocType("html")
|
|
360
|
+
}
|
|
361
|
+
|
|
292
362
|
private parseTagName() {
|
|
293
363
|
return this.parseTextUntilMany(tagNameMatches)
|
|
294
364
|
}
|
|
@@ -304,6 +374,7 @@ class ParserImpl implements Parser {
|
|
|
304
374
|
case null:
|
|
305
375
|
return Skip
|
|
306
376
|
case "whitespace":
|
|
377
|
+
this.skipWhitespace()
|
|
307
378
|
return Continue([new Template.BooleanNode(name)])
|
|
308
379
|
case "equals": {
|
|
309
380
|
this.consumeAmount(1)
|
|
@@ -366,11 +437,13 @@ class ParserImpl implements Parser {
|
|
|
366
437
|
case ".": {
|
|
367
438
|
const property = name.slice(1)
|
|
368
439
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
440
|
+
if (property === "data") {
|
|
441
|
+
return this.addPart(new Template.DataPartNode(unsafeParsePartIndex(text)))
|
|
442
|
+
} else if (property === "props" || property === "properties") {
|
|
443
|
+
return this.addPart(new Template.PropertiesPartNode(unsafeParsePartIndex(text)))
|
|
444
|
+
} else {
|
|
445
|
+
return this.addPart(new Template.PropertyPartNode(property, unsafeParsePartIndex(text)))
|
|
446
|
+
}
|
|
374
447
|
}
|
|
375
448
|
case "@":
|
|
376
449
|
return this.addPart(new Template.EventPartNode(name.slice(1), unsafeParsePartIndex(text)))
|
|
@@ -617,7 +690,7 @@ function parseTextAndParts<T>(s: string, f: (index: number) => T): Array<Templat
|
|
|
617
690
|
return out
|
|
618
691
|
}
|
|
619
692
|
|
|
620
|
-
export const parser: Parser = globalValue(Symbol.for("
|
|
693
|
+
export const parser: Parser = globalValue(Symbol.for("@typed/template/Parser2"), () => new ParserImpl())
|
|
621
694
|
|
|
622
695
|
const digestSize = 2
|
|
623
696
|
const multiplier = 33
|