goscript 0.2.4 → 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 +1238 -194
- package/compiler/lowering_bench_test.go +4 -0
- package/compiler/override-facts.go +1 -1
- 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 +241 -15
- 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/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/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/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/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/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
package/README.md
CHANGED
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p>
|
|
12
|
-
<a href="https://godoc.org/github.com/
|
|
13
|
-
<img src="https://godoc.org/github.com/
|
|
12
|
+
<a href="https://godoc.org/github.com/s4wave/goscript">
|
|
13
|
+
<img src="https://godoc.org/github.com/s4wave/goscript?status.svg" alt="GoDoc" />
|
|
14
14
|
</a>
|
|
15
|
-
<a href="https://goreportcard.com/report/github.com/
|
|
16
|
-
<img src="https://goreportcard.com/badge/github.com/
|
|
15
|
+
<a href="https://goreportcard.com/report/github.com/s4wave/goscript">
|
|
16
|
+
<img src="https://goreportcard.com/badge/github.com/s4wave/goscript" alt="Go Report Card" />
|
|
17
17
|
</a>
|
|
18
|
-
<a href="https://deepwiki.com/
|
|
18
|
+
<a href="https://deepwiki.com/s4wave/goscript">
|
|
19
19
|
<img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki" />
|
|
20
20
|
</a>
|
|
21
21
|
</p>
|
|
@@ -120,7 +120,7 @@ curl -fsSL https://bun.sh/install | bash
|
|
|
120
120
|
Install the CLI:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
go install github.com/
|
|
123
|
+
go install github.com/s4wave/goscript/cmd/goscript@latest
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
Compile a Go package from a module directory:
|
|
@@ -231,7 +231,7 @@ package main
|
|
|
231
231
|
import (
|
|
232
232
|
"context"
|
|
233
233
|
|
|
234
|
-
"github.com/
|
|
234
|
+
"github.com/s4wave/goscript/compiler"
|
|
235
235
|
)
|
|
236
236
|
|
|
237
237
|
func main() {
|
|
@@ -265,7 +265,7 @@ WASM adapter package:
|
|
|
265
265
|
```go
|
|
266
266
|
package main
|
|
267
267
|
|
|
268
|
-
import "github.com/
|
|
268
|
+
import "github.com/s4wave/goscript/compiler/wasm"
|
|
269
269
|
|
|
270
270
|
func main() {
|
|
271
271
|
ts, err := wasm.CompileSource(`
|
|
@@ -5,8 +5,8 @@ import (
|
|
|
5
5
|
"slices"
|
|
6
6
|
|
|
7
7
|
"github.com/aperturerobotics/cli"
|
|
8
|
-
"github.com/aperturerobotics/goscript/compiler"
|
|
9
8
|
"github.com/pkg/errors"
|
|
9
|
+
"github.com/s4wave/goscript/compiler"
|
|
10
10
|
"github.com/sirupsen/logrus"
|
|
11
11
|
)
|
|
12
12
|
|
|
@@ -19,6 +19,7 @@ func newCompileCommand() *cli.Command {
|
|
|
19
19
|
var packages cli.StringSlice
|
|
20
20
|
var buildFlags rawStringSlice
|
|
21
21
|
var overrideDirs cli.StringSlice
|
|
22
|
+
var packageBlocklist cli.StringSlice
|
|
22
23
|
|
|
23
24
|
return &cli.Command{
|
|
24
25
|
Name: "compile",
|
|
@@ -27,6 +28,7 @@ func newCompileCommand() *cli.Command {
|
|
|
27
28
|
Action: func(c *cli.Context) error {
|
|
28
29
|
config.BuildFlags = buildFlags.Value()
|
|
29
30
|
config.OverrideDirs = slices.Clone(overrideDirs.Value())
|
|
31
|
+
config.PackageBlocklist = slices.Clone(packageBlocklist.Value())
|
|
30
32
|
return compilePackage(c.Context, &config, packages.Value())
|
|
31
33
|
},
|
|
32
34
|
Flags: []cli.Flag{
|
|
@@ -65,6 +67,12 @@ func newCompileCommand() *cli.Command {
|
|
|
65
67
|
Destination: &overrideDirs,
|
|
66
68
|
EnvVars: []string{"GOSCRIPT_GS_PATH"},
|
|
67
69
|
},
|
|
70
|
+
&cli.StringSliceFlag{
|
|
71
|
+
Name: "package-blocklist",
|
|
72
|
+
Usage: "comma-separated Go import paths to reject from the compiled package graph",
|
|
73
|
+
Destination: &packageBlocklist,
|
|
74
|
+
EnvVars: []string{"GOSCRIPT_PACKAGE_BLOCKLIST"},
|
|
75
|
+
},
|
|
68
76
|
&cli.BoolFlag{
|
|
69
77
|
Name: "disable-emit-builtin",
|
|
70
78
|
Usage: "disable emitting built-in packages that have handwritten equivalents",
|
package/cmd/goscript/cmd-test.go
CHANGED
|
@@ -170,8 +170,52 @@ func TestCompileCommandPreservesCommaSeparatedBuildFlagEnvValue(t *testing.T) {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
func TestCompileCommandForwardsPackageBlocklist(t *testing.T) {
|
|
174
|
+
dir := t.TempDir()
|
|
175
|
+
outputDir := filepath.Join(dir, "output")
|
|
176
|
+
writeFile(t, filepath.Join(dir, "go.mod"), "module example.test/cli\n\ngo 1.25.3\n")
|
|
177
|
+
writeFile(t, filepath.Join(dir, "main.go"), strings.Join([]string{
|
|
178
|
+
"package cli",
|
|
179
|
+
`import "example.test/cli/dep"`,
|
|
180
|
+
"func Selected() int { return dep.Value() }",
|
|
181
|
+
"",
|
|
182
|
+
}, "\n"))
|
|
183
|
+
writeFile(t, filepath.Join(dir, "dep", "dep.go"), strings.Join([]string{
|
|
184
|
+
"package dep",
|
|
185
|
+
"func Value() int { return 1 }",
|
|
186
|
+
"",
|
|
187
|
+
}, "\n"))
|
|
188
|
+
|
|
189
|
+
app := newApp()
|
|
190
|
+
err := app.Run([]string{
|
|
191
|
+
"goscript",
|
|
192
|
+
"compile",
|
|
193
|
+
"--package",
|
|
194
|
+
".",
|
|
195
|
+
"--output",
|
|
196
|
+
outputDir,
|
|
197
|
+
"--dir",
|
|
198
|
+
dir,
|
|
199
|
+
"--all-dependencies",
|
|
200
|
+
"--package-blocklist=example.test/cli/dep,example.test/unused",
|
|
201
|
+
})
|
|
202
|
+
if err == nil {
|
|
203
|
+
t.Fatal("expected package blocklist error")
|
|
204
|
+
}
|
|
205
|
+
text := err.Error()
|
|
206
|
+
if !strings.Contains(text, "goscript/package-graph:blocklisted-package") {
|
|
207
|
+
t.Fatalf("expected blocklist diagnostic, got %q", text)
|
|
208
|
+
}
|
|
209
|
+
if !strings.Contains(text, "example.test/cli -> example.test/cli/dep") {
|
|
210
|
+
t.Fatalf("expected CLI diagnostic to include import chain, got %q", text)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
173
214
|
func writeFile(t *testing.T, path string, content string) {
|
|
174
215
|
t.Helper()
|
|
216
|
+
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
217
|
+
t.Fatalf("create parent for %s: %v", path, err)
|
|
218
|
+
}
|
|
175
219
|
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
|
176
220
|
t.Fatalf("write %s: %v", path, err)
|
|
177
221
|
}
|
package/cmd/goscript/deps.go
CHANGED
|
@@ -38,6 +38,8 @@ type CompileRequest struct {
|
|
|
38
38
|
BuildFlags []string
|
|
39
39
|
// OverrideDirs are additional GoScript override roots.
|
|
40
40
|
OverrideDirs []string
|
|
41
|
+
// PackageBlocklist rejects package paths in the loaded dependency closure.
|
|
42
|
+
PackageBlocklist []string
|
|
41
43
|
// DependencyMode controls whether dependencies are included in the graph.
|
|
42
44
|
DependencyMode DependencyMode
|
|
43
45
|
// RuntimeEmissionMode controls runtime package emission policy.
|
|
@@ -82,6 +84,7 @@ func (o *CompileRequestOwner) NewRequest(conf Config, patterns []string) *Compil
|
|
|
82
84
|
OutputPath: strings.TrimSpace(conf.OutputPath),
|
|
83
85
|
BuildFlags: append([]string(nil), conf.BuildFlags...),
|
|
84
86
|
OverrideDirs: append([]string(nil), conf.OverrideDirs...),
|
|
87
|
+
PackageBlocklist: normalizePackageBlocklist(conf.PackageBlocklist),
|
|
85
88
|
DependencyMode: dependencyMode,
|
|
86
89
|
RuntimeEmissionMode: runtimeEmissionMode,
|
|
87
90
|
ProtobufTypeScriptBinding: conf.ProtobufTypeScriptBinding,
|
|
@@ -235,6 +238,22 @@ func normalizePatterns(patterns []string) []string {
|
|
|
235
238
|
return normalized
|
|
236
239
|
}
|
|
237
240
|
|
|
241
|
+
func normalizePackageBlocklist(paths []string) []string {
|
|
242
|
+
var normalized []string
|
|
243
|
+
seen := make(map[string]bool)
|
|
244
|
+
for _, path := range paths {
|
|
245
|
+
for part := range strings.SplitSeq(path, ",") {
|
|
246
|
+
part = strings.TrimSpace(part)
|
|
247
|
+
if part == "" || seen[part] {
|
|
248
|
+
continue
|
|
249
|
+
}
|
|
250
|
+
seen[part] = true
|
|
251
|
+
normalized = append(normalized, part)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return normalized
|
|
255
|
+
}
|
|
256
|
+
|
|
238
257
|
func hasGoMod(dir string) bool {
|
|
239
258
|
abs, err := filepath.Abs(dir)
|
|
240
259
|
if err != nil {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"os"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"testing"
|
|
8
|
+
"time"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// benchDependencyPatterns is a representative existing GoScript dependency
|
|
12
|
+
// package graph: real util packages whose closure pulls in generics, channels,
|
|
13
|
+
// sync primitives, and context wiring, so the per-stage attribution reflects a
|
|
14
|
+
// realistic compile rather than a toy fixture.
|
|
15
|
+
var benchDependencyPatterns = []string{
|
|
16
|
+
"github.com/aperturerobotics/util/broadcast",
|
|
17
|
+
"github.com/aperturerobotics/util/keyed",
|
|
18
|
+
"github.com/aperturerobotics/util/ccontainer",
|
|
19
|
+
"github.com/aperturerobotics/util/refcount",
|
|
20
|
+
"github.com/aperturerobotics/util/routine",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// BenchmarkCompilePipelineStages runs the full CompileService pipeline over a
|
|
24
|
+
// representative existing dependency package graph and attributes wall time to
|
|
25
|
+
// each stage owner: package-graph load, semantic-model build, lowering, and
|
|
26
|
+
// TypeScript emit. It reports per-stage milliseconds-per-op metrics so a single
|
|
27
|
+
// run names the dominant compile-time stage. Service construction (which builds
|
|
28
|
+
// the runtime contract owner) is measured once as serviceinit-ms because the
|
|
29
|
+
// runtime contract is static setup, not a per-package stage. Emit is measured
|
|
30
|
+
// via EmitToMemory to isolate code-generation cost from output disk writes.
|
|
31
|
+
func BenchmarkCompilePipelineStages(b *testing.B) {
|
|
32
|
+
moduleRoot := benchModuleRoot(b)
|
|
33
|
+
outputPath := b.TempDir()
|
|
34
|
+
req := &CompileRequest{
|
|
35
|
+
Dir: moduleRoot,
|
|
36
|
+
OutputPath: outputPath,
|
|
37
|
+
Patterns: benchDependencyPatterns,
|
|
38
|
+
DependencyMode: DependencyModeAll,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Resolve the dependency graph once outside the timer to confirm the
|
|
42
|
+
// patterns load cleanly and fail fast before measuring.
|
|
43
|
+
if _, diagnostics := NewCompileService().PackageGraphOwner().Load(context.Background(), req); diagnosticsHaveErrors(diagnostics) {
|
|
44
|
+
b.Fatalf("load representative dependency graph: %v", diagnostics)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var serviceInit, graphLoad, semantic, lowering, emit time.Duration
|
|
48
|
+
loweringOpts := LoweringOptions{
|
|
49
|
+
SourceRoot: protobufTypeScriptBindingRoot(req.Dir),
|
|
50
|
+
DisplayRoot: req.Dir,
|
|
51
|
+
OutputPath: req.OutputPath,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
b.ReportAllocs()
|
|
55
|
+
b.ResetTimer()
|
|
56
|
+
for i := 0; i < b.N; i++ {
|
|
57
|
+
start := time.Now()
|
|
58
|
+
service := NewCompileService()
|
|
59
|
+
serviceInit += time.Since(start)
|
|
60
|
+
|
|
61
|
+
start = time.Now()
|
|
62
|
+
graph, graphDiagnostics := service.PackageGraphOwner().Load(context.Background(), req)
|
|
63
|
+
graphLoad += time.Since(start)
|
|
64
|
+
if diagnosticsHaveErrors(graphDiagnostics) {
|
|
65
|
+
b.Fatalf("graph load: %v", graphDiagnostics)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
start = time.Now()
|
|
69
|
+
model, semanticDiagnostics := service.SemanticModelOwner().Build(context.Background(), graph)
|
|
70
|
+
semantic += time.Since(start)
|
|
71
|
+
if diagnosticsHaveErrors(semanticDiagnostics) {
|
|
72
|
+
b.Fatalf("semantic build: %v", semanticDiagnostics)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
start = time.Now()
|
|
76
|
+
program, loweringDiagnostics := service.LoweringOwner().Build(context.Background(), model, loweringOpts)
|
|
77
|
+
lowering += time.Since(start)
|
|
78
|
+
if diagnosticsHaveErrors(loweringDiagnostics) {
|
|
79
|
+
b.Fatalf("lowering: %v", loweringDiagnostics)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
start = time.Now()
|
|
83
|
+
_, emitDiagnostics := service.TypeScriptEmitOwner().EmitToMemory(context.Background(), program)
|
|
84
|
+
emit += time.Since(start)
|
|
85
|
+
if diagnosticsHaveErrors(emitDiagnostics) {
|
|
86
|
+
b.Fatalf("emit: %v", emitDiagnostics)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
b.StopTimer()
|
|
90
|
+
|
|
91
|
+
perOpMs := func(total time.Duration) float64 {
|
|
92
|
+
return float64(total.Nanoseconds()) / float64(b.N) / 1e6
|
|
93
|
+
}
|
|
94
|
+
b.ReportMetric(perOpMs(serviceInit), "serviceinit-ms/op")
|
|
95
|
+
b.ReportMetric(perOpMs(graphLoad), "graphload-ms/op")
|
|
96
|
+
b.ReportMetric(perOpMs(semantic), "semantic-ms/op")
|
|
97
|
+
b.ReportMetric(perOpMs(lowering), "lowering-ms/op")
|
|
98
|
+
b.ReportMetric(perOpMs(emit), "emit-ms/op")
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// benchModuleRoot walks up from the test working directory to the module root
|
|
102
|
+
// that owns go.mod, so the bench loads util packages in the GoScript module's
|
|
103
|
+
// own dependency context (resolved go.sum and module cache) rather than a
|
|
104
|
+
// synthetic temp module.
|
|
105
|
+
func benchModuleRoot(tb testing.TB) string {
|
|
106
|
+
tb.Helper()
|
|
107
|
+
dir, err := os.Getwd()
|
|
108
|
+
if err != nil {
|
|
109
|
+
tb.Fatalf("getwd: %v", err)
|
|
110
|
+
}
|
|
111
|
+
for {
|
|
112
|
+
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
|
113
|
+
return dir
|
|
114
|
+
}
|
|
115
|
+
parent := filepath.Dir(dir)
|
|
116
|
+
if parent == dir {
|
|
117
|
+
tb.Fatal("module root with go.mod not found above test working directory")
|
|
118
|
+
}
|
|
119
|
+
dir = parent
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -7,7 +7,7 @@ import (
|
|
|
7
7
|
"strings"
|
|
8
8
|
"testing"
|
|
9
9
|
|
|
10
|
-
"github.com/
|
|
10
|
+
"github.com/s4wave/goscript/tests"
|
|
11
11
|
)
|
|
12
12
|
|
|
13
13
|
// TestCompliance runs the inherited GoScript compliance fixtures through the
|
|
@@ -59,6 +59,9 @@ func TestCompliance(t *testing.T) {
|
|
|
59
59
|
if expectedV2ComplianceGaps[name] {
|
|
60
60
|
t.Skip("expected v2 compliance gap")
|
|
61
61
|
}
|
|
62
|
+
if complianceHarnessExcluded[name] {
|
|
63
|
+
t.Skip("validated by a dedicated oracle test, not stdout comparison")
|
|
64
|
+
}
|
|
62
65
|
|
|
63
66
|
ranTests++
|
|
64
67
|
tests.RunGoScriptTestDir(t, workspaceDir, testPath)
|
|
@@ -120,6 +123,19 @@ func complianceCategory(name string) string {
|
|
|
120
123
|
}
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
// complianceHarnessExcluded lists fixture directories that the shared stdout
|
|
127
|
+
// comparison harness must skip because a dedicated test validates them another
|
|
128
|
+
// way. runtime_trace_proof, runtime_trace_empty, and runtime_trace_multibatch
|
|
129
|
+
// emit Go execution-trace bytes whose GoScript subset is intentionally not
|
|
130
|
+
// byte-identical to the native runtime trace, so TestRuntimeTraceProof,
|
|
131
|
+
// TestRuntimeTraceEmptyCapture, and TestRuntimeTraceMultiBatch validate them
|
|
132
|
+
// through the upstream Go trace reader.
|
|
133
|
+
var complianceHarnessExcluded = map[string]bool{
|
|
134
|
+
"runtime_trace_proof": true,
|
|
135
|
+
"runtime_trace_empty": true,
|
|
136
|
+
"runtime_trace_multibatch": true,
|
|
137
|
+
}
|
|
138
|
+
|
|
123
139
|
var expectedV2ComplianceGaps = map[string]bool{
|
|
124
140
|
"bitwise_and_not_assignment": true,
|
|
125
141
|
"buffer_value_field_error": true,
|
package/compiler/config.go
CHANGED
|
@@ -18,6 +18,8 @@ type Config struct {
|
|
|
18
18
|
BuildFlags []string
|
|
19
19
|
// OverrideDirs are additional GoScript override roots.
|
|
20
20
|
OverrideDirs []string
|
|
21
|
+
// PackageBlocklist rejects package paths in the loaded dependency closure.
|
|
22
|
+
PackageBlocklist []string
|
|
21
23
|
// AllDependencies controls whether dependencies are included in the graph.
|
|
22
24
|
AllDependencies bool
|
|
23
25
|
// DisableEmitBuiltin controls whether runtime packages are emitted.
|
|
@@ -12,9 +12,9 @@ import (
|
|
|
12
12
|
"sync"
|
|
13
13
|
"time"
|
|
14
14
|
|
|
15
|
-
"github.com/aperturerobotics/goscript/compiler"
|
|
16
|
-
"github.com/aperturerobotics/goscript/compiler/tsworkspace"
|
|
17
15
|
"github.com/pkg/errors"
|
|
16
|
+
"github.com/s4wave/goscript/compiler"
|
|
17
|
+
"github.com/s4wave/goscript/compiler/tsworkspace"
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
const combinedRuntimeResultPrefix = "__GOSCRIPT_PACKAGE_RESULT__"
|
|
@@ -11,7 +11,7 @@ import (
|
|
|
11
11
|
"testing"
|
|
12
12
|
"time"
|
|
13
13
|
|
|
14
|
-
"github.com/
|
|
14
|
+
"github.com/s4wave/goscript/compiler"
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
func TestDiagnosticsSummaryUsesCompilerFormatter(t *testing.T) {
|
|
@@ -604,7 +604,7 @@ func TestRunnerScopesPackageLoadErrors(t *testing.T) {
|
|
|
604
604
|
}
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
-
func
|
|
607
|
+
func TestRunnerCompilesAddressOfDereferencePackage(t *testing.T) {
|
|
608
608
|
moduleDir := writeFixture(t, map[string]string{
|
|
609
609
|
"go.mod": "module example.test/mixedcompile\n\ngo 1.25.3\n",
|
|
610
610
|
"clean/value.go": strings.Join([]string{
|
|
@@ -664,11 +664,8 @@ func TestRunnerScopesPackageCompileErrors(t *testing.T) {
|
|
|
664
664
|
t.Fatalf("clean package should pass independently: %#v", clean)
|
|
665
665
|
}
|
|
666
666
|
broken := requirePackageResult(t, result, "example.test/mixedcompile/broken")
|
|
667
|
-
if broken.Action !=
|
|
668
|
-
t.Fatalf("
|
|
669
|
-
}
|
|
670
|
-
if !strings.Contains(broken.Error, "unsupported address expression") {
|
|
671
|
-
t.Fatalf("broken package error should preserve compile diagnostic: %#v", broken)
|
|
667
|
+
if broken.Action != ActionPass {
|
|
668
|
+
t.Fatalf("address-of-dereference package should pass: %#v", broken)
|
|
672
669
|
}
|
|
673
670
|
}
|
|
674
671
|
|
package/compiler/index.test.ts
CHANGED
|
@@ -51,4 +51,32 @@ describe('GoScript Compiler API', () => {
|
|
|
51
51
|
stderr: expect.stringContaining('main.go:4:'),
|
|
52
52
|
})
|
|
53
53
|
}, 30000)
|
|
54
|
+
|
|
55
|
+
it('forwards the package blocklist to closure compiles', async () => {
|
|
56
|
+
const dir = await mkdtemp(join(tmpdir(), 'goscript-api-blocklist-'))
|
|
57
|
+
const output = join(dir, 'output')
|
|
58
|
+
await mkdir(join(dir, 'dep'), { recursive: true })
|
|
59
|
+
await writeFile(join(dir, 'go.mod'), 'module example.test/apiblock\n\ngo 1.25.3\n')
|
|
60
|
+
await writeFile(join(dir, 'main.go'), [
|
|
61
|
+
'package apiblock',
|
|
62
|
+
'import "example.test/apiblock/dep"',
|
|
63
|
+
'func Value() int { return dep.Value() }',
|
|
64
|
+
'',
|
|
65
|
+
].join('\n'))
|
|
66
|
+
await writeFile(join(dir, 'dep', 'dep.go'), [
|
|
67
|
+
'package dep',
|
|
68
|
+
'func Value() int { return 1 }',
|
|
69
|
+
'',
|
|
70
|
+
].join('\n'))
|
|
71
|
+
|
|
72
|
+
await expect(compile({
|
|
73
|
+
pkg: '.',
|
|
74
|
+
output,
|
|
75
|
+
dir,
|
|
76
|
+
allDependencies: true,
|
|
77
|
+
packageBlocklist: ['example.test/apiblock/dep'],
|
|
78
|
+
})).rejects.toMatchObject({
|
|
79
|
+
stderr: expect.stringContaining('example.test/apiblock -> example.test/apiblock/dep'),
|
|
80
|
+
})
|
|
81
|
+
}, 30000)
|
|
54
82
|
})
|
package/compiler/index.ts
CHANGED
|
@@ -19,6 +19,10 @@ export interface CompileConfig {
|
|
|
19
19
|
output?: string
|
|
20
20
|
/** The working directory for the compiler. Defaults to the current working directory. */
|
|
21
21
|
dir?: string
|
|
22
|
+
/** Compile all transitive dependencies of the requested package. */
|
|
23
|
+
allDependencies?: boolean
|
|
24
|
+
/** Go import paths to reject from the compiled package graph. */
|
|
25
|
+
packageBlocklist?: string[] | string
|
|
22
26
|
/** The path to the goscript executable. Defaults to `go run ./cmd/goscript`. */
|
|
23
27
|
goscriptPath?: string
|
|
24
28
|
}
|
|
@@ -33,33 +37,45 @@ export async function compile(config: CompileConfig): Promise<void> {
|
|
|
33
37
|
|
|
34
38
|
const cwd = config.dir ? path.resolve(config.dir) : process.cwd()
|
|
35
39
|
const output = config.output ? path.resolve(config.output) : './output'
|
|
40
|
+
const args = [
|
|
41
|
+
'compile',
|
|
42
|
+
'--package',
|
|
43
|
+
config.pkg,
|
|
44
|
+
'--output',
|
|
45
|
+
output,
|
|
46
|
+
'--dir',
|
|
47
|
+
cwd,
|
|
48
|
+
]
|
|
49
|
+
if (config.allDependencies) {
|
|
50
|
+
args.push('--all-dependencies')
|
|
51
|
+
}
|
|
52
|
+
const packageBlocklist = normalizePackageBlocklist(config.packageBlocklist)
|
|
53
|
+
if (packageBlocklist) {
|
|
54
|
+
args.push('--package-blocklist', packageBlocklist)
|
|
55
|
+
}
|
|
36
56
|
|
|
37
57
|
if (config.goscriptPath) {
|
|
38
|
-
await execFileAsync(config.goscriptPath,
|
|
39
|
-
'compile',
|
|
40
|
-
'--package',
|
|
41
|
-
config.pkg,
|
|
42
|
-
'--output',
|
|
43
|
-
output,
|
|
44
|
-
'--dir',
|
|
45
|
-
cwd,
|
|
46
|
-
])
|
|
58
|
+
await execFileAsync(config.goscriptPath, args)
|
|
47
59
|
return
|
|
48
60
|
}
|
|
49
61
|
|
|
50
62
|
await execFileAsync('go', [
|
|
51
63
|
'run',
|
|
52
64
|
path.join(projectRoot, 'cmd/goscript'),
|
|
53
|
-
|
|
54
|
-
'--package',
|
|
55
|
-
config.pkg,
|
|
56
|
-
'--output',
|
|
57
|
-
output,
|
|
58
|
-
'--dir',
|
|
59
|
-
cwd,
|
|
65
|
+
...args,
|
|
60
66
|
])
|
|
61
67
|
}
|
|
62
68
|
|
|
69
|
+
function normalizePackageBlocklist(value: string[] | string | undefined): string {
|
|
70
|
+
if (!value) {
|
|
71
|
+
return ''
|
|
72
|
+
}
|
|
73
|
+
if (Array.isArray(value)) {
|
|
74
|
+
return value.map((item) => item.trim()).filter(Boolean).join(',')
|
|
75
|
+
}
|
|
76
|
+
return value.trim()
|
|
77
|
+
}
|
|
78
|
+
|
|
63
79
|
/**
|
|
64
80
|
* Default export for convenience.
|
|
65
81
|
*/
|