goscript 0.1.3 → 0.2.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 (330) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +35 -8
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript/cmd_compile_test.go +105 -6
  8. package/compiler/build-flags.go +9 -10
  9. package/compiler/compile-request.go +12 -9
  10. package/compiler/compliance_test.go +0 -1
  11. package/compiler/config.go +2 -0
  12. package/compiler/gotest/request.go +28 -0
  13. package/compiler/gotest/runner.go +353 -27
  14. package/compiler/gotest/runner_test.go +400 -1
  15. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  16. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  17. package/compiler/lowered-program.go +24 -17
  18. package/compiler/lowering.go +988 -263
  19. package/compiler/lowering_bench_test.go +364 -0
  20. package/compiler/override-facts.go +15 -0
  21. package/compiler/override-parity-verifier.go +450 -0
  22. package/compiler/override-parity.go +122 -0
  23. package/compiler/override-registry_test.go +559 -0
  24. package/compiler/package-graph.go +61 -4
  25. package/compiler/package-graph_test.go +30 -0
  26. package/compiler/protobuf-ts-binding.go +514 -0
  27. package/compiler/protobuf-ts-binding_test.go +172 -0
  28. package/compiler/semantic-model-types.go +17 -4
  29. package/compiler/semantic-model.go +709 -72
  30. package/compiler/semantic-model_test.go +219 -0
  31. package/compiler/service.go +20 -1
  32. package/compiler/skeleton_test.go +1008 -20
  33. package/compiler/typescript-emitter.go +147 -15
  34. package/dist/gs/builtin/builtin.d.ts +2 -2
  35. package/dist/gs/builtin/builtin.js +20 -0
  36. package/dist/gs/builtin/builtin.js.map +1 -1
  37. package/dist/gs/builtin/slice.d.ts +2 -1
  38. package/dist/gs/builtin/slice.js +34 -4
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.d.ts +14 -6
  41. package/dist/gs/builtin/type.js +224 -64
  42. package/dist/gs/builtin/type.js.map +1 -1
  43. package/dist/gs/builtin/varRef.d.ts +11 -0
  44. package/dist/gs/builtin/varRef.js +57 -2
  45. package/dist/gs/builtin/varRef.js.map +1 -1
  46. package/dist/gs/bytes/buffer.gs.js +1 -1
  47. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  48. package/dist/gs/bytes/reader.gs.js +1 -1
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/compress/zlib/index.d.ts +13 -6
  51. package/dist/gs/compress/zlib/index.js +131 -35
  52. package/dist/gs/compress/zlib/index.js.map +1 -1
  53. package/dist/gs/crypto/sha1/index.js +2 -5
  54. package/dist/gs/crypto/sha1/index.js.map +1 -1
  55. package/dist/gs/crypto/sha256/index.js +2 -5
  56. package/dist/gs/crypto/sha256/index.js.map +1 -1
  57. package/dist/gs/crypto/sha512/index.js +2 -5
  58. package/dist/gs/crypto/sha512/index.js.map +1 -1
  59. package/dist/gs/embed/index.d.ts +6 -0
  60. package/dist/gs/embed/index.js +210 -5
  61. package/dist/gs/embed/index.js.map +1 -1
  62. package/dist/gs/encoding/json/index.d.ts +114 -0
  63. package/dist/gs/encoding/json/index.js +544 -36
  64. package/dist/gs/encoding/json/index.js.map +1 -1
  65. package/dist/gs/fmt/fmt.d.ts +3 -3
  66. package/dist/gs/fmt/fmt.js +29 -16
  67. package/dist/gs/fmt/fmt.js.map +1 -1
  68. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  69. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  70. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  71. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  72. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  73. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  74. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  75. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  76. package/dist/gs/go/scanner/index.d.ts +2 -0
  77. package/dist/gs/go/scanner/index.js +29 -5
  78. package/dist/gs/go/scanner/index.js.map +1 -1
  79. package/dist/gs/go/token/index.js +22 -6
  80. package/dist/gs/go/token/index.js.map +1 -1
  81. package/dist/gs/hash/index.d.ts +6 -0
  82. package/dist/gs/hash/index.js +20 -0
  83. package/dist/gs/hash/index.js.map +1 -1
  84. package/dist/gs/internal/goarch/index.d.ts +43 -3
  85. package/dist/gs/internal/goarch/index.js +42 -10
  86. package/dist/gs/internal/goarch/index.js.map +1 -1
  87. package/dist/gs/io/fs/fs.js +26 -14
  88. package/dist/gs/io/fs/fs.js.map +1 -1
  89. package/dist/gs/io/fs/readdir.js +8 -4
  90. package/dist/gs/io/fs/readdir.js.map +1 -1
  91. package/dist/gs/io/fs/sub.js +8 -1
  92. package/dist/gs/io/fs/sub.js.map +1 -1
  93. package/dist/gs/io/io.d.ts +12 -6
  94. package/dist/gs/io/io.js +87 -42
  95. package/dist/gs/io/io.js.map +1 -1
  96. package/dist/gs/math/bits/index.d.ts +31 -5
  97. package/dist/gs/math/bits/index.js +29 -28
  98. package/dist/gs/math/bits/index.js.map +1 -1
  99. package/dist/gs/mime/index.d.ts +16 -0
  100. package/dist/gs/mime/index.js +315 -6
  101. package/dist/gs/mime/index.js.map +1 -1
  102. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  103. package/dist/gs/net/http/httptest/index.js +85 -6
  104. package/dist/gs/net/http/httptest/index.js.map +1 -1
  105. package/dist/gs/net/http/index.d.ts +303 -6
  106. package/dist/gs/net/http/index.js +1615 -58
  107. package/dist/gs/net/http/index.js.map +1 -1
  108. package/dist/gs/os/dir_unix.gs.js +1 -1
  109. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  110. package/dist/gs/os/error.gs.js +1 -1
  111. package/dist/gs/os/error.gs.js.map +1 -1
  112. package/dist/gs/os/exec.gs.d.ts +1 -0
  113. package/dist/gs/os/exec.gs.js +4 -8
  114. package/dist/gs/os/exec.gs.js.map +1 -1
  115. package/dist/gs/os/exec_posix.gs.js +1 -1
  116. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  117. package/dist/gs/os/index.d.ts +1 -1
  118. package/dist/gs/os/index.js +1 -1
  119. package/dist/gs/os/index.js.map +1 -1
  120. package/dist/gs/os/proc.gs.d.ts +4 -0
  121. package/dist/gs/os/proc.gs.js +12 -6
  122. package/dist/gs/os/proc.gs.js.map +1 -1
  123. package/dist/gs/os/root_js.gs.js +1 -1
  124. package/dist/gs/os/root_js.gs.js.map +1 -1
  125. package/dist/gs/os/types.gs.js +1 -1
  126. package/dist/gs/os/types.gs.js.map +1 -1
  127. package/dist/gs/os/types_js.gs.d.ts +6 -2
  128. package/dist/gs/os/types_js.gs.js +170 -9
  129. package/dist/gs/os/types_js.gs.js.map +1 -1
  130. package/dist/gs/os/types_unix.gs.js +1 -1
  131. package/dist/gs/os/types_unix.gs.js.map +1 -1
  132. package/dist/gs/path/path.js +11 -7
  133. package/dist/gs/path/path.js.map +1 -1
  134. package/dist/gs/reflect/index.d.ts +5 -4
  135. package/dist/gs/reflect/index.js +4 -3
  136. package/dist/gs/reflect/index.js.map +1 -1
  137. package/dist/gs/reflect/map.js +15 -0
  138. package/dist/gs/reflect/map.js.map +1 -1
  139. package/dist/gs/reflect/type.d.ts +26 -6
  140. package/dist/gs/reflect/type.js +1498 -279
  141. package/dist/gs/reflect/type.js.map +1 -1
  142. package/dist/gs/reflect/types.d.ts +14 -6
  143. package/dist/gs/reflect/types.js +35 -1
  144. package/dist/gs/reflect/types.js.map +1 -1
  145. package/dist/gs/reflect/value.d.ts +1 -0
  146. package/dist/gs/reflect/value.js +83 -41
  147. package/dist/gs/reflect/value.js.map +1 -1
  148. package/dist/gs/reflect/visiblefields.js +4 -140
  149. package/dist/gs/reflect/visiblefields.js.map +1 -1
  150. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  151. package/dist/gs/runtime/pprof/index.js +50 -30
  152. package/dist/gs/runtime/pprof/index.js.map +1 -1
  153. package/dist/gs/runtime/runtime.js +5 -4
  154. package/dist/gs/runtime/runtime.js.map +1 -1
  155. package/dist/gs/runtime/trace/index.js +5 -19
  156. package/dist/gs/runtime/trace/index.js.map +1 -1
  157. package/dist/gs/strconv/atoi.gs.js +1 -1
  158. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  159. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  160. package/dist/gs/strconv/complex.gs.js +148 -0
  161. package/dist/gs/strconv/complex.gs.js.map +1 -0
  162. package/dist/gs/strconv/index.d.ts +1 -0
  163. package/dist/gs/strconv/index.js +1 -0
  164. package/dist/gs/strconv/index.js.map +1 -1
  165. package/dist/gs/strings/builder.js +1 -1
  166. package/dist/gs/strings/reader.d.ts +1 -1
  167. package/dist/gs/strings/reader.js +11 -7
  168. package/dist/gs/strings/reader.js.map +1 -1
  169. package/dist/gs/strings/replace.js +15 -7
  170. package/dist/gs/strings/replace.js.map +1 -1
  171. package/dist/gs/strings/strings.d.ts +5 -0
  172. package/dist/gs/strings/strings.js +57 -5
  173. package/dist/gs/strings/strings.js.map +1 -1
  174. package/dist/gs/sync/atomic/type.gs.js +9 -9
  175. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  176. package/dist/gs/sync/atomic/value.gs.js +2 -2
  177. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  178. package/dist/gs/sync/sync.d.ts +2 -1
  179. package/dist/gs/sync/sync.js +37 -16
  180. package/dist/gs/sync/sync.js.map +1 -1
  181. package/dist/gs/syscall/env.js +22 -14
  182. package/dist/gs/syscall/env.js.map +1 -1
  183. package/dist/gs/syscall/js/index.js +9 -0
  184. package/dist/gs/syscall/js/index.js.map +1 -1
  185. package/dist/gs/testing/testing.js +59 -15
  186. package/dist/gs/testing/testing.js.map +1 -1
  187. package/dist/gs/time/time.d.ts +24 -1
  188. package/dist/gs/time/time.js +43 -3
  189. package/dist/gs/time/time.js.map +1 -1
  190. package/dist/gs/unique/index.js +7 -1
  191. package/dist/gs/unique/index.js.map +1 -1
  192. package/go.mod +3 -3
  193. package/go.sum +16 -0
  194. package/gs/builtin/builtin.ts +25 -2
  195. package/gs/builtin/runtime-contract.test.ts +260 -18
  196. package/gs/builtin/slice.ts +51 -4
  197. package/gs/builtin/type.ts +310 -63
  198. package/gs/builtin/varRef.ts +85 -2
  199. package/gs/bytes/buffer.gs.ts +1 -1
  200. package/gs/bytes/reader.gs.ts +1 -1
  201. package/gs/compress/zlib/index.test.ts +159 -1
  202. package/gs/compress/zlib/index.ts +164 -37
  203. package/gs/compress/zlib/meta.json +4 -1
  204. package/gs/compress/zlib/parity.json +51 -0
  205. package/gs/crypto/sha1/index.test.ts +19 -2
  206. package/gs/crypto/sha1/index.ts +3 -6
  207. package/gs/crypto/sha256/index.test.ts +14 -2
  208. package/gs/crypto/sha256/index.ts +3 -6
  209. package/gs/crypto/sha512/index.test.ts +17 -2
  210. package/gs/crypto/sha512/index.ts +3 -6
  211. package/gs/embed/index.test.ts +87 -0
  212. package/gs/embed/index.ts +229 -5
  213. package/gs/encoding/json/index.test.ts +360 -6
  214. package/gs/encoding/json/index.ts +679 -38
  215. package/gs/encoding/json/parity.json +81 -0
  216. package/gs/fmt/fmt.test.ts +41 -3
  217. package/gs/fmt/fmt.ts +40 -17
  218. package/gs/fmt/meta.json +6 -1
  219. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  220. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  221. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  222. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  223. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  224. package/gs/github.com/pkg/errors/errors.ts +54 -30
  225. package/gs/go/scanner/index.test.ts +39 -56
  226. package/gs/go/scanner/index.ts +33 -5
  227. package/gs/go/scanner/parity.json +27 -0
  228. package/gs/go/token/index.ts +22 -6
  229. package/gs/hash/index.test.ts +20 -33
  230. package/gs/hash/index.ts +28 -0
  231. package/gs/hash/parity.json +21 -0
  232. package/gs/internal/goarch/index.test.ts +32 -0
  233. package/gs/internal/goarch/index.ts +45 -13
  234. package/gs/internal/goarch/parity.json +144 -0
  235. package/gs/io/fs/fs.ts +26 -14
  236. package/gs/io/fs/readdir.test.ts +38 -0
  237. package/gs/io/fs/readdir.ts +8 -4
  238. package/gs/io/fs/sub.ts +8 -1
  239. package/gs/io/io.test.ts +77 -6
  240. package/gs/io/io.ts +115 -52
  241. package/gs/io/meta.json +7 -1
  242. package/gs/io/parity.json +162 -0
  243. package/gs/math/bits/index.test.ts +14 -1
  244. package/gs/math/bits/index.ts +75 -32
  245. package/gs/math/bits/parity.json +156 -0
  246. package/gs/mime/index.test.ts +90 -0
  247. package/gs/mime/index.ts +369 -6
  248. package/gs/mime/parity.json +36 -0
  249. package/gs/net/http/httptest/index.test.ts +98 -2
  250. package/gs/net/http/httptest/index.ts +101 -6
  251. package/gs/net/http/httptest/parity.json +15 -0
  252. package/gs/net/http/index.test.ts +797 -12
  253. package/gs/net/http/index.ts +1874 -136
  254. package/gs/net/http/meta.json +16 -1
  255. package/gs/net/http/parity.json +193 -0
  256. package/gs/os/dir_unix.gs.ts +1 -1
  257. package/gs/os/error.gs.ts +1 -1
  258. package/gs/os/exec.gs.ts +4 -8
  259. package/gs/os/exec_posix.gs.ts +1 -1
  260. package/gs/os/file_unix_js.test.ts +52 -0
  261. package/gs/os/index.test.ts +9 -0
  262. package/gs/os/index.ts +1 -0
  263. package/gs/os/meta.json +4 -0
  264. package/gs/os/parity.json +9 -0
  265. package/gs/os/proc.gs.ts +18 -5
  266. package/gs/os/proc.test.ts +26 -0
  267. package/gs/os/readdir.test.ts +56 -0
  268. package/gs/os/root_js.gs.ts +1 -1
  269. package/gs/os/types.gs.ts +1 -1
  270. package/gs/os/types_js.gs.ts +170 -9
  271. package/gs/os/types_unix.gs.ts +1 -1
  272. package/gs/path/path.ts +11 -7
  273. package/gs/reflect/deepequal.test.ts +10 -1
  274. package/gs/reflect/field.test.ts +37 -15
  275. package/gs/reflect/function-types.test.ts +518 -22
  276. package/gs/reflect/index.ts +8 -6
  277. package/gs/reflect/map.ts +20 -0
  278. package/gs/reflect/meta.json +6 -4
  279. package/gs/reflect/parity.json +234 -0
  280. package/gs/reflect/sliceat.test.ts +156 -0
  281. package/gs/reflect/structof.test.ts +401 -0
  282. package/gs/reflect/type.ts +1980 -365
  283. package/gs/reflect/typefor.test.ts +540 -10
  284. package/gs/reflect/types.ts +43 -18
  285. package/gs/reflect/value.ts +105 -45
  286. package/gs/reflect/visiblefields.ts +5 -168
  287. package/gs/runtime/parity.json +24 -0
  288. package/gs/runtime/pprof/index.test.ts +29 -7
  289. package/gs/runtime/pprof/index.ts +56 -30
  290. package/gs/runtime/pprof/parity.json +27 -0
  291. package/gs/runtime/runtime.test.ts +3 -1
  292. package/gs/runtime/runtime.ts +4 -3
  293. package/gs/runtime/trace/index.test.ts +5 -3
  294. package/gs/runtime/trace/index.ts +8 -20
  295. package/gs/runtime/trace/parity.json +36 -0
  296. package/gs/strconv/atoi.gs.ts +1 -1
  297. package/gs/strconv/complex.gs.ts +174 -0
  298. package/gs/strconv/complex.test.ts +65 -0
  299. package/gs/strconv/index.ts +1 -0
  300. package/gs/strconv/parity.json +120 -0
  301. package/gs/strings/builder.ts +1 -1
  302. package/gs/strings/meta.json +5 -2
  303. package/gs/strings/parity.json +186 -0
  304. package/gs/strings/reader.test.ts +2 -2
  305. package/gs/strings/reader.ts +11 -7
  306. package/gs/strings/replace.ts +15 -7
  307. package/gs/strings/strings.test.ts +22 -2
  308. package/gs/strings/strings.ts +64 -6
  309. package/gs/sync/atomic/type.gs.ts +9 -9
  310. package/gs/sync/atomic/value.gs.ts +2 -2
  311. package/gs/sync/meta.json +1 -0
  312. package/gs/sync/sync.test.ts +41 -1
  313. package/gs/sync/sync.ts +41 -16
  314. package/gs/syscall/env.ts +29 -14
  315. package/gs/syscall/js/index.test.ts +18 -0
  316. package/gs/syscall/js/index.ts +12 -0
  317. package/gs/testing/testing.test.ts +99 -3
  318. package/gs/testing/testing.ts +95 -24
  319. package/gs/time/parity.json +225 -0
  320. package/gs/time/time.test.ts +20 -2
  321. package/gs/time/time.ts +49 -7
  322. package/gs/unique/index.ts +7 -1
  323. package/package.json +4 -2
  324. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  325. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
  326. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  327. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
  328. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
  329. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  330. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -176,6 +176,36 @@ func TestPackageGraphHonorsBuildFlags(t *testing.T) {
176
176
  }
