goscript 0.1.4 → 0.2.1

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 (295) 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} +7 -0
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript-wasm/main.go +38 -6
  8. package/compiler/compile-request.go +12 -9
  9. package/compiler/compliance_test.go +0 -1
  10. package/compiler/config.go +2 -0
  11. package/compiler/diagnostic.go +104 -12
  12. package/compiler/diagnostic_test.go +106 -0
  13. package/compiler/gotest/request.go +28 -0
  14. package/compiler/gotest/runner.go +354 -44
  15. package/compiler/gotest/runner_test.go +293 -1
  16. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  17. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  18. package/compiler/index.test.ts +23 -0
  19. package/compiler/lowered-program.go +33 -24
  20. package/compiler/lowering.go +746 -194
  21. package/compiler/lowering_bench_test.go +42 -27
  22. package/compiler/lowering_internal_test.go +18 -0
  23. package/compiler/override-facts.go +15 -0
  24. package/compiler/override-parity-verifier.go +450 -0
  25. package/compiler/override-parity.go +122 -0
  26. package/compiler/override-registry_test.go +559 -0
  27. package/compiler/protobuf-ts-binding.go +567 -0
  28. package/compiler/protobuf-ts-binding_test.go +402 -0
  29. package/compiler/runtime-contract.go +4 -0
  30. package/compiler/runtime-contract_test.go +2 -0
  31. package/compiler/semantic-model-types.go +9 -4
  32. package/compiler/semantic-model.go +282 -70
  33. package/compiler/semantic-model_test.go +82 -1
  34. package/compiler/service.go +21 -1
  35. package/compiler/skeleton_test.go +118 -10
  36. package/compiler/typescript-emitter.go +128 -13
  37. package/compiler/wasm/compile_test.go +37 -4
  38. package/compiler/{wasm_api.go → wasm-api.go} +57 -7
  39. package/dist/gs/builtin/hostio.js +5 -0
  40. package/dist/gs/builtin/hostio.js.map +1 -1
  41. package/dist/gs/builtin/slice.d.ts +13 -2
  42. package/dist/gs/builtin/slice.js +187 -6
  43. package/dist/gs/builtin/slice.js.map +1 -1
  44. package/dist/gs/builtin/type.d.ts +13 -5
  45. package/dist/gs/builtin/type.js +153 -60
  46. package/dist/gs/builtin/type.js.map +1 -1
  47. package/dist/gs/builtin/varRef.d.ts +11 -0
  48. package/dist/gs/builtin/varRef.js +57 -2
  49. package/dist/gs/builtin/varRef.js.map +1 -1
  50. package/dist/gs/bytes/buffer.gs.js +1 -1
  51. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  52. package/dist/gs/bytes/reader.gs.js +1 -1
  53. package/dist/gs/bytes/reader.gs.js.map +1 -1
  54. package/dist/gs/compress/zlib/index.d.ts +10 -3
  55. package/dist/gs/compress/zlib/index.js +50 -16
  56. package/dist/gs/compress/zlib/index.js.map +1 -1
  57. package/dist/gs/encoding/json/index.d.ts +114 -0
  58. package/dist/gs/encoding/json/index.js +544 -36
  59. package/dist/gs/encoding/json/index.js.map +1 -1
  60. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +101 -0
  61. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +589 -0
  62. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  63. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.d.ts +1 -0
  64. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +17 -11
  65. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  66. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  67. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  68. package/dist/gs/go/scanner/index.d.ts +2 -0
  69. package/dist/gs/go/scanner/index.js +29 -5
  70. package/dist/gs/go/scanner/index.js.map +1 -1
  71. package/dist/gs/go/token/index.js +22 -6
  72. package/dist/gs/go/token/index.js.map +1 -1
  73. package/dist/gs/hash/index.d.ts +6 -0
  74. package/dist/gs/hash/index.js +20 -0
  75. package/dist/gs/hash/index.js.map +1 -1
  76. package/dist/gs/internal/byteorder/index.js +2 -2
  77. package/dist/gs/internal/byteorder/index.js.map +1 -1
  78. package/dist/gs/internal/goarch/index.d.ts +43 -3
  79. package/dist/gs/internal/goarch/index.js +42 -10
  80. package/dist/gs/internal/goarch/index.js.map +1 -1
  81. package/dist/gs/io/fs/fs.js +26 -14
  82. package/dist/gs/io/fs/fs.js.map +1 -1
  83. package/dist/gs/io/fs/readdir.js +4 -2
  84. package/dist/gs/io/fs/readdir.js.map +1 -1
  85. package/dist/gs/io/fs/sub.js +8 -1
  86. package/dist/gs/io/fs/sub.js.map +1 -1
  87. package/dist/gs/io/io.d.ts +2 -0
  88. package/dist/gs/io/io.js.map +1 -1
  89. package/dist/gs/math/bits/index.d.ts +5 -0
  90. package/dist/gs/math/bits/index.js +16 -4
  91. package/dist/gs/math/bits/index.js.map +1 -1
  92. package/dist/gs/mime/index.d.ts +16 -0
  93. package/dist/gs/mime/index.js +315 -6
  94. package/dist/gs/mime/index.js.map +1 -1
  95. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  96. package/dist/gs/net/http/httptest/index.js +85 -6
  97. package/dist/gs/net/http/httptest/index.js.map +1 -1
  98. package/dist/gs/net/http/index.d.ts +300 -5
  99. package/dist/gs/net/http/index.js +1598 -58
  100. package/dist/gs/net/http/index.js.map +1 -1
  101. package/dist/gs/os/dir_unix.gs.js +1 -1
  102. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  103. package/dist/gs/os/error.gs.js +1 -1
  104. package/dist/gs/os/error.gs.js.map +1 -1
  105. package/dist/gs/os/exec.gs.d.ts +1 -0
  106. package/dist/gs/os/exec.gs.js +4 -8
  107. package/dist/gs/os/exec.gs.js.map +1 -1
  108. package/dist/gs/os/exec_posix.gs.js +1 -1
  109. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  110. package/dist/gs/os/index.d.ts +1 -1
  111. package/dist/gs/os/index.js +1 -1
  112. package/dist/gs/os/index.js.map +1 -1
  113. package/dist/gs/os/proc.gs.d.ts +4 -0
  114. package/dist/gs/os/proc.gs.js +12 -6
  115. package/dist/gs/os/proc.gs.js.map +1 -1
  116. package/dist/gs/os/root_js.gs.js +1 -1
  117. package/dist/gs/os/root_js.gs.js.map +1 -1
  118. package/dist/gs/os/types.gs.js +1 -1
  119. package/dist/gs/os/types.gs.js.map +1 -1
  120. package/dist/gs/os/types_js.gs.js +1 -1
  121. package/dist/gs/os/types_js.gs.js.map +1 -1
  122. package/dist/gs/os/types_unix.gs.js +1 -1
  123. package/dist/gs/os/types_unix.gs.js.map +1 -1
  124. package/dist/gs/path/path.js +11 -7
  125. package/dist/gs/path/path.js.map +1 -1
  126. package/dist/gs/reflect/index.d.ts +5 -4
  127. package/dist/gs/reflect/index.js +4 -3
  128. package/dist/gs/reflect/index.js.map +1 -1
  129. package/dist/gs/reflect/map.js +15 -0
  130. package/dist/gs/reflect/map.js.map +1 -1
  131. package/dist/gs/reflect/type.d.ts +25 -6
  132. package/dist/gs/reflect/type.js +1475 -228
  133. package/dist/gs/reflect/type.js.map +1 -1
  134. package/dist/gs/reflect/types.d.ts +14 -6
  135. package/dist/gs/reflect/types.js +35 -1
  136. package/dist/gs/reflect/types.js.map +1 -1
  137. package/dist/gs/reflect/value.d.ts +1 -0
  138. package/dist/gs/reflect/value.js +83 -41
  139. package/dist/gs/reflect/value.js.map +1 -1
  140. package/dist/gs/reflect/visiblefields.js +4 -140
  141. package/dist/gs/reflect/visiblefields.js.map +1 -1
  142. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  143. package/dist/gs/runtime/pprof/index.js +50 -30
  144. package/dist/gs/runtime/pprof/index.js.map +1 -1
  145. package/dist/gs/runtime/runtime.js +5 -4
  146. package/dist/gs/runtime/runtime.js.map +1 -1
  147. package/dist/gs/runtime/trace/index.js +5 -19
  148. package/dist/gs/runtime/trace/index.js.map +1 -1
  149. package/dist/gs/strconv/atoi.gs.js +1 -1
  150. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  151. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  152. package/dist/gs/strconv/complex.gs.js +148 -0
  153. package/dist/gs/strconv/complex.gs.js.map +1 -0
  154. package/dist/gs/strconv/index.d.ts +1 -0
  155. package/dist/gs/strconv/index.js +1 -0
  156. package/dist/gs/strconv/index.js.map +1 -1
  157. package/dist/gs/strings/builder.js +1 -1
  158. package/dist/gs/strings/reader.js +9 -5
  159. package/dist/gs/strings/reader.js.map +1 -1
  160. package/dist/gs/strings/replace.js +15 -7
  161. package/dist/gs/strings/replace.js.map +1 -1
  162. package/dist/gs/strings/strings.d.ts +5 -0
  163. package/dist/gs/strings/strings.js +57 -5
  164. package/dist/gs/strings/strings.js.map +1 -1
  165. package/dist/gs/sync/atomic/doc_64.gs.js +7 -6
  166. package/dist/gs/sync/atomic/doc_64.gs.js.map +1 -1
  167. package/dist/gs/sync/atomic/type.gs.js +9 -9
  168. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  169. package/dist/gs/sync/atomic/value.gs.js +2 -2
  170. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  171. package/dist/gs/syscall/env.js +22 -14
  172. package/dist/gs/syscall/env.js.map +1 -1
  173. package/dist/gs/testing/testing.js +55 -13
  174. package/dist/gs/testing/testing.js.map +1 -1
  175. package/dist/gs/time/time.d.ts +24 -1
  176. package/dist/gs/time/time.js +43 -3
  177. package/dist/gs/time/time.js.map +1 -1
  178. package/dist/gs/unique/index.js +7 -1
  179. package/dist/gs/unique/index.js.map +1 -1
  180. package/go.mod +3 -3
  181. package/go.sum +16 -0
  182. package/gs/builtin/hostio.test.ts +16 -0
  183. package/gs/builtin/hostio.ts +7 -0
  184. package/gs/builtin/runtime-contract.test.ts +246 -21
  185. package/gs/builtin/slice.ts +269 -24
  186. package/gs/builtin/type.ts +226 -59
  187. package/gs/builtin/varRef.ts +85 -2
  188. package/gs/bytes/buffer.gs.ts +1 -1
  189. package/gs/bytes/reader.gs.ts +1 -1
  190. package/gs/compress/zlib/index.test.ts +62 -1
  191. package/gs/compress/zlib/index.ts +53 -16
  192. package/gs/compress/zlib/parity.json +51 -0
  193. package/gs/encoding/json/index.test.ts +360 -6
  194. package/gs/encoding/json/index.ts +679 -38
  195. package/gs/encoding/json/parity.json +81 -0
  196. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +373 -3
  197. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +893 -1
  198. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +18 -0
  199. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +17 -11
  200. package/gs/github.com/pkg/errors/errors.ts +54 -30
  201. package/gs/go/scanner/index.test.ts +39 -56
  202. package/gs/go/scanner/index.ts +33 -5
  203. package/gs/go/scanner/parity.json +27 -0
  204. package/gs/go/token/index.ts +22 -6
  205. package/gs/hash/index.test.ts +20 -33
  206. package/gs/hash/index.ts +28 -0
  207. package/gs/hash/parity.json +21 -0
  208. package/gs/internal/byteorder/index.test.ts +2 -2
  209. package/gs/internal/byteorder/index.ts +2 -2
  210. package/gs/internal/goarch/index.test.ts +32 -0
  211. package/gs/internal/goarch/index.ts +45 -13
  212. package/gs/internal/goarch/parity.json +144 -0
  213. package/gs/io/fs/fs.ts +26 -14
  214. package/gs/io/fs/readdir.ts +4 -4
  215. package/gs/io/fs/sub.ts +8 -1
  216. package/gs/io/io.ts +1 -0
  217. package/gs/io/parity.json +162 -0
  218. package/gs/math/bits/index.test.ts +14 -1
  219. package/gs/math/bits/index.ts +23 -4
  220. package/gs/math/bits/parity.json +156 -0
  221. package/gs/mime/index.test.ts +90 -0
  222. package/gs/mime/index.ts +369 -6
  223. package/gs/mime/parity.json +36 -0
  224. package/gs/net/http/httptest/index.test.ts +98 -2
  225. package/gs/net/http/httptest/index.ts +101 -6
  226. package/gs/net/http/httptest/parity.json +15 -0
  227. package/gs/net/http/index.test.ts +781 -12
  228. package/gs/net/http/index.ts +1860 -139
  229. package/gs/net/http/meta.json +16 -1
  230. package/gs/net/http/parity.json +193 -0
  231. package/gs/os/dir_unix.gs.ts +1 -1
  232. package/gs/os/error.gs.ts +1 -1
  233. package/gs/os/exec.gs.ts +4 -8
  234. package/gs/os/exec_posix.gs.ts +1 -1
  235. package/gs/os/index.test.ts +9 -0
  236. package/gs/os/index.ts +1 -0
  237. package/gs/os/parity.json +9 -0
  238. package/gs/os/proc.gs.ts +18 -5
  239. package/gs/os/proc.test.ts +26 -0
  240. package/gs/os/root_js.gs.ts +1 -1
  241. package/gs/os/types.gs.ts +1 -1
  242. package/gs/os/types_js.gs.ts +1 -1
  243. package/gs/os/types_unix.gs.ts +1 -1
  244. package/gs/path/path.ts +11 -7
  245. package/gs/reflect/field.test.ts +37 -15
  246. package/gs/reflect/function-types.test.ts +518 -22
  247. package/gs/reflect/index.ts +8 -6
  248. package/gs/reflect/map.ts +20 -0
  249. package/gs/reflect/meta.json +6 -4
  250. package/gs/reflect/parity.json +234 -0
  251. package/gs/reflect/sliceat.test.ts +156 -0
  252. package/gs/reflect/structof.test.ts +401 -0
  253. package/gs/reflect/type.ts +1961 -317
  254. package/gs/reflect/typefor.test.ts +530 -10
  255. package/gs/reflect/types.ts +43 -18
  256. package/gs/reflect/value.ts +105 -45
  257. package/gs/reflect/visiblefields.ts +5 -168
  258. package/gs/runtime/parity.json +24 -0
  259. package/gs/runtime/pprof/index.test.ts +29 -7
  260. package/gs/runtime/pprof/index.ts +56 -30
  261. package/gs/runtime/pprof/parity.json +27 -0
  262. package/gs/runtime/runtime.test.ts +3 -1
  263. package/gs/runtime/runtime.ts +4 -3
  264. package/gs/runtime/trace/index.test.ts +5 -3
  265. package/gs/runtime/trace/index.ts +8 -20
  266. package/gs/runtime/trace/parity.json +36 -0
  267. package/gs/strconv/atoi.gs.ts +1 -1
  268. package/gs/strconv/complex.gs.ts +174 -0
  269. package/gs/strconv/complex.test.ts +65 -0
  270. package/gs/strconv/index.ts +1 -0
  271. package/gs/strconv/parity.json +120 -0
  272. package/gs/strings/builder.ts +1 -1
  273. package/gs/strings/parity.json +186 -0
  274. package/gs/strings/reader.ts +9 -5
  275. package/gs/strings/replace.ts +15 -7
  276. package/gs/strings/strings.test.ts +22 -2
  277. package/gs/strings/strings.ts +64 -6
  278. package/gs/sync/atomic/doc_64.gs.ts +6 -7
  279. package/gs/sync/atomic/doc_64.test.ts +43 -0
  280. package/gs/sync/atomic/type.gs.ts +9 -9
  281. package/gs/sync/atomic/value.gs.ts +2 -2
  282. package/gs/syscall/env.ts +29 -14
  283. package/gs/testing/testing.test.ts +67 -0
  284. package/gs/testing/testing.ts +87 -19
  285. package/gs/time/parity.json +225 -0
  286. package/gs/time/time.test.ts +20 -2
  287. package/gs/time/time.ts +49 -7
  288. package/gs/unique/index.ts +7 -1
  289. package/package.json +4 -2
  290. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  291. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -926
  292. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  293. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -38
  294. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1361
  295. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
