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.
Files changed (330) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +35 -8
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript/cmd_compile_test.go +105 -6
  8. package/compiler/build-flags.go +9 -10
  9. package/compiler/compile-request.go +12 -9
  10. package/compiler/compliance_test.go +0 -1
  11. package/compiler/config.go +2 -0
  12. package/compiler/gotest/request.go +28 -0
  13. package/compiler/gotest/runner.go +353 -27
  14. package/compiler/gotest/runner_test.go +400 -1
  15. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  16. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  17. package/compiler/lowered-program.go +24 -17
  18. package/compiler/lowering.go +988 -263
  19. package/compiler/lowering_bench_test.go +364 -0
  20. package/compiler/override-facts.go +15 -0
  21. package/compiler/override-parity-verifier.go +450 -0
  22. package/compiler/override-parity.go +122 -0
  23. package/compiler/override-registry_test.go +559 -0
  24. package/compiler/package-graph.go +61 -4
  25. package/compiler/package-graph_test.go +30 -0
  26. package/compiler/protobuf-ts-binding.go +514 -0
  27. package/compiler/protobuf-ts-binding_test.go +172 -0
  28. package/compiler/semantic-model-types.go +17 -4
  29. package/compiler/semantic-model.go +709 -72
  30. package/compiler/semantic-model_test.go +219 -0
  31. package/compiler/service.go +20 -1
  32. package/compiler/skeleton_test.go +1008 -20
  33. package/compiler/typescript-emitter.go +147 -15
  34. package/dist/gs/builtin/builtin.d.ts +2 -2
  35. package/dist/gs/builtin/builtin.js +20 -0
  36. package/dist/gs/builtin/builtin.js.map +1 -1
  37. package/dist/gs/builtin/slice.d.ts +2 -1
  38. package/dist/gs/builtin/slice.js +34 -4
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.d.ts +14 -6
  41. package/dist/gs/builtin/type.js +224 -64
  42. package/dist/gs/builtin/type.js.map +1 -1
  43. package/dist/gs/builtin/varRef.d.ts +11 -0
  44. package/dist/gs/builtin/varRef.js +57 -2
  45. package/dist/gs/builtin/varRef.js.map +1 -1
  46. package/dist/gs/bytes/buffer.gs.js +1 -1
  47. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  48. package/dist/gs/bytes/reader.gs.js +1 -1
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/compress/zlib/index.d.ts +13 -6
  51. package/dist/gs/compress/zlib/index.js +131 -35
  52. package/dist/gs/compress/zlib/index.js.map +1 -1
  53. package/dist/gs/crypto/sha1/index.js +2 -5
  54. package/dist/gs/crypto/sha1/index.js.map +1 -1
  55. package/dist/gs/crypto/sha256/index.js +2 -5
  56. package/dist/gs/crypto/sha256/index.js.map +1 -1
  57. package/dist/gs/crypto/sha512/index.js +2 -5
  58. package/dist/gs/crypto/sha512/index.js.map +1 -1
  59. package/dist/gs/embed/index.d.ts +6 -0
  60. package/dist/gs/embed/index.js +210 -5
  61. package/dist/gs/embed/index.js.map +1 -1
  62. package/dist/gs/encoding/json/index.d.ts +114 -0
  63. package/dist/gs/encoding/json/index.js +544 -36
  64. package/dist/gs/encoding/json/index.js.map +1 -1
  65. package/dist/gs/fmt/fmt.d.ts +3 -3
  66. package/dist/gs/fmt/fmt.js +29 -16
  67. package/dist/gs/fmt/fmt.js.map +1 -1
  68. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  69. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  70. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  71. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  72. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  73. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  74. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  75. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  76. package/dist/gs/go/scanner/index.d.ts +2 -0
  77. package/dist/gs/go/scanner/index.js +29 -5
  78. package/dist/gs/go/scanner/index.js.map +1 -1
  79. package/dist/gs/go/token/index.js +22 -6
  80. package/dist/gs/go/token/index.js.map +1 -1
  81. package/dist/gs/hash/index.d.ts +6 -0
  82. package/dist/gs/hash/index.js +20 -0
  83. package/dist/gs/hash/index.js.map +1 -1
  84. package/dist/gs/internal/goarch/index.d.ts +43 -3
  85. package/dist/gs/internal/goarch/index.js +42 -10
  86. package/dist/gs/internal/goarch/index.js.map +1 -1
  87. package/dist/gs/io/fs/fs.js +26 -14
  88. package/dist/gs/io/fs/fs.js.map +1 -1
  89. package/dist/gs/io/fs/readdir.js +8 -4
  90. package/dist/gs/io/fs/readdir.js.map +1 -1
  91. package/dist/gs/io/fs/sub.js +8 -1
  92. package/dist/gs/io/fs/sub.js.map +1 -1
  93. package/dist/gs/io/io.d.ts +12 -6
  94. package/dist/gs/io/io.js +87 -42
  95. package/dist/gs/io/io.js.map +1 -1
  96. package/dist/gs/math/bits/index.d.ts +31 -5
  97. package/dist/gs/math/bits/index.js +29 -28
  98. package/dist/gs/math/bits/index.js.map +1 -1
  99. package/dist/gs/mime/index.d.ts +16 -0
  100. package/dist/gs/mime/index.js +315 -6
  101. package/dist/gs/mime/index.js.map +1 -1
  102. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  103. package/dist/gs/net/http/httptest/index.js +85 -6
  104. package/dist/gs/net/http/httptest/index.js.map +1 -1
  105. package/dist/gs/net/http/index.d.ts +303 -6
  106. package/dist/gs/net/http/index.js +1615 -58
  107. package/dist/gs/net/http/index.js.map +1 -1
  108. package/dist/gs/os/dir_unix.gs.js +1 -1
  109. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  110. package/dist/gs/os/error.gs.js +1 -1
  111. package/dist/gs/os/error.gs.js.map +1 -1
  112. package/dist/gs/os/exec.gs.d.ts +1 -0
  113. package/dist/gs/os/exec.gs.js +4 -8
  114. package/dist/gs/os/exec.gs.js.map +1 -1
  115. package/dist/gs/os/exec_posix.gs.js +1 -1
  116. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  117. package/dist/gs/os/index.d.ts +1 -1
  118. package/dist/gs/os/index.js +1 -1
  119. package/dist/gs/os/index.js.map +1 -1
  120. package/dist/gs/os/proc.gs.d.ts +4 -0
  121. package/dist/gs/os/proc.gs.js +12 -6
  122. package/dist/gs/os/proc.gs.js.map +1 -1
  123. package/dist/gs/os/root_js.gs.js +1 -1
  124. package/dist/gs/os/root_js.gs.js.map +1 -1
  125. package/dist/gs/os/types.gs.js +1 -1
  126. package/dist/gs/os/types.gs.js.map +1 -1
  127. package/dist/gs/os/types_js.gs.d.ts +6 -2
  128. package/dist/gs/os/types_js.gs.js +170 -9
  129. package/dist/gs/os/types_js.gs.js.map +1 -1
  130. package/dist/gs/os/types_unix.gs.js +1 -1
  131. package/dist/gs/os/types_unix.gs.js.map +1 -1
  132. package/dist/gs/path/path.js +11 -7
  133. package/dist/gs/path/path.js.map +1 -1
  134. package/dist/gs/reflect/index.d.ts +5 -4
  135. package/dist/gs/reflect/index.js +4 -3
  136. package/dist/gs/reflect/index.js.map +1 -1
  137. package/dist/gs/reflect/map.js +15 -0
  138. package/dist/gs/reflect/map.js.map +1 -1
  139. package/dist/gs/reflect/type.d.ts +26 -6
  140. package/dist/gs/reflect/type.js +1498 -279
  141. package/dist/gs/reflect/type.js.map +1 -1
  142. package/dist/gs/reflect/types.d.ts +14 -6
  143. package/dist/gs/reflect/types.js +35 -1
  144. package/dist/gs/reflect/types.js.map +1 -1
  145. package/dist/gs/reflect/value.d.ts +1 -0
  146. package/dist/gs/reflect/value.js +83 -41
  147. package/dist/gs/reflect/value.js.map +1 -1
  148. package/dist/gs/reflect/visiblefields.js +4 -140
  149. package/dist/gs/reflect/visiblefields.js.map +1 -1
  150. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  151. package/dist/gs/runtime/pprof/index.js +50 -30
  152. package/dist/gs/runtime/pprof/index.js.map +1 -1
  153. package/dist/gs/runtime/runtime.js +5 -4
  154. package/dist/gs/runtime/runtime.js.map +1 -1
  155. package/dist/gs/runtime/trace/index.js +5 -19
  156. package/dist/gs/runtime/trace/index.js.map +1 -1
  157. package/dist/gs/strconv/atoi.gs.js +1 -1
  158. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  159. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  160. package/dist/gs/strconv/complex.gs.js +148 -0
  161. package/dist/gs/strconv/complex.gs.js.map +1 -0
  162. package/dist/gs/strconv/index.d.ts +1 -0
  163. package/dist/gs/strconv/index.js +1 -0
  164. package/dist/gs/strconv/index.js.map +1 -1
  165. package/dist/gs/strings/builder.js +1 -1
  166. package/dist/gs/strings/reader.d.ts +1 -1
  167. package/dist/gs/strings/reader.js +11 -7
  168. package/dist/gs/strings/reader.js.map +1 -1
  169. package/dist/gs/strings/replace.js +15 -7
  170. package/dist/gs/strings/replace.js.map +1 -1
  171. package/dist/gs/strings/strings.d.ts +5 -0
  172. package/dist/gs/strings/strings.js +57 -5
  173. package/dist/gs/strings/strings.js.map +1 -1
  174. package/dist/gs/sync/atomic/type.gs.js +9 -9
  175. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  176. package/dist/gs/sync/atomic/value.gs.js +2 -2
  177. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  178. package/dist/gs/sync/sync.d.ts +2 -1
  179. package/dist/gs/sync/sync.js +37 -16
  180. package/dist/gs/sync/sync.js.map +1 -1
  181. package/dist/gs/syscall/env.js +22 -14
  182. package/dist/gs/syscall/env.js.map +1 -1
  183. package/dist/gs/syscall/js/index.js +9 -0
  184. package/dist/gs/syscall/js/index.js.map +1 -1
  185. package/dist/gs/testing/testing.js +59 -15
  186. package/dist/gs/testing/testing.js.map +1 -1
  187. package/dist/gs/time/time.d.ts +24 -1
  188. package/dist/gs/time/time.js +43 -3
  189. package/dist/gs/time/time.js.map +1 -1
  190. package/dist/gs/unique/index.js +7 -1
  191. package/dist/gs/unique/index.js.map +1 -1
  192. package/go.mod +3 -3
  193. package/go.sum +16 -0
  194. package/gs/builtin/builtin.ts +25 -2
  195. package/gs/builtin/runtime-contract.test.ts +260 -18
  196. package/gs/builtin/slice.ts +51 -4
  197. package/gs/builtin/type.ts +310 -63
  198. package/gs/builtin/varRef.ts +85 -2
  199. package/gs/bytes/buffer.gs.ts +1 -1
  200. package/gs/bytes/reader.gs.ts +1 -1
  201. package/gs/compress/zlib/index.test.ts +159 -1
  202. package/gs/compress/zlib/index.ts +164 -37
  203. package/gs/compress/zlib/meta.json +4 -1
  204. package/gs/compress/zlib/parity.json +51 -0
  205. package/gs/crypto/sha1/index.test.ts +19 -2
  206. package/gs/crypto/sha1/index.ts +3 -6
  207. package/gs/crypto/sha256/index.test.ts +14 -2
  208. package/gs/crypto/sha256/index.ts +3 -6
  209. package/gs/crypto/sha512/index.test.ts +17 -2
  210. package/gs/crypto/sha512/index.ts +3 -6
  211. package/gs/embed/index.test.ts +87 -0
  212. package/gs/embed/index.ts +229 -5
  213. package/gs/encoding/json/index.test.ts +360 -6
  214. package/gs/encoding/json/index.ts +679 -38
  215. package/gs/encoding/json/parity.json +81 -0
  216. package/gs/fmt/fmt.test.ts +41 -3
  217. package/gs/fmt/fmt.ts +40 -17
  218. package/gs/fmt/meta.json +6 -1
  219. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  220. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  221. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  222. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  223. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  224. package/gs/github.com/pkg/errors/errors.ts +54 -30
  225. package/gs/go/scanner/index.test.ts +39 -56
  226. package/gs/go/scanner/index.ts +33 -5
  227. package/gs/go/scanner/parity.json +27 -0
  228. package/gs/go/token/index.ts +22 -6
  229. package/gs/hash/index.test.ts +20 -33
  230. package/gs/hash/index.ts +28 -0
  231. package/gs/hash/parity.json +21 -0
  232. package/gs/internal/goarch/index.test.ts +32 -0
  233. package/gs/internal/goarch/index.ts +45 -13
  234. package/gs/internal/goarch/parity.json +144 -0
  235. package/gs/io/fs/fs.ts +26 -14
  236. package/gs/io/fs/readdir.test.ts +38 -0
  237. package/gs/io/fs/readdir.ts +8 -4
  238. package/gs/io/fs/sub.ts +8 -1
  239. package/gs/io/io.test.ts +77 -6
  240. package/gs/io/io.ts +115 -52
  241. package/gs/io/meta.json +7 -1
  242. package/gs/io/parity.json +162 -0
  243. package/gs/math/bits/index.test.ts +14 -1
  244. package/gs/math/bits/index.ts +75 -32
  245. package/gs/math/bits/parity.json +156 -0
  246. package/gs/mime/index.test.ts +90 -0
  247. package/gs/mime/index.ts +369 -6
  248. package/gs/mime/parity.json +36 -0
  249. package/gs/net/http/httptest/index.test.ts +98 -2
  250. package/gs/net/http/httptest/index.ts +101 -6
  251. package/gs/net/http/httptest/parity.json +15 -0
  252. package/gs/net/http/index.test.ts +797 -12
  253. package/gs/net/http/index.ts +1874 -136
  254. package/gs/net/http/meta.json +16 -1
  255. package/gs/net/http/parity.json +193 -0
  256. package/gs/os/dir_unix.gs.ts +1 -1
  257. package/gs/os/error.gs.ts +1 -1
  258. package/gs/os/exec.gs.ts +4 -8
  259. package/gs/os/exec_posix.gs.ts +1 -1
  260. package/gs/os/file_unix_js.test.ts +52 -0
  261. package/gs/os/index.test.ts +9 -0
  262. package/gs/os/index.ts +1 -0
  263. package/gs/os/meta.json +4 -0
  264. package/gs/os/parity.json +9 -0
  265. package/gs/os/proc.gs.ts +18 -5
  266. package/gs/os/proc.test.ts +26 -0
  267. package/gs/os/readdir.test.ts +56 -0
  268. package/gs/os/root_js.gs.ts +1 -1
  269. package/gs/os/types.gs.ts +1 -1
  270. package/gs/os/types_js.gs.ts +170 -9
  271. package/gs/os/types_unix.gs.ts +1 -1
  272. package/gs/path/path.ts +11 -7
  273. package/gs/reflect/deepequal.test.ts +10 -1
  274. package/gs/reflect/field.test.ts +37 -15
  275. package/gs/reflect/function-types.test.ts +518 -22
  276. package/gs/reflect/index.ts +8 -6
  277. package/gs/reflect/map.ts +20 -0
  278. package/gs/reflect/meta.json +6 -4
  279. package/gs/reflect/parity.json +234 -0
  280. package/gs/reflect/sliceat.test.ts +156 -0
  281. package/gs/reflect/structof.test.ts +401 -0
  282. package/gs/reflect/type.ts +1980 -365
  283. package/gs/reflect/typefor.test.ts +540 -10
  284. package/gs/reflect/types.ts +43 -18
  285. package/gs/reflect/value.ts +105 -45
  286. package/gs/reflect/visiblefields.ts +5 -168
  287. package/gs/runtime/parity.json +24 -0
  288. package/gs/runtime/pprof/index.test.ts +29 -7
  289. package/gs/runtime/pprof/index.ts +56 -30
  290. package/gs/runtime/pprof/parity.json +27 -0
  291. package/gs/runtime/runtime.test.ts +3 -1
  292. package/gs/runtime/runtime.ts +4 -3
  293. package/gs/runtime/trace/index.test.ts +5 -3
  294. package/gs/runtime/trace/index.ts +8 -20
  295. package/gs/runtime/trace/parity.json +36 -0
  296. package/gs/strconv/atoi.gs.ts +1 -1
  297. package/gs/strconv/complex.gs.ts +174 -0
  298. package/gs/strconv/complex.test.ts +65 -0
  299. package/gs/strconv/index.ts +1 -0
  300. package/gs/strconv/parity.json +120 -0
  301. package/gs/strings/builder.ts +1 -1
  302. package/gs/strings/meta.json +5 -2
  303. package/gs/strings/parity.json +186 -0
  304. package/gs/strings/reader.test.ts +2 -2
  305. package/gs/strings/reader.ts +11 -7
  306. package/gs/strings/replace.ts +15 -7
  307. package/gs/strings/strings.test.ts +22 -2
  308. package/gs/strings/strings.ts +64 -6
  309. package/gs/sync/atomic/type.gs.ts +9 -9
  310. package/gs/sync/atomic/value.gs.ts +2 -2
  311. package/gs/sync/meta.json +1 -0
  312. package/gs/sync/sync.test.ts +41 -1
  313. package/gs/sync/sync.ts +41 -16
  314. package/gs/syscall/env.ts +29 -14
  315. package/gs/syscall/js/index.test.ts +18 -0
  316. package/gs/syscall/js/index.ts +12 -0
  317. package/gs/testing/testing.test.ts +99 -3
  318. package/gs/testing/testing.ts +95 -24
  319. package/gs/time/parity.json +225 -0
  320. package/gs/time/time.test.ts +20 -2
  321. package/gs/time/time.ts +49 -7
  322. package/gs/unique/index.ts +7 -1
  323. package/package.json +4 -2
  324. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  325. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
  326. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  327. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
  328. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
  329. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  330. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -64,6 +64,53 @@ func TestRunnerRunsOrdinaryPackageTest(t *testing.T) {
64
64
  }
