fusee-framework 2.7.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +98 -26
  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 +119 -44
  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,733 +0,0 @@
1
- // Package evalexpr provides a small, safe expression interpreter for Fusée
2
- // template expressions. It handles:
3
- // - Identifiers and member access (a.b.c)
4
- // - Index access (a[0], a["key"])
5
- // - Arithmetic: +, -, *, /, %
6
- // - Comparison: ==, !=, <, <=, >, >=
7
- // - Logical: &&, ||, !
8
- // - String concatenation via +
9
- // - Ternary: cond ? a : b
10
- // - Null-coalescing: a ?? b
11
- //
12
- // No code-execution path exists here — this is intentionally safer than
13
- // JS's new Function() approach, since Go has no eval capability anyway.
14
- package evalexpr
15
-
16
- import (
17
- "fmt"
18
- "math"
19
- "strconv"
20
- "strings"
21
- "unicode"
22
- )
23
-
24
- // Scope is the data context passed to Eval. Keys are variable names.
25
- type Scope map[string]any
26
-
27
- // Eval evaluates a template expression string against the given scope.
28
- // It returns the computed value (string, float64, bool, []any, map[string]any, nil).
29
- func Eval(expr string, scope Scope) (any, error) {
30
- expr = strings.TrimSpace(expr)
31
- if expr == "" {
32
- return nil, nil
33
- }
34
- p := &parser{input: expr, scope: scope}
35
- v, err := p.parseTernary()
36
- if err != nil {
37
- return nil, fmt.Errorf("evalexpr: %w (in %q)", err, expr)
38
- }
39
- return v, nil
40
- }
41
-
42
- // EvalBool evaluates an expression and coerces the result to bool.
43
- func EvalBool(expr string, scope Scope) (bool, error) {
44
- v, err := Eval(expr, scope)
45
- if err != nil {
46
- return false, err
47
- }
48
- return truthy(v), nil
49
- }
50
-
51
- // ─── parser ──────────────────────────────────────────────────────────────────
52
-
53
- type parser struct {
54
- input string
55
- pos int
56
- scope Scope
57
- }
58
-
59
- func (p *parser) peek() byte {
60
- p.skipWS()
61
- if p.pos >= len(p.input) {
62
- return 0
63
- }
64
- return p.input[p.pos]
65
- }
66
-
67
- func (p *parser) skipWS() {
68
- for p.pos < len(p.input) && isWS(p.input[p.pos]) {
69
- p.pos++
70
- }
71
- }
72
-
73
- func (p *parser) consume(n int) {
74
- p.pos += n
75
- }
76
-
77
- func (p *parser) peekStr(s string) bool {
78
- p.skipWS()
79
- return strings.HasPrefix(p.input[p.pos:], s)
80
- }
81
-
82
- func (p *parser) consumeStr(s string) bool {
83
- p.skipWS()
84
- if strings.HasPrefix(p.input[p.pos:], s) {
85
- p.pos += len(s)
86
- return true
87
- }
88
- return false
89
- }
90
-
91
- // ─── grammar (recursive-descent) ─────────────────────────────────────────────
92
-
93
- // ternary: nullCoalesce ( '?' ternary ':' ternary )?
94
- func (p *parser) parseTernary() (any, error) {
95
- cond, err := p.parseNullCoalesce()
96
- if err != nil {
97
- return nil, err
98
- }
99
- if !p.consumeStr("?") {
100
- return cond, nil
101
- }
102
- yes, err := p.parseTernary()
103
- if err != nil {
104
- return nil, err
105
- }
106
- if !p.consumeStr(":") {
107
- return nil, fmt.Errorf("expected ':' in ternary")
108
- }
109
- no, err := p.parseTernary()
110
- if err != nil {
111
- return nil, err
112
- }
113
- if truthy(cond) {
114
- return yes, nil
115
- }
116
- return no, nil
117
- }
118
-
119
- // nullCoalesce: or ( '??' or )*
120
- func (p *parser) parseNullCoalesce() (any, error) {
121
- left, err := p.parseOr()
122
- if err != nil {
123
- return nil, err
124
- }
125
- for p.consumeStr("??") {
126
- right, err := p.parseOr()
127
- if err != nil {
128
- return nil, err
129
- }
130
- if left == nil {
131
- left = right
132
- }
133
- }
134
- return left, nil
135
- }
136
-
137
- // or: and ( '||' and )*
138
- func (p *parser) parseOr() (any, error) {
139
- left, err := p.parseAnd()
140
- if err != nil {
141
- return nil, err
142
- }
143
- for p.consumeStr("||") {
144
- right, err := p.parseAnd()
145
- if err != nil {
146
- return nil, err
147
- }
148
- if !truthy(left) {
149
- left = right
150
- }
151
-
152
- }
153
- return left, nil
154
- }
155
-
156
- // and: equality ( '&&' equality )*
157
- func (p *parser) parseAnd() (any, error) {
158
- left, err := p.parseEquality()
159
- if err != nil {
160
- return nil, err
161
- }
162
- for p.consumeStr("&&") {
163
- right, err := p.parseEquality()
164
- if err != nil {
165
- return nil, err
166
- }
167
- if !truthy(left) {
168
- // short-circuit
169
- } else {
170
- left = right
171
- }
172
- }
173
- return left, nil
174
- }
175
-
176
- // equality: comparison ( ('=='|'!='|'==='|'!==') comparison )*
177
- func (p *parser) parseEquality() (any, error) {
178
- left, err := p.parseComparison()
179
- if err != nil {
180
- return nil, err
181
- }
182
- for {
183
- if p.consumeStr("===") || p.consumeStr("==") {
184
- right, err := p.parseComparison()
185
- if err != nil {
186
- return nil, err
187
- }
188
- left = looseEq(left, right)
189
- } else if p.consumeStr("!==") || p.consumeStr("!=") {
190
- right, err := p.parseComparison()
191
- if err != nil {
192
- return nil, err
193
- }
194
- left = !looseEq(left, right)
195
- } else {
196
- break
197
- }
198
- }
199
- return left, nil
200
- }
201
-
202
- // comparison: addition ( ('<='|'>='|'<'|'>') addition )*
203
- func (p *parser) parseComparison() (any, error) {
204
- left, err := p.parseAddition()
205
- if err != nil {
206
- return nil, err
207
- }
208
- for {
209
- if p.consumeStr("<=") {
210
- right, err := p.parseAddition()
211
- if err != nil {
212
- return nil, err
213
- }
214
- left = compareOp(left, right) <= 0
215
- } else if p.consumeStr(">=") {
216
- right, err := p.parseAddition()
217
- if err != nil {
218
- return nil, err
219
- }
220
- left = compareOp(left, right) >= 0
221
- } else if p.peekByte('<') {
222
- p.consume(1)
223
- right, err := p.parseAddition()
224
- if err != nil {
225
- return nil, err
226
- }
227
- left = compareOp(left, right) < 0
228
- } else if p.peekByte('>') {
229
- p.consume(1)
230
- right, err := p.parseAddition()
231
- if err != nil {
232
- return nil, err
233
- }
234
- left = compareOp(left, right) > 0
235
- } else {
236
- break
237
- }
238
- }
239
- return left, nil
240
- }
241
-
242
- func (p *parser) peekByte(b byte) bool {
243
- p.skipWS()
244
- return p.pos < len(p.input) && p.input[p.pos] == b
245
- }
246
-
247
- // addition: multiplication ( ('+'|'-') multiplication )*
248
- func (p *parser) parseAddition() (any, error) {
249
- left, err := p.parseMultiplication()
250
- if err != nil {
251
- return nil, err
252
- }
253
- for {
254
- if p.peekByte('+') {
255
- p.consume(1)
256
- right, err := p.parseMultiplication()
257
- if err != nil {
258
- return nil, err
259
- }
260
- left = addValues(left, right)
261
- } else if p.peekByte('-') {
262
- p.consume(1)
263
- right, err := p.parseMultiplication()
264
- if err != nil {
265
- return nil, err
266
- }
267
- left = numOp(left, right, func(a, b float64) float64 { return a - b })
268
- } else {
269
- break
270
- }
271
- }
272
- return left, nil
273
- }
274
-
275
- // multiplication: unary ( ('*'|'/'|'%') unary )*
276
- func (p *parser) parseMultiplication() (any, error) {
277
- left, err := p.parseUnary()
278
- if err != nil {
279
- return nil, err
280
- }
281
- for {
282
- if p.peekByte('*') {
283
- p.consume(1)
284
- right, err := p.parseUnary()
285
- if err != nil {
286
- return nil, err
287
- }
288
- left = numOp(left, right, func(a, b float64) float64 { return a * b })
289
- } else if p.peekByte('/') {
290
- p.consume(1)
291
- right, err := p.parseUnary()
292
- if err != nil {
293
- return nil, err
294
- }
295
- left = numOp(left, right, func(a, b float64) float64 {
296
- if b == 0 {
297
- return math.NaN()
298
- }
299
- return a / b
300
- })
301
- } else if p.peekByte('%') {
302
- p.consume(1)
303
- right, err := p.parseUnary()
304
- if err != nil {
305
- return nil, err
306
- }
307
- left = numOp(left, right, func(a, b float64) float64 {
308
- if b == 0 {
309
- return math.NaN()
310
- }
311
- return math.Mod(a, b)
312
- })
313
- } else {
314
- break
315
- }
316
- }
317
- return left, nil
318
- }
319
-
320
- // unary: ('!'|'-')? postfix
321
- func (p *parser) parseUnary() (any, error) {
322
- p.skipWS()
323
- if p.pos < len(p.input) && p.input[p.pos] == '!' {
324
- p.pos++
325
- v, err := p.parseUnary()
326
- if err != nil {
327
- return nil, err
328
- }
329
- return !truthy(v), nil
330
- }
331
- if p.pos < len(p.input) && p.input[p.pos] == '-' {
332
- p.pos++
333
- v, err := p.parseUnary()
334
- if err != nil {
335
- return nil, err
336
- }
337
- if n, ok := toNumber(v); ok {
338
- return -n, nil
339
- }
340
- return math.NaN(), nil
341
- }
342
- return p.parsePostfix()
343
- }
344
-
345
- // postfix: primary ( '.' ident | '[' expr ']' | '(' args ')' )*
346
- func (p *parser) parsePostfix() (any, error) {
347
- val, err := p.parsePrimary()
348
- if err != nil {
349
- return nil, err
350
- }
351
- for {
352
- p.skipWS()
353
- if p.pos >= len(p.input) {
354
- break
355
- }
356
- ch := p.input[p.pos]
357
- if ch == '.' {
358
- p.pos++
359
- name, err := p.parseIdent()
360
- if err != nil {
361
- return nil, err
362
- }
363
- val = memberAccess(val, name)
364
- } else if ch == '[' {
365
- p.pos++
366
- key, err := p.parseTernary()
367
- if err != nil {
368
- return nil, err
369
- }
370
- p.skipWS()
371
- if p.pos < len(p.input) && p.input[p.pos] == ']' {
372
- p.pos++
373
- }
374
- val = indexAccess(val, key)
375
- } else {
376
- break
377
- }
378
- }
379
- return val, nil
380
- }
381
-
382
- // primary: literal | '(' expr ')' | ident
383
- func (p *parser) parsePrimary() (any, error) {
384
- p.skipWS()
385
- if p.pos >= len(p.input) {
386
- return nil, fmt.Errorf("unexpected end of expression")
387
- }
388
-
389
- ch := p.input[p.pos]
390
-
391
- // Grouped
392
- if ch == '(' {
393
- p.pos++
394
- v, err := p.parseTernary()
395
- if err != nil {
396
- return nil, err
397
- }
398
- p.skipWS()
399
- if p.pos < len(p.input) && p.input[p.pos] == ')' {
400
- p.pos++
401
- }
402
- return v, nil
403
- }
404
-
405
- // String literals
406
- if ch == '\'' || ch == '"' || ch == '`' {
407
- return p.parseString(ch)
408
- }
409
-
410
- // Array literal
411
- if ch == '[' {
412
- return p.parseArray()
413
- }
414
-
415
- // Object literal
416
- if ch == '{' {
417
- return p.parseObject()
418
- }
419
-
420
- // Number
421
- if ch >= '0' && ch <= '9' {
422
- return p.parseNumber()
423
- }
424
-
425
- // Keyword / identifier
426
- if isIdentStart(ch) {
427
- return p.parseIdentOrKeyword()
428
- }
429
-
430
- return nil, fmt.Errorf("unexpected character %q", ch)
431
- }
432
-
433
- func (p *parser) parseString(quote byte) (any, error) {
434
- p.pos++ // skip opening quote
435
- var sb strings.Builder
436
- for p.pos < len(p.input) {
437
- c := p.input[p.pos]
438
- if c == quote {
439
- p.pos++
440
- return sb.String(), nil
441
- }
442
- if c == '\\' && p.pos+1 < len(p.input) {
443
- p.pos++
444
- switch p.input[p.pos] {
445
- case 'n':
446
- sb.WriteByte('\n')
447
- case 't':
448
- sb.WriteByte('\t')
449
- case 'r':
450
- sb.WriteByte('\r')
451
- default:
452
- sb.WriteByte(p.input[p.pos])
453
- }
454
- p.pos++
455
- continue
456
- }
457
- // Template literal interpolation (backtick): skip for now, treat as plain string
458
- sb.WriteByte(c)
459
- p.pos++
460
- }
461
- return sb.String(), nil
462
- }
463
-
464
- func (p *parser) parseNumber() (any, error) {
465
- start := p.pos
466
- for p.pos < len(p.input) && (p.input[p.pos] >= '0' && p.input[p.pos] <= '9' || p.input[p.pos] == '.' || p.input[p.pos] == 'e' || p.input[p.pos] == 'E' || p.input[p.pos] == '-' || p.input[p.pos] == '+') {
467
- p.pos++
468
- }
469
- n, err := strconv.ParseFloat(p.input[start:p.pos], 64)
470
- if err != nil {
471
- return nil, fmt.Errorf("invalid number %q", p.input[start:p.pos])
472
- }
473
- return n, nil
474
- }
475
-
476
- func (p *parser) parseArray() (any, error) {
477
- p.pos++ // skip '['
478
- var arr []any
479
- for {
480
- p.skipWS()
481
- if p.pos >= len(p.input) || p.input[p.pos] == ']' {
482
- break
483
- }
484
- v, err := p.parseTernary()
485
- if err != nil {
486
- return nil, err
487
- }
488
- arr = append(arr, v)
489
- p.skipWS()
490
- if p.pos < len(p.input) && p.input[p.pos] == ',' {
491
- p.pos++
492
- }
493
- }
494
- if p.pos < len(p.input) && p.input[p.pos] == ']' {
495
- p.pos++
496
- }
497
- return arr, nil
498
- }
499
-
500
- func (p *parser) parseObject() (any, error) {
501
- p.pos++ // skip '{'
502
- obj := map[string]any{}
503
- for {
504
- p.skipWS()
505
- if p.pos >= len(p.input) || p.input[p.pos] == '}' {
506
- break
507
- }
508
- // key: string or ident
509
- var key string
510
- ch := p.input[p.pos]
511
- if ch == '\'' || ch == '"' || ch == '`' {
512
- v, err := p.parseString(ch)
513
- if err != nil {
514
- return nil, err
515
- }
516
- key = fmt.Sprintf("%v", v)
517
- } else {
518
- k, err := p.parseIdent()
519
- if err != nil {
520
- return nil, err
521
- }
522
- key = k
523
- }
524
- p.skipWS()
525
- if p.pos < len(p.input) && p.input[p.pos] == ':' {
526
- p.pos++
527
- }
528
- val, err := p.parseTernary()
529
- if err != nil {
530
- return nil, err
531
- }
532
- obj[key] = val
533
- p.skipWS()
534
- if p.pos < len(p.input) && p.input[p.pos] == ',' {
535
- p.pos++
536
- }
537
- }
538
- if p.pos < len(p.input) && p.input[p.pos] == '}' {
539
- p.pos++
540
- }
541
- return obj, nil
542
- }
543
-
544
- func (p *parser) parseIdentOrKeyword() (any, error) {
545
- name, err := p.parseIdent()
546
- if err != nil {
547
- return nil, err
548
- }
549
- switch name {
550
- case "true":
551
- return true, nil
552
- case "false":
553
- return false, nil
554
- case "null", "undefined":
555
- return nil, nil
556
- case "NaN":
557
- return math.NaN(), nil
558
- case "Infinity":
559
- return math.Inf(1), nil
560
- }
561
- // Scope lookup
562
- if p.scope != nil {
563
- if v, ok := p.scope[name]; ok {
564
- return v, nil
565
- }
566
- }
567
- // Unknown identifier — return nil (like JS undefined)
568
- return nil, nil
569
- }
570
-
571
- func (p *parser) parseIdent() (string, error) {
572
- p.skipWS()
573
- if p.pos >= len(p.input) || !isIdentStart(p.input[p.pos]) {
574
- return "", fmt.Errorf("expected identifier at %q", p.input[p.pos:])
575
- }
576
- start := p.pos
577
- for p.pos < len(p.input) && isIdentPart(p.input[p.pos]) {
578
- p.pos++
579
- }
580
- return p.input[start:p.pos], nil
581
- }
582
-
583
- // ─── helpers ─────────────────────────────────────────────────────────────────
584
-
585
- func isWS(c byte) bool {
586
- return c == ' ' || c == '\t' || c == '\n' || c == '\r'
587
- }
588
-
589
- func isIdentStart(c byte) bool {
590
- return c == '_' || c == '$' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c > 127 && unicode.IsLetter(rune(c))
591
- }
592
-
593
- func isIdentPart(c byte) bool {
594
- return isIdentStart(c) || (c >= '0' && c <= '9')
595
- }
596
-
597
- func truthy(v any) bool {
598
- if v == nil {
599
- return false
600
- }
601
- switch t := v.(type) {
602
- case bool:
603
- return t
604
- case float64:
605
- return t != 0 && !math.IsNaN(t)
606
- case string:
607
- return t != ""
608
- case []any:
609
- return true
610
- case map[string]any:
611
- return true
612
- }
613
- return true
614
- }
615
-
616
- func toNumber(v any) (float64, bool) {
617
- switch t := v.(type) {
618
- case float64:
619
- return t, true
620
- case bool:
621
- if t {
622
- return 1, true
623
- }
624
- return 0, true
625
- case string:
626
- n, err := strconv.ParseFloat(strings.TrimSpace(t), 64)
627
- if err != nil {
628
- return 0, false
629
- }
630
- return n, true
631
- case nil:
632
- return 0, true
633
- }
634
- return 0, false
635
- }
636
-
637
- func addValues(a, b any) any {
638
- // If either is a string, concatenate
639
- as, aStr := a.(string)
640
- bs, bStr := b.(string)
641
- if aStr || bStr {
642
- return fmt.Sprintf("%v%v", as+bStr2str(a, aStr), bs+bStr2str(b, bStr))
643
- }
644
- if an, ok := toNumber(a); ok {
645
- if bn, ok := toNumber(b); ok {
646
- return an + bn
647
- }
648
- }
649
- return fmt.Sprintf("%v%v", a, b)
650
- }
651
-
652
- func bStr2str(v any, isStr bool) string {
653
- if isStr {
654
- return ""
655
- }
656
- return fmt.Sprintf("%v", v)
657
- }
658
-
659
- func numOp(a, b any, fn func(float64, float64) float64) any {
660
- an, _ := toNumber(a)
661
- bn, _ := toNumber(b)
662
- return fn(an, bn)
663
- }
664
-
665
- func looseEq(a, b any) bool {
666
- if a == nil && b == nil {
667
- return true
668
- }
669
- if a == nil || b == nil {
670
- return false
671
- }
672
- // Both numeric
673
- an, aOK := toNumber(a)
674
- bn, bOK := toNumber(b)
675
- if aOK && bOK {
676
- return an == bn
677
- }
678
- return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b)
679
- }
680
-
681
- func compareOp(a, b any) int {
682
- an, aOK := toNumber(a)
683
- bn, bOK := toNumber(b)
684
- if aOK && bOK {
685
- if an < bn {
686
- return -1
687
- }
688
- if an > bn {
689
- return 1
690
- }
691
- return 0
692
- }
693
- as := fmt.Sprintf("%v", a)
694
- bs := fmt.Sprintf("%v", b)
695
- if as < bs {
696
- return -1
697
- }
698
- if as > bs {
699
- return 1
700
- }
701
- return 0
702
- }
703
-
704
- func memberAccess(obj any, name string) any {
705
- switch t := obj.(type) {
706
- case map[string]any:
707
- return t[name]
708
- case []any:
709
- if name == "length" {
710
- return float64(len(t))
711
- }
712
- case string:
713
- if name == "length" {
714
- return float64(len(t))
715
- }
716
- }
717
- return nil
718
- }
719
-
720
- func indexAccess(obj any, key any) any {
721
- switch t := obj.(type) {
722
- case []any:
723
- if n, ok := toNumber(key); ok {
724
- idx := int(n)
725
- if idx >= 0 && idx < len(t) {
726
- return t[idx]
727
- }
728
- }
729
- case map[string]any:
730
- return t[fmt.Sprintf("%v", key)]
731
- }
732
- return nil
733
- }
@@ -1,3 +0,0 @@
1
- module fusee
2
-
3
- go 1.22.2