goscript 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/goscript/cmd-test.go +104 -11
- package/cmd/goscript/cmd-test_test.go +1 -1
- package/cmd/goscript/cmd_compile.go +9 -0
- package/compiler/compile-request.go +31 -0
- package/compiler/compiler.go +1 -1
- package/compiler/compliance_test.go +0 -2
- package/compiler/config.go +2 -0
- package/compiler/gotest/package-result.go +2 -0
- package/compiler/gotest/request.go +85 -20
- package/compiler/gotest/runner.go +733 -96
- package/compiler/gotest/runner_test.go +647 -3
- package/compiler/lowered-program.go +9 -2
- package/compiler/lowering.go +2001 -345
- package/compiler/override-facts.go +77 -27
- package/compiler/override-registry.go +5 -4
- package/compiler/override-registry_test.go +135 -0
- package/compiler/package-graph_test.go +62 -7
- package/compiler/package-test-graph-variant.go +40 -16
- package/compiler/package-test-graph.go +0 -5
- package/compiler/package-test-graph_test.go +61 -3
- package/compiler/runtime-contract.go +40 -0
- package/compiler/semantic-model-types.go +16 -0
- package/compiler/semantic-model.go +336 -91
- package/compiler/semantic-model_test.go +50 -1
- package/compiler/service.go +9 -3
- package/compiler/skeleton_test.go +1921 -298
- package/compiler/tsworkspace/owner-process-unix_test.go +72 -0
- package/compiler/tsworkspace/owner.go +8 -0
- package/compiler/tsworkspace/tool-process-other.go +14 -0
- package/compiler/tsworkspace/tool-process-unix.go +19 -0
- package/compiler/typescript-emitter.go +122 -9
- package/dist/gs/builtin/builtin.d.ts +20 -1
- package/dist/gs/builtin/builtin.js +246 -26
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +24 -10
- package/dist/gs/builtin/channel.js +107 -25
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/defer.d.ts +1 -0
- package/dist/gs/builtin/defer.js +12 -2
- package/dist/gs/builtin/defer.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +9 -0
- package/dist/gs/builtin/hostio.js +25 -0
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/map.js +40 -6
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/print.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +43 -9
- package/dist/gs/builtin/slice.js +437 -234
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +2 -0
- package/dist/gs/builtin/type.js +47 -7
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +2 -0
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js +28 -28
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/iter.gs.js +13 -13
- package/dist/gs/bytes/iter.gs.js.map +1 -1
- package/dist/gs/compress/zlib/index.d.ts +26 -0
- package/dist/gs/compress/zlib/index.js +168 -0
- package/dist/gs/compress/zlib/index.js.map +1 -0
- package/dist/gs/context/context.d.ts +1 -1
- package/dist/gs/context/context.js +8 -3
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/ecdh/index.d.ts +52 -0
- package/dist/gs/crypto/ecdh/index.js +226 -0
- package/dist/gs/crypto/ecdh/index.js.map +1 -0
- package/dist/gs/crypto/ed25519/index.d.ts +34 -0
- package/dist/gs/crypto/ed25519/index.js +160 -0
- package/dist/gs/crypto/ed25519/index.js.map +1 -0
- package/dist/gs/crypto/internal/constanttime/index.d.ts +4 -0
- package/dist/gs/crypto/internal/constanttime/index.js +18 -0
- package/dist/gs/crypto/internal/constanttime/index.js.map +1 -0
- package/dist/gs/crypto/rand/index.d.ts +2 -0
- package/dist/gs/crypto/rand/index.js +85 -0
- package/dist/gs/crypto/rand/index.js.map +1 -1
- package/dist/gs/crypto/sha256/index.d.ts +8 -0
- package/dist/gs/crypto/sha256/index.js +118 -0
- package/dist/gs/crypto/sha256/index.js.map +1 -0
- package/dist/gs/crypto/sha512/index.d.ts +14 -0
- package/dist/gs/crypto/sha512/index.js +129 -0
- package/dist/gs/crypto/sha512/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +15 -0
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/errors/errors.js +29 -6
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +7 -7
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +52 -18
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +56 -20
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +57 -3
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +366 -1
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +20 -0
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js +134 -0
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.d.ts +3 -0
- package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js +50 -0
- package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js.map +1 -0
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js +3 -2
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.d.ts +27 -0
- package/dist/gs/github.com/mr-tron/base58/base58/index.js +172 -0
- package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -0
- package/dist/gs/github.com/zeebo/blake3/internal/consts/index.d.ts +21 -0
- package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js +22 -0
- package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js.map +1 -0
- package/dist/gs/go/token/index.js +11 -4
- package/dist/gs/go/token/index.js.map +1 -1
- package/dist/gs/hash/fnv/index.d.ts +57 -0
- package/dist/gs/hash/fnv/index.js +299 -0
- package/dist/gs/hash/fnv/index.js.map +1 -0
- package/dist/gs/hash/index.d.ts +17 -0
- package/dist/gs/hash/index.js +94 -0
- package/dist/gs/hash/index.js.map +1 -0
- package/dist/gs/io/fs/readlink.js +2 -6
- package/dist/gs/io/fs/readlink.js.map +1 -1
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/iter/iter.d.ts +3 -2
- package/dist/gs/iter/iter.js.map +1 -1
- package/dist/gs/maps/iter.d.ts +5 -5
- package/dist/gs/maps/iter.js +48 -21
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.d.ts +6 -6
- package/dist/gs/math/bits/index.js +14 -24
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/mime/index.js +3 -1
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.d.ts +20 -1
- package/dist/gs/net/http/httptest/index.js +83 -3
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +110 -6
- package/dist/gs/net/http/index.js +262 -16
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.d.ts +8 -0
- package/dist/gs/net/http/pprof/index.js +59 -0
- package/dist/gs/net/http/pprof/index.js.map +1 -0
- package/dist/gs/os/error.gs.js +9 -7
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.js +95 -15
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.d.ts +5 -3
- package/dist/gs/path/filepath/path.js +65 -10
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +3 -2
- package/dist/gs/reflect/index.js +2 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/iter.js +2 -2
- package/dist/gs/reflect/iter.js.map +1 -1
- package/dist/gs/reflect/map.js +26 -0
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +24 -5
- package/dist/gs/reflect/type.js +390 -38
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.d.ts +1 -0
- package/dist/gs/reflect/types.js +3 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/value.d.ts +4 -1
- package/dist/gs/reflect/value.js +39 -1
- package/dist/gs/reflect/value.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/debug/index.d.ts +39 -0
- package/dist/gs/runtime/debug/index.js +58 -0
- package/dist/gs/runtime/debug/index.js.map +1 -1
- package/dist/gs/runtime/pprof/index.d.ts +20 -0
- package/dist/gs/runtime/pprof/index.js +85 -0
- package/dist/gs/runtime/pprof/index.js.map +1 -0
- package/dist/gs/runtime/trace/index.d.ts +19 -0
- package/dist/gs/runtime/trace/index.js +64 -0
- package/dist/gs/runtime/trace/index.js.map +1 -0
- package/dist/gs/slices/slices.d.ts +24 -9
- package/dist/gs/slices/slices.js +229 -24
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/sort/slice.gs.d.ts +5 -3
- package/dist/gs/sort/slice.gs.js +55 -17
- package/dist/gs/sort/slice.gs.js.map +1 -1
- package/dist/gs/strings/builder.js +26 -17
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/iter.js +140 -75
- package/dist/gs/strings/iter.js.map +1 -1
- package/dist/gs/strings/replace.js +2 -2
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/strings/strings.js +52 -6
- package/dist/gs/strings/strings.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +6 -3
- package/dist/gs/sync/sync.js +39 -11
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/errors.d.ts +116 -112
- package/dist/gs/syscall/errors.js +38 -1
- package/dist/gs/syscall/errors.js.map +1 -1
- package/dist/gs/syscall/fs.d.ts +2 -8
- package/dist/gs/syscall/fs.js.map +1 -1
- package/dist/gs/syscall/js/index.js +20 -12
- package/dist/gs/syscall/js/index.js.map +1 -1
- package/dist/gs/syscall/types.d.ts +4 -1
- package/dist/gs/syscall/types.js.map +1 -1
- package/dist/gs/testing/testing.d.ts +4 -3
- package/dist/gs/testing/testing.js +21 -4
- package/dist/gs/testing/testing.js.map +1 -1
- package/dist/gs/time/time.js +22 -0
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/dist/gs/unique/index.js +7 -2
- package/dist/gs/unique/index.js.map +1 -1
- package/go.mod +8 -8
- package/go.sum +14 -23
- package/gs/builtin/builtin.ts +364 -37
- package/gs/builtin/channel.ts +161 -29
- package/gs/builtin/defer.ts +13 -2
- package/gs/builtin/hostio.test.ts +1 -0
- package/gs/builtin/hostio.ts +38 -0
- package/gs/builtin/map.ts +46 -6
- package/gs/builtin/print.ts +12 -3
- package/gs/builtin/runtime-contract.test.ts +257 -10
- package/gs/builtin/slice.test.ts +70 -0
- package/gs/builtin/slice.ts +566 -255
- package/gs/builtin/type.ts +53 -9
- package/gs/builtin/varRef.ts +2 -0
- package/gs/bytes/buffer.gs.ts +28 -28
- package/gs/bytes/iter.gs.ts +13 -14
- package/gs/compress/zlib/index.test.ts +28 -0
- package/gs/compress/zlib/index.ts +200 -0
- package/gs/compress/zlib/meta.json +3 -0
- package/gs/context/context.test.ts +31 -1
- package/gs/context/context.ts +9 -4
- package/gs/crypto/ecdh/index.test.ts +43 -0
- package/gs/crypto/ecdh/index.ts +274 -0
- package/gs/crypto/ed25519/index.test.ts +41 -0
- package/gs/crypto/ed25519/index.ts +238 -0
- package/gs/crypto/ed25519/meta.json +13 -0
- package/gs/crypto/internal/constanttime/index.test.ts +25 -0
- package/gs/crypto/internal/constanttime/index.ts +22 -0
- package/gs/crypto/rand/index.test.ts +89 -1
- package/gs/crypto/rand/index.ts +103 -1
- package/gs/crypto/rand/meta.json +4 -1
- package/gs/crypto/sha256/index.test.ts +78 -0
- package/gs/crypto/sha256/index.ts +150 -0
- package/gs/crypto/sha256/meta.json +9 -0
- package/gs/crypto/sha512/index.test.ts +31 -0
- package/gs/crypto/sha512/index.ts +161 -0
- package/gs/crypto/sha512/meta.json +11 -0
- package/gs/encoding/json/index.test.ts +25 -3
- package/gs/encoding/json/index.ts +21 -3
- package/gs/errors/errors.test.ts +4 -1
- package/gs/errors/errors.ts +32 -8
- package/gs/fmt/fmt.test.ts +3 -1
- package/gs/fmt/fmt.ts +1 -5
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +62 -7
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +78 -36
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +32 -11
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +122 -43
- package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
- package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +518 -4
- package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +6 -0
- package/gs/github.com/aperturerobotics/util/conc/index.test.ts +30 -0
- package/gs/github.com/aperturerobotics/util/conc/index.ts +172 -0
- package/gs/github.com/aperturerobotics/util/conc/meta.json +9 -0
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +1 -4
- package/gs/github.com/hack-pad/safejs/internal/catch/index.test.ts +35 -0
- package/gs/github.com/hack-pad/safejs/internal/catch/index.ts +65 -0
- package/gs/github.com/hack-pad/safejs/internal/catch/meta.json +9 -0
- package/gs/github.com/klauspost/compress/internal/le/index.test.ts +2 -1
- package/gs/github.com/klauspost/compress/internal/le/index.ts +6 -5
- package/gs/github.com/mr-tron/base58/base58/index.test.ts +70 -0
- package/gs/github.com/mr-tron/base58/base58/index.ts +231 -0
- package/gs/github.com/mr-tron/base58/base58/meta.json +3 -0
- package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +46 -0
- package/gs/github.com/zeebo/blake3/internal/consts/index.ts +26 -0
- package/gs/go/token/index.ts +17 -4
- package/gs/hash/fnv/index.test.ts +67 -0
- package/gs/hash/fnv/index.ts +351 -0
- package/gs/hash/fnv/meta.json +3 -0
- package/gs/hash/index.test.ts +37 -0
- package/gs/hash/index.ts +118 -0
- package/gs/hash/meta.json +5 -0
- package/gs/internal/byteorder/index.test.ts +6 -6
- package/gs/io/fs/readlink.ts +40 -48
- package/gs/io/fs/walk.ts +10 -2
- package/gs/io/io.ts +4 -1
- package/gs/iter/iter.ts +8 -2
- package/gs/maps/iter.ts +69 -26
- package/gs/maps/maps.test.ts +23 -0
- package/gs/maps/maps.ts +6 -6
- package/gs/math/bits/index.test.ts +20 -0
- package/gs/math/bits/index.ts +15 -28
- package/gs/mime/index.ts +8 -2
- package/gs/net/http/httptest/index.test.ts +53 -0
- package/gs/net/http/httptest/index.ts +98 -3
- package/gs/net/http/index.test.ts +129 -1
- package/gs/net/http/index.ts +370 -19
- package/gs/net/http/meta.json +6 -0
- package/gs/net/http/pprof/index.test.ts +47 -0
- package/gs/net/http/pprof/index.ts +65 -0
- package/gs/os/error.gs.ts +9 -10
- package/gs/os/error.test.ts +41 -0
- package/gs/os/file_unix_js.test.ts +55 -0
- package/gs/os/tempfile.gs.test.ts +37 -10
- package/gs/os/types_js.gs.ts +94 -15
- package/gs/path/filepath/match.ts +4 -1
- package/gs/path/filepath/meta.json +6 -0
- package/gs/path/filepath/path.test.ts +57 -2
- package/gs/path/filepath/path.ts +91 -12
- package/gs/reflect/field.test.ts +63 -0
- package/gs/reflect/index.ts +4 -1
- package/gs/reflect/iter.ts +2 -2
- package/gs/reflect/map.test.ts +24 -2
- package/gs/reflect/map.ts +35 -0
- package/gs/reflect/type.ts +543 -60
- package/gs/reflect/typefor.test.ts +100 -0
- package/gs/reflect/types.ts +3 -1
- package/gs/reflect/value.ts +50 -1
- package/gs/reflect/visiblefields.ts +1 -1
- package/gs/runtime/debug/index.test.ts +22 -1
- package/gs/runtime/debug/index.ts +88 -0
- package/gs/runtime/pprof/index.test.ts +36 -0
- package/gs/runtime/pprof/index.ts +104 -0
- package/gs/runtime/pprof/meta.json +6 -0
- package/gs/runtime/trace/index.test.ts +45 -0
- package/gs/runtime/trace/index.ts +97 -0
- package/gs/runtime/trace/meta.json +7 -0
- package/gs/slices/meta.json +2 -1
- package/gs/slices/slices.test.ts +86 -0
- package/gs/slices/slices.ts +284 -37
- package/gs/sort/slice.gs.ts +73 -23
- package/gs/sort/slice.test.ts +40 -0
- package/gs/strings/builder.test.ts +8 -0
- package/gs/strings/builder.ts +29 -17
- package/gs/strings/iter.test.ts +5 -7
- package/gs/strings/iter.ts +146 -71
- package/gs/strings/replace.test.ts +1 -4
- package/gs/strings/replace.ts +6 -6
- package/gs/strings/strings.test.ts +4 -0
- package/gs/strings/strings.ts +54 -6
- package/gs/sync/sync.test.ts +57 -1
- package/gs/sync/sync.ts +45 -13
- package/gs/syscall/errors.ts +158 -115
- package/gs/syscall/fs.ts +8 -8
- package/gs/syscall/js/index.ts +49 -22
- package/gs/syscall/net.test.ts +26 -0
- package/gs/syscall/types.ts +7 -2
- package/gs/testing/testing.test.ts +56 -0
- package/gs/testing/testing.ts +27 -10
- package/gs/time/meta.json +2 -2
- package/gs/time/time.test.ts +4 -0
- package/gs/time/time.ts +33 -2
- package/gs/unicode/unicode.test.ts +14 -3
- package/gs/unicode/unicode.ts +1 -5
- package/gs/unique/index.ts +9 -2
- package/package.json +3 -3
|
@@ -235,6 +235,44 @@ func TestCompilePackagesLazilyInitializesCrossFilePackageVars(t *testing.T) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
func TestCompilePackagesLazilyInitializesSameFileLaterPackageVars(t *testing.T) {
|
|
239
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
240
|
+
"go.mod": "module example.test/lazylatervars\n\ngo 1.25.3\n",
|
|
241
|
+
"main.go": strings.Join([]string{
|
|
242
|
+
"package main",
|
|
243
|
+
"type detail struct { n int }",
|
|
244
|
+
"var table = []detail{{n: later.n}}",
|
|
245
|
+
"var later = detail{n: 7}",
|
|
246
|
+
"func main() { println(table[0].n) }",
|
|
247
|
+
"",
|
|
248
|
+
}, "\n"),
|
|
249
|
+
})
|
|
250
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
251
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
252
|
+
if err != nil {
|
|
253
|
+
t.Fatal(err.Error())
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
257
|
+
t.Fatal(err.Error())
|
|
258
|
+
}
|
|
259
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazylatervars", "main.gs.ts")
|
|
260
|
+
content, err := os.ReadFile(outputFile)
|
|
261
|
+
if err != nil {
|
|
262
|
+
t.Fatal(err.Error())
|
|
263
|
+
}
|
|
264
|
+
text := string(content)
|
|
265
|
+
for _, want := range []string{
|
|
266
|
+
"export let table: $.Slice<detail> = undefined as unknown as $.Slice<detail>",
|
|
267
|
+
"export function __goscript_get_table(): $.Slice<detail>",
|
|
268
|
+
"export let later: detail = $.markAsStructValue(new detail({n: 7}))",
|
|
269
|
+
} {
|
|
270
|
+
if !strings.Contains(text, want) {
|
|
271
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
238
276
|
func TestCompilePackagesLazilyInitializesFunctionBodyPackageVarDependencies(t *testing.T) {
|
|
239
277
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
240
278
|
"go.mod": "module example.test/lazybodyvars\n\ngo 1.25.3\n",
|
|
@@ -278,17 +316,22 @@ func TestCompilePackagesLazilyInitializesFunctionBodyPackageVarDependencies(t *t
|
|
|
278
316
|
}
|
|
279
317
|
}
|
|
280
318
|
|
|
281
|
-
func
|
|
319
|
+
func TestCompilePackagesInitializesLazyAsyncPackageVarsBeforeInit(t *testing.T) {
|
|
282
320
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
283
|
-
"go.mod": "module example.test/
|
|
321
|
+
"go.mod": "module example.test/lazyasyncvars\n\ngo 1.25.3\n",
|
|
284
322
|
"main.go": strings.Join([]string{
|
|
285
|
-
"package
|
|
286
|
-
"
|
|
287
|
-
"
|
|
288
|
-
"
|
|
289
|
-
"func
|
|
290
|
-
"
|
|
323
|
+
"package main",
|
|
324
|
+
"import \"sync\"",
|
|
325
|
+
"var lock sync.Mutex",
|
|
326
|
+
"var first = makeFirst()",
|
|
327
|
+
"func makeFirst() int {",
|
|
328
|
+
" lock.Lock()",
|
|
329
|
+
" defer lock.Unlock()",
|
|
330
|
+
" return later",
|
|
291
331
|
"}",
|
|
332
|
+
"var later = 7",
|
|
333
|
+
"func init() { println(first) }",
|
|
334
|
+
"func main() {}",
|
|
292
335
|
"",
|
|
293
336
|
}, "\n"),
|
|
294
337
|
})
|
|
@@ -301,25 +344,36 @@ func TestCompilePackagesEmitsShadowedBuiltinCalls(t *testing.T) {
|
|
|
301
344
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
302
345
|
t.Fatal(err.Error())
|
|
303
346
|
}
|
|
304
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
347
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyasyncvars", "main.gs.ts")
|
|
305
348
|
content, err := os.ReadFile(outputFile)
|
|
306
349
|
if err != nil {
|
|
307
350
|
t.Fatal(err.Error())
|
|
308
351
|
}
|
|
309
352
|
text := string(content)
|
|
310
|
-
|
|
311
|
-
|
|
353
|
+
for _, want := range []string{
|
|
354
|
+
"async function __goscript_init_first(): globalThis.Promise<void>",
|
|
355
|
+
"first = await makeFirst()",
|
|
356
|
+
"export function __goscript_get_first(): number",
|
|
357
|
+
"await __goscript_init_first()",
|
|
358
|
+
"__goscriptInit0()",
|
|
359
|
+
} {
|
|
360
|
+
if !strings.Contains(text, want) {
|
|
361
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
362
|
+
}
|
|
312
363
|
}
|
|
313
364
|
}
|
|
314
365
|
|
|
315
|
-
func
|
|
366
|
+
func TestCompilePackagesAssignsLazyPackageVarsDirectly(t *testing.T) {
|
|
316
367
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
317
|
-
"go.mod": "module example.test/
|
|
368
|
+
"go.mod": "module example.test/lazyassign\n\ngo 1.25.3\n",
|
|
318
369
|
"main.go": strings.Join([]string{
|
|
319
|
-
"package
|
|
320
|
-
"
|
|
321
|
-
"
|
|
370
|
+
"package main",
|
|
371
|
+
"var table = []int{later}",
|
|
372
|
+
"var later = 1",
|
|
373
|
+
"func init() {",
|
|
374
|
+
" table = append(table, 2)",
|
|
322
375
|
"}",
|
|
376
|
+
"func main() { println(len(table)) }",
|
|
323
377
|
"",
|
|
324
378
|
}, "\n"),
|
|
325
379
|
})
|
|
@@ -332,174 +386,163 @@ func TestCompilePackagesQuotesRawStringLiterals(t *testing.T) {
|
|
|
332
386
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
333
387
|
t.Fatal(err.Error())
|
|
334
388
|
}
|
|
335
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
389
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyassign", "main.gs.ts")
|
|
336
390
|
content, err := os.ReadFile(outputFile)
|
|
337
391
|
if err != nil {
|
|
338
392
|
t.Fatal(err.Error())
|
|
339
393
|
}
|
|
340
394
|
text := string(content)
|
|
341
|
-
if !strings.Contains(text,
|
|
342
|
-
t.Fatalf("
|
|
395
|
+
if !strings.Contains(text, "table = $.append(__goscript_get_table(), 2)") {
|
|
396
|
+
t.Fatalf("missing direct lazy package var assignment:\n%s", text)
|
|
397
|
+
}
|
|
398
|
+
if strings.Contains(text, "__goscript_get_table() =") {
|
|
399
|
+
t.Fatalf("lazy getter used as assignment target:\n%s", text)
|
|
343
400
|
}
|
|
344
401
|
}
|
|
345
402
|
|
|
346
|
-
func
|
|
403
|
+
func TestCompilePackagesAssignsImportedPackageVarsThroughSetters(t *testing.T) {
|
|
347
404
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
348
|
-
"go.mod":
|
|
349
|
-
"
|
|
350
|
-
|
|
351
|
-
|
|
405
|
+
"go.mod": "module example.test/pkgvarassign\n\ngo 1.25.3\n",
|
|
406
|
+
"dep/dep.go": strings.Join([]string{
|
|
407
|
+
"package dep",
|
|
408
|
+
"var Count int",
|
|
409
|
+
"",
|
|
410
|
+
}, "\n"),
|
|
352
411
|
"main.go": strings.Join([]string{
|
|
353
|
-
"package
|
|
354
|
-
"import
|
|
355
|
-
"
|
|
356
|
-
"
|
|
357
|
-
"
|
|
358
|
-
"
|
|
359
|
-
"//go:embed binary.bin",
|
|
360
|
-
"var Binary []byte",
|
|
361
|
-
"func GetVersion() string {",
|
|
362
|
-
" return Version",
|
|
412
|
+
"package main",
|
|
413
|
+
"import \"example.test/pkgvarassign/dep\"",
|
|
414
|
+
"func bump() {",
|
|
415
|
+
" dep.Count = 1",
|
|
416
|
+
" dep.Count += 16",
|
|
417
|
+
" dep.Count++",
|
|
363
418
|
"}",
|
|
364
419
|
"",
|
|
365
420
|
}, "\n"),
|
|
366
421
|
})
|
|
367
422
|
outputDir := filepath.Join(t.TempDir(), "output")
|
|
368
|
-
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir
|
|
423
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
369
424
|
if err != nil {
|
|
370
425
|
t.Fatal(err.Error())
|
|
371
426
|
}
|
|
372
427
|
|
|
373
|
-
|
|
374
|
-
if err != nil {
|
|
428
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
375
429
|
t.Fatal(err.Error())
|
|
376
430
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
if _, err := os.Stat(filepath.Join(outputDir, "@goscript", "embed", "index.ts")); err != nil {
|
|
381
|
-
t.Fatalf("embed override missing from output: %v", err)
|
|
382
|
-
}
|
|
383
|
-
if _, err := os.Stat(filepath.Join(outputDir, "@goscript", "embed", "embed.gs.ts")); !os.IsNotExist(err) {
|
|
384
|
-
t.Fatalf("stdlib embed was emitted instead of override: %v", err)
|
|
385
|
-
}
|
|
386
|
-
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "embedblank", "main.gs.ts"))
|
|
431
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "pkgvarassign", "main.gs.ts")
|
|
432
|
+
content, err := os.ReadFile(outputFile)
|
|
387
433
|
if err != nil {
|
|
388
434
|
t.Fatal(err.Error())
|
|
389
435
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
436
|
+
text := string(content)
|
|
437
|
+
for _, want := range []string{
|
|
438
|
+
"dep.__goscript_set_Count(1)",
|
|
439
|
+
"dep.__goscript_set_Count(dep.Count + 16)",
|
|
440
|
+
"dep.__goscript_set_Count(dep.Count + 1)",
|
|
441
|
+
} {
|
|
442
|
+
if !strings.Contains(text, want) {
|
|
443
|
+
t.Fatalf("missing imported package var setter assignment %q:\n%s", want, text)
|
|
444
|
+
}
|
|
395
445
|
}
|
|
396
|
-
if
|
|
397
|
-
t.Fatalf("
|
|
446
|
+
if strings.Contains(text, "dep.Count +=") || strings.Contains(text, "dep.Count++") {
|
|
447
|
+
t.Fatalf("imported package var assigned directly:\n%s", text)
|
|
398
448
|
}
|
|
399
449
|
}
|
|
400
450
|
|
|
401
|
-
func
|
|
451
|
+
func TestCompilePackagesAliasesForInitShortDeclShadow(t *testing.T) {
|
|
402
452
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
403
|
-
"go.mod": "module example.test/
|
|
453
|
+
"go.mod": "module example.test/forinitshadow\n\ngo 1.25.3\n",
|
|
404
454
|
"main.go": strings.Join([]string{
|
|
405
455
|
"package main",
|
|
406
|
-
"
|
|
407
|
-
"
|
|
408
|
-
"
|
|
409
|
-
"
|
|
410
|
-
"
|
|
411
|
-
"
|
|
412
|
-
" println(localMessage())",
|
|
413
|
-
"}",
|
|
414
|
-
"",
|
|
415
|
-
}, "\n"),
|
|
416
|
-
"helper.go": strings.Join([]string{
|
|
417
|
-
"package main",
|
|
418
|
-
"func localMessage() string {",
|
|
419
|
-
" return \"from helper\"",
|
|
420
|
-
"}",
|
|
421
|
-
"",
|
|
422
|
-
}, "\n"),
|
|
423
|
-
"subpkg/subpkg.go": strings.Join([]string{
|
|
424
|
-
"package subpkg",
|
|
425
|
-
"type Builder struct {",
|
|
426
|
-
" Value string",
|
|
427
|
-
"}",
|
|
428
|
-
"func (b *Builder) Set(value string) {",
|
|
429
|
-
" b.Value = value",
|
|
430
|
-
"}",
|
|
431
|
-
"func Greet(name string) string {",
|
|
432
|
-
" return \"Hello, \" + name",
|
|
456
|
+
"func checksum(n int) int {",
|
|
457
|
+
" total := 0",
|
|
458
|
+
" for n := n - 4; total <= n; total++ {",
|
|
459
|
+
" total += n",
|
|
460
|
+
" }",
|
|
461
|
+
" return total + n",
|
|
433
462
|
"}",
|
|
434
463
|
"",
|
|
435
464
|
}, "\n"),
|
|
436
465
|
})
|
|
437
466
|
outputDir := filepath.Join(t.TempDir(), "output")
|
|
438
|
-
comp, err := NewCompiler(&Config{
|
|
439
|
-
Dir: moduleDir,
|
|
440
|
-
OutputPath: outputDir,
|
|
441
|
-
AllDependencies: true,
|
|
442
|
-
}, nil, nil)
|
|
467
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
443
468
|
if err != nil {
|
|
444
469
|
t.Fatal(err.Error())
|
|
445
470
|
}
|
|
446
471
|
|
|
447
|
-
|
|
448
|
-
if err != nil {
|
|
472
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
449
473
|
t.Fatal(err.Error())
|
|
450
474
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
}
|
|
454
|
-
mainFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "main.gs.ts")
|
|
455
|
-
mainContent, err := os.ReadFile(mainFile)
|
|
475
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "forinitshadow", "main.gs.ts")
|
|
476
|
+
content, err := os.ReadFile(outputFile)
|
|
456
477
|
if err != nil {
|
|
457
478
|
t.Fatal(err.Error())
|
|
458
479
|
}
|
|
459
|
-
|
|
460
|
-
|
|
480
|
+
text := string(content)
|
|
481
|
+
if strings.Contains(text, "for (let n = n - 4") {
|
|
482
|
+
t.Fatalf("for init short declaration references itself:\n%s", text)
|
|
461
483
|
}
|
|
462
|
-
if !
|
|
463
|
-
t.Fatalf("missing
|
|
484
|
+
if !regexp.MustCompile(`let __goscriptShadow\d+ = n\s+for \(let __goscriptShadow\d+ = __goscriptShadow\d+ - 4; total <= __goscriptShadow\d+; total\+\+\)`).MatchString(text) {
|
|
485
|
+
t.Fatalf("missing aliased for init shadow declaration:\n%s", text)
|
|
464
486
|
}
|
|
465
|
-
if !strings.Contains(
|
|
466
|
-
|
|
467
|
-
t.Fatalf("missing same-package helper import:\n%s", string(mainContent))
|
|
487
|
+
if !strings.Contains(text, "return total + n") {
|
|
488
|
+
t.Fatalf("outer n was not preserved after the loop:\n%s", text)
|
|
468
489
|
}
|
|
469
|
-
|
|
470
|
-
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
func TestCompilePackagesReadsShadowedVarRefStructFieldsOnce(t *testing.T) {
|
|
493
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
494
|
+
"go.mod": "module example.test/shadowvarreffield\n\ngo 1.25.3\n",
|
|
495
|
+
"main.go": strings.Join([]string{
|
|
496
|
+
"package main",
|
|
497
|
+
"type key struct { pad []byte }",
|
|
498
|
+
"func fill(k *key) error { return nil }",
|
|
499
|
+
"func size() int {",
|
|
500
|
+
" var key key",
|
|
501
|
+
" if err := fill(&key); err != nil {",
|
|
502
|
+
" return 0",
|
|
503
|
+
" }",
|
|
504
|
+
" return len(key.pad)",
|
|
505
|
+
"}",
|
|
506
|
+
"func main() { println(size()) }",
|
|
507
|
+
"",
|
|
508
|
+
}, "\n"),
|
|
509
|
+
})
|
|
510
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
511
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
471
512
|
if err != nil {
|
|
472
513
|
t.Fatal(err.Error())
|
|
473
514
|
}
|
|
474
|
-
|
|
475
|
-
|
|
515
|
+
|
|
516
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
517
|
+
t.Fatal(err.Error())
|
|
476
518
|
}
|
|
477
|
-
|
|
478
|
-
|
|
519
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "shadowvarreffield", "main.gs.ts")
|
|
520
|
+
content, err := os.ReadFile(outputFile)
|
|
479
521
|
if err != nil {
|
|
480
522
|
t.Fatal(err.Error())
|
|
481
523
|
}
|
|
482
|
-
|
|
483
|
-
|
|
524
|
+
text := string(content)
|
|
525
|
+
if !strings.Contains(text, "$.len(__goscriptShadow0.value.pad)") {
|
|
526
|
+
t.Fatalf("missing single dereference field read:\n%s", text)
|
|
527
|
+
}
|
|
528
|
+
if strings.Contains(text, ".value.value.pad") {
|
|
529
|
+
t.Fatalf("shadowed VarRef struct field was dereferenced twice:\n%s", text)
|
|
484
530
|
}
|
|
485
531
|
}
|
|
486
532
|
|
|
487
|
-
func
|
|
533
|
+
func TestCompilePackagesWrapsChannelSendInterfaceValues(t *testing.T) {
|
|
488
534
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
489
|
-
"go.mod": "module example.test/
|
|
535
|
+
"go.mod": "module example.test/chansendiface\n\ngo 1.25.3\n",
|
|
490
536
|
"main.go": strings.Join([]string{
|
|
491
537
|
"package main",
|
|
492
|
-
"type
|
|
493
|
-
"
|
|
494
|
-
"
|
|
495
|
-
"
|
|
496
|
-
"
|
|
497
|
-
"
|
|
498
|
-
" return values[i]",
|
|
499
|
-
"}",
|
|
500
|
-
"func Items() []*Item {",
|
|
501
|
-
" return []*Item{{N: 1}}",
|
|
538
|
+
"type item interface { Name() string }",
|
|
539
|
+
"type concrete struct{}",
|
|
540
|
+
"func (*concrete) Name() string { return \"ok\" }",
|
|
541
|
+
"func send(ch chan item) {",
|
|
542
|
+
" v := &concrete{}",
|
|
543
|
+
" ch <- v",
|
|
502
544
|
"}",
|
|
545
|
+
"func main() {}",
|
|
503
546
|
"",
|
|
504
547
|
}, "\n"),
|
|
505
548
|
})
|
|
@@ -509,53 +552,33 @@ func TestCompilePackagesEmitsIndexAddressRefs(t *testing.T) {
|
|
|
509
552
|
t.Fatal(err.Error())
|
|
510
553
|
}
|
|
511
554
|
|
|
512
|
-
_, err
|
|
513
|
-
if err != nil {
|
|
555
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
514
556
|
t.Fatal(err.Error())
|
|
515
557
|
}
|
|
516
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
558
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "chansendiface", "main.gs.ts")
|
|
517
559
|
content, err := os.ReadFile(outputFile)
|
|
518
560
|
if err != nil {
|
|
519
561
|
t.Fatal(err.Error())
|
|
520
562
|
}
|
|
521
563
|
text := string(content)
|
|
522
|
-
if !strings.Contains(text, "
|
|
523
|
-
t.Fatalf("missing
|
|
524
|
-
}
|
|
525
|
-
if !strings.Contains(text, "new Item({N: 1})") {
|
|
526
|
-
t.Fatalf("missing elided pointer composite literal:\n%s", text)
|
|
564
|
+
if !strings.Contains(text, "$.chanSend(ch, $.interfaceValue<item | null>(v, \"*main.concrete\"))") {
|
|
565
|
+
t.Fatalf("missing interface wrapper for channel send:\n%s", text)
|
|
527
566
|
}
|
|
528
567
|
}
|
|
529
568
|
|
|
530
|
-
func
|
|
569
|
+
func TestCompilePackagesBindsFuncLiteralVarRefParams(t *testing.T) {
|
|
531
570
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
532
|
-
"go.mod": "module example.test/
|
|
571
|
+
"go.mod": "module example.test/funclitvarref\n\ngo 1.25.3\n",
|
|
533
572
|
"main.go": strings.Join([]string{
|
|
534
573
|
"package main",
|
|
535
|
-
"type
|
|
536
|
-
"
|
|
537
|
-
" Value int `json:\"value\"`",
|
|
538
|
-
"}",
|
|
539
|
-
"func (c Counter) Read() int {",
|
|
540
|
-
" return c.Value",
|
|
541
|
-
"}",
|
|
542
|
-
"func (c *Counter) Set(v int) {",
|
|
543
|
-
" c.Value = v",
|
|
544
|
-
"}",
|
|
545
|
-
"func NewCounter() *Counter {",
|
|
546
|
-
" return &Counter{Value: 3}",
|
|
547
|
-
"}",
|
|
574
|
+
"type words []int",
|
|
575
|
+
"func (w *words) Add(v int) { *w = append(*w, v) }",
|
|
548
576
|
"func main() {",
|
|
549
|
-
"
|
|
550
|
-
"",
|
|
551
|
-
"
|
|
552
|
-
"
|
|
553
|
-
"
|
|
554
|
-
" pointer.Set(2)",
|
|
555
|
-
" NewCounter().Set(5)",
|
|
556
|
-
" var iface any = pointer",
|
|
557
|
-
" _, ok := iface.(*Counter)",
|
|
558
|
-
" println(copy.Read(), original.Read(), ok)",
|
|
577
|
+
" addLen := func(w words) int {",
|
|
578
|
+
" w.Add(7)",
|
|
579
|
+
" return len(w)",
|
|
580
|
+
" }",
|
|
581
|
+
" println(addLen(nil))",
|
|
559
582
|
"}",
|
|
560
583
|
"",
|
|
561
584
|
}, "\n"),
|
|
@@ -569,26 +592,16 @@ func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
|
569
592
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
570
593
|
t.Fatal(err.Error())
|
|
571
594
|
}
|
|
572
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
595
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "funclitvarref", "main.gs.ts")
|
|
573
596
|
content, err := os.ReadFile(outputFile)
|
|
574
597
|
if err != nil {
|
|
575
598
|
t.Fatal(err.Error())
|
|
576
599
|
}
|
|
577
600
|
text := string(content)
|
|
578
601
|
for _, want := range []string{
|
|
579
|
-
"
|
|
580
|
-
"
|
|
581
|
-
"
|
|
582
|
-
"public Read(): number",
|
|
583
|
-
"public Set(v: number): void",
|
|
584
|
-
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))",
|
|
585
|
-
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))\n\n\t// Copy should stay readable in generated output.\n\tlet copy",
|
|
586
|
-
"let copy = $.markAsStructValue($.cloneStructValue(original.value))",
|
|
587
|
-
"let pointer: Counter | $.VarRef<Counter> | null = original",
|
|
588
|
-
"$.pointerValue<Counter>(pointer).Set(2)",
|
|
589
|
-
"$.pointerValue<Counter>(NewCounter()).Set(5)",
|
|
590
|
-
"let [, ok] = $.typeAssertTuple<Counter | $.VarRef<Counter> | null>(iface, { kind: $.TypeKind.Pointer, elemType: \"main.Counter\" })",
|
|
591
|
-
"\"Value\": { type: { kind: $.TypeKind.Basic, name: \"int\" }, tag: \"json:\\\"value\\\"\" }",
|
|
602
|
+
"(__goscriptParam0: words): number => {",
|
|
603
|
+
"let w: $.VarRef<words> = $.varRef(__goscriptParam0)",
|
|
604
|
+
"words_Add(w, 7)",
|
|
592
605
|
} {
|
|
593
606
|
if !strings.Contains(text, want) {
|
|
594
607
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -596,18 +609,19 @@ func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
|
596
609
|
}
|
|
597
610
|
}
|
|
598
611
|
|
|
599
|
-
func
|
|
612
|
+
func TestCompilePackagesAnnotatesNewPointerShortDecls(t *testing.T) {
|
|
600
613
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
601
|
-
"go.mod": "module example.test/
|
|
614
|
+
"go.mod": "module example.test/newptrdecl\n\ngo 1.25.3\n",
|
|
602
615
|
"main.go": strings.Join([]string{
|
|
603
616
|
"package main",
|
|
617
|
+
"type OID []int",
|
|
618
|
+
"func use(*OID) {}",
|
|
604
619
|
"func main() {",
|
|
605
|
-
"
|
|
606
|
-
"
|
|
607
|
-
"
|
|
608
|
-
"
|
|
609
|
-
"
|
|
610
|
-
" println(x)",
|
|
620
|
+
" oid := new(OID)",
|
|
621
|
+
" if len(*oid) == 0 {",
|
|
622
|
+
" oid = nil",
|
|
623
|
+
" }",
|
|
624
|
+
" use(oid)",
|
|
611
625
|
"}",
|
|
612
626
|
"",
|
|
613
627
|
}, "\n"),
|
|
@@ -621,18 +635,591 @@ func TestCompilePackagesEmitsNestedPointerStorageAssertions(t *testing.T) {
|
|
|
621
635
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
622
636
|
t.Fatal(err.Error())
|
|
623
637
|
}
|
|
624
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
638
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "newptrdecl", "main.gs.ts")
|
|
625
639
|
content, err := os.ReadFile(outputFile)
|
|
626
640
|
if err != nil {
|
|
627
641
|
t.Fatal(err.Error())
|
|
628
642
|
}
|
|
629
643
|
text := string(content)
|
|
630
644
|
for _, want := range []string{
|
|
631
|
-
"let
|
|
632
|
-
"
|
|
633
|
-
"
|
|
634
|
-
|
|
635
|
-
|
|
645
|
+
"let oid: $.VarRef<OID> | null = $.varRef<OID>(null as OID)",
|
|
646
|
+
"oid = null",
|
|
647
|
+
"use(oid)",
|
|
648
|
+
} {
|
|
649
|
+
if !strings.Contains(text, want) {
|
|
650
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
func TestCompilePackagesEmitsShadowedBuiltinCalls(t *testing.T) {
|
|
656
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
657
|
+
"go.mod": "module example.test/shadowbuiltin\n\ngo 1.25.3\n",
|
|
658
|
+
"main.go": strings.Join([]string{
|
|
659
|
+
"package shadowbuiltin",
|
|
660
|
+
"type Value struct {",
|
|
661
|
+
" N int",
|
|
662
|
+
"}",
|
|
663
|
+
"func Build(new func() (*Value, error)) (*Value, error) {",
|
|
664
|
+
" return new()",
|
|
665
|
+
"}",
|
|
666
|
+
"",
|
|
667
|
+
}, "\n"),
|
|
668
|
+
})
|
|
669
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
670
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
671
|
+
if err != nil {
|
|
672
|
+
t.Fatal(err.Error())
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
676
|
+
t.Fatal(err.Error())
|
|
677
|
+
}
|
|
678
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "shadowbuiltin", "main.gs.ts")
|
|
679
|
+
content, err := os.ReadFile(outputFile)
|
|
680
|
+
if err != nil {
|
|
681
|
+
t.Fatal(err.Error())
|
|
682
|
+
}
|
|
683
|
+
text := string(content)
|
|
684
|
+
if !strings.Contains(text, "return await _new!()") {
|
|
685
|
+
t.Fatalf("shadowed builtin call was not emitted as a callable value:\n%s", text)
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
func TestCompilePackagesQuotesRawStringLiterals(t *testing.T) {
|
|
690
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
691
|
+
"go.mod": "module example.test/rawstrings\n\ngo 1.25.3\n",
|
|
692
|
+
"main.go": strings.Join([]string{
|
|
693
|
+
"package rawstrings",
|
|
694
|
+
"func Values() (string, string) {",
|
|
695
|
+
" return `\\u00`, `invalid escape char after \\`",
|
|
696
|
+
"}",
|
|
697
|
+
"",
|
|
698
|
+
}, "\n"),
|
|
699
|
+
})
|
|
700
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
701
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
702
|
+
if err != nil {
|
|
703
|
+
t.Fatal(err.Error())
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
707
|
+
t.Fatal(err.Error())
|
|
708
|
+
}
|
|
709
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "rawstrings", "main.gs.ts")
|
|
710
|
+
content, err := os.ReadFile(outputFile)
|
|
711
|
+
if err != nil {
|
|
712
|
+
t.Fatal(err.Error())
|
|
713
|
+
}
|
|
714
|
+
text := string(content)
|
|
715
|
+
if !strings.Contains(text, `return ["\\u00", "invalid escape char after \\"]`) {
|
|
716
|
+
t.Fatalf("raw string literals were not quoted for TypeScript:\n%s", text)
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
func TestCompilePackagesEmitsBinaryStringLiterals(t *testing.T) {
|
|
721
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
722
|
+
"go.mod": "module example.test/binarystrings\n\ngo 1.25.3\n",
|
|
723
|
+
"main.go": strings.Join([]string{
|
|
724
|
+
"package binarystrings",
|
|
725
|
+
"const DecodeMap = \"\\xff\\x80A\"",
|
|
726
|
+
"func Value() string {",
|
|
727
|
+
" return DecodeMap",
|
|
728
|
+
"}",
|
|
729
|
+
"",
|
|
730
|
+
}, "\n"),
|
|
731
|
+
})
|
|
732
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
733
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
734
|
+
if err != nil {
|
|
735
|
+
t.Fatal(err.Error())
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
739
|
+
t.Fatal(err.Error())
|
|
740
|
+
}
|
|
741
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "binarystrings", "main.gs.ts")
|
|
742
|
+
content, err := os.ReadFile(outputFile)
|
|
743
|
+
if err != nil {
|
|
744
|
+
t.Fatal(err.Error())
|
|
745
|
+
}
|
|
746
|
+
if !strings.Contains(string(content), "$.bytesToString(new Uint8Array([255, 128, 65]))") {
|
|
747
|
+
t.Fatalf("binary string literal was not emitted as byte-backed string:\n%s", string(content))
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
func TestCompilePackagesUsesEmbedOverride(t *testing.T) {
|
|
752
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
753
|
+
"go.mod": "module example.test/embedblank\n\ngo 1.25.3\n",
|
|
754
|
+
"version.txt": "1.2.3\n",
|
|
755
|
+
"version..txt": "4.5.6\n",
|
|
756
|
+
"binary.bin": string([]byte{0x00, 0xff, 0x80, 0x41}),
|
|
757
|
+
"main.go": strings.Join([]string{
|
|
758
|
+
"package embedblank",
|
|
759
|
+
"import _ \"embed\"",
|
|
760
|
+
"//go:embed version.txt",
|
|
761
|
+
"var Version string",
|
|
762
|
+
"//go:embed version..txt",
|
|
763
|
+
"var Dotted string",
|
|
764
|
+
"//go:embed binary.bin",
|
|
765
|
+
"var Binary []byte",
|
|
766
|
+
"func GetVersion() string {",
|
|
767
|
+
" return Version",
|
|
768
|
+
"}",
|
|
769
|
+
"",
|
|
770
|
+
}, "\n"),
|
|
771
|
+
})
|
|
772
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
773
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir, AllDependencies: true}, nil, nil)
|
|
774
|
+
if err != nil {
|
|
775
|
+
t.Fatal(err.Error())
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
779
|
+
if err != nil {
|
|
780
|
+
t.Fatal(err.Error())
|
|
781
|
+
}
|
|
782
|
+
if !slices.Contains(result.CopiedPackages, "embed") {
|
|
783
|
+
t.Fatalf("embed override was not copied: %#v", result.CopiedPackages)
|
|
784
|
+
}
|
|
785
|
+
if _, err := os.Stat(filepath.Join(outputDir, "@goscript", "embed", "index.ts")); err != nil {
|
|
786
|
+
t.Fatalf("embed override missing from output: %v", err)
|
|
787
|
+
}
|
|
788
|
+
if _, err := os.Stat(filepath.Join(outputDir, "@goscript", "embed", "embed.gs.ts")); !os.IsNotExist(err) {
|
|
789
|
+
t.Fatalf("stdlib embed was emitted instead of override: %v", err)
|
|
790
|
+
}
|
|
791
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "embedblank", "main.gs.ts"))
|
|
792
|
+
if err != nil {
|
|
793
|
+
t.Fatal(err.Error())
|
|
794
|
+
}
|
|
795
|
+
if !strings.Contains(string(content), "export let Version: string = \"1.2.3\\n\"") {
|
|
796
|
+
t.Fatalf("embedded string content was not emitted:\n%s", string(content))
|
|
797
|
+
}
|
|
798
|
+
if !strings.Contains(string(content), "export let Dotted: string = \"4.5.6\\n\"") {
|
|
799
|
+
t.Fatalf("embedded dotted filename content was not emitted:\n%s", string(content))
|
|
800
|
+
}
|
|
801
|
+
if !strings.Contains(string(content), "export let Binary: $.Slice<number> = new Uint8Array([0, 255, 128, 65])") {
|
|
802
|
+
t.Fatalf("embedded binary content was not emitted as byte values:\n%s", string(content))
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
func TestCompilePackagesEmitsPackageLocalImport(t *testing.T) {
|
|
807
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
808
|
+
"go.mod": "module example.test/imports\n\ngo 1.25.3\n",
|
|
809
|
+
"main.go": strings.Join([]string{
|
|
810
|
+
"package main",
|
|
811
|
+
"import \"example.test/imports/subpkg\"",
|
|
812
|
+
"func main() {",
|
|
813
|
+
" var b subpkg.Builder",
|
|
814
|
+
" b.Set(\"built\")",
|
|
815
|
+
" println(b.Value)",
|
|
816
|
+
" println(subpkg.Greet(\"world\"))",
|
|
817
|
+
" println(localMessage())",
|
|
818
|
+
"}",
|
|
819
|
+
"",
|
|
820
|
+
}, "\n"),
|
|
821
|
+
"helper.go": strings.Join([]string{
|
|
822
|
+
"package main",
|
|
823
|
+
"func localMessage() string {",
|
|
824
|
+
" return \"from helper\"",
|
|
825
|
+
"}",
|
|
826
|
+
"",
|
|
827
|
+
}, "\n"),
|
|
828
|
+
"subpkg/subpkg.go": strings.Join([]string{
|
|
829
|
+
"package subpkg",
|
|
830
|
+
"type Builder struct {",
|
|
831
|
+
" Value string",
|
|
832
|
+
"}",
|
|
833
|
+
"func (b *Builder) Set(value string) {",
|
|
834
|
+
" b.Value = value",
|
|
835
|
+
"}",
|
|
836
|
+
"func Greet(name string) string {",
|
|
837
|
+
" return \"Hello, \" + name",
|
|
838
|
+
"}",
|
|
839
|
+
"",
|
|
840
|
+
}, "\n"),
|
|
841
|
+
})
|
|
842
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
843
|
+
comp, err := NewCompiler(&Config{
|
|
844
|
+
Dir: moduleDir,
|
|
845
|
+
OutputPath: outputDir,
|
|
846
|
+
AllDependencies: true,
|
|
847
|
+
}, nil, nil)
|
|
848
|
+
if err != nil {
|
|
849
|
+
t.Fatal(err.Error())
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
853
|
+
if err != nil {
|
|
854
|
+
t.Fatal(err.Error())
|
|
855
|
+
}
|
|
856
|
+
if result == nil || len(result.CompiledPackages) != 2 {
|
|
857
|
+
t.Fatalf("unexpected result: %#v", result)
|
|
858
|
+
}
|
|
859
|
+
mainFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "main.gs.ts")
|
|
860
|
+
mainContent, err := os.ReadFile(mainFile)
|
|
861
|
+
if err != nil {
|
|
862
|
+
t.Fatal(err.Error())
|
|
863
|
+
}
|
|
864
|
+
if !strings.Contains(string(mainContent), "import * as subpkg from \"@goscript/example.test/imports/subpkg/index.js\"") {
|
|
865
|
+
t.Fatalf("missing package-local import:\n%s", string(mainContent))
|
|
866
|
+
}
|
|
867
|
+
if !strings.Contains(string(mainContent), "let b: $.VarRef<subpkg.Builder> = $.varRef($.markAsStructValue(new subpkg.Builder()))") {
|
|
868
|
+
t.Fatalf("missing imported struct zero value qualification:\n%s", string(mainContent))
|
|
869
|
+
}
|
|
870
|
+
if !strings.Contains(string(mainContent), "import * as __goscript_helper from \"./helper.gs.ts\"") ||
|
|
871
|
+
!strings.Contains(string(mainContent), "$.println(__goscript_helper.localMessage())") {
|
|
872
|
+
t.Fatalf("missing same-package helper import:\n%s", string(mainContent))
|
|
873
|
+
}
|
|
874
|
+
indexFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "subpkg", "index.ts")
|
|
875
|
+
indexContent, err := os.ReadFile(indexFile)
|
|
876
|
+
if err != nil {
|
|
877
|
+
t.Fatal(err.Error())
|
|
878
|
+
}
|
|
879
|
+
if string(indexContent) != "export { Builder, Greet } from \"./subpkg.gs.ts\"\n" {
|
|
880
|
+
t.Fatalf("unexpected subpkg index:\n%s", string(indexContent))
|
|
881
|
+
}
|
|
882
|
+
mainIndexFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "index.ts")
|
|
883
|
+
mainIndexContent, err := os.ReadFile(mainIndexFile)
|
|
884
|
+
if err != nil {
|
|
885
|
+
t.Fatal(err.Error())
|
|
886
|
+
}
|
|
887
|
+
if strings.Contains(string(mainIndexContent), "localMessage") {
|
|
888
|
+
t.Fatalf("unexported helper leaked into package index:\n%s", string(mainIndexContent))
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
func TestCompilePackagesPreservesSourceImportAliasesForAssociatedMethods(t *testing.T) {
|
|
893
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
894
|
+
"go.mod": "module example.test/sourcealiases\n\ngo 1.25.3\n",
|
|
895
|
+
"dep/block/errors.go": strings.Join([]string{
|
|
896
|
+
"package block",
|
|
897
|
+
"import \"errors\"",
|
|
898
|
+
"var ErrUnexpectedType = errors.New(\"unexpected object type\")",
|
|
899
|
+
"",
|
|
900
|
+
}, "\n"),
|
|
901
|
+
"dep/kvtx/block/store.go": strings.Join([]string{
|
|
902
|
+
"package kvtx_block",
|
|
903
|
+
"type KeyValueStore struct{}",
|
|
904
|
+
"",
|
|
905
|
+
}, "\n"),
|
|
906
|
+
"world/world.go": strings.Join([]string{
|
|
907
|
+
"package world",
|
|
908
|
+
"import block \"example.test/sourcealiases/dep/kvtx/block\"",
|
|
909
|
+
"type World struct {",
|
|
910
|
+
" Object *block.KeyValueStore",
|
|
911
|
+
"}",
|
|
912
|
+
"",
|
|
913
|
+
}, "\n"),
|
|
914
|
+
"world/block-world.go": strings.Join([]string{
|
|
915
|
+
"package world",
|
|
916
|
+
"import (",
|
|
917
|
+
" block \"example.test/sourcealiases/dep/block\"",
|
|
918
|
+
" block_kvtx \"example.test/sourcealiases/dep/kvtx/block\"",
|
|
919
|
+
")",
|
|
920
|
+
"func (w *World) Apply(next any) error {",
|
|
921
|
+
" if _, ok := next.(*block_kvtx.KeyValueStore); !ok {",
|
|
922
|
+
" return block.ErrUnexpectedType",
|
|
923
|
+
" }",
|
|
924
|
+
" return nil",
|
|
925
|
+
"}",
|
|
926
|
+
"",
|
|
927
|
+
}, "\n"),
|
|
928
|
+
})
|
|
929
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
930
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
931
|
+
if err != nil {
|
|
932
|
+
t.Fatal(err.Error())
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if _, err := comp.CompilePackages(context.Background(), "./world"); err != nil {
|
|
936
|
+
t.Fatal(err.Error())
|
|
937
|
+
}
|
|
938
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "sourcealiases", "world", "world.gs.ts")
|
|
939
|
+
content, err := os.ReadFile(outputFile)
|
|
940
|
+
if err != nil {
|
|
941
|
+
t.Fatal(err.Error())
|
|
942
|
+
}
|
|
943
|
+
text := string(content)
|
|
944
|
+
matches := regexp.MustCompile(`import \* as (\w+) from "@goscript/example\.test/sourcealiases/dep/block/index\.js"`).FindStringSubmatch(text)
|
|
945
|
+
if len(matches) != 2 {
|
|
946
|
+
t.Fatalf("missing dep/block import in generated output:\n%s", text)
|
|
947
|
+
}
|
|
948
|
+
if !strings.Contains(text, "return "+matches[1]+".ErrUnexpectedType") {
|
|
949
|
+
t.Fatalf("selector did not use the alias for its source package %q:\n%s", matches[1], text)
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
func TestCompilePackagesEmitsSideEffectImportsForInterfaceRegistry(t *testing.T) {
|
|
954
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
955
|
+
"go.mod": "module example.test/interface-registry\n\ngo 1.25.3\n",
|
|
956
|
+
"main.go": strings.Join([]string{
|
|
957
|
+
"package main",
|
|
958
|
+
"import \"example.test/interface-registry/dep\"",
|
|
959
|
+
"type localImpl struct{}",
|
|
960
|
+
"func (*localImpl) Ping() string { return \"pong\" }",
|
|
961
|
+
"func matchLocal(v any) bool {",
|
|
962
|
+
" switch v.(type) {",
|
|
963
|
+
" case Local:",
|
|
964
|
+
" return true",
|
|
965
|
+
" }",
|
|
966
|
+
" return false",
|
|
967
|
+
"}",
|
|
968
|
+
"func matchDep(v any) bool {",
|
|
969
|
+
" _, ok := v.(dep.Remote)",
|
|
970
|
+
" return ok",
|
|
971
|
+
"}",
|
|
972
|
+
"func main() { println(matchLocal(&localImpl{}), matchDep(nil)) }",
|
|
973
|
+
"",
|
|
974
|
+
}, "\n"),
|
|
975
|
+
"local.go": strings.Join([]string{
|
|
976
|
+
"package main",
|
|
977
|
+
"type Local interface { Ping() string }",
|
|
978
|
+
"",
|
|
979
|
+
}, "\n"),
|
|
980
|
+
"dep/dep.go": strings.Join([]string{
|
|
981
|
+
"package dep",
|
|
982
|
+
"type Remote interface { Remote() string }",
|
|
983
|
+
"",
|
|
984
|
+
}, "\n"),
|
|
985
|
+
})
|
|
986
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
987
|
+
comp, err := NewCompiler(&Config{
|
|
988
|
+
Dir: moduleDir,
|
|
989
|
+
OutputPath: outputDir,
|
|
990
|
+
AllDependencies: true,
|
|
991
|
+
}, nil, nil)
|
|
992
|
+
if err != nil {
|
|
993
|
+
t.Fatal(err.Error())
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
997
|
+
t.Fatal(err.Error())
|
|
998
|
+
}
|
|
999
|
+
mainContent, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "interface-registry", "main.gs.ts"))
|
|
1000
|
+
if err != nil {
|
|
1001
|
+
t.Fatal(err.Error())
|
|
1002
|
+
}
|
|
1003
|
+
mainText := string(mainContent)
|
|
1004
|
+
for _, want := range []string{
|
|
1005
|
+
"import * as dep from \"@goscript/example.test/interface-registry/dep/index.js\"",
|
|
1006
|
+
"import \"@goscript/example.test/interface-registry/dep/index.js\"",
|
|
1007
|
+
"import * as __goscript_local from \"./local.gs.ts\"",
|
|
1008
|
+
"import \"./local.gs.ts\"",
|
|
1009
|
+
"case $.typeAssert<Exclude<__goscript_local.Local, null>>(__goscriptTypeSwitchValue, \"main.Local\").ok",
|
|
1010
|
+
"$.typeAssertTuple<dep.Remote | null>(v, \"dep.Remote\")",
|
|
1011
|
+
} {
|
|
1012
|
+
if !strings.Contains(mainText, want) {
|
|
1013
|
+
t.Fatalf("missing %q in main output:\n%s", want, mainText)
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
depIndexContent, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "interface-registry", "dep", "index.ts"))
|
|
1018
|
+
if err != nil {
|
|
1019
|
+
t.Fatal(err.Error())
|
|
1020
|
+
}
|
|
1021
|
+
if !strings.Contains(string(depIndexContent), "import \"./dep.gs.ts\"") {
|
|
1022
|
+
t.Fatalf("missing interface side-effect import in dep index:\n%s", string(depIndexContent))
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
func TestCompilePackagesEmitsIndexAddressRefs(t *testing.T) {
|
|
1027
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1028
|
+
"go.mod": "module example.test/indexaddr\n\ngo 1.25.3\n",
|
|
1029
|
+
"main.go": strings.Join([]string{
|
|
1030
|
+
"package main",
|
|
1031
|
+
"type Item struct { N int }",
|
|
1032
|
+
"func set(ptr *int, value int) {",
|
|
1033
|
+
" *ptr = value",
|
|
1034
|
+
"}",
|
|
1035
|
+
"func Use(values []int, i int) int {",
|
|
1036
|
+
" set(&values[i], 9)",
|
|
1037
|
+
" return values[i]",
|
|
1038
|
+
"}",
|
|
1039
|
+
"func Items() []*Item {",
|
|
1040
|
+
" return []*Item{{N: 1}}",
|
|
1041
|
+
"}",
|
|
1042
|
+
"",
|
|
1043
|
+
}, "\n"),
|
|
1044
|
+
})
|
|
1045
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1046
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1047
|
+
if err != nil {
|
|
1048
|
+
t.Fatal(err.Error())
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
_, err = comp.CompilePackages(context.Background(), ".")
|
|
1052
|
+
if err != nil {
|
|
1053
|
+
t.Fatal(err.Error())
|
|
1054
|
+
}
|
|
1055
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "indexaddr", "main.gs.ts")
|
|
1056
|
+
content, err := os.ReadFile(outputFile)
|
|
1057
|
+
if err != nil {
|
|
1058
|
+
t.Fatal(err.Error())
|
|
1059
|
+
}
|
|
1060
|
+
text := string(content)
|
|
1061
|
+
if !strings.Contains(text, "set($.indexRef(values!, i), 9)") {
|
|
1062
|
+
t.Fatalf("missing index address reference:\n%s", text)
|
|
1063
|
+
}
|
|
1064
|
+
if !strings.Contains(text, "new Item({N: 1})") {
|
|
1065
|
+
t.Fatalf("missing elided pointer composite literal:\n%s", text)
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
1070
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1071
|
+
"go.mod": "module example.test/structs\n\ngo 1.25.3\n",
|
|
1072
|
+
"main.go": strings.Join([]string{
|
|
1073
|
+
"package main",
|
|
1074
|
+
"type Counter struct {",
|
|
1075
|
+
" // Value counts reads.",
|
|
1076
|
+
" Value int `json:\"value\"`",
|
|
1077
|
+
" ID ObjectID",
|
|
1078
|
+
"}",
|
|
1079
|
+
"type ObjectID int32",
|
|
1080
|
+
"func (c Counter) Read() int {",
|
|
1081
|
+
" return c.Value",
|
|
1082
|
+
"}",
|
|
1083
|
+
"func (c *Counter) Set(v int) {",
|
|
1084
|
+
" c.Value = v",
|
|
1085
|
+
"}",
|
|
1086
|
+
"func NewCounter() *Counter {",
|
|
1087
|
+
" return &Counter{Value: 3}",
|
|
1088
|
+
"}",
|
|
1089
|
+
"func main() {",
|
|
1090
|
+
" original := Counter{Value: 1}",
|
|
1091
|
+
"",
|
|
1092
|
+
" // Copy should stay readable in generated output.",
|
|
1093
|
+
" copy := original",
|
|
1094
|
+
" pointer := &original",
|
|
1095
|
+
" pointer.Set(2)",
|
|
1096
|
+
" NewCounter().Set(5)",
|
|
1097
|
+
" var iface any = pointer",
|
|
1098
|
+
" _, ok := iface.(*Counter)",
|
|
1099
|
+
" println(copy.Read(), original.Read(), ok)",
|
|
1100
|
+
"}",
|
|
1101
|
+
"",
|
|
1102
|
+
}, "\n"),
|
|
1103
|
+
})
|
|
1104
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1105
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1106
|
+
if err != nil {
|
|
1107
|
+
t.Fatal(err.Error())
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1111
|
+
t.Fatal(err.Error())
|
|
1112
|
+
}
|
|
1113
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "structs", "main.gs.ts")
|
|
1114
|
+
content, err := os.ReadFile(outputFile)
|
|
1115
|
+
if err != nil {
|
|
1116
|
+
t.Fatal(err.Error())
|
|
1117
|
+
}
|
|
1118
|
+
text := string(content)
|
|
1119
|
+
for _, want := range []string{
|
|
1120
|
+
"export class Counter",
|
|
1121
|
+
"// Value counts reads.\n\tpublic get Value(): number",
|
|
1122
|
+
"public clone(): Counter",
|
|
1123
|
+
"public Read(): number",
|
|
1124
|
+
"public Set(v: number): void",
|
|
1125
|
+
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))",
|
|
1126
|
+
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))\n\n\t// Copy should stay readable in generated output.\n\tlet copy",
|
|
1127
|
+
"let copy = $.markAsStructValue($.cloneStructValue(original.value))",
|
|
1128
|
+
"let pointer: Counter | $.VarRef<Counter> | null = original",
|
|
1129
|
+
"Counter.prototype.Set.call(pointer, 2)",
|
|
1130
|
+
"Counter.prototype.Set.call(NewCounter(), 5)",
|
|
1131
|
+
"let [, ok] = $.typeAssertTuple<Counter | $.VarRef<Counter> | null>(iface, { kind: $.TypeKind.Pointer, elemType: \"main.Counter\" })",
|
|
1132
|
+
"\"Value\": { type: { kind: $.TypeKind.Basic, name: \"int\" }, tag: \"json:\\\"value\\\"\" }",
|
|
1133
|
+
"\"ID\": { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.ObjectID\" }",
|
|
1134
|
+
} {
|
|
1135
|
+
if !strings.Contains(text, want) {
|
|
1136
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
func TestCompilePackagesClonesNestedStructFieldsWithCloneMethodCollision(t *testing.T) {
|
|
1142
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1143
|
+
"go.mod": "module example.test/nestedclone\n\ngo 1.25.3\n",
|
|
1144
|
+
"main.go": strings.Join([]string{
|
|
1145
|
+
"package main",
|
|
1146
|
+
"type Box struct { Value int }",
|
|
1147
|
+
"func (b *Box) clone() (*Box, error) {",
|
|
1148
|
+
" return &Box{Value: b.Value + 1}, nil",
|
|
1149
|
+
"}",
|
|
1150
|
+
"type Holder struct { Box Box }",
|
|
1151
|
+
"func copyHolder(h Holder) Holder { return h }",
|
|
1152
|
+
"func main() {",
|
|
1153
|
+
" _ = copyHolder(Holder{Box: Box{Value: 1}})",
|
|
1154
|
+
"}",
|
|
1155
|
+
"",
|
|
1156
|
+
}, "\n"),
|
|
1157
|
+
})
|
|
1158
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1159
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1160
|
+
if err != nil {
|
|
1161
|
+
t.Fatal(err.Error())
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1165
|
+
t.Fatal(err.Error())
|
|
1166
|
+
}
|
|
1167
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "nestedclone", "main.gs.ts"))
|
|
1168
|
+
if err != nil {
|
|
1169
|
+
t.Fatal(err.Error())
|
|
1170
|
+
}
|
|
1171
|
+
text := string(content)
|
|
1172
|
+
for _, want := range []string{
|
|
1173
|
+
"public __goscriptClone(): Box",
|
|
1174
|
+
"Box: $.varRef(init?.Box ? $.markAsStructValue($.cloneStructValue(init.Box)) : $.markAsStructValue(new Box()))",
|
|
1175
|
+
"Box: $.varRef($.markAsStructValue($.cloneStructValue(this._fields.Box.value)))",
|
|
1176
|
+
} {
|
|
1177
|
+
if !strings.Contains(text, want) {
|
|
1178
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
if strings.Contains(text, "init.Box.clone()") || strings.Contains(text, "this._fields.Box.value.clone()") {
|
|
1182
|
+
t.Fatalf("nested struct-field clone bypassed cloneStructValue:\n%s", text)
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
func TestCompilePackagesEmitsNestedPointerStorageAssertions(t *testing.T) {
|
|
1187
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1188
|
+
"go.mod": "module example.test/pointers\n\ngo 1.25.3\n",
|
|
1189
|
+
"main.go": strings.Join([]string{
|
|
1190
|
+
"package main",
|
|
1191
|
+
"func main() {",
|
|
1192
|
+
" var x int = 10",
|
|
1193
|
+
" p1 := &x",
|
|
1194
|
+
" p2 := &p1",
|
|
1195
|
+
" p3 := &p2",
|
|
1196
|
+
" ***p3 = 12",
|
|
1197
|
+
" println(x)",
|
|
1198
|
+
"}",
|
|
1199
|
+
"",
|
|
1200
|
+
}, "\n"),
|
|
1201
|
+
})
|
|
1202
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1203
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1204
|
+
if err != nil {
|
|
1205
|
+
t.Fatal(err.Error())
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1209
|
+
t.Fatal(err.Error())
|
|
1210
|
+
}
|
|
1211
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "pointers", "main.gs.ts")
|
|
1212
|
+
content, err := os.ReadFile(outputFile)
|
|
1213
|
+
if err != nil {
|
|
1214
|
+
t.Fatal(err.Error())
|
|
1215
|
+
}
|
|
1216
|
+
text := string(content)
|
|
1217
|
+
for _, want := range []string{
|
|
1218
|
+
"let x: $.VarRef<number> = $.varRef(10)",
|
|
1219
|
+
"let p1 = $.varRef(x)",
|
|
1220
|
+
"let p2 = $.varRef(p1)",
|
|
1221
|
+
"let p3 = p2",
|
|
1222
|
+
"$.pointerValue<$.VarRef<number> | null>($.pointerValue<$.VarRef<$.VarRef<number> | null> | null>(p3))!.value = 12",
|
|
636
1223
|
} {
|
|
637
1224
|
if !strings.Contains(text, want) {
|
|
638
1225
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -642,28 +1229,127 @@ func TestCompilePackagesEmitsNestedPointerStorageAssertions(t *testing.T) {
|
|
|
642
1229
|
|
|
643
1230
|
func TestCompilePackagesEmitsArraySliceMapStringAndNamedMethods(t *testing.T) {
|
|
644
1231
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
645
|
-
"go.mod": "module example.test/collections\n\ngo 1.25.3\n",
|
|
1232
|
+
"go.mod": "module example.test/collections\n\ngo 1.25.3\n",
|
|
1233
|
+
"main.go": strings.Join([]string{
|
|
1234
|
+
"package main",
|
|
1235
|
+
"type MyInt int",
|
|
1236
|
+
"func (m MyInt) Double() int { return int(m) * 2 }",
|
|
1237
|
+
"type MySlice []int",
|
|
1238
|
+
"func (s *MySlice) Add(v int) { *s = append(*s, v) }",
|
|
1239
|
+
"func main() {",
|
|
1240
|
+
" arr := [3]int{1: 10}",
|
|
1241
|
+
" slice := make([]int, 0, 2)",
|
|
1242
|
+
" empty := []rune{}",
|
|
1243
|
+
" literal := []int{1, 2}",
|
|
1244
|
+
" literal = append(literal, 3)",
|
|
1245
|
+
" slice = append(slice, 5)",
|
|
1246
|
+
" slice[0] = arr[1]",
|
|
1247
|
+
" m := make(map[string]int)",
|
|
1248
|
+
" m[\"one\"] = 1",
|
|
1249
|
+
" value, ok := m[\"missing\"]",
|
|
1250
|
+
" text := \"hé\"",
|
|
1251
|
+
" var list MySlice",
|
|
1252
|
+
" list.Add(7)",
|
|
1253
|
+
" println(arr[1], slice[0], literal[2], len(slice), cap(slice), len(empty), value, ok, text[0], text[1], MyInt(5).Double(), len(list))",
|
|
1254
|
+
"}",
|
|
1255
|
+
"",
|
|
1256
|
+
}, "\n"),
|
|
1257
|
+
})
|
|
1258
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1259
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1260
|
+
if err != nil {
|
|
1261
|
+
t.Fatal(err.Error())
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1265
|
+
t.Fatal(err.Error())
|
|
1266
|
+
}
|
|
1267
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "collections", "main.gs.ts")
|
|
1268
|
+
content, err := os.ReadFile(outputFile)
|
|
1269
|
+
if err != nil {
|
|
1270
|
+
t.Fatal(err.Error())
|
|
1271
|
+
}
|
|
1272
|
+
text := string(content)
|
|
1273
|
+
for _, want := range []string{
|
|
1274
|
+
"export type MyInt = number",
|
|
1275
|
+
"export function MyInt_Double(m: MyInt): number",
|
|
1276
|
+
"export type MySlice = $.Slice<number>",
|
|
1277
|
+
"export function MySlice_Add(s: $.VarRef<MySlice> | null, v: number): void",
|
|
1278
|
+
"let arr = [0, 10, 0]",
|
|
1279
|
+
"let slice: $.Slice<number> = $.makeSlice<number>(0, 2, \"number\")",
|
|
1280
|
+
"let empty: $.Slice<number> = $.arrayToSlice<number>([])",
|
|
1281
|
+
"let literal: $.Slice<number> = $.arrayToSlice<number>([1, 2])",
|
|
1282
|
+
"literal = $.append(literal, 3)",
|
|
1283
|
+
"slice![0] = arr[1]",
|
|
1284
|
+
"let m: Map<string, number> | null = $.makeMap<string, number>()",
|
|
1285
|
+
"$.mapSet(m, \"one\", 1)",
|
|
1286
|
+
"let [value, ok] = $.mapGet(m, \"missing\", 0)",
|
|
1287
|
+
"slice![0]",
|
|
1288
|
+
"literal![2]",
|
|
1289
|
+
"let list: $.VarRef<MySlice> = $.varRef(null as MySlice)",
|
|
1290
|
+
"MySlice_Add(list, 7)",
|
|
1291
|
+
"$.indexStringOrBytes(text, 0)",
|
|
1292
|
+
"MyInt_Double(5)",
|
|
1293
|
+
} {
|
|
1294
|
+
if !strings.Contains(text, want) {
|
|
1295
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
func TestCompilePackagesWrapsAddressedMapRangeValue(t *testing.T) {
|
|
1301
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1302
|
+
"go.mod": "module example.test/maprange\n\ngo 1.25.3\n",
|
|
1303
|
+
"main.go": strings.Join([]string{
|
|
1304
|
+
"package main",
|
|
1305
|
+
"type Item struct { Values []string }",
|
|
1306
|
+
"func (i *Item) add(v string) { i.Values = append(i.Values, v) }",
|
|
1307
|
+
"func Apply(m map[int]Item, values []string) {",
|
|
1308
|
+
" for k, item := range m {",
|
|
1309
|
+
" for _, v := range values {",
|
|
1310
|
+
" item.add(v)",
|
|
1311
|
+
" }",
|
|
1312
|
+
" m[k] = item",
|
|
1313
|
+
" }",
|
|
1314
|
+
"}",
|
|
1315
|
+
"",
|
|
1316
|
+
}, "\n"),
|
|
1317
|
+
})
|
|
1318
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1319
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1320
|
+
if err != nil {
|
|
1321
|
+
t.Fatal(err.Error())
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1325
|
+
t.Fatal(err.Error())
|
|
1326
|
+
}
|
|
1327
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "maprange", "main.gs.ts")
|
|
1328
|
+
content, err := os.ReadFile(outputFile)
|
|
1329
|
+
if err != nil {
|
|
1330
|
+
t.Fatal(err.Error())
|
|
1331
|
+
}
|
|
1332
|
+
text := string(content)
|
|
1333
|
+
for _, want := range []string{
|
|
1334
|
+
"let item: $.VarRef<Item> = $.varRef($.markAsStructValue($.cloneStructValue(__goscriptRangeValue",
|
|
1335
|
+
"item.value.add(v)",
|
|
1336
|
+
"$.mapSet(m, k, $.markAsStructValue($.cloneStructValue(item.value)))",
|
|
1337
|
+
} {
|
|
1338
|
+
if !strings.Contains(text, want) {
|
|
1339
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
func TestCompilePackagesLowersPromotedNamedPrimitiveMethod(t *testing.T) {
|
|
1345
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1346
|
+
"go.mod": "module example.test/promotedprimitive\n\ngo 1.25.3\n",
|
|
646
1347
|
"main.go": strings.Join([]string{
|
|
647
1348
|
"package main",
|
|
648
|
-
"
|
|
649
|
-
"
|
|
650
|
-
"
|
|
651
|
-
"
|
|
652
|
-
"func main() {",
|
|
653
|
-
" arr := [3]int{1: 10}",
|
|
654
|
-
" slice := make([]int, 0, 2)",
|
|
655
|
-
" empty := []rune{}",
|
|
656
|
-
" literal := []int{1, 2}",
|
|
657
|
-
" literal = append(literal, 3)",
|
|
658
|
-
" slice = append(slice, 5)",
|
|
659
|
-
" slice[0] = arr[1]",
|
|
660
|
-
" m := make(map[string]int)",
|
|
661
|
-
" m[\"one\"] = 1",
|
|
662
|
-
" value, ok := m[\"missing\"]",
|
|
663
|
-
" text := \"hé\"",
|
|
664
|
-
" var list MySlice",
|
|
665
|
-
" list.Add(7)",
|
|
666
|
-
" println(arr[1], slice[0], literal[2], len(slice), cap(slice), len(empty), value, ok, text[0], text[1], MyInt(5).Double(), len(list))",
|
|
1349
|
+
"import \"time\"",
|
|
1350
|
+
"type Lifetime struct { time.Duration }",
|
|
1351
|
+
"func Seconds(l Lifetime) float64 {",
|
|
1352
|
+
" return l.Seconds()",
|
|
667
1353
|
"}",
|
|
668
1354
|
"",
|
|
669
1355
|
}, "\n"),
|
|
@@ -677,32 +1363,309 @@ func TestCompilePackagesEmitsArraySliceMapStringAndNamedMethods(t *testing.T) {
|
|
|
677
1363
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
678
1364
|
t.Fatal(err.Error())
|
|
679
1365
|
}
|
|
680
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
1366
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "promotedprimitive", "main.gs.ts")
|
|
1367
|
+
content, err := os.ReadFile(outputFile)
|
|
1368
|
+
if err != nil {
|
|
1369
|
+
t.Fatal(err.Error())
|
|
1370
|
+
}
|
|
1371
|
+
text := string(content)
|
|
1372
|
+
if !strings.Contains(text, "return time.Duration_Seconds(l.Duration)") {
|
|
1373
|
+
t.Fatalf("promoted named primitive method was not lowered through the owner function:\n%s", text)
|
|
1374
|
+
}
|
|
1375
|
+
if strings.Contains(text, ".Seconds()") {
|
|
1376
|
+
t.Fatalf("promoted named primitive method still used a JavaScript member call:\n%s", text)
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
func TestCompilePackagesMarksPackageFunctionVariablesAsync(t *testing.T) {
|
|
1381
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1382
|
+
"go.mod": "module example.test/packagefuncvar\n\ngo 1.25.3\n",
|
|
1383
|
+
"dep/dep.go": strings.Join([]string{
|
|
1384
|
+
"package dep",
|
|
1385
|
+
"func parse(raw string) (int, error) { return len(raw), nil }",
|
|
1386
|
+
"var Parse = parse",
|
|
1387
|
+
"",
|
|
1388
|
+
}, "\n"),
|
|
1389
|
+
"main.go": strings.Join([]string{
|
|
1390
|
+
"package main",
|
|
1391
|
+
"import \"example.test/packagefuncvar/dep\"",
|
|
1392
|
+
"func parse() (int, error) {",
|
|
1393
|
+
" return dep.Parse(\"turn\")",
|
|
1394
|
+
"}",
|
|
1395
|
+
"",
|
|
1396
|
+
}, "\n"),
|
|
1397
|
+
})
|
|
1398
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1399
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1400
|
+
if err != nil {
|
|
1401
|
+
t.Fatal(err.Error())
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1405
|
+
t.Fatal(err.Error())
|
|
1406
|
+
}
|
|
1407
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "packagefuncvar", "main.gs.ts")
|
|
1408
|
+
content, err := os.ReadFile(outputFile)
|
|
1409
|
+
if err != nil {
|
|
1410
|
+
t.Fatal(err.Error())
|
|
1411
|
+
}
|
|
1412
|
+
text := string(content)
|
|
1413
|
+
if !strings.Contains(text, "export async function parse(): globalThis.Promise<[number, $.GoError]>") {
|
|
1414
|
+
t.Fatalf("package function variable caller was not marked async:\n%s", text)
|
|
1415
|
+
}
|
|
1416
|
+
if !strings.Contains(text, "return await dep.Parse!(\"turn\")") {
|
|
1417
|
+
t.Fatalf("package function variable call was not awaited:\n%s", text)
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
func TestCompilePackagesAwaitsImportedAsyncMethodsAndFunctions(t *testing.T) {
|
|
1422
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1423
|
+
"go.mod": "module example.test/importedasync\n\ngo 1.25.3\n",
|
|
1424
|
+
"dep/dep.go": strings.Join([]string{
|
|
1425
|
+
"package dep",
|
|
1426
|
+
"type Host struct{ ch chan struct{} }",
|
|
1427
|
+
"func (h *Host) Snapshot() (int, error) { <-h.ch; return 1, nil }",
|
|
1428
|
+
"func Read(h *Host) (int, error) { return h.Snapshot() }",
|
|
1429
|
+
"",
|
|
1430
|
+
}, "\n"),
|
|
1431
|
+
"dep/dep_test.go": strings.Join([]string{
|
|
1432
|
+
"package dep",
|
|
1433
|
+
"import \"testing\"",
|
|
1434
|
+
"func TestHost(t *testing.T) {}",
|
|
1435
|
+
"",
|
|
1436
|
+
}, "\n"),
|
|
1437
|
+
"main.go": strings.Join([]string{
|
|
1438
|
+
"package main",
|
|
1439
|
+
"import \"example.test/importedasync/dep\"",
|
|
1440
|
+
"func UseMethod(h *dep.Host) (int, error) {",
|
|
1441
|
+
" return h.Snapshot()",
|
|
1442
|
+
"}",
|
|
1443
|
+
"func UseFunction(h *dep.Host) (int, error) {",
|
|
1444
|
+
" return dep.Read(h)",
|
|
1445
|
+
"}",
|
|
1446
|
+
"",
|
|
1447
|
+
}, "\n"),
|
|
1448
|
+
"main_test.go": strings.Join([]string{
|
|
1449
|
+
"package main",
|
|
1450
|
+
"import \"testing\"",
|
|
1451
|
+
"func TestUse(t *testing.T) {}",
|
|
1452
|
+
"",
|
|
1453
|
+
}, "\n"),
|
|
1454
|
+
})
|
|
1455
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1456
|
+
service := NewCompileService()
|
|
1457
|
+
_, err := service.Compile(context.Background(), &CompileRequest{
|
|
1458
|
+
Patterns: []string{".", "./dep"},
|
|
1459
|
+
Dir: moduleDir,
|
|
1460
|
+
OutputPath: outputDir,
|
|
1461
|
+
DependencyMode: DependencyModeAll,
|
|
1462
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
1463
|
+
Tests: true,
|
|
1464
|
+
AllDependencies: true,
|
|
1465
|
+
})
|
|
1466
|
+
if err != nil {
|
|
1467
|
+
t.Fatal(err.Error())
|
|
1468
|
+
}
|
|
1469
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "importedasync", "main.gs.ts")
|
|
1470
|
+
content, err := os.ReadFile(outputFile)
|
|
1471
|
+
if err != nil {
|
|
1472
|
+
t.Fatal(err.Error())
|
|
1473
|
+
}
|
|
1474
|
+
text := string(content)
|
|
1475
|
+
if !strings.Contains(text, "export async function UseMethod") {
|
|
1476
|
+
t.Fatalf("imported async method caller was not marked async:\n%s", text)
|
|
1477
|
+
}
|
|
1478
|
+
if !strings.Contains(text, "return await dep.Host.prototype.Snapshot.call(h)") {
|
|
1479
|
+
t.Fatalf("imported async method call was not awaited:\n%s", text)
|
|
1480
|
+
}
|
|
1481
|
+
if !strings.Contains(text, "export async function UseFunction") {
|
|
1482
|
+
t.Fatalf("imported async function caller was not marked async:\n%s", text)
|
|
1483
|
+
}
|
|
1484
|
+
if !strings.Contains(text, "return await dep.Read(h)") {
|
|
1485
|
+
t.Fatalf("imported async function call was not awaited:\n%s", text)
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
func TestCompilePackagesCastsConvertedTupleCallSpreads(t *testing.T) {
|
|
1490
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1491
|
+
"go.mod": "module example.test/tuplecallspread\n\ngo 1.25.3\n",
|
|
1492
|
+
"main.go": strings.Join([]string{
|
|
1493
|
+
"package main",
|
|
1494
|
+
"type Resolver interface { Resolve() }",
|
|
1495
|
+
"type relay struct{}",
|
|
1496
|
+
"func (*relay) Resolve() {}",
|
|
1497
|
+
"func NewRelay() (*relay, error) { return &relay{}, nil }",
|
|
1498
|
+
"func R(res Resolver, err error) ([]Resolver, error) {",
|
|
1499
|
+
" if err != nil { return nil, err }",
|
|
1500
|
+
" return []Resolver{res}, nil",
|
|
1501
|
+
"}",
|
|
1502
|
+
"func Use() ([]Resolver, error) {",
|
|
1503
|
+
" return R(NewRelay())",
|
|
1504
|
+
"}",
|
|
1505
|
+
"",
|
|
1506
|
+
}, "\n"),
|
|
1507
|
+
})
|
|
1508
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1509
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1510
|
+
if err != nil {
|
|
1511
|
+
t.Fatal(err.Error())
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1515
|
+
t.Fatal(err.Error())
|
|
1516
|
+
}
|
|
1517
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "tuplecallspread", "main.gs.ts")
|
|
1518
|
+
content, err := os.ReadFile(outputFile)
|
|
1519
|
+
if err != nil {
|
|
1520
|
+
t.Fatal(err.Error())
|
|
1521
|
+
}
|
|
1522
|
+
text := string(content)
|
|
1523
|
+
if !strings.Contains(text, "return R(...(() => {") ||
|
|
1524
|
+
!strings.Contains(text, "] as [Resolver | null, $.GoError]") {
|
|
1525
|
+
t.Fatalf("converted tuple call spread was not cast as a TypeScript tuple:\n%s", text)
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
func TestCompilePackagesPreservesBlankNamedResultSlots(t *testing.T) {
|
|
1530
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1531
|
+
"go.mod": "module example.test/blankresult\n\ngo 1.25.3\n",
|
|
1532
|
+
"main.go": strings.Join([]string{
|
|
1533
|
+
"package main",
|
|
1534
|
+
"func values() (first, second bool, _ error) {",
|
|
1535
|
+
" first = true",
|
|
1536
|
+
" return",
|
|
1537
|
+
"}",
|
|
1538
|
+
"",
|
|
1539
|
+
}, "\n"),
|
|
1540
|
+
})
|
|
1541
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1542
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1543
|
+
if err != nil {
|
|
1544
|
+
t.Fatal(err.Error())
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1548
|
+
t.Fatal(err.Error())
|
|
1549
|
+
}
|
|
1550
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "blankresult", "main.gs.ts")
|
|
1551
|
+
content, err := os.ReadFile(outputFile)
|
|
1552
|
+
if err != nil {
|
|
1553
|
+
t.Fatal(err.Error())
|
|
1554
|
+
}
|
|
1555
|
+
text := string(content)
|
|
1556
|
+
if !strings.Contains(text, "return [first, second, null as $.GoError]") {
|
|
1557
|
+
t.Fatalf("blank named result slot was not preserved in naked return:\n%s", text)
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
func TestCompilePackagesCastsGenericMethodResultAssignments(t *testing.T) {
|
|
1562
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1563
|
+
"go.mod": "module example.test/genericmethodresult\n\ngo 1.25.3\n",
|
|
1564
|
+
"main.go": strings.Join([]string{
|
|
1565
|
+
"package main",
|
|
1566
|
+
"import (",
|
|
1567
|
+
" \"errors\"",
|
|
1568
|
+
" \"sync/atomic\"",
|
|
1569
|
+
")",
|
|
1570
|
+
"func load() error {",
|
|
1571
|
+
" var ptr atomic.Pointer[error]",
|
|
1572
|
+
" err := errors.New(\"boom\")",
|
|
1573
|
+
" ptr.Store(&err)",
|
|
1574
|
+
" if errp := ptr.Load(); errp != nil {",
|
|
1575
|
+
" return *errp",
|
|
1576
|
+
" }",
|
|
1577
|
+
" return nil",
|
|
1578
|
+
"}",
|
|
1579
|
+
"",
|
|
1580
|
+
}, "\n"),
|
|
1581
|
+
})
|
|
1582
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1583
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1584
|
+
if err != nil {
|
|
1585
|
+
t.Fatal(err.Error())
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1589
|
+
t.Fatal(err.Error())
|
|
1590
|
+
}
|
|
1591
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "genericmethodresult", "main.gs.ts")
|
|
1592
|
+
content, err := os.ReadFile(outputFile)
|
|
1593
|
+
if err != nil {
|
|
1594
|
+
t.Fatal(err.Error())
|
|
1595
|
+
}
|
|
1596
|
+
text := string(content)
|
|
1597
|
+
if !strings.Contains(text, "(ptr.value.Load() as $.VarRef<$.GoError> | null)") {
|
|
1598
|
+
t.Fatalf("generic method result assignment was not cast to the target type:\n%s", text)
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
func TestCompilePackagesPreservesFloatConversionLiterals(t *testing.T) {
|
|
1603
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1604
|
+
"go.mod": "module example.test/floatconv\n\ngo 1.25.3\n",
|
|
1605
|
+
"main.go": strings.Join([]string{
|
|
1606
|
+
"package main",
|
|
1607
|
+
"import \"math\"",
|
|
1608
|
+
"func value() float64 {",
|
|
1609
|
+
" return math.Pow(float64(0.69314718056), 2)",
|
|
1610
|
+
"}",
|
|
1611
|
+
"",
|
|
1612
|
+
}, "\n"),
|
|
1613
|
+
})
|
|
1614
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1615
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1616
|
+
if err != nil {
|
|
1617
|
+
t.Fatal(err.Error())
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1621
|
+
t.Fatal(err.Error())
|
|
1622
|
+
}
|
|
1623
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "floatconv", "main.gs.ts")
|
|
1624
|
+
content, err := os.ReadFile(outputFile)
|
|
1625
|
+
if err != nil {
|
|
1626
|
+
t.Fatal(err.Error())
|
|
1627
|
+
}
|
|
1628
|
+
text := string(content)
|
|
1629
|
+
if strings.Contains(text, "$.int(0.69314718056)") {
|
|
1630
|
+
t.Fatalf("float64 literal conversion was truncated through $.int:\n%s", text)
|
|
1631
|
+
}
|
|
1632
|
+
if !strings.Contains(text, "math.Pow(0.69314718056, 2)") {
|
|
1633
|
+
t.Fatalf("missing direct float literal conversion:\n%s", text)
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
func TestCompilePackagesLowersStringOrderingThroughRuntime(t *testing.T) {
|
|
1638
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1639
|
+
"go.mod": "module example.test/stringorder\n\ngo 1.25.3\n",
|
|
1640
|
+
"main.go": strings.Join([]string{
|
|
1641
|
+
"package main",
|
|
1642
|
+
"func less(left, right []byte) bool {",
|
|
1643
|
+
" return string(left) < string(right)",
|
|
1644
|
+
"}",
|
|
1645
|
+
"func ordered(left, right string) bool {",
|
|
1646
|
+
" return left <= right",
|
|
1647
|
+
"}",
|
|
1648
|
+
"",
|
|
1649
|
+
}, "\n"),
|
|
1650
|
+
})
|
|
1651
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1652
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1653
|
+
if err != nil {
|
|
1654
|
+
t.Fatal(err.Error())
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1658
|
+
t.Fatal(err.Error())
|
|
1659
|
+
}
|
|
1660
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "stringorder", "main.gs.ts")
|
|
681
1661
|
content, err := os.ReadFile(outputFile)
|
|
682
1662
|
if err != nil {
|
|
683
1663
|
t.Fatal(err.Error())
|
|
684
1664
|
}
|
|
685
1665
|
text := string(content)
|
|
686
1666
|
for _, want := range []string{
|
|
687
|
-
"
|
|
688
|
-
"
|
|
689
|
-
"export type MySlice = $.Slice<number>",
|
|
690
|
-
"export function MySlice_Add(s: $.VarRef<MySlice> | null, v: number): void",
|
|
691
|
-
"let arr = [0, 10, 0]",
|
|
692
|
-
"let slice = $.makeSlice<number>(0, 2, \"number\")",
|
|
693
|
-
"let empty = $.arrayToSlice<number>([])",
|
|
694
|
-
"let literal = $.arrayToSlice<number>([1, 2])",
|
|
695
|
-
"literal = $.append(literal, 3)",
|
|
696
|
-
"slice![0] = arr[1]",
|
|
697
|
-
"let m: Map<string, number> | null = $.makeMap<string, number>()",
|
|
698
|
-
"$.mapSet(m, \"one\", 1)",
|
|
699
|
-
"let [value, ok] = $.mapGet(m, \"missing\", 0)",
|
|
700
|
-
"slice![0]",
|
|
701
|
-
"literal![2]",
|
|
702
|
-
"let list: $.VarRef<MySlice> = $.varRef(null as MySlice)",
|
|
703
|
-
"MySlice_Add(list, 7)",
|
|
704
|
-
"$.indexStringOrBytes(text, 0)",
|
|
705
|
-
"MyInt_Double(5)",
|
|
1667
|
+
"$.stringCompare(left, right) < 0",
|
|
1668
|
+
"$.stringCompare(left, right) <= 0",
|
|
706
1669
|
} {
|
|
707
1670
|
if !strings.Contains(text, want) {
|
|
708
1671
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -759,18 +1722,18 @@ func TestCompilePackagesEmitsInterfacesMethodValuesTypeSwitchesAndFunctionAssert
|
|
|
759
1722
|
text := string(content)
|
|
760
1723
|
for _, want := range []string{
|
|
761
1724
|
"export type Greeter = ((name: string) => string | globalThis.Promise<string>) | null",
|
|
762
|
-
"export type ReadCloser =
|
|
1725
|
+
"export type ReadCloser = {",
|
|
763
1726
|
"Read(): string",
|
|
764
1727
|
"Close(): string",
|
|
765
1728
|
"$.registerInterfaceType(\n\t\"main.ReadCloser\"",
|
|
766
1729
|
"((__receiver) => () => __receiver.Inc())($.pointerValue<Counter>(counter))",
|
|
767
1730
|
"$.namedFunction(greet, \"main.Greeter\")",
|
|
768
|
-
"$.
|
|
1731
|
+
"$.interfaceValue<any>(null, \"*struct{Name string}\")",
|
|
769
1732
|
"elemType: { kind: $.TypeKind.Struct, methods: [], fields: {\"Name\": { kind: $.TypeKind.Basic, name: \"string\" }} }",
|
|
770
1733
|
"let fn = __goscriptTuple",
|
|
771
1734
|
"switch (true)",
|
|
772
|
-
"case $.typeAssert<ReadCloser
|
|
773
|
-
"let v: ReadCloser
|
|
1735
|
+
"case $.typeAssert<Exclude<ReadCloser, null>>(__goscriptTypeSwitchValue, \"main.ReadCloser\").ok",
|
|
1736
|
+
"let v: Exclude<ReadCloser, null> = $.typeAssert<Exclude<ReadCloser, null>>(__goscriptTypeSwitchValue, \"main.ReadCloser\").value",
|
|
774
1737
|
} {
|
|
775
1738
|
if !strings.Contains(text, want) {
|
|
776
1739
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -805,15 +1768,67 @@ func TestCompilePackagesAssertsInterfaceMethodReceivers(t *testing.T) {
|
|
|
805
1768
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
806
1769
|
t.Fatal(err.Error())
|
|
807
1770
|
}
|
|
808
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "interface-receivers", "main.gs.ts")
|
|
1771
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "interface-receivers", "main.gs.ts")
|
|
1772
|
+
content, err := os.ReadFile(outputFile)
|
|
1773
|
+
if err != nil {
|
|
1774
|
+
t.Fatal(err.Error())
|
|
1775
|
+
}
|
|
1776
|
+
text := string(content)
|
|
1777
|
+
for _, want := range []string{
|
|
1778
|
+
"export type FileInfo = {",
|
|
1779
|
+
"$.println($.pointerValue<Exclude<FileInfo, null>>(info).Name())",
|
|
1780
|
+
} {
|
|
1781
|
+
if !strings.Contains(text, want) {
|
|
1782
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
func TestCompilePackagesUsesNonNilInterfaceTypeSwitchCaseVarRefs(t *testing.T) {
|
|
1788
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1789
|
+
"go.mod": "module example.test/interface-switch-varref\n\ngo 1.25.3\n",
|
|
1790
|
+
"main.go": strings.Join([]string{
|
|
1791
|
+
"package main",
|
|
1792
|
+
"type rawConn interface { Control() error }",
|
|
1793
|
+
"type tcpConn interface {",
|
|
1794
|
+
" SyscallConn() (rawConn, error)",
|
|
1795
|
+
" SetLinger(int) error",
|
|
1796
|
+
"}",
|
|
1797
|
+
"type Conn struct { c rawConn }",
|
|
1798
|
+
"func keep(*tcpConn) {}",
|
|
1799
|
+
"func NewConn(c any) (*Conn, error) {",
|
|
1800
|
+
" cc := &Conn{}",
|
|
1801
|
+
" var err error",
|
|
1802
|
+
" switch c := c.(type) {",
|
|
1803
|
+
" case tcpConn:",
|
|
1804
|
+
" keep(&c)",
|
|
1805
|
+
" cc.c, err = c.SyscallConn()",
|
|
1806
|
+
" }",
|
|
1807
|
+
" return cc, err",
|
|
1808
|
+
"}",
|
|
1809
|
+
"",
|
|
1810
|
+
}, "\n"),
|
|
1811
|
+
})
|
|
1812
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1813
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1814
|
+
if err != nil {
|
|
1815
|
+
t.Fatal(err.Error())
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1819
|
+
t.Fatal(err.Error())
|
|
1820
|
+
}
|
|
1821
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "interface-switch-varref", "main.gs.ts")
|
|
809
1822
|
content, err := os.ReadFile(outputFile)
|
|
810
1823
|
if err != nil {
|
|
811
1824
|
t.Fatal(err.Error())
|
|
812
1825
|
}
|
|
813
1826
|
text := string(content)
|
|
814
1827
|
for _, want := range []string{
|
|
815
|
-
"export type
|
|
816
|
-
"$.
|
|
1828
|
+
"export type tcpConn = {",
|
|
1829
|
+
"case $.typeAssert<Exclude<tcpConn, null>>(__goscriptTypeSwitchValue, \"main.tcpConn\").ok",
|
|
1830
|
+
"let c: $.VarRef<Exclude<tcpConn, null>> = $.varRef($.typeAssert<Exclude<tcpConn, null>>(__goscriptTypeSwitchValue, \"main.tcpConn\").value)",
|
|
1831
|
+
"$.pointerValue<Exclude<tcpConn, null>>(c.value).SyscallConn()",
|
|
817
1832
|
} {
|
|
818
1833
|
if !strings.Contains(text, want) {
|
|
819
1834
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -893,6 +1908,9 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
|
|
|
893
1908
|
" var zero T",
|
|
894
1909
|
" return zero",
|
|
895
1910
|
"}",
|
|
1911
|
+
"func Copy[T any](vals ...T) []T {",
|
|
1912
|
+
" return append([]T{}, vals...)",
|
|
1913
|
+
"}",
|
|
896
1914
|
"func main() {",
|
|
897
1915
|
" box := NewBox(7)",
|
|
898
1916
|
" println(box.Get())",
|
|
@@ -924,13 +1942,18 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
|
|
|
924
1942
|
for _, want := range []string{
|
|
925
1943
|
"public Get(): any",
|
|
926
1944
|
"export function NewBox(__typeArgs: $.GenericTypeArgs | undefined, value: any): Box",
|
|
1945
|
+
"export function ZeroValue(__typeArgs: $.GenericTypeArgs | undefined): any",
|
|
1946
|
+
"export function CallString(__typeArgs: $.GenericTypeArgs | undefined, v: any): string",
|
|
1947
|
+
"export function Sum<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): any",
|
|
1948
|
+
"export function Copy<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): $.Slice<T>",
|
|
1949
|
+
"return $.append($.arrayToSlice<T>([]), ...(vals ?? []))",
|
|
927
1950
|
"let seen: Set = $.makeMap<number, {}>()",
|
|
928
1951
|
"$.mapSet(seen, 1, {})",
|
|
929
1952
|
"$.genericZero(__typeArgs, \"T\", null)",
|
|
930
1953
|
"$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
|
|
931
|
-
"ZeroValue({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }})",
|
|
932
|
-
"CallString({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }}, zero)",
|
|
933
|
-
"Sum({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }}, null)",
|
|
1954
|
+
"ZeroValue({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)($.pointerValue(receiver), ...args)} }})",
|
|
1955
|
+
"CallString({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)($.pointerValue(receiver), ...args)} }}, zero)",
|
|
1956
|
+
"Sum({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)($.pointerValue(receiver), ...args)} }}, null)",
|
|
934
1957
|
} {
|
|
935
1958
|
if !strings.Contains(text, want) {
|
|
936
1959
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -1015,8 +2038,8 @@ func TestCompilePackagesEmitsRecursiveFunctionTypeInfo(t *testing.T) {
|
|
|
1015
2038
|
}
|
|
1016
2039
|
text := string(content)
|
|
1017
2040
|
for _, want := range []string{
|
|
1018
|
-
"export type Handler = ((_p0: ((_p0: Handler) => Handler | globalThis.Promise<Handler>) | null) => Handler | globalThis.Promise<Handler>) | null",
|
|
1019
|
-
"\"Next\": { kind: $.TypeKind.Function, name: \"main.Handler\"",
|
|
2041
|
+
"export type Handler = ((_p0: ((_p0: Handler | null) => Handler | null | globalThis.Promise<Handler | null>) | null) => Handler | null | globalThis.Promise<Handler | null>) | null",
|
|
2042
|
+
"\"Next\": ({ kind: $.TypeKind.Function, name: \"main.Handler\"",
|
|
1020
2043
|
"params: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
1021
2044
|
"results: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
1022
2045
|
} {
|
|
@@ -1082,7 +2105,7 @@ func TestCompilePackagesPacksVariadicCalls(t *testing.T) {
|
|
|
1082
2105
|
"export type Collector = ((label: string, parts: $.Slice<string>) => string | globalThis.Promise<string>) | null",
|
|
1083
2106
|
"Join(parts: $.Slice<string>): string",
|
|
1084
2107
|
"export function collect(label: string, parts: $.Slice<string>): string",
|
|
1085
|
-
"let part =
|
|
2108
|
+
"let part = __goscriptRangeTarget0![__rangeIndex]",
|
|
1086
2109
|
"export function maybeErr(parts: $.Slice<string>): $.GoError",
|
|
1087
2110
|
"public Join(parts: $.Slice<string>): string",
|
|
1088
2111
|
"collect(\"none\", null)",
|
|
@@ -1130,7 +2153,7 @@ func TestCompilePackagesPacksVariadicCallsInGeneratedSubpackage(t *testing.T) {
|
|
|
1130
2153
|
t.Fatal(err.Error())
|
|
1131
2154
|
}
|
|
1132
2155
|
text := string(content)
|
|
1133
|
-
want := "
|
|
2156
|
+
want := "State.prototype.SetErrorf.call(s, \"bad %q\", $.arrayToSlice<any>([key]))"
|
|
1134
2157
|
if !strings.Contains(text, want) {
|
|
1135
2158
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1136
2159
|
}
|
|
@@ -1139,6 +2162,112 @@ func TestCompilePackagesPacksVariadicCallsInGeneratedSubpackage(t *testing.T) {
|
|
|
1139
2162
|
}
|
|
1140
2163
|
}
|
|
1141
2164
|
|
|
2165
|
+
func TestCompilePackagesImportsSelectedExternalFieldTypes(t *testing.T) {
|
|
2166
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2167
|
+
"go.mod": "module example.test/selected-field-import\n\ngo 1.25.3\n",
|
|
2168
|
+
"dep/dep.go": strings.Join([]string{
|
|
2169
|
+
"package dep",
|
|
2170
|
+
"type URL struct { Path string }",
|
|
2171
|
+
"",
|
|
2172
|
+
}, "\n"),
|
|
2173
|
+
"api/api.go": strings.Join([]string{
|
|
2174
|
+
"package api",
|
|
2175
|
+
"import \"example.test/selected-field-import/dep\"",
|
|
2176
|
+
"type Request struct { URL *dep.URL }",
|
|
2177
|
+
"",
|
|
2178
|
+
}, "\n"),
|
|
2179
|
+
"main.go": strings.Join([]string{
|
|
2180
|
+
"package main",
|
|
2181
|
+
"import \"example.test/selected-field-import/api\"",
|
|
2182
|
+
"func requestPath(r *api.Request) string {",
|
|
2183
|
+
" return r.URL.Path",
|
|
2184
|
+
"}",
|
|
2185
|
+
"",
|
|
2186
|
+
}, "\n"),
|
|
2187
|
+
})
|
|
2188
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2189
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir, AllDependencies: true}, nil, nil)
|
|
2190
|
+
if err != nil {
|
|
2191
|
+
t.Fatal(err.Error())
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2195
|
+
t.Fatal(err.Error())
|
|
2196
|
+
}
|
|
2197
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "selected-field-import", "main.gs.ts")
|
|
2198
|
+
content, err := os.ReadFile(outputFile)
|
|
2199
|
+
if err != nil {
|
|
2200
|
+
t.Fatal(err.Error())
|
|
2201
|
+
}
|
|
2202
|
+
text := string(content)
|
|
2203
|
+
for _, want := range []string{
|
|
2204
|
+
"import * as dep from \"@goscript/example.test/selected-field-import/dep/index.js\"",
|
|
2205
|
+
"$.pointerValue<dep.URL>($.pointerValue<api.Request>(r).URL).Path",
|
|
2206
|
+
} {
|
|
2207
|
+
if !strings.Contains(text, want) {
|
|
2208
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
func TestCompilePackagesErasesUnavailableOverrideFieldTypes(t *testing.T) {
|
|
2214
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2215
|
+
"go.mod": "module example.test/override-field-type\n\ngo 1.25.3\n",
|
|
2216
|
+
"dep/dep.go": strings.Join([]string{
|
|
2217
|
+
"package dep",
|
|
2218
|
+
"type URL struct { Path string }",
|
|
2219
|
+
"",
|
|
2220
|
+
}, "\n"),
|
|
2221
|
+
"api/api.go": strings.Join([]string{
|
|
2222
|
+
"package api",
|
|
2223
|
+
"import \"example.test/override-field-type/dep\"",
|
|
2224
|
+
"type Request struct { URL *dep.URL }",
|
|
2225
|
+
"",
|
|
2226
|
+
}, "\n"),
|
|
2227
|
+
"main.go": strings.Join([]string{
|
|
2228
|
+
"package main",
|
|
2229
|
+
"import \"example.test/override-field-type/api\"",
|
|
2230
|
+
"func requestPath(r *api.Request) string {",
|
|
2231
|
+
" return r.URL.Path",
|
|
2232
|
+
"}",
|
|
2233
|
+
"",
|
|
2234
|
+
}, "\n"),
|
|
2235
|
+
})
|
|
2236
|
+
overrideDir := filepath.Join(t.TempDir(), "gs")
|
|
2237
|
+
writeFixtureFile(t, overrideDir, "example.test/override-field-type/api/index.ts", strings.Join([]string{
|
|
2238
|
+
"export class Request {",
|
|
2239
|
+
" public URL: any = null",
|
|
2240
|
+
"}",
|
|
2241
|
+
"",
|
|
2242
|
+
}, "\n"))
|
|
2243
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2244
|
+
comp, err := NewCompiler(&Config{
|
|
2245
|
+
Dir: moduleDir,
|
|
2246
|
+
OutputPath: outputDir,
|
|
2247
|
+
AllDependencies: true,
|
|
2248
|
+
OverrideDirs: []string{overrideDir},
|
|
2249
|
+
}, nil, nil)
|
|
2250
|
+
if err != nil {
|
|
2251
|
+
t.Fatal(err.Error())
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2255
|
+
t.Fatal(err.Error())
|
|
2256
|
+
}
|
|
2257
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "override-field-type", "main.gs.ts")
|
|
2258
|
+
content, err := os.ReadFile(outputFile)
|
|
2259
|
+
if err != nil {
|
|
2260
|
+
t.Fatal(err.Error())
|
|
2261
|
+
}
|
|
2262
|
+
text := string(content)
|
|
2263
|
+
if !strings.Contains(text, "$.pointerValue<any>($.pointerValue<api.Request>(r).URL).Path") {
|
|
2264
|
+
t.Fatalf("missing erased override field type in generated output:\n%s", text)
|
|
2265
|
+
}
|
|
2266
|
+
if strings.Contains(text, "dep.URL") || strings.Contains(text, "pointerValue<URL>") {
|
|
2267
|
+
t.Fatalf("generated output referenced unavailable dependency type:\n%s", text)
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
1142
2271
|
func TestCompilePackagesLowersRangeOverFunctionIterators(t *testing.T) {
|
|
1143
2272
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1144
2273
|
"go.mod": "module example.test/iterators\n\ngo 1.25.3\n",
|
|
@@ -1216,6 +2345,49 @@ func TestCompilePackagesLowersRangeOverFunctionIterators(t *testing.T) {
|
|
|
1216
2345
|
}
|
|
1217
2346
|
}
|
|
1218
2347
|
|
|
2348
|
+
func TestCompilePackagesPreservesNamedFunctionResultTypes(t *testing.T) {
|
|
2349
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2350
|
+
"go.mod": "module example.test/namedfuncresult\n\ngo 1.25.3\n",
|
|
2351
|
+
"main.go": strings.Join([]string{
|
|
2352
|
+
"package main",
|
|
2353
|
+
"type Seq func(func(int) bool)",
|
|
2354
|
+
"func values() Seq {",
|
|
2355
|
+
" return nil",
|
|
2356
|
+
"}",
|
|
2357
|
+
"func main() {",
|
|
2358
|
+
" if values() == nil {",
|
|
2359
|
+
" println(\"empty\")",
|
|
2360
|
+
" }",
|
|
2361
|
+
"}",
|
|
2362
|
+
"",
|
|
2363
|
+
}, "\n"),
|
|
2364
|
+
})
|
|
2365
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2366
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2367
|
+
if err != nil {
|
|
2368
|
+
t.Fatal(err.Error())
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2372
|
+
t.Fatal(err.Error())
|
|
2373
|
+
}
|
|
2374
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "namedfuncresult", "main.gs.ts")
|
|
2375
|
+
content, err := os.ReadFile(outputFile)
|
|
2376
|
+
if err != nil {
|
|
2377
|
+
t.Fatal(err.Error())
|
|
2378
|
+
}
|
|
2379
|
+
text := string(content)
|
|
2380
|
+
for _, want := range []string{
|
|
2381
|
+
"export type Seq = ((_p0: ((_p0: number) => boolean | globalThis.Promise<boolean>) | null) => void) | null",
|
|
2382
|
+
"export function values(): Seq | null",
|
|
2383
|
+
"return (null as Seq | null)",
|
|
2384
|
+
} {
|
|
2385
|
+
if !strings.Contains(text, want) {
|
|
2386
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
|
|
1219
2391
|
func TestCompilePackagesLowersFunctionIteratorControlFlow(t *testing.T) {
|
|
1220
2392
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1221
2393
|
"go.mod": "module example.test/iterator-control\n\ngo 1.25.3\n",
|
|
@@ -1258,17 +2430,203 @@ func TestCompilePackagesLowersFunctionIteratorControlFlow(t *testing.T) {
|
|
|
1258
2430
|
" }",
|
|
1259
2431
|
" return -1",
|
|
1260
2432
|
"}",
|
|
1261
|
-
"func nestedReturn(limit int) int {",
|
|
1262
|
-
" for v := range values {",
|
|
1263
|
-
" for i := range values {",
|
|
1264
|
-
" if i == limit {",
|
|
1265
|
-
" return v + i",
|
|
1266
|
-
" }",
|
|
1267
|
-
" }",
|
|
2433
|
+
"func nestedReturn(limit int) int {",
|
|
2434
|
+
" for v := range values {",
|
|
2435
|
+
" for i := range values {",
|
|
2436
|
+
" if i == limit {",
|
|
2437
|
+
" return v + i",
|
|
2438
|
+
" }",
|
|
2439
|
+
" }",
|
|
2440
|
+
" }",
|
|
2441
|
+
" return -1",
|
|
2442
|
+
"}",
|
|
2443
|
+
"func main() { println(first(3), nestedReturn(2)) }",
|
|
2444
|
+
"",
|
|
2445
|
+
}, "\n"),
|
|
2446
|
+
})
|
|
2447
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2448
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2449
|
+
if err != nil {
|
|
2450
|
+
t.Fatal(err.Error())
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2454
|
+
t.Fatal(err.Error())
|
|
2455
|
+
}
|
|
2456
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "iterator-control", "main.gs.ts")
|
|
2457
|
+
content, err := os.ReadFile(outputFile)
|
|
2458
|
+
if err != nil {
|
|
2459
|
+
t.Fatal(err.Error())
|
|
2460
|
+
}
|
|
2461
|
+
text := string(content)
|
|
2462
|
+
for _, want := range []string{
|
|
2463
|
+
"let __goscriptRangeReturn",
|
|
2464
|
+
"let __goscriptRangeReturnValue",
|
|
2465
|
+
"return true",
|
|
2466
|
+
"return false",
|
|
2467
|
+
"__goscriptRangeReturnValue",
|
|
2468
|
+
"if (__goscriptRangeReturn",
|
|
2469
|
+
"return __goscriptRangeReturnValue",
|
|
2470
|
+
"for (let i = 0; i < j; [i, j] = [i + 1, j - 1])",
|
|
2471
|
+
"for (let i = 0; i < 2; i++)",
|
|
2472
|
+
"switch (v)",
|
|
2473
|
+
"const __goscriptTypeSwitchValue",
|
|
2474
|
+
"switch (true)",
|
|
2475
|
+
"case $.typeAssert<number>(__goscriptTypeSwitchValue, { kind: $.TypeKind.Basic, name: \"int\" }).ok",
|
|
2476
|
+
"break",
|
|
2477
|
+
} {
|
|
2478
|
+
if !strings.Contains(text, want) {
|
|
2479
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
nestedReturn := regexp.MustCompile(`if \(__goscriptRangeReturn\d+\) \{\n\t+__goscriptRangeReturn\d+ = true\n\t+__goscriptRangeReturnValue\d+ = __goscriptRangeReturnValue\d+!\n\t+return false\n\t+\}`)
|
|
2483
|
+
if !nestedReturn.MatchString(text) {
|
|
2484
|
+
t.Fatalf("missing nested range return propagation:\n%s", text)
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
func TestCompilePackagesEmitsAsyncChannelsSelectAndDefer(t *testing.T) {
|
|
2489
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2490
|
+
"go.mod": "module example.test/async\n\ngo 1.25.3\n",
|
|
2491
|
+
"main.go": strings.Join([]string{
|
|
2492
|
+
"package main",
|
|
2493
|
+
"type Processor interface { Process(v int) int }",
|
|
2494
|
+
"type Worker struct { ch chan int }",
|
|
2495
|
+
"func (w *Worker) Process(v int) int {",
|
|
2496
|
+
" w.ch <- v",
|
|
2497
|
+
" return <-w.ch",
|
|
2498
|
+
"}",
|
|
2499
|
+
"func call(p Processor) int { return p.Process(2) }",
|
|
2500
|
+
"func stopLoop(stop chan struct{}, done chan struct{}) {",
|
|
2501
|
+
" for {",
|
|
2502
|
+
" select {",
|
|
2503
|
+
" case <-stop:",
|
|
2504
|
+
" done <- struct{}{}",
|
|
2505
|
+
" return",
|
|
2506
|
+
" }",
|
|
2507
|
+
" }",
|
|
2508
|
+
"}",
|
|
2509
|
+
"func main() {",
|
|
2510
|
+
" ch := make(chan int, 1)",
|
|
2511
|
+
" defer func() { <-ch }()",
|
|
2512
|
+
" go func() { ch <- 1 }()",
|
|
2513
|
+
" select {",
|
|
2514
|
+
" case v := <-ch:",
|
|
2515
|
+
" println(v)",
|
|
2516
|
+
" default:",
|
|
2517
|
+
" println(\"default\")",
|
|
2518
|
+
" }",
|
|
2519
|
+
" _ = call(&Worker{ch: make(chan int, 1)})",
|
|
2520
|
+
"}",
|
|
2521
|
+
"",
|
|
2522
|
+
}, "\n"),
|
|
2523
|
+
})
|
|
2524
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2525
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2526
|
+
if err != nil {
|
|
2527
|
+
t.Fatal(err.Error())
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2531
|
+
t.Fatal(err.Error())
|
|
2532
|
+
}
|
|
2533
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "async", "main.gs.ts")
|
|
2534
|
+
content, err := os.ReadFile(outputFile)
|
|
2535
|
+
if err != nil {
|
|
2536
|
+
t.Fatal(err.Error())
|
|
2537
|
+
}
|
|
2538
|
+
text := string(content)
|
|
2539
|
+
for _, want := range []string{
|
|
2540
|
+
"Process(v: number): number | globalThis.Promise<number>",
|
|
2541
|
+
"public async Process(v: number): globalThis.Promise<number>",
|
|
2542
|
+
"let ch = $.makeChannel<number>(1, 0, \"both\")",
|
|
2543
|
+
"await $.chanSend($.pointerValue<Worker>(w).ch, v)",
|
|
2544
|
+
"return await $.chanRecv($.pointerValue<Worker>(w).ch)",
|
|
2545
|
+
"await using __defer = new $.AsyncDisposableStack()",
|
|
2546
|
+
"queueMicrotask(async () => { await ($.functionValue(async (): globalThis.Promise<void> => {",
|
|
2547
|
+
"$.selectStatement<any, void>([",
|
|
2548
|
+
"let v = __goscriptSelect1Result.value",
|
|
2549
|
+
"return $.selectVoidReturn()",
|
|
2550
|
+
"await call($.interfaceValue<Processor | null>(new Worker({ch: $.makeChannel<number>(1, 0, \"both\")}), \"*main.Worker\"))",
|
|
2551
|
+
} {
|
|
2552
|
+
if !strings.Contains(text, want) {
|
|
2553
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
func TestCompilePackagesMarksSelectReturningIfElseCasesUnreachable(t *testing.T) {
|
|
2559
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2560
|
+
"go.mod": "module example.test/select-if-else\n\ngo 1.25.3\n",
|
|
2561
|
+
"main.go": strings.Join([]string{
|
|
2562
|
+
"package main",
|
|
2563
|
+
"import \"context\"",
|
|
2564
|
+
"func finish(ctx context.Context, ch <-chan int, client bool) (int, error) {",
|
|
2565
|
+
" select {",
|
|
2566
|
+
" case <-ch:",
|
|
2567
|
+
" if client {",
|
|
2568
|
+
" return 1, nil",
|
|
2569
|
+
" } else {",
|
|
2570
|
+
" return 2, nil",
|
|
2571
|
+
" }",
|
|
2572
|
+
" case <-ctx.Done():",
|
|
2573
|
+
" return 3, ctx.Err()",
|
|
2574
|
+
" }",
|
|
2575
|
+
"}",
|
|
2576
|
+
"",
|
|
2577
|
+
}, "\n"),
|
|
2578
|
+
})
|
|
2579
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2580
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2581
|
+
if err != nil {
|
|
2582
|
+
t.Fatal(err.Error())
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2586
|
+
t.Fatal(err.Error())
|
|
2587
|
+
}
|
|
2588
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "select-if-else", "main.gs.ts")
|
|
2589
|
+
content, err := os.ReadFile(outputFile)
|
|
2590
|
+
if err != nil {
|
|
2591
|
+
t.Fatal(err.Error())
|
|
2592
|
+
}
|
|
2593
|
+
text := string(content)
|
|
2594
|
+
for _, want := range []string{
|
|
2595
|
+
"export async function finish(ctx: context.Context | null, ch: $.Channel<number> | null, client: boolean): globalThis.Promise<[number, $.GoError]>",
|
|
2596
|
+
"if (__goscriptSelect0HasReturn) {",
|
|
2597
|
+
"throw new Error(\"unreachable select\")",
|
|
2598
|
+
} {
|
|
2599
|
+
if !strings.Contains(text, want) {
|
|
2600
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
|
|
2605
|
+
func TestCompilePackagesPropagatesImmediateFuncLitAsync(t *testing.T) {
|
|
2606
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2607
|
+
"go.mod": "module example.test/immediate-func-lit-async\n\ngo 1.25.3\n",
|
|
2608
|
+
"main.go": strings.Join([]string{
|
|
2609
|
+
"package main",
|
|
2610
|
+
"import \"sync\"",
|
|
2611
|
+
"type resolver struct {",
|
|
2612
|
+
" parent *resolver",
|
|
2613
|
+
" mutex sync.Mutex",
|
|
2614
|
+
"}",
|
|
2615
|
+
"func (r *resolver) lookup() (int, error) {",
|
|
2616
|
+
" value := func() int {",
|
|
2617
|
+
" r.mutex.Lock()",
|
|
2618
|
+
" defer r.mutex.Unlock()",
|
|
2619
|
+
" return 7",
|
|
2620
|
+
" }()",
|
|
2621
|
+
" if r.parent != nil {",
|
|
2622
|
+
" return r.parent.lookup()",
|
|
1268
2623
|
" }",
|
|
1269
|
-
" return
|
|
2624
|
+
" return value, nil",
|
|
1270
2625
|
"}",
|
|
1271
|
-
"func
|
|
2626
|
+
"func use(r *resolver) (int, error) {",
|
|
2627
|
+
" return r.lookup()",
|
|
2628
|
+
"}",
|
|
2629
|
+
"func main() {}",
|
|
1272
2630
|
"",
|
|
1273
2631
|
}, "\n"),
|
|
1274
2632
|
})
|
|
@@ -1281,61 +2639,44 @@ func TestCompilePackagesLowersFunctionIteratorControlFlow(t *testing.T) {
|
|
|
1281
2639
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1282
2640
|
t.Fatal(err.Error())
|
|
1283
2641
|
}
|
|
1284
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
2642
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "immediate-func-lit-async", "main.gs.ts")
|
|
1285
2643
|
content, err := os.ReadFile(outputFile)
|
|
1286
2644
|
if err != nil {
|
|
1287
2645
|
t.Fatal(err.Error())
|
|
1288
2646
|
}
|
|
1289
2647
|
text := string(content)
|
|
1290
2648
|
for _, want := range []string{
|
|
1291
|
-
"
|
|
1292
|
-
"
|
|
1293
|
-
"
|
|
1294
|
-
"return
|
|
1295
|
-
"__goscriptRangeReturnValue",
|
|
1296
|
-
"if (__goscriptRangeReturn",
|
|
1297
|
-
"return __goscriptRangeReturnValue",
|
|
1298
|
-
"for (let i = 0; i < j; [i, j] = [i + 1, j - 1])",
|
|
1299
|
-
"for (let i = 0; i < 2; i++)",
|
|
1300
|
-
"switch (v)",
|
|
1301
|
-
"const __goscriptTypeSwitchValue",
|
|
1302
|
-
"switch (true)",
|
|
1303
|
-
"case $.typeAssert<number>(__goscriptTypeSwitchValue, { kind: $.TypeKind.Basic, name: \"int\" }).ok",
|
|
1304
|
-
"break",
|
|
2649
|
+
"public async lookup(): globalThis.Promise<[number, $.GoError]>",
|
|
2650
|
+
"return await resolver.prototype.lookup.call($.pointerValue<resolver>(r).parent)",
|
|
2651
|
+
"export async function use(r: resolver | $.VarRef<resolver> | null): globalThis.Promise<[number, $.GoError]>",
|
|
2652
|
+
"return await resolver.prototype.lookup.call(r)",
|
|
1305
2653
|
} {
|
|
1306
2654
|
if !strings.Contains(text, want) {
|
|
1307
2655
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1308
2656
|
}
|
|
1309
2657
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
t.Fatalf("missing nested range return propagation:\n%s", text)
|
|
2658
|
+
if strings.Contains(text, "const __goscriptReturn0 = resolver.prototype.lookup.call") {
|
|
2659
|
+
t.Fatalf("immediate func-literal async method call was not awaited:\n%s", text)
|
|
1313
2660
|
}
|
|
1314
2661
|
}
|
|
1315
2662
|
|
|
1316
|
-
func
|
|
2663
|
+
func TestCompilePackagesParenthesizesAsyncFieldReceivers(t *testing.T) {
|
|
1317
2664
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1318
|
-
"go.mod": "module example.test/
|
|
2665
|
+
"go.mod": "module example.test/asyncfield\n\ngo 1.25.3\n",
|
|
1319
2666
|
"main.go": strings.Join([]string{
|
|
1320
2667
|
"package main",
|
|
1321
|
-
"type
|
|
1322
|
-
"type
|
|
1323
|
-
"func (
|
|
1324
|
-
"
|
|
1325
|
-
" return
|
|
2668
|
+
"type Result struct { ok bool }",
|
|
2669
|
+
"type Box struct { ch chan int }",
|
|
2670
|
+
"func (b *Box) next() Result {",
|
|
2671
|
+
" b.ch <- 1",
|
|
2672
|
+
" return Result{ok: true}",
|
|
2673
|
+
"}",
|
|
2674
|
+
"func (b *Box) OK() bool {",
|
|
2675
|
+
" return b.next().ok",
|
|
1326
2676
|
"}",
|
|
1327
|
-
"func call(p Processor) int { return p.Process(2) }",
|
|
1328
2677
|
"func main() {",
|
|
1329
|
-
"
|
|
1330
|
-
"
|
|
1331
|
-
" go func() { ch <- 1 }()",
|
|
1332
|
-
" select {",
|
|
1333
|
-
" case v := <-ch:",
|
|
1334
|
-
" println(v)",
|
|
1335
|
-
" default:",
|
|
1336
|
-
" println(\"default\")",
|
|
1337
|
-
" }",
|
|
1338
|
-
" _ = call(&Worker{ch: make(chan int, 1)})",
|
|
2678
|
+
" box := &Box{ch: make(chan int, 1)}",
|
|
2679
|
+
" println(box.OK())",
|
|
1339
2680
|
"}",
|
|
1340
2681
|
"",
|
|
1341
2682
|
}, "\n"),
|
|
@@ -1349,27 +2690,17 @@ func TestCompilePackagesEmitsAsyncChannelsSelectAndDefer(t *testing.T) {
|
|
|
1349
2690
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1350
2691
|
t.Fatal(err.Error())
|
|
1351
2692
|
}
|
|
1352
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
2693
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncfield", "main.gs.ts")
|
|
1353
2694
|
content, err := os.ReadFile(outputFile)
|
|
1354
2695
|
if err != nil {
|
|
1355
2696
|
t.Fatal(err.Error())
|
|
1356
2697
|
}
|
|
1357
2698
|
text := string(content)
|
|
1358
|
-
|
|
1359
|
-
"
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
"await
|
|
1363
|
-
"return await $.chanRecv($.pointerValue<Worker>(w).ch)",
|
|
1364
|
-
"await using __defer = new $.AsyncDisposableStack()",
|
|
1365
|
-
"queueMicrotask(async () => { await ($.functionValue(async (): globalThis.Promise<void> => {",
|
|
1366
|
-
"$.selectStatement<any, void>([",
|
|
1367
|
-
"let v = result.value",
|
|
1368
|
-
"await call($.interfaceValue<Processor | null>(new Worker({ch: $.makeChannel<number>(1, 0, \"both\")}), \"*main.Worker\"))",
|
|
1369
|
-
} {
|
|
1370
|
-
if !strings.Contains(text, want) {
|
|
1371
|
-
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1372
|
-
}
|
|
2699
|
+
if !strings.Contains(text, "return (await Box.prototype.next.call(b)).ok") {
|
|
2700
|
+
t.Fatalf("async field receiver was not parenthesized:\n%s", text)
|
|
2701
|
+
}
|
|
2702
|
+
if strings.Contains(text, "return await Box.prototype.next.call(b).ok") {
|
|
2703
|
+
t.Fatalf("async field receiver selected the promise before await:\n%s", text)
|
|
1373
2704
|
}
|
|
1374
2705
|
}
|
|
1375
2706
|
|
|
@@ -1650,6 +2981,298 @@ func TestCompilePackagesLowersUnaryBitwiseComplement(t *testing.T) {
|
|
|
1650
2981
|
}
|
|
1651
2982
|
}
|
|
1652
2983
|
|
|
2984
|
+
func TestCompilePackagesParenthesizesRepeatedUnarySigns(t *testing.T) {
|
|
2985
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2986
|
+
"go.mod": "module example.test/unary-signs\n\ngo 1.25.3\n",
|
|
2987
|
+
"constants.go": strings.Join([]string{
|
|
2988
|
+
"package main",
|
|
2989
|
+
"const extOffset = -0x1000",
|
|
2990
|
+
"",
|
|
2991
|
+
}, "\n"),
|
|
2992
|
+
"main.go": strings.Join([]string{
|
|
2993
|
+
"package main",
|
|
2994
|
+
"type Extension int32",
|
|
2995
|
+
"type LoadExtension struct { Num Extension }",
|
|
2996
|
+
"func Decode(k int32) LoadExtension {",
|
|
2997
|
+
" return LoadExtension{Num: Extension(-extOffset + k)}",
|
|
2998
|
+
"}",
|
|
2999
|
+
"",
|
|
3000
|
+
}, "\n"),
|
|
3001
|
+
})
|
|
3002
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3003
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3004
|
+
if err != nil {
|
|
3005
|
+
t.Fatal(err.Error())
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3009
|
+
t.Fatal(err.Error())
|
|
3010
|
+
}
|
|
3011
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "unary-signs", "main.gs.ts")
|
|
3012
|
+
content, err := os.ReadFile(outputFile)
|
|
3013
|
+
if err != nil {
|
|
3014
|
+
t.Fatal(err.Error())
|
|
3015
|
+
}
|
|
3016
|
+
text := string(content)
|
|
3017
|
+
if strings.Contains(text, "--4096") {
|
|
3018
|
+
t.Fatalf("generated invalid decrement token:\n%s", text)
|
|
3019
|
+
}
|
|
3020
|
+
if !strings.Contains(text, "-(-4096) + k") {
|
|
3021
|
+
t.Fatalf("missing parenthesized negative constant:\n%s", text)
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
func TestCompilePackagesNormalizesWideIntegerReturnTargets(t *testing.T) {
|
|
3026
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3027
|
+
"go.mod": "module example.test/wide-return\n\ngo 1.25.3\n",
|
|
3028
|
+
"main.go": strings.Join([]string{
|
|
3029
|
+
"package main",
|
|
3030
|
+
"import \"hash\"",
|
|
3031
|
+
"func Read(h hash.Hash64) uint64 {",
|
|
3032
|
+
" return h.Sum64()",
|
|
3033
|
+
"}",
|
|
3034
|
+
"",
|
|
3035
|
+
}, "\n"),
|
|
3036
|
+
})
|
|
3037
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3038
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3039
|
+
if err != nil {
|
|
3040
|
+
t.Fatal(err.Error())
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3044
|
+
t.Fatal(err.Error())
|
|
3045
|
+
}
|
|
3046
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "wide-return", "main.gs.ts")
|
|
3047
|
+
content, err := os.ReadFile(outputFile)
|
|
3048
|
+
if err != nil {
|
|
3049
|
+
t.Fatal(err.Error())
|
|
3050
|
+
}
|
|
3051
|
+
text := string(content)
|
|
3052
|
+
if !strings.Contains(text, "return $.uint($.pointerValue<Exclude<hash.Hash64, null>>(h).Sum64(), 64)") {
|
|
3053
|
+
t.Fatalf("missing uint64 return normalization:\n%s", text)
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
func TestCompilePackagesUnwrapsImportedVarRefValueMethodReceiver(t *testing.T) {
|
|
3058
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3059
|
+
"go.mod": "module example.test/imported-varref-receiver\n\ngo 1.25.3\n",
|
|
3060
|
+
"dep/dep.go": strings.Join([]string{
|
|
3061
|
+
"package dep",
|
|
3062
|
+
"type Info struct { Count int }",
|
|
3063
|
+
"func (i Info) Enabled() bool { return i.Count > 0 }",
|
|
3064
|
+
"func addInfo(i *Info) { i.Count = 1 }",
|
|
3065
|
+
"var CPU Info",
|
|
3066
|
+
"func init() { addInfo(&CPU) }",
|
|
3067
|
+
"",
|
|
3068
|
+
}, "\n"),
|
|
3069
|
+
"main.go": strings.Join([]string{
|
|
3070
|
+
"package main",
|
|
3071
|
+
"import \"example.test/imported-varref-receiver/dep\"",
|
|
3072
|
+
"func Enabled() bool {",
|
|
3073
|
+
" return dep.CPU.Enabled()",
|
|
3074
|
+
"}",
|
|
3075
|
+
"",
|
|
3076
|
+
}, "\n"),
|
|
3077
|
+
})
|
|
3078
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3079
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3080
|
+
if err != nil {
|
|
3081
|
+
t.Fatal(err.Error())
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3085
|
+
t.Fatal(err.Error())
|
|
3086
|
+
}
|
|
3087
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "imported-varref-receiver", "main.gs.ts")
|
|
3088
|
+
content, err := os.ReadFile(outputFile)
|
|
3089
|
+
if err != nil {
|
|
3090
|
+
t.Fatal(err.Error())
|
|
3091
|
+
}
|
|
3092
|
+
text := string(content)
|
|
3093
|
+
if !strings.Contains(text, "$.cloneStructValue($.pointerValue<dep.Info>(dep.CPU))") {
|
|
3094
|
+
t.Fatalf("missing imported VarRef receiver unwrap:\n%s", text)
|
|
3095
|
+
}
|
|
3096
|
+
if strings.Contains(text, "$.cloneStructValue(dep.CPU))") {
|
|
3097
|
+
t.Fatalf("imported VarRef receiver stayed wrapped:\n%s", text)
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
func TestCompilePackagesUnwrapsImportedArrayPackageVarReads(t *testing.T) {
|
|
3102
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3103
|
+
"go.mod": "module example.test/imported-array-var\n\ngo 1.25.3\n",
|
|
3104
|
+
"dep/dep.go": strings.Join([]string{
|
|
3105
|
+
"package dep",
|
|
3106
|
+
"var Table = [2]int{3, 5}",
|
|
3107
|
+
"func touch(v *[2]int) { v[0]++ }",
|
|
3108
|
+
"func init() { touch(&Table) }",
|
|
3109
|
+
"func Sum(v [2]int) int { return v[0] + v[1] }",
|
|
3110
|
+
"",
|
|
3111
|
+
}, "\n"),
|
|
3112
|
+
"main.go": strings.Join([]string{
|
|
3113
|
+
"package main",
|
|
3114
|
+
"import \"example.test/imported-array-var/dep\"",
|
|
3115
|
+
"func Read() int {",
|
|
3116
|
+
" return dep.Table[1] + dep.Sum(dep.Table)",
|
|
3117
|
+
"}",
|
|
3118
|
+
"",
|
|
3119
|
+
}, "\n"),
|
|
3120
|
+
})
|
|
3121
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3122
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3123
|
+
if err != nil {
|
|
3124
|
+
t.Fatal(err.Error())
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3128
|
+
t.Fatal(err.Error())
|
|
3129
|
+
}
|
|
3130
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "imported-array-var", "main.gs.ts")
|
|
3131
|
+
content, err := os.ReadFile(outputFile)
|
|
3132
|
+
if err != nil {
|
|
3133
|
+
t.Fatal(err.Error())
|
|
3134
|
+
}
|
|
3135
|
+
text := string(content)
|
|
3136
|
+
for _, want := range []string{
|
|
3137
|
+
"$.pointerValue<number[]>(dep.Table)[1]",
|
|
3138
|
+
"dep.Sum($.pointerValue<number[]>(dep.Table))",
|
|
3139
|
+
} {
|
|
3140
|
+
if !strings.Contains(text, want) {
|
|
3141
|
+
t.Fatalf("missing imported array package var read %q:\n%s", want, text)
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
|
|
3146
|
+
func TestCompilePackagesAddressesImportedArrayPackageVarsAsRefs(t *testing.T) {
|
|
3147
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3148
|
+
"go.mod": "module example.test/imported-array-var-address\n\ngo 1.25.3\n",
|
|
3149
|
+
"dep/dep.go": strings.Join([]string{
|
|
3150
|
+
"package dep",
|
|
3151
|
+
"var Table = [2]int{3, 5}",
|
|
3152
|
+
"func touch(v *[2]int) { v[0]++ }",
|
|
3153
|
+
"func init() { touch(&Table) }",
|
|
3154
|
+
"func SumPtr(v *[2]int) int { return v[0] + v[1] }",
|
|
3155
|
+
"",
|
|
3156
|
+
}, "\n"),
|
|
3157
|
+
"main.go": strings.Join([]string{
|
|
3158
|
+
"package main",
|
|
3159
|
+
"import \"example.test/imported-array-var-address/dep\"",
|
|
3160
|
+
"func Read() int {",
|
|
3161
|
+
" return dep.SumPtr(&dep.Table)",
|
|
3162
|
+
"}",
|
|
3163
|
+
"",
|
|
3164
|
+
}, "\n"),
|
|
3165
|
+
})
|
|
3166
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3167
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3168
|
+
if err != nil {
|
|
3169
|
+
t.Fatal(err.Error())
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3173
|
+
t.Fatal(err.Error())
|
|
3174
|
+
}
|
|
3175
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "imported-array-var-address", "main.gs.ts")
|
|
3176
|
+
content, err := os.ReadFile(outputFile)
|
|
3177
|
+
if err != nil {
|
|
3178
|
+
t.Fatal(err.Error())
|
|
3179
|
+
}
|
|
3180
|
+
text := string(content)
|
|
3181
|
+
if !strings.Contains(text, "dep.SumPtr(dep.Table)") {
|
|
3182
|
+
t.Fatalf("missing imported array package var address:\n%s", text)
|
|
3183
|
+
}
|
|
3184
|
+
if strings.Contains(text, "dep.SumPtr($.pointerValue<number[]>(dep.Table))") ||
|
|
3185
|
+
strings.Contains(text, "dep._fields.Table") {
|
|
3186
|
+
t.Fatalf("imported array package var address was lowered as a read or field:\n%s", text)
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
func TestCompilePackagesUnwrapsAliasedArrayPackageVarReads(t *testing.T) {
|
|
3191
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3192
|
+
"go.mod": "module example.test/aliased-array-var\n\ngo 1.25.3\n",
|
|
3193
|
+
"table.go": strings.Join([]string{
|
|
3194
|
+
"package main",
|
|
3195
|
+
"var Table = [2]int{3, 5}",
|
|
3196
|
+
"func touch(v *[2]int) { v[0]++ }",
|
|
3197
|
+
"func init() { touch(&Table) }",
|
|
3198
|
+
"func Sum(v [2]int) int { return v[0] + v[1] }",
|
|
3199
|
+
"",
|
|
3200
|
+
}, "\n"),
|
|
3201
|
+
"read.go": strings.Join([]string{
|
|
3202
|
+
"package main",
|
|
3203
|
+
"func Read() int {",
|
|
3204
|
+
" return Table[1] + Sum(Table)",
|
|
3205
|
+
"}",
|
|
3206
|
+
"",
|
|
3207
|
+
}, "\n"),
|
|
3208
|
+
})
|
|
3209
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3210
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3211
|
+
if err != nil {
|
|
3212
|
+
t.Fatal(err.Error())
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3216
|
+
t.Fatal(err.Error())
|
|
3217
|
+
}
|
|
3218
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "aliased-array-var", "read.gs.ts")
|
|
3219
|
+
content, err := os.ReadFile(outputFile)
|
|
3220
|
+
if err != nil {
|
|
3221
|
+
t.Fatal(err.Error())
|
|
3222
|
+
}
|
|
3223
|
+
text := string(content)
|
|
3224
|
+
for _, want := range []string{
|
|
3225
|
+
"$.pointerValue<number[]>(__goscript_table.Table)[1]",
|
|
3226
|
+
"Sum($.pointerValue<number[]>(__goscript_table.Table))",
|
|
3227
|
+
} {
|
|
3228
|
+
if !strings.Contains(text, want) {
|
|
3229
|
+
t.Fatalf("missing aliased array package var read %q:\n%s", want, text)
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
func TestCompilePackagesAddressesAliasedArrayPackageVarsAsRefs(t *testing.T) {
|
|
3235
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3236
|
+
"go.mod": "module example.test/aliased-array-var-address\n\ngo 1.25.3\n",
|
|
3237
|
+
"table.go": strings.Join([]string{
|
|
3238
|
+
"package main",
|
|
3239
|
+
"var Table = [2]int{3, 5}",
|
|
3240
|
+
"func touch(v *[2]int) { v[0]++ }",
|
|
3241
|
+
"func init() { touch(&Table) }",
|
|
3242
|
+
"func SumPtr(v *[2]int) int { return v[0] + v[1] }",
|
|
3243
|
+
"",
|
|
3244
|
+
}, "\n"),
|
|
3245
|
+
"read.go": strings.Join([]string{
|
|
3246
|
+
"package main",
|
|
3247
|
+
"func Read() int {",
|
|
3248
|
+
" return SumPtr(&Table)",
|
|
3249
|
+
"}",
|
|
3250
|
+
"",
|
|
3251
|
+
}, "\n"),
|
|
3252
|
+
})
|
|
3253
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3254
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3255
|
+
if err != nil {
|
|
3256
|
+
t.Fatal(err.Error())
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3260
|
+
t.Fatal(err.Error())
|
|
3261
|
+
}
|
|
3262
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "aliased-array-var-address", "read.gs.ts")
|
|
3263
|
+
content, err := os.ReadFile(outputFile)
|
|
3264
|
+
if err != nil {
|
|
3265
|
+
t.Fatal(err.Error())
|
|
3266
|
+
}
|
|
3267
|
+
text := string(content)
|
|
3268
|
+
if !strings.Contains(text, "SumPtr(__goscript_table.Table)") {
|
|
3269
|
+
t.Fatalf("missing aliased array package var address:\n%s", text)
|
|
3270
|
+
}
|
|
3271
|
+
if strings.Contains(text, "SumPtr($.pointerValue<number[]>(__goscript_table.Table))") {
|
|
3272
|
+
t.Fatalf("aliased array package var address was lowered as a read:\n%s", text)
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
|
|
1653
3276
|
func TestCompileSourceToTypeScriptCompilesSingleFile(t *testing.T) {
|
|
1654
3277
|
output, err := CompileSourceToTypeScript("package main\nfunc main() { println(\"hi\") }\n", "main")
|
|
1655
3278
|
if err != nil {
|