goscript 0.1.3 → 0.2.0
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 +5 -2
- package/cmd/go_js_wasm_exec/main.go +201 -0
- package/cmd/go_js_wasm_exec/main_test.go +83 -0
- package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +35 -8
- package/cmd/goscript/cmd-test.go +14 -0
- package/cmd/goscript/cmd-test_test.go +1 -1
- package/cmd/goscript/cmd_compile_test.go +105 -6
- package/compiler/build-flags.go +9 -10
- package/compiler/compile-request.go +12 -9
- package/compiler/compliance_test.go +0 -1
- package/compiler/config.go +2 -0
- package/compiler/gotest/request.go +28 -0
- package/compiler/gotest/runner.go +353 -27
- package/compiler/gotest/runner_test.go +400 -1
- package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
- package/compiler/gotest/testdata/browserapi/go.mod +3 -0
- package/compiler/lowered-program.go +24 -17
- package/compiler/lowering.go +988 -263
- package/compiler/lowering_bench_test.go +364 -0
- package/compiler/override-facts.go +15 -0
- package/compiler/override-parity-verifier.go +450 -0
- package/compiler/override-parity.go +122 -0
- package/compiler/override-registry_test.go +559 -0
- package/compiler/package-graph.go +61 -4
- package/compiler/package-graph_test.go +30 -0
- package/compiler/protobuf-ts-binding.go +514 -0
- package/compiler/protobuf-ts-binding_test.go +172 -0
- package/compiler/semantic-model-types.go +17 -4
- package/compiler/semantic-model.go +709 -72
- package/compiler/semantic-model_test.go +219 -0
- package/compiler/service.go +20 -1
- package/compiler/skeleton_test.go +1008 -20
- package/compiler/typescript-emitter.go +147 -15
- package/dist/gs/builtin/builtin.d.ts +2 -2
- package/dist/gs/builtin/builtin.js +20 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +2 -1
- package/dist/gs/builtin/slice.js +34 -4
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +14 -6
- package/dist/gs/builtin/type.js +224 -64
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +11 -0
- package/dist/gs/builtin/varRef.js +57 -2
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/compress/zlib/index.d.ts +13 -6
- package/dist/gs/compress/zlib/index.js +131 -35
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/sha1/index.js +2 -5
- package/dist/gs/crypto/sha1/index.js.map +1 -1
- package/dist/gs/crypto/sha256/index.js +2 -5
- package/dist/gs/crypto/sha256/index.js.map +1 -1
- package/dist/gs/crypto/sha512/index.js +2 -5
- package/dist/gs/crypto/sha512/index.js.map +1 -1
- package/dist/gs/embed/index.d.ts +6 -0
- package/dist/gs/embed/index.js +210 -5
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/encoding/json/index.d.ts +114 -0
- package/dist/gs/encoding/json/index.js +544 -36
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/fmt/fmt.d.ts +3 -3
- package/dist/gs/fmt/fmt.js +29 -16
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
- package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
- package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
- package/dist/gs/github.com/pkg/errors/errors.js +54 -30
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +2 -0
- package/dist/gs/go/scanner/index.js +29 -5
- package/dist/gs/go/scanner/index.js.map +1 -1
- package/dist/gs/go/token/index.js +22 -6
- package/dist/gs/go/token/index.js.map +1 -1
- package/dist/gs/hash/index.d.ts +6 -0
- package/dist/gs/hash/index.js +20 -0
- package/dist/gs/hash/index.js.map +1 -1
- package/dist/gs/internal/goarch/index.d.ts +43 -3
- package/dist/gs/internal/goarch/index.js +42 -10
- package/dist/gs/internal/goarch/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js +26 -14
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js +8 -4
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/sub.js +8 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.d.ts +12 -6
- package/dist/gs/io/io.js +87 -42
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/math/bits/index.d.ts +31 -5
- package/dist/gs/math/bits/index.js +29 -28
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/mime/index.d.ts +16 -0
- package/dist/gs/mime/index.js +315 -6
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.d.ts +12 -0
- package/dist/gs/net/http/httptest/index.js +85 -6
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +303 -6
- package/dist/gs/net/http/index.js +1615 -58
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +1 -1
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.d.ts +1 -0
- package/dist/gs/os/exec.gs.js +4 -8
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/index.d.ts +1 -1
- package/dist/gs/os/index.js +1 -1
- package/dist/gs/os/index.js.map +1 -1
- package/dist/gs/os/proc.gs.d.ts +4 -0
- package/dist/gs/os/proc.gs.js +12 -6
- package/dist/gs/os/proc.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +6 -2
- package/dist/gs/os/types_js.gs.js +170 -9
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/path.js +11 -7
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +5 -4
- package/dist/gs/reflect/index.js +4 -3
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js +15 -0
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +26 -6
- package/dist/gs/reflect/type.js +1498 -279
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.d.ts +14 -6
- package/dist/gs/reflect/types.js +35 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/value.d.ts +1 -0
- package/dist/gs/reflect/value.js +83 -41
- package/dist/gs/reflect/value.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js +4 -140
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/pprof/index.d.ts +8 -2
- package/dist/gs/runtime/pprof/index.js +50 -30
- package/dist/gs/runtime/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.js +5 -4
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.js +5 -19
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/complex.gs.d.ts +3 -0
- package/dist/gs/strconv/complex.gs.js +148 -0
- package/dist/gs/strconv/complex.gs.js.map +1 -0
- package/dist/gs/strconv/index.d.ts +1 -0
- package/dist/gs/strconv/index.js +1 -0
- package/dist/gs/strconv/index.js.map +1 -1
- package/dist/gs/strings/builder.js +1 -1
- package/dist/gs/strings/reader.d.ts +1 -1
- package/dist/gs/strings/reader.js +11 -7
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js +15 -7
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/strings/strings.d.ts +5 -0
- package/dist/gs/strings/strings.js +57 -5
- package/dist/gs/strings/strings.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js +9 -9
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js +2 -2
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +2 -1
- package/dist/gs/sync/sync.js +37 -16
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/env.js +22 -14
- package/dist/gs/syscall/env.js.map +1 -1
- package/dist/gs/syscall/js/index.js +9 -0
- package/dist/gs/syscall/js/index.js.map +1 -1
- package/dist/gs/testing/testing.js +59 -15
- package/dist/gs/testing/testing.js.map +1 -1
- package/dist/gs/time/time.d.ts +24 -1
- package/dist/gs/time/time.js +43 -3
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unique/index.js +7 -1
- package/dist/gs/unique/index.js.map +1 -1
- package/go.mod +3 -3
- package/go.sum +16 -0
- package/gs/builtin/builtin.ts +25 -2
- package/gs/builtin/runtime-contract.test.ts +260 -18
- package/gs/builtin/slice.ts +51 -4
- package/gs/builtin/type.ts +310 -63
- package/gs/builtin/varRef.ts +85 -2
- package/gs/bytes/buffer.gs.ts +1 -1
- package/gs/bytes/reader.gs.ts +1 -1
- package/gs/compress/zlib/index.test.ts +159 -1
- package/gs/compress/zlib/index.ts +164 -37
- package/gs/compress/zlib/meta.json +4 -1
- package/gs/compress/zlib/parity.json +51 -0
- package/gs/crypto/sha1/index.test.ts +19 -2
- package/gs/crypto/sha1/index.ts +3 -6
- package/gs/crypto/sha256/index.test.ts +14 -2
- package/gs/crypto/sha256/index.ts +3 -6
- package/gs/crypto/sha512/index.test.ts +17 -2
- package/gs/crypto/sha512/index.ts +3 -6
- package/gs/embed/index.test.ts +87 -0
- package/gs/embed/index.ts +229 -5
- package/gs/encoding/json/index.test.ts +360 -6
- package/gs/encoding/json/index.ts +679 -38
- package/gs/encoding/json/parity.json +81 -0
- package/gs/fmt/fmt.test.ts +41 -3
- package/gs/fmt/fmt.ts +40 -17
- package/gs/fmt/meta.json +6 -1
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
- package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
- package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
- package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
- package/gs/github.com/pkg/errors/errors.ts +54 -30
- package/gs/go/scanner/index.test.ts +39 -56
- package/gs/go/scanner/index.ts +33 -5
- package/gs/go/scanner/parity.json +27 -0
- package/gs/go/token/index.ts +22 -6
- package/gs/hash/index.test.ts +20 -33
- package/gs/hash/index.ts +28 -0
- package/gs/hash/parity.json +21 -0
- package/gs/internal/goarch/index.test.ts +32 -0
- package/gs/internal/goarch/index.ts +45 -13
- package/gs/internal/goarch/parity.json +144 -0
- package/gs/io/fs/fs.ts +26 -14
- package/gs/io/fs/readdir.test.ts +38 -0
- package/gs/io/fs/readdir.ts +8 -4
- package/gs/io/fs/sub.ts +8 -1
- package/gs/io/io.test.ts +77 -6
- package/gs/io/io.ts +115 -52
- package/gs/io/meta.json +7 -1
- package/gs/io/parity.json +162 -0
- package/gs/math/bits/index.test.ts +14 -1
- package/gs/math/bits/index.ts +75 -32
- package/gs/math/bits/parity.json +156 -0
- package/gs/mime/index.test.ts +90 -0
- package/gs/mime/index.ts +369 -6
- package/gs/mime/parity.json +36 -0
- package/gs/net/http/httptest/index.test.ts +98 -2
- package/gs/net/http/httptest/index.ts +101 -6
- package/gs/net/http/httptest/parity.json +15 -0
- package/gs/net/http/index.test.ts +797 -12
- package/gs/net/http/index.ts +1874 -136
- package/gs/net/http/meta.json +16 -1
- package/gs/net/http/parity.json +193 -0
- package/gs/os/dir_unix.gs.ts +1 -1
- package/gs/os/error.gs.ts +1 -1
- package/gs/os/exec.gs.ts +4 -8
- package/gs/os/exec_posix.gs.ts +1 -1
- package/gs/os/file_unix_js.test.ts +52 -0
- package/gs/os/index.test.ts +9 -0
- package/gs/os/index.ts +1 -0
- package/gs/os/meta.json +4 -0
- package/gs/os/parity.json +9 -0
- package/gs/os/proc.gs.ts +18 -5
- package/gs/os/proc.test.ts +26 -0
- package/gs/os/readdir.test.ts +56 -0
- package/gs/os/root_js.gs.ts +1 -1
- package/gs/os/types.gs.ts +1 -1
- package/gs/os/types_js.gs.ts +170 -9
- package/gs/os/types_unix.gs.ts +1 -1
- package/gs/path/path.ts +11 -7
- package/gs/reflect/deepequal.test.ts +10 -1
- package/gs/reflect/field.test.ts +37 -15
- package/gs/reflect/function-types.test.ts +518 -22
- package/gs/reflect/index.ts +8 -6
- package/gs/reflect/map.ts +20 -0
- package/gs/reflect/meta.json +6 -4
- package/gs/reflect/parity.json +234 -0
- package/gs/reflect/sliceat.test.ts +156 -0
- package/gs/reflect/structof.test.ts +401 -0
- package/gs/reflect/type.ts +1980 -365
- package/gs/reflect/typefor.test.ts +540 -10
- package/gs/reflect/types.ts +43 -18
- package/gs/reflect/value.ts +105 -45
- package/gs/reflect/visiblefields.ts +5 -168
- package/gs/runtime/parity.json +24 -0
- package/gs/runtime/pprof/index.test.ts +29 -7
- package/gs/runtime/pprof/index.ts +56 -30
- package/gs/runtime/pprof/parity.json +27 -0
- package/gs/runtime/runtime.test.ts +3 -1
- package/gs/runtime/runtime.ts +4 -3
- package/gs/runtime/trace/index.test.ts +5 -3
- package/gs/runtime/trace/index.ts +8 -20
- package/gs/runtime/trace/parity.json +36 -0
- package/gs/strconv/atoi.gs.ts +1 -1
- package/gs/strconv/complex.gs.ts +174 -0
- package/gs/strconv/complex.test.ts +65 -0
- package/gs/strconv/index.ts +1 -0
- package/gs/strconv/parity.json +120 -0
- package/gs/strings/builder.ts +1 -1
- package/gs/strings/meta.json +5 -2
- package/gs/strings/parity.json +186 -0
- package/gs/strings/reader.test.ts +2 -2
- package/gs/strings/reader.ts +11 -7
- package/gs/strings/replace.ts +15 -7
- package/gs/strings/strings.test.ts +22 -2
- package/gs/strings/strings.ts +64 -6
- package/gs/sync/atomic/type.gs.ts +9 -9
- package/gs/sync/atomic/value.gs.ts +2 -2
- package/gs/sync/meta.json +1 -0
- package/gs/sync/sync.test.ts +41 -1
- package/gs/sync/sync.ts +41 -16
- package/gs/syscall/env.ts +29 -14
- package/gs/syscall/js/index.test.ts +18 -0
- package/gs/syscall/js/index.ts +12 -0
- package/gs/testing/testing.test.ts +99 -3
- package/gs/testing/testing.ts +95 -24
- package/gs/time/parity.json +225 -0
- package/gs/time/time.test.ts +20 -2
- package/gs/time/time.ts +49 -7
- package/gs/unique/index.ts +7 -1
- package/package.json +4 -2
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
- package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
- package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
- package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
- /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
|
@@ -132,7 +132,7 @@ func TestCompilePackagesEmitsSimplePackage(t *testing.T) {
|
|
|
132
132
|
"export async function main(): globalThis.Promise<void>",
|
|
133
133
|
"let size = 5",
|
|
134
134
|
"$.print(\"total:\", size)",
|
|
135
|
-
"$.println(
|
|
135
|
+
"$.println(\"Hello\", total)",
|
|
136
136
|
"$.panic(\"unreachable\")",
|
|
137
137
|
"await main()",
|
|
138
138
|
} {
|
|
@@ -215,9 +215,9 @@ func TestCompilePackagesLazilyInitializesCrossFilePackageVars(t *testing.T) {
|
|
|
215
215
|
}
|
|
216
216
|
text := string(content)
|
|
217
217
|
for _, want := range []string{
|
|
218
|
-
"export var two: holder
|
|
218
|
+
"export var two: holder",
|
|
219
219
|
"export function __goscript_get_two(): holder",
|
|
220
|
-
"export var remoteZero: __goscript_a.remote
|
|
220
|
+
"export var remoteZero: __goscript_a.remote",
|
|
221
221
|
"export function __goscript_get_remoteZero(): __goscript_a.remote",
|
|
222
222
|
"__goscript_a.__goscript_get_one()",
|
|
223
223
|
} {
|
|
@@ -263,7 +263,7 @@ func TestCompilePackagesLazilyInitializesSameFileLaterPackageVars(t *testing.T)
|
|
|
263
263
|
}
|
|
264
264
|
text := string(content)
|
|
265
265
|
for _, want := range []string{
|
|
266
|
-
"export var table: $.Slice<detail>
|
|
266
|
+
"export var table: $.Slice<detail>",
|
|
267
267
|
"export function __goscript_get_table(): $.Slice<detail>",
|
|
268
268
|
"export let later: detail = $.markAsStructValue(new detail({n: 7}))",
|
|
269
269
|
} {
|
|
@@ -305,7 +305,7 @@ func TestCompilePackagesLazilyInitializesFunctionBodyPackageVarDependencies(t *t
|
|
|
305
305
|
}
|
|
306
306
|
text := string(content)
|
|
307
307
|
for _, want := range []string{
|
|
308
|
-
"export var first: Point | $.VarRef<Point> | null
|
|
308
|
+
"export var first: Point | $.VarRef<Point> | null",
|
|
309
309
|
"export function __goscript_get_first(): Point | $.VarRef<Point> | null",
|
|
310
310
|
"function __goscript_get___goscriptTuple",
|
|
311
311
|
"export let later: number = 7",
|
|
@@ -355,7 +355,7 @@ func TestCompilePackagesLazilyInitializesEffectFreeTypeForFromCrossFileInit(t *t
|
|
|
355
355
|
}
|
|
356
356
|
aText := string(aContent)
|
|
357
357
|
for _, want := range []string{
|
|
358
|
-
"export var stringType: reflect.Type | null
|
|
358
|
+
"export var stringType: reflect.Type | null",
|
|
359
359
|
"export function __goscript_get_stringType(): reflect.Type | null",
|
|
360
360
|
"stringType = reflect.TypeFor",
|
|
361
361
|
} {
|
|
@@ -550,6 +550,204 @@ func TestCompilePackagesAliasesForInitShortDeclShadow(t *testing.T) {
|
|
|
550
550
|
}
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
+
func TestCompilePackagesDoesNotAliasPackageShadowWithoutRead(t *testing.T) {
|
|
554
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
555
|
+
"go.mod": "module example.test/packageshadow\n\ngo 1.25.3\n",
|
|
556
|
+
"main.go": strings.Join([]string{
|
|
557
|
+
"package main",
|
|
558
|
+
"var value = 1",
|
|
559
|
+
"func main() {",
|
|
560
|
+
" value := 2",
|
|
561
|
+
" var other = 3",
|
|
562
|
+
" println(value, other)",
|
|
563
|
+
"}",
|
|
564
|
+
"",
|
|
565
|
+
}, "\n"),
|
|
566
|
+
})
|
|
567
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
568
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
569
|
+
if err != nil {
|
|
570
|
+
t.Fatal(err.Error())
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
574
|
+
t.Fatal(err.Error())
|
|
575
|
+
}
|
|
576
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "packageshadow", "main.gs.ts"))
|
|
577
|
+
if err != nil {
|
|
578
|
+
t.Fatal(err.Error())
|
|
579
|
+
}
|
|
580
|
+
text := string(content)
|
|
581
|
+
if !strings.Contains(text, "let value = 2") {
|
|
582
|
+
t.Fatalf("local package shadow was not emitted with its source name:\n%s", text)
|
|
583
|
+
}
|
|
584
|
+
if strings.Contains(text, "__goscriptShadow") {
|
|
585
|
+
t.Fatalf("package shadow without initializer read should not allocate a shadow alias:\n%s", text)
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
func TestCompilePackagesAliasesPackageShadowInitializerReads(t *testing.T) {
|
|
590
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
591
|
+
"go.mod": "module example.test/packageshadowread\n\ngo 1.25.3\n",
|
|
592
|
+
"main.go": strings.Join([]string{
|
|
593
|
+
"package main",
|
|
594
|
+
"var value = 1",
|
|
595
|
+
"func helper() int { return 4 }",
|
|
596
|
+
"func main() {",
|
|
597
|
+
" println(helper())",
|
|
598
|
+
" helper := 5",
|
|
599
|
+
" println(helper)",
|
|
600
|
+
" first := value",
|
|
601
|
+
" value := value + 1",
|
|
602
|
+
" {",
|
|
603
|
+
" var first = first + value",
|
|
604
|
+
" println(first)",
|
|
605
|
+
" }",
|
|
606
|
+
" println(value)",
|
|
607
|
+
"}",
|
|
608
|
+
"",
|
|
609
|
+
}, "\n"),
|
|
610
|
+
})
|
|
611
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
612
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
613
|
+
if err != nil {
|
|
614
|
+
t.Fatal(err.Error())
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
618
|
+
t.Fatal(err.Error())
|
|
619
|
+
}
|
|
620
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "packageshadowread", "main.gs.ts"))
|
|
621
|
+
if err != nil {
|
|
622
|
+
t.Fatal(err.Error())
|
|
623
|
+
}
|
|
624
|
+
text := string(content)
|
|
625
|
+
if strings.Contains(text, "let value = value + 1") || strings.Contains(text, "let first: number = 0\n\t\tfirst = first + value") {
|
|
626
|
+
t.Fatalf("initializer read was emitted through a TDZ self-reference:\n%s", text)
|
|
627
|
+
}
|
|
628
|
+
if strings.Contains(text, "let helper = 5") {
|
|
629
|
+
t.Fatalf("same-file package function shadow was emitted with a TDZ-prone source name:\n%s", text)
|
|
630
|
+
}
|
|
631
|
+
if strings.Count(text, "__goscriptShadow") < 3 {
|
|
632
|
+
t.Fatalf("missing shadow aliases for initializer reads:\n%s", text)
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
func TestCompilePackagesLowersPackageConstBeforeLocalShadow(t *testing.T) {
|
|
637
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
638
|
+
"go.mod": "module example.test/constshadow\n\ngo 1.25.3\n",
|
|
639
|
+
"main.go": strings.Join([]string{
|
|
640
|
+
"package main",
|
|
641
|
+
"const headerLength = 4",
|
|
642
|
+
"func parse(buf []byte) int {",
|
|
643
|
+
" if len(buf) < headerLength {",
|
|
644
|
+
" return headerLength",
|
|
645
|
+
" }",
|
|
646
|
+
" n := len(buf)",
|
|
647
|
+
" headerLength := n",
|
|
648
|
+
" return headerLength",
|
|
649
|
+
"}",
|
|
650
|
+
"",
|
|
651
|
+
}, "\n"),
|
|
652
|
+
})
|
|
653
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
654
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
655
|
+
if err != nil {
|
|
656
|
+
t.Fatal(err.Error())
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
660
|
+
t.Fatal(err.Error())
|
|
661
|
+
}
|
|
662
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "constshadow", "main.gs.ts"))
|
|
663
|
+
if err != nil {
|
|
664
|
+
t.Fatal(err.Error())
|
|
665
|
+
}
|
|
666
|
+
text := string(content)
|
|
667
|
+
if strings.Contains(text, "$.len(buf) < headerLength") || strings.Contains(text, "return headerLength\n\t}") {
|
|
668
|
+
t.Fatalf("package const read was emitted through local TDZ shadow:\n%s", text)
|
|
669
|
+
}
|
|
670
|
+
if !strings.Contains(text, "$.len(buf) < 4") || !strings.Contains(text, "return 4") {
|
|
671
|
+
t.Fatalf("package const read was not lowered to a value before local shadow:\n%s", text)
|
|
672
|
+
}
|
|
673
|
+
if !strings.Contains(text, "let headerLength = n") {
|
|
674
|
+
t.Fatalf("local shadow was not preserved:\n%s", text)
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
func TestCompilePackagesPreservesNamedUint64InterfaceTypeInfo(t *testing.T) {
|
|
679
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
680
|
+
"go.mod": "module example.test/nameduint64\n\ngo 1.25.3\n",
|
|
681
|
+
"main.go": strings.Join([]string{
|
|
682
|
+
"package main",
|
|
683
|
+
"type Pol uint64",
|
|
684
|
+
"func (p Pol) String() string { return \"\" }",
|
|
685
|
+
"func box() any {",
|
|
686
|
+
" var p Pol",
|
|
687
|
+
" return &p",
|
|
688
|
+
"}",
|
|
689
|
+
"",
|
|
690
|
+
}, "\n"),
|
|
691
|
+
})
|
|
692
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
693
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
694
|
+
if err != nil {
|
|
695
|
+
t.Fatal(err.Error())
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
699
|
+
t.Fatal(err.Error())
|
|
700
|
+
}
|
|
701
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "nameduint64", "main.gs.ts"))
|
|
702
|
+
if err != nil {
|
|
703
|
+
t.Fatal(err.Error())
|
|
704
|
+
}
|
|
705
|
+
text := string(content)
|
|
706
|
+
want := `$.namedValueInterfaceValue<any>(p, "*main.Pol"`
|
|
707
|
+
if !strings.Contains(text, want) {
|
|
708
|
+
t.Fatalf("missing named interface box %q in generated output:\n%s", want, text)
|
|
709
|
+
}
|
|
710
|
+
want = `elemType: { kind: $.TypeKind.Basic, name: "uint64", typeName: "main.Pol" }`
|
|
711
|
+
if !strings.Contains(text, want) {
|
|
712
|
+
t.Fatalf("named uint64 pointer interface box lost type metadata:\n%s", text)
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
func TestCompilePackagesLowersWideIntegerConstantsForUint64Targets(t *testing.T) {
|
|
717
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
718
|
+
"go.mod": "module example.test/wideconst\n\ngo 1.25.3\n",
|
|
719
|
+
"main.go": strings.Join([]string{
|
|
720
|
+
"package main",
|
|
721
|
+
"type Pol uint64",
|
|
722
|
+
"func normalize(f Pol) Pol {",
|
|
723
|
+
" f &= Pol((1 << 54) - 1)",
|
|
724
|
+
" f |= (1 << 53) | 1",
|
|
725
|
+
" return f",
|
|
726
|
+
"}",
|
|
727
|
+
"",
|
|
728
|
+
}, "\n"),
|
|
729
|
+
})
|
|
730
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
731
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
732
|
+
if err != nil {
|
|
733
|
+
t.Fatal(err.Error())
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
737
|
+
t.Fatal(err.Error())
|
|
738
|
+
}
|
|
739
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "wideconst", "main.gs.ts"))
|
|
740
|
+
if err != nil {
|
|
741
|
+
t.Fatal(err.Error())
|
|
742
|
+
}
|
|
743
|
+
text := string(content)
|
|
744
|
+
for _, want := range []string{`$.uint("18014398509481983", 64)`, `$.uint("9007199254740993", 64)`} {
|
|
745
|
+
if !strings.Contains(text, want) {
|
|
746
|
+
t.Fatalf("missing wide integer constant %q in generated output:\n%s", want, text)
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
553
751
|
func TestCompilePackagesReadsShadowedVarRefStructFieldsOnce(t *testing.T) {
|
|
554
752
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
555
753
|
"go.mod": "module example.test/shadowvarreffield\n\ngo 1.25.3\n",
|
|
@@ -713,6 +911,49 @@ func TestCompilePackagesAnnotatesNewPointerShortDecls(t *testing.T) {
|
|
|
713
911
|
}
|
|
714
912
|
}
|
|
715
913
|
|
|
914
|
+
func TestCompilePackagesAnnotatesNewArrayPointerShortDecls(t *testing.T) {
|
|
915
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
916
|
+
"go.mod": "module example.test/newarrayptrdecl\n\ngo 1.25.3\n",
|
|
917
|
+
"main.go": strings.Join([]string{
|
|
918
|
+
"package main",
|
|
919
|
+
"func use(*[32]byte) {}",
|
|
920
|
+
"func main() {",
|
|
921
|
+
" buf := new([32]byte)",
|
|
922
|
+
" use(buf)",
|
|
923
|
+
" if true {",
|
|
924
|
+
" buf = nil",
|
|
925
|
+
" }",
|
|
926
|
+
" use(buf)",
|
|
927
|
+
"}",
|
|
928
|
+
"",
|
|
929
|
+
}, "\n"),
|
|
930
|
+
})
|
|
931
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
932
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
933
|
+
if err != nil {
|
|
934
|
+
t.Fatal(err.Error())
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
938
|
+
t.Fatal(err.Error())
|
|
939
|
+
}
|
|
940
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "newarrayptrdecl", "main.gs.ts")
|
|
941
|
+
content, err := os.ReadFile(outputFile)
|
|
942
|
+
if err != nil {
|
|
943
|
+
t.Fatal(err.Error())
|
|
944
|
+
}
|
|
945
|
+
text := string(content)
|
|
946
|
+
for _, want := range []string{
|
|
947
|
+
"let buf: $.VarRef<Uint8Array> | null = $.varRef<Uint8Array>(new Uint8Array(32))",
|
|
948
|
+
"buf = null",
|
|
949
|
+
"use(buf)",
|
|
950
|
+
} {
|
|
951
|
+
if !strings.Contains(text, want) {
|
|
952
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
716
957
|
func TestCompilePackagesEmitsShadowedBuiltinCalls(t *testing.T) {
|
|
717
958
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
718
959
|
"go.mod": "module example.test/shadowbuiltin\n\ngo 1.25.3\n",
|
|
@@ -864,6 +1105,47 @@ func TestCompilePackagesUsesEmbedOverride(t *testing.T) {
|
|
|
864
1105
|
}
|
|
865
1106
|
}
|
|
866
1107
|
|
|
1108
|
+
func TestCompilePackagesEmbedsFS(t *testing.T) {
|
|
1109
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1110
|
+
"go.mod": "module example.test/embedfs\n\ngo 1.25.3\n",
|
|
1111
|
+
"assets/config.json": `{"ok":true}`,
|
|
1112
|
+
"assets/nested.txt": "nested",
|
|
1113
|
+
"extra.txt": "extra",
|
|
1114
|
+
"main.go": strings.Join([]string{
|
|
1115
|
+
"package embedfs",
|
|
1116
|
+
"import \"embed\"",
|
|
1117
|
+
"//go:embed assets *.txt",
|
|
1118
|
+
"var StaticFS embed.FS",
|
|
1119
|
+
"",
|
|
1120
|
+
}, "\n"),
|
|
1121
|
+
})
|
|
1122
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1123
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir, AllDependencies: true}, nil, nil)
|
|
1124
|
+
if err != nil {
|
|
1125
|
+
t.Fatal(err.Error())
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1129
|
+
t.Fatal(err.Error())
|
|
1130
|
+
}
|
|
1131
|
+
content, err := os.ReadFile(filepath.Join(outputDir, "@goscript", "example.test", "embedfs", "main.gs.ts"))
|
|
1132
|
+
if err != nil {
|
|
1133
|
+
t.Fatal(err.Error())
|
|
1134
|
+
}
|
|
1135
|
+
if !strings.Contains(string(content), `export let StaticFS: embed.FS = $.markAsStructValue(new embed.FS`) {
|
|
1136
|
+
t.Fatalf("embedded FS was not emitted as embed.FS:\n%s", string(content))
|
|
1137
|
+
}
|
|
1138
|
+
if !strings.Contains(string(content), `["assets/config.json", new Uint8Array([123, 34, 111, 107, 34, 58, 116, 114, 117, 101, 125])]`) {
|
|
1139
|
+
t.Fatalf("embedded FS file content was not emitted:\n%s", string(content))
|
|
1140
|
+
}
|
|
1141
|
+
if !strings.Contains(string(content), `["assets/nested.txt", new Uint8Array([110, 101, 115, 116, 101, 100])]`) {
|
|
1142
|
+
t.Fatalf("embedded FS directory file content was not emitted:\n%s", string(content))
|
|
1143
|
+
}
|
|
1144
|
+
if !strings.Contains(string(content), `["extra.txt", new Uint8Array([101, 120, 116, 114, 97])]`) {
|
|
1145
|
+
t.Fatalf("embedded FS glob file content was not emitted:\n%s", string(content))
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
|
|
867
1149
|
func TestCompilePackagesEmitsPackageLocalImport(t *testing.T) {
|
|
868
1150
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
869
1151
|
"go.mod": "module example.test/imports\n\ngo 1.25.3\n",
|
|
@@ -950,6 +1232,51 @@ func TestCompilePackagesEmitsPackageLocalImport(t *testing.T) {
|
|
|
950
1232
|
}
|
|
951
1233
|
}
|
|
952
1234
|
|
|
1235
|
+
func TestCompilePackagesCallsCrossPackageUnexportedReceiverDynamically(t *testing.T) {
|
|
1236
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1237
|
+
"go.mod": "module example.test/unexportedreceiver\n\ngo 1.25.3\n",
|
|
1238
|
+
"dep/dep.go": strings.Join([]string{
|
|
1239
|
+
"package dep",
|
|
1240
|
+
"type hidden struct{}",
|
|
1241
|
+
"func NewHidden() *hidden { return &hidden{} }",
|
|
1242
|
+
"func (h *hidden) Value() int { return 7 }",
|
|
1243
|
+
"",
|
|
1244
|
+
}, "\n"),
|
|
1245
|
+
"main.go": strings.Join([]string{
|
|
1246
|
+
"package main",
|
|
1247
|
+
"import \"example.test/unexportedreceiver/dep\"",
|
|
1248
|
+
"func main() {",
|
|
1249
|
+
" h := dep.NewHidden()",
|
|
1250
|
+
" println(h.Value())",
|
|
1251
|
+
"}",
|
|
1252
|
+
"",
|
|
1253
|
+
}, "\n"),
|
|
1254
|
+
})
|
|
1255
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
1256
|
+
comp, err := NewCompiler(&Config{
|
|
1257
|
+
Dir: moduleDir,
|
|
1258
|
+
OutputPath: outputDir,
|
|
1259
|
+
AllDependencies: true,
|
|
1260
|
+
}, nil, nil)
|
|
1261
|
+
if err != nil {
|
|
1262
|
+
t.Fatal(err.Error())
|
|
1263
|
+
}
|
|
1264
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
1265
|
+
t.Fatal(err.Error())
|
|
1266
|
+
}
|
|
1267
|
+
mainFile := filepath.Join(outputDir, "@goscript", "example.test", "unexportedreceiver", "main.gs.ts")
|
|
1268
|
+
mainContent, err := os.ReadFile(mainFile)
|
|
1269
|
+
if err != nil {
|
|
1270
|
+
t.Fatal(err.Error())
|
|
1271
|
+
}
|
|
1272
|
+
if !strings.Contains(string(mainContent), "$.pointerValue<any>(h).Value()") {
|
|
1273
|
+
t.Fatalf("cross-package unexported receiver method call was not dynamic:\n%s", string(mainContent))
|
|
1274
|
+
}
|
|
1275
|
+
if strings.Contains(string(mainContent), "dep.hidden.prototype.Value.call") {
|
|
1276
|
+
t.Fatalf("cross-package unexported receiver leaked through imported prototype:\n%s", string(mainContent))
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
|
|
953
1280
|
func TestCompilePackagesEmitsTypeOnlyLocalImports(t *testing.T) {
|
|
954
1281
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
955
1282
|
"go.mod": "module example.test/typeonlylocal\n\ngo 1.25.3\n",
|
|
@@ -1232,8 +1559,8 @@ func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
|
|
|
1232
1559
|
"Counter.prototype.Set.call(pointer, 2)",
|
|
1233
1560
|
"Counter.prototype.Set.call(NewCounter(), 5)",
|
|
1234
1561
|
"let [, ok] = $.typeAssertTuple<Counter | $.VarRef<Counter> | null>(iface, { kind: $.TypeKind.Pointer, elemType: \"main.Counter\" })",
|
|
1235
|
-
"\"Value\":
|
|
1236
|
-
"\"ID\": { kind: $.TypeKind.Basic, name: \"
|
|
1562
|
+
"{ name: \"Value\", key: \"Value\", type: { kind: $.TypeKind.Basic, name: \"int\" }, tag: \"json:\\\"value\\\"\", index: [0], offset: 0, exported: true }",
|
|
1563
|
+
"{ name: \"ID\", key: \"ID\", type: { kind: $.TypeKind.Basic, name: \"int32\", typeName: \"main.ObjectID\" }, index: [1], offset: 8, exported: true }",
|
|
1237
1564
|
} {
|
|
1238
1565
|
if !strings.Contains(text, want) {
|
|
1239
1566
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -1963,6 +2290,51 @@ func TestCompilePackagesLowersStringOrderingThroughRuntime(t *testing.T) {
|
|
|
1963
2290
|
}
|
|
1964
2291
|
}
|
|
1965
2292
|
|
|
2293
|
+
func TestCompilePackagesConvertsOverrideNamedStringToString(t *testing.T) {
|
|
2294
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2295
|
+
"go.mod": "module example.test/reflecttag\n\ngo 1.25.3\n",
|
|
2296
|
+
"main.go": strings.Join([]string{
|
|
2297
|
+
"package main",
|
|
2298
|
+
"import (",
|
|
2299
|
+
" \"reflect\"",
|
|
2300
|
+
" \"strings\"",
|
|
2301
|
+
")",
|
|
2302
|
+
"func tagText(st reflect.Type) string {",
|
|
2303
|
+
" field := st.Field(0)",
|
|
2304
|
+
" tag := field.Tag.Get(\"yaml\")",
|
|
2305
|
+
" if tag == \"\" && strings.Index(string(field.Tag), \":\") < 0 {",
|
|
2306
|
+
" tag = string(field.Tag)",
|
|
2307
|
+
" }",
|
|
2308
|
+
" return tag",
|
|
2309
|
+
"}",
|
|
2310
|
+
"",
|
|
2311
|
+
}, "\n"),
|
|
2312
|
+
})
|
|
2313
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2314
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2315
|
+
if err != nil {
|
|
2316
|
+
t.Fatal(err.Error())
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2320
|
+
t.Fatal(err.Error())
|
|
2321
|
+
}
|
|
2322
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "reflecttag", "main.gs.ts")
|
|
2323
|
+
content, err := os.ReadFile(outputFile)
|
|
2324
|
+
if err != nil {
|
|
2325
|
+
t.Fatal(err.Error())
|
|
2326
|
+
}
|
|
2327
|
+
text := string(content)
|
|
2328
|
+
for _, want := range []string{
|
|
2329
|
+
`strings.Index(String(field.Tag), ":")`,
|
|
2330
|
+
`tag = String(field.Tag)`,
|
|
2331
|
+
} {
|
|
2332
|
+
if !strings.Contains(text, want) {
|
|
2333
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
|
|
1966
2338
|
func TestCompilePackagesEmitsInterfacesMethodValuesTypeSwitchesAndFunctionAssertions(t *testing.T) {
|
|
1967
2339
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
1968
2340
|
"go.mod": "module example.test/interfaces\n\ngo 1.25.3\n",
|
|
@@ -2017,9 +2389,11 @@ func TestCompilePackagesEmitsInterfacesMethodValuesTypeSwitchesAndFunctionAssert
|
|
|
2017
2389
|
"Close(): string",
|
|
2018
2390
|
"$.registerInterfaceType(\n\t\"main.ReadCloser\"",
|
|
2019
2391
|
"((__receiver) => () => __receiver.Inc())($.pointerValue<Counter>(counter))",
|
|
2020
|
-
"$.namedFunction(greet, \"main.Greeter\"
|
|
2392
|
+
"$.namedFunction(greet, \"main.Greeter\", ({ kind: $.TypeKind.Function, name: \"main.Greeter\"",
|
|
2393
|
+
"params: [{ kind: $.TypeKind.Basic, name: \"string\" }]",
|
|
2394
|
+
"results: [{ kind: $.TypeKind.Basic, name: \"string\" }]",
|
|
2021
2395
|
"$.interfaceValue<any>(null, \"*struct{Name string}\")",
|
|
2022
|
-
"elemType: { kind: $.TypeKind.Struct, methods: [], fields: {\"Name\": { kind: $.TypeKind.Basic, name: \"string\" }
|
|
2396
|
+
"elemType: { kind: $.TypeKind.Struct, methods: [], fields: [{ name: \"Name\", key: \"Name\", type: { kind: $.TypeKind.Basic, name: \"string\" }",
|
|
2023
2397
|
"let fn = __goscriptTuple",
|
|
2024
2398
|
"switch (true)",
|
|
2025
2399
|
"case $.typeAssert<Exclude<ReadCloser, null>>(__goscriptTypeSwitchValue, \"main.ReadCloser\").ok",
|
|
@@ -2283,9 +2657,9 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
|
|
|
2283
2657
|
"$.mapSet(seen, 1, {})",
|
|
2284
2658
|
"$.genericZero(__typeArgs, \"T\", null)",
|
|
2285
2659
|
"$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
|
|
2286
|
-
"ZeroValue({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)} }})",
|
|
2287
|
-
"CallString({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)} }}, zero)",
|
|
2288
|
-
"Sum({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)} }}, null)",
|
|
2660
|
+
"ZeroValue({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }})",
|
|
2661
|
+
"CallString({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, zero)",
|
|
2662
|
+
"Sum({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, null)",
|
|
2289
2663
|
} {
|
|
2290
2664
|
if !strings.Contains(text, want) {
|
|
2291
2665
|
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
@@ -2293,21 +2667,80 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
|
|
|
2293
2667
|
}
|
|
2294
2668
|
}
|
|
2295
2669
|
|
|
2296
|
-
func
|
|
2670
|
+
func TestCompilePackagesInfersGenericTypeArgsFromNamedArgument(t *testing.T) {
|
|
2297
2671
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2298
|
-
"go.mod": "module example.test/
|
|
2672
|
+
"go.mod": "module example.test/genericnamedarg\n\ngo 1.25.3\n",
|
|
2299
2673
|
"main.go": strings.Join([]string{
|
|
2300
|
-
"package
|
|
2301
|
-
"type
|
|
2302
|
-
"
|
|
2674
|
+
"package genericnamedarg",
|
|
2675
|
+
"type Source interface { Load() int }",
|
|
2676
|
+
"type auto struct{}",
|
|
2677
|
+
"func (a *auto) Load() int { return 7 }",
|
|
2678
|
+
"type key[T any] struct { name string }",
|
|
2679
|
+
"type entry struct { factory any }",
|
|
2680
|
+
"var entries = map[string]*entry{}",
|
|
2681
|
+
"func NewKey[T any](name string) key[T] {",
|
|
2682
|
+
" entries[name] = &entry{}",
|
|
2683
|
+
" return key[T]{name: name}",
|
|
2684
|
+
"}",
|
|
2685
|
+
"func Register[T any](key key[T], factory func() T) {",
|
|
2686
|
+
" entries[key.name].factory = factory",
|
|
2687
|
+
"}",
|
|
2688
|
+
"func Get[T any](key key[T]) T {",
|
|
2689
|
+
" f := entries[key.name].factory",
|
|
2690
|
+
" return f.(func() T)()",
|
|
2691
|
+
"}",
|
|
2692
|
+
"var loader = NewKey[Source](\"source\")",
|
|
2693
|
+
"func Use() int {",
|
|
2694
|
+
" Register(loader, func() Source { return &auto{} })",
|
|
2695
|
+
" src := Get(loader)",
|
|
2696
|
+
" return src.Load()",
|
|
2697
|
+
"}",
|
|
2698
|
+
"",
|
|
2699
|
+
}, "\n"),
|
|
2700
|
+
})
|
|
2701
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2702
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2703
|
+
if err != nil {
|
|
2704
|
+
t.Fatal(err.Error())
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2708
|
+
t.Fatal(err.Error())
|
|
2709
|
+
}
|
|
2710
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "genericnamedarg", "main.gs.ts")
|
|
2711
|
+
content, err := os.ReadFile(outputFile)
|
|
2712
|
+
if err != nil {
|
|
2713
|
+
t.Fatal(err.Error())
|
|
2714
|
+
}
|
|
2715
|
+
text := string(content)
|
|
2716
|
+
for _, want := range []string{
|
|
2717
|
+
"await Get({T: { type: \"genericnamedarg.Source\", zero: () => null, methods: {Load: (receiver: any, ...args: any[]) => receiver.Load(...args)} }}, $.markAsStructValue($.cloneStructValue(loader)))",
|
|
2718
|
+
"return await $.mustTypeAssert<(() => any | globalThis.Promise<any>) | null>(f, ({ kind: $.TypeKind.Function, params: [], results: [{ kind: $.TypeKind.Interface, methods: [] }] } as $.FunctionTypeInfo))!()",
|
|
2719
|
+
"return $.pointerValue<Exclude<Source, null>>(src).Load()",
|
|
2720
|
+
} {
|
|
2721
|
+
if !strings.Contains(text, want) {
|
|
2722
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2727
|
+
func TestCompilePackagesAttachesFunctionLiteralTypeInfo(t *testing.T) {
|
|
2728
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2729
|
+
"go.mod": "module example.test/function-type-info\n\ngo 1.25.3\n",
|
|
2730
|
+
"main.go": strings.Join([]string{
|
|
2731
|
+
"package main",
|
|
2732
|
+
"type Callback func(value int) string",
|
|
2733
|
+
"func call(cb Callback) string {",
|
|
2303
2734
|
" return cb(1)",
|
|
2304
2735
|
"}",
|
|
2305
2736
|
"func main() {",
|
|
2306
2737
|
" fn := func(value int) string {",
|
|
2307
2738
|
" return \"\"",
|
|
2308
2739
|
" }",
|
|
2740
|
+
" var zero Callback",
|
|
2309
2741
|
" var cb Callback = nil",
|
|
2310
2742
|
" _ = fn",
|
|
2743
|
+
" _ = zero",
|
|
2311
2744
|
" _ = cb",
|
|
2312
2745
|
" _ = call(fn)",
|
|
2313
2746
|
"}",
|
|
@@ -2332,6 +2765,8 @@ func TestCompilePackagesAttachesFunctionLiteralTypeInfo(t *testing.T) {
|
|
|
2332
2765
|
for _, want := range []string{
|
|
2333
2766
|
"export type Callback = ((value: number) => string | globalThis.Promise<string>) | null",
|
|
2334
2767
|
"export async function call(cb: ((value: number) => string | globalThis.Promise<string>) | null): globalThis.Promise<string> {\n\treturn await cb!(1)",
|
|
2768
|
+
"let zero: Callback | null = null as unknown as Callback | null",
|
|
2769
|
+
"let cb: Callback | null = (null as Callback | null)",
|
|
2335
2770
|
"$.functionValue((value: number): string => {",
|
|
2336
2771
|
"kind: $.TypeKind.Function",
|
|
2337
2772
|
"params: [{ kind: $.TypeKind.Basic, name: \"int\" }]",
|
|
@@ -2371,7 +2806,7 @@ func TestCompilePackagesEmitsRecursiveFunctionTypeInfo(t *testing.T) {
|
|
|
2371
2806
|
text := string(content)
|
|
2372
2807
|
for _, want := range []string{
|
|
2373
2808
|
"export type Handler = ((_p0: ((_p0: Handler | null) => Handler | null | globalThis.Promise<Handler | null>) | null) => Handler | null | globalThis.Promise<Handler | null>) | null",
|
|
2374
|
-
"\"Next\": ({ kind: $.TypeKind.Function, name: \"main.Handler\"",
|
|
2809
|
+
"{ name: \"Next\", key: \"Next\", type: ({ kind: $.TypeKind.Function, name: \"main.Handler\"",
|
|
2375
2810
|
"params: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
2376
2811
|
"results: [{ kind: $.TypeKind.Function, params: [], results: [] }]",
|
|
2377
2812
|
} {
|
|
@@ -2494,6 +2929,88 @@ func TestCompilePackagesPacksVariadicCallsInGeneratedSubpackage(t *testing.T) {
|
|
|
2494
2929
|
}
|
|
2495
2930
|
}
|
|
2496
2931
|
|
|
2932
|
+
func TestCompilePackagesBoxesNumericVariadicInterfaceArgs(t *testing.T) {
|
|
2933
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2934
|
+
"go.mod": "module example.test/numeric-interface\n\ngo 1.25.3\n",
|
|
2935
|
+
"main.go": strings.Join([]string{
|
|
2936
|
+
"package numericinterface",
|
|
2937
|
+
"func collect(values ...any) {}",
|
|
2938
|
+
"func main() {",
|
|
2939
|
+
" var version int32 = 2",
|
|
2940
|
+
" collect(version, uint32(3))",
|
|
2941
|
+
"}",
|
|
2942
|
+
"",
|
|
2943
|
+
}, "\n"),
|
|
2944
|
+
})
|
|
2945
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2946
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2947
|
+
if err != nil {
|
|
2948
|
+
t.Fatal(err.Error())
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2952
|
+
t.Fatal(err.Error())
|
|
2953
|
+
}
|
|
2954
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "numeric-interface", "main.gs.ts")
|
|
2955
|
+
content, err := os.ReadFile(outputFile)
|
|
2956
|
+
if err != nil {
|
|
2957
|
+
t.Fatal(err.Error())
|
|
2958
|
+
}
|
|
2959
|
+
text := string(content)
|
|
2960
|
+
for _, want := range []string{
|
|
2961
|
+
"$.namedValueInterfaceValue<any>(version, \"int32\", {}, { kind: $.TypeKind.Basic, name: \"int32\" })",
|
|
2962
|
+
"$.namedValueInterfaceValue<any>($.uint(3, 32), \"uint32\", {}, { kind: $.TypeKind.Basic, name: \"uint32\" })",
|
|
2963
|
+
} {
|
|
2964
|
+
if !strings.Contains(text, want) {
|
|
2965
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
func TestCompilePackagesAwaitsFmtWriterOverrides(t *testing.T) {
|
|
2971
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2972
|
+
"go.mod": "module example.test/fmt-writer\n\ngo 1.25.3\n",
|
|
2973
|
+
"main.go": strings.Join([]string{
|
|
2974
|
+
"package fmtwriter",
|
|
2975
|
+
"import \"fmt\"",
|
|
2976
|
+
"type writer struct { buf []byte }",
|
|
2977
|
+
"func (w *writer) Write(p []byte) (int, error) {",
|
|
2978
|
+
" w.buf = append(w.buf, p...)",
|
|
2979
|
+
" return len(p), nil",
|
|
2980
|
+
"}",
|
|
2981
|
+
"func Use(w *writer) error {",
|
|
2982
|
+
" _, err := fmt.Fprintf(w, \"%s\", \"ok\")",
|
|
2983
|
+
" return err",
|
|
2984
|
+
"}",
|
|
2985
|
+
"",
|
|
2986
|
+
}, "\n"),
|
|
2987
|
+
})
|
|
2988
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
2989
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
2990
|
+
if err != nil {
|
|
2991
|
+
t.Fatal(err.Error())
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
2995
|
+
t.Fatal(err.Error())
|
|
2996
|
+
}
|
|
2997
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "fmt-writer", "main.gs.ts")
|
|
2998
|
+
content, err := os.ReadFile(outputFile)
|
|
2999
|
+
if err != nil {
|
|
3000
|
+
t.Fatal(err.Error())
|
|
3001
|
+
}
|
|
3002
|
+
text := string(content)
|
|
3003
|
+
for _, want := range []string{
|
|
3004
|
+
"export async function Use",
|
|
3005
|
+
"await fmt.Fprintf(",
|
|
3006
|
+
"return err",
|
|
3007
|
+
} {
|
|
3008
|
+
if !strings.Contains(text, want) {
|
|
3009
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
|
|
2497
3014
|
func TestCompilePackagesImportsSelectedExternalFieldTypes(t *testing.T) {
|
|
2498
3015
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2499
3016
|
"go.mod": "module example.test/selected-field-import\n\ngo 1.25.3\n",
|
|
@@ -2887,6 +3404,468 @@ func TestCompilePackagesEmitsAsyncChannelsSelectAndDefer(t *testing.T) {
|
|
|
2887
3404
|
}
|
|
2888
3405
|
}
|
|
2889
3406
|
|
|
3407
|
+
func TestCompilePackagesPropagatesAsyncGenericInterfaceMethods(t *testing.T) {
|
|
3408
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3409
|
+
"go.mod": "module example.test/genericasynciface\n\ngo 1.25.3\n",
|
|
3410
|
+
"main.go": strings.Join([]string{
|
|
3411
|
+
"package genericasynciface",
|
|
3412
|
+
"import \"context\"",
|
|
3413
|
+
"type Watchable[T comparable] interface {",
|
|
3414
|
+
" Get() T",
|
|
3415
|
+
" Wait(ctx context.Context, old T) T",
|
|
3416
|
+
"}",
|
|
3417
|
+
"type Box[T comparable] struct { ch chan T; val T }",
|
|
3418
|
+
"func (b *Box[T]) Get() T { return b.val }",
|
|
3419
|
+
"func (b *Box[T]) Wait(ctx context.Context, old T) T {",
|
|
3420
|
+
" select {",
|
|
3421
|
+
" case v := <-b.ch:",
|
|
3422
|
+
" return v",
|
|
3423
|
+
" case <-ctx.Done():",
|
|
3424
|
+
" return old",
|
|
3425
|
+
" }",
|
|
3426
|
+
"}",
|
|
3427
|
+
"func Use(ctx context.Context, w Watchable[int], old int) int {",
|
|
3428
|
+
" return w.Wait(ctx, old)",
|
|
3429
|
+
"}",
|
|
3430
|
+
"",
|
|
3431
|
+
}, "\n"),
|
|
3432
|
+
})
|
|
3433
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3434
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3435
|
+
if err != nil {
|
|
3436
|
+
t.Fatal(err.Error())
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3440
|
+
t.Fatal(err.Error())
|
|
3441
|
+
}
|
|
3442
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "genericasynciface", "main.gs.ts")
|
|
3443
|
+
content, err := os.ReadFile(outputFile)
|
|
3444
|
+
if err != nil {
|
|
3445
|
+
t.Fatal(err.Error())
|
|
3446
|
+
}
|
|
3447
|
+
text := string(content)
|
|
3448
|
+
for _, want := range []string{
|
|
3449
|
+
"Wait(ctx: context.Context | null, old: any): any | globalThis.Promise<any>",
|
|
3450
|
+
"public async Wait(ctx: context.Context | null, old: any): globalThis.Promise<any>",
|
|
3451
|
+
"return (await $.pointerValue<Exclude<Watchable, null>>(w).Wait(ctx, old) as number)",
|
|
3452
|
+
} {
|
|
3453
|
+
if !strings.Contains(text, want) {
|
|
3454
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
func TestCompilePackagesPropagatesAsyncAnonymousInterfaceMethods(t *testing.T) {
|
|
3460
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3461
|
+
"go.mod": "module example.test/anonymousasynciface\n\ngo 1.25.3\n",
|
|
3462
|
+
"main.go": strings.Join([]string{
|
|
3463
|
+
"package anonymousasynciface",
|
|
3464
|
+
"import \"context\"",
|
|
3465
|
+
"type Snapshot int",
|
|
3466
|
+
"type Watcher struct { ch chan Snapshot }",
|
|
3467
|
+
"func (w *Watcher) WaitValueChange(ctx context.Context, old Snapshot, errCh <-chan error) (Snapshot, error) {",
|
|
3468
|
+
" select {",
|
|
3469
|
+
" case v := <-w.ch:",
|
|
3470
|
+
" return v, nil",
|
|
3471
|
+
" case err := <-errCh:",
|
|
3472
|
+
" return old, err",
|
|
3473
|
+
" case <-ctx.Done():",
|
|
3474
|
+
" return old, ctx.Err()",
|
|
3475
|
+
" }",
|
|
3476
|
+
"}",
|
|
3477
|
+
"func Use(ctx context.Context, w interface {",
|
|
3478
|
+
" WaitValueChange(context.Context, Snapshot, <-chan error) (Snapshot, error)",
|
|
3479
|
+
"}, old Snapshot) (Snapshot, error) {",
|
|
3480
|
+
" return w.WaitValueChange(ctx, old, nil)",
|
|
3481
|
+
"}",
|
|
3482
|
+
"",
|
|
3483
|
+
}, "\n"),
|
|
3484
|
+
})
|
|
3485
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3486
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3487
|
+
if err != nil {
|
|
3488
|
+
t.Fatal(err.Error())
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3491
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3492
|
+
t.Fatal(err.Error())
|
|
3493
|
+
}
|
|
3494
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "anonymousasynciface", "main.gs.ts")
|
|
3495
|
+
content, err := os.ReadFile(outputFile)
|
|
3496
|
+
if err != nil {
|
|
3497
|
+
t.Fatal(err.Error())
|
|
3498
|
+
}
|
|
3499
|
+
text := string(content)
|
|
3500
|
+
for _, want := range []string{
|
|
3501
|
+
"export async function Use(ctx: context.Context | null, w: any, old: Snapshot): globalThis.Promise<[Snapshot, $.GoError]>",
|
|
3502
|
+
"return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)",
|
|
3503
|
+
} {
|
|
3504
|
+
if !strings.Contains(text, want) {
|
|
3505
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
|
|
3510
|
+
func TestCompilePackagesPropagatesAsyncThroughInstantiatedNamedInterface(t *testing.T) {
|
|
3511
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3512
|
+
"go.mod": "module example.test/instantiatedasynciface\n\ngo 1.25.3\n",
|
|
3513
|
+
"main.go": strings.Join([]string{
|
|
3514
|
+
"package instantiatedasynciface",
|
|
3515
|
+
"import \"context\"",
|
|
3516
|
+
"type Snapshot int",
|
|
3517
|
+
"type Watchable[T any] interface {",
|
|
3518
|
+
" WaitValueChange(context.Context, T, <-chan error) (T, error)",
|
|
3519
|
+
"}",
|
|
3520
|
+
"type Container[T any] struct { ch chan T }",
|
|
3521
|
+
"func (c *Container[T]) WaitValueChange(ctx context.Context, old T, errCh <-chan error) (T, error) {",
|
|
3522
|
+
" select {",
|
|
3523
|
+
" case v := <-c.ch:",
|
|
3524
|
+
" return v, nil",
|
|
3525
|
+
" case err := <-errCh:",
|
|
3526
|
+
" return old, err",
|
|
3527
|
+
" case <-ctx.Done():",
|
|
3528
|
+
" return old, ctx.Err()",
|
|
3529
|
+
" }",
|
|
3530
|
+
"}",
|
|
3531
|
+
"func Bind(w Watchable[Snapshot]) {}",
|
|
3532
|
+
"func Use(ctx context.Context, w interface {",
|
|
3533
|
+
" WaitValueChange(context.Context, Snapshot, <-chan error) (Snapshot, error)",
|
|
3534
|
+
"}, old Snapshot) (Snapshot, error) {",
|
|
3535
|
+
" return w.WaitValueChange(ctx, old, nil)",
|
|
3536
|
+
"}",
|
|
3537
|
+
"",
|
|
3538
|
+
}, "\n"),
|
|
3539
|
+
})
|
|
3540
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3541
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3542
|
+
if err != nil {
|
|
3543
|
+
t.Fatal(err.Error())
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3546
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3547
|
+
t.Fatal(err.Error())
|
|
3548
|
+
}
|
|
3549
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "instantiatedasynciface", "main.gs.ts")
|
|
3550
|
+
content, err := os.ReadFile(outputFile)
|
|
3551
|
+
if err != nil {
|
|
3552
|
+
t.Fatal(err.Error())
|
|
3553
|
+
}
|
|
3554
|
+
text := string(content)
|
|
3555
|
+
for _, want := range []string{
|
|
3556
|
+
"export async function Use(ctx: context.Context | null, w: any, old: Snapshot): globalThis.Promise<[Snapshot, $.GoError]>",
|
|
3557
|
+
"return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)",
|
|
3558
|
+
} {
|
|
3559
|
+
if !strings.Contains(text, want) {
|
|
3560
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3561
|
+
}
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3565
|
+
func TestCompilePackagesDoesNotAwaitUnmarkedAnonymousInterfaceMethod(t *testing.T) {
|
|
3566
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3567
|
+
"go.mod": "module example.test/anonymousifaceawait\n\ngo 1.25.3\n",
|
|
3568
|
+
"main.go": strings.Join([]string{
|
|
3569
|
+
"package anonymousifaceawait",
|
|
3570
|
+
"import \"context\"",
|
|
3571
|
+
"type Snapshot int",
|
|
3572
|
+
"func Use(ctx context.Context, w interface {",
|
|
3573
|
+
" WaitValueChange(context.Context, Snapshot, <-chan error) (Snapshot, error)",
|
|
3574
|
+
"}, ch <-chan struct{}, old Snapshot) (Snapshot, error) {",
|
|
3575
|
+
" select {",
|
|
3576
|
+
" case <-ch:",
|
|
3577
|
+
" default:",
|
|
3578
|
+
" }",
|
|
3579
|
+
" return w.WaitValueChange(ctx, old, nil)",
|
|
3580
|
+
"}",
|
|
3581
|
+
"",
|
|
3582
|
+
}, "\n"),
|
|
3583
|
+
})
|
|
3584
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3585
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3586
|
+
if err != nil {
|
|
3587
|
+
t.Fatal(err.Error())
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3590
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3591
|
+
t.Fatal(err.Error())
|
|
3592
|
+
}
|
|
3593
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "anonymousifaceawait", "main.gs.ts")
|
|
3594
|
+
content, err := os.ReadFile(outputFile)
|
|
3595
|
+
if err != nil {
|
|
3596
|
+
t.Fatal(err.Error())
|
|
3597
|
+
}
|
|
3598
|
+
text := string(content)
|
|
3599
|
+
if strings.Contains(text, "return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)") {
|
|
3600
|
+
t.Fatalf("anonymous interface method call without an async implementation was awaited:\n%s", text)
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
|
|
3604
|
+
func TestCompilePackagesDoesNotInheritAsyncIntoSyncFunctionLiteral(t *testing.T) {
|
|
3605
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3606
|
+
"go.mod": "module example.test/syncfunclit\n\ngo 1.25.3\n",
|
|
3607
|
+
"main.go": strings.Join([]string{
|
|
3608
|
+
"package syncfunclit",
|
|
3609
|
+
"type Directive interface{ GetDirective() any }",
|
|
3610
|
+
"type Bridge struct{ keep func(Directive) (bool, error) }",
|
|
3611
|
+
"func NewBridge(keep func(Directive) (bool, error)) *Bridge { return &Bridge{keep: keep} }",
|
|
3612
|
+
"func Execute(ch <-chan struct{}) error {",
|
|
3613
|
+
" select {",
|
|
3614
|
+
" case <-ch:",
|
|
3615
|
+
" default:",
|
|
3616
|
+
" }",
|
|
3617
|
+
" _ = NewBridge(func(di Directive) (bool, error) {",
|
|
3618
|
+
" switch di.GetDirective().(type) {",
|
|
3619
|
+
" default:",
|
|
3620
|
+
" return true, nil",
|
|
3621
|
+
" }",
|
|
3622
|
+
" })",
|
|
3623
|
+
" return nil",
|
|
3624
|
+
"}",
|
|
3625
|
+
"",
|
|
3626
|
+
}, "\n"),
|
|
3627
|
+
})
|
|
3628
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3629
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3630
|
+
if err != nil {
|
|
3631
|
+
t.Fatal(err.Error())
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3635
|
+
t.Fatal(err.Error())
|
|
3636
|
+
}
|
|
3637
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "syncfunclit", "main.gs.ts")
|
|
3638
|
+
content, err := os.ReadFile(outputFile)
|
|
3639
|
+
if err != nil {
|
|
3640
|
+
t.Fatal(err.Error())
|
|
3641
|
+
}
|
|
3642
|
+
text := string(content)
|
|
3643
|
+
if strings.Contains(text, "await $.pointerValue<Exclude<Directive, null>>(di).GetDirective()") {
|
|
3644
|
+
t.Fatalf("sync function literal inherited async await:\n%s", text)
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
func TestCompilePackagesMarksRangeFuncAsyncWhenBodyAwaits(t *testing.T) {
|
|
3649
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3650
|
+
"go.mod": "module example.test/rangefuncawaitbody\n\ngo 1.25.3\n",
|
|
3651
|
+
"main.go": strings.Join([]string{
|
|
3652
|
+
"package rangefuncawaitbody",
|
|
3653
|
+
"type Item struct{}",
|
|
3654
|
+
"func (i *Item) Release(ch <-chan struct{}) {",
|
|
3655
|
+
" select {",
|
|
3656
|
+
" case <-ch:",
|
|
3657
|
+
" default:",
|
|
3658
|
+
" }",
|
|
3659
|
+
"}",
|
|
3660
|
+
"func Back(items []Item) func(func(int, Item) bool) {",
|
|
3661
|
+
" return func(yield func(int, Item) bool) {",
|
|
3662
|
+
" for i := len(items)-1; i >= 0; i-- {",
|
|
3663
|
+
" if !yield(i, items[i]) { return }",
|
|
3664
|
+
" }",
|
|
3665
|
+
" }",
|
|
3666
|
+
"}",
|
|
3667
|
+
"func Use(ch <-chan struct{}, items []Item) {",
|
|
3668
|
+
" defer func() {",
|
|
3669
|
+
" for _, v := range Back(items) {",
|
|
3670
|
+
" v.Release(ch)",
|
|
3671
|
+
" }",
|
|
3672
|
+
" }()",
|
|
3673
|
+
"}",
|
|
3674
|
+
"",
|
|
3675
|
+
}, "\n"),
|
|
3676
|
+
})
|
|
3677
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3678
|
+
comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
|
|
3679
|
+
if err != nil {
|
|
3680
|
+
t.Fatal(err.Error())
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3683
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
3684
|
+
t.Fatal(err.Error())
|
|
3685
|
+
}
|
|
3686
|
+
outputFile := filepath.Join(outputDir, "@goscript", "example.test", "rangefuncawaitbody", "main.gs.ts")
|
|
3687
|
+
content, err := os.ReadFile(outputFile)
|
|
3688
|
+
if err != nil {
|
|
3689
|
+
t.Fatal(err.Error())
|
|
3690
|
+
}
|
|
3691
|
+
text := string(content)
|
|
3692
|
+
for _, want := range []string{
|
|
3693
|
+
";await (async () => {",
|
|
3694
|
+
"await v.value.Release(ch)",
|
|
3695
|
+
} {
|
|
3696
|
+
if !strings.Contains(text, want) {
|
|
3697
|
+
t.Fatalf("missing %q in generated output:\n%s", want, text)
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
|
|
3702
|
+
func TestCompilePackagesPropagatesImportedAsyncGenericInterfaceMethods(t *testing.T) {
|
|
3703
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3704
|
+
"go.mod": "module example.test/importedgenericasynciface\n\ngo 1.25.3\n",
|
|
3705
|
+
"dep/dep.go": strings.Join([]string{
|
|
3706
|
+
"package dep",
|
|
3707
|
+
"import \"context\"",
|
|
3708
|
+
"type Watchable[T comparable] interface {",
|
|
3709
|
+
" Get() T",
|
|
3710
|
+
" Wait(ctx context.Context, old T) T",
|
|
3711
|
+
"}",
|
|
3712
|
+
"type Box[T comparable] struct { ch chan T; val T }",
|
|
3713
|
+
"func (b *Box[T]) Get() T { return b.val }",
|
|
3714
|
+
"func (b *Box[T]) Wait(ctx context.Context, old T) T {",
|
|
3715
|
+
" select {",
|
|
3716
|
+
" case v := <-b.ch:",
|
|
3717
|
+
" return v",
|
|
3718
|
+
" case <-ctx.Done():",
|
|
3719
|
+
" return old",
|
|
3720
|
+
" }",
|
|
3721
|
+
"}",
|
|
3722
|
+
"",
|
|
3723
|
+
}, "\n"),
|
|
3724
|
+
"main.go": strings.Join([]string{
|
|
3725
|
+
"package importedgenericasynciface",
|
|
3726
|
+
"import (",
|
|
3727
|
+
" \"context\"",
|
|
3728
|
+
" \"example.test/importedgenericasynciface/dep\"",
|
|
3729
|
+
")",
|
|
3730
|
+
"func Use(ctx context.Context, w dep.Watchable[int], old int) int {",
|
|
3731
|
+
" return w.Wait(ctx, old)",
|
|
3732
|
+
"}",
|
|
3733
|
+
"",
|
|
3734
|
+
}, "\n"),
|
|
3735
|
+
})
|
|
3736
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3737
|
+
service := NewCompileService()
|
|
3738
|
+
_, err := service.Compile(context.Background(), &CompileRequest{
|
|
3739
|
+
Patterns: []string{".", "./dep"},
|
|
3740
|
+
Dir: moduleDir,
|
|
3741
|
+
OutputPath: outputDir,
|
|
3742
|
+
DependencyMode: DependencyModeAll,
|
|
3743
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
3744
|
+
})
|
|
3745
|
+
if err != nil {
|
|
3746
|
+
t.Fatal(err.Error())
|
|
3747
|
+
}
|
|
3748
|
+
depOutputFile := filepath.Join(outputDir, "@goscript", "example.test", "importedgenericasynciface", "dep", "dep.gs.ts")
|
|
3749
|
+
depContent, err := os.ReadFile(depOutputFile)
|
|
3750
|
+
if err != nil {
|
|
3751
|
+
t.Fatal(err.Error())
|
|
3752
|
+
}
|
|
3753
|
+
depText := string(depContent)
|
|
3754
|
+
for _, want := range []string{
|
|
3755
|
+
"Wait(ctx: context.Context | null, old: any): any | globalThis.Promise<any>",
|
|
3756
|
+
"public async Wait(ctx: context.Context | null, old: any): globalThis.Promise<any>",
|
|
3757
|
+
} {
|
|
3758
|
+
if !strings.Contains(depText, want) {
|
|
3759
|
+
t.Fatalf("missing %q in generated dep output:\n%s", want, depText)
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3763
|
+
mainOutputFile := filepath.Join(outputDir, "@goscript", "example.test", "importedgenericasynciface", "main.gs.ts")
|
|
3764
|
+
mainContent, err := os.ReadFile(mainOutputFile)
|
|
3765
|
+
if err != nil {
|
|
3766
|
+
t.Fatal(err.Error())
|
|
3767
|
+
}
|
|
3768
|
+
mainText := string(mainContent)
|
|
3769
|
+
if want := "return (await $.pointerValue<Exclude<dep.Watchable, null>>(w).Wait(ctx, old) as number)"; !strings.Contains(mainText, want) {
|
|
3770
|
+
t.Fatalf("missing %q in generated main output:\n%s", want, mainText)
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3774
|
+
func TestCompilePackagesPropagatesAsyncInterfaceMethodsFromTestImports(t *testing.T) {
|
|
3775
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
3776
|
+
"go.mod": "module example.test/testimportasynciface\n\ngo 1.25.3\n",
|
|
3777
|
+
"iface/provider.go": strings.Join([]string{
|
|
3778
|
+
"package iface",
|
|
3779
|
+
"import \"context\"",
|
|
3780
|
+
"type Provider interface {",
|
|
3781
|
+
" Create(context.Context) (string, error)",
|
|
3782
|
+
"}",
|
|
3783
|
+
"",
|
|
3784
|
+
}, "\n"),
|
|
3785
|
+
"impl/provider.go": strings.Join([]string{
|
|
3786
|
+
"package impl",
|
|
3787
|
+
"import (",
|
|
3788
|
+
" \"context\"",
|
|
3789
|
+
" \"example.test/testimportasynciface/iface\"",
|
|
3790
|
+
")",
|
|
3791
|
+
"type Provider struct { ch chan string }",
|
|
3792
|
+
"func NewProvider() iface.Provider {",
|
|
3793
|
+
" return &Provider{ch: make(chan string, 1)}",
|
|
3794
|
+
"}",
|
|
3795
|
+
"func (p *Provider) Create(ctx context.Context) (string, error) {",
|
|
3796
|
+
" select {",
|
|
3797
|
+
" case p.ch <- \"ok\":",
|
|
3798
|
+
" case <-ctx.Done():",
|
|
3799
|
+
" return \"\", ctx.Err()",
|
|
3800
|
+
" }",
|
|
3801
|
+
" return <-p.ch, nil",
|
|
3802
|
+
"}",
|
|
3803
|
+
"",
|
|
3804
|
+
}, "\n"),
|
|
3805
|
+
"use.go": strings.Join([]string{
|
|
3806
|
+
"package testimportasynciface",
|
|
3807
|
+
"import (",
|
|
3808
|
+
" \"context\"",
|
|
3809
|
+
" \"example.test/testimportasynciface/iface\"",
|
|
3810
|
+
")",
|
|
3811
|
+
"func Use(ctx context.Context, p iface.Provider) (string, error) {",
|
|
3812
|
+
" return p.Create(ctx)",
|
|
3813
|
+
"}",
|
|
3814
|
+
"",
|
|
3815
|
+
}, "\n"),
|
|
3816
|
+
"use_test.go": strings.Join([]string{
|
|
3817
|
+
"package testimportasynciface",
|
|
3818
|
+
"import (",
|
|
3819
|
+
" \"context\"",
|
|
3820
|
+
" \"testing\"",
|
|
3821
|
+
" \"example.test/testimportasynciface/impl\"",
|
|
3822
|
+
")",
|
|
3823
|
+
"func TestUse(t *testing.T) {",
|
|
3824
|
+
" p := impl.NewProvider()",
|
|
3825
|
+
" got, err := p.Create(context.Background())",
|
|
3826
|
+
" if err != nil || got != \"ok\" {",
|
|
3827
|
+
" t.Fatal(got, err)",
|
|
3828
|
+
" }",
|
|
3829
|
+
"}",
|
|
3830
|
+
"",
|
|
3831
|
+
}, "\n"),
|
|
3832
|
+
})
|
|
3833
|
+
outputDir := filepath.Join(t.TempDir(), "output")
|
|
3834
|
+
service := NewCompileService()
|
|
3835
|
+
_, err := service.Compile(context.Background(), &CompileRequest{
|
|
3836
|
+
Patterns: []string{"."},
|
|
3837
|
+
Dir: moduleDir,
|
|
3838
|
+
OutputPath: outputDir,
|
|
3839
|
+
DependencyMode: DependencyModeAll,
|
|
3840
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
3841
|
+
Tests: true,
|
|
3842
|
+
AllDependencies: true,
|
|
3843
|
+
})
|
|
3844
|
+
if err != nil {
|
|
3845
|
+
t.Fatal(err.Error())
|
|
3846
|
+
}
|
|
3847
|
+
|
|
3848
|
+
ifaceOutputFile := filepath.Join(outputDir, "@goscript", "example.test", "testimportasynciface", "iface", "provider.gs.ts")
|
|
3849
|
+
ifaceContent, err := os.ReadFile(ifaceOutputFile)
|
|
3850
|
+
if err != nil {
|
|
3851
|
+
t.Fatal(err.Error())
|
|
3852
|
+
}
|
|
3853
|
+
ifaceText := string(ifaceContent)
|
|
3854
|
+
if want := "Create(_p0: context.Context | null): [string, $.GoError] | globalThis.Promise<[string, $.GoError]>"; !strings.Contains(ifaceText, want) {
|
|
3855
|
+
t.Fatalf("test-import implementation did not color interface method async:\n%s", ifaceText)
|
|
3856
|
+
}
|
|
3857
|
+
|
|
3858
|
+
testOutputFile := filepath.Join(outputDir, "@goscript", "example.test", "testimportasynciface", "use_test.gs.ts")
|
|
3859
|
+
testContent, err := os.ReadFile(testOutputFile)
|
|
3860
|
+
if err != nil {
|
|
3861
|
+
t.Fatal(err.Error())
|
|
3862
|
+
}
|
|
3863
|
+
testText := string(testContent)
|
|
3864
|
+
if want := "let [got, err] = await $.pointerValue<Exclude<iface.Provider, null>>(p).Create(context.Background())"; !strings.Contains(testText, want) {
|
|
3865
|
+
t.Fatalf("test package call was not awaited:\n%s", testText)
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
|
|
2890
3869
|
func TestCompilePackagesMarksSelectReturningIfElseCasesUnreachable(t *testing.T) {
|
|
2891
3870
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
2892
3871
|
"go.mod": "module example.test/select-if-else\n\ngo 1.25.3\n",
|
|
@@ -3193,6 +4172,12 @@ func TestCompilePackagesLowersSwitchesAndFunctionValueCalls(t *testing.T) {
|
|
|
3193
4172
|
" if value > 0 {",
|
|
3194
4173
|
" goto Again",
|
|
3195
4174
|
" }",
|
|
4175
|
+
"Drive:",
|
|
4176
|
+
" window := value + 1",
|
|
4177
|
+
" if window < 0 {",
|
|
4178
|
+
" goto Drive",
|
|
4179
|
+
" }",
|
|
4180
|
+
" println(window)",
|
|
3196
4181
|
" release := func() { println(\"release\") }",
|
|
3197
4182
|
" rel := &release",
|
|
3198
4183
|
" (*rel)()",
|
|
@@ -3229,6 +4214,9 @@ func TestCompilePackagesLowersSwitchesAndFunctionValueCalls(t *testing.T) {
|
|
|
3229
4214
|
"break Block",
|
|
3230
4215
|
"Again: while (true)",
|
|
3231
4216
|
"continue Again",
|
|
4217
|
+
"Drive: while (true)",
|
|
4218
|
+
"var window = value + 1",
|
|
4219
|
+
"$.println(window)",
|
|
3232
4220
|
"($.pointerValue<(() => void) | null>(rel))!()",
|
|
3233
4221
|
"$.functionValue((): void => {\n\t\tusing __defer = new $.DisposableStack()",
|
|
3234
4222
|
"__defer.defer(() => { $.println(\"wrapped deferred\") })",
|
|
@@ -3389,7 +4377,7 @@ func TestCompilePackagesLowersUnaryBitwiseComplement(t *testing.T) {
|
|
|
3389
4377
|
}
|
|
3390
4378
|
text := string(content)
|
|
3391
4379
|
for _, want := range []string{
|
|
3392
|
-
"mask = mask & ~(3)",
|
|
4380
|
+
"mask = mask & ~((3))",
|
|
3393
4381
|
"$.println(~value, value & ~(3), mask, 0o700)",
|
|
3394
4382
|
} {
|
|
3395
4383
|
if !strings.Contains(text, want) {
|