goscript 0.1.0 → 0.1.1

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 (327) hide show
  1. package/README.md +267 -255
  2. package/cmd/goscript/cmd-test.go +193 -0
  3. package/cmd/goscript/cmd-test_test.go +76 -0
  4. package/cmd/goscript/main.go +1 -0
  5. package/compiler/build-flags.go +38 -0
  6. package/compiler/compile-request.go +2 -0
  7. package/compiler/compliance_test.go +0 -8
  8. package/compiler/gotest/owner.go +24 -0
  9. package/compiler/gotest/package-result.go +67 -0
  10. package/compiler/gotest/request.go +145 -0
  11. package/compiler/gotest/result.go +28 -0
  12. package/compiler/gotest/runner.go +588 -0
  13. package/compiler/gotest/runner_test.go +627 -0
  14. package/compiler/gotest/test.go +9 -0
  15. package/compiler/index.test.ts +1 -1
  16. package/compiler/lowered-program.go +71 -19
  17. package/compiler/lowering.go +5065 -569
  18. package/compiler/override-facts.go +307 -0
  19. package/compiler/override-registry.go +50 -189
  20. package/compiler/override-registry_test.go +47 -0
  21. package/compiler/package-graph.go +50 -27
  22. package/compiler/package-graph_test.go +37 -2
  23. package/compiler/package-test-function.go +9 -0
  24. package/compiler/package-test-graph-package.go +40 -0
  25. package/compiler/package-test-graph-variant.go +105 -0
  26. package/compiler/package-test-graph.go +117 -0
  27. package/compiler/package-test-graph_test.go +144 -0
  28. package/compiler/runtime-contract.go +189 -29
  29. package/compiler/runtime-contract_test.go +44 -30
  30. package/compiler/semantic-model-types.go +9 -6
  31. package/compiler/semantic-model.go +538 -38
  32. package/compiler/semantic-model_test.go +55 -0
  33. package/compiler/service.go +1 -1
  34. package/compiler/skeleton_test.go +679 -49
  35. package/compiler/tsworkspace/owner.go +334 -0
  36. package/compiler/tsworkspace/owner_test.go +93 -0
  37. package/compiler/tsworkspace/result.go +17 -0
  38. package/compiler/typescript-emitter.go +459 -82
  39. package/compiler/wasm/compile.go +1 -1
  40. package/compiler/wasm/compile_test.go +61 -11
  41. package/compiler/wasm_api.go +172 -7
  42. package/dist/gs/builtin/builtin.d.ts +20 -2
  43. package/dist/gs/builtin/builtin.js +194 -6
  44. package/dist/gs/builtin/builtin.js.map +1 -1
  45. package/dist/gs/builtin/channel.d.ts +8 -0
  46. package/dist/gs/builtin/channel.js +12 -0
  47. package/dist/gs/builtin/channel.js.map +1 -1
  48. package/dist/gs/builtin/slice.d.ts +22 -2
  49. package/dist/gs/builtin/slice.js +216 -44
  50. package/dist/gs/builtin/slice.js.map +1 -1
  51. package/dist/gs/builtin/type.d.ts +5 -2
  52. package/dist/gs/builtin/type.js +83 -24
  53. package/dist/gs/builtin/type.js.map +1 -1
  54. package/dist/gs/builtin/varRef.d.ts +5 -0
  55. package/dist/gs/builtin/varRef.js +23 -0
  56. package/dist/gs/builtin/varRef.js.map +1 -1
  57. package/dist/gs/bytes/buffer.gs.js +48 -44
  58. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  59. package/dist/gs/bytes/reader.gs.js +20 -18
  60. package/dist/gs/bytes/reader.gs.js.map +1 -1
  61. package/dist/gs/context/context.d.ts +5 -4
  62. package/dist/gs/context/context.js +10 -10
  63. package/dist/gs/context/context.js.map +1 -1
  64. package/dist/gs/crypto/internal/fips140deps/byteorder/index.d.ts +1 -0
  65. package/dist/gs/crypto/internal/fips140deps/byteorder/index.js +2 -0
  66. package/dist/gs/crypto/internal/fips140deps/byteorder/index.js.map +1 -0
  67. package/dist/gs/crypto/internal/fips140deps/godebug/index.d.ts +1 -0
  68. package/dist/gs/crypto/internal/fips140deps/godebug/index.js +2 -0
  69. package/dist/gs/crypto/internal/fips140deps/godebug/index.js.map +1 -0
  70. package/dist/gs/embed/index.d.ts +7 -0
  71. package/dist/gs/embed/index.js +16 -0
  72. package/dist/gs/embed/index.js.map +1 -0
  73. package/dist/gs/encoding/json/index.d.ts +1 -0
  74. package/dist/gs/encoding/json/index.js +18 -0
  75. package/dist/gs/encoding/json/index.js.map +1 -1
  76. package/dist/gs/errors/errors.d.ts +4 -0
  77. package/dist/gs/errors/errors.js +81 -0
  78. package/dist/gs/errors/errors.js.map +1 -1
  79. package/dist/gs/fmt/fmt.d.ts +4 -4
  80. package/dist/gs/fmt/fmt.js +42 -11
  81. package/dist/gs/fmt/fmt.js.map +1 -1
  82. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +35 -0
  83. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +211 -1
  84. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  85. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.d.ts +189 -0
  86. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +825 -0
  87. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -0
  88. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +163 -0
  89. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +449 -0
  90. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -0
  91. package/dist/gs/github.com/klauspost/compress/internal/le/index.d.ts +9 -0
  92. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +71 -0
  93. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -0
  94. package/dist/gs/go/internal/scannerhooks/index.d.ts +3 -0
  95. package/dist/gs/go/internal/scannerhooks/index.js +5 -0
  96. package/dist/gs/go/internal/scannerhooks/index.js.map +1 -0
  97. package/dist/gs/go/scanner/index.d.ts +13 -0
  98. package/dist/gs/go/scanner/index.js +35 -0
  99. package/dist/gs/go/scanner/index.js.map +1 -1
  100. package/dist/gs/go/token/index.d.ts +156 -0
  101. package/dist/gs/go/token/index.js +500 -4
  102. package/dist/gs/go/token/index.js.map +1 -1
  103. package/dist/gs/internal/abi/index.d.ts +4 -0
  104. package/dist/gs/internal/abi/index.js +10 -0
  105. package/dist/gs/internal/abi/index.js.map +1 -1
  106. package/dist/gs/internal/bytealg/index.d.ts +2 -0
  107. package/dist/gs/internal/bytealg/index.js +14 -0
  108. package/dist/gs/internal/bytealg/index.js.map +1 -1
  109. package/dist/gs/internal/byteorder/index.d.ts +8 -2
  110. package/dist/gs/internal/byteorder/index.js +56 -25
  111. package/dist/gs/internal/byteorder/index.js.map +1 -1
  112. package/dist/gs/internal/godebug/index.d.ts +12 -0
  113. package/dist/gs/internal/godebug/index.js +30 -0
  114. package/dist/gs/internal/godebug/index.js.map +1 -0
  115. package/dist/gs/io/fs/index.d.ts +1 -0
  116. package/dist/gs/io/fs/index.js +1 -0
  117. package/dist/gs/io/fs/index.js.map +1 -1
  118. package/dist/gs/io/fs/readlink.d.ts +8 -0
  119. package/dist/gs/io/fs/readlink.js +64 -0
  120. package/dist/gs/io/fs/readlink.js.map +1 -0
  121. package/dist/gs/io/fs/walk.d.ts +3 -3
  122. package/dist/gs/io/fs/walk.js +7 -7
  123. package/dist/gs/io/fs/walk.js.map +1 -1
  124. package/dist/gs/io/io.d.ts +40 -6
  125. package/dist/gs/io/io.js +151 -26
  126. package/dist/gs/io/io.js.map +1 -1
  127. package/dist/gs/maps/iter.d.ts +3 -3
  128. package/dist/gs/maps/iter.js +3 -3
  129. package/dist/gs/maps/iter.js.map +1 -1
  130. package/dist/gs/maps/maps.d.ts +2 -2
  131. package/dist/gs/maps/maps.js +1 -1
  132. package/dist/gs/maps/maps.js.map +1 -1
  133. package/dist/gs/math/bits/index.d.ts +13 -4
  134. package/dist/gs/math/bits/index.js +66 -34
  135. package/dist/gs/math/bits/index.js.map +1 -1
  136. package/dist/gs/math/const.gs.d.ts +5 -5
  137. package/dist/gs/math/const.gs.js +4 -4
  138. package/dist/gs/math/const.gs.js.map +1 -1
  139. package/dist/gs/mime/index.d.ts +1 -0
  140. package/dist/gs/mime/index.js +50 -0
  141. package/dist/gs/mime/index.js.map +1 -0
  142. package/dist/gs/net/http/httptest/index.d.ts +11 -0
  143. package/dist/gs/net/http/httptest/index.js +21 -0
  144. package/dist/gs/net/http/httptest/index.js.map +1 -0
  145. package/dist/gs/net/http/index.d.ts +27 -0
  146. package/dist/gs/net/http/index.js +61 -0
  147. package/dist/gs/net/http/index.js.map +1 -0
  148. package/dist/gs/os/dir_unix.gs.js +2 -2
  149. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  150. package/dist/gs/os/types_js.gs.js.map +1 -1
  151. package/dist/gs/path/filepath/match.js +165 -3
  152. package/dist/gs/path/filepath/match.js.map +1 -1
  153. package/dist/gs/path/filepath/path.d.ts +3 -1
  154. package/dist/gs/path/filepath/path.js +133 -4
  155. package/dist/gs/path/filepath/path.js.map +1 -1
  156. package/dist/gs/path/path.d.ts +4 -1
  157. package/dist/gs/path/path.js +16 -4
  158. package/dist/gs/path/path.js.map +1 -1
  159. package/dist/gs/reflect/index.d.ts +1 -1
  160. package/dist/gs/reflect/index.js +1 -1
  161. package/dist/gs/reflect/index.js.map +1 -1
  162. package/dist/gs/reflect/map.js +3 -0
  163. package/dist/gs/reflect/map.js.map +1 -1
  164. package/dist/gs/reflect/type.d.ts +7 -4
  165. package/dist/gs/reflect/type.js +148 -7
  166. package/dist/gs/reflect/type.js.map +1 -1
  167. package/dist/gs/runtime/debug/index.d.ts +2 -0
  168. package/dist/gs/runtime/debug/index.js +8 -0
  169. package/dist/gs/runtime/debug/index.js.map +1 -0
  170. package/dist/gs/runtime/runtime.d.ts +35 -3
  171. package/dist/gs/runtime/runtime.js +72 -0
  172. package/dist/gs/runtime/runtime.js.map +1 -1
  173. package/dist/gs/slices/slices.d.ts +24 -5
  174. package/dist/gs/slices/slices.js +214 -5
  175. package/dist/gs/slices/slices.js.map +1 -1
  176. package/dist/gs/sort/slice.gs.d.ts +3 -3
  177. package/dist/gs/sort/slice.gs.js +6 -6
  178. package/dist/gs/sort/slice.gs.js.map +1 -1
  179. package/dist/gs/sort/sort.gs.d.ts +4 -4
  180. package/dist/gs/sort/sort.gs.js +11 -8
  181. package/dist/gs/sort/sort.gs.js.map +1 -1
  182. package/dist/gs/strings/builder.d.ts +1 -1
  183. package/dist/gs/strings/builder.js +3 -2
  184. package/dist/gs/strings/builder.js.map +1 -1
  185. package/dist/gs/sync/atomic/type.gs.d.ts +9 -8
  186. package/dist/gs/sync/atomic/type.gs.js +0 -2
  187. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  188. package/dist/gs/sync/sync.d.ts +2 -0
  189. package/dist/gs/sync/sync.js +27 -0
  190. package/dist/gs/sync/sync.js.map +1 -1
  191. package/dist/gs/syscall/constants.d.ts +36 -24
  192. package/dist/gs/syscall/constants.js +12 -0
  193. package/dist/gs/syscall/constants.js.map +1 -1
  194. package/dist/gs/syscall/errors.d.ts +2 -0
  195. package/dist/gs/syscall/errors.js +8 -0
  196. package/dist/gs/syscall/errors.js.map +1 -1
  197. package/dist/gs/syscall/fs.d.ts +43 -0
  198. package/dist/gs/syscall/fs.js +102 -0
  199. package/dist/gs/syscall/fs.js.map +1 -1
  200. package/dist/gs/syscall/js/index.d.ts +90 -0
  201. package/dist/gs/syscall/js/index.js +375 -0
  202. package/dist/gs/syscall/js/index.js.map +1 -0
  203. package/dist/gs/syscall/types.d.ts +22 -0
  204. package/dist/gs/syscall/types.js +45 -1
  205. package/dist/gs/syscall/types.js.map +1 -1
  206. package/dist/gs/testing/index.d.ts +1 -0
  207. package/dist/gs/testing/index.js +2 -0
  208. package/dist/gs/testing/index.js.map +1 -0
  209. package/dist/gs/testing/testing.d.ts +77 -0
  210. package/dist/gs/testing/testing.js +301 -0
  211. package/dist/gs/testing/testing.js.map +1 -0
  212. package/dist/gs/time/time.d.ts +41 -4
  213. package/dist/gs/time/time.js +205 -36
  214. package/dist/gs/time/time.js.map +1 -1
  215. package/dist/gs/unicode/unicode.d.ts +23 -1
  216. package/dist/gs/unicode/unicode.js +79 -10
  217. package/dist/gs/unicode/unicode.js.map +1 -1
  218. package/dist/gs/unicode/utf8/utf8.d.ts +4 -4
  219. package/dist/gs/unicode/utf8/utf8.js +24 -11
  220. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  221. package/dist/gs/unique/index.d.ts +11 -0
  222. package/dist/gs/unique/index.js +71 -0
  223. package/dist/gs/unique/index.js.map +1 -0
  224. package/go.sum +9 -0
  225. package/gs/builtin/builtin.ts +239 -8
  226. package/gs/builtin/channel.ts +22 -0
  227. package/gs/builtin/runtime-contract.test.ts +126 -0
  228. package/gs/builtin/slice.ts +259 -50
  229. package/gs/builtin/type.ts +109 -34
  230. package/gs/builtin/varRef.ts +38 -1
  231. package/gs/bytes/buffer.gs.ts +48 -44
  232. package/gs/bytes/meta.json +8 -3
  233. package/gs/bytes/reader.gs.ts +20 -19
  234. package/gs/context/context.test.ts +41 -0
  235. package/gs/context/context.ts +22 -26
  236. package/gs/crypto/internal/fips140deps/byteorder/index.ts +1 -0
  237. package/gs/crypto/internal/fips140deps/godebug/index.ts +1 -0
  238. package/gs/embed/index.ts +20 -0
  239. package/gs/embed/meta.json +5 -0
  240. package/gs/encoding/json/index.test.ts +15 -1
  241. package/gs/encoding/json/index.ts +24 -0
  242. package/gs/errors/errors.test.ts +82 -0
  243. package/gs/errors/errors.ts +104 -0
  244. package/gs/fmt/fmt.ts +56 -16
  245. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +73 -1
  246. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +297 -1
  247. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +159 -0
  248. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +1005 -0
  249. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +719 -0
  250. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +40 -0
  251. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +36 -0
  252. package/gs/github.com/klauspost/compress/internal/le/index.ts +114 -0
  253. package/gs/go/internal/scannerhooks/index.test.ts +14 -0
  254. package/gs/go/internal/scannerhooks/index.ts +9 -0
  255. package/gs/go/scanner/index.test.ts +22 -0
  256. package/gs/go/scanner/index.ts +47 -0
  257. package/gs/go/token/index.test.ts +47 -1
  258. package/gs/go/token/index.ts +570 -4
  259. package/gs/internal/abi/index.test.ts +18 -0
  260. package/gs/internal/abi/index.ts +14 -0
  261. package/gs/internal/bytealg/index.test.ts +18 -0
  262. package/gs/internal/bytealg/index.ts +16 -0
  263. package/gs/internal/byteorder/index.test.ts +39 -0
  264. package/gs/internal/byteorder/index.ts +100 -27
  265. package/gs/internal/godebug/index.test.ts +16 -0
  266. package/gs/internal/godebug/index.ts +35 -0
  267. package/gs/io/fs/index.ts +1 -0
  268. package/gs/io/fs/meta.json +5 -0
  269. package/gs/io/fs/readlink.test.ts +43 -0
  270. package/gs/io/fs/readlink.ts +77 -0
  271. package/gs/io/fs/walk.test.ts +61 -0
  272. package/gs/io/fs/walk.ts +9 -9
  273. package/gs/io/io.ts +174 -31
  274. package/gs/io/meta.json +10 -2
  275. package/gs/maps/iter.ts +12 -6
  276. package/gs/maps/maps.ts +8 -6
  277. package/gs/math/bits/index.ts +103 -47
  278. package/gs/math/const.gs.test.ts +11 -5
  279. package/gs/math/const.gs.ts +5 -6
  280. package/gs/mime/index.ts +54 -0
  281. package/gs/net/http/httptest/index.ts +25 -0
  282. package/gs/net/http/index.test.ts +20 -0
  283. package/gs/net/http/index.ts +81 -0
  284. package/gs/os/dir_unix.gs.ts +2 -3
  285. package/gs/os/types_js.gs.ts +2 -2
  286. package/gs/path/filepath/match.test.ts +31 -12
  287. package/gs/path/filepath/match.ts +178 -3
  288. package/gs/path/filepath/path.test.ts +25 -0
  289. package/gs/path/filepath/path.ts +159 -5
  290. package/gs/path/path.ts +20 -5
  291. package/gs/reflect/index.ts +1 -0
  292. package/gs/reflect/map.test.ts +19 -0
  293. package/gs/reflect/map.ts +4 -0
  294. package/gs/reflect/type.ts +197 -17
  295. package/gs/runtime/debug/index.test.ts +24 -0
  296. package/gs/runtime/debug/index.ts +8 -0
  297. package/gs/runtime/runtime.test.ts +19 -0
  298. package/gs/runtime/runtime.ts +98 -3
  299. package/gs/slices/slices.test.ts +94 -0
  300. package/gs/slices/slices.ts +245 -5
  301. package/gs/sort/meta.json +7 -0
  302. package/gs/sort/slice.gs.ts +16 -7
  303. package/gs/sort/sort.gs.ts +16 -13
  304. package/gs/strings/builder.ts +4 -3
  305. package/gs/sync/atomic/type.gs.ts +13 -14
  306. package/gs/sync/meta.json +3 -1
  307. package/gs/sync/sync.test.ts +13 -1
  308. package/gs/sync/sync.ts +27 -0
  309. package/gs/syscall/constants.ts +39 -24
  310. package/gs/syscall/errors.ts +10 -0
  311. package/gs/syscall/fs.ts +195 -0
  312. package/gs/syscall/js/index.ts +458 -0
  313. package/gs/syscall/js/meta.json +4 -0
  314. package/gs/syscall/net.test.ts +85 -0
  315. package/gs/syscall/types.ts +56 -0
  316. package/gs/testing/index.ts +1 -0
  317. package/gs/testing/meta.json +5 -0
  318. package/gs/testing/testing.test.ts +90 -0
  319. package/gs/testing/testing.ts +382 -0
  320. package/gs/time/time.test.ts +106 -0
  321. package/gs/time/time.ts +278 -57
  322. package/gs/unicode/unicode.test.ts +25 -0
  323. package/gs/unicode/unicode.ts +119 -9
  324. package/gs/unicode/utf8/utf8.test.ts +13 -0
  325. package/gs/unicode/utf8/utf8.ts +28 -16
  326. package/gs/unique/index.ts +91 -0
  327. package/package.json +2 -1
