@typed/template 0.1.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/LICENSE +21 -0
- package/README.md +5 -0
- package/dist/cjs/Directive.js +76 -0
- package/dist/cjs/Directive.js.map +1 -0
- package/dist/cjs/ElementRef.js +83 -0
- package/dist/cjs/ElementRef.js.map +1 -0
- package/dist/cjs/ElementSource.js +244 -0
- package/dist/cjs/ElementSource.js.map +1 -0
- package/dist/cjs/Entry.js +6 -0
- package/dist/cjs/Entry.js.map +1 -0
- package/dist/cjs/EventHandler.js +65 -0
- package/dist/cjs/EventHandler.js.map +1 -0
- package/dist/cjs/Html.js +169 -0
- package/dist/cjs/Html.js.map +1 -0
- package/dist/cjs/HtmlChunk.js +257 -0
- package/dist/cjs/HtmlChunk.js.map +1 -0
- package/dist/cjs/Hydrate.js +49 -0
- package/dist/cjs/Hydrate.js.map +1 -0
- package/dist/cjs/Many.js +45 -0
- package/dist/cjs/Many.js.map +1 -0
- package/dist/cjs/Meta.js +37 -0
- package/dist/cjs/Meta.js.map +1 -0
- package/dist/cjs/Parser.js +331 -0
- package/dist/cjs/Parser.js.map +1 -0
- package/dist/cjs/Part.js +6 -0
- package/dist/cjs/Part.js.map +1 -0
- package/dist/cjs/Placeholder.js +38 -0
- package/dist/cjs/Placeholder.js.map +1 -0
- package/dist/cjs/Platform.js +64 -0
- package/dist/cjs/Platform.js.map +1 -0
- package/dist/cjs/Render.js +39 -0
- package/dist/cjs/Render.js.map +1 -0
- package/dist/cjs/RenderContext.js +130 -0
- package/dist/cjs/RenderContext.js.map +1 -0
- package/dist/cjs/RenderEvent.js +44 -0
- package/dist/cjs/RenderEvent.js.map +1 -0
- package/dist/cjs/RenderTemplate.js +41 -0
- package/dist/cjs/RenderTemplate.js.map +1 -0
- package/dist/cjs/Renderable.js +6 -0
- package/dist/cjs/Renderable.js.map +1 -0
- package/dist/cjs/Template.js +266 -0
- package/dist/cjs/Template.js.map +1 -0
- package/dist/cjs/TemplateInstance.js +51 -0
- package/dist/cjs/TemplateInstance.js.map +1 -0
- package/dist/cjs/Test.js +90 -0
- package/dist/cjs/Test.js.map +1 -0
- package/dist/cjs/Token.js +270 -0
- package/dist/cjs/Token.js.map +1 -0
- package/dist/cjs/Tokenizer.js +18 -0
- package/dist/cjs/Tokenizer.js.map +1 -0
- package/dist/cjs/Vitest.js +44 -0
- package/dist/cjs/Vitest.js.map +1 -0
- package/dist/cjs/index.js +147 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/internal/HydrateContext.js +13 -0
- package/dist/cjs/internal/HydrateContext.js.map +1 -0
- package/dist/cjs/internal/browser.js +109 -0
- package/dist/cjs/internal/browser.js.map +1 -0
- package/dist/cjs/internal/chunks.js +54 -0
- package/dist/cjs/internal/chunks.js.map +1 -0
- package/dist/cjs/internal/errors.js +23 -0
- package/dist/cjs/internal/errors.js.map +1 -0
- package/dist/cjs/internal/hydrate.js +197 -0
- package/dist/cjs/internal/hydrate.js.map +1 -0
- package/dist/cjs/internal/indexRefCounter.js +32 -0
- package/dist/cjs/internal/indexRefCounter.js.map +1 -0
- package/dist/cjs/internal/module-augmentation.js +6 -0
- package/dist/cjs/internal/module-augmentation.js.map +1 -0
- package/dist/cjs/internal/parser.js +492 -0
- package/dist/cjs/internal/parser.js.map +1 -0
- package/dist/cjs/internal/parts.js +350 -0
- package/dist/cjs/internal/parts.js.map +1 -0
- package/dist/cjs/internal/readAttribute.js +34 -0
- package/dist/cjs/internal/readAttribute.js.map +1 -0
- package/dist/cjs/internal/render.js +332 -0
- package/dist/cjs/internal/render.js.map +1 -0
- package/dist/cjs/internal/server.js +219 -0
- package/dist/cjs/internal/server.js.map +1 -0
- package/dist/cjs/internal/tokenizer.js +264 -0
- package/dist/cjs/internal/tokenizer.js.map +1 -0
- package/dist/cjs/internal/utils.js +68 -0
- package/dist/cjs/internal/utils.js.map +1 -0
- package/dist/dts/Directive.d.ts +70 -0
- package/dist/dts/Directive.d.ts.map +1 -0
- package/dist/dts/ElementRef.d.ts +40 -0
- package/dist/dts/ElementRef.d.ts.map +1 -0
- package/dist/dts/ElementSource.d.ts +72 -0
- package/dist/dts/ElementSource.d.ts.map +1 -0
- package/dist/dts/Entry.d.ts +26 -0
- package/dist/dts/Entry.d.ts.map +1 -0
- package/dist/dts/EventHandler.d.ts +61 -0
- package/dist/dts/EventHandler.d.ts.map +1 -0
- package/dist/dts/Html.d.ts +17 -0
- package/dist/dts/Html.d.ts.map +1 -0
- package/dist/dts/HtmlChunk.d.ts +56 -0
- package/dist/dts/HtmlChunk.d.ts.map +1 -0
- package/dist/dts/Hydrate.d.ts +20 -0
- package/dist/dts/Hydrate.d.ts.map +1 -0
- package/dist/dts/Many.d.ts +32 -0
- package/dist/dts/Many.d.ts.map +1 -0
- package/dist/dts/Meta.d.ts +24 -0
- package/dist/dts/Meta.d.ts.map +1 -0
- package/dist/dts/Parser.d.ts +16 -0
- package/dist/dts/Parser.d.ts.map +1 -0
- package/dist/dts/Part.d.ts +147 -0
- package/dist/dts/Part.d.ts.map +1 -0
- package/dist/dts/Placeholder.d.ts +51 -0
- package/dist/dts/Placeholder.d.ts.map +1 -0
- package/dist/dts/Platform.d.ts +23 -0
- package/dist/dts/Platform.d.ts.map +1 -0
- package/dist/dts/Render.d.ts +23 -0
- package/dist/dts/Render.d.ts.map +1 -0
- package/dist/dts/RenderContext.d.ts +88 -0
- package/dist/dts/RenderContext.d.ts.map +1 -0
- package/dist/dts/RenderEvent.d.ts +37 -0
- package/dist/dts/RenderEvent.d.ts.map +1 -0
- package/dist/dts/RenderTemplate.d.ts +38 -0
- package/dist/dts/RenderTemplate.d.ts.map +1 -0
- package/dist/dts/Renderable.d.ts +28 -0
- package/dist/dts/Renderable.d.ts.map +1 -0
- package/dist/dts/Template.d.ts +218 -0
- package/dist/dts/Template.d.ts.map +1 -0
- package/dist/dts/TemplateInstance.d.ts +32 -0
- package/dist/dts/TemplateInstance.d.ts.map +1 -0
- package/dist/dts/Test.d.ts +58 -0
- package/dist/dts/Test.d.ts.map +1 -0
- package/dist/dts/Token.d.ts +202 -0
- package/dist/dts/Token.d.ts.map +1 -0
- package/dist/dts/Tokenizer.d.ts +6 -0
- package/dist/dts/Tokenizer.d.ts.map +1 -0
- package/dist/dts/Vitest.d.ts +28 -0
- package/dist/dts/Vitest.d.ts.map +1 -0
- package/dist/dts/index.d.ts +65 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/internal/HydrateContext.d.ts +2 -0
- package/dist/dts/internal/HydrateContext.d.ts.map +1 -0
- package/dist/dts/internal/browser.d.ts +8 -0
- package/dist/dts/internal/browser.d.ts.map +1 -0
- package/dist/dts/internal/chunks.d.ts +22 -0
- package/dist/dts/internal/chunks.d.ts.map +1 -0
- package/dist/dts/internal/errors.d.ts +9 -0
- package/dist/dts/internal/errors.d.ts.map +1 -0
- package/dist/dts/internal/hydrate.d.ts +37 -0
- package/dist/dts/internal/hydrate.d.ts.map +1 -0
- package/dist/dts/internal/indexRefCounter.d.ts +6 -0
- package/dist/dts/internal/indexRefCounter.d.ts.map +1 -0
- package/dist/dts/internal/module-augmentation.d.ts +36 -0
- package/dist/dts/internal/module-augmentation.d.ts.map +1 -0
- package/dist/dts/internal/parser.d.ts +12 -0
- package/dist/dts/internal/parser.d.ts.map +1 -0
- package/dist/dts/internal/parts.d.ts +304 -0
- package/dist/dts/internal/parts.d.ts.map +1 -0
- package/dist/dts/internal/readAttribute.d.ts +9 -0
- package/dist/dts/internal/readAttribute.d.ts.map +1 -0
- package/dist/dts/internal/render.d.ts +30 -0
- package/dist/dts/internal/render.d.ts.map +1 -0
- package/dist/dts/internal/server.d.ts +31 -0
- package/dist/dts/internal/server.d.ts.map +1 -0
- package/dist/dts/internal/tokenizer.d.ts +3 -0
- package/dist/dts/internal/tokenizer.d.ts.map +1 -0
- package/dist/dts/internal/utils.d.ts +15 -0
- package/dist/dts/internal/utils.d.ts.map +1 -0
- package/dist/esm/Directive.js +64 -0
- package/dist/esm/Directive.js.map +1 -0
- package/dist/esm/ElementRef.js +72 -0
- package/dist/esm/ElementRef.js.map +1 -0
- package/dist/esm/ElementSource.js +237 -0
- package/dist/esm/ElementSource.js.map +1 -0
- package/dist/esm/Entry.js +2 -0
- package/dist/esm/Entry.js.map +1 -0
- package/dist/esm/EventHandler.js +52 -0
- package/dist/esm/EventHandler.js.map +1 -0
- package/dist/esm/Html.js +167 -0
- package/dist/esm/Html.js.map +1 -0
- package/dist/esm/HtmlChunk.js +274 -0
- package/dist/esm/HtmlChunk.js.map +1 -0
- package/dist/esm/Hydrate.js +37 -0
- package/dist/esm/Hydrate.js.map +1 -0
- package/dist/esm/Many.js +33 -0
- package/dist/esm/Many.js.map +1 -0
- package/dist/esm/Meta.js +29 -0
- package/dist/esm/Meta.js.map +1 -0
- package/dist/esm/Parser.js +342 -0
- package/dist/esm/Parser.js.map +1 -0
- package/dist/esm/Part.js +5 -0
- package/dist/esm/Part.js.map +1 -0
- package/dist/esm/Placeholder.js +30 -0
- package/dist/esm/Placeholder.js.map +1 -0
- package/dist/esm/Platform.js +41 -0
- package/dist/esm/Platform.js.map +1 -0
- package/dist/esm/Render.js +27 -0
- package/dist/esm/Render.js.map +1 -0
- package/dist/esm/RenderContext.js +113 -0
- package/dist/esm/RenderContext.js.map +1 -0
- package/dist/esm/RenderEvent.js +36 -0
- package/dist/esm/RenderEvent.js.map +1 -0
- package/dist/esm/RenderTemplate.js +26 -0
- package/dist/esm/RenderTemplate.js.map +1 -0
- package/dist/esm/Renderable.js +2 -0
- package/dist/esm/Renderable.js.map +1 -0
- package/dist/esm/Template.js +239 -0
- package/dist/esm/Template.js.map +1 -0
- package/dist/esm/TemplateInstance.js +43 -0
- package/dist/esm/TemplateInstance.js.map +1 -0
- package/dist/esm/Test.js +68 -0
- package/dist/esm/Test.js.map +1 -0
- package/dist/esm/Token.js +264 -0
- package/dist/esm/Token.js.map +1 -0
- package/dist/esm/Tokenizer.js +9 -0
- package/dist/esm/Tokenizer.js.map +1 -0
- package/dist/esm/Vitest.js +29 -0
- package/dist/esm/Vitest.js.map +1 -0
- package/dist/esm/index.js +65 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/HydrateContext.js +7 -0
- package/dist/esm/internal/HydrateContext.js.map +1 -0
- package/dist/esm/internal/browser.js +102 -0
- package/dist/esm/internal/browser.js.map +1 -0
- package/dist/esm/internal/chunks.js +47 -0
- package/dist/esm/internal/chunks.js.map +1 -0
- package/dist/esm/internal/errors.js +15 -0
- package/dist/esm/internal/errors.js.map +1 -0
- package/dist/esm/internal/hydrate.js +165 -0
- package/dist/esm/internal/hydrate.js.map +1 -0
- package/dist/esm/internal/indexRefCounter.js +24 -0
- package/dist/esm/internal/indexRefCounter.js.map +1 -0
- package/dist/esm/internal/module-augmentation.js +2 -0
- package/dist/esm/internal/module-augmentation.js.map +1 -0
- package/dist/esm/internal/parser.js +493 -0
- package/dist/esm/internal/parser.js.map +1 -0
- package/dist/esm/internal/parts.js +291 -0
- package/dist/esm/internal/parts.js.map +1 -0
- package/dist/esm/internal/readAttribute.js +24 -0
- package/dist/esm/internal/readAttribute.js.map +1 -0
- package/dist/esm/internal/render.js +329 -0
- package/dist/esm/internal/render.js.map +1 -0
- package/dist/esm/internal/server.js +174 -0
- package/dist/esm/internal/server.js.map +1 -0
- package/dist/esm/internal/tokenizer.js +296 -0
- package/dist/esm/internal/tokenizer.js.map +1 -0
- package/dist/esm/internal/utils.js +52 -0
- package/dist/esm/internal/utils.js.map +1 -0
- package/dist/esm/package.json +4 -0
- package/package.json +242 -0
- package/src/Directive.ts +114 -0
- package/src/ElementRef.ts +123 -0
- package/src/ElementSource.ts +417 -0
- package/src/Entry.ts +28 -0
- package/src/EventHandler.ts +104 -0
- package/src/Html.ts +258 -0
- package/src/HtmlChunk.ts +346 -0
- package/src/Hydrate.ts +53 -0
- package/src/Many.ts +128 -0
- package/src/Meta.ts +32 -0
- package/src/Parser.ts +457 -0
- package/src/Part.ts +186 -0
- package/src/Placeholder.ts +70 -0
- package/src/Platform.ts +71 -0
- package/src/Render.ts +45 -0
- package/src/RenderContext.ts +221 -0
- package/src/RenderEvent.ts +67 -0
- package/src/RenderTemplate.ts +88 -0
- package/src/Renderable.ts +34 -0
- package/src/Template.ts +284 -0
- package/src/TemplateInstance.ts +83 -0
- package/src/Test.ts +151 -0
- package/src/Token.ts +269 -0
- package/src/Tokenizer.ts +10 -0
- package/src/Vitest.ts +61 -0
- package/src/index.ts +66 -0
- package/src/internal/HydrateContext.ts +23 -0
- package/src/internal/browser.ts +132 -0
- package/src/internal/chunks.ts +73 -0
- package/src/internal/errors.ts +11 -0
- package/src/internal/external.d.ts +11 -0
- package/src/internal/hydrate.ts +262 -0
- package/src/internal/indexRefCounter.ts +33 -0
- package/src/internal/module-augmentation.ts +48 -0
- package/src/internal/parser.ts +637 -0
- package/src/internal/parts.ts +527 -0
- package/src/internal/readAttribute.ts +28 -0
- package/src/internal/render.ts +529 -0
- package/src/internal/server.ts +293 -0
- package/src/internal/tokenizer.ts +338 -0
- package/src/internal/utils.ts +73 -0
package/src/Part.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Cause } from "effect/Cause"
|
|
6
|
+
import type { Effect } from "effect/Effect"
|
|
7
|
+
import type { Scope } from "effect/Scope"
|
|
8
|
+
import type { ElementSource } from "./ElementSource"
|
|
9
|
+
import type { EventHandler } from "./EventHandler"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @since 1.0.0
|
|
13
|
+
*/
|
|
14
|
+
export type Part =
|
|
15
|
+
| AttributePart
|
|
16
|
+
| BooleanPart
|
|
17
|
+
| ClassNamePart
|
|
18
|
+
| CommentPart
|
|
19
|
+
| DataPart
|
|
20
|
+
| EventPart
|
|
21
|
+
| NodePart
|
|
22
|
+
| PropertyPart
|
|
23
|
+
| RefPart
|
|
24
|
+
| TextPart
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @since 1.0.0
|
|
28
|
+
*/
|
|
29
|
+
export interface AttributePart {
|
|
30
|
+
readonly _tag: "attribute"
|
|
31
|
+
readonly name: string
|
|
32
|
+
readonly value: string | null | undefined
|
|
33
|
+
readonly index: number
|
|
34
|
+
|
|
35
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
*/
|
|
41
|
+
export interface BooleanPart {
|
|
42
|
+
readonly _tag: "boolean"
|
|
43
|
+
readonly name: string
|
|
44
|
+
readonly value: boolean | null | undefined
|
|
45
|
+
readonly index: number
|
|
46
|
+
|
|
47
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @since 1.0.0
|
|
52
|
+
*/
|
|
53
|
+
export interface ClassNamePart {
|
|
54
|
+
readonly _tag: "className"
|
|
55
|
+
readonly value: ReadonlyArray<string> | null | undefined
|
|
56
|
+
readonly index: number
|
|
57
|
+
|
|
58
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @since 1.0.0
|
|
63
|
+
*/
|
|
64
|
+
export interface DataPart {
|
|
65
|
+
readonly _tag: "data"
|
|
66
|
+
readonly value: Readonly<Record<string, string | undefined>> | null | undefined
|
|
67
|
+
readonly index: number
|
|
68
|
+
|
|
69
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @since 1.0.0
|
|
74
|
+
*/
|
|
75
|
+
export interface EventPart {
|
|
76
|
+
readonly _tag: "event"
|
|
77
|
+
readonly name: string
|
|
78
|
+
readonly value: EventHandler<unknown, never> | null | undefined
|
|
79
|
+
readonly index: number
|
|
80
|
+
readonly onCause: (cause: Cause<unknown>) => Effect<never, never, unknown>
|
|
81
|
+
|
|
82
|
+
readonly update: <R = never>(value: EventHandler<R, never> | null | undefined) => Effect<R | Scope, never, void>
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @since 1.0.0
|
|
87
|
+
*/
|
|
88
|
+
export interface PropertyPart {
|
|
89
|
+
readonly _tag: "property"
|
|
90
|
+
readonly name: string
|
|
91
|
+
readonly value: unknown
|
|
92
|
+
readonly index: number
|
|
93
|
+
|
|
94
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @since 1.0.0
|
|
99
|
+
*/
|
|
100
|
+
export interface RefPart<T extends HTMLElement | SVGElement = HTMLElement | SVGElement> {
|
|
101
|
+
readonly _tag: "ref"
|
|
102
|
+
readonly value: ElementSource<T>
|
|
103
|
+
readonly index: number
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @since 1.0.0
|
|
108
|
+
*/
|
|
109
|
+
export interface CommentPart {
|
|
110
|
+
readonly _tag: "comment"
|
|
111
|
+
readonly value: string | null | undefined
|
|
112
|
+
readonly index: number
|
|
113
|
+
|
|
114
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @since 1.0.0
|
|
119
|
+
*/
|
|
120
|
+
export interface TextPart {
|
|
121
|
+
readonly _tag: "text"
|
|
122
|
+
readonly value: string | null | undefined
|
|
123
|
+
readonly index: number
|
|
124
|
+
|
|
125
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @since 1.0.0
|
|
130
|
+
*/
|
|
131
|
+
export interface NodePart {
|
|
132
|
+
readonly _tag: "node"
|
|
133
|
+
readonly value: unknown
|
|
134
|
+
readonly index: number
|
|
135
|
+
|
|
136
|
+
readonly update: (value: this["value"]) => Effect<Scope, never, void>
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @since 1.0.0
|
|
141
|
+
*/
|
|
142
|
+
export type SparsePart = SparseAttributePart | SparseClassNamePart | SparseCommentPart
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @since 1.0.0
|
|
146
|
+
*/
|
|
147
|
+
export interface SparseAttributePart {
|
|
148
|
+
readonly _tag: "sparse/attribute"
|
|
149
|
+
readonly name: string
|
|
150
|
+
readonly parts: ReadonlyArray<AttributePart | StaticText>
|
|
151
|
+
|
|
152
|
+
readonly update: (value: ReadonlyArray<string>) => Effect<Scope, never, void>
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @since 1.0.0
|
|
157
|
+
*/
|
|
158
|
+
export interface SparseClassNamePart {
|
|
159
|
+
readonly _tag: "sparse/className"
|
|
160
|
+
readonly parts: ReadonlyArray<ClassNamePart | StaticText>
|
|
161
|
+
|
|
162
|
+
readonly update: (value: ReadonlyArray<string>) => Effect<Scope, never, void>
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @since 1.0.0
|
|
167
|
+
*/
|
|
168
|
+
export interface SparseCommentPart {
|
|
169
|
+
readonly _tag: "sparse/comment"
|
|
170
|
+
readonly parts: ReadonlyArray<CommentPart | StaticText>
|
|
171
|
+
|
|
172
|
+
readonly update: (value: ReadonlyArray<string>) => Effect<Scope, never, void>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @since 1.0.0
|
|
177
|
+
*/
|
|
178
|
+
export interface StaticText {
|
|
179
|
+
readonly _tag: "static/text"
|
|
180
|
+
readonly value: string
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @since 1.0.0
|
|
185
|
+
*/
|
|
186
|
+
export type Parts = ReadonlyArray<Part | SparsePart>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import "./internal/module-augmentation"
|
|
6
|
+
import type { Fx } from "@typed/fx/Fx"
|
|
7
|
+
import { isFx } from "@typed/fx/Fx"
|
|
8
|
+
import * as RefSubject from "@typed/fx/RefSubject"
|
|
9
|
+
import type { Scope } from "effect"
|
|
10
|
+
import { Effect } from "effect"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @since 1.0.0
|
|
14
|
+
*/
|
|
15
|
+
export const PlaceholderTypeId = Symbol.for("./Placholder")
|
|
16
|
+
/**
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
*/
|
|
19
|
+
export type PlaceholderTypeId = typeof PlaceholderTypeId
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
export interface Placeholder<out R = never, out E = never, out A = unknown> {
|
|
25
|
+
readonly [PlaceholderTypeId]: {
|
|
26
|
+
readonly _R: (_: never) => R
|
|
27
|
+
readonly _E: (_: never) => E
|
|
28
|
+
readonly _A: (_: never) => A
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
*/
|
|
35
|
+
export namespace Placeholder {
|
|
36
|
+
/**
|
|
37
|
+
* @since 1.0.0
|
|
38
|
+
*/
|
|
39
|
+
export type Any<A = any> =
|
|
40
|
+
| Placeholder<any, any, A>
|
|
41
|
+
| Placeholder<any, never, A>
|
|
42
|
+
| Placeholder<never, never, A>
|
|
43
|
+
| Placeholder<never, any, A>
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @since 1.0.0
|
|
47
|
+
*/
|
|
48
|
+
export type Context<T> = [T] extends [never] ? never : T extends Placeholder<infer R, infer _E, infer _A> ? R : never
|
|
49
|
+
/**
|
|
50
|
+
* @since 1.0.0
|
|
51
|
+
*/
|
|
52
|
+
export type Error<T> = [T] extends [never] ? never : T extends Placeholder<infer _R, infer E, infer _A> ? E : never
|
|
53
|
+
/**
|
|
54
|
+
* @since 1.0.0
|
|
55
|
+
*/
|
|
56
|
+
export type Success<T> = [T] extends [never] ? never : T extends Placeholder<infer _R, infer _E, infer A> ? A : never
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @since 1.0.0
|
|
60
|
+
*/
|
|
61
|
+
export function asRef<R = never, E = never, A = never>(
|
|
62
|
+
placeholder: Placeholder<R, E, A>
|
|
63
|
+
): Effect.Effect<R | Scope.Scope, never, RefSubject.RefSubject<never, E, A>> {
|
|
64
|
+
if (isFx<R, E, A>(placeholder) || Effect.isEffect(placeholder)) {
|
|
65
|
+
return RefSubject.make(placeholder as Fx<R, E, A>)
|
|
66
|
+
} else {
|
|
67
|
+
return RefSubject.of(placeholder as A)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/Platform.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as Headers from "@effect/platform/Http/Headers"
|
|
6
|
+
import type { ServerRequest } from "@effect/platform/Http/ServerRequest"
|
|
7
|
+
import * as HttpServer from "@effect/platform/HttpServer"
|
|
8
|
+
import type * as Fx from "@typed/fx/Fx"
|
|
9
|
+
import { toStream } from "@typed/fx/Stream"
|
|
10
|
+
import { Effect, Option, Stream } from "effect"
|
|
11
|
+
import { renderToHtml } from "./Html"
|
|
12
|
+
import type * as RenderContext from "./RenderContext"
|
|
13
|
+
import type { RenderEvent } from "./RenderEvent"
|
|
14
|
+
import type { RenderTemplate } from "./RenderTemplate"
|
|
15
|
+
|
|
16
|
+
const HTML_CONTENT_TYPE = "text/html"
|
|
17
|
+
const CAMEL_CASE_CONTENT_TYPE = { contentType: HTML_CONTENT_TYPE }
|
|
18
|
+
const HYPHENATED_CONTENT_TYPE = { "content-type": HTML_CONTENT_TYPE }
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @since 1.0.0
|
|
22
|
+
*/
|
|
23
|
+
export function htmlResponse<R, E>(
|
|
24
|
+
fx: Fx.Fx<R, E, RenderEvent>,
|
|
25
|
+
options?: HttpServer.response.Options
|
|
26
|
+
): Effect.Effect<RenderContext.RenderContext | Exclude<R, RenderTemplate>, E, HttpServer.response.ServerResponse> {
|
|
27
|
+
return Effect.contextWithEffect((ctx) =>
|
|
28
|
+
HttpServer.response.stream(
|
|
29
|
+
Stream.provideContext(Stream.encodeText(toStream(renderToHtml(fx))), ctx),
|
|
30
|
+
{
|
|
31
|
+
...CAMEL_CASE_CONTENT_TYPE,
|
|
32
|
+
...options,
|
|
33
|
+
headers: { ...HYPHENATED_CONTENT_TYPE, ...options?.headers }
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @since 1.0.0
|
|
41
|
+
*/
|
|
42
|
+
export function htmlResponseString(
|
|
43
|
+
html: string,
|
|
44
|
+
options?: HttpServer.response.Options
|
|
45
|
+
): HttpServer.response.ServerResponse {
|
|
46
|
+
return HttpServer.response.raw(
|
|
47
|
+
html,
|
|
48
|
+
{
|
|
49
|
+
...CAMEL_CASE_CONTENT_TYPE,
|
|
50
|
+
...options,
|
|
51
|
+
headers: { ...HYPHENATED_CONTENT_TYPE, ...options?.headers }
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @since 1.0.0
|
|
58
|
+
*/
|
|
59
|
+
export function getUrlFromServerRequest(request: ServerRequest): URL {
|
|
60
|
+
const { headers } = request
|
|
61
|
+
const host = Headers.get(headers, "x-forwarded-host").pipe(
|
|
62
|
+
Option.orElse(() => Headers.get(headers, "host")),
|
|
63
|
+
Option.getOrElse(() => "localhost")
|
|
64
|
+
)
|
|
65
|
+
const protocol = Headers.get(headers, "x-forwarded-proto").pipe(
|
|
66
|
+
Option.orElse(() => Headers.get(headers, "protocol")),
|
|
67
|
+
Option.getOrElse(() => "http")
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return new URL(request.url, `${protocol}://${host}`)
|
|
71
|
+
}
|
package/src/Render.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as Context from "@typed/context"
|
|
6
|
+
import { Document } from "@typed/dom/Document"
|
|
7
|
+
import { RootElement } from "@typed/dom/RootElement"
|
|
8
|
+
import * as Fx from "@typed/fx/Fx"
|
|
9
|
+
import { type Rendered } from "@typed/wire"
|
|
10
|
+
import * as Effect from "effect/Effect"
|
|
11
|
+
import { attachRoot, renderTemplate } from "./internal/render"
|
|
12
|
+
import { RenderContext } from "./RenderContext"
|
|
13
|
+
import { type RenderEvent } from "./RenderEvent"
|
|
14
|
+
import { RenderTemplate } from "./RenderTemplate"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
*/
|
|
19
|
+
export type ToRendered<T extends RenderEvent | null> = T extends null ? Rendered | null : Rendered
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
export function render<R, E, T extends RenderEvent | null>(
|
|
25
|
+
rendered: Fx.Fx<R, E, T>
|
|
26
|
+
): Fx.Fx<Exclude<R, RenderTemplate> | Document | RenderContext | RootElement, E, ToRendered<T>> {
|
|
27
|
+
return Fx.fromFxEffect(Effect.contextWith((context) => {
|
|
28
|
+
const [document, ctx, { rootElement }] = Context.getMany(context, Document, RenderContext, RootElement)
|
|
29
|
+
|
|
30
|
+
return Fx.provideService(
|
|
31
|
+
Fx.mapEffect(rendered, (what) => attachRoot(ctx.renderCache, rootElement, what)),
|
|
32
|
+
RenderTemplate,
|
|
33
|
+
renderTemplate(document, ctx)
|
|
34
|
+
)
|
|
35
|
+
}))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
*/
|
|
41
|
+
export function renderLayer<R, E, T extends RenderEvent | null>(
|
|
42
|
+
rendered: Fx.Fx<R, E, T>
|
|
43
|
+
) {
|
|
44
|
+
return Fx.drainLayer(Fx.switchMapCause(render(rendered), Effect.logError))
|
|
45
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The context in which templates are rendered within
|
|
3
|
+
* @since 1.0.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as Context from "@typed/context"
|
|
7
|
+
import { type DomServices, domServices, type DomServicesElementParams } from "@typed/dom/DomServices"
|
|
8
|
+
import { GlobalThis } from "@typed/dom/GlobalThis"
|
|
9
|
+
import { Window } from "@typed/dom/Window"
|
|
10
|
+
import type { Environment } from "@typed/environment"
|
|
11
|
+
import { CurrentEnvironment } from "@typed/environment"
|
|
12
|
+
import * as Idle from "@typed/fx/Idle"
|
|
13
|
+
import type { Rendered } from "@typed/wire"
|
|
14
|
+
import { Effect, Layer, Option } from "effect"
|
|
15
|
+
import * as Scope from "effect/Scope"
|
|
16
|
+
import type { Entry } from "./Entry"
|
|
17
|
+
import type { Part, SparsePart } from "./Part"
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The context in which templates are rendered within
|
|
21
|
+
* @since 1.0.0
|
|
22
|
+
*/
|
|
23
|
+
export interface RenderContext {
|
|
24
|
+
/**
|
|
25
|
+
* The current environment we are rendering within
|
|
26
|
+
*/
|
|
27
|
+
readonly environment: Environment
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Cache for root Node's being rendered into.
|
|
31
|
+
*/
|
|
32
|
+
readonly renderCache: WeakMap<object, Rendered | null>
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Cache for individual templates.
|
|
36
|
+
*/
|
|
37
|
+
readonly templateCache: WeakMap<TemplateStringsArray, Entry>
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Queue for work to be batched
|
|
41
|
+
*/
|
|
42
|
+
readonly queue: RenderQueue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The context in which templates are rendered within
|
|
47
|
+
* @since 1.0.0
|
|
48
|
+
*/
|
|
49
|
+
export const RenderContext: Context.Tagged<RenderContext, RenderContext> = Context.Tagged<RenderContext>(
|
|
50
|
+
"./RenderContext"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @since 1.0.0
|
|
55
|
+
*/
|
|
56
|
+
export interface RenderQueue {
|
|
57
|
+
readonly add: (part: Part | SparsePart, task: () => void) => Effect.Effect<Scope.Scope, never, void>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @since 1.0.0
|
|
62
|
+
*/
|
|
63
|
+
export type RenderContextOptions = IdleRequestOptions & {
|
|
64
|
+
readonly environment: Environment
|
|
65
|
+
readonly scope: Scope.Scope
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @since 1.0.0
|
|
70
|
+
*/
|
|
71
|
+
export function make({ ...options }: Omit<RenderContextOptions, "scope">, skipRenderScheduling?: boolean) {
|
|
72
|
+
return Effect.scopeWith((scope) => Effect.succeed(unsafeMake({ ...options, scope }, skipRenderScheduling)))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @since 1.0.0
|
|
77
|
+
*/
|
|
78
|
+
export function unsafeMake({
|
|
79
|
+
environment,
|
|
80
|
+
scope,
|
|
81
|
+
...options
|
|
82
|
+
}: RenderContextOptions, skipRenderScheduling?: boolean): RenderContext {
|
|
83
|
+
return {
|
|
84
|
+
environment,
|
|
85
|
+
renderCache: new WeakMap(),
|
|
86
|
+
templateCache: new WeakMap(),
|
|
87
|
+
queue: new RenderQueueImpl(scope, options, skipRenderScheduling ?? false)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @since 1.0.0
|
|
93
|
+
*/
|
|
94
|
+
export function getRenderCache<T>(renderCache: RenderContext["renderCache"], key: object): Option.Option<T> {
|
|
95
|
+
return renderCache.has(key) ? Option.some(renderCache.get(key) as T) : Option.none()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @since 1.0.0
|
|
100
|
+
*/
|
|
101
|
+
export function getTemplateCache(
|
|
102
|
+
templateCache: RenderContext["templateCache"],
|
|
103
|
+
key: TemplateStringsArray
|
|
104
|
+
): Option.Option<Entry> {
|
|
105
|
+
return Option.fromNullable(templateCache.get(key))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const buildWithCurrentEnvironment = (environment: Environment, skipRenderScheduling?: boolean) =>
|
|
109
|
+
Layer.mergeAll(
|
|
110
|
+
RenderContext.scoped(make({ environment }, skipRenderScheduling)),
|
|
111
|
+
CurrentEnvironment.layer(environment)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @since 1.0.0
|
|
116
|
+
*/
|
|
117
|
+
export const browser: (
|
|
118
|
+
window: Window & GlobalThis,
|
|
119
|
+
options?: DomServicesElementParams & { readonly skipRenderScheduling?: boolean }
|
|
120
|
+
) => Layer.Layer<never, never, RenderContext | CurrentEnvironment | DomServices> = (window, options) =>
|
|
121
|
+
Layer.provideMerge(
|
|
122
|
+
Layer.mergeAll(Window.layer(window), GlobalThis.layer(window)),
|
|
123
|
+
Layer.mergeAll(
|
|
124
|
+
buildWithCurrentEnvironment(
|
|
125
|
+
"browser",
|
|
126
|
+
options?.skipRenderScheduling
|
|
127
|
+
),
|
|
128
|
+
domServices(options)
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @since 1.0.0
|
|
134
|
+
*/
|
|
135
|
+
export const server: Layer.Layer<never, never, RenderContext | CurrentEnvironment> = buildWithCurrentEnvironment(
|
|
136
|
+
"server"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
const static_: Layer.Layer<never, never, RenderContext | CurrentEnvironment> = buildWithCurrentEnvironment("static")
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
/**
|
|
143
|
+
* @since 1.0.0
|
|
144
|
+
*/
|
|
145
|
+
static_ as static
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
class RenderQueueImpl implements RenderQueue {
|
|
149
|
+
queue = new Map<Part | SparsePart, () => void>()
|
|
150
|
+
scheduled = false
|
|
151
|
+
|
|
152
|
+
constructor(
|
|
153
|
+
readonly scope: Scope.Scope,
|
|
154
|
+
readonly options?: IdleRequestOptions,
|
|
155
|
+
readonly skipRenderScheduling: boolean = false
|
|
156
|
+
) {
|
|
157
|
+
this.add.bind(this)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
add(part: Part | SparsePart, task: () => void) {
|
|
161
|
+
if (this.skipRenderScheduling) return Effect.sync(task)
|
|
162
|
+
|
|
163
|
+
return Effect.suspend(() => {
|
|
164
|
+
this.queue.set(part, task)
|
|
165
|
+
|
|
166
|
+
return Effect.zipRight(
|
|
167
|
+
Effect.addFinalizer(() =>
|
|
168
|
+
Effect.sync(() => {
|
|
169
|
+
const currentTask = this.queue.get(part)
|
|
170
|
+
|
|
171
|
+
// If the current task is still the same we'll delete it from the queue
|
|
172
|
+
if (currentTask === task) {
|
|
173
|
+
this.queue.delete(part)
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
),
|
|
177
|
+
this.scheduleNextRun
|
|
178
|
+
)
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
scheduleNextRun = Effect.suspend(() => {
|
|
183
|
+
if (this.queue.size === 0 || this.scheduled) return Effect.unit
|
|
184
|
+
|
|
185
|
+
this.scheduled = true
|
|
186
|
+
|
|
187
|
+
return this.run.pipe(
|
|
188
|
+
Scope.extend(this.scope),
|
|
189
|
+
Effect.forkIn(this.scope)
|
|
190
|
+
)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
run: Effect.Effect<Scope.Scope, never, void> = Effect.suspend(() =>
|
|
194
|
+
Effect.flatMap(
|
|
195
|
+
Idle.whenIdle(this.options),
|
|
196
|
+
(deadline) =>
|
|
197
|
+
Effect.suspend(() => {
|
|
198
|
+
const iterator = this.queue.entries()
|
|
199
|
+
|
|
200
|
+
while (Idle.shouldContinue(deadline)) {
|
|
201
|
+
const result = iterator.next()
|
|
202
|
+
|
|
203
|
+
if (result.done) break
|
|
204
|
+
else {
|
|
205
|
+
const [part, task] = result.value
|
|
206
|
+
this.queue.delete(part)
|
|
207
|
+
task()
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (this.queue.size > 0) {
|
|
212
|
+
return this.run
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.scheduled = false
|
|
216
|
+
|
|
217
|
+
return Effect.unit
|
|
218
|
+
})
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @since 1.0.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Rendered } from "@typed/wire"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @since 1.0.0
|
|
9
|
+
*/
|
|
10
|
+
export type RenderEvent = DomRenderEvent | HtmlRenderEvent
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @since 1.0.0
|
|
14
|
+
*/
|
|
15
|
+
export type DomRenderEvent = {
|
|
16
|
+
readonly _tag: "dom"
|
|
17
|
+
readonly rendered: Rendered
|
|
18
|
+
readonly valueOf: () => Rendered
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
export function DomRenderEvent(rendered: Rendered): DomRenderEvent {
|
|
25
|
+
return {
|
|
26
|
+
_tag: "dom",
|
|
27
|
+
rendered,
|
|
28
|
+
valueOf: () => rendered
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
*/
|
|
35
|
+
export type HtmlRenderEvent = {
|
|
36
|
+
readonly _tag: "html"
|
|
37
|
+
readonly html: string
|
|
38
|
+
readonly valueOf: () => string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @since 1.0.0
|
|
43
|
+
*/
|
|
44
|
+
export function HtmlRenderEvent(html: string): HtmlRenderEvent {
|
|
45
|
+
return {
|
|
46
|
+
_tag: "html",
|
|
47
|
+
html,
|
|
48
|
+
valueOf: () => html
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @since 1.0.0
|
|
54
|
+
*/
|
|
55
|
+
export function isRenderEvent(value: unknown): value is RenderEvent {
|
|
56
|
+
return isTaggedObject(value) && (value._tag === "html" || value._tag === "dom")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isTaggedObject(
|
|
60
|
+
value: unknown
|
|
61
|
+
): value is Record<string, unknown> & { readonly _tag: unknown } {
|
|
62
|
+
return isObject(value) && "_tag" in value
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
66
|
+
return !!value && typeof value === "object"
|
|
67
|
+
}
|