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.
Files changed (160) hide show
  1. package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
  2. package/compiler/lowering.go +279 -16
  3. package/compiler/override-registry_test.go +175 -0
  4. package/compiler/protobuf-ts-binding.go +154 -6
  5. package/compiler/protobuf-ts-binding_test.go +7 -2
  6. package/compiler/runtime-contract.go +2 -0
  7. package/compiler/runtime-contract_test.go +1 -0
  8. package/compiler/semantic-model.go +16 -0
  9. package/compiler/semantic-model_test.go +38 -0
  10. package/compiler/skeleton_test.go +522 -17
  11. package/compiler/typescript-emitter.go +4 -0
  12. package/dist/gs/builtin/builtin.js +7 -9
  13. package/dist/gs/builtin/builtin.js.map +1 -1
  14. package/dist/gs/builtin/defer.js +2 -2
  15. package/dist/gs/builtin/hostio.js +5 -5
  16. package/dist/gs/builtin/hostio.js.map +1 -1
  17. package/dist/gs/builtin/map.js +2 -1
  18. package/dist/gs/builtin/map.js.map +1 -1
  19. package/dist/gs/builtin/slice.d.ts +3 -0
  20. package/dist/gs/builtin/slice.js +39 -0
  21. package/dist/gs/builtin/slice.js.map +1 -1
  22. package/dist/gs/builtin/type.js +49 -0
  23. package/dist/gs/builtin/type.js.map +1 -1
  24. package/dist/gs/compress/gzip/index.d.ts +41 -0
  25. package/dist/gs/compress/gzip/index.js +235 -0
  26. package/dist/gs/compress/gzip/index.js.map +1 -0
  27. package/dist/gs/compress/zlib/index.js +5 -2
  28. package/dist/gs/compress/zlib/index.js.map +1 -1
  29. package/dist/gs/crypto/ecdh/index.js +27 -8
  30. package/dist/gs/crypto/ecdh/index.js.map +1 -1
  31. package/dist/gs/crypto/ed25519/index.js +3 -3
  32. package/dist/gs/crypto/ed25519/index.js.map +1 -1
  33. package/dist/gs/crypto/rand/index.js +6 -3
  34. package/dist/gs/crypto/rand/index.js.map +1 -1
  35. package/dist/gs/embed/index.js +9 -3
  36. package/dist/gs/embed/index.js.map +1 -1
  37. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
  38. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
  39. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  40. package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
  41. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
  42. package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
  43. package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
  44. package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
  45. package/dist/gs/hash/fnv/index.js +13 -5
  46. package/dist/gs/hash/fnv/index.js.map +1 -1
  47. package/dist/gs/io/fs/glob.d.ts +3 -3
  48. package/dist/gs/io/fs/glob.js +9 -9
  49. package/dist/gs/io/fs/glob.js.map +1 -1
  50. package/dist/gs/io/fs/readdir.d.ts +2 -2
  51. package/dist/gs/io/fs/readdir.js +13 -74
  52. package/dist/gs/io/fs/readdir.js.map +1 -1
  53. package/dist/gs/io/fs/readlink.d.ts +1 -1
  54. package/dist/gs/io/fs/readlink.js +2 -2
  55. package/dist/gs/io/fs/readlink.js.map +1 -1
  56. package/dist/gs/io/fs/stat.d.ts +4 -2
  57. package/dist/gs/io/fs/stat.js +12 -73
  58. package/dist/gs/io/fs/stat.js.map +1 -1
  59. package/dist/gs/io/fs/sub.d.ts +2 -2
  60. package/dist/gs/io/fs/sub.js +11 -11
  61. package/dist/gs/io/fs/sub.js.map +1 -1
  62. package/dist/gs/io/fs/walk.js +2 -2
  63. package/dist/gs/io/fs/walk.js.map +1 -1
  64. package/dist/gs/maps/iter.js.map +1 -1
  65. package/dist/gs/maps/maps.js.map +1 -1
  66. package/dist/gs/mime/index.js +5 -2
  67. package/dist/gs/mime/index.js.map +1 -1
  68. package/dist/gs/net/http/httptest/index.js +6 -3
  69. package/dist/gs/net/http/httptest/index.js.map +1 -1
  70. package/dist/gs/net/http/index.d.ts +34 -18
  71. package/dist/gs/net/http/index.js +280 -63
  72. package/dist/gs/net/http/index.js.map +1 -1
  73. package/dist/gs/net/http/pprof/index.d.ts +5 -5
  74. package/dist/gs/net/http/pprof/index.js +21 -21
  75. package/dist/gs/net/http/pprof/index.js.map +1 -1
  76. package/dist/gs/reflect/iter.js +1 -1
  77. package/dist/gs/reflect/iter.js.map +1 -1
  78. package/dist/gs/reflect/type.d.ts +2 -0
  79. package/dist/gs/reflect/type.js +53 -21
  80. package/dist/gs/reflect/type.js.map +1 -1
  81. package/dist/gs/runtime/pprof/index.js.map +1 -1
  82. package/dist/gs/runtime/runtime.js +2 -2
  83. package/dist/gs/runtime/runtime.js.map +1 -1
  84. package/dist/gs/runtime/trace/index.js.map +1 -1
  85. package/dist/gs/slices/slices.d.ts +1 -1
  86. package/dist/gs/slices/slices.js +37 -4
  87. package/dist/gs/slices/slices.js.map +1 -1
  88. package/gs/builtin/builtin.ts +11 -14
  89. package/gs/builtin/defer.ts +2 -2
  90. package/gs/builtin/hostio.ts +5 -5
  91. package/gs/builtin/map.ts +4 -1
  92. package/gs/builtin/runtime-contract.test.ts +25 -0
  93. package/gs/builtin/slice.test.ts +14 -0
  94. package/gs/builtin/slice.ts +64 -0
  95. package/gs/builtin/type.ts +72 -0
  96. package/gs/bytes/bytes.test.ts +14 -13
  97. package/gs/compress/gzip/index.test.ts +86 -0
  98. package/gs/compress/gzip/index.ts +297 -0
  99. package/gs/compress/gzip/meta.json +6 -0
  100. package/gs/compress/gzip/parity.json +45 -0
  101. package/gs/compress/zlib/index.test.ts +19 -5
  102. package/gs/compress/zlib/index.ts +16 -7
  103. package/gs/context/context.test.ts +3 -1
  104. package/gs/crypto/ecdh/index.test.ts +6 -2
  105. package/gs/crypto/ecdh/index.ts +49 -12
  106. package/gs/crypto/ed25519/index.ts +20 -7
  107. package/gs/crypto/rand/index.ts +6 -3
  108. package/gs/embed/index.test.ts +4 -4
  109. package/gs/embed/index.ts +9 -3
  110. package/gs/fmt/fmt.test.ts +29 -4
  111. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
  112. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
  113. package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
  114. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
  115. package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
  116. package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
  117. package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
  118. package/gs/hash/fnv/index.test.ts +1 -8
  119. package/gs/hash/fnv/index.ts +27 -10
  120. package/gs/io/fs/glob.ts +14 -11
  121. package/gs/io/fs/meta.json +5 -0
  122. package/gs/io/fs/readdir.test.ts +63 -2
  123. package/gs/io/fs/readdir.ts +33 -30
  124. package/gs/io/fs/readlink.test.ts +2 -2
  125. package/gs/io/fs/readlink.ts +5 -2
  126. package/gs/io/fs/stat.test.ts +79 -0
  127. package/gs/io/fs/stat.ts +24 -10
  128. package/gs/io/fs/sub.test.ts +93 -0
  129. package/gs/io/fs/sub.ts +13 -13
  130. package/gs/io/fs/walk.ts +2 -2
  131. package/gs/maps/iter.ts +9 -9
  132. package/gs/maps/maps.ts +4 -4
  133. package/gs/math/bits/index.test.ts +10 -1
  134. package/gs/mime/index.test.ts +33 -15
  135. package/gs/mime/index.ts +9 -2
  136. package/gs/net/http/httptest/index.test.ts +17 -3
  137. package/gs/net/http/httptest/index.ts +8 -3
  138. package/gs/net/http/index.test.ts +851 -124
  139. package/gs/net/http/index.ts +612 -146
  140. package/gs/net/http/meta.json +3 -1
  141. package/gs/net/http/pprof/index.test.ts +4 -4
  142. package/gs/net/http/pprof/index.ts +43 -22
  143. package/gs/os/file_unix_js.test.ts +22 -0
  144. package/gs/reflect/iter.ts +4 -2
  145. package/gs/reflect/map.test.ts +56 -1
  146. package/gs/reflect/type.ts +76 -37
  147. package/gs/runtime/pprof/index.test.ts +7 -1
  148. package/gs/runtime/pprof/index.ts +5 -1
  149. package/gs/runtime/runtime.test.ts +7 -0
  150. package/gs/runtime/runtime.ts +2 -4
  151. package/gs/runtime/trace/index.test.ts +9 -1
  152. package/gs/runtime/trace/index.ts +5 -1
  153. package/gs/slices/meta.json +3 -0
  154. package/gs/slices/slices.test.ts +59 -21
  155. package/gs/slices/slices.ts +61 -20
  156. package/gs/strconv/complex.test.ts +17 -3
  157. package/gs/sync/atomic/doc_64.test.ts +2 -9
  158. package/gs/sync/sync.test.ts +18 -8
  159. package/gs/syscall/js/index.test.ts +9 -4
  160. package/package.json +5 -4