@@ -0,0 +1,402 @@
1
+ package compiler
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "go/ast"
7
+ "os"
8
+ "path/filepath"
9
+ "strings"
10
+ "testing"
11
+
12
+ "golang.org/x/tools/go/packages"
13
+ )
14
+
15
+ func TestProtobufTypeScriptBindingSkipsPbGoEmission(t *testing.T) {
16
+ dir := t.TempDir()
17
+ writeTestFile(t, dir, "go.mod", "module example.test/protobufbinding\n\ngo 1.25\n")
18
+ writeTestFile(t, dir, "foo.pb.go", `package protobufbinding
19
+
20
+ type Foo struct {
21
+ Name string
22
+ }
23
+
24
+ type Object struct {
25
+ Name string
26
+ }
27
+ `)
28
+ writeTestFile(t, dir, "foo.pb.ts", `export interface Foo {
29
+ name?: string
30
+ }
31
+ export const Foo = {} as any
32
+ export interface Object$ {
33
+ name?: string
34
+ }
35
+ export const Object$ = {} as any
36
+ `)
37
+ writeTestFile(t, dir, "use.go", `package protobufbinding
38
+
39
+ func NewFoo() Foo {
40
+ return Foo{Name: "bound"}
41
+ }
42
+ `)
43
+
44
+ out := filepath.Join(dir, "out")
45
+ comp, err := NewCompiler(&Config{
46
+ Dir: dir,
47
+ OutputPath: out,
48
+ ProtobufTypeScriptBinding: true,
49
+ }, nil, nil)
50
+ if err != nil {
51
+ t.Fatal(err)
52
+ }
53
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
54
+ t.Fatalf("compile with protobuf TypeScript binding: %v", err)
55
+ }
56
+
57
+ pkgDir := filepath.Join(out, "@goscript", "example.test", "protobufbinding")
58
+ if _, err := os.Stat(filepath.Join(pkgDir, "foo.pb.gs.ts")); !errors.Is(err, os.ErrNotExist) {
59
+ t.Fatalf("bound protobuf file should not emit foo.pb.gs.ts, stat err=%v", err)
60
+ }
61
+ binding := readTestFile(t, filepath.Join(pkgDir, "foo.pb.ts"))
62
+ if !strings.Contains(binding, `import * as __protobuf_ts`) || !strings.Contains(binding, `foo.pb.js`) ||
63
+ !strings.Contains(binding, `class Foo`) || !strings.Contains(binding, `__protobufTypeScriptMessage = __protobuf_ts.Foo`) {
64
+ t.Fatalf("binding file should adapt sibling foo.pb.js, got:\n%s", binding)
65
+ }
66
+ if !strings.Contains(binding, `class Object`) || !strings.Contains(binding, `__protobufTypeScriptMessage = __protobuf_ts.Object$`) {
67
+ t.Fatalf("binding file should use protobuf-es-lite safe identifier for Object, got:\n%s", binding)
68
+ }
69
+ if !strings.Contains(binding, `__protobufTypeScriptMessage = __protobuf_ts.Foo;`) ||
70
+ !strings.Contains(binding, `__protobufTypeScriptFields = {};`) {
71
+ t.Fatalf("binding metadata assignments should be semicolon-terminated to avoid ASI calls, got:\n%s", binding)
72
+ }
73
+ index := readTestFile(t, filepath.Join(pkgDir, "index.ts"))
74
+ if !strings.Contains(index, `export { Foo, Object } from "./foo.pb.ts"`) {
75
+ t.Fatalf("package index should re-export binding file, got:\n%s", index)
76
+ }
77
+ use := readTestFile(t, filepath.Join(pkgDir, "use.gs.ts"))
78
+ if !strings.Contains(use, `from "./foo.pb.ts"`) {
79
+ t.Fatalf("non-protobuf file should import bound protobuf declarations, got:\n%s", use)
80
+ }
81
+ }
82
+
83
+ func TestProtobufTypeScriptBindingEmitsMetadataForPreservedOneofFiles(t *testing.T) {
84
+ dir := t.TempDir()
85
+ writeTestFile(t, dir, "go.mod", "module example.test/oneofpb\n\ngo 1.25\n")
86
+ writeTestFile(t, dir, "foo.pb.go", "package oneofpb\n\n"+
87
+ "type Inner struct {\n"+
88
+ "\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n"+
89
+ "}\n\n"+
90
+ "type Wrapper struct {\n"+
91
+ "\tInner *Inner `protobuf:\"bytes,1,opt,name=inner,proto3\" json:\"inner,omitempty\"`\n"+
92
+ "\tChoice isWrapper_Choice `protobuf_oneof:\"choice\"`\n"+
93
+ "}\n\n"+
94
+ "type isWrapper_Choice interface { isWrapper_Choice() }\n\n"+
95
+ "type Wrapper_StringValue struct {\n"+
96
+ "\tStringValue string `protobuf:\"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof\"`\n"+
97
+ "}\n\n"+
98
+ "func (*Wrapper_StringValue) isWrapper_Choice() {}\n")
99
+ writeTestFile(t, dir, "foo.pb.ts", `export interface Inner {
100
+ name?: string
101
+ }
102
+ export const Inner = {} as any
103
+ export interface Wrapper {
104
+ inner?: Inner
105
+ }
106
+ export const Wrapper = {} as any
107
+ `)
108
+
109
+ out := filepath.Join(dir, "out")
110
+ comp, err := NewCompiler(&Config{
111
+ Dir: dir,
112
+ OutputPath: out,
113
+ ProtobufTypeScriptBinding: true,
114
+ }, nil, nil)
115
+ if err != nil {
116
+ t.Fatal(err)
117
+ }
118
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
119
+ t.Fatalf("compile with protobuf TypeScript binding: %v", err)
120
+ }
121
+
122
+ binding := readTestFile(t, filepath.Join(out, "@goscript", "example.test", "oneofpb", "foo.pb.ts"))
123
+ if !strings.Contains(binding, `import * as __protobuf_ts`) ||
124
+ !strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptMessage = __protobuf_ts.Wrapper;`) ||
125
+ !strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptFields = {"inner": Inner};`) {
126
+ t.Fatalf("oneof-preserved protobuf file should still expose TypeScript metadata, got:\n%s", binding)
127
+ }
128
+ if strings.Contains(binding, `__protobuf_ts.Wrapper_StringValue`) {
129
+ t.Fatalf("oneof wrapper structs should not reference missing TypeScript exports, got:\n%s", binding)
130
+ }
131
+ }
132
+
133
+ func TestProtobufTypeScriptBindingPreservesCustomJSONMethods(t *testing.T) {
134
+ dir := t.TempDir()
135
+ writeTestFile(t, dir, "go.mod", "module example.test/custompbjson\n\ngo 1.25\n")
136
+ writeTestFile(t, dir, "foo.pb.go", `package custompbjson
137
+
138
+ type Foo struct {
139
+ Config []byte
140
+ }
141
+ `)
142
+ writeTestFile(t, dir, "foo.pb.ts", `export interface Foo {
143
+ config?: Uint8Array
144
+ }
145
+ export const Foo = {} as any
146
+ `)
147
+ writeTestFile(t, dir, "foo-json.go", `package custompbjson
148
+
149
+ func (x *Foo) UnmarshalJSON(b []byte) error {
150
+ x.Config = b
151
+ return nil
152
+ }
153
+ `)
154
+
155
+ out := filepath.Join(dir, "out")
156
+ comp, err := NewCompiler(&Config{
157
+ Dir: dir,
158
+ OutputPath: out,
159
+ ProtobufTypeScriptBinding: true,
160
+ }, nil, nil)
161
+ if err != nil {
162
+ t.Fatal(err)
163
+ }
164
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
165
+ t.Fatalf("compile with protobuf TypeScript binding: %v", err)
166
+ }
167
+
168
+ binding := readTestFile(t, filepath.Join(out, "@goscript", "example.test", "custompbjson", "foo.pb.ts"))
169
+ if strings.Contains(binding, `UnmarshalBoundMessageJSON(Foo`) {
170
+ t.Fatalf("custom JSON method should not be replaced by generic protobuf helper, got:\n%s", binding)
171
+ }
172
+ if !strings.Contains(binding, `.Config = b`) {
173
+ t.Fatalf("custom JSON method body should be preserved, got:\n%s", binding)
174
+ }
175
+ }
176
+
177
+ func TestProtobufTypeScriptBindingPreservesJSONGraphWithCustomNestedMessage(t *testing.T) {
178
+ dir := t.TempDir()
179
+ writeTestFile(t, dir, "go.mod", "module example.test/nestedcustompbjson\n\ngo 1.25\n")
180
+ writeTestFile(t, dir, "foo.pb.go", `package nestedcustompbjson
181
+
182
+ type Foo struct {
183
+ Items []*Item
184
+ }
185
+
186
+ type Item struct {
187
+ Config []byte
188
+ }
189
+
190
+ func generatedFooJSONMarker(x *Foo) error {
191
+ return nil
192
+ }
193
+
194
+ func (x *Foo) UnmarshalJSON(b []byte) error {
195
+ return generatedFooJSONMarker(x)
196
+ }
197
+
198
+ func (x *Foo) UnmarshalProtoJSON(s any) {
199
+ }
200
+ `)
201
+ writeTestFile(t, dir, "foo.pb.ts", `export interface Foo {
202
+ items?: Item[]
203
+ }
204
+ export const Foo = {} as any
205
+ export interface Item {
206
+ config?: Uint8Array
207
+ }
208
+ export const Item = {} as any
209
+ `)
210
+ writeTestFile(t, dir, "item-json.go", `package nestedcustompbjson
211
+
212
+ func (x *Item) UnmarshalJSON(b []byte) error {
213
+ x.Config = b
214
+ return nil
215
+ }
216
+ `)
217
+
218
+ out := filepath.Join(dir, "out")
219
+ comp, err := NewCompiler(&Config{
220
+ Dir: dir,
221
+ OutputPath: out,
222
+ ProtobufTypeScriptBinding: true,
223
+ }, nil, nil)
224
+ if err != nil {
225
+ t.Fatal(err)
226
+ }
227
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
228
+ t.Fatalf("compile with protobuf TypeScript binding: %v", err)
229
+ }
230
+
231
+ binding := readTestFile(t, filepath.Join(out, "@goscript", "example.test", "nestedcustompbjson", "foo.pb.ts"))
232
+ if strings.Contains(binding, `UnmarshalBoundMessageJSON(Foo`) {
233
+ t.Fatalf("outer message with nested custom JSON should keep generated JSON body, got:\n%s", binding)
234
+ }
235
+ if !strings.Contains(binding, `generatedFooJSONMarker`) {
236
+ t.Fatalf("outer generated JSON body should be preserved, got:\n%s", binding)
237
+ }
238
+ if strings.Contains(binding, `UnmarshalBoundMessageJSON(Item`) {
239
+ t.Fatalf("nested custom JSON method should not be replaced, got:\n%s", binding)
240
+ }
241
+ if !strings.Contains(binding, `.Config = b`) {
242
+ t.Fatalf("nested custom JSON method body should be preserved, got:\n%s", binding)
243
+ }
244
+ }
245
+
246
+ func TestProtobufTypeScriptBindingPreservesJSONGraphWithImportedCustomNestedMessage(t *testing.T) {
247
+ dir := t.TempDir()
248
+ writeTestFile(t, dir, "go.mod", "module example.test/importedcustompbjson\n\ngo 1.25\n")
249
+ writeTestFile(t, dir, "inner/inner.pb.go", `package inner
250
+
251
+ type Inner struct {
252
+ Config []byte
253
+ }
254
+ `)
255
+ writeTestFile(t, dir, "inner/inner.pb.ts", `export interface Inner {
256
+ config?: Uint8Array
257
+ }
258
+ export const Inner = {} as any
259
+ `)
260
+ writeTestFile(t, dir, "inner/inner-json.go", `package inner
261
+
262
+ func (x *Inner) UnmarshalJSON(b []byte) error {
263
+ x.Config = b
264
+ return nil
265
+ }
266
+ `)
267
+ writeTestFile(t, dir, "outer.pb.go", `package importedcustompbjson
268
+
269
+ import "example.test/importedcustompbjson/inner"
270
+
271
+ type Outer struct {
272
+ Inner *inner.Inner
273
+ }
274
+
275
+ func generatedOuterJSONMarker(x *Outer) error {
276
+ return nil
277
+ }
278
+
279
+ func (x *Outer) UnmarshalJSON(b []byte) error {
280
+ return generatedOuterJSONMarker(x)
281
+ }
282
+ `)
283
+ writeTestFile(t, dir, "outer.pb.ts", `import type { Inner } from './inner/inner.pb.js'
284
+
285
+ export interface Outer {
286
+ inner?: Inner
287
+ }
288
+ export const Outer = {} as any
289
+ `)
290
+
291
+ out := filepath.Join(dir, "out")
292
+ comp, err := NewCompiler(&Config{
293
+ Dir: dir,
294
+ OutputPath: out,
295
+ ProtobufTypeScriptBinding: true,
296
+ }, nil, nil)
297
+ if err != nil {
298
+ t.Fatal(err)
299
+ }
300
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
301
+ t.Fatalf("compile with protobuf TypeScript binding: %v", err)
302
+ }
303
+
304
+ binding := readTestFile(t, filepath.Join(out, "@goscript", "example.test", "importedcustompbjson", "outer.pb.ts"))
305
+ if strings.Contains(binding, `UnmarshalBoundMessageJSON(Outer`) {
306
+ t.Fatalf("outer message with imported nested custom JSON should keep generated JSON body, got:\n%s", binding)
307
+ }
308
+ if !strings.Contains(binding, `generatedOuterJSONMarker`) {
309
+ t.Fatalf("outer generated JSON body should be preserved, got:\n%s", binding)
310
+ }
311
+ }
312
+
313
+ func TestProtobufTypeScriptBindingReportsMissingSibling(t *testing.T) {
314
+ dir := t.TempDir()
315
+ writeTestFile(t, dir, "go.mod", "module example.test/missingpbts\n\ngo 1.25\n")
316
+ writeTestFile(t, dir, "foo.pb.go", `package missingpbts
317
+
318
+ type Foo struct{}
319
+ `)
320
+
321
+ comp, err := NewCompiler(&Config{
322
+ Dir: dir,
323
+ OutputPath: filepath.Join(dir, "out"),
324
+ ProtobufTypeScriptBinding: true,
325
+ }, nil, nil)
326
+ if err != nil {
327
+ t.Fatal(err)
328
+ }
329
+ result, err := comp.CompilePackages(context.Background(), ".")
330
+ if err == nil {
331
+ t.Fatal("expected missing sibling .pb.ts to fail")
332
+ }
333
+ if result == nil {
334
+ t.Fatal("expected diagnostics result")
335
+ }
336
+ for _, diag := range result.Diagnostics {
337
+ if diag.Code == "goscript/protobuf-ts-binding:missing" {
338
+ return
339
+ }
340
+ }
341
+ t.Fatalf("missing protobuf binding diagnostic not found: %#v", result.Diagnostics)
342
+ }
343
+
344
+ func TestProtobufTypeScriptBindingSkipsFilesOutsideSourceRoot(t *testing.T) {
345
+ dir := t.TempDir()
346
+ outside := filepath.Join(t.TempDir(), "outside.pb.go")
347
+ writeTestFile(t, dir, "go.mod", "module example.test/outsidepb\n\ngo 1.25\n")
348
+ writeTestFile(t, dir, "use.go", `package outsidepb
349
+ `)
350
+
351
+ semPkg := &semanticPackage{
352
+ pkgPath: "example.test/outsidepb",
353
+ source: &packages.Package{
354
+ CompiledGoFiles: []string{outside},
355
+ GoFiles: []string{outside},
356
+ Syntax: make([]*ast.File, 1),
357
+ },
358
+ }
359
+ bindings, diagnostics := protobufTypeScriptBindings(semPkg, LoweringOptions{
360
+ SourceRoot: dir,
361
+ OutputPath: filepath.Join(dir, "out"),
362
+ ProtobufTypeScriptBinding: true,
363
+ })
364
+ if len(diagnostics) != 0 {
365
+ t.Fatalf("outside source root diagnostics = %#v", diagnostics)
366
+ }
367
+ if len(bindings) != 0 {
368
+ t.Fatalf("outside source root bindings = %#v", bindings)
369
+ }
370
+ }
371
+
372
+ func TestProtobufTypeScriptBindingRootFindsParentModule(t *testing.T) {
373
+ dir := t.TempDir()
374
+ writeTestFile(t, dir, "go.mod", "module example.test/root\n\ngo 1.25\n")
375
+ nested := filepath.Join(dir, ".bldr", "build", "plugin")
376
+ if err := os.MkdirAll(nested, 0o755); err != nil {
377
+ t.Fatal(err)
378
+ }
379
+ if got := protobufTypeScriptBindingRoot(nested); got != dir {
380
+ t.Fatalf("binding root = %q, want %q", got, dir)
381
+ }
382
+ }
383
+
384
+ func writeTestFile(t *testing.T, root, rel, data string) {
385
+ t.Helper()
386
+ path := filepath.Join(root, rel)
387
+ if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
388
+ t.Fatal(err)
389
+ }
390
+ if err := os.WriteFile(path, []byte(data), 0o644); err != nil {
391
+ t.Fatal(err)
392
+ }
393
+ }
394
+
395
+ func readTestFile(t *testing.T, path string) string {
396
+ t.Helper()
397
+ data, err := os.ReadFile(path)
398
+ if err != nil {
399
+ t.Fatal(err)
400
+ }
401
+ return string(data)
402
+ }
@@ -105,6 +105,8 @@ const (
105
105
  RuntimeHelperSliceStringOrBytes RuntimeHelper = "slice.sliceStringOrBytes"
106
106
  RuntimeHelperIndexRef RuntimeHelper = "slice.indexRef"
107
107
  RuntimeHelperIndexAddress RuntimeHelper = "slice.indexAddress"
108
+ RuntimeHelperIndexByteAddress RuntimeHelper = "slice.indexByteAddress"
109
+ RuntimeHelperUnsafePointerRef RuntimeHelper = "slice.unsafePointerRef"
108
110
 
109
111
  RuntimeHelperMakeMap RuntimeHelper = "map.makeMap"
110
112
  RuntimeHelperMapGet RuntimeHelper = "map.mapGet"
@@ -333,6 +335,8 @@ func runtimeHelperContracts() []RuntimeHelperContract {
333
335
  runtimeHelper(RuntimeHelperSliceStringOrBytes, "sliceStringOrBytes", RuntimeHelperCategorySlice),
334
336
  runtimeHelper(RuntimeHelperIndexRef, "indexRef", RuntimeHelperCategorySlice),
335
337
  runtimeHelper(RuntimeHelperIndexAddress, "indexAddress", RuntimeHelperCategorySlice),
338
+ runtimeHelper(RuntimeHelperIndexByteAddress, "indexByteAddress", RuntimeHelperCategorySlice),
339
+ runtimeHelper(RuntimeHelperUnsafePointerRef, "unsafePointerRef", RuntimeHelperCategorySlice),
336
340
  runtimeHelper(RuntimeHelperMakeMap, "makeMap", RuntimeHelperCategoryMap),
337
341
  runtimeHelper(RuntimeHelperMapGet, "mapGet", RuntimeHelperCategoryMap),
338
342
  runtimeHelper(RuntimeHelperMapSet, "mapSet", RuntimeHelperCategoryMap),
@@ -25,6 +25,8 @@ func TestRuntimeContractOwnsBuiltinImportAndHelpers(t *testing.T) {
25
25
  RuntimeHelperMakeSlice: RuntimeHelperCategorySlice,
26
26
  RuntimeHelperAppend: RuntimeHelperCategorySlice,
27
27
  RuntimeHelperIndexAddress: RuntimeHelperCategorySlice,
28
+ RuntimeHelperIndexByteAddress: RuntimeHelperCategorySlice,
29
+ RuntimeHelperUnsafePointerRef: RuntimeHelperCategorySlice,
28
30
  RuntimeHelperMakeMap: RuntimeHelperCategoryMap,
29
31
  RuntimeHelperMapGet: RuntimeHelperCategoryMap,
30
32
  RuntimeHelperNewError: RuntimeHelperCategoryError,
@@ -12,12 +12,14 @@ type SemanticModel struct {
12
12
  addressTaken map[types.Object]bool
13
13
  needsVarRef map[types.Object]bool
14
14
  functions map[*types.Func]*semanticFunction
15
+ functionCallers map[*types.Func][]*semanticFunction
15
16
  functionsByFullName map[string]*semanticFunction
16
17
  functionLookupMisses map[*types.Func]bool
17
18
  functionFullNames map[*types.Func]string
18
19
  types map[*types.Named]*semanticType
19
20
  values map[types.Object]*semanticValue
20
21
  generatedImports map[string]map[string]bool
22
+ generatedImportTypes map[string]map[types.Type]bool
21
23
  interfaceImplementations []semanticInterfaceImplementation
22
24
  asyncInterfaceMethods map[string]bool
23
25
  asyncInterfaceMethodObjs map[*types.Func]bool
@@ -66,6 +68,10 @@ type semanticField struct {
66
68
  doc string
67
69
  tag string
68
70
  embedded bool
71
+ pkgPath string
72
+ index []int
73
+ offset int64
74
+ exported bool
69
75
  }
70
76
 
71
77
  type semanticValue struct {
@@ -92,10 +98,9 @@ type semanticFunction struct {
92
98
  }
93
99
 
94
100
  type semanticInterfaceImplementation struct {
95
- typ *types.Named
96
- iface *types.Named
97
- pointer bool
98
- asyncMethods map[string]bool
101
+ typ *types.Named
102
+ iface *types.Named
103
+ pointer bool
99
104
  }
100
105
 
101
106
  type semanticInterfaceImplementationGraphEntry struct {