@@ -3,9 +3,9 @@ package compiler
3
3
  import (
4
4
  "context"
5
5
  "os"
6
- "sort"
6
+ "slices"
7
+ "strings"
7
8
 
8
- gs "github.com/aperturerobotics/goscript"
9
9
  "golang.org/x/tools/go/packages"
10
10
  )
11
11
 
@@ -35,6 +35,8 @@ type PackageGraphNode struct {
35
35
  ModulePath string
36
36
  // ModuleDir is the owning module directory when known.
37
37
  ModuleDir string
38
+ // ForTest is the package path under test for Go test variants.
39
+ ForTest string
38
40
  // GoFiles are the package source files.
39
41
  GoFiles []string
40
42
  // CompiledGoFiles are files selected by build constraints.
@@ -48,11 +50,17 @@ type PackageGraphNode struct {
48
50
  }
49
51
 
50
52
  // PackageGraphOwner owns Go package loading and graph identity.
51
- type PackageGraphOwner struct{}
53
+ type PackageGraphOwner struct {
54
+ overrideOwner *OverrideRegistryOwner
55
+ }
52
56
 
53
57
  // NewPackageGraphOwner creates the package graph owner.
54
- func NewPackageGraphOwner() *PackageGraphOwner {
55
- return &PackageGraphOwner{}
58
+ func NewPackageGraphOwner(overrideOwners ...*OverrideRegistryOwner) *PackageGraphOwner {
59
+ overrideOwner := NewOverrideRegistryOwner()
60
+ if len(overrideOwners) != 0 && overrideOwners[0] != nil {
61
+ overrideOwner = overrideOwners[0]
62
+ }
63
+ return &PackageGraphOwner{overrideOwner: overrideOwner}
56
64
  }
57
65
 
58
66
  // Load builds the package graph for a validated request.
@@ -69,8 +77,8 @@ func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*Pac
69
77
  Context: ctx,
70
78
  Dir: req.Dir,
71
79
  Env: append(os.Environ(), "GOOS=js", "GOARCH=wasm"),
72
- BuildFlags: append([]string(nil), req.BuildFlags...),
73
- Tests: false,
80
+ BuildFlags: goScriptBuildFlags(req.BuildFlags),
81
+ Tests: req.Tests,
74
82
  Mode: packages.NeedName |
75
83
  packages.NeedFiles |
76
84
  packages.NeedCompiledGoFiles |
@@ -81,6 +89,7 @@ func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*Pac
81
89
  packages.NeedSyntax |
82
90
  packages.NeedTypesInfo |
83
91
  packages.NeedTypesSizes |
92
+ packages.NeedForTest |
84
93
  packages.NeedModule,
85
94
  }
86
95
  pkgs, err := packages.Load(cfg, req.Patterns...)
@@ -99,6 +108,10 @@ func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*Pac
99
108
  Message: "package patterns did not match any packages",
100
109
  }}
