goscript 0.1.3 → 0.1.4

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 (117) hide show
  1. package/cmd/goscript/cmd_compile.go +28 -8
  2. package/cmd/goscript/cmd_compile_test.go +105 -6
  3. package/compiler/build-flags.go +9 -10
  4. package/compiler/gotest/runner_test.go +127 -0
  5. package/compiler/lowering.go +596 -136
  6. package/compiler/lowering_bench_test.go +350 -0
  7. package/compiler/package-graph.go +61 -4
  8. package/compiler/package-graph_test.go +30 -0
  9. package/compiler/semantic-model-types.go +8 -0
  10. package/compiler/semantic-model.go +447 -22
  11. package/compiler/semantic-model_test.go +138 -0
  12. package/compiler/skeleton_test.go +948 -14
  13. package/compiler/typescript-emitter.go +19 -2
  14. package/dist/gs/builtin/builtin.d.ts +2 -2
  15. package/dist/gs/builtin/builtin.js +20 -0
  16. package/dist/gs/builtin/builtin.js.map +1 -1
  17. package/dist/gs/builtin/slice.js +5 -0
  18. package/dist/gs/builtin/slice.js.map +1 -1
  19. package/dist/gs/builtin/type.d.ts +1 -1
  20. package/dist/gs/builtin/type.js +72 -5
  21. package/dist/gs/builtin/type.js.map +1 -1
  22. package/dist/gs/compress/zlib/index.d.ts +3 -3
  23. package/dist/gs/compress/zlib/index.js +88 -26
  24. package/dist/gs/compress/zlib/index.js.map +1 -1
  25. package/dist/gs/crypto/sha1/index.js +2 -5
  26. package/dist/gs/crypto/sha1/index.js.map +1 -1
  27. package/dist/gs/crypto/sha256/index.js +2 -5
  28. package/dist/gs/crypto/sha256/index.js.map +1 -1
  29. package/dist/gs/crypto/sha512/index.js +2 -5
  30. package/dist/gs/crypto/sha512/index.js.map +1 -1
  31. package/dist/gs/embed/index.d.ts +6 -0
  32. package/dist/gs/embed/index.js +210 -5
  33. package/dist/gs/embed/index.js.map +1 -1
  34. package/dist/gs/fmt/fmt.d.ts +3 -3
  35. package/dist/gs/fmt/fmt.js +29 -16
  36. package/dist/gs/fmt/fmt.js.map +1 -1
  37. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +118 -6
  38. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  39. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  40. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  41. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  42. package/dist/gs/io/fs/readdir.js +5 -3
  43. package/dist/gs/io/fs/readdir.js.map +1 -1
  44. package/dist/gs/io/io.d.ts +10 -6
  45. package/dist/gs/io/io.js +87 -42
  46. package/dist/gs/io/io.js.map +1 -1
  47. package/dist/gs/math/bits/index.d.ts +26 -5
  48. package/dist/gs/math/bits/index.js +13 -24
  49. package/dist/gs/math/bits/index.js.map +1 -1
  50. package/dist/gs/net/http/index.d.ts +3 -1
  51. package/dist/gs/net/http/index.js +18 -1
  52. package/dist/gs/net/http/index.js.map +1 -1
  53. package/dist/gs/os/types_js.gs.d.ts +6 -2
  54. package/dist/gs/os/types_js.gs.js +169 -8
  55. package/dist/gs/os/types_js.gs.js.map +1 -1
  56. package/dist/gs/reflect/type.d.ts +1 -0
  57. package/dist/gs/reflect/type.js +80 -51
  58. package/dist/gs/reflect/type.js.map +1 -1
  59. package/dist/gs/strings/reader.d.ts +1 -1
  60. package/dist/gs/strings/reader.js +2 -2
  61. package/dist/gs/strings/reader.js.map +1 -1
  62. package/dist/gs/sync/sync.d.ts +2 -1
  63. package/dist/gs/sync/sync.js +37 -16
  64. package/dist/gs/sync/sync.js.map +1 -1
  65. package/dist/gs/syscall/js/index.js +9 -0
  66. package/dist/gs/syscall/js/index.js.map +1 -1
  67. package/dist/gs/testing/testing.js +8 -6
  68. package/dist/gs/testing/testing.js.map +1 -1
  69. package/gs/builtin/builtin.ts +25 -2
  70. package/gs/builtin/runtime-contract.test.ts +45 -0
  71. package/gs/builtin/slice.ts +7 -0
  72. package/gs/builtin/type.ts +85 -5
  73. package/gs/compress/zlib/index.test.ts +97 -0
  74. package/gs/compress/zlib/index.ts +117 -27
  75. package/gs/compress/zlib/meta.json +4 -1
  76. package/gs/crypto/sha1/index.test.ts +19 -2
  77. package/gs/crypto/sha1/index.ts +3 -6
  78. package/gs/crypto/sha256/index.test.ts +14 -2
  79. package/gs/crypto/sha256/index.ts +3 -6
  80. package/gs/crypto/sha512/index.test.ts +17 -2
  81. package/gs/crypto/sha512/index.ts +3 -6
  82. package/gs/embed/index.test.ts +87 -0
  83. package/gs/embed/index.ts +229 -5
  84. package/gs/fmt/fmt.test.ts +41 -3
  85. package/gs/fmt/fmt.ts +40 -17
  86. package/gs/fmt/meta.json +6 -1
  87. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +8 -1
  88. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +139 -11
  89. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  90. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  91. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  92. package/gs/io/fs/readdir.test.ts +38 -0
  93. package/gs/io/fs/readdir.ts +7 -3
  94. package/gs/io/io.test.ts +77 -6
  95. package/gs/io/io.ts +114 -52
  96. package/gs/io/meta.json +7 -1
  97. package/gs/math/bits/index.ts +52 -28
  98. package/gs/net/http/index.test.ts +16 -0
  99. package/gs/net/http/index.ts +19 -2
  100. package/gs/os/file_unix_js.test.ts +52 -0
  101. package/gs/os/meta.json +4 -0
  102. package/gs/os/readdir.test.ts +56 -0
  103. package/gs/os/types_js.gs.ts +169 -8
  104. package/gs/reflect/deepequal.test.ts +10 -1
  105. package/gs/reflect/type.ts +91 -56
  106. package/gs/reflect/typefor.test.ts +31 -1
  107. package/gs/strings/meta.json +5 -2
  108. package/gs/strings/reader.test.ts +2 -2
  109. package/gs/strings/reader.ts +2 -2
  110. package/gs/sync/meta.json +1 -0
  111. package/gs/sync/sync.test.ts +41 -1
  112. package/gs/sync/sync.ts +41 -16
  113. package/gs/syscall/js/index.test.ts +18 -0
  114. package/gs/syscall/js/index.ts +12 -0
  115. package/gs/testing/testing.test.ts +32 -3
  116. package/gs/testing/testing.ts +13 -10
  117. package/package.json +1 -1
