goscript 0.2.2 → 0.2.4
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/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
- package/compiler/lowering.go +279 -16
- package/compiler/override-registry_test.go +175 -0
- package/compiler/protobuf-ts-binding.go +154 -6
- package/compiler/protobuf-ts-binding_test.go +7 -2
- package/compiler/runtime-contract.go +2 -0
- package/compiler/runtime-contract_test.go +1 -0
- package/compiler/semantic-model.go +16 -0
- package/compiler/semantic-model_test.go +38 -0
- package/compiler/skeleton_test.go +522 -17
- package/compiler/typescript-emitter.go +4 -0
- package/dist/gs/builtin/builtin.js +7 -9
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/defer.js +2 -2
- package/dist/gs/builtin/hostio.js +5 -5
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/map.js +2 -1
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +3 -0
- package/dist/gs/builtin/slice.js +39 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +49 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/compress/gzip/index.d.ts +41 -0
- package/dist/gs/compress/gzip/index.js +235 -0
- package/dist/gs/compress/gzip/index.js.map +1 -0
- package/dist/gs/compress/zlib/index.js +5 -2
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/ecdh/index.js +27 -8
- package/dist/gs/crypto/ecdh/index.js.map +1 -1
- package/dist/gs/crypto/ed25519/index.js +3 -3
- package/dist/gs/crypto/ed25519/index.js.map +1 -1
- package/dist/gs/crypto/rand/index.js +6 -3
- package/dist/gs/crypto/rand/index.js.map +1 -1
- package/dist/gs/embed/index.js +9 -3
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
- package/dist/gs/hash/fnv/index.js +13 -5
- package/dist/gs/hash/fnv/index.js.map +1 -1
- package/dist/gs/io/fs/glob.d.ts +3 -3
- package/dist/gs/io/fs/glob.js +9 -9
- package/dist/gs/io/fs/glob.js.map +1 -1
- package/dist/gs/io/fs/readdir.d.ts +2 -2
- package/dist/gs/io/fs/readdir.js +13 -74
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readlink.d.ts +1 -1
- package/dist/gs/io/fs/readlink.js +2 -2
- package/dist/gs/io/fs/readlink.js.map +1 -1
- package/dist/gs/io/fs/stat.d.ts +4 -2
- package/dist/gs/io/fs/stat.js +12 -73
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.d.ts +2 -2
- package/dist/gs/io/fs/sub.js +11 -11
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.js +2 -2
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.js.map +1 -1
- package/dist/gs/mime/index.js +5 -2
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.js +6 -3
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +34 -18
- package/dist/gs/net/http/index.js +280 -63
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.d.ts +5 -5
- package/dist/gs/net/http/pprof/index.js +21 -21
- package/dist/gs/net/http/pprof/index.js.map +1 -1
- package/dist/gs/reflect/iter.js +1 -1
- package/dist/gs/reflect/iter.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -0
- package/dist/gs/reflect/type.js +53 -21
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/runtime/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.js +2 -2
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +1 -1
- package/dist/gs/slices/slices.js +37 -4
- package/dist/gs/slices/slices.js.map +1 -1
- package/gs/builtin/builtin.ts +11 -14
- package/gs/builtin/defer.ts +2 -2
- package/gs/builtin/hostio.ts +5 -5
- package/gs/builtin/map.ts +4 -1
- package/gs/builtin/runtime-contract.test.ts +25 -0
- package/gs/builtin/slice.test.ts +14 -0
- package/gs/builtin/slice.ts +64 -0
- package/gs/builtin/type.ts +72 -0
- package/gs/bytes/bytes.test.ts +14 -13
- package/gs/compress/gzip/index.test.ts +86 -0
- package/gs/compress/gzip/index.ts +297 -0
- package/gs/compress/gzip/meta.json +6 -0
- package/gs/compress/gzip/parity.json +45 -0
- package/gs/compress/zlib/index.test.ts +19 -5
- package/gs/compress/zlib/index.ts +16 -7
- package/gs/context/context.test.ts +3 -1
- package/gs/crypto/ecdh/index.test.ts +6 -2
- package/gs/crypto/ecdh/index.ts +49 -12
- package/gs/crypto/ed25519/index.ts +20 -7
- package/gs/crypto/rand/index.ts +6 -3
- package/gs/embed/index.test.ts +4 -4
- package/gs/embed/index.ts +9 -3
- package/gs/fmt/fmt.test.ts +29 -4
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
- package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
- package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
- package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
- package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
- package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
- package/gs/hash/fnv/index.test.ts +1 -8
- package/gs/hash/fnv/index.ts +27 -10
- package/gs/io/fs/glob.ts +14 -11
- package/gs/io/fs/meta.json +5 -0
- package/gs/io/fs/readdir.test.ts +63 -2
- package/gs/io/fs/readdir.ts +33 -30
- package/gs/io/fs/readlink.test.ts +2 -2
- package/gs/io/fs/readlink.ts +5 -2
- package/gs/io/fs/stat.test.ts +79 -0
- package/gs/io/fs/stat.ts +24 -10
- package/gs/io/fs/sub.test.ts +93 -0
- package/gs/io/fs/sub.ts +13 -13
- package/gs/io/fs/walk.ts +2 -2
- package/gs/maps/iter.ts +9 -9
- package/gs/maps/maps.ts +4 -4
- package/gs/math/bits/index.test.ts +10 -1
- package/gs/mime/index.test.ts +33 -15
- package/gs/mime/index.ts +9 -2
- package/gs/net/http/httptest/index.test.ts +17 -3
- package/gs/net/http/httptest/index.ts +8 -3
- package/gs/net/http/index.test.ts +851 -124
- package/gs/net/http/index.ts +612 -146
- package/gs/net/http/meta.json +3 -1
- package/gs/net/http/pprof/index.test.ts +4 -4
- package/gs/net/http/pprof/index.ts +43 -22
- package/gs/os/file_unix_js.test.ts +22 -0
- package/gs/reflect/iter.ts +4 -2
- package/gs/reflect/map.test.ts +56 -1
- package/gs/reflect/type.ts +76 -37
- package/gs/runtime/pprof/index.test.ts +7 -1
- package/gs/runtime/pprof/index.ts +5 -1
- package/gs/runtime/runtime.test.ts +7 -0
- package/gs/runtime/runtime.ts +2 -4
- package/gs/runtime/trace/index.test.ts +9 -1
- package/gs/runtime/trace/index.ts +5 -1
- package/gs/slices/meta.json +3 -0
- package/gs/slices/slices.test.ts +59 -21
- package/gs/slices/slices.ts +61 -20
- package/gs/strconv/complex.test.ts +17 -3
- package/gs/sync/atomic/doc_64.test.ts +2 -9
- package/gs/sync/sync.test.ts +18 -8
- package/gs/syscall/js/index.test.ts +9 -4
- package/package.json +5 -4
|
@@ -488,6 +488,181 @@ func TestCompilePackagesAwaitsOverrideAsyncFunctions(t *testing.T) {
|
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
+
func TestCompilePackagesAwaitsIOFSStatOverride(t *testing.T) {
|
|
492
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
493
|
+
"go.mod": "module example.test/iofsstat\n\ngo 1.25.3\n",
|
|
494
|
+
"main.go": strings.Join([]string{
|
|
495
|
+
"package main",
|
|
496
|
+
"import \"io/fs\"",
|
|
497
|
+
"type memFS struct{}",
|
|
498
|
+
"func (memFS) Open(name string) (fs.File, error) { return nil, fs.ErrNotExist }",
|
|
499
|
+
"func Use(fsys fs.FS) error {",
|
|
500
|
+
" _, err := fs.Stat(fsys, \"pkg\")",
|
|
501
|
+
" return err",
|
|
502
|
+
"}",
|
|
503
|
+
"func main() { _ = Use(memFS{}) }",
|
|
504
|
+
"",
|
|
505
|
+
}, "\n"),
|
|
506
|
+
})
|
|
507
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
508
|
+
comp, err := NewCompiler(&Config{
|
|
509
|
+
Dir: moduleDir,
|
|
510
|
+
OutputPath: out,
|
|
511
|
+
AllDependencies: true,
|
|
512
|
+
}, nil, nil)
|
|
513
|
+
if err != nil {
|
|
514
|
+
t.Fatal(err.Error())
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
518
|
+
t.Fatal(err.Error())
|
|
519
|
+
}
|
|
520
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "iofsstat", "main.gs.ts"))
|
|
521
|
+
if err != nil {
|
|
522
|
+
t.Fatal(err.Error())
|
|
523
|
+
}
|
|
524
|
+
text := string(content)
|
|
525
|
+
if !strings.Contains(text, "export async function Use(") {
|
|
526
|
+
t.Fatalf("fs.Stat caller was not marked async:\n%s", text)
|
|
527
|
+
}
|
|
528
|
+
if !strings.Contains(text, "await fs.Stat(") {
|
|
529
|
+
t.Fatalf("io/fs Stat override call was not awaited:\n%s", text)
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
func TestCompilePackagesAwaitsIOFSLstatOverride(t *testing.T) {
|
|
534
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
535
|
+
"go.mod": "module example.test/iofslstat\n\ngo 1.25.3\n",
|
|
536
|
+
"main.go": strings.Join([]string{
|
|
537
|
+
"package main",
|
|
538
|
+
"import \"io/fs\"",
|
|
539
|
+
"type memFS struct{}",
|
|
540
|
+
"func (memFS) Open(name string) (fs.File, error) { return nil, fs.ErrNotExist }",
|
|
541
|
+
"func Use(fsys fs.FS) error {",
|
|
542
|
+
" _, err := fs.Lstat(fsys, \"pkg\")",
|
|
543
|
+
" return err",
|
|
544
|
+
"}",
|
|
545
|
+
"func main() { _ = Use(memFS{}) }",
|
|
546
|
+
"",
|
|
547
|
+
}, "\n"),
|
|
548
|
+
})
|
|
549
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
550
|
+
comp, err := NewCompiler(&Config{
|
|
551
|
+
Dir: moduleDir,
|
|
552
|
+
OutputPath: out,
|
|
553
|
+
AllDependencies: true,
|
|
554
|
+
}, nil, nil)
|
|
555
|
+
if err != nil {
|
|
556
|
+
t.Fatal(err.Error())
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
560
|
+
t.Fatal(err.Error())
|
|
561
|
+
}
|
|
562
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "iofslstat", "main.gs.ts"))
|
|
563
|
+
if err != nil {
|
|
564
|
+
t.Fatal(err.Error())
|
|
565
|
+
}
|
|
566
|
+
text := string(content)
|
|
567
|
+
if !strings.Contains(text, "export async function Use(") {
|
|
568
|
+
t.Fatalf("fs.Lstat caller was not marked async:\n%s", text)
|
|
569
|
+
}
|
|
570
|
+
if !strings.Contains(text, "await fs.Lstat(") {
|
|
571
|
+
t.Fatalf("io/fs Lstat override call was not awaited:\n%s", text)
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
func TestCompilePackagesAwaitsIOFSSubOverride(t *testing.T) {
|
|
576
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
577
|
+
"go.mod": "module example.test/iofssub\n\ngo 1.25.3\n",
|
|
578
|
+
"main.go": strings.Join([]string{
|
|
579
|
+
"package main",
|
|
580
|
+
"import \"io/fs\"",
|
|
581
|
+
"type memFS struct{}",
|
|
582
|
+
"func (memFS) Open(name string) (fs.File, error) { return nil, fs.ErrNotExist }",
|
|
583
|
+
"func Use(fsys fs.FS) (fs.FS, error) {",
|
|
584
|
+
" return fs.Sub(fsys, \"pkg\")",
|
|
585
|
+
"}",
|
|
586
|
+
"func main() { _, _ = Use(memFS{}) }",
|
|
587
|
+
"",
|
|
588
|
+
}, "\n"),
|
|
589
|
+
})
|
|
590
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
591
|
+
comp, err := NewCompiler(&Config{
|
|
592
|
+
Dir: moduleDir,
|
|
593
|
+
OutputPath: out,
|
|
594
|
+
AllDependencies: true,
|
|
595
|
+
}, nil, nil)
|
|
596
|
+
if err != nil {
|
|
597
|
+
t.Fatal(err.Error())
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
601
|
+
t.Fatal(err.Error())
|
|
602
|
+
}
|
|
603
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "iofssub", "main.gs.ts"))
|
|
604
|
+
if err != nil {
|
|
605
|
+
t.Fatal(err.Error())
|
|
606
|
+
}
|
|
607
|
+
text := string(content)
|
|
608
|
+
if !strings.Contains(text, "export async function Use(") {
|
|
609
|
+
t.Fatalf("fs.Sub caller was not marked async:\n%s", text)
|
|
610
|
+
}
|
|
611
|
+
if !strings.Contains(text, "return await fs.Sub(") {
|
|
612
|
+
t.Fatalf("io/fs Sub override call was not awaited:\n%s", text)
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
func TestCompilePackagesAwaitsAsyncSlicesSortFuncComparator(t *testing.T) {
|
|
617
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
618
|
+
"go.mod": "module example.test/slicesasyncsort\n\ngo 1.25.3\n",
|
|
619
|
+
"main.go": strings.Join([]string{
|
|
620
|
+
"package main",
|
|
621
|
+
"import \"slices\"",
|
|
622
|
+
"type Comparator interface { Less(a, b int) bool }",
|
|
623
|
+
"func Use(c Comparator, values []int) {",
|
|
624
|
+
" slices.SortFunc(values, func(a, b int) int {",
|
|
625
|
+
" if c.Less(a, b) {",
|
|
626
|
+
" return -1",
|
|
627
|
+
" }",
|
|
628
|
+
" if c.Less(b, a) {",
|
|
629
|
+
" return 1",
|
|
630
|
+
" }",
|
|
631
|
+
" return 0",
|
|
632
|
+
" })",
|
|
633
|
+
"}",
|
|
634
|
+
"",
|
|
635
|
+
}, "\n"),
|
|
636
|
+
})
|
|
637
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
638
|
+
comp, err := NewCompiler(&Config{
|
|
639
|
+
Dir: moduleDir,
|
|
640
|
+
OutputPath: out,
|
|
641
|
+
AllDependencies: true,
|
|
642
|
+
}, nil, nil)
|
|
643
|
+
if err != nil {
|
|
644
|
+
t.Fatal(err.Error())
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
648
|
+
t.Fatal(err.Error())
|
|
649
|
+
}
|
|
650
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "slicesasyncsort", "main.gs.ts"))
|
|
651
|
+
if err != nil {
|
|
652
|
+
t.Fatal(err.Error())
|
|
653
|
+
}
|
|
654
|
+
text := string(content)
|
|
655
|
+
if !strings.Contains(text, "export async function Use") {
|
|
656
|
+
t.Fatalf("caller was not marked async for slices.SortFunc:\n%s", text)
|
|
657
|
+
}
|
|
658
|
+
if !strings.Contains(text, "await slices.SortFunc") {
|
|
659
|
+
t.Fatalf("slices.SortFunc call was not awaited:\n%s", text)
|
|
660
|
+
}
|
|
661
|
+
if !strings.Contains(text, "$.functionValue(async") {
|
|
662
|
+
t.Fatalf("SortFunc comparator was not lowered as async:\n%s", text)
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
491
666
|
func TestCompilePackagesAwaitsReflectValueCall(t *testing.T) {
|
|
492
667
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
493
668
|
"go.mod": "module example.test/reflectcallasync\n\ngo 1.25.3\n",
|
|
@@ -5,6 +5,7 @@ import (
|
|
|
5
5
|
"go/ast"
|
|
6
6
|
"os"
|
|
7
7
|
"path/filepath"
|
|
8
|
+
"slices"
|
|
8
9
|
"strings"
|
|
9
10
|
)
|
|
10
11
|
|
|
@@ -16,6 +17,13 @@ type protobufTypeScriptBinding struct {
|
|
|
16
17
|
hasOneof bool
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
type protobufTypeScriptBindingOneofCase struct {
|
|
21
|
+
groupLocalName string
|
|
22
|
+
caseLocalName string
|
|
23
|
+
branchCtor string
|
|
24
|
+
valueCtor string
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
func protobufTypeScriptBindings(semPkg *semanticPackage, options LoweringOptions) (map[string]protobufTypeScriptBinding, []Diagnostic) {
|
|
20
28
|
if semPkg == nil || semPkg.source == nil || !options.ProtobufTypeScriptBinding {
|
|
21
29
|
return nil, nil
|
|
@@ -291,6 +299,7 @@ func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTyp
|
|
|
291
299
|
source: binding.importSource,
|
|
292
300
|
sideEffect: true,
|
|
293
301
|
})
|
|
302
|
+
oneofCases := protobufTypeScriptBindingOneofCases(file)
|
|
294
303
|
var setupDecls []loweredDecl
|
|
295
304
|
for _, decl := range file.decls {
|
|
296
305
|
if decl.structType == nil {
|
|
@@ -306,7 +315,7 @@ func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTyp
|
|
|
306
315
|
if !ok {
|
|
307
316
|
continue
|
|
308
317
|
}
|
|
309
|
-
setup := protobufTypeScriptBindingStructSetupDecl(decl.structType, importAlias, messageName)
|
|
318
|
+
setup := protobufTypeScriptBindingStructSetupDecl(decl.structType, importAlias, messageName, oneofCases[decl.structType.name])
|
|
310
319
|
if setup.code != "" {
|
|
311
320
|
setupDecls = append(setupDecls, setup)
|
|
312
321
|
}
|
|
@@ -314,6 +323,102 @@ func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTyp
|
|
|
314
323
|
file.decls = append(file.decls, setupDecls...)
|
|
315
324
|
}
|
|
316
325
|
|
|
326
|
+
func protobufTypeScriptBindingOneofCases(file *loweredFile) map[string][]protobufTypeScriptBindingOneofCase {
|
|
327
|
+
parentByName := make(map[string]*loweredStruct)
|
|
328
|
+
for _, decl := range file.decls {
|
|
329
|
+
if decl.structType != nil {
|
|
330
|
+
parentByName[decl.structType.name] = decl.structType
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
out := make(map[string][]protobufTypeScriptBindingOneofCase)
|
|
334
|
+
for _, decl := range file.decls {
|
|
335
|
+
branch := decl.structType
|
|
336
|
+
if branch == nil || !strings.Contains(branch.name, "_") {
|
|
337
|
+
continue
|
|
338
|
+
}
|
|
339
|
+
parent := protobufTypeScriptBindingOneofParent(branch.name, parentByName)
|
|
340
|
+
if parent == nil {
|
|
341
|
+
continue
|
|
342
|
+
}
|
|
343
|
+
groups := protobufTypeScriptBindingOneofGroups(parent)
|
|
344
|
+
if len(groups) == 0 {
|
|
345
|
+
continue
|
|
346
|
+
}
|
|
347
|
+
groupLocalName := protobufTypeScriptBindingOneofCaseGroup(branch, parent, groups)
|
|
348
|
+
if groupLocalName == "" {
|
|
349
|
+
continue
|
|
350
|
+
}
|
|
351
|
+
for _, field := range branch.fields {
|
|
352
|
+
if !strings.Contains(field.tag, "oneof") {
|
|
353
|
+
continue
|
|
354
|
+
}
|
|
355
|
+
out[parent.name] = append(out[parent.name], protobufTypeScriptBindingOneofCase{
|
|
356
|
+
groupLocalName: groupLocalName,
|
|
357
|
+
caseLocalName: protobufTypeScriptBindingFieldLocalName(field),
|
|
358
|
+
branchCtor: branch.name,
|
|
359
|
+
valueCtor: protobufTypeScriptBindingFieldCtor(field),
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
for parentName := range out {
|
|
364
|
+
slices.SortFunc(out[parentName], func(left, right protobufTypeScriptBindingOneofCase) int {
|
|
365
|
+
if left.groupLocalName != right.groupLocalName {
|
|
366
|
+
return strings.Compare(left.groupLocalName, right.groupLocalName)
|
|
367
|
+
}
|
|
368
|
+
return strings.Compare(left.caseLocalName, right.caseLocalName)
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
return out
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
func protobufTypeScriptBindingOneofParent(branchName string, parents map[string]*loweredStruct) *loweredStruct {
|
|
375
|
+
var parent *loweredStruct
|
|
376
|
+
for name, candidate := range parents {
|
|
377
|
+
if name == branchName || !strings.HasPrefix(branchName, name+"_") {
|
|
378
|
+
continue
|
|
379
|
+
}
|
|
380
|
+
if parent == nil || len(name) > len(parent.name) {
|
|
381
|
+
parent = candidate
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return parent
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
func protobufTypeScriptBindingOneofGroups(parent *loweredStruct) map[string]string {
|
|
388
|
+
groups := make(map[string]string)
|
|
389
|
+
for _, field := range parent.fields {
|
|
390
|
+
if !strings.Contains(field.tag, "protobuf_oneof") {
|
|
391
|
+
continue
|
|
392
|
+
}
|
|
393
|
+
localName := protobufTypeScriptBindingTagValue(field.tag, "protobuf_oneof:\"")
|
|
394
|
+
if localName == "" {
|
|
395
|
+
groups[field.name] = protobufTypeScriptBindingFieldLocalName(field)
|
|
396
|
+
continue
|
|
397
|
+
}
|
|
398
|
+
groups[field.name] = protobufTypeScriptBindingProtoCamel(localName)
|
|
399
|
+
}
|
|
400
|
+
return groups
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
func protobufTypeScriptBindingOneofCaseGroup(branch, parent *loweredStruct, groups map[string]string) string {
|
|
404
|
+
if len(groups) == 1 {
|
|
405
|
+
for _, localName := range groups {
|
|
406
|
+
return localName
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
prefix := "is" + parent.name + "_"
|
|
410
|
+
for _, method := range branch.methods {
|
|
411
|
+
groupName, ok := strings.CutPrefix(method.name, prefix)
|
|
412
|
+
if !ok {
|
|
413
|
+
continue
|
|
414
|
+
}
|
|
415
|
+
if localName := groups[groupName]; localName != "" {
|
|
416
|
+
return localName
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return ""
|
|
420
|
+
}
|
|
421
|
+
|
|
317
422
|
func protobufTypeScriptBindingSyntheticMapEntry(name string) bool {
|
|
318
423
|
return strings.Contains(name, "_") && strings.HasSuffix(name, "Entry")
|
|
319
424
|
}
|
|
@@ -466,23 +571,66 @@ func protobufBindingParam(method *loweredFunction, idx int, fallback string) str
|
|
|
466
571
|
return method.params[idx].name
|
|
467
572
|
}
|
|
468
573
|
|
|
469
|
-
func protobufTypeScriptBindingStructSetupDecl(structType *loweredStruct, importAlias, messageName string) loweredDecl {
|
|
574
|
+
func protobufTypeScriptBindingStructSetupDecl(structType *loweredStruct, importAlias, messageName string, oneofCases []protobufTypeScriptBindingOneofCase) loweredDecl {
|
|
470
575
|
if structType == nil {
|
|
471
576
|
return loweredDecl{}
|
|
472
577
|
}
|
|
473
578
|
if messageName == "" {
|
|
474
579
|
messageName = structType.name
|
|
475
580
|
}
|
|
476
|
-
|
|
581
|
+
fieldEntries := make(map[string]string)
|
|
477
582
|
for _, field := range structType.fields {
|
|
478
583
|
ctor := protobufTypeScriptBindingFieldCtor(field)
|
|
479
584
|
if ctor == "" {
|
|
480
585
|
continue
|
|
481
586
|
}
|
|
482
|
-
|
|
587
|
+
fieldEntries[protobufTypeScriptBindingFieldLocalName(field)] = ctor
|
|
588
|
+
}
|
|
589
|
+
for _, oneofCase := range oneofCases {
|
|
590
|
+
if oneofCase.valueCtor != "" {
|
|
591
|
+
fieldEntries[oneofCase.caseLocalName] = oneofCase.valueCtor
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
fieldNames := make([]string, 0, len(fieldEntries))
|
|
595
|
+
for name := range fieldEntries {
|
|
596
|
+
fieldNames = append(fieldNames, name)
|
|
597
|
+
}
|
|
598
|
+
slices.Sort(fieldNames)
|
|
599
|
+
entries := make([]string, 0, len(fieldNames))
|
|
600
|
+
for _, name := range fieldNames {
|
|
601
|
+
entries = append(entries, strconvQuote(name)+": "+fieldEntries[name])
|
|
602
|
+
}
|
|
603
|
+
code := "(" + structType.name + " as any).__protobufTypeScriptMessage = " + importAlias + "." + messageName + ";\n" +
|
|
604
|
+
"(" + structType.name + " as any).__protobufTypeScriptFields = {" + strings.Join(entries, ", ") + "};"
|
|
605
|
+
if len(oneofCases) != 0 {
|
|
606
|
+
code += "\n(" + structType.name + " as any).__protobufTypeScriptOneofFields = " + protobufTypeScriptBindingOneofFieldsLiteral(oneofCases) + ";"
|
|
607
|
+
}
|
|
608
|
+
return loweredDecl{code: code}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
func protobufTypeScriptBindingOneofFieldsLiteral(oneofCases []protobufTypeScriptBindingOneofCase) string {
|
|
612
|
+
groups := make(map[string][]protobufTypeScriptBindingOneofCase)
|
|
613
|
+
for _, oneofCase := range oneofCases {
|
|
614
|
+
groups[oneofCase.groupLocalName] = append(groups[oneofCase.groupLocalName], oneofCase)
|
|
615
|
+
}
|
|
616
|
+
groupNames := make([]string, 0, len(groups))
|
|
617
|
+
for name := range groups {
|
|
618
|
+
groupNames = append(groupNames, name)
|
|
619
|
+
}
|
|
620
|
+
slices.Sort(groupNames)
|
|
621
|
+
entries := make([]string, 0, len(groupNames))
|
|
622
|
+
for _, groupName := range groupNames {
|
|
623
|
+
cases := groups[groupName]
|
|
624
|
+
slices.SortFunc(cases, func(left, right protobufTypeScriptBindingOneofCase) int {
|
|
625
|
+
return strings.Compare(left.caseLocalName, right.caseLocalName)
|
|
626
|
+
})
|
|
627
|
+
caseEntries := make([]string, 0, len(cases))
|
|
628
|
+
for _, oneofCase := range cases {
|
|
629
|
+
caseEntries = append(caseEntries, strconvQuote(oneofCase.caseLocalName)+": "+oneofCase.branchCtor)
|
|
630
|
+
}
|
|
631
|
+
entries = append(entries, strconvQuote(groupName)+": {"+strings.Join(caseEntries, ", ")+"}")
|
|
483
632
|
}
|
|
484
|
-
return
|
|
485
|
-
"(" + structType.name + " as any).__protobufTypeScriptFields = {" + strings.Join(entries, ", ") + "};"}
|
|
633
|
+
return "{" + strings.Join(entries, ", ") + "}"
|
|
486
634
|
}
|
|
487
635
|
|
|
488
636
|
func protobufTypeScriptBindingFieldLocalName(field loweredStructField) string {
|
|
@@ -204,7 +204,11 @@ func TestProtobufTypeScriptBindingEmitsMetadataForPreservedOneofFiles(t *testing
|
|
|
204
204
|
"type Wrapper_StringValue struct {\n"+
|
|
205
205
|
"\tStringValue string `protobuf:\"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof\"`\n"+
|
|
206
206
|
"}\n\n"+
|
|
207
|
-
"func (*Wrapper_StringValue) isWrapper_Choice() {}\n"
|
|
207
|
+
"func (*Wrapper_StringValue) isWrapper_Choice() {}\n\n"+
|
|
208
|
+
"type Wrapper_InnerValue struct {\n"+
|
|
209
|
+
"\tInnerValue *Inner `protobuf:\"bytes,3,opt,name=inner_value,json=innerValue,proto3,oneof\"`\n"+
|
|
210
|
+
"}\n\n"+
|
|
211
|
+
"func (*Wrapper_InnerValue) isWrapper_Choice() {}\n")
|
|
208
212
|
writeTestFile(t, dir, "foo.pb.ts", `export interface Inner {
|
|
209
213
|
name?: string
|
|
210
214
|
}
|
|
@@ -231,7 +235,8 @@ export const Wrapper = {} as any
|
|
|
231
235
|
binding := readTestFile(t, filepath.Join(out, "@goscript", "example.test", "oneofpb", "foo.pb.ts"))
|
|
232
236
|
if !strings.Contains(binding, `import * as __protobuf_ts`) ||
|
|
233
237
|
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptMessage = __protobuf_ts.Wrapper;`) ||
|
|
234
|
-
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptFields = {"inner": Inner};`)
|
|
238
|
+
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptFields = {"inner": Inner, "innerValue": Inner};`) ||
|
|
239
|
+
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptOneofFields = {"choice": {"innerValue": Wrapper_InnerValue, "stringValue": Wrapper_StringValue}};`) {
|
|
235
240
|
t.Fatalf("oneof-preserved protobuf file should still expose TypeScript metadata, got:\n%s", binding)
|
|
236
241
|
}
|
|
237
242
|
if strings.Contains(binding, `__protobuf_ts.Wrapper_StringValue`) {
|
|
@@ -88,6 +88,7 @@ const (
|
|
|
88
88
|
RuntimeHelperSliceToArray RuntimeHelper = "slice.sliceToArray"
|
|
89
89
|
RuntimeHelperSliceToArrayPointer RuntimeHelper = "slice.sliceToArrayPointer"
|
|
90
90
|
RuntimeHelperAppend RuntimeHelper = "slice.append"
|
|
91
|
+
RuntimeHelperAppendSlice RuntimeHelper = "slice.appendSlice"
|
|
91
92
|
RuntimeHelperCopy RuntimeHelper = "slice.copy"
|
|
92
93
|
RuntimeHelperAsArray RuntimeHelper = "slice.asArray"
|
|
93
94
|
RuntimeHelperStringToRunes RuntimeHelper = "slice.stringToRunes"
|
|
@@ -318,6 +319,7 @@ func runtimeHelperContracts() []RuntimeHelperContract {
|
|
|
318
319
|
runtimeHelper(RuntimeHelperSliceToArray, "sliceToArray", RuntimeHelperCategorySlice),
|
|
319
320
|
runtimeHelper(RuntimeHelperSliceToArrayPointer, "sliceToArrayPointer", RuntimeHelperCategorySlice),
|
|
320
321
|
runtimeHelper(RuntimeHelperAppend, "append", RuntimeHelperCategorySlice),
|
|
322
|
+
runtimeHelper(RuntimeHelperAppendSlice, "appendSlice", RuntimeHelperCategorySlice),
|
|
321
323
|
runtimeHelper(RuntimeHelperCopy, "copy", RuntimeHelperCategorySlice),
|
|
322
324
|
runtimeHelper(RuntimeHelperAsArray, "asArray", RuntimeHelperCategorySlice),
|
|
323
325
|
runtimeHelper(RuntimeHelperStringToRunes, "stringToRunes", RuntimeHelperCategorySlice),
|
|
@@ -24,6 +24,7 @@ func TestRuntimeContractOwnsBuiltinImportAndHelpers(t *testing.T) {
|
|
|
24
24
|
RuntimeHelperPointerValue: RuntimeHelperCategoryValue,
|
|
25
25
|
RuntimeHelperMakeSlice: RuntimeHelperCategorySlice,
|
|
26
26
|
RuntimeHelperAppend: RuntimeHelperCategorySlice,
|
|
27
|
+
RuntimeHelperAppendSlice: RuntimeHelperCategorySlice,
|
|
27
28
|
RuntimeHelperIndexAddress: RuntimeHelperCategorySlice,
|
|
28
29
|
RuntimeHelperIndexByteAddress: RuntimeHelperCategorySlice,
|
|
29
30
|
RuntimeHelperUnsafePointerRef: RuntimeHelperCategorySlice,
|
|
@@ -769,6 +769,9 @@ func (o *SemanticModelOwner) collectFunctionFacts(
|
|
|
769
769
|
if callUsesFunctionIdentifier(pkg, typed.Fun) {
|
|
770
770
|
markFunctionAsync(semFn, "function-identifier-call")
|
|
771
771
|
}
|
|
772
|
+
if callUsesInterfaceMethod(pkg, typed.Fun) {
|
|
773
|
+
markFunctionAsync(semFn, "interface-method-call")
|
|
774
|
+
}
|
|
772
775
|
if overrideFacts.IsMethodAsync(overrideCallPackage(pkg, typed.Fun), overrideCallMethod(pkg, typed.Fun)) {
|
|
773
776
|
markFunctionAsync(semFn, "override")
|
|
774
777
|
}
|
|
@@ -815,6 +818,9 @@ func recordImmediateFuncLitAsyncFacts(
|
|
|
815
818
|
if callUsesFunctionIdentifier(pkg, typed.Fun) {
|
|
816
819
|
markFunctionAsync(semFn, "async-function-literal-call")
|
|
817
820
|
}
|
|
821
|
+
if callUsesInterfaceMethod(pkg, typed.Fun) {
|
|
822
|
+
markFunctionAsync(semFn, "async-function-literal-call")
|
|
823
|
+
}
|
|
818
824
|
if called != nil {
|
|
819
825
|
calledFn := semanticFunctionFor(model, called)
|
|
820
826
|
if calledFn != nil && calledFn.async {
|
|
@@ -1156,6 +1162,10 @@ func exprMayNeedAwait(model *SemanticModel, pkg *packages.Package, expr ast.Expr
|
|
|
1156
1162
|
needsAwait = true
|
|
1157
1163
|
return false
|
|
1158
1164
|
}
|
|
1165
|
+
if callUsesInterfaceMethod(pkg, typed.Fun) {
|
|
1166
|
+
needsAwait = true
|
|
1167
|
+
return false
|
|
1168
|
+
}
|
|
1159
1169
|
if called := calledFunction(pkg, typed.Fun); called != nil {
|
|
1160
1170
|
semFn := semanticFunctionFor(model, called)
|
|
1161
1171
|
if semFn != nil && semFn.async {
|
|
@@ -1672,6 +1682,9 @@ func (o *SemanticModelOwner) applyInterfaceAsyncMethods(
|
|
|
1672
1682
|
}
|
|
1673
1683
|
for methodName, ifaceMethod := range graphEntry.ifaceMethods {
|
|
1674
1684
|
implMethod := graphEntry.implMethods[methodName]
|
|
1685
|
+
if isSyncErrorMethodFunc(ifaceMethod) || isSyncErrorMethodFunc(implMethod) {
|
|
1686
|
+
continue
|
|
1687
|
+
}
|
|
1675
1688
|
implFn := semanticFunctionFor(model, implMethod)
|
|
1676
1689
|
if implFn != nil && implFn.async {
|
|
1677
1690
|
model.markInterfaceMethodAsync(ifaceMethod)
|
|
@@ -1697,6 +1710,9 @@ func (o *SemanticModelOwner) applyAnonymousInterfaceAsyncMethods(
|
|
|
1697
1710
|
}
|
|
1698
1711
|
for methodName, ifaceMethod := range graphEntry.ifaceMethods {
|
|
1699
1712
|
implMethod := graphEntry.implMethods[methodName]
|
|
1713
|
+
if isSyncErrorMethodFunc(ifaceMethod) || isSyncErrorMethodFunc(implMethod) {
|
|
1714
|
+
continue
|
|
1715
|
+
}
|
|
1700
1716
|
if model.functionAsync(implMethod) {
|
|
1701
1717
|
model.markInterfaceMethodAsync(ifaceMethod)
|
|
1702
1718
|
}
|
|
@@ -604,6 +604,44 @@ func TestSemanticModelMarksFunctionIdentifierCallAsync(t *testing.T) {
|
|
|
604
604
|
}
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
+
func TestSemanticModelMarksInterfaceMethodCallAsync(t *testing.T) {
|
|
608
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
609
|
+
"go.mod": "module example.test/interfacecall\n\ngo 1.25.3\n",
|
|
610
|
+
"iface/controller.go": strings.Join([]string{
|
|
611
|
+
"package iface",
|
|
612
|
+
"import \"context\"",
|
|
613
|
+
"type Controller interface {",
|
|
614
|
+
" Execute(context.Context) error",
|
|
615
|
+
"}",
|
|
616
|
+
"",
|
|
617
|
+
}, "\n"),
|
|
618
|
+
"controller.go": strings.Join([]string{
|
|
619
|
+
"package interfacecall",
|
|
620
|
+
"import (",
|
|
621
|
+
" \"context\"",
|
|
622
|
+
" \"example.test/interfacecall/iface\"",
|
|
623
|
+
")",
|
|
624
|
+
"func Run(ctx context.Context, c iface.Controller) error {",
|
|
625
|
+
" return c.Execute(ctx)",
|
|
626
|
+
"}",
|
|
627
|
+
"",
|
|
628
|
+
}, "\n"),
|
|
629
|
+
})
|
|
630
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
631
|
+
Patterns: []string{".", "./iface"},
|
|
632
|
+
Dir: moduleDir,
|
|
633
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
634
|
+
DependencyMode: DependencyModeAll,
|
|
635
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
636
|
+
})
|
|
637
|
+
model := buildSemanticModel(t, graph)
|
|
638
|
+
run := requireDefinedFunc(t, graph, "example.test/interfacecall", "Run")
|
|
639
|
+
semFn := model.functions[run]
|
|
640
|
+
if semFn == nil || !semFn.async {
|
|
641
|
+
t.Fatalf("expected Run to be async after calling interface method, got %#v", semFn)
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
607
645
|
func buildSemanticModel(t *testing.T, graph *PackageGraph) *SemanticModel {
|
|
608
646
|
t.Helper()
|
|
609
647
|
|