goscript 0.1.3 → 0.1.4

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 (117) hide show
  1. package/cmd/goscript/cmd_compile.go +28 -8
  2. package/cmd/goscript/cmd_compile_test.go +105 -6
  3. package/compiler/build-flags.go +9 -10
  4. package/compiler/gotest/runner_test.go +127 -0
  5. package/compiler/lowering.go +596 -136
  6. package/compiler/lowering_bench_test.go +350 -0
  7. package/compiler/package-graph.go +61 -4
  8. package/compiler/package-graph_test.go +30 -0
  9. package/compiler/semantic-model-types.go +8 -0
  10. package/compiler/semantic-model.go +447 -22
  11. package/compiler/semantic-model_test.go +138 -0
  12. package/compiler/skeleton_test.go +948 -14
  13. package/compiler/typescript-emitter.go +19 -2
  14. package/dist/gs/builtin/builtin.d.ts +2 -2
  15. package/dist/gs/builtin/builtin.js +20 -0
  16. package/dist/gs/builtin/builtin.js.map +1 -1
  17. package/dist/gs/builtin/slice.js +5 -0
  18. package/dist/gs/builtin/slice.js.map +1 -1
  19. package/dist/gs/builtin/type.d.ts +1 -1
  20. package/dist/gs/builtin/type.js +72 -5
  21. package/dist/gs/builtin/type.js.map +1 -1
  22. package/dist/gs/compress/zlib/index.d.ts +3 -3
  23. package/dist/gs/compress/zlib/index.js +88 -26
  24. package/dist/gs/compress/zlib/index.js.map +1 -1
  25. package/dist/gs/crypto/sha1/index.js +2 -5
  26. package/dist/gs/crypto/sha1/index.js.map +1 -1
  27. package/dist/gs/crypto/sha256/index.js +2 -5
  28. package/dist/gs/crypto/sha256/index.js.map +1 -1
  29. package/dist/gs/crypto/sha512/index.js +2 -5
  30. package/dist/gs/crypto/sha512/index.js.map +1 -1
  31. package/dist/gs/embed/index.d.ts +6 -0
  32. package/dist/gs/embed/index.js +210 -5
  33. package/dist/gs/embed/index.js.map +1 -1
  34. package/dist/gs/fmt/fmt.d.ts +3 -3
  35. package/dist/gs/fmt/fmt.js +29 -16
  36. package/dist/gs/fmt/fmt.js.map +1 -1
  37. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +118 -6
  38. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  39. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  40. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  41. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  42. package/dist/gs/io/fs/readdir.js +5 -3
  43. package/dist/gs/io/fs/readdir.js.map +1 -1
  44. package/dist/gs/io/io.d.ts +10 -6
  45. package/dist/gs/io/io.js +87 -42
  46. package/dist/gs/io/io.js.map +1 -1
  47. package/dist/gs/math/bits/index.d.ts +26 -5
  48. package/dist/gs/math/bits/index.js +13 -24
  49. package/dist/gs/math/bits/index.js.map +1 -1
  50. package/dist/gs/net/http/index.d.ts +3 -1
  51. package/dist/gs/net/http/index.js +18 -1
  52. package/dist/gs/net/http/index.js.map +1 -1
  53. package/dist/gs/os/types_js.gs.d.ts +6 -2
  54. package/dist/gs/os/types_js.gs.js +169 -8
  55. package/dist/gs/os/types_js.gs.js.map +1 -1
  56. package/dist/gs/reflect/type.d.ts +1 -0
  57. package/dist/gs/reflect/type.js +80 -51
  58. package/dist/gs/reflect/type.js.map +1 -1
  59. package/dist/gs/strings/reader.d.ts +1 -1
  60. package/dist/gs/strings/reader.js +2 -2
  61. package/dist/gs/strings/reader.js.map +1 -1
  62. package/dist/gs/sync/sync.d.ts +2 -1
  63. package/dist/gs/sync/sync.js +37 -16
  64. package/dist/gs/sync/sync.js.map +1 -1
  65. package/dist/gs/syscall/js/index.js +9 -0
  66. package/dist/gs/syscall/js/index.js.map +1 -1
  67. package/dist/gs/testing/testing.js +8 -6
  68. package/dist/gs/testing/testing.js.map +1 -1
  69. package/gs/builtin/builtin.ts +25 -2
  70. package/gs/builtin/runtime-contract.test.ts +45 -0
  71. package/gs/builtin/slice.ts +7 -0
  72. package/gs/builtin/type.ts +85 -5
  73. package/gs/compress/zlib/index.test.ts +97 -0
  74. package/gs/compress/zlib/index.ts +117 -27
  75. package/gs/compress/zlib/meta.json +4 -1
  76. package/gs/crypto/sha1/index.test.ts +19 -2
  77. package/gs/crypto/sha1/index.ts +3 -6
  78. package/gs/crypto/sha256/index.test.ts +14 -2
  79. package/gs/crypto/sha256/index.ts +3 -6
  80. package/gs/crypto/sha512/index.test.ts +17 -2
  81. package/gs/crypto/sha512/index.ts +3 -6
  82. package/gs/embed/index.test.ts +87 -0
  83. package/gs/embed/index.ts +229 -5
  84. package/gs/fmt/fmt.test.ts +41 -3
  85. package/gs/fmt/fmt.ts +40 -17
  86. package/gs/fmt/meta.json +6 -1
  87. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +8 -1
  88. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +139 -11
  89. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  90. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  91. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  92. package/gs/io/fs/readdir.test.ts +38 -0
  93. package/gs/io/fs/readdir.ts +7 -3
  94. package/gs/io/io.test.ts +77 -6
  95. package/gs/io/io.ts +114 -52
  96. package/gs/io/meta.json +7 -1
  97. package/gs/math/bits/index.ts +52 -28
  98. package/gs/net/http/index.test.ts +16 -0
  99. package/gs/net/http/index.ts +19 -2
  100. package/gs/os/file_unix_js.test.ts +52 -0
  101. package/gs/os/meta.json +4 -0
  102. package/gs/os/readdir.test.ts +56 -0
  103. package/gs/os/types_js.gs.ts +169 -8
  104. package/gs/reflect/deepequal.test.ts +10 -1
  105. package/gs/reflect/type.ts +91 -56
  106. package/gs/reflect/typefor.test.ts +31 -1
  107. package/gs/strings/meta.json +5 -2
  108. package/gs/strings/reader.test.ts +2 -2
  109. package/gs/strings/reader.ts +2 -2
  110. package/gs/sync/meta.json +1 -0
  111. package/gs/sync/sync.test.ts +41 -1
  112. package/gs/sync/sync.ts +41 -16
  113. package/gs/syscall/js/index.test.ts +18 -0
  114. package/gs/syscall/js/index.ts +12 -0
  115. package/gs/testing/testing.test.ts +32 -3
  116. package/gs/testing/testing.ts +13 -10
  117. package/package.json +1 -1
