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.
Files changed (188) hide show
  1. package/README.md +13 -1
  2. package/cmd/goscript/cmd_compile.go +70 -69
  3. package/cmd/goscript/cmd_compile_test.go +79 -0
  4. package/cmd/goscript/main.go +10 -5
  5. package/compiler/compile-request.go +218 -0
  6. package/compiler/compiler.go +16 -1336
  7. package/compiler/compliance_test.go +196 -0
  8. package/compiler/config.go +6 -13
  9. package/compiler/diagnostic.go +70 -0
  10. package/compiler/index.test.ts +28 -28
  11. package/compiler/index.ts +40 -72
  12. package/compiler/lowered-program.go +132 -0
  13. package/compiler/lowering.go +3576 -0
  14. package/compiler/override-registry.go +422 -0
  15. package/compiler/override-registry_test.go +207 -0
  16. package/compiler/package-graph.go +231 -0
  17. package/compiler/package-graph_test.go +281 -0
  18. package/compiler/result.go +13 -0
  19. package/compiler/runtime-contract.go +279 -0
  20. package/compiler/runtime-contract_test.go +90 -0
  21. package/compiler/semantic-model-types.go +110 -0
  22. package/compiler/semantic-model.go +922 -0
  23. package/compiler/semantic-model_test.go +416 -0
  24. package/compiler/service.go +133 -0
  25. package/compiler/skeleton_test.go +1145 -0
  26. package/compiler/typescript-emitter.go +663 -0
  27. package/compiler/wasm/compile.go +2 -3
  28. package/compiler/wasm/compile_test.go +29 -0
  29. package/compiler/wasm_api.go +10 -159
  30. package/dist/compiler/index.d.ts +1 -3
  31. package/dist/compiler/index.js +31 -55
  32. package/dist/compiler/index.js.map +1 -1
  33. package/dist/gs/builtin/builtin.d.ts +13 -0
  34. package/dist/gs/builtin/builtin.js +23 -0
  35. package/dist/gs/builtin/builtin.js.map +1 -1
  36. package/dist/gs/builtin/channel.d.ts +3 -3
  37. package/dist/gs/builtin/channel.js.map +1 -1
  38. package/dist/gs/builtin/hostio.d.ts +15 -1
  39. package/dist/gs/builtin/hostio.js +134 -49
  40. package/dist/gs/builtin/hostio.js.map +1 -1
  41. package/dist/gs/builtin/index.d.ts +1 -0
  42. package/dist/gs/builtin/index.js +1 -0
  43. package/dist/gs/builtin/index.js.map +1 -1
  44. package/dist/gs/builtin/slice.d.ts +1 -1
  45. package/dist/gs/builtin/slice.js.map +1 -1
  46. package/dist/gs/builtin/type.d.ts +11 -0
  47. package/dist/gs/builtin/type.js +55 -1
  48. package/dist/gs/builtin/type.js.map +1 -1
  49. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  50. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  51. package/dist/gs/bytes/reader.gs.js.map +1 -1
  52. package/dist/gs/context/context.js.map +1 -1
  53. package/dist/gs/crypto/rand/index.d.ts +5 -0
  54. package/dist/gs/crypto/rand/index.js +77 -0
  55. package/dist/gs/crypto/rand/index.js.map +1 -0
  56. package/dist/gs/encoding/json/index.d.ts +3 -0
  57. package/dist/gs/encoding/json/index.js +160 -0
  58. package/dist/gs/encoding/json/index.js.map +1 -0
  59. package/dist/gs/fmt/fmt.js.map +1 -1
  60. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
  61. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
  62. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  63. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  64. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  65. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  66. package/dist/gs/go/scanner/index.d.ts +29 -0
  67. package/dist/gs/go/scanner/index.js +120 -0
  68. package/dist/gs/go/scanner/index.js.map +1 -0
  69. package/dist/gs/go/token/index.d.ts +31 -0
  70. package/dist/gs/go/token/index.js +82 -0
  71. package/dist/gs/go/token/index.js.map +1 -0
  72. package/dist/gs/internal/abi/index.js.map +1 -1
  73. package/dist/gs/io/fs/fs.js.map +1 -1
  74. package/dist/gs/io/fs/readdir.js.map +1 -1
  75. package/dist/gs/io/fs/readfile.js.map +1 -1
  76. package/dist/gs/io/fs/stat.js.map +1 -1
  77. package/dist/gs/io/fs/sub.js.map +1 -1
  78. package/dist/gs/io/io.js.map +1 -1
  79. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  80. package/dist/gs/os/error.gs.js +2 -4
  81. package/dist/gs/os/error.gs.js.map +1 -1
  82. package/dist/gs/os/exec.gs.js.map +1 -1
  83. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  84. package/dist/gs/os/rawconn_js.gs.js.map +1 -1
  85. package/dist/gs/os/root_js.gs.js.map +1 -1
  86. package/dist/gs/os/tempfile.gs.js +66 -9
  87. package/dist/gs/os/tempfile.gs.js.map +1 -1
  88. package/dist/gs/os/types.gs.js.map +1 -1
  89. package/dist/gs/os/types_js.gs.js +9 -9
  90. package/dist/gs/os/types_js.gs.js.map +1 -1
  91. package/dist/gs/os/types_unix.gs.js.map +1 -1
  92. package/dist/gs/path/filepath/match.js.map +1 -1
  93. package/dist/gs/path/match.js.map +1 -1
  94. package/dist/gs/path/path.js.map +1 -1
  95. package/dist/gs/reflect/index.d.ts +2 -2
  96. package/dist/gs/reflect/index.js +1 -1
  97. package/dist/gs/reflect/index.js.map +1 -1
  98. package/dist/gs/reflect/map.js.map +1 -1
  99. package/dist/gs/reflect/type.d.ts +2 -1
  100. package/dist/gs/reflect/type.js +85 -14
  101. package/dist/gs/reflect/type.js.map +1 -1
  102. package/dist/gs/reflect/types.js.map +1 -1
  103. package/dist/gs/reflect/visiblefields.js.map +1 -1
  104. package/dist/gs/runtime/runtime.js.map +1 -1
  105. package/dist/gs/sort/sort.gs.js.map +1 -1
  106. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  107. package/dist/gs/strconv/quote.gs.js.map +1 -1
  108. package/dist/gs/strings/builder.js.map +1 -1
  109. package/dist/gs/strings/reader.js.map +1 -1
  110. package/dist/gs/strings/replace.js.map +1 -1
  111. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  112. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  113. package/dist/gs/sync/sync.d.ts +1 -0
  114. package/dist/gs/sync/sync.js +12 -0
  115. package/dist/gs/sync/sync.js.map +1 -1
  116. package/dist/gs/time/time.js.map +1 -1
  117. package/dist/gs/unicode/unicode.js.map +1 -1
  118. package/go.mod +2 -2
  119. package/gs/builtin/builtin.ts +27 -0
  120. package/gs/builtin/hostio.test.ts +177 -0
  121. package/gs/builtin/hostio.ts +171 -56
  122. package/gs/builtin/index.ts +1 -0
  123. package/gs/builtin/runtime-contract.test.ts +230 -0
  124. package/gs/builtin/type.ts +84 -1
  125. package/gs/crypto/rand/index.test.ts +32 -0
  126. package/gs/crypto/rand/index.ts +90 -0
  127. package/gs/crypto/rand/meta.json +5 -0
  128. package/gs/encoding/json/index.test.ts +65 -0
  129. package/gs/encoding/json/index.ts +186 -0
  130. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
  131. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
  132. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
  133. package/gs/go/scanner/index.test.ts +50 -0
  134. package/gs/go/scanner/index.ts +157 -0
  135. package/gs/go/token/index.test.ts +21 -0
  136. package/gs/go/token/index.ts +120 -0
  137. package/gs/os/file_unix_js.test.ts +50 -0
  138. package/gs/os/meta.json +1 -2
  139. package/gs/os/tempfile.gs.test.ts +85 -0
  140. package/gs/os/tempfile.gs.ts +71 -11
  141. package/gs/os/types_js.gs.ts +9 -9
  142. package/gs/reflect/index.ts +1 -1
  143. package/gs/reflect/type.ts +106 -17
  144. package/gs/reflect/typefor.test.ts +75 -0
  145. package/gs/sync/sync.test.ts +24 -0
  146. package/gs/sync/sync.ts +12 -0
  147. package/package.json +13 -13
  148. package/compiler/analysis.go +0 -3475
  149. package/compiler/analysis_test.go +0 -338
  150. package/compiler/assignment.go +0 -580
  151. package/compiler/builtin_test.go +0 -92
  152. package/compiler/code-writer.go +0 -115
  153. package/compiler/compiler_test.go +0 -149
  154. package/compiler/composite-lit.go +0 -779
  155. package/compiler/config_test.go +0 -62
  156. package/compiler/constraint.go +0 -86
  157. package/compiler/decl.go +0 -801
  158. package/compiler/expr-call-async.go +0 -188
  159. package/compiler/expr-call-builtins.go +0 -208
  160. package/compiler/expr-call-helpers.go +0 -382
  161. package/compiler/expr-call-make.go +0 -318
  162. package/compiler/expr-call-type-conversion.go +0 -520
  163. package/compiler/expr-call.go +0 -413
  164. package/compiler/expr-selector.go +0 -343
  165. package/compiler/expr-star.go +0 -82
  166. package/compiler/expr-type.go +0 -442
  167. package/compiler/expr-value.go +0 -89
  168. package/compiler/expr.go +0 -773
  169. package/compiler/field.go +0 -183
  170. package/compiler/gs_dependencies_test.go +0 -298
  171. package/compiler/lit.go +0 -322
  172. package/compiler/output.go +0 -72
  173. package/compiler/primitive.go +0 -149
  174. package/compiler/protobuf.go +0 -697
  175. package/compiler/sanitize.go +0 -100
  176. package/compiler/spec-struct.go +0 -995
  177. package/compiler/spec-value.go +0 -540
  178. package/compiler/spec.go +0 -725
  179. package/compiler/stmt-assign.go +0 -664
  180. package/compiler/stmt-for.go +0 -266
  181. package/compiler/stmt-range.go +0 -475
  182. package/compiler/stmt-select.go +0 -262
  183. package/compiler/stmt-type-switch.go +0 -147
  184. package/compiler/stmt.go +0 -1308
  185. package/compiler/type-assert.go +0 -386
  186. package/compiler/type-info.go +0 -156
  187. package/compiler/type-utils.go +0 -207
  188. 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 (default: ".")
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
- var (
14
- cliCompiler *compiler.Compiler
15
- cliCompilerConfig compiler.Config
16
- cliCompilerPkg cli.StringSlice
17
- cliCompilerBuildFlags cli.StringSlice
18
- )
13
+ func compileCommands() []*cli.Command {
14
+ return []*cli.Command{newCompileCommand()}
15
+ }
19
16
 