@@ -17,7 +17,7 @@ func compileCommands() []*cli.Command {
17
17
  func newCompileCommand() *cli.Command {
18
18
  var config compiler.Config
19
19
  var packages cli.StringSlice
20
- var buildFlags cli.StringSlice
20
+ var buildFlags rawStringSlice
21
21
  var overrideDirs cli.StringSlice
22
22
 
23
23
  return &cli.Command{
@@ -25,7 +25,7 @@ func newCompileCommand() *cli.Command {
25
25
  Category: "compile",
26
26
  Usage: "compile a Go package to TypeScript",
27
27
  Action: func(c *cli.Context) error {
28
- config.BuildFlags = slices.Clone(buildFlags.Value())
28
+ config.BuildFlags = buildFlags.Value()
29
29
  config.OverrideDirs = slices.Clone(overrideDirs.Value())
30
30
  return compilePackage(c.Context, &config, packages.Value())
31
31
  },
@@ -51,12 +51,12 @@ func newCompileCommand() *cli.Command {
51
51
  Value: "",
52
52
  EnvVars: []string{"GOSCRIPT_DIR"},
53
53
  },
54
- &cli.StringSliceFlag{
55
- Name: "build-flags",
56
- Aliases: []string{"b", "buildflags", "build-flag", "buildflag"},
57
- Usage: "Go build flags (tags) to use during analysis",
58
- Destination: &buildFlags,
59
- EnvVars: []string{"GOSCRIPT_BUILD_FLAGS"},
54
+ &cli.GenericFlag{
55
+ Name: "build-flags",
56
+ Aliases: []string{"b", "buildflags", "build-flag", "buildflag"},
57
+ Usage: "Go build flags (tags) to use during analysis",
58
+ Value: &buildFlags,
59
+ EnvVars: []string{"GOSCRIPT_BUILD_FLAGS"},
60
60
  },
61
61
  &cli.StringSliceFlag{
62
62
  Name: "gs-path",
@@ -84,6 +84,26 @@ func newCompileCommand() *cli.Command {
84
84
  }
85
85
  }
86
86
 
87
+ type rawStringSlice []string
88
+
89
+ func (s *rawStringSlice) Set(value string) error {
90
+ if value == "" {
91
+ return nil
92
+ }
93
+ *s = append(*s, value)
94
+ return nil
95
+ }
96
+
97
+ func (s *rawStringSlice) String() string {
98
+ // Keep the flag default empty. The CLI package registers aliases against
99
+ // the same flag value, and echoing accumulated values here re-parses them.
100
+ return ""
101
+ }
102
+
103
+ func (s *rawStringSlice) Value() []string {
104
+ return slices.Clone(*s)
105
+ }
106
+
87
107
  // compilePackage tries to compile the package.
88
108
  func compilePackage(ctx context.Context, config *compiler.Config, pkgs []string) error {
89
109
  if len(pkgs) == 0 {
@@ -14,22 +14,20 @@ func TestCompileCommandForwardsBuildFlags(t *testing.T) {
14
14
  writeFile(t, filepath.Join(dir, "default.go"), strings.Join([]string{
15
15
  "//go:build !customtag",
16
16
  "",
17
- "package main",
17
+ "package cli",
18
18
  `const selected = "default"`,
19
19
  "",
20
20
  }, "\n"))
21
21
  writeFile(t, filepath.Join(dir, "tagged.go"), strings.Join([]string{
22
22
  "//go:build customtag",
23
23
  "",
24
- "package main",
24
+ "package cli",
25
25
  `const selected = "custom"`,
26
26
  "",
27
27
  }, "\n"))
28
28
  writeFile(t, filepath.Join(dir, "main.go"), strings.Join([]string{
29
- "package main",
30
- "func main() {",
31
- " println(selected)",
32
- "}",
29
+ "package cli",
30
+ "func Selected() string { return selected }",
33
31
  "",
34
32
  }, "\n"))
35
33
 
@@ -71,6 +69,107 @@ func TestCompileCommandForwardsBuildFlags(t *testing.T) {
71
69
  }
72
70
  }
73
71
 
72
+ func TestCompileCommandPreservesCommaSeparatedBuildFlagValues(t *testing.T) {
73
+ dir := t.TempDir()
74
+ outputDir := filepath.Join(dir, "output")
75
+ writeFile(t, filepath.Join(dir, "go.mod"), "module example.test/cli\n\ngo 1.25.3\n")
76
+ writeFile(t, filepath.Join(dir, "default.go"), strings.Join([]string{
77
+ "//go:build !(customtag && othertag)",
78
+ "",
79
+ "package cli",
80
+ `const selected = "default"`,
81
+ "",
82
+ }, "\n"))
83
+ writeFile(t, filepath.Join(dir, "tagged.go"), strings.Join([]string{
84
+ "//go:build customtag && othertag",
85
+ "",
86
+ "package cli",
87
+ `const selected = "custom"`,
88
+ "",
89
+ }, "\n"))
90
+ writeFile(t, filepath.Join(dir, "main.go"), strings.Join([]string{
91
+ "package cli",
92
+ "func Selected() string { return selected }",
93
+ "",
94
+ }, "\n"))
95
+
96
+ app := newApp()
97
+ err := app.Run([]string{
98
+ "goscript",
99
+ "compile",
100
+ "--package",
101
+ ".",
102
+ "--output",
103
+ outputDir,
104
+ "--dir",
105
+ dir,
106
+ "--build-flags=-tags=customtag,othertag",
107
+ })
108
+ if err != nil {
109
+ t.Fatalf("compile command failed: %v", err)
110
+ }
111
+
112
+ taggedPath := filepath.Join(outputDir, "@goscript", "example.test", "cli", "tagged.gs.ts")
113
+ tagged, err := os.ReadFile(taggedPath)
114
+ if err != nil {
115
+ t.Fatalf("read tagged generated file: %v", err)
116
+ }
117
+ if !strings.Contains(string(tagged), `"custom"`) {
118
+ t.Fatalf("expected tagged generated file to use tagged source, got:\n%s", tagged)
119
+ }
120
+ }
121
+
122
+ func TestCompileCommandPreservesCommaSeparatedBuildFlagEnvValue(t *testing.T) {
123
+ dir := t.TempDir()
124
+ outputDir := filepath.Join(dir, "output")
125
+ writeFile(t, filepath.Join(dir, "go.mod"), "module example.test/cli\n\ngo 1.25.3\n")
126
+ writeFile(t, filepath.Join(dir, "default.go"), strings.Join([]string{
127
+ "//go:build !(customtag && othertag)",
128
+ "",
129
+ "package cli",
130
+ `const selected = "default"`,
131
+ "",
132
+ }, "\n"))
133
+ writeFile(t, filepath.Join(dir, "tagged.go"), strings.Join([]string{
134
+ "//go:build customtag && othertag",
135
+ "",
136
+ "package cli",
137
+ `const selected = "custom"`,
138
+ "",
139
+ }, "\n"))
140
+ writeFile(t, filepath.Join(dir, "main.go"), strings.Join([]string{
141
+ "package cli",
142
+ "func Selected() string { return selected }",
143
+ "",
144
+ }, "\n"))
145
+
146
+ t.Setenv("GOSCRIPT_BUILD_FLAGS", "-tags=customtag,othertag")
147
+
148
+ app := newApp()
149
+ err := app.Run([]string{
150
+ "goscript",
151
+ "compile",
152
+ "--package",
153
+ ".",
154
+ "--output",
155
+ outputDir,
156
+ "--dir",
157
+ dir,
158
+ })
159
+ if err != nil {
160
+ t.Fatalf("compile command failed: %v", err)
161
+ }
162
+
163
+ taggedPath := filepath.Join(outputDir, "@goscript", "example.test", "cli", "tagged.gs.ts")
164
+ tagged, err := os.ReadFile(taggedPath)
165
+ if err != nil {
166
+ t.Fatalf("read tagged generated file: %v", err)
167
+ }
168
+ if !strings.Contains(string(tagged), `"custom"`) {
169
+ t.Fatalf("expected tagged generated file to use tagged source, got:\n%s", tagged)
170
+ }
171
+ }
172
+
74
173
  func writeFile(t *testing.T, path string, content string) {
75
174
  t.Helper()
76
175
  if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
@@ -1,8 +1,9 @@
1
1
  package compiler
2
2
 
3
- import "slices"
4
-
5
- import "strings"
3
+ import (
4
+ "slices"
5
+ "strings"
6
+ )
6
7
 
7
8
  const goScriptBuildTag = "goscript"
8
9
 
@@ -26,13 +27,11 @@ func appendBuildTag(value string, tag string) string {
26
27
  return r == ',' || r == ' ' || r == '\t' || r == '\n'
27
28
  })
28
29
  if slices.Contains(tags, tag) {
29
- return value
30
- }
31
- if strings.TrimSpace(value) == "" {
32
- return tag
30
+ return strings.Join(tags, " ")
33
31
  }
34
- if strings.ContainsAny(value, " \t\n") {
35
- return value + " " + tag
32
+ tags = append(tags, tag)
33
+ if len(tags) == 0 {
34
+ return ""
36
35
  }
37
- return value + "," + tag
36
+ return strings.Join(tags, " ")
38
37
  }
@@ -64,6 +64,53 @@ func TestRunnerRunsOrdinaryPackageTest(t *testing.T) {
64
64
  }
65
65
  }
66
66
 
67
+ func TestRunnerComparesInterfacePointerValuesByIdentity(t *testing.T) {
68
+ moduleDir := writeFixture(t, map[string]string{
69
+ "go.mod": "module example.test/ifaceptr\n\ngo 1.25.3\n",
70
+ "value_test.go": strings.Join([]string{
71
+ "package ifaceptr",
72
+ "",
73
+ "import \"testing\"",
74
+ "",
75
+ "type Snapshot interface {",
76
+ "\tValue() int",
77
+ "}",
78
+ "",
79
+ "type snapshot struct {",
80
+ "\tvalue int",
81
+ "}",
82
+ "",
83
+ "func (s *snapshot) Value() int { return s.value }",
84
+ "",
85
+ "func TestInterfacePointerValuesUsePointerIdentity(t *testing.T) {",
86
+ "\tvar first Snapshot = &snapshot{value: 1}",
87
+ "\tvar second Snapshot = &snapshot{value: 1}",
88
+ "\tif first == second {",
89
+ "\t\tt.Fatalf(\"distinct pointers stored in interfaces compared equal\")",
90
+ "\t}",
91
+ "\tsecond = first",
92
+ "\tif first != second {",
93
+ "\t\tt.Fatalf(\"same pointer stored in interfaces compared unequal\")",
94
+ "\t}",
95
+ "}",
96
+ "",
97
+ }, "\n"),
98
+ })
99
+
100
+ result, err := NewRunner().Run(context.Background(), &Request{
101
+ Dir: moduleDir,
102
+ Patterns: []string{"."},
103
+ Timeout: 30 * time.Second,
104
+ Verbose: true,
105
+ })
106
+ if err != nil {
107
+ t.Fatalf("run package test: %v", err)
108
+ }
109
+ if !result.Passed() {
110
+ t.Fatalf("expected package test to pass: %#v", result.Packages)
111
+ }
112
+ }
113
+
67
114
  func TestRunnerReportsShortMode(t *testing.T) {
68
115
  moduleDir := writeFixture(t, map[string]string{
69
116
  "go.mod": "module example.test/short\n\ngo 1.25.3\n",
@@ -258,6 +305,86 @@ func TestRunnerRunsExternalPackageTest(t *testing.T) {
258
305
  }
259
306
  }
260
307
 
308
+ func TestRunnerBatchCompilesSamePackageTests(t *testing.T) {
309
+ moduleDir := writeFixture(t, map[string]string{
310
+ "go.mod": "module example.test/samebatch\n\ngo 1.25.3\n",
311
+ "helper/value.go": strings.Join([]string{
312
+ "package helper",
313
+ "",
314
+ "func Value() int { return 2 }",
315
+ "",
316
+ }, "\n"),
317
+ "one/value.go": strings.Join([]string{
318
+ "package one",
319
+ "",
320
+ "func Value() int { return 1 }",
321
+ "",
322
+ }, "\n"),
323
+ "one/value_test.go": strings.Join([]string{
324
+ "package one",
325
+ "",
326
+ "import \"testing\"",
327
+ "",
328
+ "func TestOne(t *testing.T) {",
329
+ "\tif Value() != 1 {",
330
+ "\t\tt.Fatal(\"bad value\")",
331
+ "\t}",
332
+ "}",
333
+ "",
334
+ }, "\n"),
335
+ "two/value.go": strings.Join([]string{
336
+ "package two",
337
+ "",
338
+ "import \"example.test/samebatch/one\"",
339
+ "",
340
+ "func Value() int { return one.Value() + 1 }",
341
+ "",
342
+ }, "\n"),
343
+ "two/value_test.go": strings.Join([]string{
344
+ "package two",
345
+ "",
346
+ "import \"testing\"",
347
+ "",
348
+ "func TestTwo(t *testing.T) {",
349
+ "\tif Value() != 2 {",
350
+ "\t\tt.Fatal(\"bad value\")",
351
+ "\t}",
352
+ "}",
353
+ "",
354
+ }, "\n"),
355
+ "two/external_test.go": strings.Join([]string{
356
+ "package two_test",
357
+ "",
358
+ "import (",
359
+ "\t\"testing\"",
360
+ "",
361
+ "\t\"example.test/samebatch/helper\"",
362
+ "\t\"example.test/samebatch/two\"",
363
+ ")",
364
+ "",
365
+ "func TestTwoExternal(t *testing.T) {",
366
+ "\tif two.Value() != helper.Value() {",
367
+ "\t\tt.Fatal(\"bad value\")",
368
+ "\t}",
369
+ "}",
370
+ "",
371
+ }, "\n"),
372
+ })
373
+
374
+ result, err := NewRunner().Run(context.Background(), &Request{
375
+ Dir: moduleDir,
376
+ Patterns: []string{"./..."},
377
+ Timeout: 30 * time.Second,
378
+ Verbose: true,
379
+ })
380
+ if err != nil {
381
+ t.Fatalf("run same-package batch tests: %v", err)
382
+ }
383
+ if !result.Passed() {
384
+ t.Fatalf("expected same-package batch tests to pass: %#v", result.Packages)
385
+ }
386
+ }
387
+
261
388
  func TestRunnerAppliesOverridesToTestImports(t *testing.T) {
262
389
  moduleDir := writeFixture(t, map[string]string{
263
390
  "go.mod": "module example.test/testoverride\n\ngo 1.25.3\n",