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.
- package/compiler/gotest/runner.go +98 -0
- package/compiler/gotest/runner_test.go +45 -0
- package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
- package/compiler/lowering.go +227 -11
- package/compiler/override-registry_test.go +50 -0
- package/compiler/protobuf-ts-binding.go +155 -7
- package/compiler/protobuf-ts-binding_test.go +116 -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 +477 -16
- 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/aes/index.d.ts +15 -0
- package/dist/gs/crypto/aes/index.js +57 -0
- package/dist/gs/crypto/aes/index.js.map +1 -0
- package/dist/gs/crypto/cipher/index.d.ts +41 -0
- package/dist/gs/crypto/cipher/index.js +255 -0
- package/dist/gs/crypto/cipher/index.js.map +1 -0
- 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/chacha20poly1305/index.d.ts +31 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
- 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/io/io.js +18 -2
- package/dist/gs/io/io.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/debug/index.js +2 -1
- package/dist/gs/runtime/debug/index.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/go.mod +2 -2
- package/go.sum +2 -0
- package/gs/builtin/builtin.ts +11 -14
- package/gs/builtin/defer.ts +2 -2
- package/gs/builtin/hostio.test.ts +8 -3
- package/gs/builtin/hostio.ts +5 -7
- 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/aes/index.test.ts +120 -0
- package/gs/crypto/aes/index.ts +76 -0
- package/gs/crypto/cipher/index.ts +345 -0
- package/gs/crypto/cipher/meta.json +6 -0
- 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/chacha20poly1305/index.test.ts +91 -0
- package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
- 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/io/io.test.ts +56 -1
- package/gs/io/io.ts +19 -2
- 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/debug/index.test.ts +32 -4
- package/gs/runtime/debug/index.ts +5 -2
- 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 +13 -5
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/io/io.test.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import * as $ from '@goscript/builtin/index.js'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
LimitedReader,
|
|
4
|
+
MultiWriter,
|
|
5
|
+
NewSectionReader,
|
|
6
|
+
NopCloser,
|
|
7
|
+
Pipe,
|
|
8
|
+
TeeReader,
|
|
9
|
+
} from './index.js'
|
|
3
10
|
import { describe, expect, test } from 'vitest'
|
|
4
11
|
|
|
5
12
|
class sliceReader {
|
|
@@ -22,6 +29,15 @@ class captureWriter {
|
|
|
22
29
|
}
|
|
23
30
|
}
|
|
24
31
|
|
|
32
|
+
class syncReaderAt {
|
|
33
|
+
constructor(private data: Uint8Array) {}
|
|
34
|
+
|
|
35
|
+
ReadAt(p: $.Bytes, off: number): [number, $.GoError] {
|
|
36
|
+
const n = $.copy(p, this.data.subarray(off))
|
|
37
|
+
return [n, n < $.len(p) ? (new Error('EOF') as $.GoError) : null]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
25
41
|
describe('io override', () => {
|
|
26
42
|
test('LimitedReader accepts generated struct-literal construction', async () => {
|
|
27
43
|
const reader = new LimitedReader({
|
|
@@ -118,6 +134,45 @@ describe('io override', () => {
|
|
|
118
134
|
expect(Buffer.from(chunks).toString('utf8')).toBe('abc')
|
|
119
135
|
})
|
|
120
136
|
|
|
137
|
+
test('SectionReader preserves sync reads for sync ReaderAt', () => {
|
|
138
|
+
const reader = NewSectionReader(
|
|
139
|
+
new syncReaderAt($.stringToBytes('abcdef')),
|
|
140
|
+
1,
|
|
141
|
+
3,
|
|
142
|
+
)
|
|
143
|
+
const buf = new Uint8Array(4)
|
|
144
|
+
|
|
145
|
+
const result = reader.Read(buf)
|
|
146
|
+
expect(result).not.toBeInstanceOf(Promise)
|
|
147
|
+
const [n, err] = result
|
|
148
|
+
|
|
149
|
+
expect(err).toBeNull()
|
|
150
|
+
expect(n).toBe(3)
|
|
151
|
+
expect(Buffer.from(buf.subarray(0, n)).toString('utf8')).toBe('bcd')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('SectionReader awaits async ReaderAt', async () => {
|
|
155
|
+
const reader = NewSectionReader(
|
|
156
|
+
{
|
|
157
|
+
async ReadAt(p: $.Bytes, off: number): Promise<[number, $.GoError]> {
|
|
158
|
+
await Promise.resolve()
|
|
159
|
+
const data = $.stringToBytes('abcdef')
|
|
160
|
+
const n = $.copy(p, data.subarray(off))
|
|
161
|
+
return [n, n < $.len(p) ? (new Error('EOF') as $.GoError) : null]
|
|
162
|
+
},
|
|
163
|
+
} as any,
|
|
164
|
+
1,
|
|
165
|
+
3,
|
|
166
|
+
)
|
|
167
|
+
const buf = new Uint8Array(4)
|
|
168
|
+
|
|
169
|
+
const [n, err] = await reader.Read(buf)
|
|
170
|
+
|
|
171
|
+
expect(err).toBeNull()
|
|
172
|
+
expect(n).toBe(3)
|
|
173
|
+
expect(Buffer.from(buf.subarray(0, n)).toString('utf8')).toBe('bcd')
|
|
174
|
+
})
|
|
175
|
+
|
|
121
176
|
test('PipeReader waits for a later write', async () => {
|
|
122
177
|
const [reader, writer] = Pipe()
|
|
123
178
|
const buf = new Uint8Array(5)
|
package/gs/io/io.ts
CHANGED
|
@@ -363,7 +363,15 @@ export class SectionReader implements Reader, Seeker, ReaderAt {
|
|
|
363
363
|
p = $.goSlice(p, 0, max)
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
const
|
|
366
|
+
const res = this.r.ReadAt(p, this.off) as any
|
|
367
|
+
if (res instanceof Promise) {
|
|
368
|
+
return res.then(([n, err]: [number, $.GoError]) => {
|
|
369
|
+
this.off += n
|
|
370
|
+
return [n, err]
|
|
371
|
+
}) as any
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const [n, err] = res
|
|
367
375
|
this.off += n
|
|
368
376
|
return [n, err]
|
|
369
377
|
}
|
|
@@ -400,7 +408,16 @@ export class SectionReader implements Reader, Seeker, ReaderAt {
|
|
|
400
408
|
off += this.base
|
|
401
409
|
if (off + $.len(p) > this.limit) {
|
|
402
410
|
p = $.goSlice(p, 0, this.limit - off)
|
|
403
|
-
const
|
|
411
|
+
const res = this.r.ReadAt(p, off) as any
|
|
412
|
+
if (res instanceof Promise) {
|
|
413
|
+
return res.then(([n, err]: [number, $.GoError]) => {
|
|
414
|
+
if (err === null) {
|
|
415
|
+
return [n, EOF]
|
|
416
|
+
}
|
|
417
|
+
return [n, err]
|
|
418
|
+
}) as any
|
|
419
|
+
}
|
|
420
|
+
const [n, err] = res
|
|
404
421
|
if (err === null) {
|
|
405
422
|
return [n, EOF]
|
|
406
423
|
}
|
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)
|
|
@@ -47,20 +47,34 @@ describe('net/http/httptest override', () => {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
it('exports request defaults and recorder compatibility helpers', () => {
|
|
50
|
-
const req = NewRequestWithContext(
|
|
50
|
+
const req = NewRequestWithContext(
|
|
51
|
+
context.Background(),
|
|
52
|
+
'',
|
|
53
|
+
'https://example.invalid/path',
|
|
54
|
+
null,
|
|
55
|
+
)
|
|
51
56
|
expect(DefaultRemoteAddr).toBe('1.2.3.4')
|
|
52
57
|
expect(req.Method).toBe(MethodGet)
|
|
53
58
|
expect(req.Host).toBe('example.invalid')
|
|
54
59
|
expect(req.RemoteAddr).toBe('192.0.2.1:1234')
|
|
55
60
|
expect(req.TLS).not.toBeNull()
|
|
56
61
|
|
|
57
|
-
const pathReq = NewRequestWithContext(
|
|
62
|
+
const pathReq = NewRequestWithContext(
|
|
63
|
+
context.Background(),
|
|
64
|
+
MethodGet,
|
|
65
|
+
'/local?x=1',
|
|
66
|
+
null,
|
|
67
|
+
)
|
|
58
68
|
expect(pathReq.Host).toBe('example.com')
|
|
59
69
|
expect(pathReq.RequestURI).toBe('/local?x=1')
|
|
60
70
|
expect(pathReq.URL.Host).toBe('')
|
|
61
71
|
expect(pathReq.URL.Scheme).toBe('')
|
|
62
72
|
|
|
63
|
-
const bodyReq = NewTestRequest(
|
|
73
|
+
const bodyReq = NewTestRequest(
|
|
74
|
+
MethodPost,
|
|
75
|
+
'/body',
|
|
76
|
+
bytes.NewReader($.stringToBytes('abc')),
|
|
77
|
+
)
|
|
64
78
|
expect(bodyReq.ContentLength).toBe(3)
|
|
65
79
|
const noBodyReq = NewTestRequest(MethodPost, '/empty', NoBody)
|
|
66
80
|
expect(noBodyReq.ContentLength).toBe(0)
|
|
@@ -117,7 +117,11 @@ function requestBodyContentLength(body: io.Reader | null): number {
|
|
|
117
117
|
if (value === http.NoBody) {
|
|
118
118
|
return 0
|
|
119
119
|
}
|
|
120
|
-
if (
|
|
120
|
+
if (
|
|
121
|
+
value instanceof bytes.Buffer ||
|
|
122
|
+
value instanceof bytes.Reader ||
|
|
123
|
+
value instanceof strings.Reader
|
|
124
|
+
) {
|
|
121
125
|
return value.Len()
|
|
122
126
|
}
|
|
123
127
|
return -1
|
|
@@ -133,7 +137,8 @@ export class Server {
|
|
|
133
137
|
|
|
134
138
|
constructor(init?: Partial<Server> & { Handler?: http.Handler | null }) {
|
|
135
139
|
this.handler = init?.Handler ?? null
|
|
136
|
-
this.ConfigValue =
|
|
140
|
+
this.ConfigValue =
|
|
141
|
+
init?.ConfigValue ?? new http.Server({ Handler: this.handler })
|
|
137
142
|
this.URL = init?.URL ?? http.RegisterInProcessServer(this.handler)
|
|
138
143
|
}
|
|
139
144
|
|
|
@@ -200,7 +205,7 @@ function serverRequest(request: http.Request): http.Request {
|
|
|
200
205
|
const rawQuery = request.URL?.RawQuery ?? ''
|
|
201
206
|
const query = rawQuery === '' ? '' : `?${rawQuery}`
|
|
202
207
|
req.RequestURI = `${request.URL?.Path ?? '/'}${query}`
|
|
203
|
-
req.Host = request.Host === '' ? request.URL?.Host ?? '' : request.Host
|
|
208
|
+
req.Host = request.Host === '' ? (request.URL?.Host ?? '') : request.Host
|
|
204
209
|
if (req.URL?.clone != null) {
|
|
205
210
|
req.URL = req.URL.clone()
|
|
206
211
|
req.URL.Scheme = ''
|