goscript 0.2.1 → 0.2.3

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 (164) hide show
  1. package/compiler/gotest/runner.go +98 -0
  2. package/compiler/gotest/runner_test.go +45 -0
  3. package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
  4. package/compiler/lowering.go +227 -11
  5. package/compiler/override-registry_test.go +50 -0
  6. package/compiler/protobuf-ts-binding.go +155 -7
  7. package/compiler/protobuf-ts-binding_test.go +116 -2
  8. package/compiler/runtime-contract.go +2 -0
  9. package/compiler/runtime-contract_test.go +1 -0
  10. package/compiler/semantic-model.go +16 -0
  11. package/compiler/semantic-model_test.go +38 -0
  12. package/compiler/skeleton_test.go +477 -16
  13. package/compiler/typescript-emitter.go +4 -0
  14. package/dist/gs/builtin/builtin.js +7 -9
  15. package/dist/gs/builtin/builtin.js.map +1 -1
  16. package/dist/gs/builtin/defer.js +2 -2
  17. package/dist/gs/builtin/hostio.js +5 -5
  18. package/dist/gs/builtin/hostio.js.map +1 -1
  19. package/dist/gs/builtin/map.js +2 -1
  20. package/dist/gs/builtin/map.js.map +1 -1
  21. package/dist/gs/builtin/slice.d.ts +3 -0
  22. package/dist/gs/builtin/slice.js +39 -0
  23. package/dist/gs/builtin/slice.js.map +1 -1
  24. package/dist/gs/builtin/type.js +49 -0
  25. package/dist/gs/builtin/type.js.map +1 -1
  26. package/dist/gs/compress/zlib/index.js +5 -2
  27. package/dist/gs/compress/zlib/index.js.map +1 -1
  28. package/dist/gs/crypto/aes/index.d.ts +15 -0
  29. package/dist/gs/crypto/aes/index.js +57 -0
  30. package/dist/gs/crypto/aes/index.js.map +1 -0
  31. package/dist/gs/crypto/cipher/index.d.ts +41 -0
  32. package/dist/gs/crypto/cipher/index.js +255 -0
  33. package/dist/gs/crypto/cipher/index.js.map +1 -0
  34. package/dist/gs/crypto/ecdh/index.js +27 -8
  35. package/dist/gs/crypto/ecdh/index.js.map +1 -1
  36. package/dist/gs/crypto/ed25519/index.js +3 -3
  37. package/dist/gs/crypto/ed25519/index.js.map +1 -1
  38. package/dist/gs/crypto/rand/index.js +6 -3
  39. package/dist/gs/crypto/rand/index.js.map +1 -1
  40. package/dist/gs/embed/index.js +9 -3
  41. package/dist/gs/embed/index.js.map +1 -1
  42. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
  43. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
  44. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  45. package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
  46. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
  47. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.d.ts +31 -0
  48. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
  49. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
  50. package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
  51. package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
  52. package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
  53. package/dist/gs/hash/fnv/index.js +13 -5
  54. package/dist/gs/hash/fnv/index.js.map +1 -1
  55. package/dist/gs/io/fs/glob.d.ts +3 -3
  56. package/dist/gs/io/fs/glob.js +8 -8
  57. package/dist/gs/io/fs/glob.js.map +1 -1
  58. package/dist/gs/io/fs/readdir.d.ts +2 -2
  59. package/dist/gs/io/fs/readdir.js +13 -74
  60. package/dist/gs/io/fs/readdir.js.map +1 -1
  61. package/dist/gs/io/fs/sub.js +4 -4
  62. package/dist/gs/io/fs/sub.js.map +1 -1
  63. package/dist/gs/io/fs/walk.js +1 -1
  64. package/dist/gs/io/fs/walk.js.map +1 -1
  65. package/dist/gs/io/io.js +18 -2
  66. package/dist/gs/io/io.js.map +1 -1
  67. package/dist/gs/maps/iter.js.map +1 -1
  68. package/dist/gs/maps/maps.js.map +1 -1
  69. package/dist/gs/mime/index.js +5 -2
  70. package/dist/gs/mime/index.js.map +1 -1
  71. package/dist/gs/net/http/httptest/index.js +6 -3
  72. package/dist/gs/net/http/httptest/index.js.map +1 -1
  73. package/dist/gs/net/http/index.d.ts +16 -4
  74. package/dist/gs/net/http/index.js +236 -40
  75. package/dist/gs/net/http/index.js.map +1 -1
  76. package/dist/gs/net/http/pprof/index.js.map +1 -1
  77. package/dist/gs/reflect/iter.js +1 -1
  78. package/dist/gs/reflect/iter.js.map +1 -1
  79. package/dist/gs/reflect/type.d.ts +2 -0
  80. package/dist/gs/reflect/type.js +53 -21
  81. package/dist/gs/reflect/type.js.map +1 -1
  82. package/dist/gs/runtime/debug/index.js +2 -1
  83. package/dist/gs/runtime/debug/index.js.map +1 -1
  84. package/dist/gs/runtime/pprof/index.js.map +1 -1
  85. package/dist/gs/runtime/runtime.js +2 -2
  86. package/dist/gs/runtime/runtime.js.map +1 -1
  87. package/dist/gs/runtime/trace/index.js.map +1 -1
  88. package/dist/gs/slices/slices.d.ts +1 -1
  89. package/dist/gs/slices/slices.js +37 -4
  90. package/dist/gs/slices/slices.js.map +1 -1
  91. package/go.mod +2 -2
  92. package/go.sum +2 -0
  93. package/gs/builtin/builtin.ts +11 -14
  94. package/gs/builtin/defer.ts +2 -2
  95. package/gs/builtin/hostio.test.ts +8 -3
  96. package/gs/builtin/hostio.ts +5 -7
  97. package/gs/builtin/map.ts +4 -1
  98. package/gs/builtin/slice.test.ts +14 -0
  99. package/gs/builtin/slice.ts +64 -0
  100. package/gs/builtin/type.ts +72 -0
  101. package/gs/bytes/bytes.test.ts +14 -13
  102. package/gs/compress/zlib/index.test.ts +19 -5
  103. package/gs/compress/zlib/index.ts +16 -7
  104. package/gs/context/context.test.ts +3 -1
  105. package/gs/crypto/aes/index.test.ts +120 -0
  106. package/gs/crypto/aes/index.ts +76 -0
  107. package/gs/crypto/cipher/index.ts +345 -0
  108. package/gs/crypto/cipher/meta.json +6 -0
  109. package/gs/crypto/ecdh/index.test.ts +6 -2
  110. package/gs/crypto/ecdh/index.ts +49 -12
  111. package/gs/crypto/ed25519/index.ts +20 -7
  112. package/gs/crypto/rand/index.ts +6 -3
  113. package/gs/embed/index.test.ts +3 -3
  114. package/gs/embed/index.ts +9 -3
  115. package/gs/fmt/fmt.test.ts +29 -4
  116. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
  117. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
  118. package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
  119. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
  120. package/gs/golang.org/x/crypto/chacha20poly1305/index.test.ts +91 -0
  121. package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
  122. package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
  123. package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
  124. package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
  125. package/gs/hash/fnv/index.test.ts +1 -8
  126. package/gs/hash/fnv/index.ts +27 -10
  127. package/gs/io/fs/glob.ts +13 -10
  128. package/gs/io/fs/meta.json +2 -0
  129. package/gs/io/fs/readdir.test.ts +63 -2
  130. package/gs/io/fs/readdir.ts +33 -30
  131. package/gs/io/fs/sub.ts +4 -4
  132. package/gs/io/fs/walk.ts +1 -1
  133. package/gs/io/io.test.ts +56 -1
  134. package/gs/io/io.ts +19 -2
  135. package/gs/maps/iter.ts +9 -9
  136. package/gs/maps/maps.ts +4 -4
  137. package/gs/math/bits/index.test.ts +10 -1
  138. package/gs/mime/index.test.ts +33 -15
  139. package/gs/mime/index.ts +9 -2
  140. package/gs/net/http/httptest/index.test.ts +17 -3
  141. package/gs/net/http/httptest/index.ts +8 -3
  142. package/gs/net/http/index.test.ts +645 -123
  143. package/gs/net/http/index.ts +548 -113
  144. package/gs/net/http/pprof/index.ts +24 -6
  145. package/gs/os/file_unix_js.test.ts +22 -0
  146. package/gs/reflect/iter.ts +4 -2
  147. package/gs/reflect/map.test.ts +56 -1
  148. package/gs/reflect/type.ts +76 -37
  149. package/gs/runtime/debug/index.test.ts +32 -4
  150. package/gs/runtime/debug/index.ts +5 -2
  151. package/gs/runtime/pprof/index.test.ts +7 -1
  152. package/gs/runtime/pprof/index.ts +5 -1
  153. package/gs/runtime/runtime.test.ts +7 -0
  154. package/gs/runtime/runtime.ts +2 -4
  155. package/gs/runtime/trace/index.test.ts +9 -1
  156. package/gs/runtime/trace/index.ts +5 -1
  157. package/gs/slices/meta.json +3 -0
  158. package/gs/slices/slices.test.ts +59 -21
  159. package/gs/slices/slices.ts +61 -20
  160. package/gs/strconv/complex.test.ts +17 -3
  161. package/gs/sync/atomic/doc_64.test.ts +2 -9
  162. package/gs/sync/sync.test.ts +18 -8
  163. package/gs/syscall/js/index.test.ts +9 -4
  164. package/package.json +13 -5
