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,9 +1,251 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
+ import * as bytes from '@goscript/bytes/index.js'
3
+ import type * as io from '@goscript/io/index.js'
4
+
5
+ export interface Marshaler {
6
+ MarshalJSON(): [$.Slice<number>, $.GoError]
7
+ }
2
8
 
3
9
  export interface Unmarshaler {
4
10
  UnmarshalJSON(data: $.Slice<number>): $.GoError
5
11
  }
6
12
 
13
+ export type RawMessage = $.Bytes
14
+ export type Number = string
15
+ export type Token = unknown
16
+ export type Delim = number
17
+
18
+ class jsonError extends Error {
19
+ public Error(): string {
20
+ return this.message
21
+ }
22
+ }
23
+
24
+ type decodeOptions = {
25
+ disallowUnknownFields?: boolean
26
+ useNumber?: boolean
27
+ }
28
+
29
+ type fieldMetadata = {
30
+ key: string
31
+ name: string
32
+ tag?: string
33
+ type?: unknown
34
+ }
35
+
36
+ export class SyntaxError extends jsonError {
37
+ public Offset: number
38
+
39
+ constructor(init?: Partial<{ Offset: number; Message: string }>) {
40
+ super(init?.Message ?? 'invalid character in JSON')
41
+ this.name = 'SyntaxError'
42
+ this.Offset = init?.Offset ?? 0
43
+ }
44
+ }
45
+
46
+ export class InvalidUTF8Error extends jsonError {
47
+ public S: string
48
+
49
+ constructor(init?: Partial<{ S: string }>) {
50
+ super(`json: invalid UTF-8 in string: ${init?.S ?? ''}`)
51
+ this.name = 'InvalidUTF8Error'
52
+ this.S = init?.S ?? ''
53
+ }
54
+ }
55
+
56
+ export class InvalidUnmarshalError extends jsonError {
57
+ public Type: unknown
58
+
59
+ constructor(init?: Partial<{ Type: unknown }>) {
60
+ super('json: Unmarshal(non-pointer)')
61
+ this.name = 'InvalidUnmarshalError'
62
+ this.Type = init?.Type ?? null
63
+ }
64
+ }
65
+
66
+ export class MarshalerError extends jsonError {
67
+ public Type: unknown
68
+ public Err: $.GoError
69
+
70
+ constructor(init?: Partial<{ Type: unknown; Err: $.GoError }>) {
71
+ super(`json: error calling MarshalJSON: ${init?.Err?.Error?.() ?? ''}`)
72
+ this.name = 'MarshalerError'
73
+ this.Type = init?.Type ?? null
74
+ this.Err = init?.Err ?? null
75
+ }
76
+
77
+ public Unwrap(): $.GoError {
78
+ return this.Err
79
+ }
80
+ }
81
+
82
+ export class UnmarshalFieldError extends jsonError {
83
+ public Key: string
84
+ public Type: unknown
85
+ public Field: unknown
86
+
87
+ constructor(init?: Partial<{ Key: string; Type: unknown; Field: unknown }>) {
88
+ super(`json: cannot unmarshal object key ${init?.Key ?? ''}`)
89
+ this.name = 'UnmarshalFieldError'
90
+ this.Key = init?.Key ?? ''
91
+ this.Type = init?.Type ?? null
92
+ this.Field = init?.Field ?? null
93
+ }
94
+ }
95
+
96
+ export class UnmarshalTypeError extends jsonError {
97
+ public Value: string
98
+ public Type: unknown
99
+ public Offset: number
100
+ public Struct: string
101
+ public Field: string
102
+
103
+ constructor(
104
+ init?: Partial<{
105
+ Value: string
106
+ Type: unknown
107
+ Offset: number
108
+ Struct: string
109
+ Field: string
110
+ }>,
111
+ ) {
112
+ super(`json: cannot unmarshal ${init?.Value ?? ''}`)
113
+ this.name = 'UnmarshalTypeError'
114
+ this.Value = init?.Value ?? ''
115
+ this.Type = init?.Type ?? null
116
+ this.Offset = init?.Offset ?? 0
117
+ this.Struct = init?.Struct ?? ''
118
+ this.Field = init?.Field ?? ''
119
+ }
120
+ }
121
+
122
+ export class UnsupportedTypeError extends jsonError {
123
+ public Type: unknown
124
+
125
+ constructor(init?: Partial<{ Type: unknown }>) {
126
+ super('json: unsupported type')
127
+ this.name = 'UnsupportedTypeError'
128
+ this.Type = init?.Type ?? null
129
+ }
130
+ }
131
+
132
+ export class UnsupportedValueError extends jsonError {
133
+ public Value: unknown
134
+ public Str: string
135
+
136
+ constructor(init?: Partial<{ Value: unknown; Str: string }>) {
137
+ super(`json: unsupported value: ${init?.Str ?? ''}`)
138
+ this.name = 'UnsupportedValueError'
139
+ this.Value = init?.Value ?? null
140
+ this.Str = init?.Str ?? ''
141
+ }
142
+ }
143
+
144
+ export class Decoder {
145
+ private disallowUnknownFields = false
146
+ private inputOffset = 0
147
+ private useNumber = false
148
+
149
+ public constructor(private readonly reader: io.Reader) {}
150
+
151
+ public Decode(v: unknown): $.GoError {
152
+ const [data, err] = readAllSync(this.reader)
153
+ if (err !== null) {
154
+ return err
155
+ }
156
+ this.inputOffset += $.len(data)
157
+ return decode(data, v, {
158
+ disallowUnknownFields: this.disallowUnknownFields,
159
+ useNumber: this.useNumber,
160
+ })
161
+ }
162
+
163
+ public Buffered(): io.Reader {
164
+ return new bytes.Buffer()
165
+ }
166
+
167
+ public DisallowUnknownFields(): void {
168
+ this.disallowUnknownFields = true
169
+ }
170
+
171
+ public InputOffset(): number {
172
+ return this.inputOffset
173
+ }
174
+
175
+ public More(): boolean {
176
+ return false
177
+ }
178
+
179
+ public Token(): [Token, $.GoError] {
180
+ return [null, $.newError('json: token streaming is unsupported')]
181
+ }
182
+
183
+ public UseNumber(): void {
184
+ this.useNumber = true
185
+ }
186
+ }
187
+
188
+ export class Encoder {
189
+ private escapeHTML = true
190
+ private indent = ''
191
+ private prefix = ''
192
+
193
+ public constructor(private readonly writer: io.Writer) {}
194
+
195
+ public Encode(v: unknown): $.GoError {
196
+ const [data, err] =
197
+ this.indent === '' && this.prefix === '' ?
198
+ marshalBytes(v, '', '', this.escapeHTML)
199
+ : marshalBytes(v, this.prefix, this.indent, this.escapeHTML)
200
+ if (err !== null) {
201
+ return err
202
+ }
203
+
204
+ const out = $.stringToBytes($.bytesToString(data) + '\n')
205
+ const [n, writeErr] = this.writer.Write(out)
206
+ if (writeErr !== null) {
207
+ return writeErr
208
+ }
209
+ if (n < $.len(out)) {
210
+ return $.newError('short write')
211
+ }
212
+ return null
213
+ }
214
+
215
+ public SetEscapeHTML(on: boolean): void {
216
+ this.escapeHTML = on
217
+ }
218
+
219
+ public SetIndent(prefix: string, indent: string): void {
220
+ this.prefix = prefix
221
+ this.indent = indent
222
+ }
223
+ }
224
+
225
+ export function NewDecoder(r: io.Reader): Decoder {
226
+ return new Decoder(r)
227
+ }
228
+
229
+ export function NewEncoder(w: io.Writer): Encoder {
230
+ return new Encoder(w)
231
+ }
232
+
233
+ $.registerInterfaceType('json.Marshaler', null, [
234
+ {
235
+ name: 'MarshalJSON',
236
+ args: [],
237
+ returns: [
238
+ {
239
+ type: {
240
+ kind: $.TypeKind.Slice,
241
+ elemType: { kind: $.TypeKind.Basic, name: 'uint8' },
242
+ },
243
+ },
244
+ { type: 'GoError' },
245
+ ],
246
+ },
247
+ ])
248
+
7
249
  $.registerInterfaceType('json.Unmarshaler', null, [
8
250
  {
9
251
  name: 'UnmarshalJSON',
@@ -21,58 +263,272 @@ $.registerInterfaceType('json.Unmarshaler', null, [
21
263
  ])
22
264
 
23
265
  export function Marshal(v: unknown): [$.Slice<number>, $.GoError] {
266
+ return marshalBytes(v, '', '', true)
267
+ }
268
+
269
+ function marshalBytes(
270
+ v: unknown,
271
+ prefix: string,
272
+ indent: string,
273
+ escapeHTML: boolean,
274
+ ): [$.Slice<number>, $.GoError] {
24
275
  try {
25
- return [$.stringToBytes(JSON.stringify(marshalValue(v))), null]
276
+ let text = JSON.stringify(marshalValue(v), null, indent)
277
+ if (escapeHTML) {
278
+ text = escapeHTMLString(text)
279
+ }
280
+ if (prefix !== '') {
281
+ text = text
282
+ .split('\n')
283
+ .map((line, idx) => (idx === 0 ? line : prefix + line))
284
+ .join('\n')
285
+ }
286
+ return [$.stringToBytes(text), null]
26
287
  } catch (err) {
27
288
  return [null, goError(err)]
28
289
  }
29
290
  }
30
291
 
31
- export function MarshalIndent(
32
- v: unknown,
292
+ export function Compact(
293
+ dst: bytes.Buffer | $.VarRef<bytes.Buffer>,
294
+ src: $.Slice<number>,
295
+ ): $.GoError {
296
+ try {
297
+ const text = JSON.stringify(JSON.parse($.bytesToString(src)))
298
+ const [, err] = $.pointerValue<bytes.Buffer>(dst).Write(
299
+ $.stringToBytes(text),
300
+ )
301
+ return err
302
+ } catch (err) {
303
+ return goError(err)
304
+ }
305
+ }
306
+
307
+ export function HTMLEscape(
308
+ dst: bytes.Buffer | $.VarRef<bytes.Buffer>,
309
+ src: $.Slice<number>,
310
+ ): void {
311
+ const escaped = $.bytesToString(src).replace(/[<>&\u2028\u2029]/g, (char) => {
312
+ switch (char) {
313
+ case '<':
314
+ return '\\u003c'
315
+ case '>':
316
+ return '\\u003e'
317
+ case '&':
318
+ return '\\u0026'
319
+ case '\u2028':
320
+ return '\\u2028'
321
+ case '\u2029':
322
+ return '\\u2029'
323
+ default:
324
+ return char
325
+ }
326
+ })
327
+ $.pointerValue<bytes.Buffer>(dst).Write($.stringToBytes(escaped))
328
+ }
329
+
330
+ export function Indent(
331
+ dst: bytes.Buffer | $.VarRef<bytes.Buffer>,
332
+ src: $.Slice<number>,
33
333
  prefix: string,
34
334
  indent: string,
35
- ): [$.Slice<number>, $.GoError] {
335
+ ): $.GoError {
36
336
  try {
37
- const text = JSON.stringify(marshalValue(v), null, indent)
38
- if (prefix === '') {
39
- return [$.stringToBytes(text), null]
40
- }
41
- return [
42
- $.stringToBytes(
337
+ const text = JSON.stringify(JSON.parse($.bytesToString(src)), null, indent)
338
+ const prefixed =
339
+ prefix === '' ? text : (
43
340
  text
44
341
  .split('\n')
45
342
  .map((line, idx) => (idx === 0 ? line : prefix + line))
46
- .join('\n'),
47
- ),
48
- null,
49
- ]
343
+ .join('\n')
344
+ )
345
+ const [, err] = $.pointerValue<bytes.Buffer>(dst).Write(
346
+ $.stringToBytes(prefixed),
347
+ )
348
+ return err
50
349
  } catch (err) {
51
- return [null, goError(err)]
350
+ return goError(err)
52
351
  }
53
352
  }
54
353
 
354
+ export function MarshalIndent(
355
+ v: unknown,
356
+ prefix: string,
357
+ indent: string,
358
+ ): [$.Slice<number>, $.GoError] {
359
+ return marshalBytes(v, prefix, indent, true)
360
+ }
361
+
55
362
  export function Unmarshal(data: $.Slice<number>, v: unknown): $.GoError {
363
+ return decode(data, v, {})
364
+ }
365
+
366
+ function decode(
367
+ data: $.Slice<number>,
368
+ v: unknown,
369
+ opts: decodeOptions,
370
+ ): $.GoError {
56
371
  try {
57
- assignDecodedValue(v, JSON.parse($.bytesToString(data)))
372
+ if (!validUnmarshalTarget(v)) {
373
+ return $.toGoError(new InvalidUnmarshalError())
374
+ }
375
+ const unmarshaler = unmarshalJSONTarget(v)
376
+ if (unmarshaler !== null) {
377
+ const err = unmarshaler.UnmarshalJSON(data)
378
+ if (err instanceof Promise) {
379
+ return $.newError('json: asynchronous UnmarshalJSON is unsupported')
380
+ }
381
+ return err
382
+ }
383
+ assignDecodedValue(v, parseJSON(data, opts), opts)
58
384
  return null
59
385
  } catch (err) {
60
386
  return goError(err)
61
387
  }
62
388
  }
63
389
 
390
+ export function Valid(data: $.Slice<number>): boolean {
391
+ try {
392
+ JSON.parse($.bytesToString(data))
393
+ return true
394
+ } catch {
395
+ return false
396
+ }
397
+ }
398
+
399
+ export function RawMessage_MarshalJSON(
400
+ m: RawMessage,
401
+ ): [$.Slice<number>, $.GoError] {
402
+ if (m === null) {
403
+ return [$.stringToBytes('null'), null]
404
+ }
405
+ const out = $.makeSlice<number>($.len(m), undefined, 'byte')
406
+ $.copy(out, m)
407
+ return [out, null]
408
+ }
409
+
410
+ export function RawMessage_UnmarshalJSON(
411
+ m: $.VarRef<RawMessage> | RawMessage | null,
412
+ data: $.Slice<number>,
413
+ ): $.GoError {
414
+ const out = $.makeSlice<number>($.len(data), undefined, 'byte')
415
+ $.copy(out, data)
416
+ if ($.isVarRef(m)) {
417
+ m.value = out
418
+ }
419
+ return null
420
+ }
421
+
422
+ export function Number_Float64(n: Number): [number, $.GoError] {
423
+ if (!isValidFloat(n)) {
424
+ return [0, $.newError(`strconv.ParseFloat: parsing "${n}": invalid syntax`)]
425
+ }
426
+ if (/^[+-]?nan$/i.test(n)) {
427
+ return [Number.NaN, null]
428
+ }
429
+ if (/^\+?inf(?:inity)?$/i.test(n)) {
430
+ return [Infinity, null]
431
+ }
432
+ if (/^-inf(?:inity)?$/i.test(n)) {
433
+ return [-Infinity, null]
434
+ }
435
+ const value = Number.parseFloat(n)
436
+ if (Number.isNaN(value)) {
437
+ return [0, $.newError(`strconv.ParseFloat: parsing "${n}": invalid syntax`)]
438
+ }
439
+ if (!Number.isFinite(value) && !/^[+-]?(?:inf(?:inity)?|nan)$/i.test(n)) {
440
+ return [
441
+ value,
442
+ $.newError(`strconv.ParseFloat: parsing "${n}": value out of range`),
443
+ ]
444
+ }
445
+ return [value, null]
446
+ }
447
+
448
+ export function Number_Int64(n: Number): [number, $.GoError] {
449
+ if (!/^[+-]?\d+$/.test(n)) {
450
+ return [0, $.newError(`strconv.ParseInt: parsing "${n}": invalid syntax`)]
451
+ }
452
+ const value = BigInt(n)
453
+ const min = -(1n << 63n)
454
+ const max = (1n << 63n) - 1n
455
+ if (value < min || value > max) {
456
+ const clamped = value < min ? min : max
457
+ return [
458
+ Number(clamped),
459
+ $.newError(`strconv.ParseInt: parsing "${n}": value out of range`),
460
+ ]
461
+ }
462
+ return [Number(value), null]
463
+ }
464
+
465
+ export function Number_String(n: Number): string {
466
+ return n
467
+ }
468
+
469
+ function isValidFloat(value: string): boolean {
470
+ return /^[+-]?(?:(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?|inf(?:inity)?|nan)$/i.test(
471
+ value,
472
+ )
473
+ }
474
+
475
+ function readAllSync(r: io.Reader): [$.Bytes, $.GoError] {
476
+ const chunks: number[] = []
477
+ const buf = $.makeSlice<number>(512, undefined, 'byte')
478
+ while (true) {
479
+ const read = r.Read(buf)
480
+ if (read instanceof Promise) {
481
+ return [null, $.newError('json: asynchronous reader is unsupported')]
482
+ }
483
+ const [n, err] = read
484
+ if (n > 0) {
485
+ chunks.push(...$.bytesToUint8Array($.goSlice(buf, 0, n)))
486
+ }
487
+ if (err !== null) {
488
+ if (err.Error() === 'EOF') {
489
+ return [new Uint8Array(chunks), null]
490
+ }
491
+ return [null, err]
492
+ }
493
+ }
494
+ }
495
+
64
496
  function marshalValue(v: unknown): unknown {
497
+ const marshaler = marshalJSONTarget(v)
498
+ if (marshaler !== null) {
499
+ const result = marshaler.MarshalJSON()
500
+ if (result instanceof Promise) {
501
+ throw new MarshalerError({
502
+ Err: $.newError('json: asynchronous MarshalJSON is unsupported'),
503
+ })
504
+ }
505
+ const [data, err] = result
506
+ if (err !== null) {
507
+ throw new MarshalerError({ Err: err })
508
+ }
509
+ try {
510
+ return JSON.parse($.bytesToString(data))
511
+ } catch (parseErr) {
512
+ throw new MarshalerError({ Err: goError(parseErr) })
513
+ }
514
+ }
65
515
  if ($.isVarRef(v)) {
66
516
  return marshalValue(v.value)
67
517
  }
68
518
  if (v === null || v === undefined) {
69
519
  return null
70
520
  }
521
+ if (typeof v === 'number') {
522
+ if (!Number.isFinite(v)) {
523
+ throw new UnsupportedValueError({ Value: v, Str: String(v) })
524
+ }
525
+ return v
526
+ }
71
527
  if (typeof v !== 'object') {
72
528
  return v
73
529
  }
74
530
  if (v instanceof Uint8Array) {
75
- return Array.from(v).map(marshalValue)
531
+ return base64Encode(v)
76
532
  }
77
533
  if (Array.isArray(v)) {
78
534
  return v.map(marshalValue)
@@ -89,21 +545,101 @@ function marshalValue(v: unknown): unknown {
89
545
  }
90
546
 
91
547
  const out: Record<string, unknown> = {}
92
- const typeFields = structFieldMetadata(v)
93
- for (const [fieldName, ref] of Object.entries(v._fields)) {
94
- const jsonName = jsonFieldName(fieldName, typeFields[fieldName]?.tag)
548
+ for (const field of structFields(v)) {
549
+ const ref = v._fields[field.key]
550
+ if (ref === undefined) {
551
+ continue
552
+ }
553
+ const jsonName = jsonFieldName(field.name, field.tag)
95
554
  if (jsonName === '') {
96
555
  continue
97
556
  }
98
- out[jsonName] = marshalValue(ref.value)
557
+ out[jsonName] = marshalFieldValue(ref.value, field.type)
99
558
  }
100
559
  return out
101
560
  }
102
561
 
103
- function assignDecodedValue(target: unknown, decoded: unknown): void {
562
+ function marshalFieldValue(value: unknown, fieldType: unknown): unknown {
563
+ if (isRawMessageType(fieldType)) {
564
+ const target = $.isVarRef(value) ? value.value : value
565
+ if (target === null || target === undefined) {
566
+ return null
567
+ }
568
+ try {
569
+ return JSON.parse($.bytesToString(target as $.Slice<number>))
570
+ } catch (err) {
571
+ throw new MarshalerError({ Err: goError(err) })
572
+ }
573
+ }
574
+ return marshalValue(value)
575
+ }
576
+
577
+ function marshalJSONTarget(value: unknown): Marshaler | null {
578
+ const target = $.isVarRef(value) ? value.value : value
579
+ if (target === null || target === undefined) {
580
+ return null
581
+ }
582
+ if (typeof target !== 'object' && typeof target !== 'function') {
583
+ return null
584
+ }
585
+ const method = Reflect.get(target, 'MarshalJSON')
586
+ return typeof method === 'function' ? (target as Marshaler) : null
587
+ }
588
+
589
+ function unmarshalJSONTarget(value: unknown): Unmarshaler | null {
590
+ const target = $.isVarRef(value) ? value.value : value
591
+ if (target === null || target === undefined) {
592
+ return null
593
+ }
594
+ if (typeof target !== 'object' && typeof target !== 'function') {
595
+ return null
596
+ }
597
+ const method = Reflect.get(target, 'UnmarshalJSON')
598
+ return typeof method === 'function' ? (target as Unmarshaler) : null
599
+ }
600
+
601
+ function validUnmarshalTarget(value: unknown): boolean {
602
+ if (value === null || value === undefined) {
603
+ return false
604
+ }
605
+ if ($.isVarRef(value)) {
606
+ return true
607
+ }
608
+ return unmarshalJSONTarget(value) !== null || isStructValue(value)
609
+ }
610
+
611
+ function parseJSON(data: $.Slice<number>, opts: decodeOptions): unknown {
612
+ const text = $.bytesToString(data)
613
+ if (opts.useNumber) {
614
+ return JSON.parse(text, (_key, value) =>
615
+ typeof value === 'number' ? String(value) : value,
616
+ )
617
+ }
618
+ return JSON.parse(text)
619
+ }
620
+
621
+ function assignDecodedValue(
622
+ target: unknown,
623
+ decoded: unknown,
624
+ opts: decodeOptions,
625
+ ): void {
104
626
  if ($.isVarRef(target)) {
627
+ const unmarshaler = unmarshalJSONTarget(target.value)
628
+ if (unmarshaler !== null) {
629
+ const err = unmarshaler.UnmarshalJSON(
630
+ $.stringToBytes(JSON.stringify(decoded)),
631
+ )
632
+ if (err !== null) {
633
+ throw err
634
+ }
635
+ return
636
+ }
105
637
  if (isStructValue(target.value) && isPlainObject(decoded)) {
106
- assignStructFields(target.value, decoded)
638
+ assignStructFields(target.value, decoded, opts)
639
+ return
640
+ }
641
+ if (target.value instanceof Uint8Array && typeof decoded === 'string') {
642
+ target.value = base64Decode(decoded)
107
643
  return
108
644
  }
109
645
  if (isPlainObject(decoded)) {
@@ -114,26 +650,58 @@ function assignDecodedValue(target: unknown, decoded: unknown): void {
114
650
  return
115
651
  }
116
652
  if (isStructValue(target) && isPlainObject(decoded)) {
117
- assignStructFields(target, decoded)
653
+ assignStructFields(target, decoded, opts)
118
654
  }
119
655
  }
120
656
 
121
657
  function assignStructFields(
122
658
  target: { _fields: Record<string, $.VarRef<unknown>> },
123
659
  decoded: Record<string, unknown>,
660
+ opts: decodeOptions,
124
661
  ): void {
125
- const typeFields = structFieldMetadata(target)
126
- for (const [fieldName, ref] of Object.entries(target._fields)) {
127
- const jsonName = jsonFieldName(fieldName, typeFields[fieldName]?.tag)
662
+ const fields = structFields(target)
663
+ const knownNames = new Set<string>()
664
+ for (const field of fields) {
665
+ const jsonName = jsonFieldName(field.name, field.tag)
666
+ if (jsonName !== '') {
667
+ knownNames.add(jsonName)
668
+ }
669
+ }
670
+ if (opts.disallowUnknownFields) {
671
+ for (const key of Object.keys(decoded)) {
672
+ if (!knownNames.has(key)) {
673
+ throw $.newError(`json: unknown field "${key}"`)
674
+ }
675
+ }
676
+ }
677
+ for (const field of fields) {
678
+ const ref = target._fields[field.key]
679
+ if (ref === undefined) {
680
+ continue
681
+ }
682
+ const jsonName = jsonFieldName(field.name, field.tag)
128
683
  if (
129
684
  jsonName !== '' &&
130
685
  Object.prototype.hasOwnProperty.call(decoded, jsonName)
131
686
  ) {
132
- ref.value = decoded[jsonName]
687
+ assignDecodedFieldValue(ref, decoded[jsonName], opts, field.type)
133
688
  }
134
689
  }
135
690
  }
136
691
 
692
+ function assignDecodedFieldValue(
693
+ target: $.VarRef<unknown>,
694
+ decoded: unknown,
695
+ opts: decodeOptions,
696
+ fieldType: unknown,
697
+ ): void {
698
+ if (isRawMessageType(fieldType)) {
699
+ target.value = $.stringToBytes(JSON.stringify(decoded))
700
+ return
701
+ }
702
+ assignDecodedValue(target, decoded, opts)
703
+ }
704
+
137
705
  function objectToMap(decoded: Record<string, unknown>): Map<string, unknown> {
138
706
  const out = new Map<string, unknown>()
139
707
  for (const [key, value] of Object.entries(decoded)) {
@@ -167,9 +735,19 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
167
735
  )
168
736
  }
169
737
 
170
- function structFieldMetadata(value: unknown): Record<string, { tag?: string }> {
738
+ function structFields(value: {
739
+ _fields: Record<string, $.VarRef<unknown>>
740
+ }): fieldMetadata[] {
741
+ const fields = structFieldMetadata(value)
742
+ if (fields.length !== 0) {
743
+ return fields
744
+ }
745
+ return Object.keys(value._fields).map((key) => ({ key, name: key }))
746
+ }
747
+
748
+ function structFieldMetadata(value: unknown): fieldMetadata[] {
171
749
  if (value === null || typeof value !== 'object') {
172
- return {}
750
+ return []
173
751
  }
174
752
  const ctor = Reflect.get(value, 'constructor')
175
753
  if (
@@ -177,7 +755,7 @@ function structFieldMetadata(value: unknown): Record<string, { tag?: string }> {
177
755
  ctor === undefined ||
178
756
  (typeof ctor !== 'object' && typeof ctor !== 'function')
179
757
  ) {
180
- return {}
758
+ return []
181
759
  }
182
760
  const typeInfo = Reflect.get(ctor, '__typeInfo')
183
761
  if (
@@ -185,30 +763,93 @@ function structFieldMetadata(value: unknown): Record<string, { tag?: string }> {
185
763
  typeInfo === undefined ||
186
764
  typeof typeInfo !== 'object'
187
765
  ) {
188
- return {}
766
+ return []
189
767
  }
190
768
  const fields = Reflect.get(typeInfo, 'fields')
191
- if (isPlainObject(fields)) {
192
- const out: Record<string, { tag?: string }> = {}
193
- for (const [name, field] of Object.entries(fields)) {
194
- if (!isPlainObject(field)) {
769
+ if (Array.isArray(fields)) {
770
+ const out: fieldMetadata[] = []
771
+ for (const field of fields) {
772
+ if (!$.isStructFieldInfo(field)) {
195
773
  continue
196
774
  }
197
775
  const tag = field.tag
198
- out[name] = typeof tag === 'string' ? { tag } : {}
776
+ out.push({
777
+ key: $.structFieldRuntimeKey(field),
778
+ name: field.name,
779
+ type: field.type,
780
+ ...(typeof tag === 'string' ? { tag } : {}),
781
+ })
199
782
  }
200
783
  return out
201
784
  }
202
- return {}
785
+ return []
786
+ }
787
+
788
+ function isRawMessageType(value: unknown): boolean {
789
+ if (value === 'json.RawMessage' || value === 'encoding/json.RawMessage') {
790
+ return true
791
+ }
792
+ if (!isPlainObject(value)) {
793
+ return false
794
+ }
795
+ return (
796
+ value.typeName === 'json.RawMessage' ||
797
+ value.typeName === 'encoding/json.RawMessage' ||
798
+ value.name === 'json.RawMessage' ||
799
+ value.name === 'encoding/json.RawMessage'
800
+ )
203
801
  }
204
802
 
205
803
  function goError(err: unknown): $.GoError {
804
+ if (
805
+ err !== null &&
806
+ typeof err === 'object' &&
807
+ typeof (err as { Error?: unknown }).Error === 'function'
808
+ ) {
809
+ return err as $.GoError
810
+ }
206
811
  if (err instanceof Error) {
207
812
  return $.toGoError(err)
208
813
  }
209
814
  return $.newError(String(err))
210
815
  }
211
816
 
817
+ function base64Encode(data: Uint8Array): string {
818
+ let binary = ''
819
+ for (const byte of data) {
820
+ binary += String.fromCharCode(byte)
821
+ }
822
+ return btoa(binary)
823
+ }
824
+
825
+ function base64Decode(text: string): Uint8Array {
826
+ const binary = atob(text)
827
+ const out = new Uint8Array(binary.length)
828
+ for (let i = 0; i < binary.length; i++) {
829
+ out[i] = binary.charCodeAt(i)
830
+ }
831
+ return out
832
+ }
833
+
834
+ function escapeHTMLString(text: string): string {
835
+ return text.replace(/[<>&\u2028\u2029]/g, (char) => {
836
+ switch (char) {
837
+ case '<':
838
+ return '\\u003c'
839
+ case '>':
840
+ return '\\u003e'
841
+ case '&':
842
+ return '\\u0026'
843
+ case '\u2028':
844
+ return '\\u2028'
845
+ case '\u2029':
846
+ return '\\u2029'
847
+ default:
848
+ return char
849
+ }
850
+ })
851
+ }
852
+
212
853
  function jsonFieldName(fieldName: string, tag: string | undefined): string {
213
854
  if (tag === undefined || !tag.startsWith('json:"')) {
214
855
  return fieldName