65
65
  }
66
66
 
67
+ func TestRunnerComparesInterfacePointerValuesByIdentity(t *testing.T) {
68
+ moduleDir := writeFixture(t, map[string]string{
69
+ "go.mod": "module example.test/ifaceptr\n\ngo 1.25.3\n",
70
+ "value_test.go": strings.Join([]string{
71
+ "package ifaceptr",
72
+ "",
73
+ "import \"testing\"",
74
+ "",
75
+ "type Snapshot interface {",
76
+ "\tValue() int",
77
+ "}",
78
+ "",
79
+ "type snapshot struct {",
80
+ "\tvalue int",
81
+ "}",
82
+ "",
83
+ "func (s *snapshot) Value() int { return s.value }",
84
+ "",
85
+ "func TestInterfacePointerValuesUsePointerIdentity(t *testing.T) {",
86
+ "\tvar first Snapshot = &snapshot{value: 1}",
87
+ "\tvar second Snapshot = &snapshot{value: 1}",
88
+ "\tif first == second {",
89
+ "\t\tt.Fatalf(\"distinct pointers stored in interfaces compared equal\")",
90
+ "\t}",
91
+ "\tsecond = first",
92
+ "\tif first != second {",
93
+ "\t\tt.Fatalf(\"same pointer stored in interfaces compared unequal\")",
94
+ "\t}",
95
+ "}",
96
+ "",
97
+ }, "\n"),
98
+ })
99
+
100
+ result, err := NewRunner().Run(context.Background(), &Request{
101
+ Dir: moduleDir,
102
+ Patterns: []string{"."},
103
+ Timeout: 30 * time.Second,
104
+ Verbose: true,
105
+ })
106
+ if err != nil {
107
+ t.Fatalf("run package test: %v", err)
108
+ }
109
+ if !result.Passed() {
110
+ t.Fatalf("expected package test to pass: %#v", result.Packages)
111
+ }
112
+ }
113
+
67
114
  func TestRunnerReportsShortMode(t *testing.T) {
68
115
  moduleDir := writeFixture(t, map[string]string{
69
116
  "go.mod": "module example.test/short\n\ngo 1.25.3\n",
@@ -258,6 +305,86 @@ func TestRunnerRunsExternalPackageTest(t *testing.T) {
258
305
  }
259
306
  }
260
307
 
308
+ func TestRunnerBatchCompilesSamePackageTests(t *testing.T) {
309
+ moduleDir := writeFixture(t, map[string]string{
310
+ "go.mod": "module example.test/samebatch\n\ngo 1.25.3\n",
311
+ "helper/value.go": strings.Join([]string{
312
+ "package helper",
313
+ "",
314
+ "func Value() int { return 2 }",
315
+ "",
316
+ }, "\n"),
317
+ "one/value.go": strings.Join([]string{
318
+ "package one",
319
+ "",
320
+ "func Value() int { return 1 }",
321
+ "",
322
+ }, "\n"),
323
+ "one/value_test.go": strings.Join([]string{
324
+ "package one",
325
+ "",
326
+ "import \"testing\"",
327
+ "",
328
+ "func TestOne(t *testing.T) {",
329
+ "\tif Value() != 1 {",
330
+ "\t\tt.Fatal(\"bad value\")",
331
+ "\t}",
332
+ "}",
333
+ "",
334
+ }, "\n"),
335
+ "two/value.go": strings.Join([]string{
336
+ "package two",
337
+ "",
338
+ "import \"example.test/samebatch/one\"",
339
+ "",
340
+ "func Value() int { return one.Value() + 1 }",
341
+ "",
342
+ }, "\n"),
343
+ "two/value_test.go": strings.Join([]string{
344
+ "package two",
345
+ "",
346
+ "import \"testing\"",
347
+ "",
348
+ "func TestTwo(t *testing.T) {",
349
+ "\tif Value() != 2 {",
350
+ "\t\tt.Fatal(\"bad value\")",
351
+ "\t}",
352
+ "}",
353
+ "",
354
+ }, "\n"),
355
+ "two/external_test.go": strings.Join([]string{
356
+ "package two_test",
357
+ "",
358
+ "import (",
359
+ "\t\"testing\"",
360
+ "",
361
+ "\t\"example.test/samebatch/helper\"",
362
+ "\t\"example.test/samebatch/two\"",
363
+ ")",
364
+ "",
365
+ "func TestTwoExternal(t *testing.T) {",
366
+ "\tif two.Value() != helper.Value() {",
367
+ "\t\tt.Fatal(\"bad value\")",
368
+ "\t}",
369
+ "}",
370
+ "",
371
+ }, "\n"),
372
+ })
373
+
374
+ result, err := NewRunner().Run(context.Background(), &Request{
375
+ Dir: moduleDir,
376
+ Patterns: []string{"./..."},
377
+ Timeout: 30 * time.Second,
378
+ Verbose: true,
379
+ })
380
+ if err != nil {
381
+ t.Fatalf("run same-package batch tests: %v", err)
382
+ }
383
+ if !result.Passed() {
384
+ t.Fatalf("expected same-package batch tests to pass: %#v", result.Packages)
385
+ }
386
+ }
387
+
261
388
  func TestRunnerAppliesOverridesToTestImports(t *testing.T) {
262
389
  moduleDir := writeFixture(t, map[string]string{
263
390
  "go.mod": "module example.test/testoverride\n\ngo 1.25.3\n",
@@ -909,7 +1036,7 @@ func TestRunnerRunsCombinedRuntimeChunks(t *testing.T) {
909
1036
  "case \"$runner\" in",
910
1037
  "runner-all-*)",
911
1038
  "\tsed -n 's/.*await __goscriptRunPackage(\"\\([^\"]*\\)\".*/\\1/p' \"$runner\" | while IFS= read -r pkg; do",
912
- "\t\tprintf '" + combinedRuntimeResultPrefix + "{\"packagePath\":\"%s\",\"ok\":true,\"elapsedMs\":1,\"output\":\"\"}\\n' \"$pkg\"",
1039
+ "\t\tprintf '" + combinedRuntimeResultPrefix + "%s\\t1\\t1\\t\\n' \"$pkg\"",
913
1040
  "\tdone",
914
1041
  "\texit 0",
915
1042
  "\t;;",
@@ -945,6 +1072,157 @@ func TestRunnerRunsCombinedRuntimeChunks(t *testing.T) {
945
1072
  }
946
1073
  }
947
1074
 
1075
+ func TestRunnerRunsBrowserRuntimeBackend(t *testing.T) {
1076
+ moduleDir := writeFixture(t, map[string]string{
1077
+ "go.mod": "module example.test/browser\n\ngo 1.25.3\n",
1078
+ "value_test.go": strings.Join([]string{
1079
+ "package browser",
1080
+ "",
1081
+ "import \"testing\"",
1082
+ "",
1083
+ "func TestBrowser(t *testing.T) {}",
1084
+ "",
1085
+ }, "\n"),
1086
+ })
1087
+ workDir := filepath.Join(moduleDir, ".tmp", "browser-runtime")
1088
+ writeExecutable(t, filepath.Join(moduleDir, "node_modules", ".bin", "vitest"), strings.Join([]string{
1089
+ "#!/bin/sh",
1090
+ "printf '" + combinedRuntimeResultPrefix + "example.test%%2Fbrowser\\t1\\t7\\tbrowser%%20ok\\n'",
1091
+ "exit 0",
1092
+ "",
1093
+ }, "\n"))
1094
+
1095
+ result, err := NewRunner().Run(context.Background(), &Request{
1096
+ Dir: moduleDir,
1097
+ Patterns: []string{"."},
1098
+ Timeout: 30 * time.Second,
1099
+ WorkDir: workDir,
1100
+ RuntimeBackend: RuntimeBackendBrowser,
1101
+ })
1102
+ if err != nil {
1103
+ t.Fatalf("run browser runtime fixture: %v", err)
1104
+ }
1105
+ if !result.Passed() {
1106
+ t.Fatalf("expected browser runtime fixture to pass: %#v", result.Packages)
1107
+ }
1108
+ if got := result.Packages[0].Output; got != "browser ok" {
1109
+ t.Fatalf("expected browser runtime output, got %q", got)
1110
+ }
1111
+ config, err := os.ReadFile(filepath.Join(workDir, "vitest-browser-0.config.mts"))
1112
+ if err != nil {
1113
+ t.Fatalf("read browser vitest config: %v", err)
1114
+ }
1115
+ if !strings.Contains(string(config), "browser: \"chromium\"") {
1116
+ t.Fatalf("expected Chromium browser config, got:\n%s", config)
1117
+ }
1118
+ }
1119
+
1120
+ func TestRunnerReportsBrowserRuntimeFailureRecord(t *testing.T) {
1121
+ moduleDir := writeFixture(t, map[string]string{
1122
+ "go.mod": "module example.test/browserfail\n\ngo 1.25.3\n",
1123
+ "value_test.go": strings.Join([]string{
1124
+ "package browserfail",
1125
+ "",
1126
+ "import \"testing\"",
1127
+ "",
1128
+ "func TestBrowser(t *testing.T) {}",
1129
+ "",
1130
+ }, "\n"),
1131
+ })
1132
+ writeExecutable(t, filepath.Join(moduleDir, "node_modules", ".bin", "tsgo"), "#!/bin/sh\nexit 0\n")
1133
+ writeExecutable(t, filepath.Join(moduleDir, "node_modules", ".bin", "vitest"), strings.Join([]string{
1134
+ "#!/bin/sh",
1135
+ "printf '" + combinedRuntimeResultPrefix + "example.test%%2Fbrowserfail\\t0\\t3\\tpage%%20exploded\\n'",
1136
+ "exit 1",
1137
+ "",
1138
+ }, "\n"))
1139
+
1140
+ result, err := NewRunner().Run(context.Background(), &Request{
1141
+ Dir: moduleDir,
1142
+ Patterns: []string{"."},
1143
+ Timeout: 30 * time.Second,
1144
+ RuntimeBackend: RuntimeBackendBrowser,
1145
+ })
1146
+ if err != nil {
1147
+ t.Fatalf("run browser failure fixture: %v", err)
1148
+ }
1149
+ if result.Passed() {
1150
+ t.Fatalf("expected browser runtime failure")
1151
+ }
1152
+ pkg := requirePackageResult(t, result, "example.test/browserfail")
1153
+ if pkg.Action != ActionFail || pkg.Phases.Runtime != PhaseStatusFail || pkg.Error != "page exploded" {
1154
+ t.Fatalf("unexpected browser failure result: %#v", pkg)
1155
+ }
1156
+ }
1157
+
1158
+ func TestParseCombinedRuntimeRecordsLineProtocol(t *testing.T) {
1159
+ records, ok := parseCombinedRuntimeRecords(strings.Join([]string{
1160
+ "ordinary output",
1161
+ combinedRuntimeResultPrefix + "example.test%2Fpkg\t1\t42\tline%201%0Aline%202%09tail",
1162
+ "",
1163
+ }, "\n"))
1164
+ if !ok {
1165
+ t.Fatal("expected combined runtime record")
1166
+ }
1167
+ if len(records) != 1 {
1168
+ t.Fatalf("expected one combined runtime record, got %#v", records)
1169
+ }
1170
+ record := records[0]
1171
+ if record.PackagePath != "example.test/pkg" {
1172
+ t.Fatalf("unexpected package path: %q", record.PackagePath)
1173
+ }
1174
+ if !record.OK {
1175
+ t.Fatal("expected passing runtime record")
1176
+ }
1177
+ if record.ElapsedMS != 42 {
1178
+ t.Fatalf("unexpected elapsed ms: %d", record.ElapsedMS)
1179
+ }
1180
+ if record.Output != "line 1\nline 2\ttail" {
1181
+ t.Fatalf("unexpected output: %q", record.Output)
1182
+ }
1183
+ }
1184
+
1185
+ func TestRunnerReportsBrowserRuntimeMissingResult(t *testing.T) {
1186
+ moduleDir := writeFixture(t, map[string]string{
1187
+ "go.mod": "module example.test/browsermissing\n\ngo 1.25.3\n",
1188
+ "value_test.go": strings.Join([]string{
1189
+ "package browsermissing",
1190
+ "",
1191
+ "import \"testing\"",
1192
+ "",
1193
+ "func TestBrowser(t *testing.T) {}",
1194
+ "",
1195
+ }, "\n"),
1196
+ })
1197
+ writeExecutable(t, filepath.Join(moduleDir, "node_modules", ".bin", "tsgo"), "#!/bin/sh\nexit 0\n")
1198
+ writeExecutable(t, filepath.Join(moduleDir, "node_modules", ".bin", "vitest"), strings.Join([]string{
1199
+ "#!/bin/sh",
1200
+ "printf 'page exploded before result\\n'",
1201
+ "exit 1",
1202
+ "",
1203
+ }, "\n"))
1204
+
1205
+ result, err := NewRunner().Run(context.Background(), &Request{
1206
+ Dir: moduleDir,
1207
+ Patterns: []string{"."},
1208
+ Timeout: 30 * time.Second,
1209
+ RuntimeBackend: RuntimeBackendBrowser,
1210
+ })
1211
+ if err != nil {
1212
+ t.Fatalf("run browser missing-result fixture: %v", err)
1213
+ }
1214
+ if result.Passed() {
1215
+ t.Fatalf("expected browser runtime failure")
1216
+ }
1217
+ pkg := requirePackageResult(t, result, "example.test/browsermissing")
1218
+ if pkg.Action != ActionFail || pkg.Phases.Runtime != PhaseStatusFail {
1219
+ t.Fatalf("unexpected browser missing-result status: %#v", pkg)
1220
+ }
1221
+ if !strings.Contains(pkg.Error, "page exploded before result") {
1222
+ t.Fatalf("expected browser process output in error, got %#v", pkg)
1223
+ }
1224
+ }
1225
+
948
1226
  func TestRunnerFallsBackToPackageScopedTypeScriptProjects(t *testing.T) {
949
1227
  moduleDir := writeFixture(t, map[string]string{
950
1228
  "go.mod": "module example.test/packageprojects\n\ngo 1.25.3\n",
@@ -1068,6 +1346,34 @@ func TestNormalizeKeepsIncrementalTypeCheckExplicit(t *testing.T) {
1068
1346
  }
1069
1347
  }
1070
1348
 
1349
+ func TestNormalizeRuntimeBackend(t *testing.T) {
1350
+ norm, err := (&Request{Patterns: []string{"."}}).normalize()
1351
+ if err != nil {
1352
+ t.Fatalf("normalize default runtime backend: %v", err)
1353
+ }
1354
+ if norm.RuntimeBackend != RuntimeBackendBun {
1355
+ t.Fatalf("runtime backend = %q, want %q", norm.RuntimeBackend, RuntimeBackendBun)
1356
+ }
1357
+
1358
+ norm, err = (&Request{
1359
+ Patterns: []string{"."},
1360
+ RuntimeBackend: RuntimeBackendBrowser,
1361
+ }).normalize()
1362
+ if err != nil {
1363
+ t.Fatalf("normalize browser runtime backend: %v", err)
1364
+ }
1365
+ if norm.RuntimeBackend != RuntimeBackendBrowser {
1366
+ t.Fatalf("runtime backend = %q, want %q", norm.RuntimeBackend, RuntimeBackendBrowser)
1367
+ }
1368
+
1369
+ if _, err := (&Request{
1370
+ Patterns: []string{"."},
1371
+ RuntimeBackend: RuntimeBackend("deno"),
1372
+ }).normalize(); err == nil {
1373
+ t.Fatal("expected unsupported runtime backend to fail")
1374
+ }
1375
+ }
1376
+
1071
1377
  func TestPackageExecutionIndexesPrioritizesLargerTestPackages(t *testing.T) {
1072
1378
  result := &Result{Packages: []PackageResult{
1073
1379
  {
@@ -1124,6 +1430,76 @@ func TestRenderRunnerChangesToPackageSourceDir(t *testing.T) {
1124
1430
  }
1125
1431
  }
1126
1432
 
1433
+ func TestRenderBrowserRunnerAvoidsProcessAPIs(t *testing.T) {
1434
+ req := &normalizedRequest{
1435
+ RuntimeBackend: RuntimeBackendBrowser,
1436
+ }
1437
+ runner := renderPackageRunner(PackageResult{
1438
+ PackagePath: "example.test/pkg",
1439
+ SourceDir: "/workspace/pkg",
1440
+ Tests: []Test{{
1441
+ Name: "TestBrowser",
1442
+ PackagePath: "example.test/pkg",
1443
+ }},
1444
+ }, req)
1445
+
1446
+ if strings.Contains(runner, "process.") {
1447
+ t.Fatalf("browser runner should not use process APIs: %s", runner)
1448
+ }
1449
+ if !strings.Contains(runner, "import { test } from \"vitest\"") {
1450
+ t.Fatalf("expected browser runner to use Vitest: %s", runner)
1451
+ }
1452
+ if !strings.Contains(runner, "await runTests(\"example.test/pkg\"") {
1453
+ t.Fatalf("expected browser runner to execute package tests: %s", runner)
1454
+ }
1455
+ }
1456
+
1457
+ func TestRenderBrowserRunnerReportsProcessExit(t *testing.T) {
1458
+ req := &normalizedRequest{
1459
+ RuntimeBackend: RuntimeBackendBrowser,
1460
+ }
1461
+ runner := renderPackageRunner(PackageResult{
1462
+ PackagePath: "example.test/pkg",
1463
+ SourceDir: "/workspace/pkg",
1464
+ Tests: []Test{{
1465
+ Name: "TestBrowser",
1466
+ PackagePath: "example.test/pkg",
1467
+ }},
1468
+ }, req)
1469
+
1470
+ if !strings.Contains(runner, "__goscriptProcessExitCode") {
1471
+ t.Fatalf("expected browser runner to classify process exit: %s", runner)
1472
+ }
1473
+ if !strings.Contains(runner, "goscript process exited with code") {
1474
+ t.Fatalf("expected browser runner to report process exit code: %s", runner)
1475
+ }
1476
+ if !strings.Contains(runner, "__goscriptOK = exitCode === 0") {
1477
+ t.Fatalf("expected zero exit to pass and nonzero exit to fail: %s", runner)
1478
+ }
1479
+ }
1480
+
1481
+ func TestRenderBrowserRunnerHonorsPanicOnExitZero(t *testing.T) {
1482
+ req := &normalizedRequest{
1483
+ RuntimeBackend: RuntimeBackendBrowser,
1484
+ PanicOnExit0: true,
1485
+ }
1486
+ runner := renderPackageRunner(PackageResult{
1487
+ PackagePath: "example.test/pkg",
1488
+ SourceDir: "/workspace/pkg",
1489
+ Tests: []Test{{
1490
+ Name: "TestBrowser",
1491
+ PackagePath: "example.test/pkg",
1492
+ }},
1493
+ }, req)
1494
+
1495
+ if !strings.Contains(runner, "exitCode === 0 && true") {
1496
+ t.Fatalf("expected panic-on-exit-zero to reject os.Exit(0): %s", runner)
1497
+ }
1498
+ if !strings.Contains(runner, "unexpected os.Exit(0) during test") {
1499
+ t.Fatalf("expected panic-on-exit-zero error text: %s", runner)
1500
+ }
1501
+ }
1502
+
1127
1503
  func TestRenderCombinedRunnerChangesToEachPackageSourceDir(t *testing.T) {
1128
1504
  req := &normalizedRequest{}
1129
1505
  runner := renderCombinedRunner(&Result{Packages: []PackageResult{
@@ -1176,6 +1552,29 @@ func TestRenderTypeScriptProjectDisablesAmbientTypePackages(t *testing.T) {
1176
1552
  }
1177
1553
  }
1178
1554
 
1555
+ func TestRenderBrowserTypeScriptProjectsExcludeNodeAmbientDeclarations(t *testing.T) {
1556
+ req := &normalizedRequest{
1557
+ WorkDir: "/work",
1558
+ RuntimeBackend: RuntimeBackendBrowser,
1559
+ }
1560
+
1561
+ packageTSConfig := renderTypeScriptProject(req, "/work/output/package-0", "runner-0.ts", "tsconfig-0.json", false)
1562
+ if strings.Contains(packageTSConfig, "goscript-node.d.ts") {
1563
+ t.Fatalf("browser package tsconfig should not include node ambient declarations: %s", packageTSConfig)
1564
+ }
1565
+ if !strings.Contains(packageTSConfig, "goscript-browser.d.ts") {
1566
+ t.Fatalf("browser package tsconfig should include browser ambient declarations: %s", packageTSConfig)
1567
+ }
1568
+
1569
+ aggregateTSConfig := renderRuntimeTypeScriptProject(req, []string{"/work/output"}, false)
1570
+ if strings.Contains(aggregateTSConfig, "goscript-node.d.ts") {
1571
+ t.Fatalf("browser aggregate tsconfig should not include node ambient declarations: %s", aggregateTSConfig)
1572
+ }
1573
+ if !strings.Contains(aggregateTSConfig, "goscript-browser.d.ts") {
1574
+ t.Fatalf("browser aggregate tsconfig should include browser ambient declarations: %s", aggregateTSConfig)
1575
+ }
1576
+ }
1577
+
1179
1578
  func TestRenderTypeScriptProjectUsesNodeTypesWhenAvailable(t *testing.T) {
1180
1579
  req := &normalizedRequest{
1181
1580
  WorkDir: "/work",
@@ -0,0 +1,20 @@
1
+ //go:build js && wasm
2
+
3
+ package browserapi
4
+
5
+ import (
6
+ "syscall/js"
7
+ "testing"
8
+ )
9
+
10
+ func TestBrowserAPI(t *testing.T) {
11
+ document := js.Global().Get("document")
12
+ if document.IsUndefined() || document.IsNull() {
13
+ t.Fatal("missing browser document")
14
+ }
15
+ div := document.Call("createElement", "div")
16
+ div.Set("id", "goscript-browser-api")
17
+ if got := div.Get("id").String(); got != "goscript-browser-api" {
18
+ t.Fatalf("div id = %q", got)
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ module example.test/browserapi
2
+
3
+ go 1.25.3
@@ -18,6 +18,7 @@ type loweredFile struct {
18
18
  decls []loweredDecl
19
19
  exports []string
20
20
  typeExports []string
21
+ exportAll bool
21
22
  sideEffect bool
22
23
  }
23
24
 
@@ -75,28 +76,34 @@ type loweredStructField struct {
75
76
  runtimeType string
76
77
  doc string
77
78
  tag string
79
+ pkgPath string
80
+ index []int
81
+ offset int64
82
+ anonymous bool
83
+ exported bool
78
84
  structValue bool
79
85
  arrayValue bool
80
86
  }
81
87
 
82
88
  type loweredFunction struct {
83
- exported bool
84
- indexExported bool
85
- init bool
86
- async bool
87
- name string
88
- typeParams []string
89
- runtimeName string
90
- receiverAlias string
91
- receiverType string
92
- receiverValue string
93
- receiverMutable bool
94
- params []loweredParam
95
- paramBindings []loweredStmt
96
- namedResults []loweredNamedResult
97
- result string
98
- body []loweredStmt
99
- deferState *loweredDeferState
89
+ exported bool
90
+ indexExported bool
91
+ init bool
92
+ async bool
93
+ name string
94
+ typeParams []string
95
+ runtimeName string
96
+ runtimeSignature string
97
+ receiverAlias string
98
+ receiverType string
99
+ receiverValue string
100
+ receiverMutable bool
101
+ params []loweredParam
102
+ paramBindings []loweredStmt
103
+ namedResults []loweredNamedResult
104
+ result string
105
+ body []loweredStmt
106
+ deferState *loweredDeferState
100
107
  }
101
108
 
102
109
  type loweredParam struct {