goscript 0.1.1 → 0.1.3

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 (376) hide show
  1. package/cmd/goscript/cmd-test.go +104 -11
  2. package/cmd/goscript/cmd-test_test.go +1 -1
  3. package/cmd/goscript/cmd_compile.go +9 -0
  4. package/compiler/compile-request.go +31 -0
  5. package/compiler/compiler.go +1 -1
  6. package/compiler/compliance_test.go +0 -2
  7. package/compiler/config.go +2 -0
  8. package/compiler/gotest/package-result.go +2 -0
  9. package/compiler/gotest/request.go +85 -20
  10. package/compiler/gotest/runner.go +733 -96
  11. package/compiler/gotest/runner_test.go +647 -3
  12. package/compiler/lowered-program.go +10 -2
  13. package/compiler/lowering.go +2676 -349
  14. package/compiler/override-facts.go +77 -27
  15. package/compiler/override-registry.go +5 -4
  16. package/compiler/override-registry_test.go +178 -0
  17. package/compiler/package-graph_test.go +62 -7
  18. package/compiler/package-test-graph-variant.go +40 -16
  19. package/compiler/package-test-graph.go +0 -5
  20. package/compiler/package-test-graph_test.go +61 -3
  21. package/compiler/runtime-contract.go +40 -0
  22. package/compiler/semantic-model-types.go +16 -0
  23. package/compiler/semantic-model.go +336 -91
  24. package/compiler/semantic-model_test.go +50 -1
  25. package/compiler/service.go +9 -3
  26. package/compiler/skeleton_test.go +2371 -296
  27. package/compiler/tsworkspace/owner-process-unix_test.go +72 -0
  28. package/compiler/tsworkspace/owner.go +8 -0
  29. package/compiler/tsworkspace/tool-process-other.go +14 -0
  30. package/compiler/tsworkspace/tool-process-unix.go +19 -0
  31. package/compiler/typescript-emitter.go +149 -10
  32. package/dist/gs/builtin/builtin.d.ts +20 -1
  33. package/dist/gs/builtin/builtin.js +246 -26
  34. package/dist/gs/builtin/builtin.js.map +1 -1
  35. package/dist/gs/builtin/channel.d.ts +24 -10
  36. package/dist/gs/builtin/channel.js +143 -34
  37. package/dist/gs/builtin/channel.js.map +1 -1
  38. package/dist/gs/builtin/defer.d.ts +1 -0
  39. package/dist/gs/builtin/defer.js +12 -2
  40. package/dist/gs/builtin/defer.js.map +1 -1
  41. package/dist/gs/builtin/hostio.d.ts +9 -0
  42. package/dist/gs/builtin/hostio.js +25 -0
  43. package/dist/gs/builtin/hostio.js.map +1 -1
  44. package/dist/gs/builtin/map.js +40 -6
  45. package/dist/gs/builtin/map.js.map +1 -1
  46. package/dist/gs/builtin/print.js.map +1 -1
  47. package/dist/gs/builtin/slice.d.ts +43 -9
  48. package/dist/gs/builtin/slice.js +437 -234
  49. package/dist/gs/builtin/slice.js.map +1 -1
  50. package/dist/gs/builtin/type.d.ts +2 -0
  51. package/dist/gs/builtin/type.js +55 -10
  52. package/dist/gs/builtin/type.js.map +1 -1
  53. package/dist/gs/builtin/varRef.d.ts +2 -0
  54. package/dist/gs/builtin/varRef.js.map +1 -1
  55. package/dist/gs/bytes/buffer.gs.js +28 -28
  56. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  57. package/dist/gs/bytes/bytes.gs.d.ts +7 -5
  58. package/dist/gs/bytes/bytes.gs.js +10 -4
  59. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  60. package/dist/gs/bytes/iter.gs.js +13 -13
  61. package/dist/gs/bytes/iter.gs.js.map +1 -1
  62. package/dist/gs/compress/zlib/index.d.ts +26 -0
  63. package/dist/gs/compress/zlib/index.js +168 -0
  64. package/dist/gs/compress/zlib/index.js.map +1 -0
  65. package/dist/gs/context/context.d.ts +1 -1
  66. package/dist/gs/context/context.js +8 -3
  67. package/dist/gs/context/context.js.map +1 -1
  68. package/dist/gs/crypto/ecdh/index.d.ts +52 -0
  69. package/dist/gs/crypto/ecdh/index.js +226 -0
  70. package/dist/gs/crypto/ecdh/index.js.map +1 -0
  71. package/dist/gs/crypto/ed25519/index.d.ts +34 -0
  72. package/dist/gs/crypto/ed25519/index.js +160 -0
  73. package/dist/gs/crypto/ed25519/index.js.map +1 -0
  74. package/dist/gs/crypto/internal/constanttime/index.d.ts +4 -0
  75. package/dist/gs/crypto/internal/constanttime/index.js +18 -0
  76. package/dist/gs/crypto/internal/constanttime/index.js.map +1 -0
  77. package/dist/gs/crypto/rand/index.d.ts +2 -0
  78. package/dist/gs/crypto/rand/index.js +85 -0
  79. package/dist/gs/crypto/rand/index.js.map +1 -1
  80. package/dist/gs/crypto/sha1/index.d.ts +5 -0
  81. package/dist/gs/crypto/sha1/index.js +106 -0
  82. package/dist/gs/crypto/sha1/index.js.map +1 -0
  83. package/dist/gs/crypto/sha256/index.d.ts +8 -0
  84. package/dist/gs/crypto/sha256/index.js +118 -0
  85. package/dist/gs/crypto/sha256/index.js.map +1 -0
  86. package/dist/gs/crypto/sha512/index.d.ts +14 -0
  87. package/dist/gs/crypto/sha512/index.js +129 -0
  88. package/dist/gs/crypto/sha512/index.js.map +1 -0
  89. package/dist/gs/encoding/json/index.d.ts +3 -0
  90. package/dist/gs/encoding/json/index.js +15 -0
  91. package/dist/gs/encoding/json/index.js.map +1 -1
  92. package/dist/gs/errors/errors.js +29 -6
  93. package/dist/gs/errors/errors.js.map +1 -1
  94. package/dist/gs/fmt/fmt.d.ts +1 -1
  95. package/dist/gs/fmt/fmt.js +64 -3
  96. package/dist/gs/fmt/fmt.js.map +1 -1
  97. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +7 -7
  98. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +52 -18
  99. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  100. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +56 -20
  101. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  102. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +57 -3
  103. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +366 -1
  104. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  105. package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +20 -0
  106. package/dist/gs/github.com/aperturerobotics/util/conc/index.js +134 -0
  107. package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +1 -0
  108. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  109. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.d.ts +3 -0
  110. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js +50 -0
  111. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js.map +1 -0
  112. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +3 -2
  113. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -1
  114. package/dist/gs/github.com/mr-tron/base58/base58/index.d.ts +27 -0
  115. package/dist/gs/github.com/mr-tron/base58/base58/index.js +172 -0
  116. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -0
  117. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.d.ts +21 -0
  118. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js +22 -0
  119. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js.map +1 -0
  120. package/dist/gs/go/token/index.js +11 -4
  121. package/dist/gs/go/token/index.js.map +1 -1
  122. package/dist/gs/hash/fnv/index.d.ts +57 -0
  123. package/dist/gs/hash/fnv/index.js +299 -0
  124. package/dist/gs/hash/fnv/index.js.map +1 -0
  125. package/dist/gs/hash/index.d.ts +17 -0
  126. package/dist/gs/hash/index.js +94 -0
  127. package/dist/gs/hash/index.js.map +1 -0
  128. package/dist/gs/io/fs/readlink.js +2 -6
  129. package/dist/gs/io/fs/readlink.js.map +1 -1
  130. package/dist/gs/io/fs/walk.js.map +1 -1
  131. package/dist/gs/io/io.d.ts +8 -5
  132. package/dist/gs/io/io.js +20 -2
  133. package/dist/gs/io/io.js.map +1 -1
  134. package/dist/gs/iter/iter.d.ts +3 -2
  135. package/dist/gs/iter/iter.js.map +1 -1
  136. package/dist/gs/maps/iter.d.ts +5 -5
  137. package/dist/gs/maps/iter.js +48 -21
  138. package/dist/gs/maps/iter.js.map +1 -1
  139. package/dist/gs/maps/maps.d.ts +6 -6
  140. package/dist/gs/math/bits/index.js +14 -24
  141. package/dist/gs/math/bits/index.js.map +1 -1
  142. package/dist/gs/mime/index.js +3 -1
  143. package/dist/gs/mime/index.js.map +1 -1
  144. package/dist/gs/net/http/httptest/index.d.ts +20 -1
  145. package/dist/gs/net/http/httptest/index.js +85 -3
  146. package/dist/gs/net/http/httptest/index.js.map +1 -1
  147. package/dist/gs/net/http/index.d.ts +118 -6
  148. package/dist/gs/net/http/index.js +389 -14
  149. package/dist/gs/net/http/index.js.map +1 -1
  150. package/dist/gs/net/http/pprof/index.d.ts +8 -0
  151. package/dist/gs/net/http/pprof/index.js +59 -0
  152. package/dist/gs/net/http/pprof/index.js.map +1 -0
  153. package/dist/gs/os/error.gs.js +9 -7
  154. package/dist/gs/os/error.gs.js.map +1 -1
  155. package/dist/gs/os/types_js.gs.js +95 -15
  156. package/dist/gs/os/types_js.gs.js.map +1 -1
  157. package/dist/gs/os/zero_copy_posix.gs.js +1 -1
  158. package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
  159. package/dist/gs/path/filepath/match.js.map +1 -1
  160. package/dist/gs/path/filepath/path.d.ts +5 -3
  161. package/dist/gs/path/filepath/path.js +65 -10
  162. package/dist/gs/path/filepath/path.js.map +1 -1
  163. package/dist/gs/reflect/index.d.ts +3 -2
  164. package/dist/gs/reflect/index.js +2 -1
  165. package/dist/gs/reflect/index.js.map +1 -1
  166. package/dist/gs/reflect/iter.js +2 -2
  167. package/dist/gs/reflect/iter.js.map +1 -1
  168. package/dist/gs/reflect/map.js +26 -0
  169. package/dist/gs/reflect/map.js.map +1 -1
  170. package/dist/gs/reflect/type.d.ts +24 -5
  171. package/dist/gs/reflect/type.js +390 -38
  172. package/dist/gs/reflect/type.js.map +1 -1
  173. package/dist/gs/reflect/types.d.ts +1 -0
  174. package/dist/gs/reflect/types.js +3 -1
  175. package/dist/gs/reflect/types.js.map +1 -1
  176. package/dist/gs/reflect/value.d.ts +4 -1
  177. package/dist/gs/reflect/value.js +39 -1
  178. package/dist/gs/reflect/value.js.map +1 -1
  179. package/dist/gs/reflect/visiblefields.js +1 -1
  180. package/dist/gs/reflect/visiblefields.js.map +1 -1
  181. package/dist/gs/runtime/debug/index.d.ts +39 -0
  182. package/dist/gs/runtime/debug/index.js +58 -0
  183. package/dist/gs/runtime/debug/index.js.map +1 -1
  184. package/dist/gs/runtime/pprof/index.d.ts +20 -0
  185. package/dist/gs/runtime/pprof/index.js +85 -0
  186. package/dist/gs/runtime/pprof/index.js.map +1 -0
  187. package/dist/gs/runtime/trace/index.d.ts +19 -0
  188. package/dist/gs/runtime/trace/index.js +64 -0
  189. package/dist/gs/runtime/trace/index.js.map +1 -0
  190. package/dist/gs/slices/slices.d.ts +24 -9
  191. package/dist/gs/slices/slices.js +229 -24
  192. package/dist/gs/slices/slices.js.map +1 -1
  193. package/dist/gs/sort/slice.gs.d.ts +5 -3
  194. package/dist/gs/sort/slice.gs.js +55 -17
  195. package/dist/gs/sort/slice.gs.js.map +1 -1
  196. package/dist/gs/strings/builder.js +26 -17
  197. package/dist/gs/strings/builder.js.map +1 -1
  198. package/dist/gs/strings/iter.js +140 -75
  199. package/dist/gs/strings/iter.js.map +1 -1
  200. package/dist/gs/strings/replace.js +2 -2
  201. package/dist/gs/strings/replace.js.map +1 -1
  202. package/dist/gs/strings/strings.js +52 -6
  203. package/dist/gs/strings/strings.js.map +1 -1
  204. package/dist/gs/sync/sync.d.ts +6 -3
  205. package/dist/gs/sync/sync.js +39 -11
  206. package/dist/gs/sync/sync.js.map +1 -1
  207. package/dist/gs/syscall/errors.d.ts +116 -112
  208. package/dist/gs/syscall/errors.js +38 -1
  209. package/dist/gs/syscall/errors.js.map +1 -1
  210. package/dist/gs/syscall/fs.d.ts +2 -8
  211. package/dist/gs/syscall/fs.js.map +1 -1
  212. package/dist/gs/syscall/js/index.js +20 -12
  213. package/dist/gs/syscall/js/index.js.map +1 -1
  214. package/dist/gs/syscall/types.d.ts +4 -1
  215. package/dist/gs/syscall/types.js.map +1 -1
  216. package/dist/gs/testing/testing.d.ts +4 -3
  217. package/dist/gs/testing/testing.js +21 -4
  218. package/dist/gs/testing/testing.js.map +1 -1
  219. package/dist/gs/time/time.js +22 -0
  220. package/dist/gs/time/time.js.map +1 -1
  221. package/dist/gs/unicode/unicode.js.map +1 -1
  222. package/dist/gs/unique/index.js +7 -2
  223. package/dist/gs/unique/index.js.map +1 -1
  224. package/go.mod +8 -8
  225. package/go.sum +14 -23
  226. package/gs/builtin/builtin.ts +364 -37
  227. package/gs/builtin/channel.ts +208 -38
  228. package/gs/builtin/defer.ts +13 -2
  229. package/gs/builtin/hostio.test.ts +1 -0
  230. package/gs/builtin/hostio.ts +38 -0
  231. package/gs/builtin/map.ts +46 -6
  232. package/gs/builtin/print.ts +12 -3
  233. package/gs/builtin/runtime-contract.test.ts +290 -10
  234. package/gs/builtin/slice.test.ts +70 -0
  235. package/gs/builtin/slice.ts +566 -255
  236. package/gs/builtin/type.ts +63 -10
  237. package/gs/builtin/varRef.ts +2 -0
  238. package/gs/bytes/buffer.gs.ts +28 -28
  239. package/gs/bytes/bytes.gs.ts +19 -10
  240. package/gs/bytes/bytes.test.ts +17 -0
  241. package/gs/bytes/iter.gs.ts +13 -14
  242. package/gs/compress/zlib/index.test.ts +28 -0
  243. package/gs/compress/zlib/index.ts +200 -0
  244. package/gs/compress/zlib/meta.json +3 -0
  245. package/gs/context/context.test.ts +36 -2
  246. package/gs/context/context.ts +9 -4
  247. package/gs/crypto/ecdh/index.test.ts +43 -0
  248. package/gs/crypto/ecdh/index.ts +274 -0
  249. package/gs/crypto/ed25519/index.test.ts +41 -0
  250. package/gs/crypto/ed25519/index.ts +238 -0
  251. package/gs/crypto/ed25519/meta.json +13 -0
  252. package/gs/crypto/internal/constanttime/index.test.ts +25 -0
  253. package/gs/crypto/internal/constanttime/index.ts +22 -0
  254. package/gs/crypto/rand/index.test.ts +89 -1
  255. package/gs/crypto/rand/index.ts +103 -1
  256. package/gs/crypto/rand/meta.json +4 -1
  257. package/gs/crypto/sha1/index.test.ts +28 -0
  258. package/gs/crypto/sha1/index.ts +130 -0
  259. package/gs/crypto/sha1/meta.json +8 -0
  260. package/gs/crypto/sha256/index.test.ts +78 -0
  261. package/gs/crypto/sha256/index.ts +150 -0
  262. package/gs/crypto/sha256/meta.json +9 -0
  263. package/gs/crypto/sha512/index.test.ts +31 -0
  264. package/gs/crypto/sha512/index.ts +161 -0
  265. package/gs/crypto/sha512/meta.json +11 -0
  266. package/gs/encoding/json/index.test.ts +25 -3
  267. package/gs/encoding/json/index.ts +21 -3
  268. package/gs/errors/errors.test.ts +4 -1
  269. package/gs/errors/errors.ts +32 -8
  270. package/gs/fmt/fmt.test.ts +23 -1
  271. package/gs/fmt/fmt.ts +76 -10
  272. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +62 -7
  273. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +78 -36
  274. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +32 -11
  275. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +122 -43
  276. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
  277. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +518 -4
  278. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +6 -0
  279. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +30 -0
  280. package/gs/github.com/aperturerobotics/util/conc/index.ts +172 -0
  281. package/gs/github.com/aperturerobotics/util/conc/meta.json +9 -0
  282. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +1 -4
  283. package/gs/github.com/hack-pad/safejs/internal/catch/index.test.ts +35 -0
  284. package/gs/github.com/hack-pad/safejs/internal/catch/index.ts +65 -0
  285. package/gs/github.com/hack-pad/safejs/internal/catch/meta.json +9 -0
  286. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +2 -1
  287. package/gs/github.com/klauspost/compress/internal/le/index.ts +6 -5
  288. package/gs/github.com/mr-tron/base58/base58/index.test.ts +70 -0
  289. package/gs/github.com/mr-tron/base58/base58/index.ts +231 -0
  290. package/gs/github.com/mr-tron/base58/base58/meta.json +3 -0
  291. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +46 -0
  292. package/gs/github.com/zeebo/blake3/internal/consts/index.ts +26 -0
  293. package/gs/go/token/index.ts +17 -4
  294. package/gs/hash/fnv/index.test.ts +67 -0
  295. package/gs/hash/fnv/index.ts +351 -0
  296. package/gs/hash/fnv/meta.json +3 -0
  297. package/gs/hash/index.test.ts +37 -0
  298. package/gs/hash/index.ts +118 -0
  299. package/gs/hash/meta.json +5 -0
  300. package/gs/internal/byteorder/index.test.ts +6 -6
  301. package/gs/io/fs/readlink.ts +40 -48
  302. package/gs/io/fs/walk.ts +10 -2
  303. package/gs/io/io.test.ts +64 -0
  304. package/gs/io/io.ts +34 -13
  305. package/gs/iter/iter.ts +8 -2
  306. package/gs/maps/iter.ts +69 -26
  307. package/gs/maps/maps.test.ts +23 -0
  308. package/gs/maps/maps.ts +6 -6
  309. package/gs/math/bits/index.test.ts +20 -0
  310. package/gs/math/bits/index.ts +15 -28
  311. package/gs/mime/index.ts +8 -2
  312. package/gs/net/http/httptest/index.test.ts +85 -0
  313. package/gs/net/http/httptest/index.ts +113 -3
  314. package/gs/net/http/index.test.ts +159 -1
  315. package/gs/net/http/index.ts +515 -15
  316. package/gs/net/http/meta.json +6 -0
  317. package/gs/net/http/pprof/index.test.ts +47 -0
  318. package/gs/net/http/pprof/index.ts +65 -0
  319. package/gs/os/error.gs.ts +9 -10
  320. package/gs/os/error.test.ts +41 -0
  321. package/gs/os/file_unix_js.test.ts +55 -0
  322. package/gs/os/tempfile.gs.test.ts +37 -10
  323. package/gs/os/types_js.gs.ts +94 -15
  324. package/gs/os/zero_copy_posix.gs.ts +1 -2
  325. package/gs/path/filepath/match.ts +4 -1
  326. package/gs/path/filepath/meta.json +6 -0
  327. package/gs/path/filepath/path.test.ts +57 -2
  328. package/gs/path/filepath/path.ts +91 -12
  329. package/gs/reflect/field.test.ts +63 -0
  330. package/gs/reflect/index.ts +4 -1
  331. package/gs/reflect/iter.ts +2 -2
  332. package/gs/reflect/map.test.ts +24 -2
  333. package/gs/reflect/map.ts +35 -0
  334. package/gs/reflect/type.ts +543 -60
  335. package/gs/reflect/typefor.test.ts +100 -0
  336. package/gs/reflect/types.ts +3 -1
  337. package/gs/reflect/value.ts +50 -1
  338. package/gs/reflect/visiblefields.ts +1 -1
  339. package/gs/runtime/debug/index.test.ts +22 -1
  340. package/gs/runtime/debug/index.ts +88 -0
  341. package/gs/runtime/pprof/index.test.ts +36 -0
  342. package/gs/runtime/pprof/index.ts +104 -0
  343. package/gs/runtime/pprof/meta.json +6 -0
  344. package/gs/runtime/trace/index.test.ts +45 -0
  345. package/gs/runtime/trace/index.ts +97 -0
  346. package/gs/runtime/trace/meta.json +7 -0
  347. package/gs/slices/meta.json +2 -1
  348. package/gs/slices/slices.test.ts +86 -0
  349. package/gs/slices/slices.ts +284 -37
  350. package/gs/sort/slice.gs.ts +73 -23
  351. package/gs/sort/slice.test.ts +40 -0
  352. package/gs/strings/builder.test.ts +8 -0
  353. package/gs/strings/builder.ts +29 -17
  354. package/gs/strings/iter.test.ts +5 -7
  355. package/gs/strings/iter.ts +146 -71
  356. package/gs/strings/replace.test.ts +1 -4
  357. package/gs/strings/replace.ts +6 -6
  358. package/gs/strings/strings.test.ts +4 -0
  359. package/gs/strings/strings.ts +54 -6
  360. package/gs/sync/meta.json +1 -0
  361. package/gs/sync/sync.test.ts +57 -1
  362. package/gs/sync/sync.ts +45 -13
  363. package/gs/syscall/errors.ts +158 -115
  364. package/gs/syscall/fs.ts +8 -8
  365. package/gs/syscall/js/index.ts +49 -22
  366. package/gs/syscall/net.test.ts +26 -0
  367. package/gs/syscall/types.ts +7 -2
  368. package/gs/testing/testing.test.ts +56 -0
  369. package/gs/testing/testing.ts +27 -10
  370. package/gs/time/meta.json +2 -2
  371. package/gs/time/time.test.ts +4 -0
  372. package/gs/time/time.ts +33 -2
  373. package/gs/unicode/unicode.test.ts +14 -3
  374. package/gs/unicode/unicode.ts +1 -5
  375. package/gs/unique/index.ts +9 -2
  376. package/package.json +3 -3