@@ -3,7 +3,11 @@ import * as errors from '@goscript/errors/index.js'
3
3
  import * as io from '@goscript/io/index.js'
4
4
 
5
5
  export type Resetter = {
6
- Reset(r: io.Reader | null, dict: $.Bytes | null): Promise<$.GoError>
6
+ Reset(r: io.Reader | null, dict: $.Bytes | null): $.GoError
7
+ }
8
+
9
+ type maybeAsyncWriter = {
10
+ Write(p: $.Bytes): [number, $.GoError] | Promise<[number, $.GoError]>
7
11
  }
8
12
 
9
13
  export let ErrChecksum = errors.New('zlib: invalid checksum')
@@ -22,12 +26,30 @@ export function __goscript_set_ErrHeader(value: $.GoError): void {
22
26
  ErrHeader = value
23
27
  }
24
28
 
25
- class zlibReader implements io.ReadCloser {
29
+ class zlibReader implements Resetter {
30
+ private data: Uint8Array = new Uint8Array(0)
26
31
  private offset = 0
32
+ private pending:
33
+ | Promise<{ data: Uint8Array | null; err: $.GoError }>
34
+ | null = null
27
35
 
28
- constructor(private data: Uint8Array) {}
36
+ constructor(data?: Uint8Array) {
37
+ if (data != null) {
38
+ this.data = data
39
+ }
40
+ }
29
41
 
30
- Read(p: $.Bytes): [number, $.GoError] {
42
+ async Read(p: $.Bytes): Promise<[number, $.GoError]> {
43
+ const pending = this.pending
44
+ if (pending != null) {
45
+ this.pending = null
46
+ const result = await pending
47
+ if (result.err != null) {
48
+ return [0, result.err]
49
+ }
50
+ this.data = result.data ?? new Uint8Array(0)
51
+ this.offset = 0
52
+ }
31
53
  if (this.offset >= this.data.length) {
32
54
  return [0, io.EOF]
33
55
  }
@@ -41,6 +63,26 @@ class zlibReader implements io.ReadCloser {
41
63
  Close(): $.GoError {
42
64
  return null
43
65
  }
66
+
67
+ Reset(r: io.Reader | null, dict: $.Bytes | null): $.GoError {
68
+ if (r == null) {
69
+ return errors.New('zlib: nil reader')
70
+ }
71
+ const result = readInflated(r, dict)
72
+ if (result instanceof Promise) {
73
+ this.data = new Uint8Array(0)
74
+ this.offset = 0
75
+ this.pending = result
76
+ return null
77
+ }
78
+ if (result.err != null) {
79
+ return result.err
80
+ }
81
+ this.data = result.data ?? new Uint8Array(0)
82
+ this.offset = 0
83
+ this.pending = null
84
+ return null
85
+ }
44
86
  }
45
87
 
46
88
  export class Writer {
@@ -58,7 +100,7 @@ export class Writer {
58
100
  return [data.length, null]
59
101
  }
60
102
 
61
- Close(): $.GoError {
103
+ async Close(): Promise<$.GoError> {
62
104
  if (this.closed) {
63
105
  return null
64
106
  }
@@ -67,7 +109,8 @@ export class Writer {
67
109
  return errors.New('zlib: nil writer')
68
110
  }
69
111
  const compressed = deflate(concat(this.chunks))
70
- const [, err] = this.w.Write(compressed)
112
+ const writer = $.pointerValue<maybeAsyncWriter>(this.w)
113
+ const [, err] = await writer.Write(compressed)
71
114
  return err
72
115
  }
73
116
 
@@ -109,21 +152,14 @@ export function NewReader(
109
152
 
110
153
  export function NewReaderDict(
111
154
  r: io.Reader | null,
112
- _dict: $.Bytes | null,
155
+ dict: $.Bytes | null,
113
156
  ): [io.ReadCloser | null, $.GoError] {
114
- if (r == null) {
115
- return [null, errors.New('zlib: nil reader')]
116
- }
117
- const [data, readErr] = readAll(r)
118
- if (readErr != null) {
119
- return [null, readErr]
120
- }
121
- try {
122
- const out = inflate($.bytesToUint8Array(data))
123
- return [new zlibReader(out), null]
124
- } catch {
125
- return [null, ErrHeader]
157
+ const reader = new zlibReader()
158
+ const err = reader.Reset(r, dict)
159
+ if (err != null) {
160
+ return [null, err]
126
161
  }
162
+ return [reader as any, null]
127
163
  }
128
164
 
129
165
  function deflate(data: Uint8Array): Uint8Array {
@@ -168,20 +204,74 @@ function nodeZlib(): any {
168
204
  throw new Error('compress/zlib: node zlib module unavailable')
169
205
  }
170
206
 
171
- function readAll(r: io.Reader): [Uint8Array, $.GoError] {
172
- const chunks: Uint8Array[] = []
173
- const buf = $.makeSlice<number>(32 * 1024, undefined, 'byte')
207
+ function readInflated(
208
+ r: io.Reader,
209
+ dict: $.Bytes | null,
210
+ ):
211
+ | { data: Uint8Array | null; err: $.GoError }
212
+ | Promise<{ data: Uint8Array | null; err: $.GoError }> {
213
+ const chunks: number[] = []
214
+ const buf = $.makeSlice<number>(1, undefined, 'byte')
215
+ while (true) {
216
+ const read = r.Read(buf)
217
+ if (read instanceof Promise) {
218
+ return readInflatedAsync(read, r, buf, chunks, dict)
219
+ }
220
+ const [n, err] = read
221
+ const result = recordCompressedBytes(chunks, buf, n, dict)
222
+ if (result.err == null && result.data != null) {
223
+ return result
224
+ }
225
+ if (err != null) {
226
+ if (err === io.EOF) {
227
+ return result
228
+ }
229
+ return { data: null, err }
230
+ }
231
+ }
232
+ }
233
+
234
+ async function readInflatedAsync(
235
+ first: Promise<[number, $.GoError]>,
236
+ r: io.Reader,
237
+ buf: $.Bytes,
238
+ chunks: number[],
239
+ dict: $.Bytes | null,
240
+ ): Promise<{ data: Uint8Array | null; err: $.GoError }> {
241
+ let read = await first
174
242
  while (true) {
175
- const [n, err] = r.Read(buf)
176
- if (n > 0) {
177
- chunks.push($.bytesToUint8Array($.goSlice(buf, 0, n)).slice())
243
+ const [n, err] = read
244
+ const result = recordCompressedBytes(chunks, buf, n, dict)
245
+ if (result.err == null && result.data != null) {
246
+ return result
178
247
  }
179
248
  if (err != null) {
180
249
  if (err === io.EOF) {
181
- return [concat(chunks), null]
250
+ return result
182
251
  }
183
- return [new Uint8Array(0), err]
252
+ return { data: null, err }
253
+ }
254
+ read = await r.Read(buf)
255
+ }
256
+ }
257
+
258
+ function recordCompressedBytes(
259
+ chunks: number[],
260
+ buf: $.Bytes,
261
+ n: number,
262
+ dict: $.Bytes | null,
263
+ ): { data: Uint8Array | null; err: $.GoError } {
264
+ if (n > 0) {
265
+ chunks.push(...$.bytesToUint8Array($.goSlice(buf, 0, n)))
266
+ }
267
+ const compressed = new Uint8Array(chunks)
268
+ try {
269
+ return { data: inflate(compressed), err: null }
270
+ } catch {
271
+ if (dict != null && $.len(dict) > 0) {
272
+ return { data: null, err: ErrDictionary }
184
273
  }
274
+ return { data: null, err: ErrHeader }
185
275
  }
186
276
  }
187
277
 
@@ -1,3 +1,6 @@
1
1
  {
2
- "dependencies": []
2
+ "dependencies": [],
3
+ "asyncMethods": {
4
+ "Writer.Close": true
5
+ }
3
6
  }
@@ -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
+ })