101
110
  }
111
+ overrideFacts, overrideDiagnostics := o.overrideOwner.Facts(ctx)
112
+ if diagnosticsHaveErrors(overrideDiagnostics) {
113
+ return nil, overrideDiagnostics
114
+ }
102
115
 
103
116
  graph := &PackageGraph{
104
117
  RequestedPatterns: append([]string(nil), req.Patterns...),
@@ -109,23 +122,29 @@ func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*Pac
109
122
 
110
123
  requested := make(map[string]bool)
111
124
  for _, pkg := range pkgs {
125
+ if isTestMainPackage(pkg) {
126
+ continue
127
+ }
112
128
  path := packagePath(pkg)
113
129
  requested[path] = true
114
130
  graph.RequestedPackagePaths = append(graph.RequestedPackagePaths, path)
115
131
  }
116
- sort.Strings(graph.RequestedPackagePaths)
132
+ slices.Sort(graph.RequestedPackagePaths)
117
133
 
118
134
  var diagnostics []Diagnostic
119
135
  seen := make(map[string]bool)
120
136
  for _, pkg := range pkgs {
121
- o.collect(graph, pkg, req.DependencyMode, requested, seen)
137
+ if isTestMainPackage(pkg) {
138
+ continue
139
+ }
140
+ o.collect(graph, pkg, req.DependencyMode, requested, overrideFacts, seen)
122
141
  diagnostics = append(diagnostics, packageDiagnostics(pkg)...)
123
142
  }
124
- sort.Slice(graph.Nodes, func(i, j int) bool {
125
- if graph.Nodes[i].PkgPath == graph.Nodes[j].PkgPath {
126
- return graph.Nodes[i].ID < graph.Nodes[j].ID
143
+ slices.SortFunc(graph.Nodes, func(a, b *PackageGraphNode) int {
144
+ if a.PkgPath == b.PkgPath {
145
+ return strings.Compare(a.ID, b.ID)
127
146
  }
128
- return graph.Nodes[i].PkgPath < graph.Nodes[j].PkgPath
147
+ return strings.Compare(a.PkgPath, b.PkgPath)
129
148
  })
130
149
  if len(graph.Nodes) == 0 {
131
150
  diagnostics = append(diagnostics, Diagnostic{
@@ -142,15 +161,22 @@ func (o *PackageGraphOwner) collect(
142
161
  pkg *packages.Package,
143
162
  mode DependencyMode,
144
163
  requested map[string]bool,
164
+ overrideFacts *OverrideFacts,
145
165
  seen map[string]bool,
146
166
  ) {
147
167
  if pkg == nil || seen[pkg.ID] {
148
168
  return
149
169
  }
170
+ if pkg.ForTest != "" && !requested[pkg.ForTest] {
171
+ if prod := pkg.Imports[pkg.ForTest]; prod != nil {
172
+ o.collect(graph, prod, mode, requested, overrideFacts, seen)
173
+ }
174
+ return
175
+ }
150
176
  seen[pkg.ID] = true
151
177
 
152
178
  path := packagePath(pkg)
153
- node := newPackageGraphNode(pkg, requested[path])
179
+ node := newPackageGraphNode(pkg, requested[path], overrideFacts)
154
180
  graph.Nodes = append(graph.Nodes, node)
155
181
  graph.NodesByPackagePath[path] = node
156
182
  graph.packagesByPath[path] = pkg
@@ -162,18 +188,18 @@ func (o *PackageGraphOwner) collect(
162
188
  for importPath := range pkg.Imports {
163
189
  imports = append(imports, importPath)
164
190
  }
165
- sort.Strings(imports)
191
+ slices.Sort(imports)
166
192
  for _, importPath := range imports {
167
- o.collect(graph, pkg.Imports[importPath], mode, requested, seen)
193
+ o.collect(graph, pkg.Imports[importPath], mode, requested, overrideFacts, seen)
168
194
  }
169
195
  }
170
196
 
171
- func newPackageGraphNode(pkg *packages.Package, requested bool) *PackageGraphNode {
197
+ func newPackageGraphNode(pkg *packages.Package, requested bool, overrideFacts *OverrideFacts) *PackageGraphNode {
172
198
  imports := make([]string, 0, len(pkg.Imports))
173
199
  for importPath := range pkg.Imports {
174
200
  imports = append(imports, importPath)
175
201
  }
176
- sort.Strings(imports)
202
+ slices.Sort(imports)
177
203
 
178
204
  var modulePath string
179
205
  var moduleDir string
@@ -188,14 +214,19 @@ func newPackageGraphNode(pkg *packages.Package, requested bool) *PackageGraphNod
188
214
  Name: pkg.Name,
189
215
  ModulePath: modulePath,
190
216
  ModuleDir: moduleDir,
217
+ ForTest: pkg.ForTest,
191
218
  GoFiles: append([]string(nil), pkg.GoFiles...),
192
219
  CompiledGoFiles: append([]string(nil), pkg.CompiledGoFiles...),
193
220
  Imports: imports,
194
221
  Requested: requested,
195
- OverrideCandidate: hasOverrideCandidate(packagePath(pkg)),
222
+ OverrideCandidate: overrideFacts.HasPackage(packagePath(pkg)),
196
223
  }
197
224
  }
198
225
 
226
+ func isTestMainPackage(pkg *packages.Package) bool {
227
+ return pkg != nil && pkg.ForTest == "" && pkg.Name == "main" && strings.HasSuffix(packagePath(pkg), ".test")
228
+ }
229
+
199
230
  func packagePath(pkg *packages.Package) string {
200
231
  if pkg == nil {
201
232
  return ""
@@ -221,11 +252,3 @@ func packageDiagnostics(pkg *packages.Package) []Diagnostic {
221
252
  }
222
253
  return diagnostics
223
254
  }
224
-
225
- func hasOverrideCandidate(pkgPath string) bool {
226
- if pkgPath == "" {
227
- return false
228
- }
229
- _, err := gs.GsOverrides.ReadFile("gs/" + pkgPath + "/index.ts")
230
- return err == nil
231
- }
@@ -176,6 +176,37 @@ func TestPackageGraphHonorsBuildFlags(t *testing.T) {
176
176
  }
177
177
  }
178
178
 
179
+ func TestPackageGraphAddsGoScriptBuildTag(t *testing.T) {
180
+ moduleDir := writePackageGraphFixture(t, map[string]string{
181
+ "go.mod": "module example.test/goscripttag\n\ngo 1.25.3\n",
182
+ "default.go": "package goscripttag\nconst Selected = \"default\"\n",
183
+ "goscript.go": "//go:build goscript\n\npackage goscripttag\nconst GoScript = true\n",
184
+ "excluded.go": "//go:build !goscript\n\npackage goscripttag\nconst Excluded = true\n",
185
+ "customtag.go": "//go:build customtag\n\npackage goscripttag\nconst Custom = true\n",
186
+ })
187
+ graph := loadPackageGraph(t, &CompileRequest{
188
+ Patterns: []string{"."},
189
+ Dir: moduleDir,
190
+ OutputPath: filepath.Join(t.TempDir(), "out"),
191
+ BuildFlags: []string{"-tags=customtag"},
192
+ DependencyMode: DependencyModeRequested,
193
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
194
+ })
195
+
196
+ var compiled []string
197
+ for _, file := range graph.Nodes[0].CompiledGoFiles {
198
+ compiled = append(compiled, filepath.Base(file))
199
+ }
200
+ for _, expected := range []string{"default.go", "goscript.go", "customtag.go"} {
201
+ if !slices.Contains(compiled, expected) {
202
+ t.Fatalf("expected %s in compiled files: %v", expected, compiled)
203
+ }
204
+ }
205
+ if slices.Contains(compiled, "excluded.go") {
206
+ t.Fatalf("did not expect excluded.go in compiled files: %v", compiled)
207
+ }
208
+ }
209
+
179
210
  func TestPackageGraphLoadsLocalReplacement(t *testing.T) {
180
211
  moduleDir := writePackageGraphFixture(t, map[string]string{
181
212
  "go.mod": strings.Join([]string{
@@ -230,11 +261,15 @@ func TestPackageGraphDetectsOverrideCandidates(t *testing.T) {
230
261
  func TestPackageGraphOverrideCandidatesRequirePackageIndex(t *testing.T) {
231
262
  parent := "github.com/aperturerobotics/wasivm/wazero/kernel"
232
263
  child := parent + "/runtime"
264
+ facts, diagnostics := NewOverrideRegistryOwner().Facts(context.Background())
265
+ if diagnosticsHaveErrors(diagnostics) {
266
+ t.Fatalf("override facts failed: %#v", diagnostics)
267
+ }
233
268
 
234
- if hasOverrideCandidate(parent) {
269
+ if facts.HasPackage(parent) {
235
270
  t.Fatalf("parent directory without an override index was detected as an override candidate")
236
271
  }
237
- if !hasOverrideCandidate(child) {
272
+ if !facts.HasPackage(child) {
238
273
  t.Fatalf("nested package with an override index was not detected as an override candidate")
239
274
  }
240
275
  }
@@ -0,0 +1,9 @@
1
+ package compiler
2
+
3
+ // PackageTestFunction describes one discovered ordinary Go test function.
4
+ type PackageTestFunction struct {
5
+ // Name is the Go TestXxx function name.
6
+ Name string
7
+ // PackagePath is the package variant that exports the function.
8
+ PackagePath string
9
+ }
@@ -0,0 +1,40 @@
1
+ package compiler
2
+
3
+ import "golang.org/x/tools/go/packages"
4
+
5
+ // PackageTestGraphPackage describes one requested package under test.
6
+ type PackageTestGraphPackage struct {
7
+ // PackagePath is the package under test.
8
+ PackagePath string
9
+ // PackageName is the base package name.
10
+ PackageName string
11
+ // PackageID is the go/packages package identity for the package under test.
12
+ PackageID string
13
+ // GoFiles are the package source files.
14
+ GoFiles []string
15
+ // CompiledGoFiles are files selected by build constraints.
16
+ CompiledGoFiles []string
17
+ // SamePackageTests is the same-package test variant when present.
18
+ SamePackageTests *PackageTestGraphVariant
19
+ // ExternalPackageTests is the external-package test variant when present.
20
+ ExternalPackageTests *PackageTestGraphVariant
21
+ // Diagnostics are package or variant load diagnostics attached to this package.
22
+ Diagnostics []Diagnostic
23
+ }
24
+
25
+ // HasTests returns true when the package has any loaded test variant.
26
+ func (p *PackageTestGraphPackage) HasTests() bool {
27
+ return p != nil && (p.SamePackageTests != nil || p.ExternalPackageTests != nil)
28
+ }
29
+
30
+ func (p *PackageTestGraphPackage) appendDiagnostics(diagnostics []Diagnostic) {
31
+ p.Diagnostics = append(p.Diagnostics, diagnostics...)
32
+ }
33
+
34
+ func (p *PackageTestGraphPackage) setPackage(pkg *packages.Package) {
35
+ p.PackagePath = packagePath(pkg)
36
+ p.PackageName = pkg.Name
37
+ p.PackageID = pkg.ID
38
+ p.GoFiles = append([]string(nil), pkg.GoFiles...)
39
+ p.CompiledGoFiles = append([]string(nil), pkg.CompiledGoFiles...)
40
+ }
@@ -0,0 +1,105 @@
1
+ package compiler
2
+
3
+ import (
4
+ "go/ast"
5
+ "go/types"
6
+ "slices"
7
+ "strings"
8
+ "unicode"
9
+
10
+ "golang.org/x/tools/go/packages"
11
+ )
12
+
13
+ // PackageTestGraphVariant describes one Go test package variant.
14
+ type PackageTestGraphVariant struct {
15
+ // ID is the go/packages package identity.
16
+ ID string
17
+ // PkgPath is the stable Go package path for this variant.
18
+ PkgPath string
19
+ // Name is the Go package name for this variant.
20
+ Name string
21
+ // ForTest is the package path this variant tests.
22
+ ForTest string
23
+ // GoFiles are the package source files.
24
+ GoFiles []string
25
+ // CompiledGoFiles are files selected by build constraints.
26
+ CompiledGoFiles []string
27
+ // Imports are packages imported directly by this test variant.
28
+ Imports []string
29
+ // Diagnostics are load diagnostics attached to this variant.
30
+ Diagnostics []Diagnostic
31
+ // Tests are ordinary TestXxx functions discovered in this variant.
32
+ Tests []PackageTestFunction
33
+ }
34
+
35
+ func newPackageTestGraphVariant(pkg *packages.Package, diagnostics []Diagnostic) *PackageTestGraphVariant {
36
+ imports := make([]string, 0, len(pkg.Imports))
37
+ for importPath := range pkg.Imports {
38
+ imports = append(imports, importPath)
39
+ }
40
+ slices.Sort(imports)
41
+ return &PackageTestGraphVariant{
42
+ ID: pkg.ID,
43
+ PkgPath: packagePath(pkg),
44
+ Name: pkg.Name,
45
+ ForTest: pkg.ForTest,
46
+ GoFiles: append([]string(nil), pkg.GoFiles...),
47
+ CompiledGoFiles: append([]string(nil), pkg.CompiledGoFiles...),
48
+ Imports: imports,
49
+ Diagnostics: append([]Diagnostic(nil), diagnostics...),
50
+ Tests: discoverPackageTestFunctions(pkg),
51
+ }
52
+ }
53
+
54
+ func discoverPackageTestFunctions(pkg *packages.Package) []PackageTestFunction {
55
+ if pkg == nil {
56
+ return nil
57
+ }
58
+ var tests []PackageTestFunction
59
+ for _, file := range pkg.Syntax {
60
+ 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) {
67
+ continue
68
+ }
69
+ tests = append(tests, PackageTestFunction{
70
+ Name: fn.Name.Name,
71
+ PackagePath: packagePath(pkg),
72
+ })
73
+ }
74
+ }
75
+ return tests
76
+ }
77
+
78
+ func isOrdinaryTestFunc(fn *types.Func) bool {
79
+ if fn == nil {
80
+ return false
81
+ }
82
+ sig, _ := fn.Type().(*types.Signature)
83
+ if sig == nil || sig.Params().Len() != 1 || sig.Results().Len() != 0 {
84
+ return false
85
+ }
86
+ ptr, _ := sig.Params().At(0).Type().(*types.Pointer)
87
+ if ptr == nil {
88
+ return false
89
+ }
90
+ named, _ := ptr.Elem().(*types.Named)
91
+ if named == nil || named.Obj() == nil || named.Obj().Pkg() == nil {
92
+ return false
93
+ }
94
+ return named.Obj().Name() == "T" && named.Obj().Pkg().Path() == "testing"
95
+ }
96
+
97
+ func isTestName(name string) bool {
98
+ if !strings.HasPrefix(name, "Test") || name == "Test" {
99
+ return false
100
+ }
101
+ for _, r := range strings.TrimPrefix(name, "Test") {
102
+ return !unicode.IsLower(r)
103
+ }
104
+ return false
105
+ }
@@ -0,0 +1,117 @@
1
+ package compiler
2
+
3
+ import (
4
+ "context"
5
+ "os"
6
+ "slices"
7
+ "strings"
8
+
9
+ "golang.org/x/tools/go/packages"
10
+ )
11
+
12
+ // PackageTestGraph is the package-scoped graph used by GoScript test runners.
13
+ type PackageTestGraph struct {
14
+ // RequestedPatterns are the package patterns from the compile request.
15
+ RequestedPatterns []string
16
+ // Packages are deterministic package-test facts keyed by package under test.
17
+ Packages []*PackageTestGraphPackage
18
+
19
+ packagesByPath map[string]*PackageTestGraphPackage
20
+ }
21
+
22
+ // PackageByPath returns the package facts for a package under test.
23
+ func (g *PackageTestGraph) PackageByPath(path string) *PackageTestGraphPackage {
24
+ if g == nil {
25
+ return nil
26
+ }
27
+ return g.packagesByPath[path]
28
+ }
29
+
30
+ // LoadTestGraph builds package-scoped test graph facts for a validated request.
31
+ func (o *PackageGraphOwner) LoadTestGraph(ctx context.Context, req *CompileRequest) (*PackageTestGraph, []Diagnostic) {
32
+ if err := ctx.Err(); err != nil {
33
+ return nil, []Diagnostic{{
34
+ Severity: DiagnosticSeverityError,
35
+ Code: "goscript/context:canceled",
36
+ Message: err.Error(),
37
+ }}
38
+ }
39
+
40
+ cfg := &packages.Config{
41
+ Context: ctx,
42
+ Dir: req.Dir,
43
+ Env: append(os.Environ(), "GOOS=js", "GOARCH=wasm"),
44
+ BuildFlags: goScriptBuildFlags(req.BuildFlags),
45
+ Tests: true,
46
+ Mode: packages.NeedName |
47
+ packages.NeedFiles |
48
+ packages.NeedCompiledGoFiles |
49
+ packages.NeedImports |
50
+ packages.NeedDeps |
51
+ packages.NeedExportFile |
52
+ packages.NeedTypes |
53
+ packages.NeedSyntax |
54
+ packages.NeedTypesInfo |
55
+ packages.NeedTypesSizes |
56
+ packages.NeedForTest |
57
+ packages.NeedModule,
58
+ }
59
+ pkgs, err := packages.Load(cfg, req.Patterns...)
60
+ if err != nil {
61
+ return nil, []Diagnostic{{
62
+ Severity: DiagnosticSeverityError,
63
+ Code: "goscript/package-graph:load",
64
+ Message: "failed to load Go test packages",
65
+ Detail: err.Error(),
66
+ }}
67
+ }
68
+
69
+ graph := &PackageTestGraph{
70
+ RequestedPatterns: append([]string(nil), req.Patterns...),
71
+ packagesByPath: make(map[string]*PackageTestGraphPackage),
72
+ }
73
+ var diagnostics []Diagnostic
74
+ for _, pkg := range pkgs {
75
+ if pkg == nil || isTestMainPackage(pkg) {
76
+ continue
77
+ }
78
+ pkgDiagnostics := packageDiagnostics(pkg)
79
+ diagnostics = append(diagnostics, pkgDiagnostics...)
80
+ if pkg.ForTest == "" {
81
+ facts := graph.packageFacts(packagePath(pkg))
82
+ facts.setPackage(pkg)
83
+ facts.appendDiagnostics(pkgDiagnostics)
84
+ continue
85
+ }
86
+ facts := graph.packageFacts(pkg.ForTest)
87
+ variant := newPackageTestGraphVariant(pkg, pkgDiagnostics)
88
+ if strings.HasSuffix(pkg.Name, "_test") {
89
+ facts.ExternalPackageTests = variant
90
+ } else {
91
+ facts.SamePackageTests = variant
92
+ }
93
+ facts.appendDiagnostics(pkgDiagnostics)
94
+ }
95
+ if len(graph.Packages) == 0 {
96
+ diagnostics = append(diagnostics, Diagnostic{
97
+ Severity: DiagnosticSeverityError,
98
+ Code: "goscript/package-graph:no-test-packages",
99
+ Message: "package patterns did not match any test packages",
100
+ })
101
+ }
102
+ slices.SortFunc(graph.Packages, func(a, b *PackageTestGraphPackage) int {
103
+ return strings.Compare(a.PackagePath, b.PackagePath)
104
+ })
105
+ return graph, diagnostics
106
+ }
107
+
108
+ func (g *PackageTestGraph) packageFacts(path string) *PackageTestGraphPackage {
109
+ facts := g.packagesByPath[path]
110
+ if facts != nil {
111
+ return facts
112
+ }
113
+ facts = &PackageTestGraphPackage{PackagePath: path}
114
+ g.packagesByPath[path] = facts
115
+ g.Packages = append(g.Packages, facts)
116
+ return facts
117
+ }
@@ -0,0 +1,144 @@
1
+ package compiler
2
+
3
+ import (
4
+ "context"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+ )
9
+
10
+ func TestPackageGraphOwnerLoadTestGraphFacts(t *testing.T) {
11
+ moduleDir := writePackageGraphFixture(t, map[string]string{
12
+ "go.mod": "module example.test/testgraph\n\ngo 1.25.3\n",
13
+ "same/value.go": strings.Join([]string{
14
+ "package same",
15
+ "",
16
+ "func Add(a int, b int) int {",
17
+ "\treturn a + b",
18
+ "}",
19
+ "",
20
+ }, "\n"),
21
+ "same/value_test.go": strings.Join([]string{
22
+ "package same",
23
+ "",
24
+ "import \"testing\"",
25
+ "",
26
+ "func TestAdd(t *testing.T) {}",
27
+ "",
28
+ }, "\n"),
29
+ "external/value.go": strings.Join([]string{
30
+ "package external",
31
+ "",
32
+ "func Name() string {",
33
+ "\treturn \"external\"",
34
+ "}",
35
+ "",
36
+ }, "\n"),
37
+ "external/value_test.go": strings.Join([]string{
38
+ "package external_test",
39
+ "",
40
+ "import (",
41
+ "\t\"testing\"",
42
+ "",
43
+ "\texternal \"example.test/testgraph/external\"",
44
+ ")",
45
+ "",
46
+ "func TestName(t *testing.T) {",
47
+ "\t_ = external.Name()",
48
+ "}",
49
+ "",
50
+ }, "\n"),
51
+ "notests/value.go": "package notests\nconst Value = 1\n",
52
+ })
53
+
54
+ graph, diagnostics := loadPackageTestGraph(t, &CompileRequest{
55
+ Patterns: []string{"./..."},
56
+ Dir: moduleDir,
57
+ OutputPath: filepath.Join(t.TempDir(), "out"),
58
+ DependencyMode: DependencyModeRequested,
59
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
60
+ })
61
+ if diagnosticsHaveErrors(diagnostics) {
62
+ t.Fatalf("test graph load failed: %#v", diagnostics)
63
+ }
64
+
65
+ if len(graph.Packages) != 3 {
66
+ t.Fatalf("expected three requested packages, got %#v", graph.Packages)
67
+ }
68
+ same := graph.PackageByPath("example.test/testgraph/same")
69
+ if same == nil || same.SamePackageTests == nil || same.ExternalPackageTests != nil || !same.HasTests() {
70
+ t.Fatalf("unexpected same-package facts: %#v", same)
71
+ }
72
+ external := graph.PackageByPath("example.test/testgraph/external")
73
+ if external == nil || external.ExternalPackageTests == nil || external.SamePackageTests != nil || !external.HasTests() {
74
+ t.Fatalf("unexpected external-package facts: %#v", external)
75
+ }
76
+ notests := graph.PackageByPath("example.test/testgraph/notests")
77
+ if notests == nil || notests.HasTests() {
78
+ t.Fatalf("unexpected no-test package facts: %#v", notests)
79
+ }
80
+ }
81
+
82
+ func TestPackageGraphOwnerLoadTestGraphScopesDiagnostics(t *testing.T) {
83
+ moduleDir := writePackageGraphFixture(t, map[string]string{
84
+ "go.mod": "module example.test/testgraphdiag\n\ngo 1.25.3\n",
85
+ "clean/value.go": strings.Join([]string{
86
+ "package clean",
87
+ "",
88
+ "func Value() int {",
89
+ "\treturn 1",
90
+ "}",
91
+ "",
92
+ }, "\n"),
93
+ "clean/value_test.go": strings.Join([]string{
94
+ "package clean",
95
+ "",
96
+ "import \"testing\"",
97
+ "",
98
+ "func TestValue(t *testing.T) {}",
99
+ "",
100
+ }, "\n"),
101
+ "broken/value.go": "package broken\nconst Value = 1\n",
102
+ "broken/value_test.go": strings.Join([]string{
103
+ "package broken",
104
+ "",
105
+ "import \"testing\"",
106
+ "",
107
+ "func TestBroken(t *testing.T) {",
108
+ "\tMissing()",
109
+ "}",
110
+ "",
111
+ }, "\n"),
112
+ })
113
+
114
+ graph, diagnostics := loadPackageTestGraph(t, &CompileRequest{
115
+ Patterns: []string{"./..."},
116
+ Dir: moduleDir,
117
+ OutputPath: filepath.Join(t.TempDir(), "out"),
118
+ DependencyMode: DependencyModeRequested,
119
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
120
+ })
121
+ requireDiagnosticCode(t, diagnostics, "goscript/package-graph:load-error")
122
+
123
+ clean := graph.PackageByPath("example.test/testgraphdiag/clean")
124
+ if clean == nil || len(clean.Diagnostics) != 0 {
125
+ t.Fatalf("clean package should not inherit broken diagnostics: %#v", clean)
126
+ }
127
+ broken := graph.PackageByPath("example.test/testgraphdiag/broken")
128
+ if broken == nil || len(broken.Diagnostics) == 0 {
129
+ t.Fatalf("broken package should carry load diagnostics: %#v", broken)
130
+ }
131
+ if broken.SamePackageTests == nil || len(broken.SamePackageTests.Diagnostics) == 0 {
132
+ t.Fatalf("broken same-package test variant should carry diagnostics: %#v", broken)
133
+ }
134
+ }
135
+
136
+ func loadPackageTestGraph(t *testing.T, req *CompileRequest) (*PackageTestGraph, []Diagnostic) {
137
+ t.Helper()
138
+
139
+ diagnostics := NewCompileRequestOwner().Validate(req)
140
+ if diagnosticsHaveErrors(diagnostics) {
141
+ t.Fatalf("request validation failed: %#v", diagnostics)
142
+ }
143
+ return NewPackageGraphOwner().LoadTestGraph(context.Background(), req)
144
+ }