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,7 +1,8 @@
1
1
  import { createHash } from 'node:crypto'
2
2
  import { describe, expect, it } from 'vitest'
3
+ import * as $ from '@goscript/builtin/index.js'
3
4
 
4
- import { New, Sum } from './index.js'
5
+ import { New, Size, Sum } from './index.js'
5
6
 
6
7
  describe('crypto/sha1 override', () => {
7
8
  it('matches Node digest', async () => {
@@ -15,7 +16,23 @@ describe('crypto/sha1 override', () => {
15
16
  h.Write(new TextEncoder().encode('go'))
16
17
  h.Write(new TextEncoder().encode('script'))
17
18
 
18
- expect(toHex(await h.Sum(null))).toBe(nodeHash(new TextEncoder().encode('goscript')))
19
+ expect(toHex(await h.Sum(null))).toBe(
20
+ nodeHash(new TextEncoder().encode('goscript')),
21
+ )
22
+ })
23
+
24
+ it('appends into spare byte-slice backing', async () => {
25
+ const h = New()
26
+ h.Write(new TextEncoder().encode('abc'))
27
+
28
+ const backing = $.makeSlice<number>(Size, undefined, 'byte')
29
+ const out = await h.Sum($.goSlice(backing, 0, 0))
30
+ expect(out.length).toBe(Size)
31
+ expect(backing[0]).toBe(out[0])
32
+ expect(backing[Size - 1]).toBe(out[Size - 1])
33
+ expect(toHex($.bytesToUint8Array(backing))).toBe(
34
+ nodeHash(new TextEncoder().encode('abc')),
35
+ )
19
36
  })
20
37
  })
21
38
 
@@ -41,7 +41,7 @@ class Digest {
41
41
  this.canCopyHash ?
42
42
  new Uint8Array(this.hash!.copy!().digest())
43
43
  : await sum(this.snapshotBytes())
44
- return appendDigest($.bytesToUint8Array(b), digest)
44
+ return appendDigest(b, digest)
45
45
  }
46
46
 
47
47
  Reset(): void {
@@ -92,11 +92,8 @@ async function sum(data: $.Bytes): Promise<Uint8Array> {
92
92
  return new Uint8Array(digest)
93
93
  }
94
94
 
95
- function appendDigest(prefix: Uint8Array, digest: Uint8Array): Uint8Array {
96
- const out = new Uint8Array(prefix.length + digest.length)
97
- out.set(prefix)
98
- out.set(digest, prefix.length)
99
- return out
95
+ function appendDigest(prefix: $.Bytes, digest: Uint8Array): $.Bytes {
96
+ return $.append(prefix as any, ...digest) as $.Bytes
100
97
  }
101
98
 
102
99
  function createNodeHash(): NodeCryptoHash | null {
@@ -25,11 +25,23 @@ describe('crypto/sha256 override', () => {
25
25
  )
26
26
  })
27
27
 
28
+ test('streaming digest appends into spare byte-slice backing', async () => {
29
+ const digest = New()
30
+ expect(digest.Write($.stringToBytes('abc'))).toEqual([3, null])
31
+
32
+ const backing = $.makeSlice<number>(Size, undefined, 'byte')
33
+ const out = await digest.Sum($.goSlice(backing, 0, 0))
34
+ expect(out.length).toBe(Size)
35
+ expect(Array.from($.bytesToUint8Array(backing))).toEqual(
36
+ Array.from(await Sum256($.stringToBytes('abc'))),
37
+ )
38
+ })
39
+
28
40
  test('sums SHA-224 with host crypto', async () => {
29
41
  const sum = await Sum224($.stringToBytes('abc'))
30
42
  expect(Array.from(sum)).toEqual([
31
- 35, 9, 125, 34, 52, 5, 216, 34, 134, 66, 164, 119, 189, 162, 85, 179,
32
- 42, 173, 188, 228, 189, 160, 179, 247, 227, 108, 157, 167,
43
+ 35, 9, 125, 34, 52, 5, 216, 34, 134, 66, 164, 119, 189, 162, 85, 179, 42,
44
+ 173, 188, 228, 189, 160, 179, 247, 227, 108, 157, 167,
33
45
  ])
34
46
  })
35
47
 
@@ -44,7 +44,7 @@ class Digest {
44
44
  this.canCopyHash ?
45
45
  new Uint8Array(this.hash!.copy!().digest())
46
46
  : await sum(this.algorithm, this.snapshotBytes())
47
- return appendDigest($.bytesToUint8Array(b), digest)
47
+ return appendDigest(b, digest)
48
48
  }
49
49
 
50
50
  Reset(): void {
@@ -112,11 +112,8 @@ async function sum(
112
112
  return new Uint8Array(digest)
113
113
  }
114
114
 
115
- function appendDigest(prefix: Uint8Array, digest: Uint8Array): Uint8Array {
116
- const out = new Uint8Array(prefix.length + digest.length)
117
- out.set(prefix)
118
- out.set(digest, prefix.length)
119
- return out
115
+ function appendDigest(prefix: $.Bytes, digest: Uint8Array): $.Bytes {
116
+ return $.append(prefix as any, ...digest) as $.Bytes
120
117
  }
121
118
 
122
119
  function createNodeHash(algorithm: ShaAlgorithm): NodeCryptoHash | null {
@@ -1,7 +1,8 @@
1
1
  import { createHash } from 'node:crypto'
2
2
  import { describe, expect, it } from 'vitest'
3
+ import * as $ from '@goscript/builtin/index.js'
3
4
 
4
- import { New, Sum384, Sum512, Sum512_224, Sum512_256 } from './index.js'
5
+ import { New, Size, Sum384, Sum512, Sum512_224, Sum512_256 } from './index.js'
5
6
 
6
7
  describe('crypto/sha512 override', () => {
7
8
  it('matches Node digests', async () => {
@@ -18,7 +19,21 @@ describe('crypto/sha512 override', () => {
18
19
  h.Write(new TextEncoder().encode('go'))
19
20
  h.Write(new TextEncoder().encode('script'))
20
21
 
21
- expect(toHex(await h.Sum(null))).toBe(nodeHash('sha512', new TextEncoder().encode('goscript')))
22
+ expect(toHex(await h.Sum(null))).toBe(
23
+ nodeHash('sha512', new TextEncoder().encode('goscript')),
24
+ )
25
+ })
26
+
27
+ it('appends into spare byte-slice backing', async () => {
28
+ const h = New()
29
+ h.Write(new TextEncoder().encode('abc'))
30
+
31
+ const backing = $.makeSlice<number>(Size, undefined, 'byte')
32
+ const out = await h.Sum($.goSlice(backing, 0, 0))
33
+ expect(out.length).toBe(Size)
34
+ expect(toHex($.bytesToUint8Array(backing))).toBe(
35
+ nodeHash('sha512', new TextEncoder().encode('abc')),
36
+ )
22
37
  })
23
38
  })
24
39
 
@@ -38,7 +38,7 @@ class Digest {
38
38
  this.canCopyHash ?
39
39
  new Uint8Array(this.hash!.copy!().digest())
40
40
  : await sum(this.algorithm, this.snapshotBytes())
41
- return appendDigest($.bytesToUint8Array(b), digest)
41
+ return appendDigest(b, digest)
42
42
  }
43
43
 
44
44
  Reset(): void {
@@ -123,11 +123,8 @@ async function sum(
123
123
  return new Uint8Array(digest)
124
124
  }
125
125
 
126
- function appendDigest(prefix: Uint8Array, digest: Uint8Array): Uint8Array {
127
- const out = new Uint8Array(prefix.length + digest.length)
128
- out.set(prefix)
129
- out.set(digest, prefix.length)
130
- return out
126
+ function appendDigest(prefix: $.Bytes, digest: Uint8Array): $.Bytes {
127
+ return $.append(prefix as any, ...digest) as $.Bytes
131
128
  }
132
129
 
133
130
  function createNodeHash(algorithm: ShaAlgorithm): NodeCryptoHash | null {
@@ -0,0 +1,87 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { cloneStructValue, markAsStructValue } from '@goscript/builtin/index.js'
4
+ import { EOF } from '@goscript/io/index.js'
5
+ import { ReadDir, ReadFile, Stat } from '@goscript/io/fs/index.js'
6
+
7
+ import { FS } from './index.js'
8
+
9
+ describe('embed.FS', () => {
10
+ it('clones embedded files as Go struct values', () => {
11
+ const original = markAsStructValue(
12
+ new FS(new Map([['config-set.bin', new Uint8Array([1, 2, 3])]])),
13
+ )
14
+
15
+ const cloned = cloneStructValue(original)
16
+ const [data, err] = cloned.ReadFile('config-set.bin')
17
+
18
+ expect(err).toBeNull()
19
+ expect(Array.from(data)).toEqual([1, 2, 3])
20
+ })
21
+
22
+ it('supports io/fs read, stat, and directory APIs', () => {
23
+ const fsys = markAsStructValue(
24
+ new FS(
25
+ new Map([
26
+ ['config-set.bin', new Uint8Array([1, 2, 3])],
27
+ ['assets/config.json', new Uint8Array([4])],
28
+ ]),
29
+ ),
30
+ )
31
+
32
+ const [data, readErr] = ReadFile(fsys, 'config-set.bin')
33
+ expect(readErr).toBeNull()
34
+ expect(Array.from(data)).toEqual([1, 2, 3])
35
+ data[0] = 9
36
+ const [dataAgain, readAgainErr] = ReadFile(fsys, 'config-set.bin')
37
+ expect(readAgainErr).toBeNull()
38
+ expect(Array.from(dataAgain)).toEqual([1, 2, 3])
39
+
40
+ const [rootEntries, rootErr] = ReadDir(fsys, '.')
41
+ expect(rootErr).toBeNull()
42
+ expect(rootEntries!.map((entry) => entry!.Name())).toEqual([
43
+ 'assets',
44
+ 'config-set.bin',
45
+ ])
46
+
47
+ const [assetInfo, statErr] = Stat(fsys, 'assets')
48
+ expect(statErr).toBeNull()
49
+ expect(assetInfo!.IsDir()).toBe(true)
50
+
51
+ const [assetEntries, assetErr] = ReadDir(fsys, 'assets')
52
+ expect(assetErr).toBeNull()
53
+ expect(assetEntries!.map((entry) => entry!.Name())).toEqual(['config.json'])
54
+ })
55
+
56
+ it('supports Open file reads and directory iteration', () => {
57
+ const fsys = markAsStructValue(
58
+ new FS(
59
+ new Map([
60
+ ['config-set.bin', new Uint8Array([1, 2, 3])],
61
+ ['assets/config.json', new Uint8Array([4])],
62
+ ]),
63
+ ),
64
+ )
65
+
66
+ const [file, openErr] = fsys.Open('config-set.bin')
67
+ expect(openErr).toBeNull()
68
+ const buffer = new Uint8Array(2)
69
+ const [firstRead, firstErr] = file!.Read(buffer)
70
+ expect(firstErr).toBeNull()
71
+ expect(firstRead).toBe(2)
72
+ expect(Array.from(buffer)).toEqual([1, 2])
73
+ const [secondRead, secondErr] = file!.Read(buffer)
74
+ expect(secondErr).toBeNull()
75
+ expect(secondRead).toBe(1)
76
+ expect(Array.from(buffer)).toEqual([3, 2])
77
+ const [eofRead, eofErr] = file!.Read(buffer)
78
+ expect(eofRead).toBe(0)
79
+ expect(eofErr).toBe(EOF)
80
+
81
+ const [dir, dirOpenErr] = fsys.Open('.')
82
+ expect(dirOpenErr).toBeNull()
83
+ const [entries, readDirErr] = dir!.ReadDir(1)
84
+ expect(readDirErr).toBeNull()
85
+ expect(entries!.map((entry) => entry!.Name())).toEqual(['assets'])
86
+ })
87
+ })
package/gs/embed/index.ts CHANGED
@@ -1,20 +1,244 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
+ import * as io from '@goscript/io/index.js'
2
3
  import * as fs from '@goscript/io/fs/index.js'
4
+ import * as time from '@goscript/time/index.js'
3
5
 
4
6
  export class FS {
7
+ private files: Map<string, Uint8Array>
8
+
9
+ constructor(files?: Map<string, Uint8Array>) {
10
+ this.files = files ?? new Map()
11
+ }
12
+
13
+ clone(): FS {
14
+ const files = new Map<string, Uint8Array>()
15
+ for (const [name, data] of this.files) {
16
+ files.set(name, data.slice())
17
+ }
18
+ return $.markAsStructValue(new FS(files))
19
+ }
20
+
5
21
  Open(name: string): [fs.File, $.GoError] {
6
- return [null, pathError('open', name)]
22
+ const err = validatePath('open', name)
23
+ if (err != null) {
24
+ return [null, err]
25
+ }
26
+ const data = this.files.get(name)
27
+ if (data !== undefined) {
28
+ return [new embedFile(name, data), null]
29
+ }
30
+ const entries = this.dirEntries(name)
31
+ if (entries === null) {
32
+ return [null, pathError('open', name, fs.ErrNotExist)]
33
+ }
34
+ return [new embedFile(name, null, entries), null]
7
35
  }
8
36
 
9
37
  ReadDir(name: string): [$.Slice<fs.DirEntry>, $.GoError] {
10
- return [null, pathError('read', name)]
38
+ const err = validatePath('read', name)
39
+ if (err != null) {
40
+ return [null, err]
41
+ }
42
+ const entries = this.dirEntries(name)
43
+ if (entries === null) {
44
+ return [null, pathError('read', name, fs.ErrNotExist)]
45
+ }
46
+ return [entries, null]
11
47
  }
12
48
 
13
49
  ReadFile(name: string): [Uint8Array, $.GoError] {
14
- return [new Uint8Array(0), pathError('read', name)]
50
+ const err = validatePath('read', name)
51
+ if (err != null) {
52
+ return [new Uint8Array(0), err]
53
+ }
54
+ const data = this.files.get(name)
55
+ if (data === undefined) {
56
+ const err = this.dirExists(name) ? fs.ErrInvalid : fs.ErrNotExist
57
+ return [new Uint8Array(0), pathError('read', name, err)]
58
+ }
59
+ return [data.slice(), null]
60
+ }
61
+
62
+ Stat(name: string): [fs.FileInfo, $.GoError] {
63
+ const err = validatePath('stat', name)
64
+ if (err != null) {
65
+ return [null, err]
66
+ }
67
+ const data = this.files.get(name)
68
+ if (data !== undefined) {
69
+ return [new embedFileInfo(baseName(name), data.byteLength, 0o444), null]
70
+ }
71
+ if (!this.dirExists(name)) {
72
+ return [null, pathError('stat', name, fs.ErrNotExist)]
73
+ }
74
+ return [new embedFileInfo(baseName(name), 0, fs.ModeDir | 0o555), null]
75
+ }
76
+
77
+ private dirEntries(name: string): $.Slice<fs.DirEntry> | null {
78
+ if (!this.dirExists(name)) {
79
+ return null
80
+ }
81
+ const prefix = name === '.' ? '' : name + '/'
82
+ const entries = new Map<string, fs.DirEntry>()
83
+ for (const [filePath, data] of this.files) {
84
+ if (prefix !== '' && !filePath.startsWith(prefix)) {
85
+ continue
86
+ }
87
+ const rest = prefix === '' ? filePath : filePath.slice(prefix.length)
88
+ if (rest === '') {
89
+ continue
90
+ }
91
+ const slash = rest.indexOf('/')
92
+ const childName = slash === -1 ? rest : rest.slice(0, slash)
93
+ if (entries.has(childName)) {
94
+ continue
95
+ }
96
+ const isDir = slash !== -1
97
+ const info =
98
+ isDir ?
99
+ new embedFileInfo(childName, 0, fs.ModeDir | 0o555)
100
+ : new embedFileInfo(childName, data.byteLength, 0o444)
101
+ entries.set(childName, new embedDirEntry(info))
102
+ }
103
+ return Array.from(entries.values()).sort((a, b) =>
104
+ a!.Name().localeCompare(b!.Name()),
105
+ )
106
+ }
107
+
108
+ private dirExists(name: string): boolean {
109
+ if (name === '.') {
110
+ return true
111
+ }
112
+ const prefix = name + '/'
113
+ for (const path of this.files.keys()) {
114
+ if (path.startsWith(prefix)) {
115
+ return true
116
+ }
117
+ }
118
+ return false
119
+ }
120
+ }
121
+
122
+ class embedFile {
123
+ private offset = 0
124
+ private dirOffset = 0
125
+
126
+ constructor(
127
+ private readonly name: string,
128
+ private readonly data: Uint8Array | null,
129
+ private readonly entries: $.Slice<fs.DirEntry> = [],
130
+ ) {}
131
+
132
+ Close(): $.GoError {
133
+ return null
134
+ }
135
+
136
+ Read(buffer: Uint8Array): [number, $.GoError] {
137
+ if (this.data === null) {
138
+ return [0, pathError('read', this.name, fs.ErrInvalid)]
139
+ }
140
+ if (this.offset >= this.data.byteLength) {
141
+ return [0, io.EOF]
142
+ }
143
+ const n = Math.min(buffer.byteLength, this.data.byteLength - this.offset)
144
+ buffer.set(this.data.subarray(this.offset, this.offset + n))
145
+ this.offset += n
146
+ return [n, null]
147
+ }
148
+
149
+ ReadDir(n: number): [$.Slice<fs.DirEntry>, $.GoError] {
150
+ if (this.data !== null) {
151
+ return [null, pathError('readdir', this.name, fs.ErrInvalid)]
152
+ }
153
+ const allEntries = this.entries ?? []
154
+ if (n <= 0) {
155
+ const entries = allEntries.slice(this.dirOffset)
156
+ this.dirOffset = allEntries.length
157
+ return [entries, null]
158
+ }
159
+ if (this.dirOffset >= allEntries.length) {
160
+ return [[], io.EOF]
161
+ }
162
+ const entries = allEntries.slice(this.dirOffset, this.dirOffset + n)
163
+ this.dirOffset += entries.length
164
+ return [entries, null]
165
+ }
166
+
167
+ Stat(): [fs.FileInfo, $.GoError] {
168
+ if (this.data === null) {
169
+ return [new embedFileInfo(baseName(this.name), 0, fs.ModeDir | 0o555), null]
170
+ }
171
+ return [new embedFileInfo(baseName(this.name), this.data.byteLength, 0o444), null]
172
+ }
173
+ }
174
+
175
+ class embedFileInfo {
176
+ constructor(
177
+ private readonly name: string,
178
+ private readonly size: number,
179
+ private readonly mode: fs.FileMode,
180
+ ) {}
181
+
182
+ IsDir(): boolean {
183
+ return fs.FileMode_IsDir(this.mode)
184
+ }
185
+
186
+ ModTime(): time.Time {
187
+ return new time.Time()
188
+ }
189
+
190
+ Mode(): fs.FileMode {
191
+ return this.mode
192
+ }
193
+
194
+ Name(): string {
195
+ return this.name
196
+ }
197
+
198
+ Size(): number {
199
+ return this.size
200
+ }
201
+
202
+ Sys(): null {
203
+ return null
204
+ }
205
+ }
206
+
207
+ class embedDirEntry {
208
+ constructor(private readonly info: fs.FileInfo) {}
209
+
210
+ Info(): [fs.FileInfo, $.GoError] {
211
+ return [this.info, null]
212
+ }
213
+
214
+ IsDir(): boolean {
215
+ return this.info!.IsDir()
216
+ }
217
+
218
+ Name(): string {
219
+ return this.info!.Name()
220
+ }
221
+
222
+ Type(): fs.FileMode {
223
+ return fs.fileModeType(this.info!.Mode())
15
224
  }
16
225
  }
17
226
 
18
- function pathError(op: string, name: string): $.GoError {
19
- return new fs.PathError({ Op: op, Path: name, Err: fs.ErrNotExist })
227
+ function validatePath(op: string, name: string): $.GoError {
228
+ if (!fs.ValidPath(name)) {
229
+ return pathError(op, name, fs.ErrInvalid)
230
+ }
231
+ return null
232
+ }
233
+
234
+ function pathError(op: string, name: string, err: $.GoError): $.GoError {
235
+ return new fs.PathError({ Op: op, Path: name, Err: err })
236
+ }
237
+
238
+ function baseName(name: string): string {
239
+ const idx = name.lastIndexOf('/')
240
+ if (idx === -1) {
241
+ return name
242
+ }
243
+ return name.slice(idx + 1)
20
244
  }