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.
Files changed (61) hide show
  1. package/README.md +56 -2
  2. package/bin/create-fusee-linux +0 -0
  3. package/bin/create-fusee-mac-arm64 +0 -0
  4. package/bin/create-fusee-mac-intel +0 -0
  5. package/bin/create-fusee-win.exe +0 -0
  6. package/framework/auto-import-preset.js +20 -12
  7. package/framework/auto-imports.d.ts +68 -39
  8. package/framework/core/compiler.js +310 -310
  9. package/framework/core/component-core.js +445 -0
  10. package/framework/core/component.js +11 -440
  11. package/framework/core/composable.js +29 -29
  12. package/framework/core/h.js +588 -557
  13. package/framework/core/jsx-helpers.js +11 -2
  14. package/framework/core/jsx-runtime.js +73 -73
  15. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm +0 -0
  16. package/framework/core/store.js +333 -333
  17. package/framework/globals.js +42 -0
  18. package/framework/index.js +22 -55
  19. package/framework/router/file-router.js +184 -184
  20. package/framework/server/actions.js +183 -183
  21. package/framework/server/generate-manifest.js +3 -3
  22. package/framework/types/component.d.ts +97 -86
  23. package/framework/types/index.d.ts +118 -117
  24. package/package.json +83 -80
  25. package/framework/core/rust-compiler/Cargo.toml +0 -31
  26. package/framework/core/rust-compiler/README.md +0 -69
  27. package/framework/core/rust-compiler/pkg/README.md +0 -69
  28. package/framework/core/rust-compiler/pkg/fusee_compiler.d.ts +0 -6
  29. package/framework/core/rust-compiler/pkg/fusee_compiler.js +0 -9
  30. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.js +0 -137
  31. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm.d.ts +0 -11
  32. package/framework/core/rust-compiler/pkg/package.json +0 -18
  33. package/framework/core/rust-compiler/src/ast.rs +0 -274
  34. package/framework/core/rust-compiler/src/errors.rs +0 -204
  35. package/framework/core/rust-compiler/src/generator.rs +0 -583
  36. package/framework/core/rust-compiler/src/lexer.rs +0 -414
  37. package/framework/core/rust-compiler/src/lib.rs +0 -87
  38. package/framework/core/rust-compiler/src/main_compiler.rs +0 -165
  39. package/framework/core/rust-compiler/src/parser.rs +0 -516
  40. package/framework/core/rust-compiler/src/ssr_generator.rs +0 -688
  41. package/framework/core/rust-compiler/src/transformer.rs +0 -562
  42. package/framework/core/rust-compiler/src/utils.rs +0 -10
  43. package/framework/engine-go/actions.go +0 -112
  44. package/framework/engine-go/cmd/server/main.go +0 -233
  45. package/framework/engine-go/comet/comet.go +0 -41
  46. package/framework/engine-go/comet/fragment.go +0 -51
  47. package/framework/engine-go/dispatcher.go +0 -120
  48. package/framework/engine-go/elements.go +0 -248
  49. package/framework/engine-go/evalexpr/evalexpr.go +0 -733
  50. package/framework/engine-go/go.mod +0 -3
  51. package/framework/engine-go/hydration.go +0 -43
  52. package/framework/engine-go/load-helpers.go +0 -29
  53. package/framework/engine-go/manifest.go +0 -41
  54. package/framework/engine-go/reactive.go +0 -123
  55. package/framework/engine-go/render.go +0 -635
  56. package/framework/engine-go/reqcontext.go +0 -48
  57. package/framework/engine-go/router.go +0 -85
  58. package/framework/engine-go/rustast/rustast.go +0 -317
  59. package/framework/engine-go/ssr.go +0 -103
  60. package/framework/engine-go/static-assets.go +0 -139
  61. 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("&amp;")
547
- case '<':
548
- sb.WriteString("&lt;")
549
- case '>':
550
- sb.WriteString("&gt;")
551
- case '"':
552
- sb.WriteString("&quot;")
553
- case '\'':
554
- sb.WriteString("&#39;")
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
- }