20
- // CompileCommands are commands related to compiling code.
21
- var CompileCommands = []*cli.Command{{
22
- Name: "compile",
23
- Category: "compile",
24
- Usage: "compile a Go package to TypeScript",
25
- Action: compilePackage,
26
- Before: func(c *cli.Context) (err error) {
27
- logger := logrus.New()
28
- logger.SetLevel(logrus.DebugLevel)
29
- le := logrus.NewEntry(logger)
30
- cliCompiler, err = compiler.NewCompiler(&cliCompilerConfig, le, nil)
31
- return
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
- &cli.BoolFlag{
70
- Name: "all-dependencies",
71
- Usage: "compile all dependencies of the requested packages",
72
- Aliases: []string{"all-deps", "deps"},
73
- Destination: &cliCompilerConfig.AllDependencies,
74
- Value: false,
75
- EnvVars: []string{"GOSCRIPT_ALL_DEPENDENCIES"},
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(c *cli.Context) error {
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
- // build flags
88
- cliCompilerConfig.BuildFlags = slices.Clone(cliCompilerBuildFlags.Value())
89
-
90
- _, err := cliCompiler.CompilePackages(context.Background(), pkgs...)
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
+ }
@@ -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, CompileCommands...)
29
+ app.Commands = append(app.Commands, compileCommands()...)
22
30
 
23
- if err := app.Run(os.Args); err != nil {
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
+ }