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
@@ -1,8 +1,34 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
3
  import * as $ from '@goscript/builtin/index.js'
4
+ import * as bytes from '@goscript/bytes/index.js'
4
5
 
5
- import { Marshal, MarshalIndent, Unmarshal, type Unmarshaler } from './index.js'
6
+ import {
7
+ Compact,
8
+ HTMLEscape,
9
+ Indent,
10
+ InvalidUTF8Error,
11
+ InvalidUnmarshalError,
12
+ MarshalerError,
13
+ Marshal,
14
+ MarshalIndent,
15
+ NewDecoder,
16
+ NewEncoder,
17
+ Number_Float64,
18
+ Number_Int64,
19
+ Number_String,
20
+ RawMessage_MarshalJSON,
21
+ RawMessage_UnmarshalJSON,
22
+ SyntaxError as JSONSyntaxError,
23
+ UnmarshalFieldError,
24
+ Unmarshal,
25
+ UnmarshalTypeError,
26
+ UnsupportedTypeError,
27
+ UnsupportedValueError,
28
+ Valid,
29
+ type Marshaler,
30
+ type Unmarshaler,
31
+ } from './index.js'
6
32
 
7
33
  class Person {
8
34
  public _fields = {
@@ -16,37 +42,92 @@ class Person {
16
42
  new Person(),
17
43
  [],
18
44
  Person,
19
- {
20
- Name: {
45
+ [
46
+ {
47
+ name: 'Name',
48
+ key: 'Name',
21
49
  type: { kind: $.TypeKind.Basic, name: 'string' },
22
50
  tag: 'json:"name"',
23
51
  },
24
- Age: { type: { kind: $.TypeKind.Basic, name: 'int' }, tag: 'json:"age"' },
25
- Active: {
52
+ {
53
+ name: 'Age',
54
+ key: 'Age',
55
+ type: { kind: $.TypeKind.Basic, name: 'int' },
56
+ tag: 'json:"age"',
57
+ },
58
+ {
59
+ name: 'Active',
60
+ key: 'Active',
26
61
  type: { kind: $.TypeKind.Basic, name: 'bool' },
27
62
  tag: 'json:"active"',
28
63
  },
29
- },
64
+ ],
65
+ )
66
+ }
67
+
68
+ class FieldAlias {
69
+ public _fields = {
70
+ Name: $.varRef(''),
71
+ }
72
+
73
+ static __typeInfo = $.registerStructType(
74
+ 'test.FieldAlias',
75
+ new FieldAlias(),
76
+ [],
77
+ FieldAlias,
78
+ [
79
+ {
80
+ name: 'FullName',
81
+ key: 'Name',
82
+ type: { kind: $.TypeKind.Basic, name: 'string' },
83
+ },
84
+ ],
30
85
  )
31
86
  }
32
87
 
33
88
  describe('encoding/json override', () => {
34
89
  it('registers the Unmarshaler interface shape', () => {
90
+ class CustomMarshaler implements Marshaler {
91
+ MarshalJSON(): [$.Slice<number>, $.GoError] {
92
+ return [$.stringToBytes('{"ok":true}'), null]
93
+ }
94
+ }
95
+
35
96
  class CustomUnmarshaler implements Unmarshaler {
36
97
  UnmarshalJSON(_data: $.Slice<number>): $.GoError {
37
98
  return null
38
99
  }
39
100
  }
40
101
 
102
+ const [, marshalOK] = $.typeAssertTuple<Marshaler>(
103
+ new CustomMarshaler(),
104
+ 'json.Marshaler',
105
+ )
41
106
  const [value, ok] = $.typeAssertTuple<Unmarshaler>(
42
107
  new CustomUnmarshaler(),
43
108
  'json.Unmarshaler',
44
109
  )
45
110
 
111
+ expect(marshalOK).toBe(true)
46
112
  expect(ok).toBe(true)
47
113
  expect(value.UnmarshalJSON($.stringToBytes('{}'))).toBeNull()
48
114
  })
49
115
 
116
+ it('exposes JSON error structs as Go errors', () => {
117
+ for (const err of [
118
+ new JSONSyntaxError(),
119
+ new InvalidUTF8Error({ S: 'bad' }),
120
+ new InvalidUnmarshalError(),
121
+ new MarshalerError({ Err: $.newError('bad marshal') }),
122
+ new UnmarshalFieldError({ Key: 'field' }),
123
+ new UnmarshalTypeError({ Value: 'string' }),
124
+ new UnsupportedTypeError(),
125
+ new UnsupportedValueError({ Str: 'NaN' }),
126
+ ]) {
127
+ expect(err.Error()).toBe(err.message)
128
+ }
129
+ })
130
+
50
131
  it('marshals struct fields through json tags', () => {
51
132
  const person = new Person()
52
133
  person._fields.Name.value = 'Alice'
@@ -61,6 +142,187 @@ describe('encoding/json override', () => {
61
142
  )
62
143
  })
63
144
 
145
+ it('uses descriptor names separately from storage keys', () => {
146
+ const alias = new FieldAlias()
147
+ alias._fields.Name.value = 'Ada'
148
+
149
+ const [data, err] = Marshal(alias)
150
+ expect(err).toBeNull()
151
+ expect($.bytesToString(data)).toBe('{"FullName":"Ada"}')
152
+
153
+ const target = $.varRef(new FieldAlias())
154
+ expect(
155
+ Unmarshal($.stringToBytes('{"FullName":"Grace"}'), target),
156
+ ).toBeNull()
157
+ expect(target.value._fields.Name.value).toBe('Grace')
158
+ })
159
+
160
+ it('rejects unsupported values and invalid unmarshal targets', () => {
161
+ const [nanData, nanErr] = Marshal(Number.NaN)
162
+ expect(nanData).toBeNull()
163
+ expect(nanErr).toBeInstanceOf(UnsupportedValueError)
164
+
165
+ const [htmlData, htmlErr] = Marshal(new Map([['text', '<tag>&']]))
166
+ expect(htmlErr).toBeNull()
167
+ expect($.bytesToString(htmlData)).toBe(
168
+ '{"text":"\\u003ctag\\u003e\\u0026"}',
169
+ )
170
+
171
+ expect(Unmarshal($.stringToBytes('{}'), null)).toBeInstanceOf(
172
+ InvalidUnmarshalError,
173
+ )
174
+ expect(Unmarshal($.stringToBytes('{}'), 1)).toBeInstanceOf(
175
+ InvalidUnmarshalError,
176
+ )
177
+ })
178
+
179
+ it('uses custom marshal and unmarshal hooks', () => {
180
+ class CustomJSON implements Marshaler, Unmarshaler {
181
+ public Text = ''
182
+
183
+ MarshalJSON(): [$.Slice<number>, $.GoError] {
184
+ return [$.stringToBytes('{"hook":true}'), null]
185
+ }
186
+
187
+ UnmarshalJSON(data: $.Slice<number>): $.GoError {
188
+ this.Text = $.bytesToString(data)
189
+ return null
190
+ }
191
+ }
192
+
193
+ class RawEnvelope {
194
+ public _fields = {
195
+ Raw: $.varRef($.stringToBytes('{"embedded":true}')),
196
+ }
197
+
198
+ static __typeInfo = $.registerStructType(
199
+ 'test.RawEnvelope',
200
+ new RawEnvelope(),
201
+ [],
202
+ RawEnvelope,
203
+ [
204
+ {
205
+ name: 'Raw',
206
+ key: 'Raw',
207
+ type: 'json.RawMessage',
208
+ tag: 'json:"raw"',
209
+ },
210
+ ],
211
+ )
212
+ }
213
+
214
+ class Envelope {
215
+ public _fields = {
216
+ Person: $.varRef(new Person()),
217
+ Data: $.varRef(new Uint8Array(0)),
218
+ Raw: $.varRef(new Uint8Array(0)),
219
+ Hook: $.varRef(new CustomJSON()),
220
+ }
221
+
222
+ static __typeInfo = $.registerStructType(
223
+ 'test.Envelope',
224
+ new Envelope(),
225
+ [],
226
+ Envelope,
227
+ [
228
+ {
229
+ name: 'Person',
230
+ key: 'Person',
231
+ type: { kind: $.TypeKind.Struct, name: 'test.Person' },
232
+ tag: 'json:"person"',
233
+ },
234
+ {
235
+ name: 'Data',
236
+ key: 'Data',
237
+ type: {
238
+ kind: $.TypeKind.Slice,
239
+ elemType: { kind: $.TypeKind.Basic, name: 'uint8' },
240
+ },
241
+ tag: 'json:"data"',
242
+ },
243
+ {
244
+ name: 'Raw',
245
+ key: 'Raw',
246
+ type: {
247
+ kind: $.TypeKind.Slice,
248
+ elemType: { kind: $.TypeKind.Basic, name: 'uint8' },
249
+ typeName: 'json.RawMessage',
250
+ },
251
+ tag: 'json:"raw"',
252
+ },
253
+ {
254
+ name: 'Hook',
255
+ key: 'Hook',
256
+ type: { kind: $.TypeKind.Struct, name: 'test.CustomJSON' },
257
+ tag: 'json:"hook"',
258
+ },
259
+ ],
260
+ )
261
+ }
262
+
263
+ const [data, err] = Marshal(new CustomJSON())
264
+ expect(err).toBeNull()
265
+ expect($.bytesToString(data)).toBe('{"hook":true}')
266
+
267
+ const [indented, indentErr] = MarshalIndent(new CustomJSON(), '', ' ')
268
+ expect(indentErr).toBeNull()
269
+ expect($.bytesToString(indented)).toBe('{\n "hook": true\n}')
270
+
271
+ const target = $.varRef(new CustomJSON())
272
+ expect(Unmarshal($.stringToBytes('{"input":1}'), target)).toBeNull()
273
+ expect(target.value.Text).toBe('{"input":1}')
274
+
275
+ const raw = $.namedValueInterfaceValue<unknown>(
276
+ $.stringToBytes('{"raw":true}'),
277
+ 'json.RawMessage',
278
+ { MarshalJSON: RawMessage_MarshalJSON },
279
+ )
280
+ const [rawData, rawErr] = Marshal(raw)
281
+ expect(rawErr).toBeNull()
282
+ expect($.bytesToString(rawData)).toBe('{"raw":true}')
283
+
284
+ const [byteData, byteErr] = Marshal($.stringToBytes('x'))
285
+ expect(byteErr).toBeNull()
286
+ expect($.bytesToString(byteData)).toBe('"eA=="')
287
+
288
+ const [rawEnvelopeData, rawEnvelopeErr] = Marshal(new RawEnvelope())
289
+ expect(rawEnvelopeErr).toBeNull()
290
+ expect($.bytesToString(rawEnvelopeData)).toBe('{"raw":{"embedded":true}}')
291
+
292
+ const rawEnvelopeTarget = $.varRef(new RawEnvelope())
293
+ expect(
294
+ Unmarshal($.stringToBytes('{"raw":{"next":1}}'), rawEnvelopeTarget),
295
+ ).toBeNull()
296
+ expect($.bytesToString(rawEnvelopeTarget.value._fields.Raw.value)).toBe(
297
+ '{"next":1}',
298
+ )
299
+
300
+ const byteTarget = $.varRef(new Uint8Array(0))
301
+ expect(Unmarshal($.stringToBytes('"eA=="'), byteTarget)).toBeNull()
302
+ expect($.bytesToString(byteTarget.value)).toBe('x')
303
+
304
+ const envelope = $.varRef(new Envelope())
305
+ expect(
306
+ Unmarshal(
307
+ $.stringToBytes(
308
+ '{"person":{"name":"Eve","age":31},"data":"eA==","raw":{"keep":true},"hook":{"nested":true}}',
309
+ ),
310
+ envelope,
311
+ ),
312
+ ).toBeNull()
313
+ expect(envelope.value._fields.Person.value._fields.Name.value).toBe('Eve')
314
+ expect(envelope.value._fields.Person.value._fields.Age.value).toBe(31)
315
+ expect($.bytesToString(envelope.value._fields.Data.value)).toBe('x')
316
+ expect($.bytesToString(envelope.value._fields.Raw.value)).toBe(
317
+ '{"keep":true}',
318
+ )
319
+ expect(envelope.value._fields.Hook.value.Text).toBe('{"nested":true}')
320
+
321
+ const [envelopeData, envelopeErr] = Marshal(envelope.value)
322
+ expect(envelopeErr).toBeNull()
323
+ expect($.bytesToString(envelopeData)).toContain('"raw":{"keep":true}')
324
+ })
325
+
64
326
  it('marshals indented JSON with a line prefix', () => {
65
327
  const person = new Person()
66
328
  person._fields.Name.value = 'Alice'
@@ -98,4 +360,96 @@ describe('encoding/json override', () => {
98
360
  expect(mapRef.value?.get('age')).toBe(22)
99
361
  expect(mapRef.value?.get('active')).toBe(true)
100
362
  })
363
+
364
+ it('encodes JSON to an io.Writer with newline, indentation, and HTML escaping', () => {
365
+ const chunks: string[] = []
366
+ const writer = {
367
+ Write(p: $.Bytes): [number, $.GoError] {
368
+ chunks.push($.bytesToString(p))
369
+ return [$.len(p), null]
370
+ },
371
+ }
372
+
373
+ const encoder = NewEncoder(writer)
374
+ expect(encoder.Encode(new Map([['text', '<tag>&']]))).toBeNull()
375
+ encoder.SetEscapeHTML(false)
376
+ encoder.SetIndent('', ' ')
377
+ expect(encoder.Encode(new Map([['text', '<tag>&']]))).toBeNull()
378
+
379
+ expect(chunks).toEqual([
380
+ '{"text":"\\u003ctag\\u003e\\u0026"}\n',
381
+ '{\n "text": "<tag>&"\n}\n',
382
+ ])
383
+ })
384
+
385
+ it('validates, compacts, indents, and escapes JSON bytes', () => {
386
+ expect(Valid($.stringToBytes('{"ok":true}'))).toBe(true)
387
+ expect(Valid($.stringToBytes('{'))).toBe(false)
388
+
389
+ const compact = new bytes.Buffer()
390
+ expect(Compact(compact, $.stringToBytes('{ "ok" : true }'))).toBeNull()
391
+ expect(compact.String()).toBe('{"ok":true}')
392
+
393
+ const indented = new bytes.Buffer()
394
+ expect(
395
+ Indent(indented, $.stringToBytes('{"ok":true}'), '> ', ' '),
396
+ ).toBeNull()
397
+ expect(indented.String()).toBe('{\n> "ok": true\n> }')
398
+
399
+ const escaped = new bytes.Buffer()
400
+ HTMLEscape(escaped, $.stringToBytes('"<tag>&"'))
401
+ expect(escaped.String()).toBe('"\\u003ctag\\u003e\\u0026"')
402
+ })
403
+
404
+ it('decodes from readers and exposes raw message and number helpers', () => {
405
+ const reader = bytes.NewBufferString('{"name":"Dana","age":28}')!
406
+ const decoder = NewDecoder(reader)
407
+ const target = $.varRef(new Person())
408
+
409
+ expect(decoder.Decode(target)).toBeNull()
410
+ expect(target.value._fields.Name.value).toBe('Dana')
411
+ expect(target.value._fields.Age.value).toBe(28)
412
+ expect(decoder.InputOffset()).toBeGreaterThan(0)
413
+
414
+ const raw = $.stringToBytes('{"raw":true}')
415
+ const [marshaled, marshalErr] = RawMessage_MarshalJSON(raw)
416
+ expect(marshalErr).toBeNull()
417
+ expect($.bytesToString(marshaled)).toBe('{"raw":true}')
418
+
419
+ const rawRef = $.varRef<$.Bytes>(null)
420
+ expect(
421
+ RawMessage_UnmarshalJSON(rawRef, $.stringToBytes('[1,2]')),
422
+ ).toBeNull()
423
+ expect($.bytesToString(rawRef.value)).toBe('[1,2]')
424
+
425
+ expect(Number_String('42')).toBe('42')
426
+ expect(Number_Int64('42')).toEqual([42, null])
427
+ expect(Number_Float64('3.5')).toEqual([3.5, null])
428
+ expect(Number.isNaN(Number_Float64('NaN')[0])).toBe(true)
429
+ expect(Number_Float64('-Inf')).toEqual([-Infinity, null])
430
+ expect(Number_Float64('1x')[1]?.Error()).toContain('invalid syntax')
431
+ expect(Number_Float64('1e999')[1]?.Error()).toContain('value out of range')
432
+ expect(Number_Int64('9223372036854775808')[1]?.Error()).toContain(
433
+ 'value out of range',
434
+ )
435
+ })
436
+
437
+ it('applies decoder UseNumber and DisallowUnknownFields options', () => {
438
+ const numberReader = bytes.NewBufferString('{"n":12}')!
439
+ const numberDecoder = NewDecoder(numberReader)
440
+ numberDecoder.UseNumber()
441
+ const numberTarget = $.varRef<Map<string, unknown> | null>(null)
442
+
443
+ expect(numberDecoder.Decode(numberTarget)).toBeNull()
444
+ expect(numberTarget.value?.get('n')).toBe('12')
445
+
446
+ const strictReader = bytes.NewBufferString('{"name":"Ada","extra":true}')!
447
+ const strictDecoder = NewDecoder(strictReader)
448
+ strictDecoder.DisallowUnknownFields()
449
+ const strictTarget = $.varRef(new Person())
450
+
451
+ expect(strictDecoder.Decode(strictTarget)?.Error()).toBe(
452
+ 'json: unknown field "extra"',
453
+ )
454
+ })
101
455
  })