goscript 0.1.0 → 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/README.md +267 -255
- package/cmd/goscript/cmd-test.go +286 -0
- package/cmd/goscript/cmd-test_test.go +76 -0
- package/cmd/goscript/cmd_compile.go +9 -0
- package/cmd/goscript/main.go +1 -0
- package/compiler/build-flags.go +38 -0
- package/compiler/compile-request.go +33 -0
- package/compiler/compiler.go +1 -1
- package/compiler/compliance_test.go +0 -10
- package/compiler/config.go +2 -0
- package/compiler/gotest/owner.go +24 -0
- package/compiler/gotest/package-result.go +69 -0
- package/compiler/gotest/request.go +210 -0
- package/compiler/gotest/result.go +28 -0
- package/compiler/gotest/runner.go +1225 -0
- package/compiler/gotest/runner_test.go +1271 -0
- package/compiler/gotest/test.go +9 -0
- package/compiler/index.test.ts +1 -1
- package/compiler/lowered-program.go +80 -21
- package/compiler/lowering.go +6754 -602
- package/compiler/override-facts.go +357 -0
- package/compiler/override-registry.go +52 -190
- package/compiler/override-registry_test.go +182 -0
- package/compiler/package-graph.go +50 -27
- package/compiler/package-graph_test.go +99 -9
- package/compiler/package-test-function.go +9 -0
- package/compiler/package-test-graph-package.go +40 -0
- package/compiler/package-test-graph-variant.go +129 -0
- package/compiler/package-test-graph.go +112 -0
- package/compiler/package-test-graph_test.go +202 -0
- package/compiler/runtime-contract.go +229 -29
- package/compiler/runtime-contract_test.go +44 -30
- package/compiler/semantic-model-types.go +25 -6
- package/compiler/semantic-model.go +819 -74
- package/compiler/semantic-model_test.go +104 -0
- package/compiler/service.go +10 -4
- package/compiler/skeleton_test.go +2777 -524
- package/compiler/tsworkspace/owner-process-unix_test.go +72 -0
- package/compiler/tsworkspace/owner.go +342 -0
- package/compiler/tsworkspace/owner_test.go +93 -0
- package/compiler/tsworkspace/result.go +17 -0
- package/compiler/tsworkspace/tool-process-other.go +14 -0
- package/compiler/tsworkspace/tool-process-unix.go +19 -0
- package/compiler/typescript-emitter.go +576 -86
- package/compiler/wasm/compile.go +1 -1
- package/compiler/wasm/compile_test.go +61 -11
- package/compiler/wasm_api.go +172 -7
- package/dist/gs/builtin/builtin.d.ts +40 -3
- package/dist/gs/builtin/builtin.js +430 -22
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +32 -10
- package/dist/gs/builtin/channel.js +119 -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 +64 -10
- package/dist/gs/builtin/slice.js +619 -244
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +7 -2
- package/dist/gs/builtin/type.js +128 -29
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +7 -0
- package/dist/gs/builtin/varRef.js +23 -0
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js +74 -70
- 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/bytes/reader.gs.js +20 -18
- package/dist/gs/bytes/reader.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 +6 -5
- package/dist/gs/context/context.js +17 -12
- 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/internal/fips140deps/byteorder/index.d.ts +1 -0
- package/dist/gs/crypto/internal/fips140deps/byteorder/index.js +2 -0
- package/dist/gs/crypto/internal/fips140deps/byteorder/index.js.map +1 -0
- package/dist/gs/crypto/internal/fips140deps/godebug/index.d.ts +1 -0
- package/dist/gs/crypto/internal/fips140deps/godebug/index.js +2 -0
- package/dist/gs/crypto/internal/fips140deps/godebug/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/embed/index.d.ts +7 -0
- package/dist/gs/embed/index.js +16 -0
- package/dist/gs/embed/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +4 -0
- package/dist/gs/encoding/json/index.js +33 -0
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/errors/errors.d.ts +4 -0
- package/dist/gs/errors/errors.js +108 -4
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/fmt/fmt.d.ts +4 -4
- package/dist/gs/fmt/fmt.js +42 -11
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +37 -2
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +245 -1
- 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.d.ts +189 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +861 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -0
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +217 -0
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +814 -0
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -0
- 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.d.ts +9 -0
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js +72 -0
- package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -0
- 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/internal/scannerhooks/index.d.ts +3 -0
- package/dist/gs/go/internal/scannerhooks/index.js +5 -0
- package/dist/gs/go/internal/scannerhooks/index.js.map +1 -0
- package/dist/gs/go/scanner/index.d.ts +13 -0
- package/dist/gs/go/scanner/index.js +35 -0
- package/dist/gs/go/scanner/index.js.map +1 -1
- package/dist/gs/go/token/index.d.ts +156 -0
- package/dist/gs/go/token/index.js +507 -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/internal/abi/index.d.ts +4 -0
- package/dist/gs/internal/abi/index.js +10 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/internal/bytealg/index.d.ts +2 -0
- package/dist/gs/internal/bytealg/index.js +14 -0
- package/dist/gs/internal/bytealg/index.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +8 -2
- package/dist/gs/internal/byteorder/index.js +56 -25
- package/dist/gs/internal/byteorder/index.js.map +1 -1
- package/dist/gs/internal/godebug/index.d.ts +12 -0
- package/dist/gs/internal/godebug/index.js +30 -0
- package/dist/gs/internal/godebug/index.js.map +1 -0
- package/dist/gs/io/fs/index.d.ts +1 -0
- package/dist/gs/io/fs/index.js +1 -0
- package/dist/gs/io/fs/index.js.map +1 -1
- package/dist/gs/io/fs/readlink.d.ts +8 -0
- package/dist/gs/io/fs/readlink.js +60 -0
- package/dist/gs/io/fs/readlink.js.map +1 -0
- package/dist/gs/io/fs/walk.d.ts +3 -3
- package/dist/gs/io/fs/walk.js +7 -7
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/io/io.d.ts +40 -6
- package/dist/gs/io/io.js +151 -26
- 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/maps/maps.js +1 -1
- package/dist/gs/maps/maps.js.map +1 -1
- package/dist/gs/math/bits/index.d.ts +13 -4
- package/dist/gs/math/bits/index.js +70 -48
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/math/const.gs.d.ts +5 -5
- package/dist/gs/math/const.gs.js +4 -4
- package/dist/gs/math/const.gs.js.map +1 -1
- package/dist/gs/mime/index.d.ts +1 -0
- package/dist/gs/mime/index.js +52 -0
- package/dist/gs/mime/index.js.map +1 -0
- package/dist/gs/net/http/httptest/index.d.ts +30 -0
- package/dist/gs/net/http/httptest/index.js +101 -0
- package/dist/gs/net/http/httptest/index.js.map +1 -0
- package/dist/gs/net/http/index.d.ts +131 -0
- package/dist/gs/net/http/index.js +307 -0
- package/dist/gs/net/http/index.js.map +1 -0
- 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/dir_unix.gs.js +2 -2
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- 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 +165 -3
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.d.ts +8 -4
- package/dist/gs/path/filepath/path.js +192 -8
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/path/path.d.ts +4 -1
- package/dist/gs/path/path.js +16 -4
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +4 -3
- package/dist/gs/reflect/index.js +3 -2
- 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 +29 -0
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +31 -9
- package/dist/gs/reflect/type.js +536 -43
- 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 +41 -0
- package/dist/gs/runtime/debug/index.js +66 -0
- package/dist/gs/runtime/debug/index.js.map +1 -0
- 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/runtime.d.ts +35 -3
- package/dist/gs/runtime/runtime.js +72 -0
- package/dist/gs/runtime/runtime.js.map +1 -1
- 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 +42 -8
- package/dist/gs/slices/slices.js +425 -11
- 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 +60 -22
- package/dist/gs/sort/slice.gs.js.map +1 -1
- package/dist/gs/sort/sort.gs.d.ts +4 -4
- package/dist/gs/sort/sort.gs.js +11 -8
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strings/builder.d.ts +1 -1
- package/dist/gs/strings/builder.js +29 -19
- 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/atomic/type.gs.d.ts +9 -8
- package/dist/gs/sync/atomic/type.gs.js +0 -2
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +8 -3
- package/dist/gs/sync/sync.js +66 -11
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/constants.d.ts +36 -24
- package/dist/gs/syscall/constants.js +12 -0
- package/dist/gs/syscall/constants.js.map +1 -1
- package/dist/gs/syscall/errors.d.ts +117 -111
- package/dist/gs/syscall/errors.js +45 -0
- package/dist/gs/syscall/errors.js.map +1 -1
- package/dist/gs/syscall/fs.d.ts +37 -0
- package/dist/gs/syscall/fs.js +102 -0
- package/dist/gs/syscall/fs.js.map +1 -1
- package/dist/gs/syscall/js/index.d.ts +90 -0
- package/dist/gs/syscall/js/index.js +383 -0
- package/dist/gs/syscall/js/index.js.map +1 -0
- package/dist/gs/syscall/types.d.ts +26 -1
- package/dist/gs/syscall/types.js +45 -1
- package/dist/gs/syscall/types.js.map +1 -1
- package/dist/gs/testing/index.d.ts +1 -0
- package/dist/gs/testing/index.js +2 -0
- package/dist/gs/testing/index.js.map +1 -0
- package/dist/gs/testing/testing.d.ts +78 -0
- package/dist/gs/testing/testing.js +318 -0
- package/dist/gs/testing/testing.js.map +1 -0
- package/dist/gs/time/time.d.ts +41 -4
- package/dist/gs/time/time.js +227 -36
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.d.ts +23 -1
- package/dist/gs/unicode/unicode.js +79 -10
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/dist/gs/unicode/utf8/utf8.d.ts +4 -4
- package/dist/gs/unicode/utf8/utf8.js +24 -11
- package/dist/gs/unicode/utf8/utf8.js.map +1 -1
- package/dist/gs/unique/index.d.ts +11 -0
- package/dist/gs/unique/index.js +76 -0
- package/dist/gs/unique/index.js.map +1 -0
- package/go.mod +8 -8
- package/go.sum +14 -14
- package/gs/builtin/builtin.ts +585 -27
- package/gs/builtin/channel.ts +183 -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 +383 -10
- package/gs/builtin/slice.test.ts +70 -0
- package/gs/builtin/slice.ts +785 -265
- package/gs/builtin/type.ts +160 -41
- package/gs/builtin/varRef.ts +40 -1
- package/gs/bytes/buffer.gs.ts +74 -70
- package/gs/bytes/iter.gs.ts +13 -14
- package/gs/bytes/meta.json +8 -3
- package/gs/bytes/reader.gs.ts +20 -19
- 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 +71 -0
- package/gs/context/context.ts +30 -29
- 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/internal/fips140deps/byteorder/index.ts +1 -0
- package/gs/crypto/internal/fips140deps/godebug/index.ts +1 -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/embed/index.ts +20 -0
- package/gs/embed/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +39 -3
- package/gs/encoding/json/index.ts +45 -3
- package/gs/errors/errors.test.ts +85 -0
- package/gs/errors/errors.ts +132 -4
- package/gs/fmt/fmt.test.ts +3 -1
- package/gs/fmt/fmt.ts +55 -19
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +128 -1
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +342 -4
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +180 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +1084 -0
- package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
- package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +1233 -0
- package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +46 -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 +37 -0
- package/gs/github.com/klauspost/compress/internal/le/index.ts +115 -0
- 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/internal/scannerhooks/index.test.ts +14 -0
- package/gs/go/internal/scannerhooks/index.ts +9 -0
- package/gs/go/scanner/index.test.ts +22 -0
- package/gs/go/scanner/index.ts +47 -0
- package/gs/go/token/index.test.ts +47 -1
- package/gs/go/token/index.ts +583 -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/abi/index.test.ts +18 -0
- package/gs/internal/abi/index.ts +14 -0
- package/gs/internal/bytealg/index.test.ts +18 -0
- package/gs/internal/bytealg/index.ts +16 -0
- package/gs/internal/byteorder/index.test.ts +39 -0
- package/gs/internal/byteorder/index.ts +100 -27
- package/gs/internal/godebug/index.test.ts +16 -0
- package/gs/internal/godebug/index.ts +35 -0
- package/gs/io/fs/index.ts +1 -0
- package/gs/io/fs/meta.json +5 -0
- package/gs/io/fs/readlink.test.ts +43 -0
- package/gs/io/fs/readlink.ts +69 -0
- package/gs/io/fs/walk.test.ts +61 -0
- package/gs/io/fs/walk.ts +17 -9
- package/gs/io/io.ts +177 -31
- package/gs/io/meta.json +10 -2
- package/gs/iter/iter.ts +8 -2
- package/gs/maps/iter.ts +75 -26
- package/gs/maps/maps.test.ts +23 -0
- package/gs/maps/maps.ts +13 -11
- package/gs/math/bits/index.test.ts +20 -0
- package/gs/math/bits/index.ts +107 -64
- package/gs/math/const.gs.test.ts +11 -5
- package/gs/math/const.gs.ts +5 -6
- package/gs/mime/index.ts +60 -0
- package/gs/net/http/httptest/index.test.ts +53 -0
- package/gs/net/http/httptest/index.ts +120 -0
- package/gs/net/http/index.test.ts +148 -0
- package/gs/net/http/index.ts +432 -0
- 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/dir_unix.gs.ts +2 -3
- 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 +96 -17
- package/gs/path/filepath/match.test.ts +31 -12
- package/gs/path/filepath/match.ts +181 -3
- package/gs/path/filepath/meta.json +6 -0
- package/gs/path/filepath/path.test.ts +80 -0
- package/gs/path/filepath/path.ts +244 -11
- package/gs/path/path.ts +20 -5
- package/gs/reflect/field.test.ts +63 -0
- package/gs/reflect/index.ts +5 -1
- package/gs/reflect/iter.ts +2 -2
- package/gs/reflect/map.test.ts +42 -1
- package/gs/reflect/map.ts +39 -0
- package/gs/reflect/type.ts +728 -65
- 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 +45 -0
- package/gs/runtime/debug/index.ts +96 -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/runtime.test.ts +19 -0
- package/gs/runtime/runtime.ts +98 -3
- 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 +180 -0
- package/gs/slices/slices.ts +502 -15
- package/gs/sort/meta.json +7 -0
- package/gs/sort/slice.gs.ts +85 -26
- package/gs/sort/slice.test.ts +40 -0
- package/gs/sort/sort.gs.ts +16 -13
- package/gs/strings/builder.test.ts +8 -0
- package/gs/strings/builder.ts +33 -20
- 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/atomic/type.gs.ts +13 -14
- package/gs/sync/meta.json +3 -1
- package/gs/sync/sync.test.ts +69 -1
- package/gs/sync/sync.ts +72 -13
- package/gs/syscall/constants.ts +39 -24
- package/gs/syscall/errors.ts +165 -112
- package/gs/syscall/fs.ts +195 -0
- package/gs/syscall/js/index.ts +485 -0
- package/gs/syscall/js/meta.json +4 -0
- package/gs/syscall/net.test.ts +111 -0
- package/gs/syscall/types.ts +63 -2
- package/gs/testing/index.ts +1 -0
- package/gs/testing/meta.json +5 -0
- package/gs/testing/testing.test.ts +146 -0
- package/gs/testing/testing.ts +399 -0
- package/gs/time/meta.json +2 -2
- package/gs/time/time.test.ts +110 -0
- package/gs/time/time.ts +309 -57
- package/gs/unicode/unicode.test.ts +36 -0
- package/gs/unicode/unicode.ts +115 -9
- package/gs/unicode/utf8/utf8.test.ts +13 -0
- package/gs/unicode/utf8/utf8.ts +28 -16
- package/gs/unique/index.ts +98 -0
- package/package.json +3 -2
|
@@ -5,6 +5,8 @@ import (
|
|
|
5
5
|
"errors"
|
|
6
6
|
"os"
|
|
7
7
|
"path/filepath"
|
|
8
|
+
"regexp"
|
|
9
|
+
"slices"
|
|
8
10
|
"strings"
|
|
9
11
|
"testing"
|
|
10
12
|
)
|
|
@@ -127,8 +129,8 @@ func TestCompilePackagesEmitsSimplePackage(t *testing.T) {
|
|
|
127
129
|
"import * as $ from \"@goscript/builtin/index.js\"",
|
|
128
130
|
"export const Greeting: string = \"Hello\"",
|
|
129
131
|
"export function Add(a: number, b: number): number",
|
|
130
|
-
"export async function main(): Promise<void>",
|
|
131
|
-
"let size =
|
|
132
|
+
"export async function main(): globalThis.Promise<void>",
|
|
133
|
+
"let size = 5",
|
|
132
134
|
"$.print(\"total:\", size)",
|
|
133
135
|
"$.println(Greeting, total)",
|
|
134
136
|
"$.panic(\"unreachable\")",
|
|
@@ -140,118 +142,108 @@ func TestCompilePackagesEmitsSimplePackage(t *testing.T) {
|
|
|
140
142
|
}
|
|
141
143
|
}
|
|
142
144
|
|
|
143
|
-
func
|
|
145
|
+
func TestCompilePackagesSkipsPureTopLevelBlankAssertions(t *testing.T) {
|
|
144
146
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
145
|
-
"go.mod": "module example.test/
|
|
147
|
+
"go.mod": "module example.test/blankassert\n\ngo 1.25.3\n",
|
|
146
148
|
"main.go": strings.Join([]string{
|
|
147
149
|
"package main",
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
154
|
-
" println(localMessage())",
|
|
155
|
-
"}",
|
|
156
|
-
"",
|
|
157
|
-
}, "\n"),
|
|
158
|
-
"helper.go": strings.Join([]string{
|
|
159
|
-
"package main",
|
|
160
|
-
"func localMessage() string {",
|
|
161
|
-
" return \"from helper\"",
|
|
162
|
-
"}",
|
|
163
|
-
"",
|
|
164
|
-
}, "\n"),
|
|
165
|
-
"subpkg/subpkg.go": strings.Join([]string{
|
|
166
|
-
"package subpkg",
|
|
167
|
-
"type Builder struct {",
|
|
168
|
-
" Value string",
|
|
169
|
-
"}",
|
|
170
|
-
"func (b *Builder) Set(value string) {",
|
|
171
|
-
" b.Value = value",
|
|
172
|
-
"}",
|
|
173
|
-
"func Greet(name string) string {",
|
|
174
|
-
" return \"Hello, \" + name",
|
|
175
|
-
"}",
|
|
150
|
+
"type named interface { Name() string }",
|
|
151
|
+
"type item struct{}",
|
|
152
|
+
"func (*item) Name() string { return \"item\" }",
|
|
153
|
+
"var defaultItem = &item{}",
|
|
154
|
+
"var _ named = defaultItem",
|
|
155
|
+
"func main() { println(defaultItem.Name()) }",
|
|
176
156
|
"",
|
|
177
157
|
}, "\n"),
|
|
178
158
|
})
|
|
179
159
|
outputDir := filepath.Join(t.TempDir(), "output")
|
|
180
|
-
comp, err := NewCompiler(&Config{
|
|
181
|
-
Dir: moduleDir,
|
|
182
|
-
OutputPath: outputDir,
|
|
183
|
-
AllDependencies: true,
|
|
184
|
-
}, nil, nil)
|
|
160
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
185
161
|
if err != nil {
|
|
186
162
|
t.Fatal(err.Error())
|
|
187
163
|
}
|
|
188
164
|
|
|
189
|
-
|
|
190
|
-
if err != nil {
|
|
165
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
191
166
|
t.Fatal(err.Error())
|
|
192
167
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
mainFile := filepath.Join(outputDir, "@goscript", "example.test", "imports", "main.gs.ts")
|
|
197
|
-
mainContent, err := os.ReadFile(mainFile)
|
|
168
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "blankassert", "main.gs.ts")
|
|
169
|
+
content, err := os.ReadFile(outputFile)
|
|
198
170
|
if err != nil {
|
|
199
171
|
t.Fatal(err.Error())
|
|
200
172
|
}
|
|
201
|
-
|
|
202
|
-
|
|
173
|
+
text := string(content)
|
|
174
|
+
if strings.Contains(text, "__goscriptBlank") {
|
|
175
|
+
t.Fatalf("pure top-level blank assertion emitted runtime binding:\n%s", text)
|
|
203
176
|
}
|
|
204
|
-
if !strings.Contains(
|
|
205
|
-
t.Fatalf("missing
|
|
177
|
+
if !strings.Contains(text, "export let defaultItem") {
|
|
178
|
+
t.Fatalf("missing real package variable:\n%s", text)
|
|
206
179
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
func TestCompilePackagesLazilyInitializesCrossFilePackageVars(t *testing.T) {
|
|
183
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
184
|
+
"go.mod": "module example.test/lazyvars\n\ngo 1.25.3\n",
|
|
185
|
+
"a.go": strings.Join([]string{
|
|
186
|
+
"package main",
|
|
187
|
+
"type words []int",
|
|
188
|
+
"type remote struct { n int }",
|
|
189
|
+
"var one = words{1}",
|
|
190
|
+
"func useTwo() int { return two.values[0] + remoteZero.n }",
|
|
191
|
+
"",
|
|
192
|
+
}, "\n"),
|
|
193
|
+
"b.go": strings.Join([]string{
|
|
194
|
+
"package main",
|
|
195
|
+
"type holder struct { values words }",
|
|
196
|
+
"var two = holder{one}",
|
|
197
|
+
"var remoteZero remote",
|
|
198
|
+
"func main() { println(useTwo(), two.values[0]) }",
|
|
199
|
+
"",
|
|
200
|
+
}, "\n"),
|
|
201
|
+
})
|
|
202
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
203
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
204
|
+
if err != nil {
|
|
205
|
+
t.Fatal(err.Error())
|
|
210
206
|
}
|
|
211
|
-
|
|
212
|
-
|
|
207
|
+
|
|
208
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
209
|
+
t.Fatal(err.Error())
|
|
210
|
+
}
|
|
211
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyvars", "b.gs.ts")
|
|
212
|
+
content, err := os.ReadFile(outputFile)
|
|
213
213
|
if err != nil {
|
|
214
214
|
t.Fatal(err.Error())
|
|
215
215
|
}
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
text := string(content)
|
|
217
|
+
for _, want := range []string{
|
|
218
|
+
"export let two: holder = undefined as unknown as holder",
|
|
219
|
+
"export function __goscript_get_two(): holder",
|
|
220
|
+
"export let remoteZero: __goscript_a.remote = undefined as unknown as __goscript_a.remote",
|
|
221
|
+
"export function __goscript_get_remoteZero(): __goscript_a.remote",
|
|
222
|
+
"__goscript_a.one",
|
|
223
|
+
} {
|
|
224
|
+
if !strings.Contains(text, want) {
|
|
225
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
226
|
+
}
|
|
218
227
|
}
|
|
219
|
-
|
|
220
|
-
|
|
228
|
+
aFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyvars", "a.gs.ts")
|
|
229
|
+
aContent, err := os.ReadFile(aFile)
|
|
221
230
|
if err != nil {
|
|
222
231
|
t.Fatal(err.Error())
|
|
223
232
|
}
|
|
224
|
-
if strings.Contains(string(
|
|
225
|
-
t.Fatalf("
|
|
233
|
+
if !strings.Contains(string(aContent), "__goscript_b.__goscript_get_two()") {
|
|
234
|
+
t.Fatalf("missing lazy cross-file getter use in a.go output:\n%s", string(aContent))
|
|
226
235
|
}
|
|
227
236
|
}
|
|
228
237
|
|
|
229
|
-
func
|
|
238
|
+
func TestCompilePackagesLazilyInitializesSameFileLaterPackageVars(t *testing.T) {
|
|
230
239
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
231
|
-
"go.mod": "module example.test/
|
|
240
|
+
"go.mod": "module example.test/lazylatervars\n\ngo 1.25.3\n",
|
|
232
241
|
"main.go": strings.Join([]string{
|
|
233
242
|
"package main",
|
|
234
|
-
"type
|
|
235
|
-
"
|
|
236
|
-
"
|
|
237
|
-
"}",
|
|
238
|
-
"func (c Counter) Read() int {",
|
|
239
|
-
" return c.Value",
|
|
240
|
-
"}",
|
|
241
|
-
"func (c *Counter) Set(v int) {",
|
|
242
|
-
" c.Value = v",
|
|
243
|
-
"}",
|
|
244
|
-
"func main() {",
|
|
245
|
-
" original := Counter{Value: 1}",
|
|
246
|
-
"",
|
|
247
|
-
" // Copy should stay readable in generated output.",
|
|
248
|
-
" copy := original",
|
|
249
|
-
" pointer := &original",
|
|
250
|
-
" pointer.Set(2)",
|
|
251
|
-
" var iface any = pointer",
|
|
252
|
-
" _, ok := iface.(*Counter)",
|
|
253
|
-
" println(copy.Read(), original.Read(), ok)",
|
|
254
|
-
"}",
|
|
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) }",
|
|
255
247
|
"",
|
|
256
248
|
}, "\n"),
|
|
257
249
|
})
|
|
@@ -264,25 +256,16 @@ func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
|
264
256
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
265
257
|
t.Fatal(err.Error())
|
|
266
258
|
}
|
|
267
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
259
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazylatervars", "main.gs.ts")
|
|
268
260
|
content, err := os.ReadFile(outputFile)
|
|
269
261
|
if err != nil {
|
|
270
262
|
t.Fatal(err.Error())
|
|
271
263
|
}
|
|
272
264
|
text := string(content)
|
|
273
265
|
for _, want := range []string{
|
|
274
|
-
"export
|
|
275
|
-
"
|
|
276
|
-
"
|
|
277
|
-
"public Read(): number",
|
|
278
|
-
"public Set(v: number): void",
|
|
279
|
-
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))",
|
|
280
|
-
"let original = $.varRef($.markAsStructValue(new Counter({Value: 1})))\n\n\t// Copy should stay readable in generated output.\n\tlet copy",
|
|
281
|
-
"let copy = $.markAsStructValue(original.value.clone())",
|
|
282
|
-
"let pointer = original",
|
|
283
|
-
"$.pointerValue(pointer).Set(2)",
|
|
284
|
-
"let [, ok] = $.typeAssertTuple<Counter | $.VarRef<Counter> | null>(iface, { kind: $.TypeKind.Pointer, elemType: \"main.Counter\" })",
|
|
285
|
-
"\"Value\": { type: { kind: $.TypeKind.Basic, name: \"int\" }, tag: \"json:\\\"value\\\"\" }",
|
|
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}))",
|
|
286
269
|
} {
|
|
287
270
|
if !strings.Contains(text, want) {
|
|
288
271
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -290,19 +273,19 @@ func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
|
290
273
|
}
|
|
291
274
|
}
|
|
292
275
|
|
|
293
|
-
func
|
|
276
|
+
func TestCompilePackagesLazilyInitializesFunctionBodyPackageVarDependencies(t *testing.T) {
|
|
294
277
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
295
|
-
"go.mod": "module example.test/
|
|
278
|
+
"go.mod": "module example.test/lazybodyvars\n\ngo 1.25.3\n",
|
|
296
279
|
"main.go": strings.Join([]string{
|
|
297
280
|
"package main",
|
|
298
|
-
"
|
|
299
|
-
"
|
|
300
|
-
"
|
|
301
|
-
"
|
|
302
|
-
"
|
|
303
|
-
" ***p3 = 12",
|
|
304
|
-
" println(x)",
|
|
281
|
+
"type Point struct { n int }",
|
|
282
|
+
"var first, _ = new(Point).SetBytes()",
|
|
283
|
+
"func (p *Point) SetBytes() (*Point, error) {",
|
|
284
|
+
" p.n = later",
|
|
285
|
+
" return p, nil",
|
|
305
286
|
"}",
|
|
287
|
+
"var later = 7",
|
|
288
|
+
"func main() { println(first.n) }",
|
|
306
289
|
"",
|
|
307
290
|
}, "\n"),
|
|
308
291
|
})
|
|
@@ -315,18 +298,17 @@ func TestCompilePackagesEmitsNestedPointerStorageAssertions(t *testing.T) {
|
|
|
315
298
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
316
299
|
t.Fatal(err.Error())
|
|
317
300
|
}
|
|
318
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
301
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazybodyvars", "main.gs.ts")
|
|
319
302
|
content, err := os.ReadFile(outputFile)
|
|
320
303
|
if err != nil {
|
|
321
304
|
t.Fatal(err.Error())
|
|
322
305
|
}
|
|
323
306
|
text := string(content)
|
|
324
307
|
for _, want := range []string{
|
|
325
|
-
"let
|
|
326
|
-
"
|
|
327
|
-
"
|
|
328
|
-
"let
|
|
329
|
-
"$.pointerValue($.pointerValue(p3))!.value = 12",
|
|
308
|
+
"export let first: Point | $.VarRef<Point> | null = undefined as unknown as Point | $.VarRef<Point> | null",
|
|
309
|
+
"export function __goscript_get_first(): Point | $.VarRef<Point> | null",
|
|
310
|
+
"function __goscript_get___goscriptTuple",
|
|
311
|
+
"export let later: number = 7",
|
|
330
312
|
} {
|
|
331
313
|
if !strings.Contains(text, want) {
|
|
332
314
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -334,31 +316,22 @@ func TestCompilePackagesEmitsNestedPointerStorageAssertions(t *testing.T) {
|
|
|
334
316
|
}
|
|
335
317
|
}
|
|
336
318
|
|
|
337
|
-
func
|
|
319
|
+
func TestCompilePackagesInitializesLazyAsyncPackageVarsBeforeInit(t *testing.T) {
|
|
338
320
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
339
|
-
"go.mod": "module example.test/
|
|
321
|
+
"go.mod": "module example.test/lazyasyncvars\n\ngo 1.25.3\n",
|
|
340
322
|
"main.go": strings.Join([]string{
|
|
341
323
|
"package main",
|
|
342
|
-
"
|
|
343
|
-
"
|
|
344
|
-
"
|
|
345
|
-
"func (
|
|
346
|
-
"
|
|
347
|
-
"
|
|
348
|
-
"
|
|
349
|
-
" empty := []rune{}",
|
|
350
|
-
" literal := []int{1, 2}",
|
|
351
|
-
" literal = append(literal, 3)",
|
|
352
|
-
" slice = append(slice, 5)",
|
|
353
|
-
" slice[0] = arr[1]",
|
|
354
|
-
" m := make(map[string]int)",
|
|
355
|
-
" m[\"one\"] = 1",
|
|
356
|
-
" value, ok := m[\"missing\"]",
|
|
357
|
-
" text := \"hé\"",
|
|
358
|
-
" var list MySlice",
|
|
359
|
-
" list.Add(7)",
|
|
360
|
-
" println(arr[1], slice[0], literal[2], len(slice), cap(slice), len(empty), value, ok, text[0], text[1], MyInt(5).Double(), len(list))",
|
|
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",
|
|
361
331
|
"}",
|
|
332
|
+
"var later = 7",
|
|
333
|
+
"func init() { println(first) }",
|
|
334
|
+
"func main() {}",
|
|
362
335
|
"",
|
|
363
336
|
}, "\n"),
|
|
364
337
|
})
|
|
@@ -371,32 +344,18 @@ func TestCompilePackagesEmitsArraySliceMapStringAndNamedMethods(t *testing.T) {
|
|
|
371
344
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
372
345
|
t.Fatal(err.Error())
|
|
373
346
|
}
|
|
374
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
347
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyasyncvars", "main.gs.ts")
|
|
375
348
|
content, err := os.ReadFile(outputFile)
|
|
376
349
|
if err != nil {
|
|
377
350
|
t.Fatal(err.Error())
|
|
378
351
|
}
|
|
379
352
|
text := string(content)
|
|
380
353
|
for _, want := range []string{
|
|
381
|
-
"
|
|
382
|
-
"
|
|
383
|
-
"export
|
|
384
|
-
"
|
|
385
|
-
"
|
|
386
|
-
"let slice = $.makeSlice<number>(0, 2, \"number\")",
|
|
387
|
-
"let empty = $.arrayToSlice<number>([])",
|
|
388
|
-
"let literal = $.arrayToSlice<number>([1, 2])",
|
|
389
|
-
"literal = $.append(literal, 3)",
|
|
390
|
-
"slice![0] = arr[1]",
|
|
391
|
-
"let m = $.makeMap<string, number>()",
|
|
392
|
-
"$.mapSet(m, \"one\", 1)",
|
|
393
|
-
"let [value, ok] = $.mapGet(m, \"missing\", 0)",
|
|
394
|
-
"slice![0]",
|
|
395
|
-
"literal![2]",
|
|
396
|
-
"let list: $.VarRef<MySlice> = $.varRef(null)",
|
|
397
|
-
"MySlice_Add(list, 7)",
|
|
398
|
-
"$.indexStringOrBytes(text, 0)",
|
|
399
|
-
"MyInt_Double(5)",
|
|
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()",
|
|
400
359
|
} {
|
|
401
360
|
if !strings.Contains(text, want) {
|
|
402
361
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -404,35 +363,17 @@ func TestCompilePackagesEmitsArraySliceMapStringAndNamedMethods(t *testing.T) {
|
|
|
404
363
|
}
|
|
405
364
|
}
|
|
406
365
|
|
|
407
|
-
func
|
|
366
|
+
func TestCompilePackagesAssignsLazyPackageVarsDirectly(t *testing.T) {
|
|
408
367
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
409
|
-
"go.mod": "module example.test/
|
|
368
|
+
"go.mod": "module example.test/lazyassign\n\ngo 1.25.3\n",
|
|
410
369
|
"main.go": strings.Join([]string{
|
|
411
370
|
"package main",
|
|
412
|
-
"
|
|
413
|
-
"
|
|
414
|
-
"
|
|
415
|
-
"
|
|
416
|
-
"type ReadCloser interface { Reader; Closer }",
|
|
417
|
-
"type Counter struct { Value int }",
|
|
418
|
-
"func (c *Counter) Inc() { c.Value++ }",
|
|
419
|
-
"func (c Counter) Read() string { return \"read\" }",
|
|
420
|
-
"func (c Counter) Close() string { return \"close\" }",
|
|
421
|
-
"func call(fn func()) { fn() }",
|
|
422
|
-
"func main() {",
|
|
423
|
-
" counter := &Counter{}",
|
|
424
|
-
" call(counter.Inc)",
|
|
425
|
-
" var rc ReadCloser = counter",
|
|
426
|
-
" _, ok := rc.(ReadCloser)",
|
|
427
|
-
" var i any = Greeter(greet)",
|
|
428
|
-
" fn, ok := i.(Greeter)",
|
|
429
|
-
" var l any = (*struct { Name string })(nil)",
|
|
430
|
-
" _, ok2 := l.(*struct { Name string })",
|
|
431
|
-
" switch v := rc.(type) {",
|
|
432
|
-
" case ReadCloser:",
|
|
433
|
-
" println(v.Read(), fn(\"gopher\"), ok, ok2)",
|
|
434
|
-
" }",
|
|
371
|
+
"var table = []int{later}",
|
|
372
|
+
"var later = 1",
|
|
373
|
+
"func init() {",
|
|
374
|
+
" table = append(table, 2)",
|
|
435
375
|
"}",
|
|
376
|
+
"func main() { println(len(table)) }",
|
|
436
377
|
"",
|
|
437
378
|
}, "\n"),
|
|
438
379
|
})
|
|
@@ -445,46 +386,35 @@ func TestCompilePackagesEmitsInterfacesMethodValuesTypeSwitchesAndFunctionAssert
|
|
|
445
386
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
446
387
|
t.Fatal(err.Error())
|
|
447
388
|
}
|
|
448
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
389
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "lazyassign", "main.gs.ts")
|
|
449
390
|
content, err := os.ReadFile(outputFile)
|
|
450
391
|
if err != nil {
|
|
451
392
|
t.Fatal(err.Error())
|
|
452
393
|
}
|
|
453
394
|
text := string(content)
|
|
454
|
-
|
|
455
|
-
"
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
"
|
|
459
|
-
"$.registerInterfaceType(\n\t\"main.ReadCloser\"",
|
|
460
|
-
"((__receiver) => () => __receiver.Inc())($.pointerValue(counter))",
|
|
461
|
-
"$.namedFunction(greet, \"main.Greeter\")",
|
|
462
|
-
"$.typedNil(\"*struct{Name string}\")",
|
|
463
|
-
"elemType: { kind: $.TypeKind.Struct, methods: [], fields: {\"Name\": { kind: $.TypeKind.Basic, name: \"string\" }} }",
|
|
464
|
-
"let fn = __goscriptTuple",
|
|
465
|
-
"$.typeSwitch(",
|
|
466
|
-
"types: [\"main.ReadCloser\"]",
|
|
467
|
-
} {
|
|
468
|
-
if !strings.Contains(text, want) {
|
|
469
|
-
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
470
|
-
}
|
|
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)
|
|
471
400
|
}
|
|
472
401
|
}
|
|
473
402
|
|
|
474
|
-
func
|
|
403
|
+
func TestCompilePackagesAssignsImportedPackageVarsThroughSetters(t *testing.T) {
|
|
475
404
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
476
|
-
"go.mod": "module example.test/
|
|
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"),
|
|
477
411
|
"main.go": strings.Join([]string{
|
|
478
412
|
"package main",
|
|
479
|
-
"
|
|
480
|
-
"
|
|
481
|
-
"
|
|
482
|
-
"
|
|
483
|
-
"
|
|
484
|
-
" info, err := stat()",
|
|
485
|
-
" if err == nil {",
|
|
486
|
-
" println(info.Name())",
|
|
487
|
-
" }",
|
|
413
|
+
"import \"example.test/pkgvarassign/dep\"",
|
|
414
|
+
"func bump() {",
|
|
415
|
+
" dep.Count = 1",
|
|
416
|
+
" dep.Count += 16",
|
|
417
|
+
" dep.Count++",
|
|
488
418
|
"}",
|
|
489
419
|
"",
|
|
490
420
|
}, "\n"),
|
|
@@ -498,43 +428,37 @@ func TestCompilePackagesAssertsInterfaceMethodReceivers(t *testing.T) {
|
|
|
498
428
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
499
429
|
t.Fatal(err.Error())
|
|
500
430
|
}
|
|
501
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
431
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "pkgvarassign", "main.gs.ts")
|
|
502
432
|
content, err := os.ReadFile(outputFile)
|
|
503
433
|
if err != nil {
|
|
504
434
|
t.Fatal(err.Error())
|
|
505
435
|
}
|
|
506
436
|
text := string(content)
|
|
507
437
|
for _, want := range []string{
|
|
508
|
-
"
|
|
509
|
-
"
|
|
438
|
+
"dep.__goscript_set_Count(1)",
|
|
439
|
+
"dep.__goscript_set_Count(dep.Count + 16)",
|
|
440
|
+
"dep.__goscript_set_Count(dep.Count + 1)",
|
|
510
441
|
} {
|
|
511
442
|
if !strings.Contains(text, want) {
|
|
512
|
-
t.Fatalf("missing
|
|
443
|
+
t.Fatalf("missing imported package var setter assignment %q:\n%s", want, text)
|
|
513
444
|
}
|
|
514
445
|
}
|
|
446
|
+
if strings.Contains(text, "dep.Count +=") || strings.Contains(text, "dep.Count++") {
|
|
447
|
+
t.Fatalf("imported package var assigned directly:\n%s", text)
|
|
448
|
+
}
|
|
515
449
|
}
|
|
516
450
|
|
|
517
|
-
func
|
|
451
|
+
func TestCompilePackagesAliasesForInitShortDeclShadow(t *testing.T) {
|
|
518
452
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
519
|
-
"go.mod": "module example.test/
|
|
453
|
+
"go.mod": "module example.test/forinitshadow\n\ngo 1.25.3\n",
|
|
520
454
|
"main.go": strings.Join([]string{
|
|
521
455
|
"package main",
|
|
522
|
-
"
|
|
523
|
-
"
|
|
524
|
-
"
|
|
525
|
-
"
|
|
526
|
-
" return \"unknown dog\"",
|
|
456
|
+
"func checksum(n int) int {",
|
|
457
|
+
" total := 0",
|
|
458
|
+
" for n := n - 4; total <= n; total++ {",
|
|
459
|
+
" total += n",
|
|
527
460
|
" }",
|
|
528
|
-
" return
|
|
529
|
-
"}",
|
|
530
|
-
"func FindDog() *Dog { return nil }",
|
|
531
|
-
"func FindAnimal() Animal { return Animal(FindDog()) }",
|
|
532
|
-
"func main() {",
|
|
533
|
-
" animal := FindAnimal()",
|
|
534
|
-
" println(animal.Name())",
|
|
535
|
-
" var dog *Dog = nil",
|
|
536
|
-
" var a Animal = dog",
|
|
537
|
-
" println(a == nil)",
|
|
461
|
+
" return total + n",
|
|
538
462
|
"}",
|
|
539
463
|
"",
|
|
540
464
|
}, "\n"),
|
|
@@ -548,54 +472,38 @@ func TestCompilePackagesBoxesTypedNilInterfaceValues(t *testing.T) {
|
|
|
548
472
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
549
473
|
t.Fatal(err.Error())
|
|
550
474
|
}
|
|
551
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
475
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "forinitshadow", "main.gs.ts")
|
|
552
476
|
content, err := os.ReadFile(outputFile)
|
|
553
477
|
if err != nil {
|
|
554
478
|
t.Fatal(err.Error())
|
|
555
479
|
}
|
|
556
480
|
text := string(content)
|
|
557
|
-
|
|
558
|
-
"
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
481
|
+
if strings.Contains(text, "for (let n = n - 4") {
|
|
482
|
+
t.Fatalf("for init short declaration references itself:\n%s", text)
|
|
483
|
+
}
|
|
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)
|
|
486
|
+
}
|
|
487
|
+
if !strings.Contains(text, "return total + n") {
|
|
488
|
+
t.Fatalf("outer n was not preserved after the loop:\n%s", text)
|
|
565
489
|
}
|
|
566
490
|
}
|
|
567
491
|
|
|
568
|
-
func
|
|
492
|
+
func TestCompilePackagesReadsShadowedVarRefStructFieldsOnce(t *testing.T) {
|
|
569
493
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
570
|
-
"go.mod": "module example.test/
|
|
494
|
+
"go.mod": "module example.test/shadowvarreffield\n\ngo 1.25.3\n",
|
|
571
495
|
"main.go": strings.Join([]string{
|
|
572
496
|
"package main",
|
|
573
|
-
"type
|
|
574
|
-
"
|
|
575
|
-
"func (
|
|
576
|
-
"
|
|
577
|
-
"
|
|
578
|
-
"
|
|
579
|
-
"
|
|
580
|
-
"
|
|
581
|
-
" var zero T",
|
|
582
|
-
" return zero",
|
|
583
|
-
"}",
|
|
584
|
-
"func CallString[T Stringer](v T) string { return v.String() }",
|
|
585
|
-
"func Sum[T Stringer](vals ...T) T {",
|
|
586
|
-
" var zero T",
|
|
587
|
-
" return zero",
|
|
588
|
-
"}",
|
|
589
|
-
"func main() {",
|
|
590
|
-
" box := NewBox(7)",
|
|
591
|
-
" println(box.Get())",
|
|
592
|
-
" seen := make(Set[int])",
|
|
593
|
-
" seen[1] = struct{}{}",
|
|
594
|
-
" zero := ZeroValue[MyInt]()",
|
|
595
|
-
" println(CallString(zero))",
|
|
596
|
-
" sum := Sum[MyInt]()",
|
|
597
|
-
" println(CallString(sum))",
|
|
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)",
|
|
598
505
|
"}",
|
|
506
|
+
"func main() { println(size()) }",
|
|
599
507
|
"",
|
|
600
508
|
}, "\n"),
|
|
601
509
|
})
|
|
@@ -608,47 +516,33 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
|
|
|
608
516
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
609
517
|
t.Fatal(err.Error())
|
|
610
518
|
}
|
|
611
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
519
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "shadowvarreffield", "main.gs.ts")
|
|
612
520
|
content, err := os.ReadFile(outputFile)
|
|
613
521
|
if err != nil {
|
|
614
522
|
t.Fatal(err.Error())
|
|
615
523
|
}
|
|
616
524
|
text := string(content)
|
|
617
|
-
|
|
618
|
-
"
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
"
|
|
622
|
-
"$.genericZero(__typeArgs, \"T\", null)",
|
|
623
|
-
"$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
|
|
624
|
-
"ZeroValue({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }})",
|
|
625
|
-
"CallString({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }}, zero)",
|
|
626
|
-
"Sum({T: { type: \"main.MyInt\", zero: () => 0, methods: {String: MyInt_String} }}, null)",
|
|
627
|
-
} {
|
|
628
|
-
if !strings.Contains(text, want) {
|
|
629
|
-
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
630
|
-
}
|
|
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)
|
|
631
530
|
}
|
|
632
531
|
}
|
|
633
532
|
|
|
634
|
-
func
|
|
533
|
+
func TestCompilePackagesWrapsChannelSendInterfaceValues(t *testing.T) {
|
|
635
534
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
636
|
-
"go.mod": "module example.test/
|
|
535
|
+
"go.mod": "module example.test/chansendiface\n\ngo 1.25.3\n",
|
|
637
536
|
"main.go": strings.Join([]string{
|
|
638
537
|
"package main",
|
|
639
|
-
"type
|
|
640
|
-
"
|
|
641
|
-
"
|
|
642
|
-
"
|
|
643
|
-
"
|
|
644
|
-
"
|
|
645
|
-
" return \"\"",
|
|
646
|
-
" }",
|
|
647
|
-
" var cb Callback = nil",
|
|
648
|
-
" _ = fn",
|
|
649
|
-
" _ = cb",
|
|
650
|
-
" _ = call(fn)",
|
|
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",
|
|
651
544
|
"}",
|
|
545
|
+
"func main() {}",
|
|
652
546
|
"",
|
|
653
547
|
}, "\n"),
|
|
654
548
|
})
|
|
@@ -661,59 +555,30 @@ func TestCompilePackagesAttachesFunctionLiteralTypeInfo(t *testing.T) {
|
|
|
661
555
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
662
556
|
t.Fatal(err.Error())
|
|
663
557
|
}
|
|
664
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
558
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "chansendiface", "main.gs.ts")
|
|
665
559
|
content, err := os.ReadFile(outputFile)
|
|
666
560
|
if err != nil {
|
|
667
561
|
t.Fatal(err.Error())
|
|
668
562
|
}
|
|
669
563
|
text := string(content)
|
|
670
|
-
|
|
671
|
-
"
|
|
672
|
-
"export function call(cb: Callback): string {\n\treturn cb!(1)",
|
|
673
|
-
"$.functionValue((value: number): string => {",
|
|
674
|
-
"kind: $.TypeKind.Function",
|
|
675
|
-
"params: [{ kind: $.TypeKind.Basic, name: \"int\" }]",
|
|
676
|
-
"results: [{ kind: $.TypeKind.Basic, name: \"string\" }]",
|
|
677
|
-
} {
|
|
678
|
-
if !strings.Contains(text, want) {
|
|
679
|
-
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
680
|
-
}
|
|
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)
|
|
681
566
|
}
|
|
682
567
|
}
|
|
683
568
|
|
|
684
|
-
func
|
|
569
|
+
func TestCompilePackagesBindsFuncLiteralVarRefParams(t *testing.T) {
|
|
685
570
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
686
|
-
"go.mod": "module example.test/
|
|
571
|
+
"go.mod": "module example.test/funclitvarref\n\ngo 1.25.3\n",
|
|
687
572
|
"main.go": strings.Join([]string{
|
|
688
573
|
"package main",
|
|
689
|
-
"type
|
|
690
|
-
"
|
|
691
|
-
" Join(parts ...string) string",
|
|
692
|
-
"}",
|
|
693
|
-
"type Path struct{}",
|
|
694
|
-
"func collect(label string, parts ...string) string {",
|
|
695
|
-
" for _, part := range parts {",
|
|
696
|
-
" if part == \"\" {",
|
|
697
|
-
" return label",
|
|
698
|
-
" }",
|
|
699
|
-
" }",
|
|
700
|
-
" return label + string(rune(len(parts)+'0'))",
|
|
701
|
-
"}",
|
|
702
|
-
"func maybeErr(parts ...string) error { return nil }",
|
|
703
|
-
"func (Path) Join(parts ...string) string {",
|
|
704
|
-
" return collect(\"method\", parts...)",
|
|
705
|
-
"}",
|
|
574
|
+
"type words []int",
|
|
575
|
+
"func (w *words) Add(v int) { *w = append(*w, v) }",
|
|
706
576
|
"func main() {",
|
|
707
|
-
"
|
|
708
|
-
"
|
|
709
|
-
"
|
|
710
|
-
"
|
|
711
|
-
"
|
|
712
|
-
" maybeErr(\"ok\")",
|
|
713
|
-
" var fn Collector = collect",
|
|
714
|
-
" fn(\"fn\", \"x\")",
|
|
715
|
-
" var joiner Joiner = Path{}",
|
|
716
|
-
" joiner.Join(\"q\", \"r\")",
|
|
577
|
+
" addLen := func(w words) int {",
|
|
578
|
+
" w.Add(7)",
|
|
579
|
+
" return len(w)",
|
|
580
|
+
" }",
|
|
581
|
+
" println(addLen(nil))",
|
|
717
582
|
"}",
|
|
718
583
|
"",
|
|
719
584
|
}, "\n"),
|
|
@@ -727,26 +592,16 @@ func TestCompilePackagesPacksVariadicCalls(t *testing.T) {
|
|
|
727
592
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
728
593
|
t.Fatal(err.Error())
|
|
729
594
|
}
|
|
730
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
595
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "funclitvarref", "main.gs.ts")
|
|
731
596
|
content, err := os.ReadFile(outputFile)
|
|
732
597
|
if err != nil {
|
|
733
598
|
t.Fatal(err.Error())
|
|
734
599
|
}
|
|
735
600
|
text := string(content)
|
|
736
601
|
for _, want := range []string{
|
|
737
|
-
"
|
|
738
|
-
"
|
|
739
|
-
"
|
|
740
|
-
"let part = parts![__rangeIndex]",
|
|
741
|
-
"export function maybeErr(parts: $.Slice<string>): $.GoError",
|
|
742
|
-
"public Join(parts: $.Slice<string>): string",
|
|
743
|
-
"collect(\"none\", null)",
|
|
744
|
-
"collect(\"two\", $.arrayToSlice<string>([\"a\", \"b\"]))",
|
|
745
|
-
"collect(\"spread\", parts)",
|
|
746
|
-
"$.append(parts, \"c\", \"d\")",
|
|
747
|
-
"maybeErr($.arrayToSlice<string>([\"ok\"]))",
|
|
748
|
-
"fn!(\"fn\", $.arrayToSlice<string>([\"x\"]))",
|
|
749
|
-
"joiner!.Join($.arrayToSlice<string>([\"q\", \"r\"]))",
|
|
602
|
+
"(__goscriptParam0: words): number => {",
|
|
603
|
+
"let w: $.VarRef<words> = $.varRef(__goscriptParam0)",
|
|
604
|
+
"words_Add(w, 7)",
|
|
750
605
|
} {
|
|
751
606
|
if !strings.Contains(text, want) {
|
|
752
607
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -754,33 +609,19 @@ func TestCompilePackagesPacksVariadicCalls(t *testing.T) {
|
|
|
754
609
|
}
|
|
755
610
|
}
|
|
756
611
|
|
|
757
|
-
func
|
|
612
|
+
func TestCompilePackagesAnnotatesNewPointerShortDecls(t *testing.T) {
|
|
758
613
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
759
|
-
"go.mod": "module example.test/
|
|
614
|
+
"go.mod": "module example.test/newptrdecl\n\ngo 1.25.3\n",
|
|
760
615
|
"main.go": strings.Join([]string{
|
|
761
616
|
"package main",
|
|
762
|
-
"
|
|
763
|
-
"
|
|
764
|
-
" for i, v := range values {",
|
|
765
|
-
" if !yield(i, v) {",
|
|
766
|
-
" break",
|
|
767
|
-
" }",
|
|
768
|
-
" }",
|
|
769
|
-
"}",
|
|
617
|
+
"type OID []int",
|
|
618
|
+
"func use(*OID) {}",
|
|
770
619
|
"func main() {",
|
|
771
|
-
"
|
|
772
|
-
"
|
|
773
|
-
"
|
|
774
|
-
" var last int",
|
|
775
|
-
" for last = range pairs {",
|
|
776
|
-
" println(last)",
|
|
777
|
-
" }",
|
|
778
|
-
" for i := range 3 {",
|
|
779
|
-
" if i == 1 {",
|
|
780
|
-
" continue",
|
|
781
|
-
" }",
|
|
782
|
-
" println(i)",
|
|
620
|
+
" oid := new(OID)",
|
|
621
|
+
" if len(*oid) == 0 {",
|
|
622
|
+
" oid = nil",
|
|
783
623
|
" }",
|
|
624
|
+
" use(oid)",
|
|
784
625
|
"}",
|
|
785
626
|
"",
|
|
786
627
|
}, "\n"),
|
|
@@ -794,19 +635,16 @@ func TestCompilePackagesLowersRangeOverFunctionIterators(t *testing.T) {
|
|
|
794
635
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
795
636
|
t.Fatal(err.Error())
|
|
796
637
|
}
|
|
797
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
638
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "newptrdecl", "main.gs.ts")
|
|
798
639
|
content, err := os.ReadFile(outputFile)
|
|
799
640
|
if err != nil {
|
|
800
641
|
t.Fatal(err.Error())
|
|
801
642
|
}
|
|
802
643
|
text := string(content)
|
|
803
644
|
for _, want := range []string{
|
|
804
|
-
"
|
|
805
|
-
"
|
|
806
|
-
"
|
|
807
|
-
"last = __goscriptRange",
|
|
808
|
-
"return true",
|
|
809
|
-
"continue",
|
|
645
|
+
"let oid: $.VarRef<OID> | null = $.varRef<OID>(null as OID)",
|
|
646
|
+
"oid = null",
|
|
647
|
+
"use(oid)",
|
|
810
648
|
} {
|
|
811
649
|
if !strings.Contains(text, want) {
|
|
812
650
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -814,29 +652,16 @@ func TestCompilePackagesLowersRangeOverFunctionIterators(t *testing.T) {
|
|
|
814
652
|
}
|
|
815
653
|
}
|
|
816
654
|
|
|
817
|
-
func
|
|
655
|
+
func TestCompilePackagesEmitsShadowedBuiltinCalls(t *testing.T) {
|
|
818
656
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
819
|
-
"go.mod": "module example.test/
|
|
657
|
+
"go.mod": "module example.test/shadowbuiltin\n\ngo 1.25.3\n",
|
|
820
658
|
"main.go": strings.Join([]string{
|
|
821
|
-
"package
|
|
822
|
-
"type
|
|
823
|
-
"
|
|
824
|
-
"func (w *Worker) Process(v int) int {",
|
|
825
|
-
" w.ch <- v",
|
|
826
|
-
" return <-w.ch",
|
|
659
|
+
"package shadowbuiltin",
|
|
660
|
+
"type Value struct {",
|
|
661
|
+
" N int",
|
|
827
662
|
"}",
|
|
828
|
-
"func
|
|
829
|
-
"
|
|
830
|
-
" ch := make(chan int, 1)",
|
|
831
|
-
" defer func() { <-ch }()",
|
|
832
|
-
" go func() { ch <- 1 }()",
|
|
833
|
-
" select {",
|
|
834
|
-
" case v := <-ch:",
|
|
835
|
-
" println(v)",
|
|
836
|
-
" default:",
|
|
837
|
-
" println(\"default\")",
|
|
838
|
-
" }",
|
|
839
|
-
" _ = call(&Worker{ch: make(chan int, 1)})",
|
|
663
|
+
"func Build(new func() (*Value, error)) (*Value, error) {",
|
|
664
|
+
" return new()",
|
|
840
665
|
"}",
|
|
841
666
|
"",
|
|
842
667
|
}, "\n"),
|
|
@@ -850,45 +675,24 @@ func TestCompilePackagesEmitsAsyncChannelsSelectAndDefer(t *testing.T) {
|
|
|
850
675
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
851
676
|
t.Fatal(err.Error())
|
|
852
677
|
}
|
|
853
|
-
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "
|
|
678
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "shadowbuiltin", "main.gs.ts")
|
|
854
679
|
content, err := os.ReadFile(outputFile)
|
|
855
680
|
if err != nil {
|
|
856
681
|
t.Fatal(err.Error())
|
|
857
682
|
}
|
|
858
683
|
text := string(content)
|
|
859
|
-
|
|
860
|
-
"
|
|
861
|
-
"public async Process(v: number): Promise<number>",
|
|
862
|
-
"let ch = $.makeChannel<number>(1, 0, \"both\")",
|
|
863
|
-
"await $.chanSend($.pointerValue(w).ch, v)",
|
|
864
|
-
"return await $.chanRecv($.pointerValue(w).ch)",
|
|
865
|
-
"await using __defer = new $.AsyncDisposableStack()",
|
|
866
|
-
"queueMicrotask(async () => { await ($.functionValue(async (): Promise<void> => {",
|
|
867
|
-
"$.selectStatement<any, void>([",
|
|
868
|
-
"let v = result.value",
|
|
869
|
-
"await call(new Worker({ch: $.makeChannel<number>(1, 0, \"both\")}))",
|
|
870
|
-
} {
|
|
871
|
-
if !strings.Contains(text, want) {
|
|
872
|
-
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
873
|
-
}
|
|
684
|
+
if !strings.Contains(text, "return await _new!()") {
|
|
685
|
+
t.Fatalf("shadowed builtin call was not emitted as a callable value:\n%s", text)
|
|
874
686
|
}
|
|
875
687
|
}
|
|
876
688
|
|
|
877
|
-
func
|
|
689
|
+
func TestCompilePackagesQuotesRawStringLiterals(t *testing.T) {
|
|
878
690
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
879
|
-
"go.mod": "module example.test/
|
|
691
|
+
"go.mod": "module example.test/rawstrings\n\ngo 1.25.3\n",
|
|
880
692
|
"main.go": strings.Join([]string{
|
|
881
|
-
"package
|
|
882
|
-
"func
|
|
883
|
-
" return
|
|
884
|
-
"}",
|
|
885
|
-
"func main() {",
|
|
886
|
-
" if value, ok := pair(); ok {",
|
|
887
|
-
" println(value)",
|
|
888
|
-
" }",
|
|
889
|
-
" if value, ok := pair(); ok {",
|
|
890
|
-
" println(value)",
|
|
891
|
-
" }",
|
|
693
|
+
"package rawstrings",
|
|
694
|
+
"func Values() (string, string) {",
|
|
695
|
+
" return `\\u00`, `invalid escape char after \\`",
|
|
892
696
|
"}",
|
|
893
697
|
"",
|
|
894
698
|
}, "\n"),
|
|
@@ -902,43 +706,25 @@ func TestCompilePackagesScopesIfInitDeclarations(t *testing.T) {
|
|
|
902
706
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
903
707
|
t.Fatal(err.Error())
|
|
904
708
|
}
|
|
905
|
-
|
|
709
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "rawstrings", "main.gs.ts")
|
|
710
|
+
content, err := os.ReadFile(outputFile)
|
|
906
711
|
if err != nil {
|
|
907
712
|
t.Fatal(err.Error())
|
|
908
713
|
}
|
|
909
|
-
|
|
910
|
-
|
|
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)
|
|
911
717
|
}
|
|
912
718
|
}
|
|
913
719
|
|
|
914
|
-
func
|
|
720
|
+
func TestCompilePackagesEmitsBinaryStringLiterals(t *testing.T) {
|
|
915
721
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
916
|
-
"go.mod": "module example.test/
|
|
722
|
+
"go.mod": "module example.test/binarystrings\n\ngo 1.25.3\n",
|
|
917
723
|
"main.go": strings.Join([]string{
|
|
918
|
-
"package
|
|
919
|
-
"
|
|
920
|
-
"
|
|
921
|
-
"
|
|
922
|
-
" case 1:",
|
|
923
|
-
" println(\"one\")",
|
|
924
|
-
" case 2, 3:",
|
|
925
|
-
" local := \"two-three\"",
|
|
926
|
-
" println(local)",
|
|
927
|
-
" default:",
|
|
928
|
-
" println(\"other\")",
|
|
929
|
-
" }",
|
|
930
|
-
" switch {",
|
|
931
|
-
" case value > 1:",
|
|
932
|
-
" println(\"positive\")",
|
|
933
|
-
" }",
|
|
934
|
-
" release := func() { println(\"release\") }",
|
|
935
|
-
" rel := &release",
|
|
936
|
-
" (*rel)()",
|
|
937
|
-
" wrapped := func() {",
|
|
938
|
-
" defer println(\"wrapped deferred\")",
|
|
939
|
-
" println(\"wrapped body\")",
|
|
940
|
-
" }",
|
|
941
|
-
" wrapped()",
|
|
724
|
+
"package binarystrings",
|
|
725
|
+
"const DecodeMap = \"\\xff\\x80A\"",
|
|
726
|
+
"func Value() string {",
|
|
727
|
+
" return DecodeMap",
|
|
942
728
|
"}",
|
|
943
729
|
"",
|
|
944
730
|
}, "\n"),
|
|
@@ -952,86 +738,2152 @@ func TestCompilePackagesLowersSwitchesAndFunctionValueCalls(t *testing.T) {
|
|
|
952
738
|
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
953
739
|
t.Fatal(err.Error())
|
|
954
740
|
}
|
|
955
|
-
|
|
741
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "binarystrings", "main.gs.ts")
|
|
742
|
+
content, err := os.ReadFile(outputFile)
|
|
956
743
|
if err != nil {
|
|
957
744
|
t.Fatal(err.Error())
|
|
958
745
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
"switch (value) {",
|
|
962
|
-
"case 2:",
|
|
963
|
-
"case 3:",
|
|
964
|
-
"let local = \"two-three\"",
|
|
965
|
-
"switch (true) {",
|
|
966
|
-
"($.pointerValue(rel))!()",
|
|
967
|
-
"$.functionValue((): void => {\n\t\tusing __defer = new $.DisposableStack()",
|
|
968
|
-
"__defer.defer(() => { $.println(\"wrapped deferred\") })",
|
|
969
|
-
"$.println(\"wrapped body\")",
|
|
970
|
-
} {
|
|
971
|
-
if !strings.Contains(text, want) {
|
|
972
|
-
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
if strings.Count(text, "\t\tbreak\n") < 3 {
|
|
976
|
-
t.Fatalf("switch cases were not rendered with implicit breaks:\n%s", text)
|
|
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))
|
|
977
748
|
}
|
|
978
749
|
}
|
|
979
750
|
|
|
980
|
-
func
|
|
751
|
+
func TestCompilePackagesUsesEmbedOverride(t *testing.T) {
|
|
981
752
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
982
|
-
"go.mod":
|
|
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}),
|
|
983
757
|
"main.go": strings.Join([]string{
|
|
984
|
-
"package
|
|
985
|
-
"
|
|
986
|
-
"
|
|
987
|
-
"
|
|
988
|
-
"
|
|
989
|
-
"
|
|
990
|
-
"
|
|
991
|
-
"
|
|
992
|
-
"
|
|
993
|
-
"
|
|
994
|
-
" c := Counter(4)",
|
|
995
|
-
" add := c.Add",
|
|
996
|
-
" println(add(3))",
|
|
997
|
-
" r := Runner{}",
|
|
998
|
-
" run := r.Run",
|
|
999
|
-
" run()",
|
|
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",
|
|
1000
768
|
"}",
|
|
1001
769
|
"",
|
|
1002
770
|
}, "\n"),
|
|
1003
771
|
})
|
|
1004
772
|
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1005
|
-
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
773
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir, AllDependencies: true}, nil, nil)
|
|
1006
774
|
if err != nil {
|
|
1007
775
|
t.Fatal(err.Error())
|
|
1008
776
|
}
|
|
1009
777
|
|
|
1010
|
-
|
|
778
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
779
|
+
if err != nil {
|
|
1011
780
|
t.Fatal(err.Error())
|
|
1012
781
|
}
|
|
1013
|
-
|
|
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"))
|
|
1014
792
|
if err != nil {
|
|
1015
793
|
t.Fatal(err.Error())
|
|
1016
794
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
"((__receiver) => (n: number) => Counter_Add(__receiver, n))(c)",
|
|
1020
|
-
"((__receiver) => () => __receiver.Run())(",
|
|
1021
|
-
} {
|
|
1022
|
-
if !strings.Contains(text, want) {
|
|
1023
|
-
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1024
|
-
}
|
|
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))
|
|
1025
797
|
}
|
|
1026
|
-
if strings.Contains(
|
|
1027
|
-
t.Fatalf("
|
|
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))
|
|
1028
803
|
}
|
|
1029
804
|
}
|
|
1030
805
|
|
|
1031
|
-
func
|
|
806
|
+
func TestCompilePackagesEmitsPackageLocalImport(t *testing.T) {
|
|
1032
807
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1033
|
-
"go.mod": "module example.test/
|
|
1034
|
-
"
|
|
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",
|
|
1223
|
+
} {
|
|
1224
|
+
if !strings.Contains(text, want) {
|
|
1225
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
func TestCompilePackagesEmitsArraySliceMapStringAndNamedMethods(t *testing.T) {
|
|
1231
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
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",
|
|
1347
|
+
"main.go": strings.Join([]string{
|
|
1348
|
+
"package main",
|
|
1349
|
+
"import \"time\"",
|
|
1350
|
+
"type Lifetime struct { time.Duration }",
|
|
1351
|
+
"func Seconds(l Lifetime) float64 {",
|
|
1352
|
+
" return l.Seconds()",
|
|
1353
|
+
"}",
|
|
1354
|
+
"",
|
|
1355
|
+
}, "\n"),
|
|
1356
|
+
})
|
|
1357
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1358
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1359
|
+
if err != nil {
|
|
1360
|
+
t.Fatal(err.Error())
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1364
|
+
t.Fatal(err.Error())
|
|
1365
|
+
}
|
|
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")
|
|
1661
|
+
content, err := os.ReadFile(outputFile)
|
|
1662
|
+
if err != nil {
|
|
1663
|
+
t.Fatal(err.Error())
|
|
1664
|
+
}
|
|
1665
|
+
text := string(content)
|
|
1666
|
+
for _, want := range []string{
|
|
1667
|
+
"$.stringCompare(left, right) < 0",
|
|
1668
|
+
"$.stringCompare(left, right) <= 0",
|
|
1669
|
+
} {
|
|
1670
|
+
if !strings.Contains(text, want) {
|
|
1671
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
func TestCompilePackagesEmitsInterfacesMethodValuesTypeSwitchesAndFunctionAssertions(t *testing.T) {
|
|
1677
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1678
|
+
"go.mod": "module example.test/interfaces\n\ngo 1.25.3\n",
|
|
1679
|
+
"main.go": strings.Join([]string{
|
|
1680
|
+
"package main",
|
|
1681
|
+
"type Greeter func(name string) string",
|
|
1682
|
+
"func greet(name string) string { return \"hello \" + name }",
|
|
1683
|
+
"type Reader interface { Read() string }",
|
|
1684
|
+
"type Closer interface { Close() string }",
|
|
1685
|
+
"type ReadCloser interface { Reader; Closer }",
|
|
1686
|
+
"type Counter struct { Value int }",
|
|
1687
|
+
"func (c *Counter) Inc() { c.Value++ }",
|
|
1688
|
+
"func (c Counter) Read() string { return \"read\" }",
|
|
1689
|
+
"func (c Counter) Close() string { return \"close\" }",
|
|
1690
|
+
"func call(fn func()) { fn() }",
|
|
1691
|
+
"func main() {",
|
|
1692
|
+
" counter := &Counter{}",
|
|
1693
|
+
" call(counter.Inc)",
|
|
1694
|
+
" var rc ReadCloser = counter",
|
|
1695
|
+
" _, ok := rc.(ReadCloser)",
|
|
1696
|
+
" var i any = Greeter(greet)",
|
|
1697
|
+
" fn, ok := i.(Greeter)",
|
|
1698
|
+
" var l any = (*struct { Name string })(nil)",
|
|
1699
|
+
" _, ok2 := l.(*struct { Name string })",
|
|
1700
|
+
" switch v := rc.(type) {",
|
|
1701
|
+
" case ReadCloser:",
|
|
1702
|
+
" println(v.Read(), fn(\"gopher\"), ok, ok2)",
|
|
1703
|
+
" }",
|
|
1704
|
+
"}",
|
|
1705
|
+
"",
|
|
1706
|
+
}, "\n"),
|
|
1707
|
+
})
|
|
1708
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1709
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1710
|
+
if err != nil {
|
|
1711
|
+
t.Fatal(err.Error())
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1715
|
+
t.Fatal(err.Error())
|
|
1716
|
+
}
|
|
1717
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "interfaces", "main.gs.ts")
|
|
1718
|
+
content, err := os.ReadFile(outputFile)
|
|
1719
|
+
if err != nil {
|
|
1720
|
+
t.Fatal(err.Error())
|
|
1721
|
+
}
|
|
1722
|
+
text := string(content)
|
|
1723
|
+
for _, want := range []string{
|
|
1724
|
+
"export type Greeter = ((name: string) => string | globalThis.Promise<string>) | null",
|
|
1725
|
+
"export type ReadCloser = {",
|
|
1726
|
+
"Read(): string",
|
|
1727
|
+
"Close(): string",
|
|
1728
|
+
"$.registerInterfaceType(\n\t\"main.ReadCloser\"",
|
|
1729
|
+
"((__receiver) => () => __receiver.Inc())($.pointerValue<Counter>(counter))",
|
|
1730
|
+
"$.namedFunction(greet, \"main.Greeter\")",
|
|
1731
|
+
"$.interfaceValue<any>(null, \"*struct{Name string}\")",
|
|
1732
|
+
"elemType: { kind: $.TypeKind.Struct, methods: [], fields: {\"Name\": { kind: $.TypeKind.Basic, name: \"string\" }} }",
|
|
1733
|
+
"let fn = __goscriptTuple",
|
|
1734
|
+
"switch (true)",
|
|
1735
|
+
"case $.typeAssert<Exclude<ReadCloser, null>>(__goscriptTypeSwitchValue, \"main.ReadCloser\").ok",
|
|
1736
|
+
"let v: Exclude<ReadCloser, null> = $.typeAssert<Exclude<ReadCloser, null>>(__goscriptTypeSwitchValue, \"main.ReadCloser\").value",
|
|
1737
|
+
} {
|
|
1738
|
+
if !strings.Contains(text, want) {
|
|
1739
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
func TestCompilePackagesAssertsInterfaceMethodReceivers(t *testing.T) {
|
|
1745
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1746
|
+
"go.mod": "module example.test/interface-receivers\n\ngo 1.25.3\n",
|
|
1747
|
+
"main.go": strings.Join([]string{
|
|
1748
|
+
"package main",
|
|
1749
|
+
"type FileInfo interface { Name() string }",
|
|
1750
|
+
"type fileInfo struct { name string }",
|
|
1751
|
+
"func (f fileInfo) Name() string { return f.name }",
|
|
1752
|
+
"func stat() (FileInfo, error) { return fileInfo{name: \"demo\"}, nil }",
|
|
1753
|
+
"func main() {",
|
|
1754
|
+
" info, err := stat()",
|
|
1755
|
+
" if err == nil {",
|
|
1756
|
+
" println(info.Name())",
|
|
1757
|
+
" }",
|
|
1758
|
+
"}",
|
|
1759
|
+
"",
|
|
1760
|
+
}, "\n"),
|
|
1761
|
+
})
|
|
1762
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1763
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1764
|
+
if err != nil {
|
|
1765
|
+
t.Fatal(err.Error())
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1769
|
+
t.Fatal(err.Error())
|
|
1770
|
+
}
|
|
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")
|
|
1822
|
+
content, err := os.ReadFile(outputFile)
|
|
1823
|
+
if err != nil {
|
|
1824
|
+
t.Fatal(err.Error())
|
|
1825
|
+
}
|
|
1826
|
+
text := string(content)
|
|
1827
|
+
for _, want := range []string{
|
|
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()",
|
|
1832
|
+
} {
|
|
1833
|
+
if !strings.Contains(text, want) {
|
|
1834
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
func TestCompilePackagesBoxesTypedNilInterfaceValues(t *testing.T) {
|
|
1840
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1841
|
+
"go.mod": "module example.test/typed-nil-interface\n\ngo 1.25.3\n",
|
|
1842
|
+
"main.go": strings.Join([]string{
|
|
1843
|
+
"package main",
|
|
1844
|
+
"type Animal interface { Name() string }",
|
|
1845
|
+
"type Dog struct { name string }",
|
|
1846
|
+
"func (d *Dog) Name() string {",
|
|
1847
|
+
" if d == nil {",
|
|
1848
|
+
" return \"unknown dog\"",
|
|
1849
|
+
" }",
|
|
1850
|
+
" return d.name",
|
|
1851
|
+
"}",
|
|
1852
|
+
"func FindDog() *Dog { return nil }",
|
|
1853
|
+
"func FindAnimal() Animal { return Animal(FindDog()) }",
|
|
1854
|
+
"func main() {",
|
|
1855
|
+
" animal := FindAnimal()",
|
|
1856
|
+
" println(animal.Name())",
|
|
1857
|
+
" var dog *Dog = nil",
|
|
1858
|
+
" var a Animal = dog",
|
|
1859
|
+
" println(a == nil)",
|
|
1860
|
+
"}",
|
|
1861
|
+
"",
|
|
1862
|
+
}, "\n"),
|
|
1863
|
+
})
|
|
1864
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1865
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1866
|
+
if err != nil {
|
|
1867
|
+
t.Fatal(err.Error())
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1871
|
+
t.Fatal(err.Error())
|
|
1872
|
+
}
|
|
1873
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "typed-nil-interface", "main.gs.ts")
|
|
1874
|
+
content, err := os.ReadFile(outputFile)
|
|
1875
|
+
if err != nil {
|
|
1876
|
+
t.Fatal(err.Error())
|
|
1877
|
+
}
|
|
1878
|
+
text := string(content)
|
|
1879
|
+
for _, want := range []string{
|
|
1880
|
+
"return $.interfaceValue<Animal | null>(FindDog(), \"*main.Dog\")",
|
|
1881
|
+
"$.println($.pointerValue<Exclude<Animal, null>>(animal).Name())",
|
|
1882
|
+
"let a: Animal | null = $.interfaceValue<Animal | null>(dog, \"*main.Dog\")",
|
|
1883
|
+
} {
|
|
1884
|
+
if !strings.Contains(text, want) {
|
|
1885
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T) {
|
|
1891
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1892
|
+
"go.mod": "module example.test/generics\n\ngo 1.25.3\n",
|
|
1893
|
+
"main.go": strings.Join([]string{
|
|
1894
|
+
"package main",
|
|
1895
|
+
"type Stringer interface { String() string }",
|
|
1896
|
+
"type MyInt int",
|
|
1897
|
+
"func (m MyInt) String() string { return \"int\" }",
|
|
1898
|
+
"type Box[T any] struct { value T }",
|
|
1899
|
+
"func (b Box[T]) Get() T { return b.value }",
|
|
1900
|
+
"func NewBox[T any](value T) Box[T] { return Box[T]{value: value} }",
|
|
1901
|
+
"type Set[T comparable] map[T]struct{}",
|
|
1902
|
+
"func ZeroValue[T Stringer]() T {",
|
|
1903
|
+
" var zero T",
|
|
1904
|
+
" return zero",
|
|
1905
|
+
"}",
|
|
1906
|
+
"func CallString[T Stringer](v T) string { return v.String() }",
|
|
1907
|
+
"func Sum[T Stringer](vals ...T) T {",
|
|
1908
|
+
" var zero T",
|
|
1909
|
+
" return zero",
|
|
1910
|
+
"}",
|
|
1911
|
+
"func Copy[T any](vals ...T) []T {",
|
|
1912
|
+
" return append([]T{}, vals...)",
|
|
1913
|
+
"}",
|
|
1914
|
+
"func main() {",
|
|
1915
|
+
" box := NewBox(7)",
|
|
1916
|
+
" println(box.Get())",
|
|
1917
|
+
" seen := make(Set[int])",
|
|
1918
|
+
" seen[1] = struct{}{}",
|
|
1919
|
+
" zero := ZeroValue[MyInt]()",
|
|
1920
|
+
" println(CallString(zero))",
|
|
1921
|
+
" sum := Sum[MyInt]()",
|
|
1922
|
+
" println(CallString(sum))",
|
|
1923
|
+
"}",
|
|
1924
|
+
"",
|
|
1925
|
+
}, "\n"),
|
|
1926
|
+
})
|
|
1927
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1928
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1929
|
+
if err != nil {
|
|
1930
|
+
t.Fatal(err.Error())
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1934
|
+
t.Fatal(err.Error())
|
|
1935
|
+
}
|
|
1936
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "generics", "main.gs.ts")
|
|
1937
|
+
content, err := os.ReadFile(outputFile)
|
|
1938
|
+
if err != nil {
|
|
1939
|
+
t.Fatal(err.Error())
|
|
1940
|
+
}
|
|
1941
|
+
text := string(content)
|
|
1942
|
+
for _, want := range []string{
|
|
1943
|
+
"public Get(): any",
|
|
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 ?? []))",
|
|
1950
|
+
"let seen: Set = $.makeMap<number, {}>()",
|
|
1951
|
+
"$.mapSet(seen, 1, {})",
|
|
1952
|
+
"$.genericZero(__typeArgs, \"T\", null)",
|
|
1953
|
+
"$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
|
|
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)",
|
|
1957
|
+
} {
|
|
1958
|
+
if !strings.Contains(text, want) {
|
|
1959
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
func TestCompilePackagesAttachesFunctionLiteralTypeInfo(t *testing.T) {
|
|
1965
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1966
|
+
"go.mod": "module example.test/function-type-info\n\ngo 1.25.3\n",
|
|
1967
|
+
"main.go": strings.Join([]string{
|
|
1968
|
+
"package main",
|
|
1969
|
+
"type Callback func(value int) string",
|
|
1970
|
+
"func call(cb Callback) string {",
|
|
1971
|
+
" return cb(1)",
|
|
1972
|
+
"}",
|
|
1973
|
+
"func main() {",
|
|
1974
|
+
" fn := func(value int) string {",
|
|
1975
|
+
" return \"\"",
|
|
1976
|
+
" }",
|
|
1977
|
+
" var cb Callback = nil",
|
|
1978
|
+
" _ = fn",
|
|
1979
|
+
" _ = cb",
|
|
1980
|
+
" _ = call(fn)",
|
|
1981
|
+
"}",
|
|
1982
|
+
"",
|
|
1983
|
+
}, "\n"),
|
|
1984
|
+
})
|
|
1985
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1986
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
1987
|
+
if err != nil {
|
|
1988
|
+
t.Fatal(err.Error())
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1992
|
+
t.Fatal(err.Error())
|
|
1993
|
+
}
|
|
1994
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "function-type-info", "main.gs.ts")
|
|
1995
|
+
content, err := os.ReadFile(outputFile)
|
|
1996
|
+
if err != nil {
|
|
1997
|
+
t.Fatal(err.Error())
|
|
1998
|
+
}
|
|
1999
|
+
text := string(content)
|
|
2000
|
+
for _, want := range []string{
|
|
2001
|
+
"export type Callback = ((value: number) => string | globalThis.Promise<string>) | null",
|
|
2002
|
+
"export async function call(cb: ((value: number) => string | globalThis.Promise<string>) | null): globalThis.Promise<string> {\n\treturn await cb!(1)",
|
|
2003
|
+
"$.functionValue((value: number): string => {",
|
|
2004
|
+
"kind: $.TypeKind.Function",
|
|
2005
|
+
"params: [{ kind: $.TypeKind.Basic, name: \"int\" }]",
|
|
2006
|
+
"results: [{ kind: $.TypeKind.Basic, name: \"string\" }]",
|
|
2007
|
+
} {
|
|
2008
|
+
if !strings.Contains(text, want) {
|
|
2009
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
func TestCompilePackagesEmitsRecursiveFunctionTypeInfo(t *testing.T) {
|
|
2015
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2016
|
+
"go.mod": "module example.test/recursive-function-type\n\ngo 1.25.3\n",
|
|
2017
|
+
"main.go": strings.Join([]string{
|
|
2018
|
+
"package main",
|
|
2019
|
+
"type Handler func(Handler) Handler",
|
|
2020
|
+
"type Holder struct { Next Handler }",
|
|
2021
|
+
"func main() { _ = Holder{} }",
|
|
2022
|
+
"",
|
|
2023
|
+
}, "\n"),
|
|
2024
|
+
})
|
|
2025
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2026
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2027
|
+
if err != nil {
|
|
2028
|
+
t.Fatal(err.Error())
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2032
|
+
t.Fatal(err.Error())
|
|
2033
|
+
}
|
|
2034
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "recursive-function-type", "main.gs.ts")
|
|
2035
|
+
content, err := os.ReadFile(outputFile)
|
|
2036
|
+
if err != nil {
|
|
2037
|
+
t.Fatal(err.Error())
|
|
2038
|
+
}
|
|
2039
|
+
text := string(content)
|
|
2040
|
+
for _, want := range []string{
|
|
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\"",
|
|
2043
|
+
"params: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
2044
|
+
"results: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
2045
|
+
} {
|
|
2046
|
+
if !strings.Contains(text, want) {
|
|
2047
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
func TestCompilePackagesPacksVariadicCalls(t *testing.T) {
|
|
2053
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2054
|
+
"go.mod": "module example.test/variadic\n\ngo 1.25.3\n",
|
|
2055
|
+
"main.go": strings.Join([]string{
|
|
2056
|
+
"package main",
|
|
2057
|
+
"type Collector func(label string, parts ...string) string",
|
|
2058
|
+
"type Joiner interface {",
|
|
2059
|
+
" Join(parts ...string) string",
|
|
2060
|
+
"}",
|
|
2061
|
+
"type Path struct{}",
|
|
2062
|
+
"func collect(label string, parts ...string) string {",
|
|
2063
|
+
" for _, part := range parts {",
|
|
2064
|
+
" if part == \"\" {",
|
|
2065
|
+
" return label",
|
|
2066
|
+
" }",
|
|
2067
|
+
" }",
|
|
2068
|
+
" return label + string(rune(len(parts)+'0'))",
|
|
2069
|
+
"}",
|
|
2070
|
+
"func maybeErr(parts ...string) error { return nil }",
|
|
2071
|
+
"func (Path) Join(parts ...string) string {",
|
|
2072
|
+
" return collect(\"method\", parts...)",
|
|
2073
|
+
"}",
|
|
2074
|
+
"func main() {",
|
|
2075
|
+
" parts := []string{\"a\", \"b\"}",
|
|
2076
|
+
" collect(\"none\")",
|
|
2077
|
+
" collect(\"two\", \"a\", \"b\")",
|
|
2078
|
+
" collect(\"spread\", parts...)",
|
|
2079
|
+
" parts = append(parts, \"c\", \"d\")",
|
|
2080
|
+
" maybeErr(\"ok\")",
|
|
2081
|
+
" var fn Collector = collect",
|
|
2082
|
+
" fn(\"fn\", \"x\")",
|
|
2083
|
+
" var joiner Joiner = Path{}",
|
|
2084
|
+
" joiner.Join(\"q\", \"r\")",
|
|
2085
|
+
"}",
|
|
2086
|
+
"",
|
|
2087
|
+
}, "\n"),
|
|
2088
|
+
})
|
|
2089
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2090
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2091
|
+
if err != nil {
|
|
2092
|
+
t.Fatal(err.Error())
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2096
|
+
t.Fatal(err.Error())
|
|
2097
|
+
}
|
|
2098
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "variadic", "main.gs.ts")
|
|
2099
|
+
content, err := os.ReadFile(outputFile)
|
|
2100
|
+
if err != nil {
|
|
2101
|
+
t.Fatal(err.Error())
|
|
2102
|
+
}
|
|
2103
|
+
text := string(content)
|
|
2104
|
+
for _, want := range []string{
|
|
2105
|
+
"export type Collector = ((label: string, parts: $.Slice<string>) => string | globalThis.Promise<string>) | null",
|
|
2106
|
+
"Join(parts: $.Slice<string>): string",
|
|
2107
|
+
"export function collect(label: string, parts: $.Slice<string>): string",
|
|
2108
|
+
"let part = __goscriptRangeTarget0![__rangeIndex]",
|
|
2109
|
+
"export function maybeErr(parts: $.Slice<string>): $.GoError",
|
|
2110
|
+
"public Join(parts: $.Slice<string>): string",
|
|
2111
|
+
"collect(\"none\", null)",
|
|
2112
|
+
"collect(\"two\", $.arrayToSlice<string>([\"a\", \"b\"]))",
|
|
2113
|
+
"collect(\"spread\", parts)",
|
|
2114
|
+
"$.append(parts, \"c\", \"d\")",
|
|
2115
|
+
"maybeErr($.arrayToSlice<string>([\"ok\"]))",
|
|
2116
|
+
"fn!(\"fn\", $.arrayToSlice<string>([\"x\"]))",
|
|
2117
|
+
"$.pointerValue<Exclude<Joiner, null>>(joiner).Join($.arrayToSlice<string>([\"q\", \"r\"]))",
|
|
2118
|
+
} {
|
|
2119
|
+
if !strings.Contains(text, want) {
|
|
2120
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
func TestCompilePackagesPacksVariadicCallsInGeneratedSubpackage(t *testing.T) {
|
|
2126
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2127
|
+
"go.mod": "module example.test/variadic-subpackage\n\ngo 1.25.3\n",
|
|
2128
|
+
"json/json.go": strings.Join([]string{
|
|
2129
|
+
"package json",
|
|
2130
|
+
"import \"fmt\"",
|
|
2131
|
+
"type State struct { err error }",
|
|
2132
|
+
"func (s *State) SetErrorf(format string, a ...any) {",
|
|
2133
|
+
" s.err = fmt.Errorf(format, a...)",
|
|
2134
|
+
"}",
|
|
2135
|
+
"func (s *State) Read(key string) {",
|
|
2136
|
+
" s.SetErrorf(\"bad %q\", key)",
|
|
2137
|
+
"}",
|
|
2138
|
+
"",
|
|
2139
|
+
}, "\n"),
|
|
2140
|
+
})
|
|
2141
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2142
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2143
|
+
if err != nil {
|
|
2144
|
+
t.Fatal(err.Error())
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
if _, err := comp.CompilePackages(context.Background(), "./json"); err != nil {
|
|
2148
|
+
t.Fatal(err.Error())
|
|
2149
|
+
}
|
|
2150
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "variadic-subpackage", "json", "json.gs.ts")
|
|
2151
|
+
content, err := os.ReadFile(outputFile)
|
|
2152
|
+
if err != nil {
|
|
2153
|
+
t.Fatal(err.Error())
|
|
2154
|
+
}
|
|
2155
|
+
text := string(content)
|
|
2156
|
+
want := "State.prototype.SetErrorf.call(s, \"bad %q\", $.arrayToSlice<any>([key]))"
|
|
2157
|
+
if !strings.Contains(text, want) {
|
|
2158
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2159
|
+
}
|
|
2160
|
+
if strings.Contains(text, "$.pointerValue<State>(s).SetErrorf(\"bad %q\", key)") {
|
|
2161
|
+
t.Fatalf("generated override subpackage call was not packed:\n%s", text)
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
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
|
+
|
|
2271
|
+
func TestCompilePackagesLowersRangeOverFunctionIterators(t *testing.T) {
|
|
2272
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2273
|
+
"go.mod": "module example.test/iterators\n\ngo 1.25.3\n",
|
|
2274
|
+
"main.go": strings.Join([]string{
|
|
2275
|
+
"package main",
|
|
2276
|
+
"func pairs(yield func(int, string) bool) {",
|
|
2277
|
+
" values := []string{\"a\", \"b\"}",
|
|
2278
|
+
" for i, v := range values {",
|
|
2279
|
+
" if !yield(i, v) {",
|
|
2280
|
+
" break",
|
|
2281
|
+
" }",
|
|
2282
|
+
" }",
|
|
2283
|
+
"}",
|
|
2284
|
+
"func main() {",
|
|
2285
|
+
" for i, v := range pairs {",
|
|
2286
|
+
" println(i, v)",
|
|
2287
|
+
" }",
|
|
2288
|
+
" var last int",
|
|
2289
|
+
" for last = range pairs {",
|
|
2290
|
+
" println(last)",
|
|
2291
|
+
" }",
|
|
2292
|
+
" for i := range 3 {",
|
|
2293
|
+
" if i == 1 {",
|
|
2294
|
+
" continue",
|
|
2295
|
+
" }",
|
|
2296
|
+
" println(i)",
|
|
2297
|
+
" }",
|
|
2298
|
+
" ch := make(chan int, 1)",
|
|
2299
|
+
" for _, outer := range backward([]int{1, 2}) {",
|
|
2300
|
+
" for range backward([]int{3}) {",
|
|
2301
|
+
" ch <- outer",
|
|
2302
|
+
" }",
|
|
2303
|
+
" }",
|
|
2304
|
+
"}",
|
|
2305
|
+
"func backward(values []int) func(func(int, int) bool) {",
|
|
2306
|
+
" return func(yield func(int, int) bool) {",
|
|
2307
|
+
" for i := len(values) - 1; i >= 0; i-- {",
|
|
2308
|
+
" if !yield(i, values[i]) {",
|
|
2309
|
+
" return",
|
|
2310
|
+
" }",
|
|
2311
|
+
" }",
|
|
2312
|
+
" }",
|
|
2313
|
+
"}",
|
|
2314
|
+
"",
|
|
2315
|
+
}, "\n"),
|
|
2316
|
+
})
|
|
2317
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2318
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2319
|
+
if err != nil {
|
|
2320
|
+
t.Fatal(err.Error())
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2324
|
+
t.Fatal(err.Error())
|
|
2325
|
+
}
|
|
2326
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "iterators", "main.gs.ts")
|
|
2327
|
+
content, err := os.ReadFile(outputFile)
|
|
2328
|
+
if err != nil {
|
|
2329
|
+
t.Fatal(err.Error())
|
|
2330
|
+
}
|
|
2331
|
+
text := string(content)
|
|
2332
|
+
for _, want := range []string{
|
|
2333
|
+
"if (!await _yield!(i, v))",
|
|
2334
|
+
"break",
|
|
2335
|
+
"await pairs!(async (i, v) => {",
|
|
2336
|
+
"last = __goscriptRange",
|
|
2337
|
+
"return true",
|
|
2338
|
+
"continue",
|
|
2339
|
+
"await backward($.arrayToSlice<number>([1, 2]))!(async (__goscriptRange",
|
|
2340
|
+
"await backward($.arrayToSlice<number>([3]))!(async (__goscriptRange",
|
|
2341
|
+
} {
|
|
2342
|
+
if !strings.Contains(text, want) {
|
|
2343
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
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
|
+
|
|
2391
|
+
func TestCompilePackagesLowersFunctionIteratorControlFlow(t *testing.T) {
|
|
2392
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2393
|
+
"go.mod": "module example.test/iterator-control\n\ngo 1.25.3\n",
|
|
2394
|
+
"main.go": strings.Join([]string{
|
|
2395
|
+
"package main",
|
|
2396
|
+
"func values(yield func(int) bool) {",
|
|
2397
|
+
" for i := range 4 {",
|
|
2398
|
+
" if !yield(i) {",
|
|
2399
|
+
" return",
|
|
2400
|
+
" }",
|
|
2401
|
+
" }",
|
|
2402
|
+
"}",
|
|
2403
|
+
"func first(limit int) int {",
|
|
2404
|
+
" j := 3",
|
|
2405
|
+
" for i := 0; i < j; i, j = i+1, j-1 {",
|
|
2406
|
+
" println(i, j)",
|
|
2407
|
+
" }",
|
|
2408
|
+
" for v := range values {",
|
|
2409
|
+
" if v == 0 {",
|
|
2410
|
+
" continue",
|
|
2411
|
+
" }",
|
|
2412
|
+
" for i := range 2 {",
|
|
2413
|
+
" if i == 1 {",
|
|
2414
|
+
" break",
|
|
2415
|
+
" }",
|
|
2416
|
+
" }",
|
|
2417
|
+
" if v == limit {",
|
|
2418
|
+
" break",
|
|
2419
|
+
" }",
|
|
2420
|
+
" switch v {",
|
|
2421
|
+
" case 2:",
|
|
2422
|
+
" return v",
|
|
2423
|
+
" }",
|
|
2424
|
+
" switch any(v).(type) {",
|
|
2425
|
+
" case int:",
|
|
2426
|
+
" if v == 3 {",
|
|
2427
|
+
" return v",
|
|
2428
|
+
" }",
|
|
2429
|
+
" }",
|
|
2430
|
+
" }",
|
|
2431
|
+
" return -1",
|
|
2432
|
+
"}",
|
|
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()",
|
|
2623
|
+
" }",
|
|
2624
|
+
" return value, nil",
|
|
2625
|
+
"}",
|
|
2626
|
+
"func use(r *resolver) (int, error) {",
|
|
2627
|
+
" return r.lookup()",
|
|
2628
|
+
"}",
|
|
2629
|
+
"func main() {}",
|
|
2630
|
+
"",
|
|
2631
|
+
}, "\n"),
|
|
2632
|
+
})
|
|
2633
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2634
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2635
|
+
if err != nil {
|
|
2636
|
+
t.Fatal(err.Error())
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2640
|
+
t.Fatal(err.Error())
|
|
2641
|
+
}
|
|
2642
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "immediate-func-lit-async", "main.gs.ts")
|
|
2643
|
+
content, err := os.ReadFile(outputFile)
|
|
2644
|
+
if err != nil {
|
|
2645
|
+
t.Fatal(err.Error())
|
|
2646
|
+
}
|
|
2647
|
+
text := string(content)
|
|
2648
|
+
for _, want := range []string{
|
|
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)",
|
|
2653
|
+
} {
|
|
2654
|
+
if !strings.Contains(text, want) {
|
|
2655
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
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)
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
func TestCompilePackagesParenthesizesAsyncFieldReceivers(t *testing.T) {
|
|
2664
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2665
|
+
"go.mod": "module example.test/asyncfield\n\ngo 1.25.3\n",
|
|
2666
|
+
"main.go": strings.Join([]string{
|
|
2667
|
+
"package main",
|
|
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",
|
|
2676
|
+
"}",
|
|
2677
|
+
"func main() {",
|
|
2678
|
+
" box := &Box{ch: make(chan int, 1)}",
|
|
2679
|
+
" println(box.OK())",
|
|
2680
|
+
"}",
|
|
2681
|
+
"",
|
|
2682
|
+
}, "\n"),
|
|
2683
|
+
})
|
|
2684
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2685
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2686
|
+
if err != nil {
|
|
2687
|
+
t.Fatal(err.Error())
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2691
|
+
t.Fatal(err.Error())
|
|
2692
|
+
}
|
|
2693
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncfield", "main.gs.ts")
|
|
2694
|
+
content, err := os.ReadFile(outputFile)
|
|
2695
|
+
if err != nil {
|
|
2696
|
+
t.Fatal(err.Error())
|
|
2697
|
+
}
|
|
2698
|
+
text := string(content)
|
|
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)
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
func TestCompilePackagesScopesIfInitDeclarations(t *testing.T) {
|
|
2708
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2709
|
+
"go.mod": "module example.test/ifinit\n\ngo 1.25.3\n",
|
|
2710
|
+
"main.go": strings.Join([]string{
|
|
2711
|
+
"package main",
|
|
2712
|
+
"func pair() (string, bool) {",
|
|
2713
|
+
" return \"value\", true",
|
|
2714
|
+
"}",
|
|
2715
|
+
"func main() {",
|
|
2716
|
+
" if value, ok := pair(); ok {",
|
|
2717
|
+
" println(value)",
|
|
2718
|
+
" }",
|
|
2719
|
+
" if value, ok := pair(); ok {",
|
|
2720
|
+
" println(value)",
|
|
2721
|
+
" }",
|
|
2722
|
+
"}",
|
|
2723
|
+
"",
|
|
2724
|
+
}, "\n"),
|
|
2725
|
+
})
|
|
2726
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2727
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2728
|
+
if err != nil {
|
|
2729
|
+
t.Fatal(err.Error())
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2733
|
+
t.Fatal(err.Error())
|
|
2734
|
+
}
|
|
2735
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "ifinit", "main.gs.ts"))
|
|
2736
|
+
if err != nil {
|
|
2737
|
+
t.Fatal(err.Error())
|
|
2738
|
+
}
|
|
2739
|
+
if strings.Count(string(content), "{\n\t\tlet [value, ok] = pair()") != 2 {
|
|
2740
|
+
t.Fatalf("if init declarations were not block scoped:\n%s", string(content))
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
func TestCompilePackagesLowersSwitchesAndFunctionValueCalls(t *testing.T) {
|
|
2745
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2746
|
+
"go.mod": "module example.test/switchcall\n\ngo 1.25.3\n",
|
|
2747
|
+
"main.go": strings.Join([]string{
|
|
2748
|
+
"package main",
|
|
2749
|
+
"func main() {",
|
|
2750
|
+
" value := 2",
|
|
2751
|
+
" switch value {",
|
|
2752
|
+
" case 1:",
|
|
2753
|
+
" println(\"one\")",
|
|
2754
|
+
" case 2, 3:",
|
|
2755
|
+
" local := \"two-three\"",
|
|
2756
|
+
" println(local)",
|
|
2757
|
+
" default:",
|
|
2758
|
+
" println(\"other\")",
|
|
2759
|
+
" }",
|
|
2760
|
+
" switch {",
|
|
2761
|
+
" case value > 1:",
|
|
2762
|
+
" println(\"positive\")",
|
|
2763
|
+
" }",
|
|
2764
|
+
"Block:",
|
|
2765
|
+
" for value > 0 {",
|
|
2766
|
+
" switch value {",
|
|
2767
|
+
" case 2:",
|
|
2768
|
+
" value--",
|
|
2769
|
+
" fallthrough",
|
|
2770
|
+
" case 1:",
|
|
2771
|
+
" break Block",
|
|
2772
|
+
" }",
|
|
2773
|
+
" }",
|
|
2774
|
+
"Again:",
|
|
2775
|
+
" value--",
|
|
2776
|
+
" if value > 0 {",
|
|
2777
|
+
" goto Again",
|
|
2778
|
+
" }",
|
|
2779
|
+
" release := func() { println(\"release\") }",
|
|
2780
|
+
" rel := &release",
|
|
2781
|
+
" (*rel)()",
|
|
2782
|
+
" wrapped := func() {",
|
|
2783
|
+
" defer println(\"wrapped deferred\")",
|
|
2784
|
+
" println(\"wrapped body\")",
|
|
2785
|
+
" }",
|
|
2786
|
+
" wrapped()",
|
|
2787
|
+
"}",
|
|
2788
|
+
"",
|
|
2789
|
+
}, "\n"),
|
|
2790
|
+
})
|
|
2791
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2792
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2793
|
+
if err != nil {
|
|
2794
|
+
t.Fatal(err.Error())
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2798
|
+
t.Fatal(err.Error())
|
|
2799
|
+
}
|
|
2800
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "switchcall", "main.gs.ts"))
|
|
2801
|
+
if err != nil {
|
|
2802
|
+
t.Fatal(err.Error())
|
|
2803
|
+
}
|
|
2804
|
+
text := string(content)
|
|
2805
|
+
for _, want := range []string{
|
|
2806
|
+
"switch (value) {",
|
|
2807
|
+
"case 2:",
|
|
2808
|
+
"case 3:",
|
|
2809
|
+
"let local = \"two-three\"",
|
|
2810
|
+
"switch (true) {",
|
|
2811
|
+
"Block: while (value > 0)",
|
|
2812
|
+
"break Block",
|
|
2813
|
+
"Again: while (true)",
|
|
2814
|
+
"continue Again",
|
|
2815
|
+
"($.pointerValue<(() => void) | null>(rel))!()",
|
|
2816
|
+
"$.functionValue((): void => {\n\t\tusing __defer = new $.DisposableStack()",
|
|
2817
|
+
"__defer.defer(() => { $.println(\"wrapped deferred\") })",
|
|
2818
|
+
"$.println(\"wrapped body\")",
|
|
2819
|
+
} {
|
|
2820
|
+
if !strings.Contains(text, want) {
|
|
2821
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
if strings.Count(text, "\t\tbreak\n") < 3 {
|
|
2825
|
+
t.Fatalf("switch cases were not rendered with implicit breaks:\n%s", text)
|
|
2826
|
+
}
|
|
2827
|
+
if strings.Contains(text, "fallthrough") {
|
|
2828
|
+
t.Fatalf("fallthrough marker leaked into generated output:\n%s", text)
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2832
|
+
func TestCompilePackagesLowersMethodValuesWithFixedParameters(t *testing.T) {
|
|
2833
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2834
|
+
"go.mod": "module example.test/methodvalue\n\ngo 1.25.3\n",
|
|
2835
|
+
"main.go": strings.Join([]string{
|
|
2836
|
+
"package main",
|
|
2837
|
+
"type Counter int",
|
|
2838
|
+
"func (c Counter) Add(n int) int {",
|
|
2839
|
+
" return int(c) + n",
|
|
2840
|
+
"}",
|
|
2841
|
+
"type Runner struct{}",
|
|
2842
|
+
"func (r Runner) Run() {",
|
|
2843
|
+
" println(\"run\")",
|
|
2844
|
+
"}",
|
|
2845
|
+
"func main() {",
|
|
2846
|
+
" c := Counter(4)",
|
|
2847
|
+
" add := c.Add",
|
|
2848
|
+
" println(add(3))",
|
|
2849
|
+
" r := Runner{}",
|
|
2850
|
+
" run := r.Run",
|
|
2851
|
+
" run()",
|
|
2852
|
+
"}",
|
|
2853
|
+
"",
|
|
2854
|
+
}, "\n"),
|
|
2855
|
+
})
|
|
2856
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2857
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2858
|
+
if err != nil {
|
|
2859
|
+
t.Fatal(err.Error())
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2863
|
+
t.Fatal(err.Error())
|
|
2864
|
+
}
|
|
2865
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "methodvalue", "main.gs.ts"))
|
|
2866
|
+
if err != nil {
|
|
2867
|
+
t.Fatal(err.Error())
|
|
2868
|
+
}
|
|
2869
|
+
text := string(content)
|
|
2870
|
+
for _, want := range []string{
|
|
2871
|
+
"((__receiver) => (n: number) => Counter_Add(__receiver, n))(c)",
|
|
2872
|
+
"((__receiver) => () => __receiver.Run())(",
|
|
2873
|
+
} {
|
|
2874
|
+
if !strings.Contains(text, want) {
|
|
2875
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
if strings.Contains(text, "...args: any[]") {
|
|
2879
|
+
t.Fatalf("method value lowering still uses spread args:\n%s", text)
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
|
|
2883
|
+
func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testing.T) {
|
|
2884
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2885
|
+
"go.mod": "module example.test/qualified\n\ngo 1.25.3\n",
|
|
2886
|
+
"lib/lib.go": strings.Join([]string{
|
|
1035
2887
|
"package lib",
|
|
1036
2888
|
"type Box struct {",
|
|
1037
2889
|
" Value int",
|
|
@@ -1077,11 +2929,11 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
|
|
|
1077
2929
|
for _, want := range []string{
|
|
1078
2930
|
"Box: $.VarRef<lib.Box>",
|
|
1079
2931
|
"Boxes: $.VarRef<$.Slice<lib.Box>>",
|
|
1080
|
-
"Fn: $.VarRef<((_p0: lib.Box) => [lib.Box, $.GoError]) | null>",
|
|
2932
|
+
"Fn: $.VarRef<((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null>",
|
|
1081
2933
|
"Ptr: $.VarRef<atomic.Pointer<(() => void) | null>>",
|
|
1082
2934
|
"$.markAsStructValue(new lib.Box())",
|
|
1083
2935
|
"$.markAsStructValue(new atomic.Pointer<(() => void) | null>())",
|
|
1084
|
-
"export function Use(fn: ((_p0: lib.Box) => [lib.Box, $.GoError]) | null, box: lib.Box): [lib.Box, $.GoError]",
|
|
2936
|
+
"export async function Use(fn: ((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null, box: lib.Box): globalThis.Promise<[lib.Box, $.GoError]>",
|
|
1085
2937
|
"$.functionValue((box: lib.Box): [lib.Box, $.GoError] => {",
|
|
1086
2938
|
} {
|
|
1087
2939
|
if !strings.Contains(text, want) {
|
|
@@ -1090,14 +2942,16 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
|
|
|
1090
2942
|
}
|
|
1091
2943
|
}
|
|
1092
2944
|
|
|
1093
|
-
func
|
|
2945
|
+
func TestCompilePackagesLowersUnaryBitwiseComplement(t *testing.T) {
|
|
1094
2946
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1095
|
-
"go.mod": "module example.test/
|
|
2947
|
+
"go.mod": "module example.test/unary-bitwise\n\ngo 1.25.3\n",
|
|
1096
2948
|
"main.go": strings.Join([]string{
|
|
1097
2949
|
"package main",
|
|
1098
2950
|
"var value = 1",
|
|
1099
2951
|
"func main() {",
|
|
1100
|
-
"
|
|
2952
|
+
" mask := 7",
|
|
2953
|
+
" mask &^= 3",
|
|
2954
|
+
" println(^value, value &^ 3, mask, 0700)",
|
|
1101
2955
|
"}",
|
|
1102
2956
|
"",
|
|
1103
2957
|
}, "\n"),
|
|
@@ -1108,25 +2962,424 @@ func TestCompilePackagesReportsUnsupportedUnaryBeforeOutput(t *testing.T) {
|
|
|
1108
2962
|
t.Fatal(err.Error())
|
|
1109
2963
|
}
|
|
1110
2964
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
t.Fatal("expected unsupported unary expression to fail")
|
|
2965
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2966
|
+
t.Fatal(err.Error())
|
|
1114
2967
|
}
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
2968
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "unary-bitwise", "main.gs.ts")
|
|
2969
|
+
content, err := os.ReadFile(outputFile)
|
|
2970
|
+
if err != nil {
|
|
2971
|
+
t.Fatal(err.Error())
|
|
1118
2972
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
2973
|
+
text := string(content)
|
|
2974
|
+
for _, want := range []string{
|
|
2975
|
+
"mask = mask & ~(3)",
|
|
2976
|
+
"$.println(~value, value & ~(3), mask, 0o700)",
|
|
2977
|
+
} {
|
|
2978
|
+
if !strings.Contains(text, want) {
|
|
2979
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2980
|
+
}
|
|
1121
2981
|
}
|
|
1122
2982
|
}
|
|
1123
2983
|
|
|
1124
|
-
func
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
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
|
+
|
|
3276
|
+
func TestCompileSourceToTypeScriptCompilesSingleFile(t *testing.T) {
|
|
3277
|
+
output, err := CompileSourceToTypeScript("package main\nfunc main() { println(\"hi\") }\n", "main")
|
|
3278
|
+
if err != nil {
|
|
3279
|
+
t.Fatal(err.Error())
|
|
3280
|
+
}
|
|
3281
|
+
if !strings.Contains(output, "$.println(\"hi\")") {
|
|
3282
|
+
t.Fatalf("missing println in generated output:\n%s", output)
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
|
|
3286
|
+
func TestTypeScriptEmitOwnerEmitsToMemoryOnDiskPath(t *testing.T) {
|
|
3287
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3288
|
+
"go.mod": "module example.test/memoryemit\n\ngo 1.25.3\n",
|
|
3289
|
+
"main.go": "package main\nfunc main() { println(\"memory\") }\n",
|
|
3290
|
+
})
|
|
3291
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3292
|
+
req := &CompileRequest{
|
|
3293
|
+
Patterns: []string{"."},
|
|
3294
|
+
Dir: moduleDir,
|
|
3295
|
+
OutputPath: outputDir,
|
|
3296
|
+
DependencyMode: DependencyModeRequested,
|
|
3297
|
+
RuntimeEmissionMode: RuntimeEmissionModeReference,
|
|
3298
|
+
}
|
|
3299
|
+
service := NewCompileService()
|
|
3300
|
+
graph, diagnostics := service.PackageGraphOwner().Load(context.Background(), req)
|
|
3301
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
3302
|
+
t.Fatalf("graph diagnostics: %#v", diagnostics)
|
|
3303
|
+
}
|
|
3304
|
+
model, diagnostics := service.SemanticModelOwner().Build(context.Background(), graph)
|
|
3305
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
3306
|
+
t.Fatalf("semantic diagnostics: %#v", diagnostics)
|
|
3307
|
+
}
|
|
3308
|
+
program, diagnostics := service.LoweringOwner().Build(context.Background(), model)
|
|
3309
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
3310
|
+
t.Fatalf("lowering diagnostics: %#v", diagnostics)
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
files, diagnostics := service.TypeScriptEmitOwner().EmitToMemory(context.Background(), program)
|
|
3314
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
3315
|
+
t.Fatalf("memory emit diagnostics: %#v", diagnostics)
|
|
3316
|
+
}
|
|
3317
|
+
path := "@goscript/example.test/memoryemit/main.gs.ts"
|
|
3318
|
+
if !strings.Contains(files[path], "$.println(\"memory\")") {
|
|
3319
|
+
t.Fatalf("missing in-memory output: %#v", files)
|
|
3320
|
+
}
|
|
3321
|
+
if _, diagnostics := service.TypeScriptEmitOwner().Emit(context.Background(), req, program); diagnosticsHaveErrors(diagnostics) {
|
|
3322
|
+
t.Fatalf("disk emit diagnostics: %#v", diagnostics)
|
|
3323
|
+
}
|
|
3324
|
+
content, err := os.ReadFile(filepath.Join(outputDir, filepath.FromSlash(path)))
|
|
3325
|
+
if err != nil {
|
|
3326
|
+
t.Fatal(err.Error())
|
|
3327
|
+
}
|
|
3328
|
+
if string(content) != files[path] {
|
|
3329
|
+
t.Fatalf("disk and memory emit diverged:\n%s\n---\n%s", string(content), files[path])
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
|
|
3333
|
+
func TestCompilePackagesLowersNamedStructConversionWithTypedAsyncFact(t *testing.T) {
|
|
3334
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3335
|
+
"go.mod": "module example.test/namedstructconvert\n\ngo 1.25.3\n",
|
|
3336
|
+
"main.go": strings.Join([]string{
|
|
3337
|
+
"package main",
|
|
3338
|
+
"type Source struct { Value int }",
|
|
3339
|
+
"type Target Source",
|
|
3340
|
+
"func Make() Source {",
|
|
3341
|
+
" ch := make(chan Source, 1)",
|
|
3342
|
+
" ch <- Source{Value: 7}",
|
|
3343
|
+
" return <-ch",
|
|
3344
|
+
"}",
|
|
3345
|
+
"func Convert() Target {",
|
|
3346
|
+
" return Target(Make())",
|
|
3347
|
+
"}",
|
|
3348
|
+
"func ConvertLiteral() Target {",
|
|
3349
|
+
" return Target(func() Source {",
|
|
3350
|
+
" ch := make(chan Source, 1)",
|
|
3351
|
+
" ch <- Source{Value: 9}",
|
|
3352
|
+
" return <-ch",
|
|
3353
|
+
" }())",
|
|
3354
|
+
"}",
|
|
3355
|
+
"func main() { println(Convert().Value) }",
|
|
3356
|
+
"",
|
|
3357
|
+
}, "\n"),
|
|
3358
|
+
})
|
|
3359
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3360
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3361
|
+
if err != nil {
|
|
3362
|
+
t.Fatal(err.Error())
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3365
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3366
|
+
t.Fatal(err.Error())
|
|
3367
|
+
}
|
|
3368
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "namedstructconvert", "main.gs.ts")
|
|
3369
|
+
content, err := os.ReadFile(outputFile)
|
|
3370
|
+
if err != nil {
|
|
3371
|
+
t.Fatal(err.Error())
|
|
3372
|
+
}
|
|
3373
|
+
text := string(content)
|
|
3374
|
+
if !strings.Contains(text, "await (async () => { const __goscriptConvert") {
|
|
3375
|
+
t.Fatalf("missing async named struct conversion:\n%s", text)
|
|
3376
|
+
}
|
|
3377
|
+
if !strings.Contains(text, "$.markAsStructValue(new Target({Value: __goscriptConvert") {
|
|
3378
|
+
t.Fatalf("missing typed named struct conversion target:\n%s", text)
|
|
3379
|
+
}
|
|
3380
|
+
if !strings.Contains(text, "const __goscriptConvert1 = await ($.functionValue(async ") {
|
|
3381
|
+
t.Fatalf("missing async fact from function literal conversion source:\n%s", text)
|
|
1128
3382
|
}
|
|
1129
|
-
requireDiagnostic(t, err, "goscript/wasm:single-file-unsupported")
|
|
1130
3383
|
}
|
|
1131
3384
|
|
|
1132
3385
|
func requireDiagnostic(t *testing.T, err error, code string) {
|