goscript 0.2.1 → 0.2.3
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/runner.go +98 -0
- package/compiler/gotest/runner_test.go +45 -0
- package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
- package/compiler/lowering.go +227 -11
- package/compiler/override-registry_test.go +50 -0
- package/compiler/protobuf-ts-binding.go +155 -7
- package/compiler/protobuf-ts-binding_test.go +116 -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 +477 -16
- 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/zlib/index.js +5 -2
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/aes/index.d.ts +15 -0
- package/dist/gs/crypto/aes/index.js +57 -0
- package/dist/gs/crypto/aes/index.js.map +1 -0
- package/dist/gs/crypto/cipher/index.d.ts +41 -0
- package/dist/gs/crypto/cipher/index.js +255 -0
- package/dist/gs/crypto/cipher/index.js.map +1 -0
- 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/chacha20poly1305/index.d.ts +31 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
- 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 +8 -8
- 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/sub.js +4 -4
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.js +1 -1
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/io/io.js +18 -2
- package/dist/gs/io/io.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 +16 -4
- package/dist/gs/net/http/index.js +236 -40
- package/dist/gs/net/http/index.js.map +1 -1
- 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/debug/index.js +2 -1
- package/dist/gs/runtime/debug/index.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/go.mod +2 -2
- package/go.sum +2 -0
- package/gs/builtin/builtin.ts +11 -14
- package/gs/builtin/defer.ts +2 -2
- package/gs/builtin/hostio.test.ts +8 -3
- package/gs/builtin/hostio.ts +5 -7
- package/gs/builtin/map.ts +4 -1
- 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/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/aes/index.test.ts +120 -0
- package/gs/crypto/aes/index.ts +76 -0
- package/gs/crypto/cipher/index.ts +345 -0
- package/gs/crypto/cipher/meta.json +6 -0
- 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 +3 -3
- 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/chacha20poly1305/index.test.ts +91 -0
- package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
- 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 +13 -10
- package/gs/io/fs/meta.json +2 -0
- package/gs/io/fs/readdir.test.ts +63 -2
- package/gs/io/fs/readdir.ts +33 -30
- package/gs/io/fs/sub.ts +4 -4
- package/gs/io/fs/walk.ts +1 -1
- package/gs/io/io.test.ts +56 -1
- package/gs/io/io.ts +19 -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 +645 -123
- package/gs/net/http/index.ts +548 -113
- package/gs/net/http/pprof/index.ts +24 -6
- 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/debug/index.test.ts +32 -4
- package/gs/runtime/debug/index.ts +5 -2
- 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 +13 -5
|
@@ -1541,6 +1541,9 @@ func TestCompilePackagesLowersUnsafeBytePointerArithmetic(t *testing.T) {
|
|
|
1541
1541
|
if !strings.Contains(text, "$.arrayPointerFromIndexRef<number>($.indexRef($.pointerValue<number[]>(words), 0), 64, 4, 1)") {
|
|
1542
1542
|
t.Fatalf("missing byte-view array pointer conversion:\n%s", text)
|
|
1543
1543
|
}
|
|
1544
|
+
if !strings.Contains(text, "($.arrayPointerFromIndexRef<number>($.indexRef(dst!, 0), 64, 1, 1) as unknown as $.VarRef<Uint8Array> | null)!.value =") {
|
|
1545
|
+
t.Fatalf("missing non-null byte-view array pointer storage:\n%s", text)
|
|
1546
|
+
}
|
|
1544
1547
|
}
|
|
1545
1548
|
|
|
1546
1549
|
func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
@@ -2488,7 +2491,7 @@ func TestCompilePackagesAssertsInterfaceMethodReceivers(t *testing.T) {
|
|
|
2488
2491
|
text := string(content)
|
|
2489
2492
|
for _, want := range []string{
|
|
2490
2493
|
"export type FileInfo = {",
|
|
2491
|
-
"$.println($.pointerValue<Exclude<FileInfo, null>>(info).Name())",
|
|
2494
|
+
"$.println(await $.pointerValue<Exclude<FileInfo, null>>(info).Name())",
|
|
2492
2495
|
} {
|
|
2493
2496
|
if !strings.Contains(text, want) {
|
|
2494
2497
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -2590,7 +2593,7 @@ func TestCompilePackagesBoxesTypedNilInterfaceValues(t *testing.T) {
|
|
|
2590
2593
|
text := string(content)
|
|
2591
2594
|
for _, want := range []string{
|
|
2592
2595
|
"return $.interfaceValue<Animal | null>(FindDog(), \"*main.Dog\")",
|
|
2593
|
-
"$.println($.pointerValue<Exclude<Animal, null>>(animal).Name())",
|
|
2596
|
+
"$.println(await $.pointerValue<Exclude<Animal, null>>(animal).Name())",
|
|
2594
2597
|
"let a: Animal | null = $.interfaceValue<Animal | null>(dog, \"*main.Dog\")",
|
|
2595
2598
|
} {
|
|
2596
2599
|
if !strings.Contains(text, want) {
|
|
@@ -2697,16 +2700,16 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
|
|
|
2697
2700
|
"public Get(): any",
|
|
2698
2701
|
"export function NewBox(__typeArgs: $.GenericTypeArgs | undefined, value: any): Box",
|
|
2699
2702
|
"export function ZeroValue(__typeArgs: $.GenericTypeArgs | undefined): any",
|
|
2700
|
-
"export function CallString(__typeArgs: $.GenericTypeArgs | undefined, v: any): string",
|
|
2703
|
+
"export async function CallString(__typeArgs: $.GenericTypeArgs | undefined, v: any): globalThis.Promise<string>",
|
|
2701
2704
|
"export function Sum<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): any",
|
|
2702
2705
|
"export function Copy<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): $.Slice<T>",
|
|
2703
|
-
"return $.
|
|
2706
|
+
"return $.appendSlice($.arrayToSlice<T>([]), vals)",
|
|
2704
2707
|
"let seen: Set = $.makeMap<number, {}>()",
|
|
2705
2708
|
"$.mapSet(seen, 1, {})",
|
|
2706
2709
|
"$.genericZero(__typeArgs, \"T\", null)",
|
|
2707
|
-
"$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
|
|
2710
|
+
"await $.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
|
|
2708
2711
|
"ZeroValue({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }})",
|
|
2709
|
-
"CallString({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, zero)",
|
|
2712
|
+
"await CallString({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, zero)",
|
|
2710
2713
|
"Sum({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, null)",
|
|
2711
2714
|
} {
|
|
2712
2715
|
if !strings.Contains(text, want) {
|
|
@@ -2737,11 +2740,17 @@ func TestCompilePackagesInfersGenericTypeArgsFromNamedArgument(t *testing.T) {
|
|
|
2737
2740
|
" f := entries[key.name].factory",
|
|
2738
2741
|
" return f.(func() T)()",
|
|
2739
2742
|
"}",
|
|
2743
|
+
"type typedLoader[T any] struct { value T }",
|
|
2744
|
+
"func (t *typedLoader[T]) Load() T { return t.value }",
|
|
2745
|
+
"func GetTyped[T any](v any) T {",
|
|
2746
|
+
" src := v.(interface { Load() T })",
|
|
2747
|
+
" return src.Load()",
|
|
2748
|
+
"}",
|
|
2740
2749
|
"var loader = NewKey[Source](\"source\")",
|
|
2741
2750
|
"func Use() int {",
|
|
2742
2751
|
" Register(loader, func() Source { return &auto{} })",
|
|
2743
2752
|
" src := Get(loader)",
|
|
2744
|
-
" return src.Load()",
|
|
2753
|
+
" return src.Load() + GetTyped[int](&typedLoader[int]{value: 5})",
|
|
2745
2754
|
"}",
|
|
2746
2755
|
"",
|
|
2747
2756
|
}, "\n"),
|
|
@@ -2763,8 +2772,9 @@ func TestCompilePackagesInfersGenericTypeArgsFromNamedArgument(t *testing.T) {
|
|
|
2763
2772
|
text := string(content)
|
|
2764
2773
|
for _, want := range []string{
|
|
2765
2774
|
"await Get({T: { type: \"genericnamedarg.Source\", zero: () => null, methods: {Load: (receiver: any, ...args: any[]) => receiver.Load(...args)} }}, $.markAsStructValue($.cloneStructValue(loader)))",
|
|
2766
|
-
"return await $.mustTypeAssert<(() => any | globalThis.Promise<any>) | null>(f, ({ kind: $.TypeKind.Function, params: [], results: [{ kind: $.TypeKind.Interface, methods: [] }] } as $.FunctionTypeInfo))!()",
|
|
2767
|
-
"
|
|
2775
|
+
"return await $.mustTypeAssert<(() => any | globalThis.Promise<any>) | null>(f, ({ kind: $.TypeKind.Function, params: [], results: [__typeArgs?.[\"T\"]?.type ?? { kind: $.TypeKind.Interface, methods: [] }] } as $.FunctionTypeInfo))!()",
|
|
2776
|
+
"$.mustTypeAssert<any>(v, { kind: $.TypeKind.Interface, methods: [{ name: \"Load\", args: [], returns: [{ name: \"_r0\", type: __typeArgs?.[\"T\"]?.type ?? { kind: $.TypeKind.Interface, methods: [] } }] }] })",
|
|
2777
|
+
"return await $.pointerValue<Exclude<Source, null>>(src).Load()",
|
|
2768
2778
|
} {
|
|
2769
2779
|
if !strings.Contains(text, want) {
|
|
2770
2780
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -3051,12 +3061,16 @@ func TestCompilePackagesAwaitsFmtWriterOverrides(t *testing.T) {
|
|
|
3051
3061
|
for _, want := range []string{
|
|
3052
3062
|
"export async function Use",
|
|
3053
3063
|
"await fmt.Fprintf(",
|
|
3064
|
+
"$.pointerValue<writer>(w).buf = $.appendSlice($.pointerValue<writer>(w).buf, p)",
|
|
3054
3065
|
"return err",
|
|
3055
3066
|
} {
|
|
3056
3067
|
if !strings.Contains(text, want) {
|
|
3057
3068
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3058
3069
|
}
|
|
3059
3070
|
}
|
|
3071
|
+
if strings.Contains(text, "...(p ?? [])") {
|
|
3072
|
+
t.Fatalf("append with slice expansion used JavaScript argument spreading:\n%s", text)
|
|
3073
|
+
}
|
|
3060
3074
|
}
|
|
3061
3075
|
|
|
3062
3076
|
func TestCompilePackagesImportsSelectedExternalFieldTypes(t *testing.T) {
|
|
@@ -3436,7 +3450,7 @@ func TestCompilePackagesEmitsAsyncChannelsSelectAndDefer(t *testing.T) {
|
|
|
3436
3450
|
for _, want := range []string{
|
|
3437
3451
|
"Process(v: number): number | globalThis.Promise<number>",
|
|
3438
3452
|
"public async Process(v: number): globalThis.Promise<number>",
|
|
3439
|
-
"let ch = $.makeChannel<number>(1, 0, \"both\")",
|
|
3453
|
+
"let ch: $.Channel<number> | null = $.makeChannel<number>(1, 0, \"both\")",
|
|
3440
3454
|
"await $.chanSend($.pointerValue<Worker>(w).ch, v)",
|
|
3441
3455
|
"return await $.chanRecv($.pointerValue<Worker>(w).ch)",
|
|
3442
3456
|
"await using __defer = new $.AsyncDisposableStack()",
|
|
@@ -3610,7 +3624,7 @@ func TestCompilePackagesPropagatesAsyncThroughInstantiatedNamedInterface(t *test
|
|
|
3610
3624
|
}
|
|
3611
3625
|
}
|
|
3612
3626
|
|
|
3613
|
-
func
|
|
3627
|
+
func TestCompilePackagesAwaitsUnmarkedAnonymousInterfaceMethodInsideAsyncCaller(t *testing.T) {
|
|
3614
3628
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3615
3629
|
"go.mod": "module example.test/anonymousifaceawait\n\ngo 1.25.3\n",
|
|
3616
3630
|
"main.go": strings.Join([]string{
|
|
@@ -3644,8 +3658,8 @@ func TestCompilePackagesDoesNotAwaitUnmarkedAnonymousInterfaceMethod(t *testing.
|
|
|
3644
3658
|
t.Fatal(err.Error())
|
|
3645
3659
|
}
|
|
3646
3660
|
text := string(content)
|
|
3647
|
-
if strings.Contains(text, "return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)") {
|
|
3648
|
-
t.Fatalf("anonymous interface method call
|
|
3661
|
+
if !strings.Contains(text, "return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)") {
|
|
3662
|
+
t.Fatalf("anonymous interface method call inside async caller was not awaited:\n%s", text)
|
|
3649
3663
|
}
|
|
3650
3664
|
}
|
|
3651
3665
|
|
|
@@ -3654,7 +3668,8 @@ func TestCompilePackagesDoesNotInheritAsyncIntoSyncFunctionLiteral(t *testing.T)
|
|
|
3654
3668
|
"go.mod": "module example.test/syncfunclit\n\ngo 1.25.3\n",
|
|
3655
3669
|
"main.go": strings.Join([]string{
|
|
3656
3670
|
"package syncfunclit",
|
|
3657
|
-
"type Directive
|
|
3671
|
+
"type Directive struct{}",
|
|
3672
|
+
"func (Directive) GetDirective() any { return nil }",
|
|
3658
3673
|
"type Bridge struct{ keep func(Directive) (bool, error) }",
|
|
3659
3674
|
"func NewBridge(keep func(Directive) (bool, error)) *Bridge { return &Bridge{keep: keep} }",
|
|
3660
3675
|
"func Execute(ch <-chan struct{}) error {",
|
|
@@ -3688,11 +3703,103 @@ func TestCompilePackagesDoesNotInheritAsyncIntoSyncFunctionLiteral(t *testing.T)
|
|
|
3688
3703
|
t.Fatal(err.Error())
|
|
3689
3704
|
}
|
|
3690
3705
|
text := string(content)
|
|
3691
|
-
if strings.Contains(text, "await
|
|
3706
|
+
if strings.Contains(text, "await Directive.prototype.GetDirective.call(di)") {
|
|
3692
3707
|
t.Fatalf("sync function literal inherited async await:\n%s", text)
|
|
3693
3708
|
}
|
|
3694
3709
|
}
|
|
3695
3710
|
|
|
3711
|
+
func TestCompilePackagesMarksFunctionLiteralAsyncForInterfaceMethodCall(t *testing.T) {
|
|
3712
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3713
|
+
"go.mod": "module example.test/funclitifaceawait\n\ngo 1.25.3\n",
|
|
3714
|
+
"main.go": strings.Join([]string{
|
|
3715
|
+
"package funclitifaceawait",
|
|
3716
|
+
"type Ref struct{}",
|
|
3717
|
+
"type BlockWithRefs interface {",
|
|
3718
|
+
" ApplyBlockRef(uint32, *Ref) error",
|
|
3719
|
+
"}",
|
|
3720
|
+
"func Each(cb func(BlockWithRefs) error) error { return nil }",
|
|
3721
|
+
"func Copy(ref *Ref) error {",
|
|
3722
|
+
" return Each(func(block BlockWithRefs) error {",
|
|
3723
|
+
" if err := block.ApplyBlockRef(7, ref); err != nil {",
|
|
3724
|
+
" return err",
|
|
3725
|
+
" }",
|
|
3726
|
+
" return nil",
|
|
3727
|
+
" })",
|
|
3728
|
+
"}",
|
|
3729
|
+
"",
|
|
3730
|
+
}, "\n"),
|
|
3731
|
+
})
|
|
3732
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3733
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3734
|
+
if err != nil {
|
|
3735
|
+
t.Fatal(err.Error())
|
|
3736
|
+
}
|
|
3737
|
+
|
|
3738
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3739
|
+
t.Fatal(err.Error())
|
|
3740
|
+
}
|
|
3741
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "funclitifaceawait", "main.gs.ts")
|
|
3742
|
+
content, err := os.ReadFile(outputFile)
|
|
3743
|
+
if err != nil {
|
|
3744
|
+
t.Fatal(err.Error())
|
|
3745
|
+
}
|
|
3746
|
+
text := string(content)
|
|
3747
|
+
for _, want := range []string{
|
|
3748
|
+
"$.functionValue(async (block: BlockWithRefs | null): globalThis.Promise<$.GoError> => {",
|
|
3749
|
+
"let err = await $.pointerValue<Exclude<BlockWithRefs, null>>(block).ApplyBlockRef($.uint(7, 32), ref)",
|
|
3750
|
+
} {
|
|
3751
|
+
if !strings.Contains(text, want) {
|
|
3752
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3753
|
+
}
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
|
|
3757
|
+
func TestCompilePackagesMarksFunctionLiteralAsyncForInterfaceMethodTypeSwitch(t *testing.T) {
|
|
3758
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3759
|
+
"go.mod": "module example.test/funclittypeswitchawait\n\ngo 1.25.3\n",
|
|
3760
|
+
"main.go": strings.Join([]string{
|
|
3761
|
+
"package funclittypeswitchawait",
|
|
3762
|
+
"type GetPeer struct{}",
|
|
3763
|
+
"type Directive interface{ GetDirective() any }",
|
|
3764
|
+
"type Bridge struct{ keep func(Directive) (bool, error) }",
|
|
3765
|
+
"func NewBridge(keep func(Directive) (bool, error)) *Bridge { return &Bridge{keep: keep} }",
|
|
3766
|
+
"func Build() *Bridge {",
|
|
3767
|
+
" return NewBridge(func(di Directive) (bool, error) {",
|
|
3768
|
+
" switch di.GetDirective().(type) {",
|
|
3769
|
+
" case GetPeer:",
|
|
3770
|
+
" return false, nil",
|
|
3771
|
+
" }",
|
|
3772
|
+
" return true, nil",
|
|
3773
|
+
" })",
|
|
3774
|
+
"}",
|
|
3775
|
+
"",
|
|
3776
|
+
}, "\n"),
|
|
3777
|
+
})
|
|
3778
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3779
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3780
|
+
if err != nil {
|
|
3781
|
+
t.Fatal(err.Error())
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3784
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3785
|
+
t.Fatal(err.Error())
|
|
3786
|
+
}
|
|
3787
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "funclittypeswitchawait", "main.gs.ts")
|
|
3788
|
+
content, err := os.ReadFile(outputFile)
|
|
3789
|
+
if err != nil {
|
|
3790
|
+
t.Fatal(err.Error())
|
|
3791
|
+
}
|
|
3792
|
+
text := string(content)
|
|
3793
|
+
for _, want := range []string{
|
|
3794
|
+
"$.functionValue(async (di: Directive | null): globalThis.Promise<[boolean, $.GoError]> => {",
|
|
3795
|
+
"const __goscriptTypeSwitchValue = await $.pointerValue<Exclude<Directive, null>>(di).GetDirective()",
|
|
3796
|
+
} {
|
|
3797
|
+
if !strings.Contains(text, want) {
|
|
3798
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
|
|
3696
3803
|
func TestCompilePackagesMarksRangeFuncAsyncWhenBodyAwaits(t *testing.T) {
|
|
3697
3804
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3698
3805
|
"go.mod": "module example.test/rangefuncawaitbody\n\ngo 1.25.3\n",
|
|
@@ -3914,6 +4021,179 @@ func TestCompilePackagesPropagatesAsyncInterfaceMethodsFromTestImports(t *testin
|
|
|
3914
4021
|
}
|
|
3915
4022
|
}
|
|
3916
4023
|
|
|
4024
|
+
func TestCompilePackagesAwaitsAsyncInterfaceMethodSingleResultAssignment(t *testing.T) {
|
|
4025
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
4026
|
+
"go.mod": "module example.test/asyncifaceassign\n\ngo 1.25.3\n",
|
|
4027
|
+
"iface/controller.go": strings.Join([]string{
|
|
4028
|
+
"package iface",
|
|
4029
|
+
"import \"context\"",
|
|
4030
|
+
"type Controller interface {",
|
|
4031
|
+
" Execute(context.Context) error",
|
|
4032
|
+
"}",
|
|
4033
|
+
"",
|
|
4034
|
+
}, "\n"),
|
|
4035
|
+
"impl/controller.go": strings.Join([]string{
|
|
4036
|
+
"package impl",
|
|
4037
|
+
"import (",
|
|
4038
|
+
" \"context\"",
|
|
4039
|
+
" \"example.test/asyncifaceassign/iface\"",
|
|
4040
|
+
")",
|
|
4041
|
+
"type Controller struct { ch chan struct{} }",
|
|
4042
|
+
"func NewController() iface.Controller {",
|
|
4043
|
+
" return &Controller{ch: make(chan struct{}, 1)}",
|
|
4044
|
+
"}",
|
|
4045
|
+
"func (c *Controller) Execute(ctx context.Context) error {",
|
|
4046
|
+
" select {",
|
|
4047
|
+
" case <-c.ch:",
|
|
4048
|
+
" return nil",
|
|
4049
|
+
" case <-ctx.Done():",
|
|
4050
|
+
" return ctx.Err()",
|
|
4051
|
+
" }",
|
|
4052
|
+
"}",
|
|
4053
|
+
"",
|
|
4054
|
+
}, "\n"),
|
|
4055
|
+
"use.go": strings.Join([]string{
|
|
4056
|
+
"package asyncifaceassign",
|
|
4057
|
+
"import (",
|
|
4058
|
+
" \"context\"",
|
|
4059
|
+
" \"example.test/asyncifaceassign/iface\"",
|
|
4060
|
+
")",
|
|
4061
|
+
"func Run(ctx context.Context, c iface.Controller) error {",
|
|
4062
|
+
" err := c.Execute(ctx)",
|
|
4063
|
+
" return err",
|
|
4064
|
+
"}",
|
|
4065
|
+
"",
|
|
4066
|
+
}, "\n"),
|
|
4067
|
+
})
|
|
4068
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
4069
|
+
service := NewCompileService()
|
|
4070
|
+
_, err := service.Compile(context.Background(), &CompileRequest{
|
|
4071
|
+
Patterns: []string{".", "./iface", "./impl"},
|
|
4072
|
+
Dir: moduleDir,
|
|
4073
|
+
OutputPath: outputDir,
|
|
4074
|
+
DependencyMode: DependencyModeAll,
|
|
4075
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
4076
|
+
})
|
|
4077
|
+
if err != nil {
|
|
4078
|
+
t.Fatal(err.Error())
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4081
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncifaceassign", "use.gs.ts")
|
|
4082
|
+
content, err := os.ReadFile(outputFile)
|
|
4083
|
+
if err != nil {
|
|
4084
|
+
t.Fatal(err.Error())
|
|
4085
|
+
}
|
|
4086
|
+
text := string(content)
|
|
4087
|
+
if want := "let err = await $.pointerValue<Exclude<iface.Controller, null>>(c).Execute(ctx)"; !strings.Contains(text, want) {
|
|
4088
|
+
t.Fatalf("single-result async interface assignment was not awaited:\n%s", text)
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
|
|
4092
|
+
func TestCompilePackagesAwaitsInterfaceMethodCallInsideAsyncCallerWithoutKnownImplementation(t *testing.T) {
|
|
4093
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
4094
|
+
"go.mod": "module example.test/asyncifaceunknownimpl\n\ngo 1.25.3\n",
|
|
4095
|
+
"iface/controller.go": strings.Join([]string{
|
|
4096
|
+
"package iface",
|
|
4097
|
+
"import \"context\"",
|
|
4098
|
+
"type Controller interface {",
|
|
4099
|
+
" Execute(context.Context) error",
|
|
4100
|
+
"}",
|
|
4101
|
+
"",
|
|
4102
|
+
}, "\n"),
|
|
4103
|
+
"use.go": strings.Join([]string{
|
|
4104
|
+
"package asyncifaceunknownimpl",
|
|
4105
|
+
"import (",
|
|
4106
|
+
" \"context\"",
|
|
4107
|
+
" \"example.test/asyncifaceunknownimpl/iface\"",
|
|
4108
|
+
")",
|
|
4109
|
+
"func Run(ctx context.Context, c iface.Controller, ready <-chan struct{}) error {",
|
|
4110
|
+
" select {",
|
|
4111
|
+
" case <-ready:",
|
|
4112
|
+
" default:",
|
|
4113
|
+
" }",
|
|
4114
|
+
" err := c.Execute(ctx)",
|
|
4115
|
+
" return err",
|
|
4116
|
+
"}",
|
|
4117
|
+
"",
|
|
4118
|
+
}, "\n"),
|
|
4119
|
+
})
|
|
4120
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
4121
|
+
service := NewCompileService()
|
|
4122
|
+
_, err := service.Compile(context.Background(), &CompileRequest{
|
|
4123
|
+
Patterns: []string{".", "./iface"},
|
|
4124
|
+
Dir: moduleDir,
|
|
4125
|
+
OutputPath: outputDir,
|
|
4126
|
+
DependencyMode: DependencyModeAll,
|
|
4127
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
4128
|
+
})
|
|
4129
|
+
if err != nil {
|
|
4130
|
+
t.Fatal(err.Error())
|
|
4131
|
+
}
|
|
4132
|
+
|
|
4133
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncifaceunknownimpl", "use.gs.ts")
|
|
4134
|
+
content, err := os.ReadFile(outputFile)
|
|
4135
|
+
if err != nil {
|
|
4136
|
+
t.Fatal(err.Error())
|
|
4137
|
+
}
|
|
4138
|
+
text := string(content)
|
|
4139
|
+
if want := "let err = await $.pointerValue<Exclude<iface.Controller, null>>(c).Execute(ctx)"; !strings.Contains(text, want) {
|
|
4140
|
+
t.Fatalf("async caller did not await interface method with unknown implementation:\n%s", text)
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
func TestCompilePackagesMarksNamedFunctionAsyncForInterfaceMethodCallWithoutKnownImplementation(t *testing.T) {
|
|
4145
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
4146
|
+
"go.mod": "module example.test/syncifaceunknownimpl\n\ngo 1.25.3\n",
|
|
4147
|
+
"iface/controller.go": strings.Join([]string{
|
|
4148
|
+
"package iface",
|
|
4149
|
+
"import \"context\"",
|
|
4150
|
+
"type Controller interface {",
|
|
4151
|
+
" Execute(context.Context) error",
|
|
4152
|
+
"}",
|
|
4153
|
+
"",
|
|
4154
|
+
}, "\n"),
|
|
4155
|
+
"use.go": strings.Join([]string{
|
|
4156
|
+
"package syncifaceunknownimpl",
|
|
4157
|
+
"import (",
|
|
4158
|
+
" \"context\"",
|
|
4159
|
+
" \"example.test/syncifaceunknownimpl/iface\"",
|
|
4160
|
+
")",
|
|
4161
|
+
"func Run(ctx context.Context, c iface.Controller) error {",
|
|
4162
|
+
" err := c.Execute(ctx)",
|
|
4163
|
+
" return err",
|
|
4164
|
+
"}",
|
|
4165
|
+
"",
|
|
4166
|
+
}, "\n"),
|
|
4167
|
+
})
|
|
4168
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
4169
|
+
service := NewCompileService()
|
|
4170
|
+
_, err := service.Compile(context.Background(), &CompileRequest{
|
|
4171
|
+
Patterns: []string{".", "./iface"},
|
|
4172
|
+
Dir: moduleDir,
|
|
4173
|
+
OutputPath: outputDir,
|
|
4174
|
+
DependencyMode: DependencyModeAll,
|
|
4175
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
4176
|
+
})
|
|
4177
|
+
if err != nil {
|
|
4178
|
+
t.Fatal(err.Error())
|
|
4179
|
+
}
|
|
4180
|
+
|
|
4181
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "syncifaceunknownimpl", "use.gs.ts")
|
|
4182
|
+
content, err := os.ReadFile(outputFile)
|
|
4183
|
+
if err != nil {
|
|
4184
|
+
t.Fatal(err.Error())
|
|
4185
|
+
}
|
|
4186
|
+
text := string(content)
|
|
4187
|
+
for _, want := range []string{
|
|
4188
|
+
"export async function Run(ctx: context.Context | null, c: iface.Controller | null): globalThis.Promise<$.GoError>",
|
|
4189
|
+
"let err = await $.pointerValue<Exclude<iface.Controller, null>>(c).Execute(ctx)",
|
|
4190
|
+
} {
|
|
4191
|
+
if !strings.Contains(text, want) {
|
|
4192
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
|
|
3917
4197
|
func TestCompilePackagesMarksSelectReturningIfElseCasesUnreachable(t *testing.T) {
|
|
3918
4198
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3919
4199
|
"go.mod": "module example.test/select-if-else\n\ngo 1.25.3\n",
|
|
@@ -4148,6 +4428,148 @@ func TestCompilePackagesParenthesizesAsyncFieldReceivers(t *testing.T) {
|
|
|
4148
4428
|
}
|
|
4149
4429
|
}
|
|
4150
4430
|
|
|
4431
|
+
func TestCompilePackagesAwaitsAsyncMethodValuesInAssignmentsAndReceivers(t *testing.T) {
|
|
4432
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
4433
|
+
"go.mod": "module example.test/asyncmethodvalues\n\ngo 1.25.3\n",
|
|
4434
|
+
"main.go": strings.Join([]string{
|
|
4435
|
+
"package asyncmethodvalues",
|
|
4436
|
+
"import \"reflect\"",
|
|
4437
|
+
"type Entry struct { value any }",
|
|
4438
|
+
"type Holder struct { entry *Entry }",
|
|
4439
|
+
"func (e *Entry) WithField(key string, value any) *Entry {",
|
|
4440
|
+
" return e.WithFields(map[string]any{key: value})",
|
|
4441
|
+
"}",
|
|
4442
|
+
"func (e *Entry) WithFields(fields map[string]any) *Entry {",
|
|
4443
|
+
" for _, value := range fields {",
|
|
4444
|
+
" if t := reflect.TypeOf(value); t != nil {",
|
|
4445
|
+
" switch {",
|
|
4446
|
+
" case t.Kind() == reflect.Func:",
|
|
4447
|
+
" e.value = value",
|
|
4448
|
+
" }",
|
|
4449
|
+
" }",
|
|
4450
|
+
" }",
|
|
4451
|
+
" return e",
|
|
4452
|
+
"}",
|
|
4453
|
+
"func (e *Entry) Warn(msg string) {}",
|
|
4454
|
+
"func Use(entry *Entry) {",
|
|
4455
|
+
" le := entry.WithField(\"first\", func(){})",
|
|
4456
|
+
" h := Holder{entry: entry.WithField(\"holder\", func(){})}",
|
|
4457
|
+
" _ = h",
|
|
4458
|
+
" le.WithField(\"second\", func(){}).Warn(\"done\")",
|
|
4459
|
+
"}",
|
|
4460
|
+
"",
|
|
4461
|
+
}, "\n"),
|
|
4462
|
+
})
|
|
4463
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
4464
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
4465
|
+
if err != nil {
|
|
4466
|
+
t.Fatal(err.Error())
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4469
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
4470
|
+
t.Fatal(err.Error())
|
|
4471
|
+
}
|
|
4472
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncmethodvalues", "main.gs.ts")
|
|
4473
|
+
content, err := os.ReadFile(outputFile)
|
|
4474
|
+
if err != nil {
|
|
4475
|
+
t.Fatal(err.Error())
|
|
4476
|
+
}
|
|
4477
|
+
text := string(content)
|
|
4478
|
+
for _, want := range []string{
|
|
4479
|
+
"public async WithField(key: string, value: any): globalThis.Promise<Entry | $.VarRef<Entry> | null>",
|
|
4480
|
+
"let le: Entry | $.VarRef<Entry> | null = await Entry.prototype.WithField.call(entry, \"first\",",
|
|
4481
|
+
"const __goscriptLiteralField0 = await Entry.prototype.WithField.call(entry, \"holder\",",
|
|
4482
|
+
"Entry.prototype.Warn.call(await Entry.prototype.WithField.call(le, \"second\",",
|
|
4483
|
+
} {
|
|
4484
|
+
if !strings.Contains(text, want) {
|
|
4485
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
for _, bad := range []string{
|
|
4489
|
+
"let le: Entry | $.VarRef<Entry> | null = Entry.prototype.WithField.call",
|
|
4490
|
+
"const __goscriptLiteralField0 = Entry.prototype.WithField.call",
|
|
4491
|
+
"Entry.prototype.Warn.call(Entry.prototype.WithField.call",
|
|
4492
|
+
} {
|
|
4493
|
+
if strings.Contains(text, bad) {
|
|
4494
|
+
t.Fatalf("async method value was consumed without await at %q:\n%s", bad, text)
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
|
|
4499
|
+
func TestCompilePackagesKeepsErrorInterfaceErrorSynchronous(t *testing.T) {
|
|
4500
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
4501
|
+
"go.mod": "module example.test/syncerrorstring\n\ngo 1.25.3\n",
|
|
4502
|
+
"main.go": strings.Join([]string{
|
|
4503
|
+
"package syncerrorstring",
|
|
4504
|
+
"type wrappedError struct {",
|
|
4505
|
+
" cause error",
|
|
4506
|
+
" msg string",
|
|
4507
|
+
"}",
|
|
4508
|
+
"func (w *wrappedError) Error() string {",
|
|
4509
|
+
" return w.msg + \": \" + w.cause.Error()",
|
|
4510
|
+
"}",
|
|
4511
|
+
"type healthError struct {",
|
|
4512
|
+
" cause error",
|
|
4513
|
+
" health string",
|
|
4514
|
+
"}",
|
|
4515
|
+
"type HealthError interface {",
|
|
4516
|
+
" error",
|
|
4517
|
+
" GetHealth() string",
|
|
4518
|
+
"}",
|
|
4519
|
+
"func (h *healthError) Error() string {",
|
|
4520
|
+
" if h.cause != nil {",
|
|
4521
|
+
" return h.cause.Error()",
|
|
4522
|
+
" }",
|
|
4523
|
+
" return h.health",
|
|
4524
|
+
"}",
|
|
4525
|
+
"func (h *healthError) GetHealth() string { return h.health }",
|
|
4526
|
+
"type baseError string",
|
|
4527
|
+
"func (b baseError) Error() string { return string(b) }",
|
|
4528
|
+
"func NewWrapped() error {",
|
|
4529
|
+
" return &wrappedError{msg: \"load\", cause: &healthError{cause: baseError(\"missing\")}}",
|
|
4530
|
+
"}",
|
|
4531
|
+
"func ReadHealthError(h HealthError) string {",
|
|
4532
|
+
" return h.Error()",
|
|
4533
|
+
"}",
|
|
4534
|
+
"",
|
|
4535
|
+
}, "\n"),
|
|
4536
|
+
})
|
|
4537
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
4538
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
4539
|
+
if err != nil {
|
|
4540
|
+
t.Fatal(err.Error())
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
4544
|
+
t.Fatal(err.Error())
|
|
4545
|
+
}
|
|
4546
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "syncerrorstring", "main.gs.ts")
|
|
4547
|
+
content, err := os.ReadFile(outputFile)
|
|
4548
|
+
if err != nil {
|
|
4549
|
+
t.Fatal(err.Error())
|
|
4550
|
+
}
|
|
4551
|
+
text := string(content)
|
|
4552
|
+
for _, want := range []string{
|
|
4553
|
+
"public Error(): string {",
|
|
4554
|
+
"return ($.pointerValue<wrappedError>(w).msg + \": \") + $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<wrappedError>(w).cause).Error()",
|
|
4555
|
+
"return $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<healthError>(h).cause).Error()",
|
|
4556
|
+
} {
|
|
4557
|
+
if !strings.Contains(text, want) {
|
|
4558
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
for _, bad := range []string{
|
|
4562
|
+
"public async Error(): globalThis.Promise<string>",
|
|
4563
|
+
"await $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<wrappedError>(w).cause).Error()",
|
|
4564
|
+
"await $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<healthError>(h).cause).Error()",
|
|
4565
|
+
"await $.pointerValue<HealthError>(h).Error()",
|
|
4566
|
+
} {
|
|
4567
|
+
if strings.Contains(text, bad) {
|
|
4568
|
+
t.Fatalf("error stringification became async at %q:\n%s", bad, text)
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
|
|
4151
4573
|
func TestCompilePackagesScopesIfInitDeclarations(t *testing.T) {
|
|
4152
4574
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
4153
4575
|
"go.mod": "module example.test/ifinit\n\ngo 1.25.3\n",
|
|
@@ -4341,6 +4763,7 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
|
|
|
4341
4763
|
"type Box struct {",
|
|
4342
4764
|
" Value int",
|
|
4343
4765
|
"}",
|
|
4766
|
+
"type Header map[string][]string",
|
|
4344
4767
|
"",
|
|
4345
4768
|
}, "\n"),
|
|
4346
4769
|
"main.go": strings.Join([]string{
|
|
@@ -4352,6 +4775,7 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
|
|
|
4352
4775
|
"type Holder struct {",
|
|
4353
4776
|
" Box lib.Box",
|
|
4354
4777
|
" Boxes []lib.Box",
|
|
4778
|
+
" Header lib.Header",
|
|
4355
4779
|
" Fn func(lib.Box) (lib.Box, error)",
|
|
4356
4780
|
" Ptr atomic.Pointer[func()]",
|
|
4357
4781
|
"}",
|
|
@@ -4382,8 +4806,10 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
|
|
|
4382
4806
|
for _, want := range []string{
|
|
4383
4807
|
"Box: $.VarRef<lib.Box>",
|
|
4384
4808
|
"Boxes: $.VarRef<$.Slice<lib.Box>>",
|
|
4809
|
+
"Header: $.VarRef<lib.Header>",
|
|
4385
4810
|
"Fn: $.VarRef<((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null>",
|
|
4386
4811
|
"Ptr: $.VarRef<atomic.Pointer<(() => void) | null>>",
|
|
4812
|
+
"Header: $.varRef(init?.Header ?? (null as unknown as lib.Header))",
|
|
4387
4813
|
"$.markAsStructValue(new lib.Box())",
|
|
4388
4814
|
"$.markAsStructValue(new atomic.Pointer<(() => void) | null>())",
|
|
4389
4815
|
"export async function Use(fn: ((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null, box: lib.Box): globalThis.Promise<[lib.Box, $.GoError]>",
|
|
@@ -4508,7 +4934,7 @@ func TestCompilePackagesNormalizesWideIntegerReturnTargets(t *testing.T) {
|
|
|
4508
4934
|
t.Fatal(err.Error())
|
|
4509
4935
|
}
|
|
4510
4936
|
text := string(content)
|
|
4511
|
-
if !strings.Contains(text, "return $.uint($.pointerValue<Exclude<hash.Hash64, null>>(h).Sum64(), 64)") {
|
|
4937
|
+
if !strings.Contains(text, "return $.uint(await $.pointerValue<Exclude<hash.Hash64, null>>(h).Sum64(), 64)") {
|
|
4512
4938
|
t.Fatalf("missing uint64 return normalization:\n%s", text)
|
|
4513
4939
|
}
|
|
4514
4940
|
}
|
|
@@ -4592,6 +5018,41 @@ func TestCompilePackagesUnwrapsOverridePointerMethodReceiver(t *testing.T) {
|
|
|
4592
5018
|
}
|
|
4593
5019
|
}
|
|
4594
5020
|
|
|
5021
|
+
func TestCompilePackagesUsesRuntimeValueForAbsentSelectedReceiverType(t *testing.T) {
|
|
5022
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
5023
|
+
"go.mod": "module example.test/selected-receiver-import\n\ngo 1.25.3\n",
|
|
5024
|
+
"main.go": strings.Join([]string{
|
|
5025
|
+
"package main",
|
|
5026
|
+
"import \"net/http\"",
|
|
5027
|
+
"func URLString(req *http.Request) string {",
|
|
5028
|
+
" return req.URL.String()",
|
|
5029
|
+
"}",
|
|
5030
|
+
"",
|
|
5031
|
+
}, "\n"),
|
|
5032
|
+
})
|
|
5033
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
5034
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
5035
|
+
if err != nil {
|
|
5036
|
+
t.Fatal(err.Error())
|
|
5037
|
+
}
|
|
5038
|
+
|
|
5039
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
5040
|
+
t.Fatal(err.Error())
|
|
5041
|
+
}
|
|
5042
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "selected-receiver-import", "main.gs.ts")
|
|
5043
|
+
content, err := os.ReadFile(outputFile)
|
|
5044
|
+
if err != nil {
|
|
5045
|
+
t.Fatal(err.Error())
|
|
5046
|
+
}
|
|
5047
|
+
text := string(content)
|
|
5048
|
+
if strings.Contains(text, "URL.prototype.String.call") {
|
|
5049
|
+
t.Fatalf("selected receiver method call used unqualified type:\n%s", text)
|
|
5050
|
+
}
|
|
5051
|
+
if !strings.Contains(text, "$.pointerValue<http.Request>(req).URL.String()") {
|
|
5052
|
+
t.Fatalf("selected receiver method call did not use runtime value method:\n%s", text)
|
|
5053
|
+
}
|
|
5054
|
+
}
|
|
5055
|
+
|
|
4595
5056
|
func TestCompilePackagesUnwrapsImportedArrayPackageVarReads(t *testing.T) {
|
|
4596
5057
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
4597
5058
|
"go.mod": "module example.test/imported-array-var\n\ngo 1.25.3\n",
|
|
@@ -456,7 +456,11 @@ func renderStruct(b *strings.Builder, structType *loweredStruct, runtimeOwner *R
|
|
|
456
456
|
b.WriteString("init?.")
|
|
457
457
|
b.WriteString(field.name)
|
|
458
458
|
b.WriteString(" ?? ")
|
|
459
|
+
b.WriteString("(")
|
|
459
460
|
b.WriteString(field.zero)
|
|
461
|
+
b.WriteString(" as unknown as ")
|
|
462
|
+
b.WriteString(field.typ)
|
|
463
|
+
b.WriteString(")")
|
|
460
464
|
}
|
|
461
465
|
b.WriteString(")")
|
|
462
466
|
if idx != len(structType.fields)-1 {
|