fusee-framework 2.7.0 → 2.7.1
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/README.md +56 -2
- package/bin/create-fusee-linux +0 -0
- package/bin/create-fusee-mac-arm64 +0 -0
- package/bin/create-fusee-mac-intel +0 -0
- package/bin/create-fusee-win.exe +0 -0
- package/framework/auto-import-preset.js +20 -12
- package/framework/auto-imports.d.ts +68 -39
- package/framework/core/compiler.js +310 -310
- package/framework/core/component-core.js +445 -0
- package/framework/core/component.js +11 -440
- package/framework/core/composable.js +29 -29
- package/framework/core/h.js +588 -557
- package/framework/core/jsx-helpers.js +11 -2
- package/framework/core/jsx-runtime.js +73 -73
- package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm +0 -0
- package/framework/core/store.js +333 -333
- package/framework/globals.js +42 -0
- package/framework/index.js +22 -55
- package/framework/router/file-router.js +184 -184
- package/framework/server/actions.js +183 -183
- package/framework/server/generate-manifest.js +3 -3
- package/framework/types/component.d.ts +97 -86
- package/framework/types/index.d.ts +118 -117
- package/package.json +83 -80
- package/framework/core/rust-compiler/Cargo.toml +0 -31
- package/framework/core/rust-compiler/README.md +0 -69
- package/framework/core/rust-compiler/pkg/README.md +0 -69
- package/framework/core/rust-compiler/pkg/fusee_compiler.d.ts +0 -6
- package/framework/core/rust-compiler/pkg/fusee_compiler.js +0 -9
- package/framework/core/rust-compiler/pkg/fusee_compiler_bg.js +0 -137
- package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm.d.ts +0 -11
- package/framework/core/rust-compiler/pkg/package.json +0 -18
- package/framework/core/rust-compiler/src/ast.rs +0 -274
- package/framework/core/rust-compiler/src/errors.rs +0 -204
- package/framework/core/rust-compiler/src/generator.rs +0 -583
- package/framework/core/rust-compiler/src/lexer.rs +0 -414
- package/framework/core/rust-compiler/src/lib.rs +0 -87
- package/framework/core/rust-compiler/src/main_compiler.rs +0 -165
- package/framework/core/rust-compiler/src/parser.rs +0 -516
- package/framework/core/rust-compiler/src/ssr_generator.rs +0 -688
- package/framework/core/rust-compiler/src/transformer.rs +0 -562
- package/framework/core/rust-compiler/src/utils.rs +0 -10
- package/framework/engine-go/actions.go +0 -112
- package/framework/engine-go/cmd/server/main.go +0 -233
- package/framework/engine-go/comet/comet.go +0 -41
- package/framework/engine-go/comet/fragment.go +0 -51
- package/framework/engine-go/dispatcher.go +0 -120
- package/framework/engine-go/elements.go +0 -248
- package/framework/engine-go/evalexpr/evalexpr.go +0 -733
- package/framework/engine-go/go.mod +0 -3
- package/framework/engine-go/hydration.go +0 -43
- package/framework/engine-go/load-helpers.go +0 -29
- package/framework/engine-go/manifest.go +0 -41
- package/framework/engine-go/reactive.go +0 -123
- package/framework/engine-go/render.go +0 -635
- package/framework/engine-go/reqcontext.go +0 -48
- package/framework/engine-go/router.go +0 -85
- package/framework/engine-go/rustast/rustast.go +0 -317
- package/framework/engine-go/ssr.go +0 -103
- package/framework/engine-go/static-assets.go +0 -139
- package/framework/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
|
@@ -1,635 +0,0 @@
|
|
|
1
|
-
package engine
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"fmt"
|
|
6
|
-
"strconv"
|
|
7
|
-
"strings"
|
|
8
|
-
|
|
9
|
-
"fusee/evalexpr"
|
|
10
|
-
"fusee/rustast"
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
type Component struct {
|
|
14
|
-
AST *rustast.Node
|
|
15
|
-
Setup func(props evalexpr.Scope) (evalexpr.Scope, error)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
type Renderer struct {
|
|
19
|
-
Components map[string]*Component
|
|
20
|
-
Elements ElementRegistry
|
|
21
|
-
|
|
22
|
-
depth int
|
|
23
|
-
anchorIdx int
|
|
24
|
-
hoistedByID map[int]*rustast.Node // id -> the actual ElementNode Node, built once per Render call
|
|
25
|
-
hoistedCache map[int]string // id -> cached rendered HTML, built once per Render call
|
|
26
|
-
hoistedIDs map[int]bool
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
func NewRenderer(components map[string]*Component) *Renderer {
|
|
30
|
-
if components == nil {
|
|
31
|
-
components = map[string]*Component{}
|
|
32
|
-
}
|
|
33
|
-
return &Renderer{Components: components}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
func Render(root *rustast.Node, scope evalexpr.Scope) (string, error) {
|
|
37
|
-
if root.Type != rustast.NodeRoot {
|
|
38
|
-
return "", fmt.Errorf("render: expected a Root node, got %s", root.Type)
|
|
39
|
-
}
|
|
40
|
-
r := NewRenderer(nil)
|
|
41
|
-
return r.renderRoot(root, scope)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
func RenderWithComponents(root *rustast.Node, scope evalexpr.Scope, components map[string]*Component) (string, error) {
|
|
45
|
-
if root.Type != rustast.NodeRoot {
|
|
46
|
-
return "", fmt.Errorf("render: expected a Root node, got %s", root.Type)
|
|
47
|
-
}
|
|
48
|
-
r := NewRenderer(components)
|
|
49
|
-
return r.renderRoot(root, scope)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// RenderWithElements renders a page, server-rendering registered custom elements as
|
|
53
|
-
// declarative shadow DOM.
|
|
54
|
-
func RenderWithElements(root *rustast.Node, scope evalexpr.Scope, components map[string]*Component, elements ElementRegistry) (string, error) {
|
|
55
|
-
if root.Type != rustast.NodeRoot {
|
|
56
|
-
return "", fmt.Errorf("render: expected a Root node, got %s", root.Type)
|
|
57
|
-
}
|
|
58
|
-
r := NewRenderer(components)
|
|
59
|
-
r.Elements = elements
|
|
60
|
-
return r.renderRoot(root, scope)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
func (r *Renderer) renderRoot(root *rustast.Node, scope evalexpr.Scope) (string, error) {
|
|
64
|
-
r.anchorIdx = 0
|
|
65
|
-
r.hoistedByID = map[int]*rustast.Node{}
|
|
66
|
-
r.hoistedCache = map[int]string{}
|
|
67
|
-
r.hoistedIDs = map[int]bool{}
|
|
68
|
-
|
|
69
|
-
for _, id := range root.Root.Hoisted {
|
|
70
|
-
r.hoistedIDs[id] = true
|
|
71
|
-
}
|
|
72
|
-
collectElementRefs(root.Root.Children, r.hoistedByID)
|
|
73
|
-
|
|
74
|
-
var sb strings.Builder
|
|
75
|
-
if err := r.renderChildren(root.Root.Children, scope, &sb); err != nil {
|
|
76
|
-
return "", err
|
|
77
|
-
}
|
|
78
|
-
return sb.String(), nil
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
func collectElementRefs(nodes []*rustast.Node, out map[int]*rustast.Node) {
|
|
82
|
-
for _, n := range nodes {
|
|
83
|
-
switch n.Type {
|
|
84
|
-
case rustast.NodeElement:
|
|
85
|
-
out[n.Element.ID] = n
|
|
86
|
-
collectElementRefs(n.Element.Children, out)
|
|
87
|
-
case rustast.NodeComponent:
|
|
88
|
-
for _, slot := range n.Component.Slots {
|
|
89
|
-
collectElementRefs(slot.Children, out)
|
|
90
|
-
}
|
|
91
|
-
case rustast.NodeIf:
|
|
92
|
-
for _, b := range n.If.Branches {
|
|
93
|
-
collectElementRefs([]*rustast.Node{b.Node}, out)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
func (r *Renderer) nextAnchor() int {
|
|
100
|
-
id := r.anchorIdx
|
|
101
|
-
r.anchorIdx++
|
|
102
|
-
return id
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
func (r *Renderer) renderChildren(nodes []*rustast.Node, scope evalexpr.Scope, sb *strings.Builder) error {
|
|
106
|
-
for _, n := range nodes {
|
|
107
|
-
if forDir := findForDir(n); forDir != nil {
|
|
108
|
-
if err := r.renderFor(n, forDir, scope, sb); err != nil {
|
|
109
|
-
return err
|
|
110
|
-
}
|
|
111
|
-
continue
|
|
112
|
-
}
|
|
113
|
-
if err := r.renderNode(n, scope, sb, false); err != nil {
|
|
114
|
-
return err
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return nil
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
func findForDir(n *rustast.Node) *rustast.DirectiveNode {
|
|
121
|
-
for _, p := range n.Props() {
|
|
122
|
-
if p.Type == rustast.PropDirective && p.Directive.Name == "for" {
|
|
123
|
-
return p.Directive
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return nil
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
func (r *Renderer) renderNode(n *rustast.Node, scope evalexpr.Scope, sb *strings.Builder, inHoist bool) error {
|
|
130
|
-
if !inHoist && n.Type == rustast.NodeElement && r.hoistedIDs[n.Element.ID] {
|
|
131
|
-
cached, ok := r.hoistedCache[n.Element.ID]
|
|
132
|
-
if !ok {
|
|
133
|
-
var hb strings.Builder
|
|
134
|
-
if err := r.renderElement(n.Element, scope, &hb, true); err != nil {
|
|
135
|
-
return err
|
|
136
|
-
}
|
|
137
|
-
cached = hb.String()
|
|
138
|
-
r.hoistedCache[n.Element.ID] = cached
|
|
139
|
-
}
|
|
140
|
-
sb.WriteString(cached)
|
|
141
|
-
return nil
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
switch n.Type {
|
|
145
|
-
case rustast.NodeText:
|
|
146
|
-
sb.WriteString(n.Text.Content)
|
|
147
|
-
return nil
|
|
148
|
-
case rustast.NodeInterpolation:
|
|
149
|
-
return r.renderInterpolation(n.Interpolation, scope, sb)
|
|
150
|
-
case rustast.NodeElement:
|
|
151
|
-
return r.renderElement(n.Element, scope, sb, inHoist)
|
|
152
|
-
case rustast.NodeComponent:
|
|
153
|
-
return r.renderComponent(n.Component, scope, sb)
|
|
154
|
-
case rustast.NodeSlotOutlet:
|
|
155
|
-
return r.renderSlotOutlet(n.SlotOutlet, scope, sb)
|
|
156
|
-
case rustast.NodeIf:
|
|
157
|
-
return r.renderIf(n.If, scope, sb)
|
|
158
|
-
default:
|
|
159
|
-
return fmt.Errorf("render: unexpected node type %s here", n.Type)
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
func (r *Renderer) renderInterpolation(n *rustast.InterpolationNode, scope evalexpr.Scope, sb *strings.Builder) error {
|
|
164
|
-
if n.Expression.IsStatic {
|
|
165
|
-
v, err := evalexpr.Eval(n.Expression.Content, scope)
|
|
166
|
-
if err != nil {
|
|
167
|
-
return err
|
|
168
|
-
}
|
|
169
|
-
sb.WriteString(escapeHTML(displayString(v)))
|
|
170
|
-
return nil
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
id := r.nextAnchor()
|
|
174
|
-
v, err := evalexpr.Eval(n.Expression.Content, scope)
|
|
175
|
-
if err != nil {
|
|
176
|
-
return err
|
|
177
|
-
}
|
|
178
|
-
fmt.Fprintf(sb, "<!--f-bind:%d-->%s<!--/f-bind:%d-->", id, escapeHTML(displayString(v)), id)
|
|
179
|
-
return nil
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
var voidElements = map[string]bool{
|
|
183
|
-
"area": true, "base": true, "br": true, "col": true, "embed": true,
|
|
184
|
-
"hr": true, "img": true, "input": true, "link": true, "meta": true,
|
|
185
|
-
"param": true, "source": true, "track": true, "wbr": true,
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
func (r *Renderer) renderElement(n *rustast.ElementNode, scope evalexpr.Scope, sb *strings.Builder, inHoist bool) error {
|
|
189
|
-
element := r.Elements.lookup(n.Tag)
|
|
190
|
-
// A registered custom element always needs a closing tag to hold its shadow root.
|
|
191
|
-
isVoid := element == nil && (n.SelfClosing || voidElements[strings.ToLower(n.Tag)])
|
|
192
|
-
|
|
193
|
-
var htmlDir *rustast.DirectiveNode
|
|
194
|
-
needsAnchor := false
|
|
195
|
-
for _, p := range n.Props {
|
|
196
|
-
switch p.Type {
|
|
197
|
-
case rustast.PropDirective:
|
|
198
|
-
if p.Directive.Name == "html" {
|
|
199
|
-
htmlDir = p.Directive
|
|
200
|
-
}
|
|
201
|
-
if p.Directive.Name != "if" && p.Directive.Name != "else-if" && p.Directive.Name != "else" && p.Directive.Name != "for" {
|
|
202
|
-
needsAnchor = true
|
|
203
|
-
}
|
|
204
|
-
case rustast.PropBinding, rustast.PropEvent:
|
|
205
|
-
needsAnchor = true
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
var anchorID int
|
|
210
|
-
hasAnchor := false
|
|
211
|
-
if needsAnchor {
|
|
212
|
-
anchorID = r.nextAnchor()
|
|
213
|
-
hasAnchor = true
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
sb.WriteByte('<')
|
|
217
|
-
sb.WriteString(n.Tag)
|
|
218
|
-
if err := r.renderAttrs(n.Props, scope, sb, strings.Contains(n.Tag, "-")); err != nil {
|
|
219
|
-
return err
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
var elementProps evalexpr.Scope
|
|
223
|
-
if element != nil {
|
|
224
|
-
var reflected [][2]string
|
|
225
|
-
var err error
|
|
226
|
-
elementProps, reflected, err = resolveElementProps(element, n.Props, scope)
|
|
227
|
-
if err != nil {
|
|
228
|
-
return err
|
|
229
|
-
}
|
|
230
|
-
for _, attr := range reflected {
|
|
231
|
-
if attr[1] == "" {
|
|
232
|
-
fmt.Fprintf(sb, " %s", attr[0])
|
|
233
|
-
} else {
|
|
234
|
-
fmt.Fprintf(sb, ` %s="%s"`, attr[0], escapeAttr(attr[1]))
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if hasAnchor {
|
|
240
|
-
fmt.Fprintf(sb, ` data-f-id="%d"`, anchorID)
|
|
241
|
-
}
|
|
242
|
-
if isVoid {
|
|
243
|
-
sb.WriteString("/>")
|
|
244
|
-
return nil
|
|
245
|
-
}
|
|
246
|
-
sb.WriteByte('>')
|
|
247
|
-
|
|
248
|
-
if element != nil {
|
|
249
|
-
if err := r.renderShadowRoot(element, elementProps, sb); err != nil {
|
|
250
|
-
return err
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if htmlDir != nil {
|
|
255
|
-
v, err := evalexpr.Eval(htmlDir.Expression.Content, scope)
|
|
256
|
-
if err != nil {
|
|
257
|
-
return err
|
|
258
|
-
}
|
|
259
|
-
sb.WriteString(displayString(v))
|
|
260
|
-
} else {
|
|
261
|
-
if err := r.renderChildren(n.Children, scope, sb); err != nil {
|
|
262
|
-
return err
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
sb.WriteString("</")
|
|
267
|
-
sb.WriteString(n.Tag)
|
|
268
|
-
sb.WriteByte('>')
|
|
269
|
-
return nil
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
func (r *Renderer) renderAttrs(props []*rustast.Prop, scope evalexpr.Scope, sb *strings.Builder, isCustomElement bool) error {
|
|
273
|
-
for _, p := range props {
|
|
274
|
-
switch p.Type {
|
|
275
|
-
case rustast.PropAttribute:
|
|
276
|
-
renderStaticAttr(p.Attribute, sb)
|
|
277
|
-
case rustast.PropBinding:
|
|
278
|
-
if err := r.renderBindingAttr(p.Binding, scope, sb, isCustomElement); err != nil {
|
|
279
|
-
return err
|
|
280
|
-
}
|
|
281
|
-
case rustast.PropDirective:
|
|
282
|
-
if err := r.renderDirectiveAttr(p.Directive, scope, sb); err != nil {
|
|
283
|
-
return err
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return nil
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
func renderStaticAttr(a *rustast.AttributeNode, sb *strings.Builder) {
|
|
291
|
-
if a.Value == nil {
|
|
292
|
-
fmt.Fprintf(sb, " %s", a.Name)
|
|
293
|
-
return
|
|
294
|
-
}
|
|
295
|
-
fmt.Fprintf(sb, ` %s="%s"`, a.Name, escapeAttr(*a.Value))
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
func (r *Renderer) renderBindingAttr(b *rustast.BindingNode, scope evalexpr.Scope, sb *strings.Builder, isCustomElement bool) error {
|
|
299
|
-
if b.IsProp {
|
|
300
|
-
return nil
|
|
301
|
-
}
|
|
302
|
-
v, err := evalexpr.Eval(b.Expression.Content, scope)
|
|
303
|
-
if err != nil {
|
|
304
|
-
return err
|
|
305
|
-
}
|
|
306
|
-
switch b.Name {
|
|
307
|
-
case "class":
|
|
308
|
-
fmt.Fprintf(sb, ` class="%s"`, escapeAttr(renderClass(v)))
|
|
309
|
-
case "style":
|
|
310
|
-
fmt.Fprintf(sb, ` style="%s"`, escapeAttr(renderStyle(v)))
|
|
311
|
-
default:
|
|
312
|
-
if v == false || v == nil {
|
|
313
|
-
return nil
|
|
314
|
-
}
|
|
315
|
-
if v == true {
|
|
316
|
-
fmt.Fprintf(sb, " %s", b.Name)
|
|
317
|
-
return nil
|
|
318
|
-
}
|
|
319
|
-
// Custom elements parse Array/Object props from JSON attributes.
|
|
320
|
-
if isCustomElement {
|
|
321
|
-
switch v.(type) {
|
|
322
|
-
case []any, map[string]any:
|
|
323
|
-
if raw, err := json.Marshal(v); err == nil {
|
|
324
|
-
fmt.Fprintf(sb, ` %s="%s"`, b.Name, escapeAttr(string(raw)))
|
|
325
|
-
return nil
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
fmt.Fprintf(sb, ` %s="%s"`, b.Name, escapeAttr(displayString(v)))
|
|
330
|
-
}
|
|
331
|
-
return nil
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
func (r *Renderer) renderDirectiveAttr(d *rustast.DirectiveNode, scope evalexpr.Scope, sb *strings.Builder) error {
|
|
335
|
-
switch d.Name {
|
|
336
|
-
case "show":
|
|
337
|
-
v, err := evalexpr.EvalBool(d.Expression.Content, scope)
|
|
338
|
-
if err != nil {
|
|
339
|
-
return err
|
|
340
|
-
}
|
|
341
|
-
if !v {
|
|
342
|
-
sb.WriteString(` style="display:none"`)
|
|
343
|
-
}
|
|
344
|
-
case "model":
|
|
345
|
-
v, err := evalexpr.Eval(d.Expression.Content, scope)
|
|
346
|
-
if err != nil {
|
|
347
|
-
return err
|
|
348
|
-
}
|
|
349
|
-
fmt.Fprintf(sb, ` value="%s"`, escapeAttr(displayString(v)))
|
|
350
|
-
}
|
|
351
|
-
return nil
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
func (r *Renderer) renderIf(n *rustast.IfNode, scope evalexpr.Scope, sb *strings.Builder) error {
|
|
355
|
-
id := r.nextAnchor()
|
|
356
|
-
fmt.Fprintf(sb, "<!--f-if:%d-->", id)
|
|
357
|
-
|
|
358
|
-
for _, branch := range n.Branches {
|
|
359
|
-
take := branch.Condition == nil
|
|
360
|
-
if !take {
|
|
361
|
-
var err error
|
|
362
|
-
take, err = evalexpr.EvalBool(branch.Condition.Content, scope)
|
|
363
|
-
if err != nil {
|
|
364
|
-
return err
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
if take {
|
|
368
|
-
if err := r.renderNode(branch.Node, scope, sb, false); err != nil {
|
|
369
|
-
return err
|
|
370
|
-
}
|
|
371
|
-
break
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
fmt.Fprintf(sb, "<!--/f-if:%d-->", id)
|
|
376
|
-
return nil
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
func (r *Renderer) renderFor(n *rustast.Node, forDir *rustast.DirectiveNode, scope evalexpr.Scope, sb *strings.Builder) error {
|
|
380
|
-
id := r.nextAnchor()
|
|
381
|
-
arg := forDir.Arg
|
|
382
|
-
|
|
383
|
-
src, err := evalexpr.Eval(arg.Source, scope)
|
|
384
|
-
if err != nil {
|
|
385
|
-
return err
|
|
386
|
-
}
|
|
387
|
-
items, indices, keys := enumerate(src)
|
|
388
|
-
|
|
389
|
-
fmt.Fprintf(sb, "<!--f-for:%d-->", id)
|
|
390
|
-
for i, item := range items {
|
|
391
|
-
childScope := cloneScope(scope)
|
|
392
|
-
childScope[arg.Item] = item
|
|
393
|
-
if arg.Index != nil {
|
|
394
|
-
childScope[*arg.Index] = indices[i]
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
var key any
|
|
398
|
-
if keyBinding := findKeyBinding(n); keyBinding != nil {
|
|
399
|
-
key, err = evalexpr.Eval(keyBinding.Expression.Content, childScope)
|
|
400
|
-
if err != nil {
|
|
401
|
-
return err
|
|
402
|
-
}
|
|
403
|
-
} else {
|
|
404
|
-
key = keys[i]
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
fmt.Fprintf(sb, "<!--f-for-item:%d:%s-->", id, escapeAttr(displayString(key)))
|
|
408
|
-
if err := r.renderNode(n, childScope, sb, false); err != nil {
|
|
409
|
-
return err
|
|
410
|
-
}
|
|
411
|
-
sb.WriteString(fmt.Sprintf("<!--/f-for-item:%d-->", id))
|
|
412
|
-
}
|
|
413
|
-
fmt.Fprintf(sb, "<!--/f-for:%d-->", id)
|
|
414
|
-
return nil
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
func findKeyBinding(n *rustast.Node) *rustast.BindingNode {
|
|
418
|
-
for _, p := range n.Props() {
|
|
419
|
-
if p.Type == rustast.PropBinding && p.Binding.Name == "key" {
|
|
420
|
-
return p.Binding
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return nil
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
func enumerate(src any) (items []any, indices []any, keys []any) {
|
|
427
|
-
switch t := src.(type) {
|
|
428
|
-
case []any:
|
|
429
|
-
for i, v := range t {
|
|
430
|
-
items = append(items, v)
|
|
431
|
-
indices = append(indices, float64(i))
|
|
432
|
-
keys = append(keys, float64(i))
|
|
433
|
-
}
|
|
434
|
-
case map[string]any:
|
|
435
|
-
i := 0
|
|
436
|
-
for k, v := range t {
|
|
437
|
-
items = append(items, v)
|
|
438
|
-
indices = append(indices, float64(i))
|
|
439
|
-
keys = append(keys, k)
|
|
440
|
-
i++
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
return
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
func cloneScope(scope evalexpr.Scope) evalexpr.Scope {
|
|
447
|
-
out := make(evalexpr.Scope, len(scope)+2)
|
|
448
|
-
for k, v := range scope {
|
|
449
|
-
out[k] = v
|
|
450
|
-
}
|
|
451
|
-
return out
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
func (r *Renderer) renderComponent(n *rustast.ComponentNode, scope evalexpr.Scope, sb *strings.Builder) error {
|
|
455
|
-
id := r.nextAnchor()
|
|
456
|
-
fmt.Fprintf(sb, "<!--f-component:%s:%d-->", n.Name, id)
|
|
457
|
-
|
|
458
|
-
comp, ok := r.Components[n.Name]
|
|
459
|
-
if !ok || comp == nil || comp.AST == nil {
|
|
460
|
-
fmt.Fprintf(sb, "<!--/f-component:%d-->", id)
|
|
461
|
-
return nil
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
props := evalexpr.Scope{}
|
|
465
|
-
for _, p := range n.Props {
|
|
466
|
-
switch p.Type {
|
|
467
|
-
case rustast.PropAttribute:
|
|
468
|
-
if p.Attribute.Value != nil {
|
|
469
|
-
props[p.Attribute.Name] = *p.Attribute.Value
|
|
470
|
-
} else {
|
|
471
|
-
props[p.Attribute.Name] = true
|
|
472
|
-
}
|
|
473
|
-
case rustast.PropBinding:
|
|
474
|
-
v, err := evalexpr.Eval(p.Binding.Expression.Content, scope)
|
|
475
|
-
if err != nil {
|
|
476
|
-
return err
|
|
477
|
-
}
|
|
478
|
-
props[p.Binding.Name] = v
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
childScope := props
|
|
483
|
-
if comp.Setup != nil {
|
|
484
|
-
extra, err := comp.Setup(props)
|
|
485
|
-
if err != nil {
|
|
486
|
-
return err
|
|
487
|
-
}
|
|
488
|
-
childScope = mergeScopes(props, extra)
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
if len(n.Slots) > 0 {
|
|
492
|
-
slotsMap := make(map[string][]*rustast.Node, len(n.Slots))
|
|
493
|
-
for _, s := range n.Slots {
|
|
494
|
-
slotsMap[s.Name] = s.Children
|
|
495
|
-
}
|
|
496
|
-
childScope = cloneScope(childScope)
|
|
497
|
-
childScope["_slots"] = slotsMap
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
childR := NewRenderer(r.Components)
|
|
501
|
-
childR.Elements = r.Elements
|
|
502
|
-
childR.depth = r.depth
|
|
503
|
-
html, err := childR.renderRoot(comp.AST, childScope)
|
|
504
|
-
if err != nil {
|
|
505
|
-
return err
|
|
506
|
-
}
|
|
507
|
-
sb.WriteString(html)
|
|
508
|
-
|
|
509
|
-
fmt.Fprintf(sb, "<!--/f-component:%d-->", id)
|
|
510
|
-
return nil
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
func mergeScopes(base, overlay evalexpr.Scope) evalexpr.Scope {
|
|
514
|
-
out := make(evalexpr.Scope, len(base)+len(overlay))
|
|
515
|
-
for k, v := range base {
|
|
516
|
-
out[k] = v
|
|
517
|
-
}
|
|
518
|
-
for k, v := range overlay {
|
|
519
|
-
out[k] = v
|
|
520
|
-
}
|
|
521
|
-
return out
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
func (r *Renderer) renderSlotOutlet(n *rustast.SlotOutletNode, scope evalexpr.Scope, sb *strings.Builder) error {
|
|
525
|
-
id := r.nextAnchor()
|
|
526
|
-
fmt.Fprintf(sb, "<!--f-slot:%d-->", id)
|
|
527
|
-
|
|
528
|
-
provided, _ := scope["_slots"].(map[string][]*rustast.Node)
|
|
529
|
-
content, ok := provided[n.SlotName]
|
|
530
|
-
if !ok {
|
|
531
|
-
content = n.Fallback
|
|
532
|
-
}
|
|
533
|
-
if err := r.renderChildren(content, scope, sb); err != nil {
|
|
534
|
-
return err
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
fmt.Fprintf(sb, "<!--/f-slot:%d-->", id)
|
|
538
|
-
return nil
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
func escapeHTML(s string) string {
|
|
542
|
-
var sb strings.Builder
|
|
543
|
-
for _, c := range s {
|
|
544
|
-
switch c {
|
|
545
|
-
case '&':
|
|
546
|
-
sb.WriteString("&")
|
|
547
|
-
case '<':
|
|
548
|
-
sb.WriteString("<")
|
|
549
|
-
case '>':
|
|
550
|
-
sb.WriteString(">")
|
|
551
|
-
case '"':
|
|
552
|
-
sb.WriteString(""")
|
|
553
|
-
case '\'':
|
|
554
|
-
sb.WriteString("'")
|
|
555
|
-
default:
|
|
556
|
-
sb.WriteRune(c)
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
return sb.String()
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
func escapeAttr(s string) string { return escapeHTML(s) }
|
|
563
|
-
|
|
564
|
-
func displayString(v any) string {
|
|
565
|
-
switch t := v.(type) {
|
|
566
|
-
case nil:
|
|
567
|
-
return ""
|
|
568
|
-
case string:
|
|
569
|
-
return t
|
|
570
|
-
case float64:
|
|
571
|
-
return strconv.FormatFloat(t, 'f', -1, 64)
|
|
572
|
-
case bool:
|
|
573
|
-
return strconv.FormatBool(t)
|
|
574
|
-
default:
|
|
575
|
-
return fmt.Sprintf("%v", t)
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
func renderClass(v any) string {
|
|
580
|
-
switch t := v.(type) {
|
|
581
|
-
case []any:
|
|
582
|
-
var parts []string
|
|
583
|
-
for _, item := range t {
|
|
584
|
-
if s, ok := item.(string); ok && s != "" {
|
|
585
|
-
parts = append(parts, s)
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
return strings.Join(parts, " ")
|
|
589
|
-
case map[string]any:
|
|
590
|
-
var parts []string
|
|
591
|
-
for k, val := range t {
|
|
592
|
-
if truthyForClass(val) {
|
|
593
|
-
parts = append(parts, k)
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
return strings.Join(parts, " ")
|
|
597
|
-
default:
|
|
598
|
-
return displayString(v)
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
func truthyForClass(v any) bool {
|
|
603
|
-
switch t := v.(type) {
|
|
604
|
-
case bool:
|
|
605
|
-
return t
|
|
606
|
-
case nil:
|
|
607
|
-
return false
|
|
608
|
-
default:
|
|
609
|
-
return true
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
func renderStyle(v any) string {
|
|
614
|
-
if m, ok := v.(map[string]any); ok {
|
|
615
|
-
var parts []string
|
|
616
|
-
for k, val := range m {
|
|
617
|
-
parts = append(parts, fmt.Sprintf("%s:%s", kebabCase(k), displayString(val)))
|
|
618
|
-
}
|
|
619
|
-
return strings.Join(parts, ";")
|
|
620
|
-
}
|
|
621
|
-
return displayString(v)
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
func kebabCase(s string) string {
|
|
625
|
-
var sb strings.Builder
|
|
626
|
-
for _, c := range s {
|
|
627
|
-
if c >= 'A' && c <= 'Z' {
|
|
628
|
-
sb.WriteByte('-')
|
|
629
|
-
sb.WriteRune(c - 'A' + 'a')
|
|
630
|
-
} else {
|
|
631
|
-
sb.WriteRune(c)
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
return sb.String()
|
|
635
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
package engine
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"net/http"
|
|
6
|
-
"sync"
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
type contextKey struct{}
|
|
10
|
-
type RequestContext struct {
|
|
11
|
-
mu sync.Mutex
|
|
12
|
-
ResourceCache map[string]map[string]any
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
func New() *RequestContext {
|
|
16
|
-
return &RequestContext{
|
|
17
|
-
ResourceCache: make(map[string]map[string]any),
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
func (rc *RequestContext) SetResource(resourceKey, cacheKey string, value any) {
|
|
22
|
-
rc.mu.Lock()
|
|
23
|
-
defer rc.mu.Unlock()
|
|
24
|
-
m, ok := rc.ResourceCache[resourceKey]
|
|
25
|
-
if !ok {
|
|
26
|
-
m = make(map[string]any)
|
|
27
|
-
rc.ResourceCache[resourceKey] = m
|
|
28
|
-
}
|
|
29
|
-
m[cacheKey] = value
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
func With(ctx context.Context, rc *RequestContext) context.Context {
|
|
33
|
-
return context.WithValue(ctx, contextKey{}, rc)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
func From(ctx context.Context) *RequestContext {
|
|
37
|
-
rc, _ := ctx.Value(contextKey{}).(*RequestContext)
|
|
38
|
-
return rc
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
func Middleware(next http.Handler) http.Handler {
|
|
42
|
-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
43
|
-
rc := New()
|
|
44
|
-
ctx := With(r.Context(), rc)
|
|
45
|
-
ctx = WithRegistry(ctx, NewRegistry())
|
|
46
|
-
next.ServeHTTP(w, r.WithContext(ctx))
|
|
47
|
-
})
|
|
48
|
-
}
|