@@ -2491,7 +2491,7 @@ func TestCompilePackagesAssertsInterfaceMethodReceivers(t *testing.T) {
2491
2491
  text := string(content)
2492
2492
  for _, want := range []string{
2493
2493
  "export type FileInfo = {",
2494
- "$.println($.pointerValue<Exclude<FileInfo, null>>(info).Name())",
2494
+ "$.println(await $.pointerValue<Exclude<FileInfo, null>>(info).Name())",
2495
2495
  } {
2496
2496
  if !strings.Contains(text, want) {
2497
2497
  t.Fatalf("missing %q in generated output:\n%s", want, text)
@@ -2593,7 +2593,7 @@ func TestCompilePackagesBoxesTypedNilInterfaceValues(t *testing.T) {
2593
2593
  text := string(content)
2594
2594
  for _, want := range []string{
2595
2595
  "return $.interfaceValue<Animal | null>(FindDog(), \"*main.Dog\")",
2596
- "$.println($.pointerValue<Exclude<Animal, null>>(animal).Name())",
2596
+ "$.println(await $.pointerValue<Exclude<Animal, null>>(animal).Name())",
2597
2597
  "let a: Animal | null = $.interfaceValue<Animal | null>(dog, \"*main.Dog\")",
2598
2598
  } {
2599
2599
  if !strings.Contains(text, want) {
@@ -2700,16 +2700,16 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
2700
2700
  "public Get(): any",
2701
2701
  "export function NewBox(__typeArgs: $.GenericTypeArgs | undefined, value: any): Box",
2702
2702
  "export function ZeroValue(__typeArgs: $.GenericTypeArgs | undefined): any",
2703
- "export function CallString(__typeArgs: $.GenericTypeArgs | undefined, v: any): string",
2703
+ "export async function CallString(__typeArgs: $.GenericTypeArgs | undefined, v: any): globalThis.Promise<string>",
2704
2704
  "export function Sum<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): any",
2705
2705
  "export function Copy<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): $.Slice<T>",
2706
- "return $.append($.arrayToSlice<T>([]), ...(vals ?? []))",
2706
+ "return $.appendSlice($.arrayToSlice<T>([]), vals)",
2707
2707
  "let seen: Set = $.makeMap<number, {}>()",
2708
2708
  "$.mapSet(seen, 1, {})",
2709
2709
  "$.genericZero(__typeArgs, \"T\", null)",
2710
- "$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
2710
+ "await $.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
2711
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\" } }] }] }})",
2712
- "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)",
2713
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)",
2714
2714
  } {
2715
2715
  if !strings.Contains(text, want) {
@@ -2740,11 +2740,17 @@ func TestCompilePackagesInfersGenericTypeArgsFromNamedArgument(t *testing.T) {
2740
2740
  " f := entries[key.name].factory",
2741
2741
  " return f.(func() T)()",
2742
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
+ "}",
2743
2749
  "var loader = NewKey[Source](\"source\")",
2744
2750
  "func Use() int {",
2745
2751
  " Register(loader, func() Source { return &auto{} })",
2746
2752
  " src := Get(loader)",
2747
- " return src.Load()",
2753
+ " return src.Load() + GetTyped[int](&typedLoader[int]{value: 5})",
2748
2754
  "}",
2749
2755
  "",
2750
2756
  }, "\n"),
@@ -2766,8 +2772,9 @@ func TestCompilePackagesInfersGenericTypeArgsFromNamedArgument(t *testing.T) {
2766
2772
  text := string(content)
2767
2773
  for _, want := range []string{
2768
2774
  "await Get({T: { type: \"genericnamedarg.Source\", zero: () => null, methods: {Load: (receiver: any, ...args: any[]) => receiver.Load(...args)} }}, $.markAsStructValue($.cloneStructValue(loader)))",
2769
- "return await $.mustTypeAssert<(() => any | globalThis.Promise<any>) | null>(f, ({ kind: $.TypeKind.Function, params: [], results: [{ kind: $.TypeKind.Interface, methods: [] }] } as $.FunctionTypeInfo))!()",
2770
- "return $.pointerValue<Exclude<Source, null>>(src).Load()",
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()",
2771
2778
  } {
2772
2779
  if !strings.Contains(text, want) {
2773
2780
  t.Fatalf("missing %q in generated output:\n%s", want, text)
@@ -3054,12 +3061,16 @@ func TestCompilePackagesAwaitsFmtWriterOverrides(t *testing.T) {
3054
3061
  for _, want := range []string{
3055
3062
  "export async function Use",
3056
3063
  "await fmt.Fprintf(",
3064
+ "$.pointerValue<writer>(w).buf = $.appendSlice($.pointerValue<writer>(w).buf, p)",
3057
3065
  "return err",
3058
3066
  } {
3059
3067
  if !strings.Contains(text, want) {
3060
3068
  t.Fatalf("missing %q in generated output:\n%s", want, text)
3061
3069
  }
3062
3070
  }
3071
+ if strings.Contains(text, "...(p ?? [])") {
3072
+ t.Fatalf("append with slice expansion used JavaScript argument spreading:\n%s", text)
3073
+ }
3063
3074
  }
3064
3075
 
3065
3076
  func TestCompilePackagesImportsSelectedExternalFieldTypes(t *testing.T) {
@@ -3613,7 +3624,7 @@ func TestCompilePackagesPropagatesAsyncThroughInstantiatedNamedInterface(t *test
3613
3624
  }
3614
3625
  }
3615
3626
 
3616
- func TestCompilePackagesDoesNotAwaitUnmarkedAnonymousInterfaceMethod(t *testing.T) {
3627
+ func TestCompilePackagesAwaitsUnmarkedAnonymousInterfaceMethodInsideAsyncCaller(t *testing.T) {
3617
3628
  moduleDir := writePackageGraphFixture(t, map[string]string{
3618
3629
  "go.mod": "module example.test/anonymousifaceawait\n\ngo 1.25.3\n",
3619
3630
  "main.go": strings.Join([]string{
@@ -3647,8 +3658,8 @@ func TestCompilePackagesDoesNotAwaitUnmarkedAnonymousInterfaceMethod(t *testing.
3647
3658
  t.Fatal(err.Error())
3648
3659
  }
3649
3660
  text := string(content)
3650
- if strings.Contains(text, "return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)") {
3651
- t.Fatalf("anonymous interface method call without an async implementation was awaited:\n%s", text)
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)
3652
3663
  }
3653
3664
  }
3654
3665
 
@@ -3657,7 +3668,8 @@ func TestCompilePackagesDoesNotInheritAsyncIntoSyncFunctionLiteral(t *testing.T)
3657
3668
  "go.mod": "module example.test/syncfunclit\n\ngo 1.25.3\n",
3658
3669
  "main.go": strings.Join([]string{
3659
3670
  "package syncfunclit",
3660
- "type Directive interface{ GetDirective() any }",
3671
+ "type Directive struct{}",
3672
+ "func (Directive) GetDirective() any { return nil }",
3661
3673
  "type Bridge struct{ keep func(Directive) (bool, error) }",
3662
3674
  "func NewBridge(keep func(Directive) (bool, error)) *Bridge { return &Bridge{keep: keep} }",
3663
3675
  "func Execute(ch <-chan struct{}) error {",
@@ -3691,11 +3703,103 @@ func TestCompilePackagesDoesNotInheritAsyncIntoSyncFunctionLiteral(t *testing.T)
3691
3703
  t.Fatal(err.Error())
3692
3704
  }
3693
3705
  text := string(content)
3694
- if strings.Contains(text, "await $.pointerValue<Exclude<Directive, null>>(di).GetDirective()") {
3706
+ if strings.Contains(text, "await Directive.prototype.GetDirective.call(di)") {
3695
3707
  t.Fatalf("sync function literal inherited async await:\n%s", text)
3696
3708
  }
3697
3709
  }
3698
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
+
3699
3803
  func TestCompilePackagesMarksRangeFuncAsyncWhenBodyAwaits(t *testing.T) {
3700
3804
  moduleDir := writePackageGraphFixture(t, map[string]string{
3701
3805
  "go.mod": "module example.test/rangefuncawaitbody\n\ngo 1.25.3\n",
@@ -3917,6 +4021,179 @@ func TestCompilePackagesPropagatesAsyncInterfaceMethodsFromTestImports(t *testin
3917
4021
  }
3918
4022
  }
3919
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
+
3920
4197
  func TestCompilePackagesMarksSelectReturningIfElseCasesUnreachable(t *testing.T) {
3921
4198
  moduleDir := writePackageGraphFixture(t, map[string]string{
3922
4199
  "go.mod": "module example.test/select-if-else\n\ngo 1.25.3\n",
@@ -4151,6 +4428,148 @@ func TestCompilePackagesParenthesizesAsyncFieldReceivers(t *testing.T) {
4151
4428
  }
4152
4429
  }
4153
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
+
4154
4573
  func TestCompilePackagesScopesIfInitDeclarations(t *testing.T) {
4155
4574
  moduleDir := writePackageGraphFixture(t, map[string]string{
4156
4575
  "go.mod": "module example.test/ifinit\n\ngo 1.25.3\n",
@@ -4324,8 +4743,8 @@ func TestCompilePackagesLowersMethodValuesWithFixedParameters(t *testing.T) {
4324
4743
  }
4325
4744
  text := string(content)
4326
4745
  for _, want := range []string{
4327
- "((__receiver) => (n: number) => Counter_Add(__receiver, n))(c)",
4328
- "((__receiver) => () => __receiver.Run())(",
4746
+ "$.functionValue(((__receiver) => (n: number) => Counter_Add(__receiver, n))(c), ({ kind: $.TypeKind.Function",
4747
+ "$.functionValue(((__receiver) => () => __receiver.Run())(",
4329
4748
  } {
4330
4749
  if !strings.Contains(text, want) {
4331
4750
  t.Fatalf("missing %q in generated output:\n%s", want, text)
@@ -4336,6 +4755,53 @@ func TestCompilePackagesLowersMethodValuesWithFixedParameters(t *testing.T) {
4336
4755
  }
4337
4756
  }
4338
4757
 
4758
+ func TestCompilePackagesLowersSyncOverrideCallbackWithoutAsyncWrapper(t *testing.T) {
4759
+ moduleDir := writePackageGraphFixture(t, map[string]string{
4760
+ "go.mod": "module example.test/sync-callback\n\ngo 1.25.3\n",
4761
+ "main.go": strings.Join([]string{
4762
+ "package main",
4763
+ "import \"sort\"",
4764
+ "type Item interface {",
4765
+ " Name() string",
4766
+ "}",
4767
+ "type Items interface {",
4768
+ " Len() int",
4769
+ " Get(i int) Item",
4770
+ "}",
4771
+ "func Lookup(items Items, name string) int {",
4772
+ " return sort.Search(items.Len(), func(i int) bool {",
4773
+ " item := items.Get(i)",
4774
+ " if item == nil {",
4775
+ " return true",
4776
+ " }",
4777
+ " return item.Name() >= name",
4778
+ " })",
4779
+ "}",
4780
+ "",
4781
+ }, "\n"),
4782
+ })
4783
+ outputDir := filepath.Join(t.TempDir(), "output")
4784
+ comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
4785
+ if err != nil {
4786
+ t.Fatal(err.Error())
4787
+ }
4788
+
4789
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
4790
+ t.Fatal(err.Error())
4791
+ }
4792
+ content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "sync-callback", "main.gs.ts"))
4793
+ if err != nil {
4794
+ t.Fatal(err.Error())
4795
+ }
4796
+ text := string(content)
4797
+ if strings.Contains(text, "$.functionValue(async (i: number)") {
4798
+ t.Fatalf("sync override callback lowered as async:\n%s", text)
4799
+ }
4800
+ if !strings.Contains(text, "$.functionValue((i: number): boolean => {") {
4801
+ t.Fatalf("sync override callback was not lowered as a synchronous function value:\n%s", text)
4802
+ }
4803
+ }
4804
+
4339
4805
  func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testing.T) {
4340
4806
  moduleDir := writePackageGraphFixture(t, map[string]string{
4341
4807
  "go.mod": "module example.test/qualified\n\ngo 1.25.3\n",
@@ -4344,6 +4810,7 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
4344
4810
  "type Box struct {",
4345
4811
  " Value int",
4346
4812
  "}",
4813
+ "type Header map[string][]string",
4347
4814
  "",
4348
4815
  }, "\n"),
4349
4816
  "main.go": strings.Join([]string{
@@ -4355,6 +4822,7 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
4355
4822
  "type Holder struct {",
4356
4823
  " Box lib.Box",
4357
4824
  " Boxes []lib.Box",
4825
+ " Header lib.Header",
4358
4826
  " Fn func(lib.Box) (lib.Box, error)",
4359
4827
  " Ptr atomic.Pointer[func()]",
4360
4828
  "}",
@@ -4385,8 +4853,10 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
4385
4853
  for _, want := range []string{
4386
4854
  "Box: $.VarRef<lib.Box>",
4387
4855
  "Boxes: $.VarRef<$.Slice<lib.Box>>",
4856
+ "Header: $.VarRef<lib.Header>",
4388
4857
  "Fn: $.VarRef<((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null>",
4389
4858
  "Ptr: $.VarRef<atomic.Pointer<(() => void) | null>>",
4859
+ "Header: $.varRef(init?.Header ?? (null as unknown as lib.Header))",
4390
4860
  "$.markAsStructValue(new lib.Box())",
4391
4861
  "$.markAsStructValue(new atomic.Pointer<(() => void) | null>())",
4392
4862
  "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]>",
@@ -4511,7 +4981,7 @@ func TestCompilePackagesNormalizesWideIntegerReturnTargets(t *testing.T) {
4511
4981
  t.Fatal(err.Error())
4512
4982
  }
4513
4983
  text := string(content)
4514
- if !strings.Contains(text, "return $.uint($.pointerValue<Exclude<hash.Hash64, null>>(h).Sum64(), 64)") {
4984
+ if !strings.Contains(text, "return $.uint(await $.pointerValue<Exclude<hash.Hash64, null>>(h).Sum64(), 64)") {
4515
4985
  t.Fatalf("missing uint64 return normalization:\n%s", text)
4516
4986
  }
4517
4987
  }
@@ -4595,6 +5065,41 @@ func TestCompilePackagesUnwrapsOverridePointerMethodReceiver(t *testing.T) {
4595
5065
  }
4596
5066
  }
4597
5067
 
5068
+ func TestCompilePackagesUsesRuntimeValueForAbsentSelectedReceiverType(t *testing.T) {
5069
+ moduleDir := writePackageGraphFixture(t, map[string]string{
5070
+ "go.mod": "module example.test/selected-receiver-import\n\ngo 1.25.3\n",
5071
+ "main.go": strings.Join([]string{
5072
+ "package main",
5073
+ "import \"net/http\"",
5074
+ "func URLString(req *http.Request) string {",
5075
+ " return req.URL.String()",
5076
+ "}",
5077
+ "",
5078
+ }, "\n"),
5079
+ })
5080
+ outputDir := filepath.Join(t.TempDir(), "output")
5081
+ comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
5082
+ if err != nil {
5083
+ t.Fatal(err.Error())
5084
+ }
5085
+
5086
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
5087
+ t.Fatal(err.Error())
5088
+ }
5089
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "selected-receiver-import", "main.gs.ts")
5090
+ content, err := os.ReadFile(outputFile)
5091
+ if err != nil {
5092
+ t.Fatal(err.Error())
5093
+ }
5094
+ text := string(content)
5095
+ if strings.Contains(text, "URL.prototype.String.call") {
5096
+ t.Fatalf("selected receiver method call used unqualified type:\n%s", text)
5097
+ }
5098
+ if !strings.Contains(text, "$.pointerValue<http.Request>(req).URL.String()") {
5099
+ t.Fatalf("selected receiver method call did not use runtime value method:\n%s", text)
5100
+ }
5101
+ }
5102
+
4598
5103
  func TestCompilePackagesUnwrapsImportedArrayPackageVarReads(t *testing.T) {
4599
5104
  moduleDir := writePackageGraphFixture(t, map[string]string{
4600
5105
  "go.mod": "module example.test/imported-array-var\n\ngo 1.25.3\n",