goscript 0.2.2 → 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.
- package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
- package/compiler/lowering.go +223 -9
- package/compiler/override-registry_test.go +50 -0
- package/compiler/protobuf-ts-binding.go +154 -6
- package/compiler/protobuf-ts-binding_test.go +7 -2
- package/compiler/runtime-contract.go +2 -0
- package/compiler/runtime-contract_test.go +1 -0
- package/compiler/semantic-model.go +16 -0
- package/compiler/semantic-model_test.go +38 -0
- package/compiler/skeleton_test.go +473 -15
- package/compiler/typescript-emitter.go +4 -0
- package/dist/gs/builtin/builtin.js +7 -9
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/defer.js +2 -2
- package/dist/gs/builtin/hostio.js +5 -5
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/map.js +2 -1
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +3 -0
- package/dist/gs/builtin/slice.js +39 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +49 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/compress/zlib/index.js +5 -2
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/ecdh/index.js +27 -8
- package/dist/gs/crypto/ecdh/index.js.map +1 -1
- package/dist/gs/crypto/ed25519/index.js +3 -3
- package/dist/gs/crypto/ed25519/index.js.map +1 -1
- package/dist/gs/crypto/rand/index.js +6 -3
- package/dist/gs/crypto/rand/index.js.map +1 -1
- package/dist/gs/embed/index.js +9 -3
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
- package/dist/gs/hash/fnv/index.js +13 -5
- package/dist/gs/hash/fnv/index.js.map +1 -1
- package/dist/gs/io/fs/glob.d.ts +3 -3
- package/dist/gs/io/fs/glob.js +8 -8
- package/dist/gs/io/fs/glob.js.map +1 -1
- package/dist/gs/io/fs/readdir.d.ts +2 -2
- package/dist/gs/io/fs/readdir.js +13 -74
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/sub.js +4 -4
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.js +1 -1
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.js.map +1 -1
- package/dist/gs/mime/index.js +5 -2
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.js +6 -3
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +16 -4
- package/dist/gs/net/http/index.js +236 -40
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.js.map +1 -1
- package/dist/gs/reflect/iter.js +1 -1
- package/dist/gs/reflect/iter.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -0
- package/dist/gs/reflect/type.js +53 -21
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/runtime/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.js +2 -2
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +1 -1
- package/dist/gs/slices/slices.js +37 -4
- package/dist/gs/slices/slices.js.map +1 -1
- package/gs/builtin/builtin.ts +11 -14
- package/gs/builtin/defer.ts +2 -2
- package/gs/builtin/hostio.ts +5 -5
- package/gs/builtin/map.ts +4 -1
- package/gs/builtin/slice.test.ts +14 -0
- package/gs/builtin/slice.ts +64 -0
- package/gs/builtin/type.ts +72 -0
- package/gs/bytes/bytes.test.ts +14 -13
- package/gs/compress/zlib/index.test.ts +19 -5
- package/gs/compress/zlib/index.ts +16 -7
- package/gs/context/context.test.ts +3 -1
- package/gs/crypto/ecdh/index.test.ts +6 -2
- package/gs/crypto/ecdh/index.ts +49 -12
- package/gs/crypto/ed25519/index.ts +20 -7
- package/gs/crypto/rand/index.ts +6 -3
- package/gs/embed/index.test.ts +3 -3
- package/gs/embed/index.ts +9 -3
- package/gs/fmt/fmt.test.ts +29 -4
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
- package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
- package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
- package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
- package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
- package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
- package/gs/hash/fnv/index.test.ts +1 -8
- package/gs/hash/fnv/index.ts +27 -10
- package/gs/io/fs/glob.ts +13 -10
- package/gs/io/fs/meta.json +2 -0
- package/gs/io/fs/readdir.test.ts +63 -2
- package/gs/io/fs/readdir.ts +33 -30
- package/gs/io/fs/sub.ts +4 -4
- package/gs/io/fs/walk.ts +1 -1
- package/gs/maps/iter.ts +9 -9
- package/gs/maps/maps.ts +4 -4
- package/gs/math/bits/index.test.ts +10 -1
- package/gs/mime/index.test.ts +33 -15
- package/gs/mime/index.ts +9 -2
- package/gs/net/http/httptest/index.test.ts +17 -3
- package/gs/net/http/httptest/index.ts +8 -3
- package/gs/net/http/index.test.ts +645 -123
- package/gs/net/http/index.ts +548 -113
- package/gs/net/http/pprof/index.ts +24 -6
- package/gs/os/file_unix_js.test.ts +22 -0
- package/gs/reflect/iter.ts +4 -2
- package/gs/reflect/map.test.ts +56 -1
- package/gs/reflect/type.ts +76 -37
- package/gs/runtime/pprof/index.test.ts +7 -1
- package/gs/runtime/pprof/index.ts +5 -1
- package/gs/runtime/runtime.test.ts +7 -0
- package/gs/runtime/runtime.ts +2 -4
- package/gs/runtime/trace/index.test.ts +9 -1
- package/gs/runtime/trace/index.ts +5 -1
- package/gs/slices/meta.json +3 -0
- package/gs/slices/slices.test.ts +59 -21
- package/gs/slices/slices.ts +61 -20
- package/gs/strconv/complex.test.ts +17 -3
- package/gs/sync/atomic/doc_64.test.ts +2 -9
- package/gs/sync/sync.test.ts +18 -8
- package/gs/syscall/js/index.test.ts +9 -4
- package/package.json +5 -4
|
@@ -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
|
+
}
|
|
@@ -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 () => {
|
package/gs/hash/fnv/index.ts
CHANGED
|
@@ -65,7 +65,10 @@ class FNV32 {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
AppendBinary(prefix: $.Bytes | null): [$.Bytes, $.GoError] {
|
|
68
|
-
return [
|
|
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 [
|
|
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(
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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(
|
|
64
|
-
|
|
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) {
|
package/gs/io/fs/meta.json
CHANGED
package/gs/io/fs/readdir.test.ts
CHANGED
|
@@ -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
|
})
|
package/gs/io/fs/readdir.ts
CHANGED
|
@@ -17,7 +17,11 @@ export type ReadDirFS =
|
|
|
17
17
|
| ({
|
|
18
18
|
// ReadDir reads the named directory
|
|
19
19
|
// and returns a list of directory entries sorted by filename.
|
|
20
|
-
ReadDir(
|
|
20
|
+
ReadDir(
|
|
21
|
+
name: string,
|
|
22
|
+
):
|
|
23
|
+
| [$.Slice<DirEntry>, $.GoError]
|
|
24
|
+
| Promise<[$.Slice<DirEntry>, $.GoError]>
|
|
21
25
|
} & FS)
|
|
22
26
|
|
|
23
27
|
$.registerInterfaceType(
|
|
@@ -55,51 +59,50 @@ $.registerInterfaceType(
|
|
|
55
59
|
// If fs implements [ReadDirFS], ReadDir calls fs.ReadDir.
|
|
56
60
|
// Otherwise ReadDir calls fs.Open and uses ReadDir and Close
|
|
57
61
|
// on the returned file.
|
|
58
|
-
export function ReadDir(
|
|
62
|
+
export async function ReadDir(
|
|
59
63
|
fsys: FS,
|
|
60
64
|
name: string,
|
|
61
|
-
): [$.Slice<DirEntry>, $.GoError] {
|
|
62
|
-
using __defer = new $.DisposableStack()
|
|
65
|
+
): Promise<[$.Slice<DirEntry>, $.GoError]> {
|
|
63
66
|
{
|
|
64
67
|
let { value: fsysTyped, ok: ok } = $.typeAssert<ReadDirFS>(
|
|
65
68
|
fsys,
|
|
66
69
|
'ReadDirFS',
|
|
67
70
|
)
|
|
68
71
|
if (ok) {
|
|
69
|
-
return fsysTyped!.ReadDir(name)
|
|
72
|
+
return await fsysTyped!.ReadDir(name)
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
let [file, err] = fsys!.Open(name)
|
|
76
|
+
let [file, err] = await fsys!.Open(name)
|
|
74
77
|
if (err != null) {
|
|
75
78
|
return [null, err]
|
|
76
79
|
}
|
|
77
|
-
|
|
78
|
-
file
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}),
|
|
90
|
-
]
|
|
91
|
-
}
|
|
80
|
+
try {
|
|
81
|
+
let { value: dir, ok: ok } = $.typeAssert<ReadDirFile>(file, 'ReadDirFile')
|
|
82
|
+
if (!ok) {
|
|
83
|
+
return [
|
|
84
|
+
null,
|
|
85
|
+
new PathError({
|
|
86
|
+
Err: errors.New('not implemented'),
|
|
87
|
+
Op: 'readdir',
|
|
88
|
+
Path: name,
|
|
89
|
+
}),
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
let list: $.Slice<DirEntry>
|
|
94
|
+
;[list, err] = await dir!.ReadDir(-1)
|
|
95
|
+
if (list) {
|
|
96
|
+
list.sort((a: DirEntry, b: DirEntry): number => {
|
|
97
|
+
return $.pointerValue<Exclude<DirEntry, null>>(a)
|
|
98
|
+
.Name()
|
|
99
|
+
.localeCompare($.pointerValue<Exclude<DirEntry, null>>(b).Name())
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
return [list, err]
|
|
103
|
+
} finally {
|
|
104
|
+
await file!.Close()
|
|
101
105
|
}
|
|
102
|
-
return [list, err]
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
class dirInfo {
|
package/gs/io/fs/sub.ts
CHANGED
|
@@ -164,14 +164,14 @@ class subFS {
|
|
|
164
164
|
return [file, f!.fixErr(err)]
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
public ReadDir(name: string): [$.Slice<DirEntry>, $.GoError] {
|
|
167
|
+
public async ReadDir(name: string): Promise<[$.Slice<DirEntry>, $.GoError]> {
|
|
168
168
|
const f = this
|
|
169
169
|
let [full, err] = f!.fullName('read', name)
|
|
170
170
|
if (err != null) {
|
|
171
171
|
return [null, err]
|
|
172
172
|
}
|
|
173
173
|
let dir: $.Slice<DirEntry>
|
|
174
|
-
;[dir, err] = ReadDir(f!.fsys, full)
|
|
174
|
+
;[dir, err] = await ReadDir(f!.fsys, full)
|
|
175
175
|
return [dir, f!.fixErr(err)]
|
|
176
176
|
}
|
|
177
177
|
|
|
@@ -186,7 +186,7 @@ class subFS {
|
|
|
186
186
|
return [data, f!.fixErr(err)]
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
public Glob(pattern: string): [$.Slice<string>, $.GoError] {
|
|
189
|
+
public async Glob(pattern: string): Promise<[$.Slice<string>, $.GoError]> {
|
|
190
190
|
const f = this
|
|
191
191
|
{
|
|
192
192
|
let [, err] = path.Match(pattern, '')
|
|
@@ -198,7 +198,7 @@ class subFS {
|
|
|
198
198
|
return [$.arrayToSlice<string>(['.']), null]
|
|
199
199
|
}
|
|
200
200
|
let full = f!.dir + '/' + pattern
|
|
201
|
-
let [list, err] = Glob(f!.fsys, full)
|
|
201
|
+
let [list, err] = await Glob(f!.fsys, full)
|
|
202
202
|
for (let i = 0; i < $.len(list); i++) {
|
|
203
203
|
const name = list![i]
|
|
204
204
|
{
|
package/gs/io/fs/walk.ts
CHANGED
package/gs/maps/iter.ts
CHANGED
|
@@ -8,9 +8,9 @@ import * as iter from '@goscript/iter/index.js'
|
|
|
8
8
|
export function All<K extends $.Comparable | null, V>(
|
|
9
9
|
m: Map<K, V> | null,
|
|
10
10
|
): iter.Seq2<K, V> {
|
|
11
|
-
return (
|
|
12
|
-
|
|
|
13
|
-
|
|
11
|
+
return (
|
|
12
|
+
_yield: ((p0: K, p1: V) => iter.YieldResult) | null,
|
|
13
|
+
): void | globalThis.Promise<void> => iteratePairs(m?.entries() ?? [], _yield)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// Keys returns an iterator over keys in m.
|
|
@@ -19,9 +19,9 @@ export function All<K extends $.Comparable | null, V>(
|
|
|
19
19
|
export function Keys<K extends $.Comparable | null, V>(
|
|
20
20
|
m: Map<K, V> | null,
|
|
21
21
|
): iter.Seq<K> {
|
|
22
|
-
return (
|
|
23
|
-
|
|
|
24
|
-
|
|
22
|
+
return (
|
|
23
|
+
_yield: ((p0: K) => iter.YieldResult) | null,
|
|
24
|
+
): void | globalThis.Promise<void> => iterateValues(mapKeys(m), _yield)
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Values returns an iterator over values in m.
|
|
@@ -30,9 +30,9 @@ export function Keys<K extends $.Comparable | null, V>(
|
|
|
30
30
|
export function Values<K extends $.Comparable | null, V>(
|
|
31
31
|
m: Map<K, V> | null,
|
|
32
32
|
): iter.Seq<V> {
|
|
33
|
-
return (
|
|
34
|
-
|
|
|
35
|
-
|
|
33
|
+
return (
|
|
34
|
+
_yield: ((p0: V) => iter.YieldResult) | null,
|
|
35
|
+
): void | globalThis.Promise<void> => iterateValues(mapValues(m), _yield)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
// Insert adds the key-value pairs from seq to m.
|
package/gs/maps/maps.ts
CHANGED
|
@@ -4,10 +4,10 @@ import * as _ from '@goscript/unsafe/index.js'
|
|
|
4
4
|
|
|
5
5
|
// Equal reports whether two maps contain the same key/value pairs.
|
|
6
6
|
// Values are compared using ==.
|
|
7
|
-
export function Equal<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
): boolean {
|
|
7
|
+
export function Equal<
|
|
8
|
+
K extends $.Comparable | null,
|
|
9
|
+
V extends $.Comparable | null,
|
|
10
|
+
>(m1: Map<K, V>, m2: Map<K, V>): boolean {
|
|
11
11
|
if ($.len(m1) != $.len(m2)) {
|
|
12
12
|
return false
|
|
13
13
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Mul64,
|
|
5
|
+
Rem,
|
|
6
|
+
Rem32,
|
|
7
|
+
Rem64,
|
|
8
|
+
RotateLeft16,
|
|
9
|
+
RotateLeft32,
|
|
10
|
+
RotateLeft64,
|
|
11
|
+
RotateLeft8,
|
|
12
|
+
} from './index.js'
|
|
4
13
|
|
|
5
14
|
describe('math/bits override', () => {
|
|
6
15
|
it('returns the full 128-bit product from Mul64', () => {
|
package/gs/mime/index.test.ts
CHANGED
|
@@ -22,14 +22,15 @@ describe('mime override', () => {
|
|
|
22
22
|
expect(mediaType).toBe('text/plain')
|
|
23
23
|
expect(params.get('charset')).toBe('utf-8')
|
|
24
24
|
expect(params.get('format')).toBe('flowed')
|
|
25
|
-
const [trailingMediaType, trailingParams, trailingErr] =
|
|
25
|
+
const [trailingMediaType, trailingParams, trailingErr] =
|
|
26
|
+
ParseMediaType('text/plain;')
|
|
26
27
|
expect(trailingErr).toBeNull()
|
|
27
28
|
expect(trailingMediaType).toBe('text/plain')
|
|
28
29
|
expect(trailingParams.size).toBe(0)
|
|
29
30
|
|
|
30
|
-
expect(
|
|
31
|
-
|
|
32
|
-
)
|
|
31
|
+
expect(FormatMediaType('text/plain', new Map([['charset', 'utf-8']]))).toBe(
|
|
32
|
+
'text/plain; charset=utf-8',
|
|
33
|
+
)
|
|
33
34
|
expect(
|
|
34
35
|
FormatMediaType('Attachment', new Map([['FileName', 'hello.txt']])),
|
|
35
36
|
).toBe('attachment; filename=hello.txt')
|
|
@@ -37,10 +38,13 @@ describe('mime override', () => {
|
|
|
37
38
|
FormatMediaType('attachment', new Map([['filename', 'foo bar.txt']])),
|
|
38
39
|
).toBe('attachment; filename="foo bar.txt"')
|
|
39
40
|
expect(
|
|
40
|
-
FormatMediaType(
|
|
41
|
-
|
|
42
|
-
[
|
|
43
|
-
|
|
41
|
+
FormatMediaType(
|
|
42
|
+
'text/plain',
|
|
43
|
+
new Map([
|
|
44
|
+
['z', 'last'],
|
|
45
|
+
['a', 'first'],
|
|
46
|
+
]),
|
|
47
|
+
),
|
|
44
48
|
).toBe('text/plain; a=first; z=last')
|
|
45
49
|
|
|
46
50
|
const encoded = FormatMediaType(
|
|
@@ -51,13 +55,17 @@ describe('mime override', () => {
|
|
|
51
55
|
const [, encodedParams, encodedErr] = ParseMediaType(encoded)
|
|
52
56
|
expect(encodedErr).toBeNull()
|
|
53
57
|
expect(encodedParams.get('filename')).toBe('résumé.txt')
|
|
54
|
-
const [, pathParams, pathErr] = ParseMediaType(
|
|
58
|
+
const [, pathParams, pathErr] = ParseMediaType(
|
|
59
|
+
'form-data; filename="C:\\dev\\go.txt"; quoted="a\\"b"',
|
|
60
|
+
)
|
|
55
61
|
expect(pathErr).toBeNull()
|
|
56
62
|
expect(pathParams.get('filename')).toBe('C:\\dev\\go.txt')
|
|
57
63
|
expect(pathParams.get('quoted')).toBe('a"b')
|
|
58
64
|
|
|
59
65
|
expect(TypeByExtension('.json')).toBe('application/json')
|
|
60
|
-
expect(
|
|
66
|
+
expect(
|
|
67
|
+
AddExtensionType('.goscript', 'text/plain; charset=utf-8'),
|
|
68
|
+
).toBeNull()
|
|
61
69
|
const [extensions, extensionErr] = ExtensionsByType('text/plain')
|
|
62
70
|
expect(extensionErr).toBeNull()
|
|
63
71
|
expect(extensions).toContain('.goscript')
|
|
@@ -66,10 +74,18 @@ describe('mime override', () => {
|
|
|
66
74
|
it('reports invalid media parameters', () => {
|
|
67
75
|
const [, , err] = ParseMediaType('text/plain; broken')
|
|
68
76
|
expect(err).toBe(ErrInvalidMediaParameter)
|
|
69
|
-
expect(ParseMediaType('text/plain; filename=foo bar')[2]).toBe(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
expect(ParseMediaType('text/plain;
|
|
77
|
+
expect(ParseMediaType('text/plain; filename=foo bar')[2]).toBe(
|
|
78
|
+
ErrInvalidMediaParameter,
|
|
79
|
+
)
|
|
80
|
+
expect(ParseMediaType('text/plain; filename="unterminated')[2]).toBe(
|
|
81
|
+
ErrInvalidMediaParameter,
|
|
82
|
+
)
|
|
83
|
+
expect(ParseMediaType('text/plain; x=1; x=2')[2]).toBe(
|
|
84
|
+
ErrInvalidMediaParameter,
|
|
85
|
+
)
|
|
86
|
+
expect(ParseMediaType('text/plain; bad[]=x')[2]).toBe(
|
|
87
|
+
ErrInvalidMediaParameter,
|
|
88
|
+
)
|
|
73
89
|
expect(ParseMediaType('text/plain; bad{}=x')[1].get('bad{}')).toBe('x')
|
|
74
90
|
})
|
|
75
91
|
|
|
@@ -83,7 +99,9 @@ describe('mime override', () => {
|
|
|
83
99
|
expect(qWord).toBe('hello world')
|
|
84
100
|
|
|
85
101
|
const encodedQWord = WordEncoder_Encode(QEncoding, 'utf-8', 'héllo world')
|
|
86
|
-
const [header, err] = new WordDecoder().DecodeHeader(
|
|
102
|
+
const [header, err] = new WordDecoder().DecodeHeader(
|
|
103
|
+
`subject ${encodedQWord}`,
|
|
104
|
+
)
|
|
87
105
|
expect(err).toBeNull()
|
|
88
106
|
expect(header).toBe('subject héllo world')
|
|
89
107
|
})
|
package/gs/mime/index.ts
CHANGED
|
@@ -52,7 +52,11 @@ export function FormatMediaType(
|
|
|
52
52
|
param instanceof Map ?
|
|
53
53
|
Array.from(param.entries())
|
|
54
54
|
: Object.entries(param ?? {})
|
|
55
|
-
entries.sort(([a], [b]) =>
|
|
55
|
+
entries.sort(([a], [b]) =>
|
|
56
|
+
a < b ? -1
|
|
57
|
+
: a > b ? 1
|
|
58
|
+
: 0,
|
|
59
|
+
)
|
|
56
60
|
for (const [key, value] of entries) {
|
|
57
61
|
if (!isToken(key)) {
|
|
58
62
|
return ''
|
|
@@ -92,7 +96,10 @@ export function ParseMediaType(
|
|
|
92
96
|
if (key.endsWith('*')) {
|
|
93
97
|
const decoded = decode2231Value(value)
|
|
94
98
|
if (decoded !== null) {
|
|
95
|
-
if (
|
|
99
|
+
if (
|
|
100
|
+
params.has(key.slice(0, -1)) &&
|
|
101
|
+
params.get(key.slice(0, -1)) !== decoded
|
|
102
|
+
) {
|
|
96
103
|
return ['', new Map(), ErrInvalidMediaParameter]
|
|
97
104
|
}
|
|
98
105
|
params.set(key.slice(0, -1), decoded)
|