177
177
  }
178
178
 
179
+ func TestPackageGraphNormalizesCompiledFileOrder(t *testing.T) {
180
+ moduleDir := writePackageGraphFixture(t, map[string]string{
181
+ "go.mod": "module example.test/order\n\ngo 1.25.3\n",
182
+ "z.go": "package order\nconst Z = 1\n",
183
+ "a.go": "package order\nconst A = 1\n",
184
+ "m.go": "package order\nconst M = 1\n",
185
+ })
186
+ graph := loadPackageGraph(t, &CompileRequest{
187
+ Patterns: []string{"."},
188
+ Dir: moduleDir,
189
+ OutputPath: filepath.Join(t.TempDir(), "out"),
190
+ DependencyMode: DependencyModeRequested,
191
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
192
+ })
193
+
194
+ pkg := graph.packagesByPath["example.test/order"]
195
+ if pkg == nil {
196
+ t.Fatalf("missing loaded package")
197
+ }
198
+ var compiled []string
199
+ var syntax []string
200
+ for idx, file := range pkg.Syntax {
201
+ compiled = append(compiled, filepath.Base(pkg.CompiledGoFiles[idx]))
202
+ syntax = append(syntax, filepath.Base(pkg.Fset.Position(file.Package).Filename))
203
+ }
204
+ if want := []string{"a.go", "m.go", "z.go"}; !slices.Equal(compiled, want) || !slices.Equal(syntax, want) {
205
+ t.Fatalf("compiled files and syntax must sort together, got compiled=%v syntax=%v", compiled, syntax)
206
+ }
207
+ }
208
+
179
209
  func TestPackageGraphAddsGoScriptBuildTag(t *testing.T) {
180
210
  moduleDir := writePackageGraphFixture(t, map[string]string{
181
211
  "go.mod": "module example.test/goscripttag\n\ngo 1.25.3\n",
@@ -0,0 +1,514 @@
1
+ package compiler
2
+
3
+ import (
4
+ "fmt"
5
+ "go/ast"
6
+ "os"
7
+ "path/filepath"
8
+ "strings"
9
+ )
10
+
11
+ type protobufTypeScriptBinding struct {
12
+ sourcePath string
13
+ outputName string
14
+ importSource string
15
+ messageNames map[string]string
16
+ hasOneof bool
17
+ }
18
+
19
+ func protobufTypeScriptBindings(semPkg *semanticPackage, options LoweringOptions) (map[string]protobufTypeScriptBinding, []Diagnostic) {
20
+ if semPkg == nil || semPkg.source == nil || !options.ProtobufTypeScriptBinding {
21
+ return nil, nil
22
+ }
23
+ bindings := make(map[string]protobufTypeScriptBinding)
24
+ var diagnostics []Diagnostic
25
+ for idx, syntax := range semPkg.source.Syntax {
26
+ sourcePath := sourceFilePath(semPkg, idx, syntax)
27
+ if !strings.HasSuffix(sourcePath, ".pb.go") {
28
+ continue
29
+ }
30
+ if strings.HasSuffix(filepath.Base(sourcePath), "_srpc.pb.go") {
31
+ continue
32
+ }
33
+ if !protobufTypeScriptBindingInSourceRoot(options.SourceRoot, sourcePath) {
34
+ continue
35
+ }
36
+ tsPath := strings.TrimSuffix(sourcePath, ".go") + ".ts"
37
+ if _, err := os.Stat(tsPath); err != nil {
38
+ if os.IsNotExist(err) {
39
+ diagnostics = append(diagnostics, Diagnostic{
40
+ Severity: DiagnosticSeverityError,
41
+ Code: "goscript/protobuf-ts-binding:missing",
42
+ Message: "protobuf TypeScript binding is missing sibling .pb.ts",
43
+ Detail: fmt.Sprintf("%s requires %s", sourcePath, tsPath),
44
+ })
45
+ continue
46
+ }
47
+ diagnostics = append(diagnostics, Diagnostic{
48
+ Severity: DiagnosticSeverityError,
49
+ Code: "goscript/protobuf-ts-binding:stat",
50
+ Message: "failed to inspect protobuf TypeScript binding",
51
+ Detail: err.Error(),
52
+ })
53
+ continue
54
+ }
55
+ importSource, err := protobufTypeScriptBindingImportSource(options.OutputPath, semPkg.pkgPath, tsPath)
56
+ if err != nil {
57
+ diagnostics = append(diagnostics, Diagnostic{
58
+ Severity: DiagnosticSeverityError,
59
+ Code: "goscript/protobuf-ts-binding:import-source",
60
+ Message: "failed to compute protobuf TypeScript binding import",
61
+ Detail: err.Error(),
62
+ })
63
+ continue
64
+ }
65
+ bindings[sourcePath] = protobufTypeScriptBinding{
66
+ sourcePath: sourcePath,
67
+ outputName: strings.TrimSuffix(filepath.Base(sourcePath), ".go") + ".ts",
68
+ importSource: importSource,
69
+ messageNames: protobufTypeScriptBindingMessageNames(syntax),
70
+ hasOneof: protobufTypeScriptBindingHasOneof(syntax),
71
+ }
72
+ }
73
+ return bindings, diagnostics
74
+ }
75
+
76
+ func protobufTypeScriptBindingRoot(dir string) string {
77
+ dir = strings.TrimSpace(dir)
78
+ if dir == "" {
79
+ return ""
80
+ }
81
+ abs, err := filepath.Abs(dir)
82
+ if err != nil {
83
+ return dir
84
+ }
85
+ for {
86
+ if _, err := os.Stat(filepath.Join(abs, "go.mod")); err == nil {
87
+ return abs
88
+ }
89
+ parent := filepath.Dir(abs)
90
+ if parent == abs {
91
+ return dir
92
+ }
93
+ abs = parent
94
+ }
95
+ }
96
+
97
+ func protobufTypeScriptBindingInSourceRoot(sourceRoot, sourcePath string) bool {
98
+ if strings.TrimSpace(sourceRoot) == "" {
99
+ return true
100
+ }
101
+ rootAbs, err := filepath.Abs(sourceRoot)
102
+ if err != nil {
103
+ return false
104
+ }
105
+ sourceAbs, err := filepath.Abs(sourcePath)
106
+ if err != nil {
107
+ return false
108
+ }
109
+ rel, err := filepath.Rel(rootAbs, sourceAbs)
110
+ if err != nil {
111
+ return false
112
+ }
113
+ return rel == "." || !strings.HasPrefix(rel, ".."+string(filepath.Separator)) && rel != ".." && !filepath.IsAbs(rel)
114
+ }
115
+
116
+ func protobufTypeScriptBindingImportSource(outputPath, pkgPath, tsPath string) (string, error) {
117
+ outputDir := filepath.Join(outputPath, "@goscript", filepath.FromSlash(pkgPath))
118
+ outputDir, err := filepath.Abs(outputDir)
119
+ if err != nil {
120
+ return "", err
121
+ }
122
+ rel, err := filepath.Rel(outputDir, tsPath)
123
+ if err != nil {
124
+ return "", err
125
+ }
126
+ rel = filepath.ToSlash(rel)
127
+ if !strings.HasPrefix(rel, ".") {
128
+ rel = "./" + rel
129
+ }
130
+ return strings.TrimSuffix(rel, ".ts") + ".js", nil
131
+ }
132
+
133
+ func protobufTypeScriptBindingHasOneof(file *ast.File) bool {
134
+ if file == nil {
135
+ return false
136
+ }
137
+ for _, decl := range file.Decls {
138
+ genDecl, ok := decl.(*ast.GenDecl)
139
+ if !ok {
140
+ continue
141
+ }
142
+ for _, spec := range genDecl.Specs {
143
+ typeSpec, ok := spec.(*ast.TypeSpec)
144
+ if !ok {
145
+ continue
146
+ }
147
+ structType, ok := typeSpec.Type.(*ast.StructType)
148
+ if !ok || structType.Fields == nil {
149
+ continue
150
+ }
151
+ for _, field := range structType.Fields.List {
152
+ if field.Tag != nil && strings.Contains(field.Tag.Value, "protobuf_oneof") {
153
+ return true
154
+ }
155
+ }
156
+ }
157
+ }
158
+ return false
159
+ }
160
+
161
+ func protobufTypeScriptBindingMessageNames(file *ast.File) map[string]string {
162
+ names := make(map[string]string)
163
+ if file == nil {
164
+ return names
165
+ }
166
+ for _, decl := range file.Decls {
167
+ genDecl, ok := decl.(*ast.GenDecl)
168
+ if !ok {
169
+ continue
170
+ }
171
+ for _, spec := range genDecl.Specs {
172
+ typeSpec, ok := spec.(*ast.TypeSpec)
173
+ if !ok {
174
+ continue
175
+ }
176
+ if _, ok := typeSpec.Type.(*ast.StructType); !ok {
177
+ continue
178
+ }
179
+ name := typeSpec.Name.Name
180
+ names[name] = protobufTypeScriptBindingSafeIdentifier(name)
181
+ }
182
+ }
183
+ return names
184
+ }
185
+
186
+ func protobufTypeScriptBindingSafeIdentifier(name string) string {
187
+ switch name {
188
+ case "break",
189
+ "case",
190
+ "catch",
191
+ "class",
192
+ "const",
193
+ "continue",
194
+ "debugger",
195
+ "default",
196
+ "delete",
197
+ "do",
198
+ "else",
199
+ "export",
200
+ "extends",
201
+ "false",
202
+ "finally",
203
+ "for",
204
+ "function",
205
+ "if",
206
+ "import",
207
+ "in",
208
+ "instanceof",
209
+ "new",
210
+ "null",
211
+ "return",
212
+ "super",
213
+ "switch",
214
+ "this",
215
+ "throw",
216
+ "true",
217
+ "try",
218
+ "typeof",
219
+ "var",
220
+ "void",
221
+ "while",
222
+ "with",
223
+ "yield",
224
+ "enum",
225
+ "implements",
226
+ "interface",
227
+ "let",
228
+ "package",
229
+ "private",
230
+ "protected",
231
+ "public",
232
+ "static",
233
+ "Object",
234
+ "bigint",
235
+ "number",
236
+ "boolean",
237
+ "string",
238
+ "object",
239
+ "globalThis",
240
+ "Uint8Array",
241
+ "Partial":
242
+ return name + "$"
243
+ default:
244
+ return name
245
+ }
246
+ }
247
+
248
+ func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTypeScriptBinding) {
249
+ if file == nil {
250
+ return
251
+ }
252
+ file.outputName = binding.outputName
253
+ if binding.hasOneof {
254
+ return
255
+ }
256
+ const importAlias = "__protobuf_ts"
257
+ file.imports = append(file.imports, loweredImport{
258
+ alias: importAlias,
259
+ source: binding.importSource,
260
+ sideEffect: true,
261
+ })
262
+ var setupDecls []loweredDecl
263
+ for _, decl := range file.decls {
264
+ if decl.structType == nil {
265
+ continue
266
+ }
267
+ if protobufTypeScriptBindingSyntheticMapEntry(decl.structType.name) {
268
+ continue
269
+ }
270
+ rewriteProtobufTypeScriptBindingStruct(decl.structType)
271
+ setup := protobufTypeScriptBindingStructSetupDecl(decl.structType, importAlias, binding.messageNames[decl.structType.name])
272
+ if setup.code != "" {
273
+ setupDecls = append(setupDecls, setup)
274
+ }
275
+ }
276
+ file.decls = append(file.decls, setupDecls...)
277
+ }
278
+
279
+ func protobufTypeScriptBindingSyntheticMapEntry(name string) bool {
280
+ return strings.Contains(name, "_") && strings.HasSuffix(name, "Entry")
281
+ }
282
+
283
+ func lowerProtobufSRPCTypeScriptBindingStub(semPkg *semanticPackage, sourcePath string, options LoweringOptions) (*loweredFile, []Diagnostic) {
284
+ tsPath := strings.TrimSuffix(sourcePath, ".go") + ".ts"
285
+ if _, err := os.Stat(tsPath); err != nil {
286
+ if os.IsNotExist(err) {
287
+ return nil, nil
288
+ }
289
+ return nil, []Diagnostic{{
290
+ Severity: DiagnosticSeverityError,
291
+ Code: "goscript/protobuf-ts-binding:srpc-stat",
292
+ Message: "failed to inspect SRPC TypeScript binding",
293
+ Detail: err.Error(),
294
+ }}
295
+ }
296
+ importSource, err := protobufTypeScriptBindingImportSource(options.OutputPath, semPkg.pkgPath, tsPath)
297
+ if err != nil {
298
+ return nil, []Diagnostic{{
299
+ Severity: DiagnosticSeverityError,
300
+ Code: "goscript/protobuf-ts-binding:srpc-import-source",
301
+ Message: "failed to compute SRPC TypeScript binding import",
302
+ Detail: err.Error(),
303
+ }}
304
+ }
305
+ return &loweredFile{
306
+ sourcePath: sourcePath,
307
+ outputName: sourceOutputName(sourcePath),
308
+ decls: []loweredDecl{{
309
+ code: "export * from " + strconvQuote(importSource),
310
+ }},
311
+ exportAll: true,
312
+ }, nil
313
+ }
314
+
315
+ func protobufSRPCHasGoScriptReplacement(sourcePath string) bool {
316
+ base := filepath.Base(sourcePath)
317
+ if !strings.HasSuffix(base, "_srpc.pb.go") {
318
+ return false
319
+ }
320
+ replacement := strings.TrimSuffix(base, "_srpc.pb.go") + "-srpc-goscript.go"
321
+ _, err := os.Stat(filepath.Join(filepath.Dir(sourcePath), replacement))
322
+ return err == nil
323
+ }
324
+
325
+ func rewriteProtobufTypeScriptBindingStruct(structType *loweredStruct) {
326
+ if structType == nil {
327
+ return
328
+ }
329
+ for idx := range structType.methods {
330
+ method := &structType.methods[idx]
331
+ body := protobufTypeScriptBindingMethodBody(structType, method)
332
+ if body == "" {
333
+ continue
334
+ }
335
+ method.async = false
336
+ method.paramBindings = nil
337
+ method.namedResults = nil
338
+ method.deferState = nil
339
+ method.body = []loweredStmt{{text: body}}
340
+ }
341
+ }
342
+
343
+ func protobufTypeScriptBindingMethodBody(structType *loweredStruct, method *loweredFunction) string {
344
+ if structType == nil || method == nil {
345
+ return ""
346
+ }
347
+ ctor := structType.name
348
+ if !protobufTypeScriptBindingReplacesMethodName(method.name) {
349
+ return ""
350
+ }
351
+ switch method.name {
352
+ case "CloneMessageVT":
353
+ return "return $.interfaceValue<protobuf_go_lite.CloneMessage | null>(protobuf_go_lite.CloneBoundMessage(" +
354
+ ctor + ", this) as any, " + strconvQuote("*"+structType.typeName) + ")"
355
+ case "CloneVT":
356
+ return "return protobuf_go_lite.CloneBoundMessage(" + ctor + ", this) as any"
357
+ case "EqualVT":
358
+ return "return protobuf_go_lite.EqualBoundMessage(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
359
+ case "MarshalJSON":
360
+ return "return protobuf_go_lite.MarshalBoundMessageJSON(" + ctor + ", this)"
361
+ case "MarshalProtoJSON":
362
+ return "protobuf_go_lite.MarshalBoundMessageProtoJSON(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
363
+ case "MarshalProtoText", "String":
364
+ return "return protobuf_go_lite.MarshalBoundMessageProtoText(" + ctor + ", this)"
365
+ case "MarshalToSizedBufferVT":
366
+ return "return protobuf_go_lite.MarshalBoundMessageToSizedBufferVT(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
367
+ case "MarshalVT":
368
+ return "return protobuf_go_lite.MarshalBoundMessageVT(" + ctor + ", this)"
369
+ case "ProtoMessage":
370
+ return "return"
371
+ case "Reset":
372
+ return "$.assignStruct($.pointerValue<" + ctor + ">(this), $.markAsStructValue(new " + ctor + "()))"
373
+ case "SizeVT":
374
+ return "return protobuf_go_lite.SizeBoundMessageVT(" + ctor + ", this)"
375
+ case "UnmarshalJSON":
376
+ return "return protobuf_go_lite.UnmarshalBoundMessageJSON(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
377
+ case "UnmarshalProtoJSON":
378
+ return "protobuf_go_lite.UnmarshalBoundMessageProtoJSON(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
379
+ case "UnmarshalVT":
380
+ return "return protobuf_go_lite.UnmarshalBoundMessageVT(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
381
+ default:
382
+ return ""
383
+ }
384
+ }
385
+
386
+ func protobufTypeScriptBindingReplacesMethodName(name string) bool {
387
+ switch name {
388
+ case "CloneMessageVT",
389
+ "CloneVT",
390
+ "EqualVT",
391
+ "MarshalJSON",
392
+ "MarshalProtoJSON",
393
+ "MarshalProtoText",
394
+ "MarshalToSizedBufferVT",
395
+ "MarshalVT",
396
+ "ProtoMessage",
397
+ "Reset",
398
+ "SizeVT",
399
+ "String",
400
+ "UnmarshalJSON",
401
+ "UnmarshalProtoJSON",
402
+ "UnmarshalVT":
403
+ return true
404
+ default:
405
+ return false
406
+ }
407
+ }
408
+
409
+ func protobufBindingParam(method *loweredFunction, idx int, fallback string) string {
410
+ if method == nil || idx < 0 || idx >= len(method.params) || strings.TrimSpace(method.params[idx].name) == "" {
411
+ return fallback
412
+ }
413
+ return method.params[idx].name
414
+ }
415
+
416
+ func protobufTypeScriptBindingStructSetupDecl(structType *loweredStruct, importAlias, messageName string) loweredDecl {
417
+ if structType == nil {
418
+ return loweredDecl{}
419
+ }
420
+ if messageName == "" {
421
+ messageName = structType.name
422
+ }
423
+ entries := make([]string, 0, len(structType.fields))
424
+ for _, field := range structType.fields {
425
+ ctor := protobufTypeScriptBindingFieldCtor(field)
426
+ if ctor == "" {
427
+ continue
428
+ }
429
+ entries = append(entries, strconvQuote(protobufTypeScriptBindingFieldLocalName(field))+": "+ctor)
430
+ }
431
+ return loweredDecl{code: "(" + structType.name + " as any).__protobufTypeScriptMessage = " + importAlias + "." + messageName + ";\n" +
432
+ "(" + structType.name + " as any).__protobufTypeScriptFields = {" + strings.Join(entries, ", ") + "};"}
433
+ }
434
+
435
+ func protobufTypeScriptBindingFieldLocalName(field loweredStructField) string {
436
+ if tag := field.tag; tag != "" {
437
+ if value := protobufTypeScriptBindingTagValue(tag, "json="); value != "" {
438
+ return value
439
+ }
440
+ if value := protobufTypeScriptBindingTagValue(tag, "name="); value != "" {
441
+ return protobufTypeScriptBindingProtoCamel(value)
442
+ }
443
+ }
444
+ if field.name == "" {
445
+ return field.name
446
+ }
447
+ return strings.ToLower(field.name[:1]) + field.name[1:]
448
+ }
449
+
450
+ func protobufTypeScriptBindingTagValue(tag, key string) string {
451
+ idx := strings.Index(tag, key)
452
+ if idx < 0 {
453
+ return ""
454
+ }
455
+ rest := tag[idx+len(key):]
456
+ end := len(rest)
457
+ for idx, ch := range rest {
458
+ if ch == ',' || ch == '"' || ch == '`' || ch == ' ' {
459
+ end = idx
460
+ break
461
+ }
462
+ }
463
+ return rest[:end]
464
+ }
465
+
466
+ func protobufTypeScriptBindingProtoCamel(name string) string {
467
+ if name == "" {
468
+ return ""
469
+ }
470
+ parts := strings.Split(name, "_")
471
+ var out strings.Builder
472
+ for idx, part := range parts {
473
+ if part == "" {
474
+ continue
475
+ }
476
+ part = strings.ToLower(part)
477
+ if idx == 0 {
478
+ out.WriteString(part)
479
+ continue
480
+ }
481
+ out.WriteString(strings.ToUpper(part[:1]))
482
+ out.WriteString(part[1:])
483
+ }
484
+ return out.String()
485
+ }
486
+
487
+ func protobufTypeScriptBindingFieldCtor(field loweredStructField) string {
488
+ if !strings.Contains(field.runtimeType, "TypeKind.Pointer") {
489
+ return ""
490
+ }
491
+ for _, token := range strings.FieldsFunc(field.typ, func(r rune) bool {
492
+ return !(r == '.' || r == '_' || r == '$' || r >= '0' && r <= '9' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z')
493
+ }) {
494
+ if protobufTypeScriptBindingCtorToken(token) {
495
+ return token
496
+ }
497
+ }
498
+ return ""
499
+ }
500
+
501
+ func protobufTypeScriptBindingCtorToken(token string) bool {
502
+ if token == "" || strings.HasPrefix(token, "$.") || strings.HasPrefix(token, "globalThis.") {
503
+ return false
504
+ }
505
+ switch token {
506
+ case "any", "bigint", "boolean", "Date", "Map", "null", "number", "Promise", "Set", "Slice", "string", "Uint8Array", "undefined", "unknown", "VarRef", "void":
507
+ return false
508
+ }
509
+ if strings.Contains(token, ".") {
510
+ return true
511
+ }
512
+ first := token[0]
513
+ return first >= 'A' && first <= 'Z'
514
+ }