@@ -0,0 +1,245 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import * as errors from '@goscript/errors/index.js'
3
+ import {
4
+ chacha20poly1305 as nobleChaCha20Poly1305,
5
+ xchacha20poly1305 as nobleXChaCha20Poly1305,
6
+ } from '@noble/ciphers/chacha.js'
7
+
8
+ export const KeySize = 32
9
+ export const NonceSize = 12
10
+ export const NonceSizeX = 24
11
+ export const Overhead = 16
12
+
13
+ const maxIETFPlaintext = 2 ** 38 - 64
14
+ const maxIETFCiphertext = 2 ** 38 - 48
15
+
16
+ type NobleAEAD = typeof nobleChaCha20Poly1305 | typeof nobleXChaCha20Poly1305
17
+
18
+ export let errOpen: $.GoError = errors.New(
19
+ 'chacha20poly1305: message authentication failed',
20
+ )
21
+
22
+ export function __goscript_set_errOpen(value: $.GoError): void {
23
+ errOpen = value
24
+ }
25
+
26
+ export interface AEAD {
27
+ NonceSize(): number
28
+ Overhead(): number
29
+ Seal(
30
+ dst: $.Slice<number>,
31
+ nonce: $.Slice<number>,
32
+ plaintext: $.Slice<number>,
33
+ additionalData: $.Slice<number>,
34
+ ): $.Slice<number>
35
+ Open(
36
+ dst: $.Slice<number>,
37
+ nonce: $.Slice<number>,
38
+ ciphertext: $.Slice<number>,
39
+ additionalData: $.Slice<number>,
40
+ ): [$.Slice<number>, $.GoError]
41
+ }
42
+
43
+ export class chacha20poly1305 implements AEAD {
44
+ readonly key: Uint8Array
45
+
46
+ constructor(key: Uint8Array) {
47
+ this.key = key.slice()
48
+ }
49
+
50
+ NonceSize(): number {
51
+ return NonceSize
52
+ }
53
+
54
+ Overhead(): number {
55
+ return Overhead
56
+ }
57
+
58
+ Seal(
59
+ dst: $.Slice<number>,
60
+ nonce: $.Slice<number>,
61
+ plaintext: $.Slice<number>,
62
+ additionalData: $.Slice<number>,
63
+ ): $.Slice<number> {
64
+ return seal(
65
+ dst,
66
+ nobleChaCha20Poly1305,
67
+ this.key,
68
+ nonce,
69
+ NonceSize,
70
+ plaintext,
71
+ additionalData,
72
+ )
73
+ }
74
+
75
+ Open(
76
+ dst: $.Slice<number>,
77
+ nonce: $.Slice<number>,
78
+ ciphertext: $.Slice<number>,
79
+ additionalData: $.Slice<number>,
80
+ ): [$.Slice<number>, $.GoError] {
81
+ return open(
82
+ dst,
83
+ nobleChaCha20Poly1305,
84
+ this.key,
85
+ nonce,
86
+ NonceSize,
87
+ ciphertext,
88
+ additionalData,
89
+ )
90
+ }
91
+ }
92
+
93
+ export class xchacha20poly1305 implements AEAD {
94
+ readonly key: Uint8Array
95
+
96
+ constructor(key: Uint8Array) {
97
+ this.key = key.slice()
98
+ }
99
+
100
+ NonceSize(): number {
101
+ return NonceSizeX
102
+ }
103
+
104
+ Overhead(): number {
105
+ return Overhead
106
+ }
107
+
108
+ Seal(
109
+ dst: $.Slice<number>,
110
+ nonce: $.Slice<number>,
111
+ plaintext: $.Slice<number>,
112
+ additionalData: $.Slice<number>,
113
+ ): $.Slice<number> {
114
+ return seal(
115
+ dst,
116
+ nobleXChaCha20Poly1305,
117
+ this.key,
118
+ nonce,
119
+ NonceSizeX,
120
+ plaintext,
121
+ additionalData,
122
+ )
123
+ }
124
+
125
+ Open(
126
+ dst: $.Slice<number>,
127
+ nonce: $.Slice<number>,
128
+ ciphertext: $.Slice<number>,
129
+ additionalData: $.Slice<number>,
130
+ ): [$.Slice<number>, $.GoError] {
131
+ return open(
132
+ dst,
133
+ nobleXChaCha20Poly1305,
134
+ this.key,
135
+ nonce,
136
+ NonceSizeX,
137
+ ciphertext,
138
+ additionalData,
139
+ )
140
+ }
141
+ }
142
+
143
+ export function New(key: $.Slice<number>): [AEAD | null, $.GoError] {
144
+ const keyBytes = bytes(key)
145
+ if (keyBytes.length !== KeySize) {
146
+ return [null, errors.New('chacha20poly1305: bad key length')]
147
+ }
148
+ return [
149
+ $.interfaceValue<AEAD | null>(
150
+ new chacha20poly1305(keyBytes),
151
+ '*chacha20poly1305.chacha20poly1305',
152
+ ),
153
+ null,
154
+ ]
155
+ }
156
+
157
+ export function NewX(key: $.Slice<number>): [AEAD | null, $.GoError] {
158
+ const keyBytes = bytes(key)
159
+ if (keyBytes.length !== KeySize) {
160
+ return [null, errors.New('chacha20poly1305: bad key length')]
161
+ }
162
+ return [
163
+ $.interfaceValue<AEAD | null>(
164
+ new xchacha20poly1305(keyBytes),
165
+ '*chacha20poly1305.xchacha20poly1305',
166
+ ),
167
+ null,
168
+ ]
169
+ }
170
+
171
+ function seal(
172
+ dst: $.Slice<number>,
173
+ cipher: NobleAEAD,
174
+ key: Uint8Array,
175
+ nonce: $.Slice<number>,
176
+ expectedNonceSize: number,
177
+ plaintext: $.Slice<number>,
178
+ additionalData: $.Slice<number>,
179
+ ): $.Slice<number> {
180
+ const nonceBytes = bytes(nonce)
181
+ if (nonceBytes.length !== expectedNonceSize) {
182
+ $.panic('chacha20poly1305: bad nonce length passed to Seal')
183
+ }
184
+ const plaintextBytes = bytes(plaintext)
185
+ if (plaintextBytes.length > maxIETFPlaintext) {
186
+ $.panic('chacha20poly1305: plaintext too large')
187
+ }
188
+
189
+ const sealed = cipher(key, nonceBytes, bytes(additionalData)).encrypt(
190
+ plaintextBytes,
191
+ )
192
+ return appendBytes(dst, sealed)
193
+ }
194
+
195
+ function open(
196
+ dst: $.Slice<number>,
197
+ cipher: NobleAEAD,
198
+ key: Uint8Array,
199
+ nonce: $.Slice<number>,
200
+ expectedNonceSize: number,
201
+ ciphertext: $.Slice<number>,
202
+ additionalData: $.Slice<number>,
203
+ ): [$.Slice<number>, $.GoError] {
204
+ const nonceBytes = bytes(nonce)
205
+ if (nonceBytes.length !== expectedNonceSize) {
206
+ $.panic('chacha20poly1305: bad nonce length passed to Open')
207
+ }
208
+ const ciphertextBytes = bytes(ciphertext)
209
+ if (ciphertextBytes.length < Overhead) {
210
+ return [null, errOpen]
211
+ }
212
+ if (ciphertextBytes.length > maxIETFCiphertext) {
213
+ $.panic('chacha20poly1305: ciphertext too large')
214
+ }
215
+
216
+ try {
217
+ return [
218
+ appendBytes(
219
+ dst,
220
+ cipher(key, nonceBytes, bytes(additionalData)).decrypt(ciphertextBytes),
221
+ ),
222
+ null,
223
+ ]
224
+ } catch {
225
+ return [null, errOpen]
226
+ }
227
+ }
228
+
229
+ function bytes(value: $.Slice<number>): Uint8Array {
230
+ return $.bytesToUint8Array(value).slice()
231
+ }
232
+
233
+ function appendBytes(
234
+ dst: $.Slice<number>,
235
+ suffix: Uint8Array,
236
+ ): $.Slice<number> {
237
+ const prefix = $.bytesToUint8Array(dst)
238
+ if (prefix.length === 0) {
239
+ return suffix.slice()
240
+ }
241
+ const out = new Uint8Array(prefix.length + suffix.length)
242
+ out.set(prefix)
243
+ out.set(suffix, prefix.length)
244
+ return out
245
+ }
@@ -0,0 +1,81 @@
1
+ import { describe, expect, test } from 'vitest'
2
+ import * as $ from '@goscript/builtin/index.js'
3
+
4
+ import { Key } from './index.js'
5
+
6
+ describe('scrypt override', () => {
7
+ test('matches Go scrypt vectors', async () => {
8
+ const vectors = [
9
+ {
10
+ password: 'password',
11
+ salt: 'salt',
12
+ N: 2,
13
+ r: 10,
14
+ p: 10,
15
+ output:
16
+ '482c858e229055e62f41e0ec819a5ee18bdb87251a534f75acd95ac5e50aa15f',
17
+ },
18
+ {
19
+ password: 'p',
20
+ salt: 's',
21
+ N: 2,
22
+ r: 1,
23
+ p: 1,
24
+ output: '48b0d2a8a3272611984c50ebd630af52',
25
+ },
26
+ {
27
+ password: '',
28
+ salt: '',
29
+ N: 16,
30
+ r: 1,
31
+ p: 1,
32
+ output:
33
+ '77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906',
34
+ },
35
+ ]
36
+
37
+ for (const vector of vectors) {
38
+ const [key, err] = await Key(
39
+ $.stringToBytes(vector.password),
40
+ $.stringToBytes(vector.salt),
41
+ vector.N,
42
+ vector.r,
43
+ vector.p,
44
+ vector.output.length / 2,
45
+ )
46
+ expect(err).toBeNull()
47
+ expect(toHex(key)).toBe(vector.output)
48
+ }
49
+ })
50
+
51
+ test('validates invalid parameters like Go', async () => {
52
+ const invalid = [
53
+ [0, 1, 1, 'scrypt: N must be > 1 and a power of 2'],
54
+ [1, 1, 1, 'scrypt: N must be > 1 and a power of 2'],
55
+ [7, 8, 1, 'scrypt: N must be > 1 and a power of 2'],
56
+ [2, 0, 1, 'scrypt: parameters must be > 0'],
57
+ [2, 1, 0, 'scrypt: parameters must be > 0'],
58
+ [2, -1, 1, 'scrypt: parameters must be > 0'],
59
+ [2, 1, -1, 'scrypt: parameters must be > 0'],
60
+ ] as const
61
+
62
+ for (const [N, r, p, message] of invalid) {
63
+ const [key, err] = await Key(
64
+ $.stringToBytes('p'),
65
+ $.stringToBytes('s'),
66
+ N,
67
+ r,
68
+ p,
69
+ 32,
70
+ )
71
+ expect(key).toBeNull()
72
+ expect(err?.Error()).toBe(message)
73
+ }
74
+ })
75
+ })
76
+
77
+ function toHex(input: Uint8Array | number[] | null): string {
78
+ return Array.from(input ?? [])
79
+ .map((value) => value.toString(16).padStart(2, '0'))
80
+ .join('')
81
+ }
@@ -0,0 +1,54 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import * as errors from '@goscript/errors/index.js'
3
+ import { scryptAsync } from '@noble/hashes/scrypt.js'
4
+
5
+ const maxInt = Number.MAX_SAFE_INTEGER
6
+
7
+ export async function Key(
8
+ password: $.Bytes,
9
+ salt: $.Bytes,
10
+ N: number,
11
+ r: number,
12
+ p: number,
13
+ keyLen: number,
14
+ ): Promise<[$.Bytes, $.GoError]> {
15
+ if (N <= 1 || (N & (N - 1)) !== 0) {
16
+ return [null, errors.New('scrypt: N must be > 1 and a power of 2')]
17
+ }
18
+ if (r <= 0 || p <= 0) {
19
+ return [null, errors.New('scrypt: parameters must be > 0')]
20
+ }
21
+ if (
22
+ r * p >= 1 << 30 ||
23
+ r > maxInt / 128 / p ||
24
+ r > maxInt / 256 ||
25
+ N > maxInt / 128 / r
26
+ ) {
27
+ return [null, errors.New('scrypt: parameters are too large')]
28
+ }
29
+
30
+ try {
31
+ const derived = await scryptAsync(
32
+ $.bytesToUint8Array(password),
33
+ $.bytesToUint8Array(salt),
34
+ {
35
+ N,
36
+ r,
37
+ p,
38
+ dkLen: keyLen,
39
+ asyncTick: 8,
40
+ maxmem: maxInt,
41
+ },
42
+ )
43
+ return [new Uint8Array(derived), null]
44
+ } catch (err) {
45
+ return [null, errors.New(`scrypt: ${errorMessage(err)}`)]
46
+ }
47
+ }
48
+
49
+ function errorMessage(err: unknown): string {
50
+ if (err instanceof Error) {
51
+ return err.message
52
+ }
53
+ return String(err)
54
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "asyncFunctions": {
3
+ "Key": true
4
+ }
5
+ }
@@ -1,14 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
3
  import * as $ from '../../builtin/index.js'
