goscript 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/cmd/go_js_wasm_exec/main.go +1 -1
- package/cmd/go_js_wasm_exec/main_test.go +1 -1
- package/cmd/goscript/cmd-compile.go +9 -1
- package/cmd/goscript/cmd-test.go +1 -1
- package/cmd/goscript/cmd_compile_test.go +44 -0
- package/cmd/goscript/deps.go +1 -1
- package/cmd/goscript-wasm/main.go +2 -2
- package/compiler/compile-request.go +19 -0
- package/compiler/compile_bench_test.go +121 -0
- package/compiler/compliance_test.go +17 -1
- package/compiler/config.go +2 -0
- package/compiler/gotest/result.go +1 -1
- package/compiler/gotest/runner.go +2 -2
- package/compiler/gotest/runner_test.go +4 -7
- package/compiler/index.test.ts +28 -0
- package/compiler/index.ts +32 -16
- package/compiler/lowering.go +1236 -143
- package/compiler/lowering_bench_test.go +4 -0
- package/compiler/override-facts.go +1 -1
- package/compiler/override-registry_test.go +125 -0
- package/compiler/package-graph.go +92 -0
- package/compiler/package-graph_test.go +113 -0
- package/compiler/runtime-contract.go +1 -1
- package/compiler/semantic-model.go +32 -0
- package/compiler/skeleton_test.go +284 -11
- package/compiler/wasm/compile.go +1 -1
- package/compiler/wasm/compile_test.go +1 -1
- package/dist/compiler/index.d.ts +4 -0
- package/dist/compiler/index.js +26 -15
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/compress/gzip/index.d.ts +41 -0
- package/dist/gs/compress/gzip/index.js +235 -0
- package/dist/gs/compress/gzip/index.js.map +1 -0
- package/dist/gs/database/sql/driver/index.d.ts +165 -0
- package/dist/gs/database/sql/driver/index.js +432 -0
- package/dist/gs/database/sql/driver/index.js.map +1 -0
- package/dist/gs/encoding/binary/index.d.ts +71 -0
- package/dist/gs/encoding/binary/index.js +778 -0
- package/dist/gs/encoding/binary/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js +156 -57
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/klauspost/cpuid/v2/index.d.ts +11 -0
- package/dist/gs/github.com/klauspost/cpuid/v2/index.js +28 -0
- package/dist/gs/github.com/klauspost/cpuid/v2/index.js.map +1 -0
- package/dist/gs/github.com/pkg/errors/errors.d.ts +0 -2
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/index.d.ts +2 -1
- package/dist/gs/github.com/pkg/errors/index.js +1 -1
- package/dist/gs/github.com/pkg/errors/index.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.d.ts +8 -19
- package/dist/gs/github.com/pkg/errors/stack.js +26 -61
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.d.ts +19 -0
- package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js +25 -0
- package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js.map +1 -0
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.d.ts +104 -0
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1107 -0
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -0
- package/dist/gs/golang.org/x/crypto/internal/alias/index.d.ts +3 -0
- package/dist/gs/golang.org/x/crypto/internal/alias/index.js +39 -0
- package/dist/gs/golang.org/x/crypto/internal/alias/index.js.map +1 -0
- package/dist/gs/io/fs/glob.js +1 -1
- package/dist/gs/io/fs/glob.js.map +1 -1
- package/dist/gs/io/fs/readlink.d.ts +1 -1
- package/dist/gs/io/fs/readlink.js +2 -2
- package/dist/gs/io/fs/readlink.js.map +1 -1
- package/dist/gs/io/fs/stat.d.ts +4 -2
- package/dist/gs/io/fs/stat.js +12 -73
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.d.ts +2 -2
- package/dist/gs/io/fs/sub.js +7 -7
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.js +1 -1
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +18 -14
- package/dist/gs/net/http/index.js +44 -23
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.d.ts +5 -5
- package/dist/gs/net/http/pprof/index.js +21 -21
- package/dist/gs/net/http/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.d.ts +6 -1
- package/dist/gs/runtime/runtime.js +15 -8
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.d.ts +8 -5
- package/dist/gs/runtime/trace/index.js +324 -23
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +2 -1
- package/dist/gs/slices/slices.js +9 -3
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/sort/search.gs.d.ts +3 -1
- package/dist/gs/sort/search.gs.js +18 -53
- package/dist/gs/sort/search.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -1
- package/dist/gs/sync/sync.js +3 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.d.ts +22 -29
- package/dist/gs/time/time.js +111 -32
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unsafe/unsafe.d.ts +3 -2
- package/dist/gs/unsafe/unsafe.js.map +1 -1
- package/go.mod +7 -5
- package/go.sum +12 -26
- package/gs/builtin/runtime-contract.test.ts +25 -0
- package/gs/compress/gzip/index.test.ts +86 -0
- package/gs/compress/gzip/index.ts +297 -0
- package/gs/compress/gzip/meta.json +6 -0
- package/gs/compress/gzip/parity.json +45 -0
- package/gs/database/sql/driver/index.test.ts +88 -0
- package/gs/database/sql/driver/index.ts +675 -0
- package/gs/database/sql/driver/meta.json +3 -0
- package/gs/database/sql/driver/parity.json +144 -0
- package/gs/embed/index.test.ts +1 -1
- package/gs/encoding/binary/index.test.ts +239 -0
- package/gs/encoding/binary/index.ts +999 -0
- package/gs/encoding/binary/meta.json +9 -0
- package/gs/encoding/binary/parity.json +72 -0
- package/gs/fmt/fmt.test.ts +28 -0
- package/gs/fmt/fmt.ts +198 -61
- package/gs/fmt/meta.json +2 -1
- package/gs/github.com/klauspost/cpuid/v2/index.ts +38 -0
- package/gs/github.com/klauspost/cpuid/v2/meta.json +3 -0
- package/gs/github.com/pkg/errors/errors.ts +1 -2
- package/gs/github.com/pkg/errors/index.ts +2 -1
- package/gs/github.com/pkg/errors/stack.ts +34 -62
- package/gs/golang.org/x/crypto/cryptobyte/asn1/index.test.ts +19 -0
- package/gs/golang.org/x/crypto/cryptobyte/asn1/index.ts +29 -0
- package/gs/golang.org/x/crypto/cryptobyte/index.test.ts +255 -0
- package/gs/golang.org/x/crypto/cryptobyte/index.ts +1441 -0
- package/gs/golang.org/x/crypto/cryptobyte/meta.json +3 -0
- package/gs/golang.org/x/crypto/internal/alias/index.test.ts +40 -0
- package/gs/golang.org/x/crypto/internal/alias/index.ts +40 -0
- package/gs/io/fs/glob.ts +1 -1
- package/gs/io/fs/meta.json +3 -0
- package/gs/io/fs/readlink.test.ts +2 -2
- package/gs/io/fs/readlink.ts +5 -2
- package/gs/io/fs/stat.test.ts +79 -0
- package/gs/io/fs/stat.ts +24 -10
- package/gs/io/fs/sub.test.ts +93 -0
- package/gs/io/fs/sub.ts +9 -9
- package/gs/io/fs/walk.ts +1 -1
- package/gs/net/http/index.test.ts +207 -2
- package/gs/net/http/index.ts +68 -37
- package/gs/net/http/meta.json +3 -1
- package/gs/net/http/pprof/index.test.ts +4 -4
- package/gs/net/http/pprof/index.ts +30 -27
- package/gs/runtime/runtime.test.ts +16 -0
- package/gs/runtime/runtime.ts +17 -9
- package/gs/runtime/trace/index.test.ts +113 -14
- package/gs/runtime/trace/index.ts +384 -34
- package/gs/runtime/trace/meta.json +1 -0
- package/gs/slices/slices.test.ts +24 -1
- package/gs/slices/slices.ts +14 -4
- package/gs/sort/meta.json +1 -0
- package/gs/sort/search.gs.ts +20 -5
- package/gs/sync/sync.ts +4 -1
- package/gs/time/time.test.ts +79 -2
- package/gs/time/time.ts +133 -33
- package/gs/unsafe/unsafe.ts +4 -2
- package/package.json +2 -2
|
@@ -47,6 +47,8 @@ func BenchmarkLoweringPackage(b *testing.B) {
|
|
|
47
47
|
fixture.model,
|
|
48
48
|
fixture.semPkg,
|
|
49
49
|
make(map[string]map[types.Object]bool),
|
|
50
|
+
make(map[*types.Func]bool),
|
|
51
|
+
make(map[*types.Func]bool),
|
|
50
52
|
make(runtimeMethodSetCache),
|
|
51
53
|
LoweringOptions{},
|
|
52
54
|
); diagnosticsHaveErrors(diagnostics) {
|
|
@@ -86,6 +88,8 @@ func BenchmarkLoweringFile(b *testing.B) {
|
|
|
86
88
|
fixture.file.outputNames,
|
|
87
89
|
fixture.file.lazyPackageVars,
|
|
88
90
|
fixture.lazyPackageVarsByPkg,
|
|
91
|
+
make(map[*types.Func]bool),
|
|
92
|
+
make(map[*types.Func]bool),
|
|
89
93
|
make(runtimeMethodSetCache),
|
|
90
94
|
false,
|
|
91
95
|
"",
|
|
@@ -13,8 +13,8 @@ import (
|
|
|
13
13
|
"slices"
|
|
14
14
|
"strings"
|
|
15
15
|
|
|
16
|
-
gs "github.com/aperturerobotics/goscript"
|
|
17
16
|
jsoniter "github.com/aperturerobotics/json-iterator-lite"
|
|
17
|
+
gs "github.com/s4wave/goscript"
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
// OverrideFacts is the immutable compiler-visible view of GoScript overrides.
|
|
@@ -488,6 +488,131 @@ func TestCompilePackagesAwaitsOverrideAsyncFunctions(t *testing.T) {
|
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
+
func TestCompilePackagesAwaitsIOFSStatOverride(t *testing.T) {
|
|
492
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
493
|
+
"go.mod": "module example.test/iofsstat\n\ngo 1.25.3\n",
|
|
494
|
+
"main.go": strings.Join([]string{
|
|
495
|
+
"package main",
|
|
496
|
+
"import \"io/fs\"",
|
|
497
|
+
"type memFS struct{}",
|
|
498
|
+
"func (memFS) Open(name string) (fs.File, error) { return nil, fs.ErrNotExist }",
|
|
499
|
+
"func Use(fsys fs.FS) error {",
|
|
500
|
+
" _, err := fs.Stat(fsys, \"pkg\")",
|
|
501
|
+
" return err",
|
|
502
|
+
"}",
|
|
503
|
+
"func main() { _ = Use(memFS{}) }",
|
|
504
|
+
"",
|
|
505
|
+
}, "\n"),
|
|
506
|
+
})
|
|
507
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
508
|
+
comp, err := NewCompiler(&Config{
|
|
509
|
+
Dir: moduleDir,
|
|
510
|
+
OutputPath: out,
|
|
511
|
+
AllDependencies: true,
|
|
512
|
+
}, nil, nil)
|
|
513
|
+
if err != nil {
|
|
514
|
+
t.Fatal(err.Error())
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
518
|
+
t.Fatal(err.Error())
|
|
519
|
+
}
|
|
520
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "iofsstat", "main.gs.ts"))
|
|
521
|
+
if err != nil {
|
|
522
|
+
t.Fatal(err.Error())
|
|
523
|
+
}
|
|
524
|
+
text := string(content)
|
|
525
|
+
if !strings.Contains(text, "export async function Use(") {
|
|
526
|
+
t.Fatalf("fs.Stat caller was not marked async:\n%s", text)
|
|
527
|
+
}
|
|
528
|
+
if !strings.Contains(text, "await fs.Stat(") {
|
|
529
|
+
t.Fatalf("io/fs Stat override call was not awaited:\n%s", text)
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
func TestCompilePackagesAwaitsIOFSLstatOverride(t *testing.T) {
|
|
534
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
535
|
+
"go.mod": "module example.test/iofslstat\n\ngo 1.25.3\n",
|
|
536
|
+
"main.go": strings.Join([]string{
|
|
537
|
+
"package main",
|
|
538
|
+
"import \"io/fs\"",
|
|
539
|
+
"type memFS struct{}",
|
|
540
|
+
"func (memFS) Open(name string) (fs.File, error) { return nil, fs.ErrNotExist }",
|
|
541
|
+
"func Use(fsys fs.FS) error {",
|
|
542
|
+
" _, err := fs.Lstat(fsys, \"pkg\")",
|
|
543
|
+
" return err",
|
|
544
|
+
"}",
|
|
545
|
+
"func main() { _ = Use(memFS{}) }",
|
|
546
|
+
"",
|
|
547
|
+
}, "\n"),
|
|
548
|
+
})
|
|
549
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
550
|
+
comp, err := NewCompiler(&Config{
|
|
551
|
+
Dir: moduleDir,
|
|
552
|
+
OutputPath: out,
|
|
553
|
+
AllDependencies: true,
|
|
554
|
+
}, nil, nil)
|
|
555
|
+
if err != nil {
|
|
556
|
+
t.Fatal(err.Error())
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
560
|
+
t.Fatal(err.Error())
|
|
561
|
+
}
|
|
562
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "iofslstat", "main.gs.ts"))
|
|
563
|
+
if err != nil {
|
|
564
|
+
t.Fatal(err.Error())
|
|
565
|
+
}
|
|
566
|
+
text := string(content)
|
|
567
|
+
if !strings.Contains(text, "export async function Use(") {
|
|
568
|
+
t.Fatalf("fs.Lstat caller was not marked async:\n%s", text)
|
|
569
|
+
}
|
|
570
|
+
if !strings.Contains(text, "await fs.Lstat(") {
|
|
571
|
+
t.Fatalf("io/fs Lstat override call was not awaited:\n%s", text)
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
func TestCompilePackagesAwaitsIOFSSubOverride(t *testing.T) {
|
|
576
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
577
|
+
"go.mod": "module example.test/iofssub\n\ngo 1.25.3\n",
|
|
578
|
+
"main.go": strings.Join([]string{
|
|
579
|
+
"package main",
|
|
580
|
+
"import \"io/fs\"",
|
|
581
|
+
"type memFS struct{}",
|
|
582
|
+
"func (memFS) Open(name string) (fs.File, error) { return nil, fs.ErrNotExist }",
|
|
583
|
+
"func Use(fsys fs.FS) (fs.FS, error) {",
|
|
584
|
+
" return fs.Sub(fsys, \"pkg\")",
|
|
585
|
+
"}",
|
|
586
|
+
"func main() { _, _ = Use(memFS{}) }",
|
|
587
|
+
"",
|
|
588
|
+
}, "\n"),
|
|
589
|
+
})
|
|
590
|
+
out := filepath.Join(t.TempDir(), "out")
|
|
591
|
+
comp, err := NewCompiler(&Config{
|
|
592
|
+
Dir: moduleDir,
|
|
593
|
+
OutputPath: out,
|
|
594
|
+
AllDependencies: true,
|
|
595
|
+
}, nil, nil)
|
|
596
|
+
if err != nil {
|
|
597
|
+
t.Fatal(err.Error())
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
601
|
+
t.Fatal(err.Error())
|
|
602
|
+
}
|
|
603
|
+
content, err := os.ReadFile(filepath.Join(out, "@goscript", "example.test", "iofssub", "main.gs.ts"))
|
|
604
|
+
if err != nil {
|
|
605
|
+
t.Fatal(err.Error())
|
|
606
|
+
}
|
|
607
|
+
text := string(content)
|
|
608
|
+
if !strings.Contains(text, "export async function Use(") {
|
|
609
|
+
t.Fatalf("fs.Sub caller was not marked async:\n%s", text)
|
|
610
|
+
}
|
|
611
|
+
if !strings.Contains(text, "return await fs.Sub(") {
|
|
612
|
+
t.Fatalf("io/fs Sub override call was not awaited:\n%s", text)
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
491
616
|
func TestCompilePackagesAwaitsAsyncSlicesSortFuncComparator(t *testing.T) {
|
|
492
617
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
493
618
|
"go.mod": "module example.test/slicesasyncsort\n\ngo 1.25.3\n",
|
|
@@ -5,6 +5,7 @@ import (
|
|
|
5
5
|
"go/ast"
|
|
6
6
|
"os"
|
|
7
7
|
"slices"
|
|
8
|
+
"strconv"
|
|
8
9
|
"strings"
|
|
9
10
|
|
|
10
11
|
"golang.org/x/tools/go/packages"
|
|
@@ -163,6 +164,9 @@ func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*Pac
|
|
|
163
164
|
Message: "package graph did not contain any package nodes",
|
|
164
165
|
})
|
|
165
166
|
}
|
|
167
|
+
if len(req.PackageBlocklist) != 0 {
|
|
168
|
+
diagnostics = append(diagnostics, packageBlocklistDiagnostics(graph, req.PackageBlocklist)...)
|
|
169
|
+
}
|
|
166
170
|
return graph, diagnostics
|
|
167
171
|
}
|
|
168
172
|
|
|
@@ -245,6 +249,94 @@ func newPackageGraphNode(pkg *packages.Package, requested bool, overrideFacts *O
|
|
|
245
249
|
}
|
|
246
250
|
}
|
|
247
251
|
|
|
252
|
+
func packageBlocklistDiagnostics(graph *PackageGraph, blocklist []string) []Diagnostic {
|
|
253
|
+
chain := packageBlocklistChain(graph, blocklist)
|
|
254
|
+
if len(chain) == 0 {
|
|
255
|
+
return nil
|
|
256
|
+
}
|
|
257
|
+
blocked := chain[len(chain)-1]
|
|
258
|
+
return []Diagnostic{{
|
|
259
|
+
Severity: DiagnosticSeverityError,
|
|
260
|
+
Code: "goscript/package-graph:blocklisted-package",
|
|
261
|
+
Message: "package graph contains blocklisted package " + strconv.Quote(blocked),
|
|
262
|
+
Detail: "import chain: " + strings.Join(chain, " -> "),
|
|
263
|
+
}}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
func packageBlocklistChain(graph *PackageGraph, blocklist []string) []string {
|
|
267
|
+
if graph == nil || len(graph.RequestedPackagePaths) == 0 {
|
|
268
|
+
return nil
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
roots := slices.Clone(graph.RequestedPackagePaths)
|
|
272
|
+
slices.Sort(roots)
|
|
273
|
+
|
|
274
|
+
type queueEntry struct {
|
|
275
|
+
path string
|
|
276
|
+
chain []string
|
|
277
|
+
}
|
|
278
|
+
queue := make([]queueEntry, 0, len(roots))
|
|
279
|
+
seen := make(map[string]bool)
|
|
280
|
+
for _, root := range roots {
|
|
281
|
+
if graph.NodesByPackagePath[root] == nil || seen[root] {
|
|
282
|
+
continue
|
|
283
|
+
}
|
|
284
|
+
seen[root] = true
|
|
285
|
+
queue = append(queue, queueEntry{
|
|
286
|
+
path: root,
|
|
287
|
+
chain: []string{root},
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
for len(queue) != 0 {
|
|
292
|
+
entry := queue[0]
|
|
293
|
+
queue = queue[1:]
|
|
294
|
+
if packagePathBlocklisted(entry.path, blocklist) {
|
|
295
|
+
return entry.chain
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
node := graph.NodesByPackagePath[entry.path]
|
|
299
|
+
if node == nil {
|
|
300
|
+
continue
|
|
301
|
+
}
|
|
302
|
+
// Override candidates are compiled from their GoScript override, whose
|
|
303
|
+
// TypeScript imports replace the native Go imports. collect prunes their
|
|
304
|
+
// native dependencies from the graph, so the blocklist walk must treat
|
|
305
|
+
// them as leaves; otherwise an overridden package (for example a
|
|
306
|
+
// reflect-free encoding/json override) would falsely chain to a
|
|
307
|
+
// blocklisted package it no longer imports in the compiled output.
|
|
308
|
+
if node.OverrideCandidate {
|
|
309
|
+
continue
|
|
310
|
+
}
|
|
311
|
+
imports := slices.Clone(node.Imports)
|
|
312
|
+
slices.Sort(imports)
|
|
313
|
+
for _, importPath := range imports {
|
|
314
|
+
if graph.NodesByPackagePath[importPath] == nil || seen[importPath] {
|
|
315
|
+
continue
|
|
316
|
+
}
|
|
317
|
+
seen[importPath] = true
|
|
318
|
+
nextChain := slices.Clone(entry.chain)
|
|
319
|
+
nextChain = append(nextChain, importPath)
|
|
320
|
+
queue = append(queue, queueEntry{
|
|
321
|
+
path: importPath,
|
|
322
|
+
chain: nextChain,
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return nil
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
func packagePathBlocklisted(path string, blocklist []string) bool {
|
|
330
|
+
for _, blocked := range blocklist {
|
|
331
|
+
// Match the package exactly or any subpackage, on a path-segment
|
|
332
|
+
// boundary so "crypto" blocks "crypto/ecdsa" but not "cryptobyte".
|
|
333
|
+
if path == blocked || strings.HasPrefix(path, blocked+"/") {
|
|
334
|
+
return true
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return false
|
|
338
|
+
}
|
|
339
|
+
|
|
248
340
|
func normalizePackageFileOrder(pkg *packages.Package) {
|
|
249
341
|
if pkg == nil {
|
|
250
342
|
return
|
|
@@ -266,6 +266,119 @@ func TestPackageGraphLoadsLocalReplacement(t *testing.T) {
|
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
func TestPackageBlocklistAllowsCleanFixture(t *testing.T) {
|
|
270
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
271
|
+
"go.mod": "module example.test/blockclean\n\ngo 1.25.3\n",
|
|
272
|
+
"main.go": "package blockclean\nimport \"example.test/blockclean/dep\"\nfunc Value() int { return dep.Value() }\n",
|
|
273
|
+
"dep/dep.go": "package dep\nfunc Value() int { return 1 }\n",
|
|
274
|
+
"other/doc.go": "package other\n",
|
|
275
|
+
})
|
|
276
|
+
comp, err := NewCompiler(&Config{
|
|
277
|
+
Dir: moduleDir,
|
|
278
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
279
|
+
AllDependencies: true,
|
|
280
|
+
PackageBlocklist: []string{"example.test/blockclean/other"},
|
|
281
|
+
}, nil, nil)
|
|
282
|
+
if err != nil {
|
|
283
|
+
t.Fatal(err.Error())
|
|
284
|
+
}
|
|
285
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
286
|
+
t.Fatalf("compile with clean blocklist failed: %v", err)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
func TestPackageBlocklistReportsShortestImportChain(t *testing.T) {
|
|
291
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
292
|
+
"go.mod": "module example.test/blockchain\n\ngo 1.25.3\n",
|
|
293
|
+
"main.go": "package blockchain\nimport \"example.test/blockchain/dep\"\nfunc Value() int { return dep.Value() }\n",
|
|
294
|
+
"dep/dep.go": "package dep\nimport \"example.test/blockchain/mid/blocked\"\nfunc Value() int { return blocked.Value() }\n",
|
|
295
|
+
"mid/leaf.go": "package mid\nimport \"example.test/blockchain/mid/blocked\"\nfunc Leaf() int { return blocked.Value() }\n",
|
|
296
|
+
"mid/blocked/blocked.go": "package blocked\nfunc Value() int { return 1 }\n",
|
|
297
|
+
})
|
|
298
|
+
comp, err := NewCompiler(&Config{
|
|
299
|
+
Dir: moduleDir,
|
|
300
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
301
|
+
AllDependencies: true,
|
|
302
|
+
PackageBlocklist: []string{"example.test/blockchain/mid/blocked"},
|
|
303
|
+
}, nil, nil)
|
|
304
|
+
if err != nil {
|
|
305
|
+
t.Fatal(err.Error())
|
|
306
|
+
}
|
|
307
|
+
_, err = comp.CompilePackages(context.Background(), ".")
|
|
308
|
+
if err == nil {
|
|
309
|
+
t.Fatal("expected blocklisted package diagnostic")
|
|
310
|
+
}
|
|
311
|
+
text := err.Error()
|
|
312
|
+
if !strings.Contains(text, "goscript/package-graph:blocklisted-package") {
|
|
313
|
+
t.Fatalf("expected blocklist diagnostic, got %q", text)
|
|
314
|
+
}
|
|
315
|
+
if !strings.Contains(text, `package graph contains blocklisted package "example.test/blockchain/mid/blocked"`) {
|
|
316
|
+
t.Fatalf("expected blocklisted package name, got %q", text)
|
|
317
|
+
}
|
|
318
|
+
expected := "example.test/blockchain -> example.test/blockchain/dep -> example.test/blockchain/mid/blocked"
|
|
319
|
+
if !strings.Contains(text, expected) {
|
|
320
|
+
t.Fatalf("expected shortest import chain %q, got %q", expected, text)
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
func TestPackageBlocklistIgnoresOverrideCandidateImports(t *testing.T) {
|
|
325
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
326
|
+
"go.mod": strings.Join([]string{
|
|
327
|
+
"module example.test/blockoverride",
|
|
328
|
+
"",
|
|
329
|
+
"go 1.25.3",
|
|
330
|
+
"",
|
|
331
|
+
"require example.test/over v0.0.0",
|
|
332
|
+
"replace example.test/over => ./over",
|
|
333
|
+
"",
|
|
334
|
+
}, "\n"),
|
|
335
|
+
"main.go": "package blockoverride\nimport (\n\t\"example.test/over\"\n\t\"example.test/blockoverride/dep\"\n)\nfunc Value() int { return over.Value() + dep.Value() }\n",
|
|
336
|
+
"dep/dep.go": "package dep\nimport \"example.test/blockoverride/mid\"\nfunc Value() int { return mid.Value() }\n",
|
|
337
|
+
"mid/mid.go": "package mid\nimport \"example.test/blockoverride/mid/blocked\"\nfunc Value() int { return blocked.Value() }\n",
|
|
338
|
+
"mid/blocked/blocked.go": "package blocked\nfunc Value() int { return 1 }\n",
|
|
339
|
+
"over/go.mod": strings.Join([]string{
|
|
340
|
+
"module example.test/over",
|
|
341
|
+
"",
|
|
342
|
+
"go 1.25.3",
|
|
343
|
+
"",
|
|
344
|
+
"require example.test/blockoverride v0.0.0",
|
|
345
|
+
"replace example.test/blockoverride => ../",
|
|
346
|
+
"",
|
|
347
|
+
}, "\n"),
|
|
348
|
+
"over/over.go": "package over\nimport \"example.test/blockoverride/mid/blocked\"\nfunc Value() int { return blocked.Value() }\n",
|
|
349
|
+
})
|
|
350
|
+
overrideDir := filepath.Join(t.TempDir(), "gs")
|
|
351
|
+
writeFixtureFile(t, overrideDir, "example.test/over/index.ts", "export function Value(): number { return 0 }\n")
|
|
352
|
+
|
|
353
|
+
overrideOwner := NewOverrideRegistryOwner(overrideDir)
|
|
354
|
+
req := &CompileRequest{
|
|
355
|
+
Patterns: []string{"."},
|
|
356
|
+
Dir: moduleDir,
|
|
357
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
358
|
+
DependencyMode: DependencyModeAll,
|
|
359
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
360
|
+
PackageBlocklist: []string{"example.test/blockoverride/mid/blocked"},
|
|
361
|
+
}
|
|
362
|
+
graph, diagnostics := NewPackageGraphOwner(overrideOwner).Load(context.Background(), req)
|
|
363
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
364
|
+
chain := packageBlocklistChain(graph, req.PackageBlocklist)
|
|
365
|
+
if slices.Contains(chain, "example.test/over") {
|
|
366
|
+
t.Fatalf("blocklist chain routed through override candidate: %v", chain)
|
|
367
|
+
}
|
|
368
|
+
expected := []string{
|
|
369
|
+
"example.test/blockoverride",
|
|
370
|
+
"example.test/blockoverride/dep",
|
|
371
|
+
"example.test/blockoverride/mid",
|
|
372
|
+
"example.test/blockoverride/mid/blocked",
|
|
373
|
+
}
|
|
374
|
+
if !slices.Equal(chain, expected) {
|
|
375
|
+
t.Fatalf("expected real import chain %v, got %v", expected, chain)
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
t.Fatal("expected blocklisted package diagnostic via the real import path")
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
269
382
|
func TestPackageGraphDetectsOverrideCandidates(t *testing.T) {
|
|
270
383
|
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
271
384
|
"go.mod": "module example.test/override\n\ngo 1.25.3\n",
|
|
@@ -756,6 +756,15 @@ func (o *SemanticModelOwner) collectFunctionFacts(
|
|
|
756
756
|
if typed.Op == token.ARROW {
|
|
757
757
|
markFunctionAsync(semFn, "channel-receive")
|
|
758
758
|
}
|
|
759
|
+
case *ast.RangeStmt:
|
|
760
|
+
if signatureForType(pkg.TypesInfo.TypeOf(typed.X)) != nil {
|
|
761
|
+
if called := calledFunction(pkg, typed.X); called != nil {
|
|
762
|
+
semFn.calls[functionOriginOrSelf(called)] = true
|
|
763
|
+
}
|
|
764
|
+
if rangeFunctionExprNeedsAwait(model, pkg, overrideFacts, typed.X) {
|
|
765
|
+
markFunctionAsync(semFn, "range-function")
|
|
766
|
+
}
|
|
767
|
+
}
|
|
759
768
|
case *ast.CallExpr:
|
|
760
769
|
if called := calledFunction(pkg, typed.Fun); called != nil {
|
|
761
770
|
semFn.calls[functionOriginOrSelf(called)] = true
|
|
@@ -785,6 +794,29 @@ func (o *SemanticModelOwner) collectFunctionFacts(
|
|
|
785
794
|
return diagnostics
|
|
786
795
|
}
|
|
787
796
|
|
|
797
|
+
func rangeFunctionExprNeedsAwait(
|
|
798
|
+
model *SemanticModel,
|
|
799
|
+
pkg *packages.Package,
|
|
800
|
+
overrideFacts *OverrideFacts,
|
|
801
|
+
expr ast.Expr,
|
|
802
|
+
) bool {
|
|
803
|
+
if model == nil || pkg == nil || signatureForType(pkg.TypesInfo.TypeOf(expr)) == nil {
|
|
804
|
+
return false
|
|
805
|
+
}
|
|
806
|
+
if called := calledFunction(pkg, expr); called != nil {
|
|
807
|
+
if semFn := semanticFunctionFor(model, called); semFn != nil && semFn.async {
|
|
808
|
+
return true
|
|
809
|
+
}
|
|
810
|
+
if called.Pkg() != nil && overrideFacts.IsFunctionAsync(called.Pkg().Path(), called.Name()) {
|
|
811
|
+
return true
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if overrideFacts.IsMethodAsync(overrideCallPackage(pkg, expr), overrideCallMethod(pkg, expr)) {
|
|
815
|
+
return true
|
|
816
|
+
}
|
|
817
|
+
return callUsesFunctionValue(pkg, expr)
|
|
818
|
+
}
|
|
819
|
+
|
|
788
820
|
func recordImmediateFuncLitAsyncFacts(
|
|
789
821
|
model *SemanticModel,
|
|
790
822
|
pkg *packages.Package,
|