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
|
@@ -35,9 +35,13 @@ describe('crypto/ecdh override', () => {
|
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
function hex(value: string): Uint8Array {
|
|
38
|
-
return new Uint8Array(
|
|
38
|
+
return new Uint8Array(
|
|
39
|
+
value.match(/../g)!.map((byte) => Number.parseInt(byte, 16)),
|
|
40
|
+
)
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
function toHex(value: Uint8Array | null): string {
|
|
42
|
-
return Array.from(value ?? [], (byte) =>
|
|
44
|
+
return Array.from(value ?? [], (byte) =>
|
|
45
|
+
byte.toString(16).padStart(2, '0'),
|
|
46
|
+
).join('')
|
|
43
47
|
}
|
package/gs/crypto/ecdh/index.ts
CHANGED
|
@@ -29,7 +29,9 @@ export class PublicKey {
|
|
|
29
29
|
|
|
30
30
|
public Equal(x: PublicKey | $.VarRef<PublicKey> | null): boolean {
|
|
31
31
|
const other = $.pointerValueOrNil(x)
|
|
32
|
-
return
|
|
32
|
+
return (
|
|
33
|
+
other instanceof PublicKey && bytesEqual(this.publicKey, other.publicKey)
|
|
34
|
+
)
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -54,17 +56,27 @@ export class PrivateKey {
|
|
|
54
56
|
return this.curve
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
public ECDH(
|
|
59
|
+
public ECDH(
|
|
60
|
+
remote: PublicKey | $.VarRef<PublicKey> | null,
|
|
61
|
+
): [$.Bytes, $.GoError] {
|
|
58
62
|
const remoteKey = $.pointerValueOrNil(remote)
|
|
59
63
|
if (remoteKey == null || remoteKey.curve !== this.curve) {
|
|
60
|
-
return [
|
|
64
|
+
return [
|
|
65
|
+
null,
|
|
66
|
+
$.newError(
|
|
67
|
+
'crypto/ecdh: private key and public key curves do not match',
|
|
68
|
+
),
|
|
69
|
+
]
|
|
61
70
|
}
|
|
62
71
|
return this.curve.ecdh(this, remoteKey)
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
public Equal(x: PrivateKey | $.VarRef<PrivateKey> | null): boolean {
|
|
66
75
|
const other = $.pointerValueOrNil(x)
|
|
67
|
-
return
|
|
76
|
+
return (
|
|
77
|
+
other instanceof PrivateKey &&
|
|
78
|
+
bytesEqual(this.privateKey, other.privateKey)
|
|
79
|
+
)
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
public Public(): PublicKey {
|
|
@@ -80,7 +92,9 @@ export class x25519Curve {
|
|
|
80
92
|
public GenerateKey(r: io.Reader | null): [PrivateKey | null, $.GoError] {
|
|
81
93
|
const key = new Uint8Array(x25519PrivateKeySize)
|
|
82
94
|
if (r != null) {
|
|
83
|
-
throw new Error(
|
|
95
|
+
throw new Error(
|
|
96
|
+
'crypto/ecdh: custom random readers are not implemented in GoScript',
|
|
97
|
+
)
|
|
84
98
|
}
|
|
85
99
|
globalThis.crypto.getRandomValues(key)
|
|
86
100
|
return this.NewPrivateKey(key)
|
|
@@ -113,10 +127,18 @@ export class x25519Curve {
|
|
|
113
127
|
return 'X25519'
|
|
114
128
|
}
|
|
115
129
|
|
|
116
|
-
public ecdh(
|
|
130
|
+
public ecdh(
|
|
131
|
+
local: PrivateKey | null,
|
|
132
|
+
remote: PublicKey | null,
|
|
133
|
+
): [$.Bytes, $.GoError] {
|
|
117
134
|
const out = scalarMult(local?.privateKey ?? null, remote?.publicKey ?? null)
|
|
118
135
|
if (isZero(out)) {
|
|
119
|
-
return [
|
|
136
|
+
return [
|
|
137
|
+
null,
|
|
138
|
+
$.newError(
|
|
139
|
+
'crypto/ecdh: bad X25519 remote ECDH input: low order point',
|
|
140
|
+
),
|
|
141
|
+
]
|
|
120
142
|
}
|
|
121
143
|
return [out, null]
|
|
122
144
|
}
|
|
@@ -132,23 +154,38 @@ export class unsupportedCurve {
|
|
|
132
154
|
constructor(private readonly name: string) {}
|
|
133
155
|
|
|
134
156
|
public GenerateKey(_r: io.Reader | null): [PrivateKey | null, $.GoError] {
|
|
135
|
-
return [
|
|
157
|
+
return [
|
|
158
|
+
null,
|
|
159
|
+
$.newError(`crypto/ecdh: ${this.name} is not implemented in GoScript`),
|
|
160
|
+
]
|
|
136
161
|
}
|
|
137
162
|
|
|
138
163
|
public NewPrivateKey(_key: $.Bytes): [PrivateKey | null, $.GoError] {
|
|
139
|
-
return [
|
|
164
|
+
return [
|
|
165
|
+
null,
|
|
166
|
+
$.newError(`crypto/ecdh: ${this.name} is not implemented in GoScript`),
|
|
167
|
+
]
|
|
140
168
|
}
|
|
141
169
|
|
|
142
170
|
public NewPublicKey(_key: $.Bytes): [PublicKey | null, $.GoError] {
|
|
143
|
-
return [
|
|
171
|
+
return [
|
|
172
|
+
null,
|
|
173
|
+
$.newError(`crypto/ecdh: ${this.name} is not implemented in GoScript`),
|
|
174
|
+
]
|
|
144
175
|
}
|
|
145
176
|
|
|
146
177
|
public String(): string {
|
|
147
178
|
return this.name
|
|
148
179
|
}
|
|
149
180
|
|
|
150
|
-
public ecdh(
|
|
151
|
-
|
|
181
|
+
public ecdh(
|
|
182
|
+
_local: PrivateKey | null,
|
|
183
|
+
_remote: PublicKey | null,
|
|
184
|
+
): [$.Bytes, $.GoError] {
|
|
185
|
+
return [
|
|
186
|
+
null,
|
|
187
|
+
$.newError(`crypto/ecdh: ${this.name} is not implemented in GoScript`),
|
|
188
|
+
]
|
|
152
189
|
}
|
|
153
190
|
}
|
|
154
191
|
|
|
@@ -14,8 +14,8 @@ export const SignatureSize = 64
|
|
|
14
14
|
export const SeedSize = 32
|
|
15
15
|
|
|
16
16
|
const pkcs8Prefix = new Uint8Array([
|
|
17
|
-
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70,
|
|
18
|
-
|
|
17
|
+
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04,
|
|
18
|
+
0x22, 0x04, 0x20,
|
|
19
19
|
])
|
|
20
20
|
|
|
21
21
|
export class Options {
|
|
@@ -32,7 +32,10 @@ export class Options {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function PublicKey_Equal(
|
|
35
|
+
export function PublicKey_Equal(
|
|
36
|
+
pub: PublicKey,
|
|
37
|
+
x: PublicKeyInterface | null,
|
|
38
|
+
): boolean {
|
|
36
39
|
const [xx, ok] = $.typeAssertTuple<PublicKey>(x, 'ed25519.PublicKey')
|
|
37
40
|
return ok && bytesEqual(pub, xx)
|
|
38
41
|
}
|
|
@@ -47,7 +50,10 @@ export function PrivateKey_Public(priv: PrivateKey): PublicKeyInterface | null {
|
|
|
47
50
|
)
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
export function PrivateKey_Equal(
|
|
53
|
+
export function PrivateKey_Equal(
|
|
54
|
+
priv: PrivateKey,
|
|
55
|
+
x: PrivateKeyInterface | null,
|
|
56
|
+
): boolean {
|
|
51
57
|
const [xx, ok] = $.typeAssertTuple<PrivateKey>(x, 'ed25519.PrivateKey')
|
|
52
58
|
return ok && bytesEqual(priv, xx)
|
|
53
59
|
}
|
|
@@ -68,7 +74,9 @@ export async function PrivateKey_Sign(
|
|
|
68
74
|
return [await Sign(priv, message), null]
|
|
69
75
|
}
|
|
70
76
|
|
|
71
|
-
export async function GenerateKey(
|
|
77
|
+
export async function GenerateKey(
|
|
78
|
+
random: io.Reader | null,
|
|
79
|
+
): Promise<[PublicKey, PrivateKey, $.GoError]> {
|
|
72
80
|
const seed = new Uint8Array(SeedSize)
|
|
73
81
|
if (random == null) {
|
|
74
82
|
const subtle = subtleCrypto()
|
|
@@ -124,7 +132,10 @@ export async function NewKeyFromSeed(seed: $.Bytes): Promise<PrivateKey> {
|
|
|
124
132
|
return privateKey
|
|
125
133
|
}
|
|
126
134
|
|
|
127
|
-
export async function Sign(
|
|
135
|
+
export async function Sign(
|
|
136
|
+
privateKey: PrivateKey,
|
|
137
|
+
message: $.Bytes,
|
|
138
|
+
): Promise<$.Bytes> {
|
|
128
139
|
const priv = $.bytesToUint8Array(privateKey)
|
|
129
140
|
if (priv.length !== PrivateKeySize) {
|
|
130
141
|
throw new Error(`ed25519: bad private key length: ${priv.length}`)
|
|
@@ -150,7 +161,9 @@ export async function Verify(
|
|
|
150
161
|
message: $.Bytes,
|
|
151
162
|
sig: $.Bytes,
|
|
152
163
|
): Promise<boolean> {
|
|
153
|
-
return (
|
|
164
|
+
return (
|
|
165
|
+
(await VerifyWithOptions(publicKey, message, sig, new Options())) == null
|
|
166
|
+
)
|
|
154
167
|
}
|
|
155
168
|
|
|
156
169
|
export async function VerifyWithOptions(
|
package/gs/crypto/rand/index.ts
CHANGED
|
@@ -71,7 +71,10 @@ export async function Prime(
|
|
|
71
71
|
bits: number,
|
|
72
72
|
): Promise<[any, $.GoError]> {
|
|
73
73
|
if (bits < 2) {
|
|
74
|
-
return [
|
|
74
|
+
return [
|
|
75
|
+
null,
|
|
76
|
+
new RandError('crypto/rand: prime size must be at least 2-bit'),
|
|
77
|
+
]
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
const bitOffset = bits % 8
|
|
@@ -123,8 +126,8 @@ function newBigInt(): any {
|
|
|
123
126
|
| { zeroValue?: unknown; ctor?: new () => unknown }
|
|
124
127
|
| undefined
|
|
125
128
|
if (info?.zeroValue !== undefined) {
|
|
126
|
-
return typeof info.zeroValue === 'function'
|
|
127
|
-
|
|
129
|
+
return typeof info.zeroValue === 'function' ?
|
|
130
|
+
(info.zeroValue as () => unknown)()
|
|
128
131
|
: info.zeroValue
|
|
129
132
|
}
|
|
130
133
|
if (info?.ctor != null) {
|
package/gs/embed/index.test.ts
CHANGED
|
@@ -19,7 +19,7 @@ describe('embed.FS', () => {
|
|
|
19
19
|
expect(Array.from(data)).toEqual([1, 2, 3])
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
-
it('supports io/fs read, stat, and directory APIs', () => {
|
|
22
|
+
it('supports io/fs read, stat, and directory APIs', async () => {
|
|
23
23
|
const fsys = markAsStructValue(
|
|
24
24
|
new FS(
|
|
25
25
|
new Map([
|
|
@@ -37,7 +37,7 @@ describe('embed.FS', () => {
|
|
|
37
37
|
expect(readAgainErr).toBeNull()
|
|
38
38
|
expect(Array.from(dataAgain)).toEqual([1, 2, 3])
|
|
39
39
|
|
|
40
|
-
const [rootEntries, rootErr] = ReadDir(fsys, '.')
|
|
40
|
+
const [rootEntries, rootErr] = await ReadDir(fsys, '.')
|
|
41
41
|
expect(rootErr).toBeNull()
|
|
42
42
|
expect(rootEntries!.map((entry) => entry!.Name())).toEqual([
|
|
43
43
|
'assets',
|
|
@@ -48,7 +48,7 @@ describe('embed.FS', () => {
|
|
|
48
48
|
expect(statErr).toBeNull()
|
|
49
49
|
expect(assetInfo!.IsDir()).toBe(true)
|
|
50
50
|
|
|
51
|
-
const [assetEntries, assetErr] = ReadDir(fsys, 'assets')
|
|
51
|
+
const [assetEntries, assetErr] = await ReadDir(fsys, 'assets')
|
|
52
52
|
expect(assetErr).toBeNull()
|
|
53
53
|
expect(assetEntries!.map((entry) => entry!.Name())).toEqual(['config.json'])
|
|
54
54
|
})
|
package/gs/embed/index.ts
CHANGED
|
@@ -166,9 +166,15 @@ class embedFile {
|
|
|
166
166
|
|
|
167
167
|
Stat(): [fs.FileInfo, $.GoError] {
|
|
168
168
|
if (this.data === null) {
|
|
169
|
-
return [
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
return [
|
|
170
|
+
new embedFileInfo(baseName(this.name), 0, fs.ModeDir | 0o555),
|
|
171
|
+
null,
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
return [
|
|
175
|
+
new embedFileInfo(baseName(this.name), this.data.byteLength, 0o444),
|
|
176
|
+
null,
|
|
177
|
+
]
|
|
172
178
|
}
|
|
173
179
|
}
|
|
174
180
|
|
package/gs/fmt/fmt.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
2
|
import { resetHostRuntimeForTests } from '@goscript/builtin/hostio.js'
|
|
3
3
|
import * as $ from '@goscript/builtin/index.js'
|
|
4
|
+
import * as os from '@goscript/os/index.js'
|
|
4
5
|
import * as fmt from './fmt.js'
|
|
5
6
|
|
|
6
7
|
const originalDeno = (globalThis as any).Deno
|
|
@@ -61,10 +62,15 @@ describe('fmt basic value formatting', () => {
|
|
|
61
62
|
expect(
|
|
62
63
|
fmt.Sprintf(
|
|
63
64
|
'Type: %T',
|
|
64
|
-
$.namedValueInterfaceValue(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
$.namedValueInterfaceValue(
|
|
66
|
+
123,
|
|
67
|
+
'int',
|
|
68
|
+
{},
|
|
69
|
+
{
|
|
70
|
+
kind: $.TypeKind.Basic,
|
|
71
|
+
name: 'int',
|
|
72
|
+
},
|
|
73
|
+
),
|
|
68
74
|
),
|
|
69
75
|
).toBe('Type: int')
|
|
70
76
|
})
|
|
@@ -187,6 +193,25 @@ describe('fmt spacing rules', () => {
|
|
|
187
193
|
expect(new TextDecoder().decode(chunks[1])).toBe('hi there 1 2\n')
|
|
188
194
|
})
|
|
189
195
|
|
|
196
|
+
it('Fprintln writes Stderr through console.log in browser-like hosts', async () => {
|
|
197
|
+
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
|
198
|
+
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
199
|
+
delete (globalThis as any).Deno
|
|
200
|
+
delete (globalThis as any).process
|
|
201
|
+
resetHostRuntimeForTests()
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
const [n, err] = await fmt.Fprintln(os.Stderr!, 'err')
|
|
205
|
+
expect(err).toBeNull()
|
|
206
|
+
expect(n).toBe(4)
|
|
207
|
+
expect(consoleLog).toHaveBeenCalledWith('err')
|
|
208
|
+
expect(consoleError).not.toHaveBeenCalled()
|
|
209
|
+
} finally {
|
|
210
|
+
consoleLog.mockRestore()
|
|
211
|
+
consoleError.mockRestore()
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
190
215
|
it('Fprintf awaits async writers', async () => {
|
|
191
216
|
const chunks: Uint8Array[] = []
|
|
192
217
|
const writer = {
|
|
@@ -258,6 +258,104 @@ class TimestampParentBoundMessage {
|
|
|
258
258
|
timestamp: TimestampBoundMessage,
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
const oneofLeafMessageType = {
|
|
262
|
+
typeName: 'test.OneofLeafBoundMessage',
|
|
263
|
+
fields: {
|
|
264
|
+
list: () => [{ localName: 'label', kind: 'scalar' }],
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
class OneofLeafBoundMessage {
|
|
269
|
+
public get Label(): string {
|
|
270
|
+
return this._fields.Label.value
|
|
271
|
+
}
|
|
272
|
+
public set Label(value: string) {
|
|
273
|
+
this._fields.Label.value = value
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
public _fields: {
|
|
277
|
+
Label: $.VarRef<string>
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
constructor(init?: Partial<{ Label?: string }>) {
|
|
281
|
+
this._fields = {
|
|
282
|
+
Label: $.varRef(init?.Label ?? ''),
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
;(OneofLeafBoundMessage as any).__protobufTypeScriptMessage =
|
|
288
|
+
oneofLeafMessageType
|
|
289
|
+
;(OneofLeafBoundMessage as any).__protobufTypeScriptFields = {}
|
|
290
|
+
|
|
291
|
+
class OneofBoundMessage_TabSet {
|
|
292
|
+
public get TabSet(): OneofLeafBoundMessage | null {
|
|
293
|
+
return this._fields.TabSet.value
|
|
294
|
+
}
|
|
295
|
+
public set TabSet(value: OneofLeafBoundMessage | null) {
|
|
296
|
+
this._fields.TabSet.value = value
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
public _fields: {
|
|
300
|
+
TabSet: $.VarRef<OneofLeafBoundMessage | null>
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
constructor(init?: Partial<{ TabSet?: OneofLeafBoundMessage | null }>) {
|
|
304
|
+
this._fields = {
|
|
305
|
+
TabSet: $.varRef(init?.TabSet ?? null),
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
class OneofBoundMessage {
|
|
311
|
+
public get Node(): OneofBoundMessage_TabSet | null {
|
|
312
|
+
return this._fields.Node.value
|
|
313
|
+
}
|
|
314
|
+
public set Node(value: OneofBoundMessage_TabSet | null) {
|
|
315
|
+
this._fields.Node.value = value
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
public _fields: {
|
|
319
|
+
Node: $.VarRef<OneofBoundMessage_TabSet | null>
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
constructor(init?: Partial<{ Node?: OneofBoundMessage_TabSet | null }>) {
|
|
323
|
+
this._fields = {
|
|
324
|
+
Node: $.varRef(init?.Node ?? null),
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
;(OneofBoundMessage as any).__protobufTypeScriptMessage = {
|
|
330
|
+
typeName: 'test.OneofBoundMessage',
|
|
331
|
+
fields: {
|
|
332
|
+
list: () => [
|
|
333
|
+
{
|
|
334
|
+
localName: 'tabSet',
|
|
335
|
+
kind: 'message',
|
|
336
|
+
T: oneofLeafMessageType,
|
|
337
|
+
oneof: { localName: 'node' },
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
fromBinary: () => ({
|
|
342
|
+
node: { case: 'tabSet', value: { label: 'files' } },
|
|
343
|
+
}),
|
|
344
|
+
toBinary: (value: {
|
|
345
|
+
node?: { case: string; value?: { label?: string } }
|
|
346
|
+
}) => {
|
|
347
|
+
expect(value.node?.case).toBe('tabSet')
|
|
348
|
+
expect(value.node?.value?.label).toBe('files')
|
|
349
|
+
return new Uint8Array([7])
|
|
350
|
+
},
|
|
351
|
+
}
|
|
352
|
+
;(OneofBoundMessage as any).__protobufTypeScriptFields = {
|
|
353
|
+
tabSet: OneofLeafBoundMessage,
|
|
354
|
+
}
|
|
355
|
+
;(OneofBoundMessage as any).__protobufTypeScriptOneofFields = {
|
|
356
|
+
node: { tabSet: OneofBoundMessage_TabSet },
|
|
357
|
+
}
|
|
358
|
+
|
|
261
359
|
describe('protobuf-go-lite EqualVT helpers', () => {
|
|
262
360
|
it('accepts compiler-emitted runtime type arguments', () => {
|
|
263
361
|
const equal = CompareEqualVT<TestValue>({
|
|
@@ -405,6 +503,34 @@ describe('protobuf-go-lite TypeScript binding helpers', () => {
|
|
|
405
503
|
expect(target.Timestamp?.Seconds).toBe(1780230896)
|
|
406
504
|
expect(target.Timestamp?.Nanos).toBe(789000000)
|
|
407
505
|
})
|
|
506
|
+
|
|
507
|
+
it('preserves protobuf oneof branches in bound binary helpers', () => {
|
|
508
|
+
const source = new OneofBoundMessage({
|
|
509
|
+
Node: new OneofBoundMessage_TabSet({
|
|
510
|
+
TabSet: new OneofLeafBoundMessage({ Label: 'files' }),
|
|
511
|
+
}),
|
|
512
|
+
})
|
|
513
|
+
|
|
514
|
+
const [bytes, marshalErr] = MarshalBoundMessageVT(
|
|
515
|
+
OneofBoundMessage as any,
|
|
516
|
+
source,
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
expect(marshalErr).toBeNull()
|
|
520
|
+
expect(Array.from(bytes ?? [])).toEqual([7])
|
|
521
|
+
|
|
522
|
+
const target = new OneofBoundMessage()
|
|
523
|
+
const unmarshalErr = UnmarshalBoundMessageVT(
|
|
524
|
+
OneofBoundMessage as any,
|
|
525
|
+
target,
|
|
526
|
+
new Uint8Array([7]),
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
expect(unmarshalErr).toBeNull()
|
|
530
|
+
expect(target.Node).toBeInstanceOf(OneofBoundMessage_TabSet)
|
|
531
|
+
expect(target.Node?.TabSet).toBeInstanceOf(OneofLeafBoundMessage)
|
|
532
|
+
expect(target.Node?.TabSet?.Label).toBe('files')
|
|
533
|
+
})
|
|
408
534
|
})
|
|
409
535
|
|
|
410
536
|
describe('protobuf-go-lite wire helpers', () => {
|
|
@@ -369,6 +369,10 @@ type BoundFieldInfo = {
|
|
|
369
369
|
type BoundMessageCtor<T = any> = {
|
|
370
370
|
new (init?: any): T
|
|
371
371
|
__protobufTypeScriptFields?: Record<string, BoundMessageCtor>
|
|
372
|
+
__protobufTypeScriptOneofFields?: Record<
|
|
373
|
+
string,
|
|
374
|
+
Record<string, BoundMessageCtor>
|
|
375
|
+
>
|
|
372
376
|
__protobufTypeScriptMessage?: BoundMessageType
|
|
373
377
|
}
|
|
374
378
|
|
|
@@ -404,6 +408,10 @@ function boundFieldValue(source: any, field: BoundFieldInfo): any {
|
|
|
404
408
|
return source[boundFieldGoName(field)]
|
|
405
409
|
}
|
|
406
410
|
|
|
411
|
+
function boundOneofGroupGoName(field: BoundFieldInfo): string {
|
|
412
|
+
return boundFieldGoName({ ...field, localName: field.oneof?.localName ?? '' })
|
|
413
|
+
}
|
|
414
|
+
|
|
407
415
|
function toTypeScriptScalarValue(value: any, field?: BoundFieldInfo): any {
|
|
408
416
|
const unwrapped = $.pointerValueOrNil(value)
|
|
409
417
|
if (
|
|
@@ -471,6 +479,27 @@ function toTypeScriptMessage(
|
|
|
471
479
|
const out: Record<string, unknown> = {}
|
|
472
480
|
for (const field of fields) {
|
|
473
481
|
if (field.oneof != null) {
|
|
482
|
+
const groupName = field.oneof.localName
|
|
483
|
+
const group = boundFieldValue(value, {
|
|
484
|
+
...field,
|
|
485
|
+
localName: groupName,
|
|
486
|
+
oneof: undefined,
|
|
487
|
+
})
|
|
488
|
+
if (group == null || out[groupName] !== undefined) {
|
|
489
|
+
continue
|
|
490
|
+
}
|
|
491
|
+
const raw = boundFieldValue(group, field)
|
|
492
|
+
if (raw === undefined || raw === null) {
|
|
493
|
+
continue
|
|
494
|
+
}
|
|
495
|
+
out[groupName] = {
|
|
496
|
+
case: field.localName,
|
|
497
|
+
value: toTypeScriptFieldValue(
|
|
498
|
+
field,
|
|
499
|
+
raw,
|
|
500
|
+
fieldCtors[field.localName] ?? raw?.constructor,
|
|
501
|
+
),
|
|
502
|
+
}
|
|
474
503
|
continue
|
|
475
504
|
}
|
|
476
505
|
const raw = boundFieldValue(value, field)
|
|
@@ -566,8 +595,25 @@ function fromTypeScriptMessage(
|
|
|
566
595
|
return Object.assign(out, value)
|
|
567
596
|
}
|
|
568
597
|
const fieldCtors = ctor.__protobufTypeScriptFields ?? {}
|
|
598
|
+
const oneofCtors = ctor.__protobufTypeScriptOneofFields ?? {}
|
|
569
599
|
for (const field of fields) {
|
|
570
600
|
if (field.oneof != null) {
|
|
601
|
+
const groupName = field.oneof.localName
|
|
602
|
+
const raw = value[groupName]
|
|
603
|
+
if (raw?.case !== field.localName) {
|
|
604
|
+
continue
|
|
605
|
+
}
|
|
606
|
+
const branchCtor = oneofCtors[groupName]?.[field.localName]
|
|
607
|
+
const branchValue = fromTypeScriptFieldValue(
|
|
608
|
+
field,
|
|
609
|
+
raw.value,
|
|
610
|
+
fieldCtors[field.localName],
|
|
611
|
+
)
|
|
612
|
+
const branchFieldName = boundFieldGoName(field)
|
|
613
|
+
out[boundOneofGroupGoName(field)] =
|
|
614
|
+
branchCtor == null ?
|
|
615
|
+
{ [branchFieldName]: branchValue }
|
|
616
|
+
: new branchCtor({ [branchFieldName]: branchValue })
|
|
571
617
|
continue
|
|
572
618
|
}
|
|
573
619
|
const raw = value[field.localName]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as $ from '@goscript/builtin/index.js'
|
|
2
2
|
|
|
3
3
|
const btcAlphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|
4
|
-
const flickrAlphabet =
|
|
4
|
+
const flickrAlphabet =
|
|
5
|
+
'123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
|
|
5
6
|
|
|
6
7
|
export class Alphabet {
|
|
7
8
|
decode: Int8Array
|
|
@@ -130,7 +131,9 @@ export function DecodeAlphabet(
|
|
|
130
131
|
return FastBase58DecodingAlphabet(str, alphabet)
|
|
131
132
|
}
|
|
132
133
|
|
|
133
|
-
export function FastBase58Decoding(
|
|
134
|
+
export function FastBase58Decoding(
|
|
135
|
+
str: string,
|
|
136
|
+
): [Uint8Array | null, $.GoError] {
|
|
134
137
|
return FastBase58DecodingAlphabet(str, BTCAlphabet)
|
|
135
138
|
}
|
|
136
139
|
|
|
@@ -187,7 +190,10 @@ export function FastBase58DecodingAlphabet(
|
|
|
187
190
|
}
|
|
188
191
|
|
|
189
192
|
if (c > 0) {
|
|
190
|
-
return [
|
|
193
|
+
return [
|
|
194
|
+
null,
|
|
195
|
+
$.newError('Output number too big (carry to the next int32)'),
|
|
196
|
+
]
|
|
191
197
|
}
|
|
192
198
|
if ((outi[0] & zmask) !== 0) {
|
|
193
199
|
return [
|
|
@@ -20,14 +20,8 @@ import {
|
|
|
20
20
|
describe('blake3 consts override', () => {
|
|
21
21
|
test('uses portable constants for GoScript', () => {
|
|
22
22
|
expect(IV).toEqual([
|
|
23
|
-
0x6a09e667,
|
|
24
|
-
|
|
25
|
-
0x3c6ef372,
|
|
26
|
-
0xa54ff53a,
|
|
27
|
-
0x510e527f,
|
|
28
|
-
0x9b05688c,
|
|
29
|
-
0x1f83d9ab,
|
|
30
|
-
0x5be0cd19,
|
|
23
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c,
|
|
24
|
+
0x1f83d9ab, 0x5be0cd19,
|
|
31
25
|
])
|
|
32
26
|
expect(IV[0]).toBe(IV0)
|
|
33
27
|
expect(BlockLen).toBe(64)
|
|
@@ -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
|
+
}
|