4
- import {
5
- New128,
6
- New128a,
7
- New32,
8
- New32a,
9
- New64,
10
- New64a,
11
- } from './index.js'
4
+ import { New128, New128a, New32, New32a, New64, New64a } from './index.js'
12
5
 
13
6
  describe('hash/fnv override', () => {
14
7
  it('matches Go FNV sums for hello', async () => {
@@ -65,7 +65,10 @@ class FNV32 {
65
65
  }
66
66
 
67
67
  AppendBinary(prefix: $.Bytes | null): [$.Bytes, $.GoError] {
68
- return [appendBytes($.bytesToUint8Array(prefix), this.magic, be32(this.hash)), null]
68
+ return [
69
+ appendBytes($.bytesToUint8Array(prefix), this.magic, be32(this.hash)),
70
+ null,
71
+ ]
69
72
  }
70
73
 
71
74
  MarshalBinary(): [$.Bytes, $.GoError] {
@@ -136,7 +139,10 @@ class FNV64 {
136
139
  }
137
140
 
138
141
  AppendBinary(prefix: $.Bytes | null): [$.Bytes, $.GoError] {
139
- return [appendBytes($.bytesToUint8Array(prefix), this.magic, be64(this.hash)), null]
142
+ return [
143
+ appendBytes($.bytesToUint8Array(prefix), this.magic, be64(this.hash)),
144
+ null,
145
+ ]
140
146
  }
141
147
 
142
148
  MarshalBinary(): [$.Bytes, $.GoError] {
@@ -185,7 +191,11 @@ class FNV128 {
185
191
  }
186
192
 
187
193
  async Sum(prefix: $.Bytes | null): Promise<$.Bytes> {
188
- return appendBytes($.bytesToUint8Array(prefix), be64(this.high()), be64(this.low()))
194
+ return appendBytes(
195
+ $.bytesToUint8Array(prefix),
196
+ be64(this.high()),
197
+ be64(this.low()),
198
+ )
189
199
  }
190
200
 
191
201
  Reset(): void {
@@ -202,7 +212,12 @@ class FNV128 {
202
212
 
203
213
  AppendBinary(prefix: $.Bytes | null): [$.Bytes, $.GoError] {
204
214
  return [
205
- appendBytes($.bytesToUint8Array(prefix), this.magic, be64(this.high()), be64(this.low())),
215
+ appendBytes(
216
+ $.bytesToUint8Array(prefix),
217
+ this.magic,
218
+ be64(this.high()),
219
+ be64(this.low()),
220
+ ),
206
221
  null,
207
222
  ]
208
223
  }
@@ -217,7 +232,8 @@ class FNV128 {
217
232
  if (err != null) {
218
233
  return err
219
234
  }
220
- this.hash = ((readBE64(state, 4) << 64n) | readBE64(state, 12)) & uint128Mask
235
+ this.hash =
236
+ ((readBE64(state, 4) << 64n) | readBE64(state, 12)) & uint128Mask
221
237
  return null
222
238
  }
223
239
 
@@ -304,11 +320,12 @@ function be64(value: bigint): Uint8Array {
304
320
 
305
321
  function readBE32(bytes: Uint8Array, offset: number): number {
306
322
  return (
307
- ((bytes[offset] << 24) >>> 0) |
308
- (bytes[offset + 1] << 16) |
309
- (bytes[offset + 2] << 8) |
310
- bytes[offset + 3]
311
- ) >>> 0
323
+ (((bytes[offset] << 24) >>> 0) |
324
+ (bytes[offset + 1] << 16) |
325
+ (bytes[offset + 2] << 8) |
326
+ bytes[offset + 3]) >>>
327
+ 0
328
+ )
312
329
  }
313
330
 
314
331
  function readBE64(bytes: Uint8Array, offset: number): bigint {
package/gs/io/fs/glob.ts CHANGED
@@ -60,15 +60,18 @@ $.registerInterfaceType(
60
60
  // If fs implements [GlobFS], Glob calls fs.Glob.
61
61
  // Otherwise, Glob uses [ReadDir] to traverse the directory tree
62
62
  // and look for matches for the pattern.
63
- export function Glob(fsys: FS, pattern: string): [$.Slice<string>, $.GoError] {
64
- return globWithLimit(fsys, pattern, 0)
63
+ export async function Glob(
64
+ fsys: FS,
65
+ pattern: string,
66
+ ): Promise<[$.Slice<string>, $.GoError]> {
67
+ return await globWithLimit(fsys, pattern, 0)
65
68
  }
66
69
 
67
- export function globWithLimit(
70
+ export async function globWithLimit(
68
71
  fsys: FS,
69
72
  pattern: string,
70
73
  depth: number,
71
- ): [$.Slice<string>, $.GoError] {
74
+ ): Promise<[$.Slice<string>, $.GoError]> {
72
75
  let matches: $.Slice<string> = null
73
76
  {
74
77
  // This limit is added to prevent stack exhaustion issues. See
@@ -105,7 +108,7 @@ export function globWithLimit(
105
108
  dir = cleanGlobPath(dir)
106
109
 
107
110
  if (!hasMeta(dir)) {
108
- return glob(fsys, dir, file, null)
111
+ return await glob(fsys, dir, file, null)
109
112
  }
110
113
 
111
114
  // Prevent infinite recursion. See issue 15879.
@@ -113,14 +116,14 @@ export function globWithLimit(
113
116
  return [null, path.ErrBadPattern]
114
117
  }
115
118
 
116
- const [dirs, dirErr] = globWithLimit(fsys, dir, depth + 1)
119
+ const [dirs, dirErr] = await globWithLimit(fsys, dir, depth + 1)
117
120
  if (dirErr != null) {
118
121
  return [null, dirErr]
119
122
  }
120
123
  for (let _i = 0; _i < $.len(dirs); _i++) {
121
124
  const d = dirs![_i]
122
125
  {
123
- const [nextMatches, globErr] = glob(fsys, d, file, matches)
126
+ const [nextMatches, globErr] = await glob(fsys, d, file, matches)
124
127
  matches = nextMatches
125
128
  if (globErr != null) {
126
129
  return [matches, globErr]
@@ -148,15 +151,15 @@ export function cleanGlobPath(path: string): string {
148
151
  // and appends them to matches, returning the updated slice.
149
152
  // If the directory cannot be opened, glob returns the existing matches.
150
153
  // New matches are added in lexicographical order.
151
- export function glob(
154
+ export async function glob(
152
155
  fs: FS,
153
156
  dir: string,
154
157
  pattern: string,
155
158
  matches: $.Slice<string>,
156
- ): [$.Slice<string>, $.GoError] {
159
+ ): Promise<[$.Slice<string>, $.GoError]> {
157
160
  let m = matches
158
161
  {
159
- let [infos, err] = ReadDir(fs, dir)
162
+ let [infos, err] = await ReadDir(fs, dir)
160
163
 
161
164
  // ignore I/O error
162
165
  if (err != null) {
@@ -1,5 +1,7 @@
1
1
  {
2
2
  "asyncFunctions": {
3
+ "Glob": true,
4
+ "ReadDir": true,
3
5
  "WalkDir": true
4
6
  }
5
7
  }
@@ -4,7 +4,7 @@ import * as $ from '@goscript/builtin/index.js'
4
4
  import { File, FileInfo, ReadDir } from './index.js'
5
5
 
6
6
  describe('io/fs ReadDir override', () => {
7
- it('returns a nil entry slice without sorting when directory read fails', () => {
7
+ it('returns a nil entry slice without sorting when directory read fails', async () => {
8
8
  const readErr = $.newError('read failed')
9
9
  const file: File & {
10
10
  ReadDir(n: number): [null, $.GoError]
@@ -23,7 +23,7 @@ describe('io/fs ReadDir override', () => {
23
23
  },
24
24
  }
25
25
 
26
- const [list, err] = ReadDir(
26
+ const [list, err] = await ReadDir(
27
27
  {
28
28
  Open(_name: string): [File, $.GoError] {
29
29
  return [file, null]
@@ -35,4 +35,65 @@ describe('io/fs ReadDir override', () => {
35
35
  expect(list).toBeNull()
36
36
  expect(err).toBe(readErr)
37
37
  })
38
+
39
+ it('awaits async FS.Open fallback implementations', async () => {
40
+ const entries = [
41
+ {
42
+ Name(): string {
43
+ return 'b.txt'
44
+ },
45
+ IsDir(): boolean {
46
+ return false
47
+ },
48
+ Info(): [FileInfo, $.GoError] {
49
+ return [null, null]
50
+ },
51
+ Type(): number {
52
+ return 0
53
+ },
54
+ },
55
+ {
56
+ Name(): string {
57
+ return 'a.txt'
58
+ },
59
+ IsDir(): boolean {
60
+ return false
61
+ },
62
+ Info(): [FileInfo, $.GoError] {
63
+ return [null, null]
64
+ },
65
+ Type(): number {
66
+ return 0
67
+ },
68
+ },
69
+ ]
70
+ const file: File & {
71
+ ReadDir(n: number): Promise<[$.Slice<any>, $.GoError]>
72
+ } = {
73
+ Close(): $.GoError {
74
+ return null
75
+ },
76
+ Read(_p0: Uint8Array): [number, $.GoError] {
77
+ return [0, null]
78
+ },
79
+ Stat(): [FileInfo, $.GoError] {
80
+ return [null, null]
81
+ },
82
+ async ReadDir(_n: number): Promise<[$.Slice<any>, $.GoError]> {
83
+ return [$.arrayToSlice(entries), null]
84
+ },
85
+ }
86
+
87
+ const [list, err] = await ReadDir(
88
+ {
89
+ async Open(_name: string): Promise<[File, $.GoError]> {
90
+ return [file, null]
91
+ },
92
+ },
93
+ 'dir',
94
+ )
95
+
96
+ expect(err).toBeNull()
97
+ expect(list?.map((entry) => entry?.Name())).toEqual(['a.txt', 'b.txt'])
98
+ })
38
99
  })