goscript 0.0.84 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +23 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +15 -1
- package/dist/gs/builtin/hostio.js +134 -49
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.js +9 -9
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +27 -0
- package/gs/builtin/hostio.test.ts +177 -0
- package/gs/builtin/hostio.ts +171 -56
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +50 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +9 -9
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"os"
|
|
6
|
+
"sort"
|
|
7
|
+
|
|
8
|
+
gs "github.com/aperturerobotics/goscript"
|
|
9
|
+
"golang.org/x/tools/go/packages"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// PackageGraph is the immutable package graph produced for a compile request.
|
|
13
|
+
type PackageGraph struct {
|
|
14
|
+
// RequestedPatterns are the package patterns from the compile request.
|
|
15
|
+
RequestedPatterns []string
|
|
16
|
+
// RequestedPackagePaths are the loaded package paths for requested patterns.
|
|
17
|
+
RequestedPackagePaths []string
|
|
18
|
+
// Nodes are the deterministic package graph nodes.
|
|
19
|
+
Nodes []*PackageGraphNode
|
|
20
|
+
// NodesByPackagePath maps package path to graph node.
|
|
21
|
+
NodesByPackagePath map[string]*PackageGraphNode
|
|
22
|
+
|
|
23
|
+
packagesByPath map[string]*packages.Package
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// PackageGraphNode is one package in the loaded graph.
|
|
27
|
+
type PackageGraphNode struct {
|
|
28
|
+
// ID is the go/packages package identity.
|
|
29
|
+
ID string
|
|
30
|
+
// PkgPath is the stable Go package path.
|
|
31
|
+
PkgPath string
|
|
32
|
+
// Name is the Go package name.
|
|
33
|
+
Name string
|
|
34
|
+
// ModulePath is the owning module path when known.
|
|
35
|
+
ModulePath string
|
|
36
|
+
// ModuleDir is the owning module directory when known.
|
|
37
|
+
ModuleDir string
|
|
38
|
+
// GoFiles are the package source files.
|
|
39
|
+
GoFiles []string
|
|
40
|
+
// CompiledGoFiles are files selected by build constraints.
|
|
41
|
+
CompiledGoFiles []string
|
|
42
|
+
// Imports are imported package paths.
|
|
43
|
+
Imports []string
|
|
44
|
+
// Requested marks packages matched by request patterns.
|
|
45
|
+
Requested bool
|
|
46
|
+
// OverrideCandidate marks packages with a matching GoScript override package.
|
|
47
|
+
OverrideCandidate bool
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// PackageGraphOwner owns Go package loading and graph identity.
|
|
51
|
+
type PackageGraphOwner struct{}
|
|
52
|
+
|
|
53
|
+
// NewPackageGraphOwner creates the package graph owner.
|
|
54
|
+
func NewPackageGraphOwner() *PackageGraphOwner {
|
|
55
|
+
return &PackageGraphOwner{}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Load builds the package graph for a validated request.
|
|
59
|
+
func (o *PackageGraphOwner) Load(ctx context.Context, req *CompileRequest) (*PackageGraph, []Diagnostic) {
|
|
60
|
+
if err := ctx.Err(); err != nil {
|
|
61
|
+
return nil, []Diagnostic{{
|
|
62
|
+
Severity: DiagnosticSeverityError,
|
|
63
|
+
Code: "goscript/context:canceled",
|
|
64
|
+
Message: err.Error(),
|
|
65
|
+
}}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
cfg := &packages.Config{
|
|
69
|
+
Context: ctx,
|
|
70
|
+
Dir: req.Dir,
|
|
71
|
+
Env: append(os.Environ(), "GOOS=js", "GOARCH=wasm"),
|
|
72
|
+
BuildFlags: append([]string(nil), req.BuildFlags...),
|
|
73
|
+
Tests: false,
|
|
74
|
+
Mode: packages.NeedName |
|
|
75
|
+
packages.NeedFiles |
|
|
76
|
+
packages.NeedCompiledGoFiles |
|
|
77
|
+
packages.NeedImports |
|
|
78
|
+
packages.NeedDeps |
|
|
79
|
+
packages.NeedExportFile |
|
|
80
|
+
packages.NeedTypes |
|
|
81
|
+
packages.NeedSyntax |
|
|
82
|
+
packages.NeedTypesInfo |
|
|
83
|
+
packages.NeedTypesSizes |
|
|
84
|
+
packages.NeedModule,
|
|
85
|
+
}
|
|
86
|
+
pkgs, err := packages.Load(cfg, req.Patterns...)
|
|
87
|
+
if err != nil {
|
|
88
|
+
return nil, []Diagnostic{{
|
|
89
|
+
Severity: DiagnosticSeverityError,
|
|
90
|
+
Code: "goscript/package-graph:load",
|
|
91
|
+
Message: "failed to load Go packages",
|
|
92
|
+
Detail: err.Error(),
|
|
93
|
+
}}
|
|
94
|
+
}
|
|
95
|
+
if len(pkgs) == 0 {
|
|
96
|
+
return nil, []Diagnostic{{
|
|
97
|
+
Severity: DiagnosticSeverityError,
|
|
98
|
+
Code: "goscript/package-graph:no-packages",
|
|
99
|
+
Message: "package patterns did not match any packages",
|
|
100
|
+
}}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
graph := &PackageGraph{
|
|
104
|
+
RequestedPatterns: append([]string(nil), req.Patterns...),
|
|
105
|
+
NodesByPackagePath: make(map[string]*PackageGraphNode),
|
|
106
|
+
packagesByPath: make(map[string]*packages.Package),
|
|
107
|
+
RequestedPackagePaths: make([]string, 0, len(pkgs)),
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
requested := make(map[string]bool)
|
|
111
|
+
for _, pkg := range pkgs {
|
|
112
|
+
path := packagePath(pkg)
|
|
113
|
+
requested[path] = true
|
|
114
|
+
graph.RequestedPackagePaths = append(graph.RequestedPackagePaths, path)
|
|
115
|
+
}
|
|
116
|
+
sort.Strings(graph.RequestedPackagePaths)
|
|
117
|
+
|
|
118
|
+
var diagnostics []Diagnostic
|
|
119
|
+
seen := make(map[string]bool)
|
|
120
|
+
for _, pkg := range pkgs {
|
|
121
|
+
o.collect(graph, pkg, req.DependencyMode, requested, seen)
|
|
122
|
+
diagnostics = append(diagnostics, packageDiagnostics(pkg)...)
|
|
123
|
+
}
|
|
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
|
|
127
|
+
}
|
|
128
|
+
return graph.Nodes[i].PkgPath < graph.Nodes[j].PkgPath
|
|
129
|
+
})
|
|
130
|
+
if len(graph.Nodes) == 0 {
|
|
131
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
132
|
+
Severity: DiagnosticSeverityError,
|
|
133
|
+
Code: "goscript/package-graph:no-nodes",
|
|
134
|
+
Message: "package graph did not contain any package nodes",
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
return graph, diagnostics
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
func (o *PackageGraphOwner) collect(
|
|
141
|
+
graph *PackageGraph,
|
|
142
|
+
pkg *packages.Package,
|
|
143
|
+
mode DependencyMode,
|
|
144
|
+
requested map[string]bool,
|
|
145
|
+
seen map[string]bool,
|
|
146
|
+
) {
|
|
147
|
+
if pkg == nil || seen[pkg.ID] {
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
seen[pkg.ID] = true
|
|
151
|
+
|
|
152
|
+
path := packagePath(pkg)
|
|
153
|
+
node := newPackageGraphNode(pkg, requested[path])
|
|
154
|
+
graph.Nodes = append(graph.Nodes, node)
|
|
155
|
+
graph.NodesByPackagePath[path] = node
|
|
156
|
+
graph.packagesByPath[path] = pkg
|
|
157
|
+
|
|
158
|
+
if mode != DependencyModeAll || node.OverrideCandidate {
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
imports := make([]string, 0, len(pkg.Imports))
|
|
162
|
+
for importPath := range pkg.Imports {
|
|
163
|
+
imports = append(imports, importPath)
|
|
164
|
+
}
|
|
165
|
+
sort.Strings(imports)
|
|
166
|
+
for _, importPath := range imports {
|
|
167
|
+
o.collect(graph, pkg.Imports[importPath], mode, requested, seen)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func newPackageGraphNode(pkg *packages.Package, requested bool) *PackageGraphNode {
|
|
172
|
+
imports := make([]string, 0, len(pkg.Imports))
|
|
173
|
+
for importPath := range pkg.Imports {
|
|
174
|
+
imports = append(imports, importPath)
|
|
175
|
+
}
|
|
176
|
+
sort.Strings(imports)
|
|
177
|
+
|
|
178
|
+
var modulePath string
|
|
179
|
+
var moduleDir string
|
|
180
|
+
if pkg.Module != nil {
|
|
181
|
+
modulePath = pkg.Module.Path
|
|
182
|
+
moduleDir = pkg.Module.Dir
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return &PackageGraphNode{
|
|
186
|
+
ID: pkg.ID,
|
|
187
|
+
PkgPath: packagePath(pkg),
|
|
188
|
+
Name: pkg.Name,
|
|
189
|
+
ModulePath: modulePath,
|
|
190
|
+
ModuleDir: moduleDir,
|
|
191
|
+
GoFiles: append([]string(nil), pkg.GoFiles...),
|
|
192
|
+
CompiledGoFiles: append([]string(nil), pkg.CompiledGoFiles...),
|
|
193
|
+
Imports: imports,
|
|
194
|
+
Requested: requested,
|
|
195
|
+
OverrideCandidate: hasOverrideCandidate(packagePath(pkg)),
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
func packagePath(pkg *packages.Package) string {
|
|
200
|
+
if pkg == nil {
|
|
201
|
+
return ""
|
|
202
|
+
}
|
|
203
|
+
if pkg.PkgPath != "" {
|
|
204
|
+
return pkg.PkgPath
|
|
205
|
+
}
|
|
206
|
+
return pkg.ID
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
func packageDiagnostics(pkg *packages.Package) []Diagnostic {
|
|
210
|
+
if pkg == nil || len(pkg.Errors) == 0 {
|
|
211
|
+
return nil
|
|
212
|
+
}
|
|
213
|
+
diagnostics := make([]Diagnostic, 0, len(pkg.Errors))
|
|
214
|
+
for _, pkgErr := range pkg.Errors {
|
|
215
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
216
|
+
Severity: DiagnosticSeverityError,
|
|
217
|
+
Code: "goscript/package-graph:load-error",
|
|
218
|
+
Message: "Go package contains load errors",
|
|
219
|
+
Detail: pkgErr.Msg,
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
return diagnostics
|
|
223
|
+
}
|
|
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
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"os"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"slices"
|
|
8
|
+
"strings"
|
|
9
|
+
"testing"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
func TestCompileRequestValidation(t *testing.T) {
|
|
13
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
14
|
+
"go.mod": "module example.test/request\n\ngo 1.25.3\n",
|
|
15
|
+
"main.go": "package main\nfunc main() {}\n",
|
|
16
|
+
})
|
|
17
|
+
owner := NewCompileRequestOwner()
|
|
18
|
+
|
|
19
|
+
tests := []struct {
|
|
20
|
+
name string
|
|
21
|
+
req *CompileRequest
|
|
22
|
+
code string
|
|
23
|
+
}{
|
|
24
|
+
{
|
|
25
|
+
name: "empty package",
|
|
26
|
+
req: &CompileRequest{
|
|
27
|
+
Patterns: []string{""},
|
|
28
|
+
Dir: moduleDir,
|
|
29
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
30
|
+
DependencyMode: DependencyModeRequested,
|
|
31
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
32
|
+
},
|
|
33
|
+
code: "goscript/request:empty-package",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "single file",
|
|
37
|
+
req: &CompileRequest{
|
|
38
|
+
Patterns: []string{"main.go"},
|
|
39
|
+
Dir: moduleDir,
|
|
40
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
41
|
+
DependencyMode: DependencyModeRequested,
|
|
42
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
43
|
+
},
|
|
44
|
+
code: "goscript/request:single-file-unsupported",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "no output",
|
|
48
|
+
req: &CompileRequest{
|
|
49
|
+
Patterns: []string{"."},
|
|
50
|
+
Dir: moduleDir,
|
|
51
|
+
DependencyMode: DependencyModeRequested,
|
|
52
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
53
|
+
},
|
|
54
|
+
code: "goscript/request:no-output",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "no module",
|
|
58
|
+
req: &CompileRequest{
|
|
59
|
+
Patterns: []string{"."},
|
|
60
|
+
Dir: t.TempDir(),
|
|
61
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
62
|
+
DependencyMode: DependencyModeRequested,
|
|
63
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
64
|
+
},
|
|
65
|
+
code: "goscript/request:no-module",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "empty build flag",
|
|
69
|
+
req: &CompileRequest{
|
|
70
|
+
Patterns: []string{"."},
|
|
71
|
+
Dir: moduleDir,
|
|
72
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
73
|
+
BuildFlags: []string{" "},
|
|
74
|
+
DependencyMode: DependencyModeRequested,
|
|
75
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
76
|
+
},
|
|
77
|
+
code: "goscript/request:empty-build-flag",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "dependency mode",
|
|
81
|
+
req: &CompileRequest{
|
|
82
|
+
Patterns: []string{"."},
|
|
83
|
+
Dir: moduleDir,
|
|
84
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
85
|
+
DependencyMode: DependencyMode("invalid"),
|
|
86
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
87
|
+
},
|
|
88
|
+
code: "goscript/request:dependency-mode",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "runtime emission mode",
|
|
92
|
+
req: &CompileRequest{
|
|
93
|
+
Patterns: []string{"."},
|
|
94
|
+
Dir: moduleDir,
|
|
95
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
96
|
+
DependencyMode: DependencyModeRequested,
|
|
97
|
+
RuntimeEmissionMode: RuntimeEmissionMode("invalid"),
|
|
98
|
+
},
|
|
99
|
+
code: "goscript/request:runtime-emission-mode",
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
for _, tt := range tests {
|
|
104
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
105
|
+
diagnostics := owner.Validate(tt.req)
|
|
106
|
+
requireDiagnosticCode(t, diagnostics, tt.code)
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func TestPackageGraphLoadsRequestedPackage(t *testing.T) {
|
|
112
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
113
|
+
"go.mod": "module example.test/graph\n\ngo 1.25.3\n",
|
|
114
|
+
"main.go": "package main\nfunc main() {}\n",
|
|
115
|
+
})
|
|
116
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
117
|
+
Patterns: []string{"."},
|
|
118
|
+
Dir: moduleDir,
|
|
119
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
120
|
+
DependencyMode: DependencyModeRequested,
|
|
121
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
if len(graph.Nodes) != 1 {
|
|
125
|
+
t.Fatalf("expected one requested node, got %d", len(graph.Nodes))
|
|
126
|
+
}
|
|
127
|
+
node := graph.Nodes[0]
|
|
128
|
+
if node.PkgPath != "example.test/graph" || !node.Requested {
|
|
129
|
+
t.Fatalf("unexpected node: %#v", node)
|
|
130
|
+
}
|
|
131
|
+
if node.ModulePath != "example.test/graph" {
|
|
132
|
+
t.Fatalf("unexpected module path: %q", node.ModulePath)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func TestPackageGraphReportsLoadErrors(t *testing.T) {
|
|
137
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
138
|
+
"go.mod": "module example.test/loaderr\n\ngo 1.25.3\n",
|
|
139
|
+
"main.go": "package main\nimport \"missing.invalid/pkg\"\nfunc main() { _ = pkg.Value }\n",
|
|
140
|
+
})
|
|
141
|
+
_, diagnostics := NewPackageGraphOwner().Load(context.Background(), &CompileRequest{
|
|
142
|
+
Patterns: []string{"."},
|
|
143
|
+
Dir: moduleDir,
|
|
144
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
145
|
+
DependencyMode: DependencyModeRequested,
|
|
146
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
147
|
+
})
|
|
148
|
+
requireDiagnosticCode(t, diagnostics, "goscript/package-graph:load-error")
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
func TestPackageGraphHonorsBuildFlags(t *testing.T) {
|
|
152
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
153
|
+
"go.mod": "module example.test/tags\n\ngo 1.25.3\n",
|
|
154
|
+
"default.go": "package tags\nconst Selected = \"default\"\n",
|
|
155
|
+
"tagged.go": "//go:build customtag\n\npackage tags\nconst Tagged = true\n",
|
|
156
|
+
"excluded.go": "//go:build !customtag\n\npackage tags\nconst Excluded = true\n",
|
|
157
|
+
})
|
|
158
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
159
|
+
Patterns: []string{"."},
|
|
160
|
+
Dir: moduleDir,
|
|
161
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
162
|
+
BuildFlags: []string{"-tags=customtag"},
|
|
163
|
+
DependencyMode: DependencyModeRequested,
|
|
164
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
var compiled []string
|
|
168
|
+
for _, file := range graph.Nodes[0].CompiledGoFiles {
|
|
169
|
+
compiled = append(compiled, filepath.Base(file))
|
|
170
|
+
}
|
|
171
|
+
if !slices.Contains(compiled, "tagged.go") {
|
|
172
|
+
t.Fatalf("expected tagged.go in compiled files: %v", compiled)
|
|
173
|
+
}
|
|
174
|
+
if slices.Contains(compiled, "excluded.go") {
|
|
175
|
+
t.Fatalf("did not expect excluded.go in compiled files: %v", compiled)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func TestPackageGraphLoadsLocalReplacement(t *testing.T) {
|
|
180
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
181
|
+
"go.mod": strings.Join([]string{
|
|
182
|
+
"module example.test/app",
|
|
183
|
+
"",
|
|
184
|
+
"go 1.25.3",
|
|
185
|
+
"",
|
|
186
|
+
"require example.test/lib v0.0.0",
|
|
187
|
+
"replace example.test/lib => ./lib",
|
|
188
|
+
"",
|
|
189
|
+
}, "\n"),
|
|
190
|
+
"main.go": "package main\nimport \"example.test/lib\"\nfunc main() { lib.Value() }\n",
|
|
191
|
+
"lib/go.mod": "module example.test/lib\n\ngo 1.25.3\n",
|
|
192
|
+
"lib/value.go": "package lib\nfunc Value() int { return 1 }\n",
|
|
193
|
+
"lib/unused.go": "package lib\n",
|
|
194
|
+
})
|
|
195
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
196
|
+
Patterns: []string{"."},
|
|
197
|
+
Dir: moduleDir,
|
|
198
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
199
|
+
DependencyMode: DependencyModeAll,
|
|
200
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
if graph.NodesByPackagePath["example.test/lib"] == nil {
|
|
204
|
+
t.Fatalf("expected local replacement dependency in graph")
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
func TestPackageGraphDetectsOverrideCandidates(t *testing.T) {
|
|
209
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
210
|
+
"go.mod": "module example.test/override\n\ngo 1.25.3\n",
|
|
211
|
+
"main.go": "package main\nimport \"fmt\"\nfunc main() { fmt.Println(\"ok\") }\n",
|
|
212
|
+
})
|
|
213
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
214
|
+
Patterns: []string{"."},
|
|
215
|
+
Dir: moduleDir,
|
|
216
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
217
|
+
DependencyMode: DependencyModeAll,
|
|
218
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
node := graph.NodesByPackagePath["fmt"]
|
|
222
|
+
if node == nil {
|
|
223
|
+
t.Fatalf("expected fmt node in graph")
|
|
224
|
+
}
|
|
225
|
+
if !node.OverrideCandidate {
|
|
226
|
+
t.Fatalf("expected fmt to be detected as an override candidate")
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
func TestPackageGraphOverrideCandidatesRequirePackageIndex(t *testing.T) {
|
|
231
|
+
parent := "github.com/aperturerobotics/wasivm/wazero/kernel"
|
|
232
|
+
child := parent + "/runtime"
|
|
233
|
+
|
|
234
|
+
if hasOverrideCandidate(parent) {
|
|
235
|
+
t.Fatalf("parent directory without an override index was detected as an override candidate")
|
|
236
|
+
}
|
|
237
|
+
if !hasOverrideCandidate(child) {
|
|
238
|
+
t.Fatalf("nested package with an override index was not detected as an override candidate")
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
func loadPackageGraph(t *testing.T, req *CompileRequest) *PackageGraph {
|
|
243
|
+
t.Helper()
|
|
244
|
+
|
|
245
|
+
diagnostics := NewCompileRequestOwner().Validate(req)
|
|
246
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
247
|
+
t.Fatalf("request validation failed: %#v", diagnostics)
|
|
248
|
+
}
|
|
249
|
+
graph, diagnostics := NewPackageGraphOwner().Load(context.Background(), req)
|
|
250
|
+
if diagnosticsHaveErrors(diagnostics) {
|
|
251
|
+
t.Fatalf("package graph load failed: %#v", diagnostics)
|
|
252
|
+
}
|
|
253
|
+
return graph
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
func writePackageGraphFixture(t *testing.T, files map[string]string) string {
|
|
257
|
+
t.Helper()
|
|
258
|
+
|
|
259
|
+
dir := t.TempDir()
|
|
260
|
+
for name, contents := range files {
|
|
261
|
+
path := filepath.Join(dir, name)
|
|
262
|
+
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
263
|
+
t.Fatal(err.Error())
|
|
264
|
+
}
|
|
265
|
+
if err := os.WriteFile(path, []byte(contents), 0o644); err != nil {
|
|
266
|
+
t.Fatal(err.Error())
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return dir
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
func requireDiagnosticCode(t *testing.T, diagnostics []Diagnostic, code string) {
|
|
273
|
+
t.Helper()
|
|
274
|
+
|
|
275
|
+
for _, diagnostic := range diagnostics {
|
|
276
|
+
if diagnostic.Code == code {
|
|
277
|
+
return
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
t.Fatalf("missing diagnostic %q in %#v", code, diagnostics)
|
|
281
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
// CompilationResult describes a compiler run after adapter normalization.
|
|
4
|
+
type CompilationResult struct {
|
|
5
|
+
// CompiledPackages contains package paths compiled to TypeScript.
|
|
6
|
+
CompiledPackages []string
|
|
7
|
+
// CopiedPackages contains package paths copied from override packages.
|
|
8
|
+
CopiedPackages []string
|
|
9
|
+
// OriginalPackages contains the package patterns or package paths requested.
|
|
10
|
+
OriginalPackages []string
|
|
11
|
+
// Diagnostics contains all diagnostics produced by the compile request.
|
|
12
|
+
Diagnostics []Diagnostic
|
|
13
|
+
}
|