@@ -7,7 +7,9 @@ import (
7
7
  "io"
8
8
  "io/fs"
9
9
  "maps"
10
+ "os"
10
11
  "path"
12
+ "path/filepath"
11
13
  "slices"
12
14
  "strings"
13
15
 
@@ -26,6 +28,12 @@ type overridePackageFacts struct {
26
28
  dependencies []string
27
29
  }
28
30
 
31
+ type overridePackageRoot struct {
32
+ pkgPath string
33
+ fsys fs.FS
34
+ dir string
35
+ }
36
+
29
37
  // HasPackage returns true when pkgPath has a GoScript override package.
30
38
  func (f *OverrideFacts) HasPackage(pkgPath string) bool {
31
39
  if f == nil || pkgPath == "" {
@@ -93,10 +101,10 @@ func (f *OverrideFacts) importPackageRoot(importPath string) (string, bool) {
93
101
  return "", false
94
102
  }
95
103
 
96
- func buildOverrideFacts(ctx context.Context) (*OverrideFacts, []Diagnostic) {
97
- roots, err := discoverOverridePackageRoots()
98
- if err != nil {
99
- return nil, []Diagnostic{overrideError("discover override packages", "", err)}
104
+ func buildOverrideFacts(ctx context.Context, overrideDirs []string) (*OverrideFacts, []Diagnostic) {
105
+ roots, diagnostics := discoverOverridePackageRoots(overrideDirs)
106
+ if diagnosticsHaveErrors(diagnostics) {
107
+ return nil, diagnostics
100
108
  }
101
109
  paths := make([]string, 0, len(roots))
102
110
  for pkgPath := range roots {
@@ -105,17 +113,16 @@ func buildOverrideFacts(ctx context.Context) (*OverrideFacts, []Diagnostic) {
105
113
  slices.Sort(paths)
106
114
 
107
115
  facts := &OverrideFacts{packages: make(map[string]overridePackageFacts, len(paths))}
108
- var diagnostics []Diagnostic
109
116
  for _, pkgPath := range paths {
110
117
  if err := ctx.Err(); err != nil {
111
118
  return facts, []Diagnostic{contextCanceledDiagnostic(err)}
112
119
  }
113
- metadata, err := loadOverrideMetadata(pkgPath)
120
+ metadata, err := loadOverrideMetadata(roots[pkgPath])
114
121
  if err != nil {
115
122
  diagnostics = append(diagnostics, overrideError("read override metadata", pkgPath, err))
116
123
  continue
117
124
  }
118
- copyPackage, dependencies, packageDiagnostics := loadOverrideCopyPackage(pkgPath, roots, metadata)
125
+ copyPackage, dependencies, packageDiagnostics := loadOverrideCopyPackage(roots[pkgPath], roots, metadata)
119
126
  diagnostics = append(diagnostics, packageDiagnostics...)
120
127
  if diagnosticsHaveErrors(packageDiagnostics) {
121
128
  continue
@@ -132,29 +139,62 @@ func buildOverrideFacts(ctx context.Context) (*OverrideFacts, []Diagnostic) {
132
139
  return facts, diagnostics
133
140
  }
134
141
 
135
- func discoverOverridePackageRoots() (map[string]bool, error) {
136
- roots := make(map[string]bool)
137
- if err := fs.WalkDir(gs.GsOverrides, "gs", func(filePath string, entry fs.DirEntry, err error) error {
142
+ func discoverOverridePackageRoots(overrideDirs []string) (map[string]overridePackageRoot, []Diagnostic) {
143
+ roots := make(map[string]overridePackageRoot)
144
+ var diagnostics []Diagnostic
145
+ for _, dir := range overrideDirs {
146
+ dir = strings.TrimSpace(dir)
147
+ if dir == "" {
148
+ continue
149
+ }
150
+ abs, err := filepath.Abs(dir)
151
+ if err != nil {
152
+ diagnostics = append(diagnostics, overrideError("resolve override directory", dir, err))
153
+ continue
154
+ }
155
+ if err := discoverOverridePackageRootsInFS(roots, os.DirFS(abs), ".", false); err != nil {
156
+ diagnostics = append(diagnostics, overrideError("discover override packages", abs, err))
157
+ }
158
+ }
159
+ if err := discoverOverridePackageRootsInFS(roots, gs.GsOverrides, "gs", true); err != nil {
160
+ diagnostics = append(diagnostics, overrideError("discover override packages", "embedded gs", err))
161
+ }
162
+ return roots, diagnostics
163
+ }
164
+
165
+ func discoverOverridePackageRootsInFS(
166
+ roots map[string]overridePackageRoot,
167
+ fsys fs.FS,
168
+ rootDir string,
169
+ embedded bool,
170
+ ) error {
171
+ return fs.WalkDir(fsys, rootDir, func(filePath string, entry fs.DirEntry, err error) error {
138
172
  if err != nil {
139
173
  return err
140
174
  }
141
175
  if entry.IsDir() || path.Base(filePath) != "index.ts" {
142
176
  return nil
143
177
  }
144
- pkgPath := strings.TrimPrefix(path.Dir(filePath), "gs/")
178
+ pkgPath := strings.TrimPrefix(path.Dir(filePath), rootDir+"/")
179
+ if rootDir == "." {
180
+ pkgPath = path.Dir(filePath)
181
+ }
145
182
  if pkgPath != "." && pkgPath != "" {
146
- roots[pkgPath] = true
183
+ if _, exists := roots[pkgPath]; !exists || !embedded {
184
+ roots[pkgPath] = overridePackageRoot{
185
+ pkgPath: pkgPath,
186
+ fsys: fsys,
187
+ dir: path.Dir(filePath),
188
+ }
189
+ }
147
190
  }
148
191
  return nil
149
- }); err != nil {
150
- return nil, err
151
- }
152
- return roots, nil
192
+ })
153
193
  }
154
194
 
155
- func loadOverrideMetadata(pkgPath string) (OverrideMetadata, error) {
195
+ func loadOverrideMetadata(root overridePackageRoot) (OverrideMetadata, error) {
156
196
  metadata := newOverrideMetadata()
157
- data, err := gs.GsOverrides.ReadFile("gs/" + pkgPath + "/meta.json")
197
+ data, err := fs.ReadFile(root.fsys, path.Join(root.dir, "meta.json"))
158
198
  if err != nil {
159
199
  if errors.Is(err, fs.ErrNotExist) {
160
200
  return metadata, nil
@@ -188,11 +228,12 @@ func loadOverrideMetadata(pkgPath string) (OverrideMetadata, error) {
188
228
  }
189
229
 
190
230
  func loadOverrideCopyPackage(
191
- pkgPath string,
192
- roots map[string]bool,
231
+ root overridePackageRoot,
232
+ roots map[string]overridePackageRoot,
193
233
  metadata OverrideMetadata,
194
234
  ) (overrideCopyPackage, []string, []Diagnostic) {
195
- if !roots[pkgPath] {
235
+ pkgPath := root.pkgPath
236
+ if _, ok := roots[pkgPath]; !ok {
196
237
  return overrideCopyPackage{}, nil, []Diagnostic{{
197
238
  Severity: DiagnosticSeverityError,
198
239
  Code: "goscript/overrides:missing-package",
@@ -215,14 +256,18 @@ func loadOverrideCopyPackage(
215
256
  }
216
257
  }
217
258
 
218
- root := "gs/" + pkgPath
219
- err := fs.WalkDir(gs.GsOverrides, root, func(filePath string, entry fs.DirEntry, walkErr error) error {
259
+ err := fs.WalkDir(root.fsys, root.dir, func(filePath string, entry fs.DirEntry, walkErr error) error {
220
260
  if walkErr != nil {
221
261
  return walkErr
222
262
  }
223
263
  if entry.IsDir() {
224
- nestedPkg := strings.TrimPrefix(filePath, "gs/")
225
- if nestedPkg != pkgPath && roots[nestedPkg] {
264
+ nestedPkg := strings.TrimPrefix(filePath, root.dir+"/")
265
+ if root.dir == "." {
266
+ nestedPkg = filePath
267
+ } else if nestedPkg != filePath {
268
+ nestedPkg = path.Join(pkgPath, nestedPkg)
269
+ }
270
+ if _, ok := roots[nestedPkg]; nestedPkg != pkgPath && ok {
226
271
  return fs.SkipDir
227
272
  }
228
273
  return nil
@@ -230,11 +275,16 @@ func loadOverrideCopyPackage(
230
275
  if !isOverrideSourceFile(filePath) {
231
276
  return nil
232
277
  }
233
- data, readErr := gs.GsOverrides.ReadFile(filePath)
278
+ data, readErr := fs.ReadFile(root.fsys, filePath)
234
279
  if readErr != nil {
235
280
  return readErr
236
281
  }
237
- rel := strings.TrimPrefix(filePath, "gs/")
282
+ rel := strings.TrimPrefix(filePath, root.dir+"/")
283
+ if root.dir == "." {
284
+ rel = filePath
285
+ } else if rel != filePath {
286
+ rel = path.Join(pkgPath, rel)
287
+ }
238
288
  copyPackage.files = append(copyPackage.files, overrideCopyFile{
239
289
  path: rel,
240
290
  data: data,
@@ -20,12 +20,13 @@ type OverrideMetadata struct {
20
20
 
21
21
  // OverrideRegistryOwner owns GoScript override package metadata and copy plans.
22
22
  type OverrideRegistryOwner struct {
23
- facts *OverrideFacts
23
+ overrideDirs []string
24
+ facts *OverrideFacts
24
25
  }
25
26
 
26
27
  // NewOverrideRegistryOwner creates the override registry owner.
27
- func NewOverrideRegistryOwner() *OverrideRegistryOwner {
28
- return &OverrideRegistryOwner{}
28
+ func NewOverrideRegistryOwner(overrideDirs ...string) *OverrideRegistryOwner {
29
+ return &OverrideRegistryOwner{overrideDirs: slices.Clone(overrideDirs)}
29
30
  }
30
31
 
31
32
  // Facts returns the immutable compiler-visible override facts.
@@ -36,7 +37,7 @@ func (o *OverrideRegistryOwner) Facts(ctx context.Context) (*OverrideFacts, []Di
36
37
  if o.facts != nil {
37
38
  return o.facts, nil
38
39
  }
39
- facts, diagnostics := buildOverrideFacts(ctx)
40
+ facts, diagnostics := buildOverrideFacts(ctx, o.overrideDirs)
40
41
  if diagnosticsHaveErrors(diagnostics) {
41
42
  return facts, diagnostics
42
43
  }
@@ -118,6 +118,47 @@ func TestOverrideRegistryCopiesRuntimeAndOverrides(t *testing.T) {
118
118
  }
119
119
  }
120
120
 
121
+ func TestOverrideRegistryCopiesExternalOverride(t *testing.T) {
122
+ overrideDir := filepath.Join(t.TempDir(), "gs")
123
+ writeFixtureFile(t, overrideDir, "example.test/lib/index.ts", strings.Join([]string{
124
+ "import * as helper from '@goscript/example.test/helper/index.js'",
125
+ "export function Run(): void { helper.Run() }",
126
+ "",
127
+ }, "\n"))
128
+ writeFixtureFile(t, overrideDir, "example.test/lib/meta.json", `{"dependencies":["example.test/helper"]}`)
129
+ writeFixtureFile(t, overrideDir, "example.test/helper/index.ts", "export function Run(): void {}\n")
130
+
131
+ owner := NewOverrideRegistryOwner(overrideDir)
132
+ req := &CompileRequest{
133
+ OutputPath: filepath.Join(t.TempDir(), "out"),
134
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
135
+ }
136
+ plan, diagnostics := owner.CopyPlan(context.Background(), req, &PackageGraph{Nodes: []*PackageGraphNode{{
137
+ PkgPath: "example.test/lib",
138
+ OverrideCandidate: true,
139
+ }}})
140
+ if diagnosticsHaveErrors(diagnostics) {
141
+ t.Fatalf("copy plan failed: %#v", diagnostics)
142
+ }
143
+ copied, diagnostics := owner.CopyPackages(context.Background(), req, plan)
144
+ if diagnosticsHaveErrors(diagnostics) {
145
+ t.Fatalf("copy failed: %#v", diagnostics)
146
+ }
147
+ for _, pkg := range []string{"builtin", "example.test/helper", "example.test/lib"} {
148
+ if !slices.Contains(copied, pkg) {
149
+ t.Fatalf("missing copied package %s in %v", pkg, copied)
150
+ }
151
+ }
152
+ for _, path := range []string{
153
+ "@goscript/example.test/helper/index.ts",
154
+ "@goscript/example.test/lib/index.ts",
155
+ } {
156
+ if _, err := os.Stat(filepath.Join(req.OutputPath, filepath.FromSlash(path))); err != nil {
157
+ t.Fatalf("expected copied file %s: %v", path, err)
158
+ }
159
+ }
160
+ }
161
+
121
162
  func TestOverrideRegistryReportsMissingOverridePackage(t *testing.T) {
122
163
  _, diagnostics := NewOverrideRegistryOwner().CopyPlan(context.Background(), &CompileRequest{
123
164
  RuntimeEmissionMode: RuntimeEmissionModeEmit,
@@ -252,3 +293,140 @@ func TestCompilePackagesAwaitsOverrideAsyncMethods(t *testing.T) {
252
293
  t.Fatalf("override async method call was not awaited:\n%s", string(content))
253
294
  }
254
295
  }
296
+
297
+ func TestCompilePackagesPropagatesOverrideAsyncInterfaceMethods(t *testing.T) {
298
+ moduleDir := writePackageGraphFixture(t, map[string]string{
299
+ "go.mod": "module example.test/overrideasynciface\n\ngo 1.25.3\n",
300
+ "main.go": strings.Join([]string{
301
+ "package main",
302
+ "import \"net/http\"",
303
+ "type client struct { rt http.RoundTripper }",
304
+ "func (c *client) Do(req *http.Request) (*http.Response, error) {",
305
+ " return c.rt.RoundTrip(req)",
306
+ "}",
307
+ "func Use(c *client, req *http.Request) (*http.Response, error) {",
308
+ " return c.Do(req)",
309
+ "}",
310
+ "func main() {}",
311
+ "",
312
+ }, "\n"),
313
+ })
314
+ out := filepath.Join(t.TempDir(), "out")
315
+ comp, err := NewCompiler(&Config{
316
+ Dir: moduleDir,
317
+ OutputPath: out,
318
+ AllDependencies: true,
319
+ }, nil, nil)
320
+ if err != nil {
321
+ t.Fatal(err.Error())
322
+ }
323
+
324
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
325
+ t.Fatal(err.Error())
326
+ }
327
+ content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "overrideasynciface", "main.gs.ts"))
328
+ if err != nil {
329
+ t.Fatal(err.Error())
330
+ }
331
+ text := string(content)
332
+ for _, want := range []string{
333
+ "public async Do(req: http.Request | $.VarRef<http.Request> | null): globalThis.Promise<[http.Response | $.VarRef<http.Response> | null, $.GoError]>",
334
+ "return await $.pointerValue<Exclude<http.RoundTripper, null>>($.pointerValue<client>(c).rt).RoundTrip(req)",
335
+ "export async function Use(c: client | $.VarRef<client> | null, req: http.Request | $.VarRef<http.Request> | null): globalThis.Promise<[http.Response | $.VarRef<http.Response> | null, $.GoError]>",
336
+ "return await client.prototype.Do.call(c, req)",
337
+ } {
338
+ if !strings.Contains(text, want) {
339
+ t.Fatalf("missing %q in generated output:\n%s", want, text)
340
+ }
341
+ }
342
+ }
343
+
344
+ func TestCompilePackagesAwaitsOverrideAsyncInterfaceMethodCalls(t *testing.T) {
345
+ moduleDir := writePackageGraphFixture(t, map[string]string{
346
+ "go.mod": "module example.test/overrideasyncinterfacemethod\n\ngo 1.25.3\n",
347
+ "main.go": strings.Join([]string{
348
+ "package main",
349
+ "import \"sync\"",
350
+ "func Use(l sync.Locker) {",
351
+ " l.Lock()",
352
+ " l.Unlock()",
353
+ "}",
354
+ "func main() {}",
355
+ "",
356
+ }, "\n"),
357
+ })
358
+ out := filepath.Join(t.TempDir(), "out")
359
+ comp, err := NewCompiler(&Config{
360
+ Dir: moduleDir,
361
+ OutputPath: out,
362
+ AllDependencies: true,
363
+ }, nil, nil)
364
+ if err != nil {
365
+ t.Fatal(err.Error())
366
+ }
367
+
368
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
369
+ t.Fatal(err.Error())
370
+ }
371
+ content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "overrideasyncinterfacemethod", "main.gs.ts"))
372
+ if err != nil {
373
+ t.Fatal(err.Error())
374
+ }
375
+ text := string(content)
376
+ for _, want := range []string{
377
+ "export async function Use(l: sync.Locker | null): globalThis.Promise<void>",
378
+ "await $.pointerValue<Exclude<sync.Locker, null>>(l).Lock()",
379
+ "$.pointerValue<Exclude<sync.Locker, null>>(l).Unlock()",
380
+ } {
381
+ if !strings.Contains(text, want) {
382
+ t.Fatalf("missing %q in generated output:\n%s", want, text)
383
+ }
384
+ }
385
+ }
386
+
387
+ func TestCompilePackagesAwaitsOverrideAsyncFunctions(t *testing.T) {
388
+ moduleDir := writePackageGraphFixture(t, map[string]string{
389
+ "go.mod": "module example.test/overrideasyncfunc\n\ngo 1.25.3\n",
390
+ "main.go": strings.Join([]string{
391
+ "package main",
392
+ "import (",
393
+ " \"io/fs\"",
394
+ " \"path/filepath\"",
395
+ " \"sync\"",
396
+ ")",
397
+ "func main() {",
398
+ " var m sync.Map",
399
+ " _ = filepath.WalkDir(\".\", func(path string, d fs.DirEntry, err error) error {",
400
+ " if _, ok := m.Load(path); ok {",
401
+ " return nil",
402
+ " }",
403
+ " return nil",
404
+ " })",
405
+ "}",
406
+ "",
407
+ }, "\n"),
408
+ })
409
+ out := filepath.Join(t.TempDir(), "out")
410
+ comp, err := NewCompiler(&Config{
411
+ Dir: moduleDir,
412
+ OutputPath: out,
413
+ AllDependencies: true,
414
+ }, nil, nil)
415
+ if err != nil {
416
+ t.Fatal(err.Error())
417
+ }
418
+
419
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
420
+ t.Fatal(err.Error())
421
+ }
422
+ content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "overrideasyncfunc", "main.gs.ts"))
423
+ if err != nil {
424
+ t.Fatal(err.Error())
425
+ }
426
+ if !strings.Contains(string(content), "await filepath.WalkDir") {
427
+ t.Fatalf("override async function call was not awaited:\n%s", string(content))
428
+ }
429
+ if !strings.Contains(string(content), "$.functionValue(async") {
430
+ t.Fatalf("walk callback was not lowered as async:\n%s", string(content))
431
+ }
432
+ }
@@ -258,6 +258,55 @@ func TestPackageGraphDetectsOverrideCandidates(t *testing.T) {
258
258
  }
259
259
  }
260
260
 
261
+ func TestPackageGraphDetectsExternalOverrideCandidates(t *testing.T) {
262
+ moduleDir := writePackageGraphFixture(t, map[string]string{
263
+ "go.mod": strings.Join([]string{
264
+ "module example.test/externaloverride",
265
+ "",
266
+ "go 1.25.3",
267
+ "",
268
+ "require example.test/lib v0.0.0",
269
+ "replace example.test/lib => ./lib",
270
+ "",
271
+ }, "\n"),
272
+ "main.go": "package main\nimport \"example.test/lib\"\nfunc main() { lib.Run() }\n",
273
+ "lib/go.mod": strings.Join([]string{
274
+ "module example.test/lib",
275
+ "",
276
+ "go 1.25.3",
277
+ "",
278
+ "require example.test/heavy v0.0.0",
279
+ "replace example.test/heavy => ../heavy",
280
+ "",
281
+ }, "\n"),
282
+ "lib/lib.go": "package lib\nimport \"example.test/heavy\"\nfunc Run() { heavy.Run() }\n",
283
+ "heavy/go.mod": "module example.test/heavy\n\ngo 1.25.3\n",
284
+ "heavy/heavy.go": "package heavy\nfunc Run() {}\n",
285
+ })
286
+ overrideDir := filepath.Join(t.TempDir(), "gs")
287
+ writeFixtureFile(t, overrideDir, "example.test/lib/index.ts", "export function Run(): void {}\n")
288
+
289
+ overrideOwner := NewOverrideRegistryOwner(overrideDir)
290
+ req := &CompileRequest{
291
+ Patterns: []string{"."},
292
+ Dir: moduleDir,
293
+ OutputPath: filepath.Join(t.TempDir(), "out"),
294
+ DependencyMode: DependencyModeAll,
295
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
296
+ }
297
+ graph, diagnostics := NewPackageGraphOwner(overrideOwner).Load(context.Background(), req)
298
+ if diagnosticsHaveErrors(diagnostics) {
299
+ t.Fatalf("package graph failed: %#v", diagnostics)
300
+ }
301
+ lib := graph.NodesByPackagePath["example.test/lib"]
302
+ if lib == nil || !lib.OverrideCandidate {
303
+ t.Fatalf("expected external override candidate for lib")
304
+ }
305
+ if graph.NodesByPackagePath["example.test/heavy"] != nil {
306
+ t.Fatalf("external override dependency should not be collected")
307
+ }
308
+ }
309
+
261
310
  func TestPackageGraphOverrideCandidatesRequirePackageIndex(t *testing.T) {
262
311
  parent := "github.com/aperturerobotics/wasivm/wazero/kernel"
263
312
  child := parent + "/runtime"
@@ -293,17 +342,23 @@ func writePackageGraphFixture(t *testing.T, files map[string]string) string {
293
342
 
294
343
  dir := t.TempDir()
295
344
  for name, contents := range files {
296
- path := filepath.Join(dir, name)
297
- if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
298
- t.Fatal(err.Error())
299
- }
300
- if err := os.WriteFile(path, []byte(contents), 0o644); err != nil {
301
- t.Fatal(err.Error())
302
- }
345
+ writeFixtureFile(t, dir, name, contents)
303
346
  }
304
347
  return dir
305
348
  }
306
349
 
350
+ func writeFixtureFile(t *testing.T, root, name, contents string) {
351
+ t.Helper()
352
+
353
+ path := filepath.Join(root, filepath.FromSlash(name))
354
+ if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
355
+ t.Fatal(err.Error())
356
+ }
357
+ if err := os.WriteFile(path, []byte(contents), 0o644); err != nil {
358
+ t.Fatal(err.Error())
359
+ }
360
+ }
361
+
307
362
  func requireDiagnosticCode(t *testing.T, diagnostics []Diagnostic, code string) {
308
363
  t.Helper()
309
364
 
@@ -2,8 +2,8 @@ package compiler
2
2
 
3
3
  import (
4
4
  "go/ast"
5
- "go/types"
6
5
  "slices"
6
+ "strconv"
7
7
  "strings"
8
8
  "unicode"
9
9
 
@@ -57,13 +57,10 @@ func discoverPackageTestFunctions(pkg *packages.Package) []PackageTestFunction {
57
57
  }
58
58
  var tests []PackageTestFunction
59
59
  for _, file := range pkg.Syntax {
60
+ testingAliases := fileTestingAliases(file)
60
61
  for _, decl := range file.Decls {
61
- fn, ok := decl.(*ast.FuncDecl)
62
- if !ok || fn.Recv != nil || !isTestName(fn.Name.Name) {
63
- continue
64
- }
65
- obj, _ := pkg.TypesInfo.Defs[fn.Name].(*types.Func)
66
- if !isOrdinaryTestFunc(obj) {
62
+ fn, _ := decl.(*ast.FuncDecl)
63
+ if !isOrdinaryTestFuncDecl(fn, testingAliases) {
67
64
  continue
68
65
  }
69
66
  tests = append(tests, PackageTestFunction{
@@ -75,23 +72,50 @@ func discoverPackageTestFunctions(pkg *packages.Package) []PackageTestFunction {
75
72
  return tests
76
73
  }
77
74
 
78
- func isOrdinaryTestFunc(fn *types.Func) bool {
79
- if fn == nil {
75
+ func isOrdinaryTestFuncDecl(fn *ast.FuncDecl, testingAliases map[string]bool) bool {
76
+ if fn == nil || fn.Recv != nil || !isTestName(fn.Name.Name) || fn.Type == nil {
77
+ return false
78
+ }
79
+ if fn.Type.Results != nil && len(fn.Type.Results.List) != 0 {
80
80
  return false
81
81
  }
82
- sig, _ := fn.Type().(*types.Signature)
83
- if sig == nil || sig.Params().Len() != 1 || sig.Results().Len() != 0 {
82
+ if fn.Type.Params == nil || len(fn.Type.Params.List) != 1 {
84
83
  return false
85
84
  }
86
- ptr, _ := sig.Params().At(0).Type().(*types.Pointer)
87
- if ptr == nil {
85
+ param := fn.Type.Params.List[0]
86
+ if len(param.Names) > 1 {
88
87
  return false
89
88
  }
90
- named, _ := ptr.Elem().(*types.Named)
91
- if named == nil || named.Obj() == nil || named.Obj().Pkg() == nil {
89
+ ptr, ok := param.Type.(*ast.StarExpr)
90
+ return ok && isTestingT(ptr.X, testingAliases)
91
+ }
92
+
93
+ func fileTestingAliases(file *ast.File) map[string]bool {
94
+ aliases := make(map[string]bool)
95
+ for _, imp := range file.Imports {
96
+ path, err := strconv.Unquote(imp.Path.Value)
97
+ if err != nil || path != "testing" {
98
+ continue
99
+ }
100
+ name := "testing"
101
+ if imp.Name != nil {
102
+ name = imp.Name.Name
103
+ }
104
+ aliases[name] = true
105
+ }
106
+ return aliases
107
+ }
108
+
109
+ func isTestingT(expr ast.Expr, aliases map[string]bool) bool {
110
+ switch typed := expr.(type) {
111
+ case *ast.SelectorExpr:
112
+ base, _ := typed.X.(*ast.Ident)
113
+ return base != nil && aliases[base.Name] && typed.Sel.Name == "T"
114
+ case *ast.Ident:
115
+ return aliases["."] && typed.Name == "T"
116
+ default:
92
117
  return false
93
118
  }
94
- return named.Obj().Name() == "T" && named.Obj().Pkg().Path() == "testing"
95
119
  }
96
120
 
97
121
  func isTestName(name string) bool {
@@ -47,12 +47,7 @@ func (o *PackageGraphOwner) LoadTestGraph(ctx context.Context, req *CompileReque
47
47
  packages.NeedFiles |
48
48
  packages.NeedCompiledGoFiles |
49
49
  packages.NeedImports |
50
- packages.NeedDeps |
51
- packages.NeedExportFile |
52
- packages.NeedTypes |
53
50
  packages.NeedSyntax |
54
- packages.NeedTypesInfo |
55
- packages.NeedTypesSizes |
56
51
  packages.NeedForTest |
57
52
  packages.NeedModule,
58
53
  }
@@ -3,6 +3,7 @@ package compiler
3
3
  import (
4
4
  "context"
5
5
  "path/filepath"
6
+ "slices"
6
7
  "strings"
7
8
  "testing"
8
9
  )
@@ -21,9 +22,11 @@ func TestPackageGraphOwnerLoadTestGraphFacts(t *testing.T) {
21
22
  "same/value_test.go": strings.Join([]string{
22
23
  "package same",
23
24
  "",
24
- "import \"testing\"",
25
+ "import testpkg \"testing\"",
25
26
  "",
26
- "func TestAdd(t *testing.T) {}",
27
+ "func TestAdd(t *testpkg.T) {}",
28
+ "func TestIgnoredBadSignature(t *badT) {}",
29
+ "type badT struct{}",
27
30
  "",
28
31
  }, "\n"),
29
32
  "external/value.go": strings.Join([]string{
@@ -69,6 +72,9 @@ func TestPackageGraphOwnerLoadTestGraphFacts(t *testing.T) {
69
72
  if same == nil || same.SamePackageTests == nil || same.ExternalPackageTests != nil || !same.HasTests() {
70
73
  t.Fatalf("unexpected same-package facts: %#v", same)
71
74
  }
75
+ if len(same.SamePackageTests.Tests) != 1 || same.SamePackageTests.Tests[0].Name != "TestAdd" {
76
+ t.Fatalf("same-package test discovery should keep only ordinary tests: %#v", same.SamePackageTests.Tests)
77
+ }
72
78
  external := graph.PackageByPath("example.test/testgraph/external")
73
79
  if external == nil || external.ExternalPackageTests == nil || external.SamePackageTests != nil || !external.HasTests() {
74
80
  t.Fatalf("unexpected external-package facts: %#v", external)
@@ -105,7 +111,7 @@ func TestPackageGraphOwnerLoadTestGraphScopesDiagnostics(t *testing.T) {
105
111
  "import \"testing\"",
106
112
  "",
107
113
  "func TestBroken(t *testing.T) {",
108
- "\tMissing()",
114
+ "\tif {",
109
115
  "}",
110
116
  "",
111
117
  }, "\n"),
@@ -133,6 +139,58 @@ func TestPackageGraphOwnerLoadTestGraphScopesDiagnostics(t *testing.T) {
133
139
  }
134
140
  }
135
141
 
142
+ func TestPackageGraphOwnerLoadTestGraphDoesNotLoadDependencies(t *testing.T) {
143
+ moduleDir := writePackageGraphFixture(t, map[string]string{
144
+ "go.mod": "module example.test/testgraphdeps\n\ngo 1.25.3\n",
145
+ "clean/value.go": strings.Join([]string{
146
+ "package clean",
147
+ "",
148
+ "func Value() int {",
149
+ "\treturn 1",
150
+ "}",
151
+ "",
152
+ }, "\n"),
153
+ "clean/value_test.go": strings.Join([]string{
154
+ "package clean",
155
+ "",
156
+ "import (",
157
+ "\t\"testing\"",
158
+ "",
159
+ "\t\"example.test/testgraphdeps/brokendep\"",
160
+ ")",
161
+ "",
162
+ "func TestValue(t *testing.T) {",
163
+ "\t_ = brokendep.Value",
164
+ "}",
165
+ "",
166
+ }, "\n"),
167
+ "brokendep/value.go": strings.Join([]string{
168
+ "package brokendep",
169
+ "",
170
+ "const Value =",
171
+ "",
172
+ }, "\n"),
173
+ })
174
+
175
+ graph, diagnostics := loadPackageTestGraph(t, &CompileRequest{
176
+ Patterns: []string{"./clean"},
177
+ Dir: moduleDir,
178
+ OutputPath: filepath.Join(t.TempDir(), "out"),
179
+ DependencyMode: DependencyModeRequested,
180
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
181
+ })
182
+ if diagnosticsHaveErrors(diagnostics) {
183
+ t.Fatalf("test graph discovery should not load dependency bodies: %#v", diagnostics)
184
+ }
185
+ clean := graph.PackageByPath("example.test/testgraphdeps/clean")
186
+ if clean == nil || clean.SamePackageTests == nil || len(clean.SamePackageTests.Tests) != 1 {
187
+ t.Fatalf("clean package test discovery failed: %#v", clean)
188
+ }
189
+ if !slices.Contains(clean.SamePackageTests.Imports, "example.test/testgraphdeps/brokendep") {
190
+ t.Fatalf("test graph should retain direct test imports: %#v", clean.SamePackageTests.Imports)
191
+ }
192
+ }
193
+
136
194
  func loadPackageTestGraph(t *testing.T, req *CompileRequest) (*PackageTestGraph, []Diagnostic) {
137
195
  t.Helper()
138
196