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
package/README.md
CHANGED
|
@@ -89,6 +89,11 @@ npm install -g goscript
|
|
|
89
89
|
goscript compile --package . --output ./dist
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
GoScript v2 compiles Go packages from inside a Go module. Direct single-file
|
|
93
|
+
inputs such as `main.go` and browser/WASM source-string compilation are not
|
|
94
|
+
supported yet; those paths return structured diagnostics before output is
|
|
95
|
+
written.
|
|
96
|
+
|
|
92
97
|
## 📦 Using Generated Code in Your Project
|
|
93
98
|
|
|
94
99
|
After compiling your Go code to TypeScript, you'll need to set up your project appropriately.
|
|
@@ -125,6 +130,11 @@ Create or update your `tsconfig.json` with these settings:
|
|
|
125
130
|
|
|
126
131
|
You should be able to use any TypeScript bundler to compile the generated TypeScript.
|
|
127
132
|
|
|
133
|
+
For a generated `package main`, GoScript emits a main-script guard so the
|
|
134
|
+
generated module can be executed directly by a TypeScript runtime or bundler
|
|
135
|
+
that resolves `@goscript/*` imports. The `example/simple` package shows the
|
|
136
|
+
supported compile-and-run workflow.
|
|
137
|
+
|
|
128
138
|
## 🛠️ Integration & Usage
|
|
129
139
|
|
|
130
140
|
### Command Line
|
|
@@ -135,8 +145,10 @@ goscript compile --package ./my-go-code --output ./dist
|
|
|
135
145
|
|
|
136
146
|
**Options:**
|
|
137
147
|
|
|
138
|
-
- `--package <path>` - Go package to compile
|
|
148
|
+
- `--package <path>` - Go package pattern to compile
|
|
139
149
|
- `--output <dir>` - Output directory for TypeScript files
|
|
150
|
+
- `--dir <dir>` - Working directory for module/package loading
|
|
151
|
+
- `--build-flags <flag>` - Go package loader build flag, repeatable
|
|
140
152
|
|
|
141
153
|
### Programmatic API
|
|
142
154
|
|
|
@@ -10,83 +10,84 @@ import (
|
|
|
10
10
|
"github.com/sirupsen/logrus"
|
|
11
11
|
)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
cliCompilerPkg cli.StringSlice
|
|
17
|
-
cliCompilerBuildFlags cli.StringSlice
|
|
18
|
-
)
|
|
13
|
+
func compileCommands() []*cli.Command {
|
|
14
|
+
return []*cli.Command{newCompileCommand()}
|
|
15
|
+
}
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
Flags: []cli.Flag{
|
|
34
|
-
&cli.StringSliceFlag{
|
|
35
|
-
Name: "package",
|
|
36
|
-
Usage: "the package(s) to compile",
|
|
37
|
-
Aliases: []string{"p", "packages"},
|
|
38
|
-
EnvVars: []string{"GOSCRIPT_PACKAGES"},
|
|
39
|
-
Destination: &cliCompilerPkg,
|
|
40
|
-
},
|
|
41
|
-
&cli.StringFlag{
|
|
42
|
-
Name: "output",
|
|
43
|
-
Usage: "the output typescript path to use",
|
|
44
|
-
Destination: &cliCompilerConfig.OutputPath,
|
|
45
|
-
Value: "./output",
|
|
46
|
-
EnvVars: []string{"GOSCRIPT_OUTPUT"},
|
|
47
|
-
},
|
|
48
|
-
&cli.StringFlag{
|
|
49
|
-
Name: "dir",
|
|
50
|
-
Usage: "the working directory to use for the compiler (default: current directory)",
|
|
51
|
-
Destination: &cliCompilerConfig.Dir,
|
|
52
|
-
Value: "",
|
|
53
|
-
EnvVars: []string{"GOSCRIPT_DIR"},
|
|
54
|
-
},
|
|
55
|
-
&cli.StringSliceFlag{
|
|
56
|
-
Name: "build-flags",
|
|
57
|
-
Aliases: []string{"b", "buildflags", "build-flag", "buildflag"},
|
|
58
|
-
Usage: "Go build flags (tags) to use during analysis",
|
|
59
|
-
Destination: &cliCompilerBuildFlags,
|
|
60
|
-
EnvVars: []string{"GOSCRIPT_BUILD_FLAGS"},
|
|
61
|
-
},
|
|
62
|
-
&cli.BoolFlag{
|
|
63
|
-
Name: "disable-emit-builtin",
|
|
64
|
-
Usage: "disable emitting built-in packages that have handwritten equivalents",
|
|
65
|
-
Destination: &cliCompilerConfig.DisableEmitBuiltin,
|
|
66
|
-
Value: false,
|
|
67
|
-
EnvVars: []string{"GOSCRIPT_DISABLE_EMIT_BUILTIN"},
|
|
17
|
+
func newCompileCommand() *cli.Command {
|
|
18
|
+
var config compiler.Config
|
|
19
|
+
var packages cli.StringSlice
|
|
20
|
+
var buildFlags cli.StringSlice
|
|
21
|
+
|
|
22
|
+
return &cli.Command{
|
|
23
|
+
Name: "compile",
|
|
24
|
+
Category: "compile",
|
|
25
|
+
Usage: "compile a Go package to TypeScript",
|
|
26
|
+
Action: func(c *cli.Context) error {
|
|
27
|
+
config.BuildFlags = slices.Clone(buildFlags.Value())
|
|
28
|
+
return compilePackage(c.Context, &config, packages.Value())
|
|
68
29
|
},
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
30
|
+
Flags: []cli.Flag{
|
|
31
|
+
&cli.StringSliceFlag{
|
|
32
|
+
Name: "package",
|
|
33
|
+
Usage: "the package(s) to compile",
|
|
34
|
+
Aliases: []string{"p", "packages"},
|
|
35
|
+
EnvVars: []string{"GOSCRIPT_PACKAGES"},
|
|
36
|
+
Destination: &packages,
|
|
37
|
+
},
|
|
38
|
+
&cli.StringFlag{
|
|
39
|
+
Name: "output",
|
|
40
|
+
Usage: "the output typescript path to use",
|
|
41
|
+
Destination: &config.OutputPath,
|
|
42
|
+
Value: "./output",
|
|
43
|
+
EnvVars: []string{"GOSCRIPT_OUTPUT"},
|
|
44
|
+
},
|
|
45
|
+
&cli.StringFlag{
|
|
46
|
+
Name: "dir",
|
|
47
|
+
Usage: "the working directory to use for the compiler (default: current directory)",
|
|
48
|
+
Destination: &config.Dir,
|
|
49
|
+
Value: "",
|
|
50
|
+
EnvVars: []string{"GOSCRIPT_DIR"},
|
|
51
|
+
},
|
|
52
|
+
&cli.StringSliceFlag{
|
|
53
|
+
Name: "build-flags",
|
|
54
|
+
Aliases: []string{"b", "buildflags", "build-flag", "buildflag"},
|
|
55
|
+
Usage: "Go build flags (tags) to use during analysis",
|
|
56
|
+
Destination: &buildFlags,
|
|
57
|
+
EnvVars: []string{"GOSCRIPT_BUILD_FLAGS"},
|
|
58
|
+
},
|
|
59
|
+
&cli.BoolFlag{
|
|
60
|
+
Name: "disable-emit-builtin",
|
|
61
|
+
Usage: "disable emitting built-in packages that have handwritten equivalents",
|
|
62
|
+
Destination: &config.DisableEmitBuiltin,
|
|
63
|
+
Value: false,
|
|
64
|
+
EnvVars: []string{"GOSCRIPT_DISABLE_EMIT_BUILTIN"},
|
|
65
|
+
},
|
|
66
|
+
&cli.BoolFlag{
|
|
67
|
+
Name: "all-dependencies",
|
|
68
|
+
Usage: "compile all dependencies of the requested packages",
|
|
69
|
+
Aliases: []string{"all-deps", "deps"},
|
|
70
|
+
Destination: &config.AllDependencies,
|
|
71
|
+
Value: false,
|
|
72
|
+
EnvVars: []string{"GOSCRIPT_ALL_DEPENDENCIES"},
|
|
73
|
+
},
|
|
76
74
|
},
|
|
77
|
-
}
|
|
78
|
-
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
79
77
|
|
|
80
78
|
// compilePackage tries to compile the package.
|
|
81
|
-
func compilePackage(
|
|
82
|
-
pkgs := cliCompilerPkg.Value()
|
|
79
|
+
func compilePackage(ctx context.Context, config *compiler.Config, pkgs []string) error {
|
|
83
80
|
if len(pkgs) == 0 {
|
|
84
81
|
return errors.New("package(s) must be specified")
|
|
85
82
|
}
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
84
|
+
logger := logrus.New()
|
|
85
|
+
logger.SetLevel(logrus.DebugLevel)
|
|
86
|
+
le := logrus.NewEntry(logger)
|
|
87
|
+
comp, err := compiler.NewCompiler(config, le, nil)
|
|
88
|
+
if err != nil {
|
|
89
|
+
return err
|
|
90
|
+
}
|
|
91
|
+
_, err = comp.CompilePackages(ctx, pkgs...)
|
|
91
92
|
return err
|
|
92
93
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func TestCompileCommandForwardsBuildFlags(t *testing.T) {
|
|
11
|
+
dir := t.TempDir()
|
|
12
|
+
outputDir := filepath.Join(dir, "output")
|
|
13
|
+
writeFile(t, filepath.Join(dir, "go.mod"), "module example.test/cli\n\ngo 1.25.3\n")
|
|
14
|
+
writeFile(t, filepath.Join(dir, "default.go"), strings.Join([]string{
|
|
15
|
+
"//go:build !customtag",
|
|
16
|
+
"",
|
|
17
|
+
"package main",
|
|
18
|
+
`const selected = "default"`,
|
|
19
|
+
"",
|
|
20
|
+
}, "\n"))
|
|
21
|
+
writeFile(t, filepath.Join(dir, "tagged.go"), strings.Join([]string{
|
|
22
|
+
"//go:build customtag",
|
|
23
|
+
"",
|
|
24
|
+
"package main",
|
|
25
|
+
`const selected = "custom"`,
|
|
26
|
+
"",
|
|
27
|
+
}, "\n"))
|
|
28
|
+
writeFile(t, filepath.Join(dir, "main.go"), strings.Join([]string{
|
|
29
|
+
"package main",
|
|
30
|
+
"func main() {",
|
|
31
|
+
" println(selected)",
|
|
32
|
+
"}",
|
|
33
|
+
"",
|
|
34
|
+
}, "\n"))
|
|
35
|
+
|
|
36
|
+
app := newApp()
|
|
37
|
+
err := app.Run([]string{
|
|
38
|
+
"goscript",
|
|
39
|
+
"compile",
|
|
40
|
+
"--package",
|
|
41
|
+
".",
|
|
42
|
+
"--output",
|
|
43
|
+
outputDir,
|
|
44
|
+
"--dir",
|
|
45
|
+
dir,
|
|
46
|
+
"--build-flags",
|
|
47
|
+
"-tags=customtag",
|
|
48
|
+
})
|
|
49
|
+
if err != nil {
|
|
50
|
+
t.Fatalf("compile command failed: %v", err)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
generatedPath := filepath.Join(outputDir, "@goscript", "example.test", "cli", "main.gs.ts")
|
|
54
|
+
generated, err := os.ReadFile(generatedPath)
|
|
55
|
+
if err != nil {
|
|
56
|
+
t.Fatalf("read generated file: %v", err)
|
|
57
|
+
}
|
|
58
|
+
if !strings.Contains(string(generated), `./tagged.gs.ts`) {
|
|
59
|
+
t.Fatalf("expected main output to import tagged source, got:\n%s", generated)
|
|
60
|
+
}
|
|
61
|
+
taggedPath := filepath.Join(outputDir, "@goscript", "example.test", "cli", "tagged.gs.ts")
|
|
62
|
+
tagged, err := os.ReadFile(taggedPath)
|
|
63
|
+
if err != nil {
|
|
64
|
+
t.Fatalf("read tagged generated file: %v", err)
|
|
65
|
+
}
|
|
66
|
+
if !strings.Contains(string(tagged), `"custom"`) {
|
|
67
|
+
t.Fatalf("expected tagged generated file to use tagged source, got:\n%s", tagged)
|
|
68
|
+
}
|
|
69
|
+
if strings.Contains(string(tagged), `"default"`) {
|
|
70
|
+
t.Fatalf("tagged generated file used source excluded by build tag:\n%s", tagged)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func writeFile(t *testing.T, path string, content string) {
|
|
75
|
+
t.Helper()
|
|
76
|
+
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
|
77
|
+
t.Fatalf("write %s: %v", path, err)
|
|
78
|
+
}
|
|
79
|
+
}
|
package/cmd/goscript/main.go
CHANGED
|
@@ -10,6 +10,14 @@ import (
|
|
|
10
10
|
var version = "dev"
|
|
11
11
|
|
|
12
12
|
func main() {
|
|
13
|
+
app := newApp()
|
|
14
|
+
if err := app.Run(os.Args); err != nil {
|
|
15
|
+
_, _ = os.Stderr.WriteString(err.Error() + "\n")
|
|
16
|
+
os.Exit(1)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
func newApp() *cli.App {
|
|
13
21
|
app := cli.NewApp()
|
|
14
22
|
app.Version = version
|
|
15
23
|
|
|
@@ -18,10 +26,7 @@ func main() {
|
|
|
18
26
|
}
|
|
19
27
|
|
|
20
28
|
app.Usage = "GoScript compiles Go to Typescript."
|
|
21
|
-
app.Commands = append(app.Commands,
|
|
29
|
+
app.Commands = append(app.Commands, compileCommands()...)
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
_, _ = os.Stderr.WriteString(err.Error() + "\n")
|
|
25
|
-
os.Exit(1)
|
|
26
|
-
}
|
|
31
|
+
return app
|
|
27
32
|
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"strings"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// DependencyMode describes how much of the loaded package graph to keep.
|
|
10
|
+
type DependencyMode string
|
|
11
|
+
|
|
12
|
+
const (
|
|
13
|
+
// DependencyModeRequested keeps only requested package nodes.
|
|
14
|
+
DependencyModeRequested DependencyMode = "requested"
|
|
15
|
+
// DependencyModeAll keeps reachable dependency package nodes.
|
|
16
|
+
DependencyModeAll DependencyMode = "all"
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
// RuntimeEmissionMode describes how runtime packages should be handled.
|
|
20
|
+
type RuntimeEmissionMode string
|
|
21
|
+
|
|
22
|
+
const (
|
|
23
|
+
// RuntimeEmissionModeEmit emits required runtime packages with output.
|
|
24
|
+
RuntimeEmissionModeEmit RuntimeEmissionMode = "emit"
|
|
25
|
+
// RuntimeEmissionModeReference references runtime packages without emitting them.
|
|
26
|
+
RuntimeEmissionModeReference RuntimeEmissionMode = "reference"
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
// CompileRequest describes one compiler invocation after adapter normalization.
|
|
30
|
+
type CompileRequest struct {
|
|
31
|
+
// Patterns are the Go package patterns requested by the caller.
|
|
32
|
+
Patterns []string
|
|
33
|
+
// Dir is the working directory for package loading.
|
|
34
|
+
Dir string
|
|
35
|
+
// OutputPath is the root where TypeScript output would be written.
|
|
36
|
+
OutputPath string
|
|
37
|
+
// BuildFlags are forwarded to the Go package loader.
|
|
38
|
+
BuildFlags []string
|
|
39
|
+
// DependencyMode controls whether dependencies are included in the graph.
|
|
40
|
+
DependencyMode DependencyMode
|
|
41
|
+
// RuntimeEmissionMode controls runtime package emission policy.
|
|
42
|
+
RuntimeEmissionMode RuntimeEmissionMode
|
|
43
|
+
// AllDependencies controls whether the package graph should include deps.
|
|
44
|
+
AllDependencies bool
|
|
45
|
+
// DisableEmitBuiltin controls whether runtime packages are emitted.
|
|
46
|
+
DisableEmitBuiltin bool
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// CompileRequestOwner owns adapter input normalization and validation.
|
|
50
|
+
type CompileRequestOwner struct{}
|
|
51
|
+
|
|
52
|
+
// NewCompileRequestOwner creates a compile request owner.
|
|
53
|
+
func NewCompileRequestOwner() *CompileRequestOwner {
|
|
54
|
+
return &CompileRequestOwner{}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// NewRequest builds a request from public compiler config and package patterns.
|
|
58
|
+
func (o *CompileRequestOwner) NewRequest(conf Config, patterns []string) *CompileRequest {
|
|
59
|
+
dir := conf.Dir
|
|
60
|
+
if dir == "" {
|
|
61
|
+
dir = "."
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
dependencyMode := DependencyModeRequested
|
|
65
|
+
if conf.AllDependencies {
|
|
66
|
+
dependencyMode = DependencyModeAll
|
|
67
|
+
}
|
|
68
|
+
runtimeEmissionMode := RuntimeEmissionModeEmit
|
|
69
|
+
if conf.DisableEmitBuiltin {
|
|
70
|
+
runtimeEmissionMode = RuntimeEmissionModeReference
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return &CompileRequest{
|
|
74
|
+
Patterns: normalizePatterns(patterns),
|
|
75
|
+
Dir: strings.TrimSpace(dir),
|
|
76
|
+
OutputPath: strings.TrimSpace(conf.OutputPath),
|
|
77
|
+
BuildFlags: append([]string(nil), conf.BuildFlags...),
|
|
78
|
+
DependencyMode: dependencyMode,
|
|
79
|
+
RuntimeEmissionMode: runtimeEmissionMode,
|
|
80
|
+
AllDependencies: conf.AllDependencies,
|
|
81
|
+
DisableEmitBuiltin: conf.DisableEmitBuiltin,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Validate returns request diagnostics that must stop compilation before output.
|
|
86
|
+
func (o *CompileRequestOwner) Validate(req *CompileRequest) []Diagnostic {
|
|
87
|
+
if req == nil {
|
|
88
|
+
return []Diagnostic{{
|
|
89
|
+
Severity: DiagnosticSeverityError,
|
|
90
|
+
Code: "goscript/request:nil",
|
|
91
|
+
Message: "compile request is nil",
|
|
92
|
+
}}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
var diagnostics []Diagnostic
|
|
96
|
+
if len(req.Patterns) == 0 {
|
|
97
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
98
|
+
Severity: DiagnosticSeverityError,
|
|
99
|
+
Code: "goscript/request:no-packages",
|
|
100
|
+
Message: "at least one Go package pattern is required",
|
|
101
|
+
Detail: "Use goscript compile --package . from inside a Go module.",
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
if strings.TrimSpace(req.OutputPath) == "" {
|
|
105
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
106
|
+
Severity: DiagnosticSeverityError,
|
|
107
|
+
Code: "goscript/request:no-output",
|
|
108
|
+
Message: "output path root must be specified",
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
if strings.TrimSpace(req.Dir) == "" {
|
|
112
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
113
|
+
Severity: DiagnosticSeverityError,
|
|
114
|
+
Code: "goscript/request:no-working-dir",
|
|
115
|
+
Message: "working directory must be specified",
|
|
116
|
+
})
|
|
117
|
+
} else {
|
|
118
|
+
info, err := os.Stat(req.Dir)
|
|
119
|
+
switch {
|
|
120
|
+
case err != nil:
|
|
121
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
122
|
+
Severity: DiagnosticSeverityError,
|
|
123
|
+
Code: "goscript/request:working-dir",
|
|
124
|
+
Message: "working directory is not readable",
|
|
125
|
+
Detail: err.Error(),
|
|
126
|
+
})
|
|
127
|
+
case !info.IsDir():
|
|
128
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
129
|
+
Severity: DiagnosticSeverityError,
|
|
130
|
+
Code: "goscript/request:working-dir",
|
|
131
|
+
Message: "working directory must be a directory",
|
|
132
|
+
})
|
|
133
|
+
case !hasGoMod(req.Dir):
|
|
134
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
135
|
+
Severity: DiagnosticSeverityError,
|
|
136
|
+
Code: "goscript/request:no-module",
|
|
137
|
+
Message: "working directory is not inside a Go module",
|
|
138
|
+
Detail: "Run goscript from a directory containing go.mod, or pass --dir for a module directory.",
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if req.DependencyMode != DependencyModeRequested && req.DependencyMode != DependencyModeAll {
|
|
143
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
144
|
+
Severity: DiagnosticSeverityError,
|
|
145
|
+
Code: "goscript/request:dependency-mode",
|
|
146
|
+
Message: "dependency mode is invalid",
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
if req.RuntimeEmissionMode != RuntimeEmissionModeEmit &&
|
|
150
|
+
req.RuntimeEmissionMode != RuntimeEmissionModeReference {
|
|
151
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
152
|
+
Severity: DiagnosticSeverityError,
|
|
153
|
+
Code: "goscript/request:runtime-emission-mode",
|
|
154
|
+
Message: "runtime emission mode is invalid",
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
for _, flag := range req.BuildFlags {
|
|
158
|
+
if strings.TrimSpace(flag) == "" {
|
|
159
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
160
|
+
Severity: DiagnosticSeverityError,
|
|
161
|
+
Code: "goscript/request:empty-build-flag",
|
|
162
|
+
Message: "build flags must not contain empty values",
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for _, pattern := range req.Patterns {
|
|
168
|
+
trimmed := strings.TrimSpace(pattern)
|
|
169
|
+
if trimmed == "" {
|
|
170
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
171
|
+
Severity: DiagnosticSeverityError,
|
|
172
|
+
Code: "goscript/request:empty-package",
|
|
173
|
+
Message: "package pattern must not be empty",
|
|
174
|
+
})
|
|
175
|
+
continue
|
|
176
|
+
}
|
|
177
|
+
if strings.HasSuffix(filepath.Base(trimmed), ".go") {
|
|
178
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
179
|
+
Severity: DiagnosticSeverityError,
|
|
180
|
+
Code: "goscript/request:single-file-unsupported",
|
|
181
|
+
Message: "single-file compilation is not supported by the v2 compiler",
|
|
182
|
+
Detail: "Use a package pattern such as . or ./path from inside a Go module.",
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return diagnostics
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
func normalizePatterns(patterns []string) []string {
|
|
191
|
+
if len(patterns) == 0 {
|
|
192
|
+
return nil
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
normalized := make([]string, 0, len(patterns))
|
|
196
|
+
for _, pattern := range patterns {
|
|
197
|
+
normalized = append(normalized, strings.TrimSpace(pattern))
|
|
198
|
+
}
|
|
199
|
+
return normalized
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
func hasGoMod(dir string) bool {
|
|
203
|
+
abs, err := filepath.Abs(dir)
|
|
204
|
+
if err != nil {
|
|
205
|
+
return false
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for {
|
|
209
|
+
if _, err := os.Stat(filepath.Join(abs, "go.mod")); err == nil {
|
|
210
|
+
return true
|
|
211
|
+
}
|
|
212
|
+
parent := filepath.Dir(abs)
|
|
213
|
+
if parent == abs {
|
|
214
|
+
return false
|
|
215
|
+
}
|
|
216
|
+
abs = parent
|
|
217
|
+
}
|
|
218
|
+
}
|