@cloudpss/ubjson 0.6.0-alpha.8 → 0.6.0-alpha.9
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/package.json +1 -1
- package/tests/.utils.ts +9 -8
- package/tests/decode.ts +12 -16
- package/tests/e2e/stream.ts +5 -5
- package/tests/encode.ts +5 -5
- package/tests/huge-string.ts +1 -4
- package/tests/rxjs/decode.ts +11 -12
- package/tests/rxjs/encode.ts +2 -4
- package/tests/stream/decode.ts +7 -9
- package/tests/stream/encode.ts +7 -9
- package/tests/stream/many.ts +19 -30
- package/tests/string-encoding.ts +7 -4
package/package.json
CHANGED
package/tests/.utils.ts
CHANGED
|
@@ -7,7 +7,7 @@ import '../dist/options.js';
|
|
|
7
7
|
/**
|
|
8
8
|
* 重设所有环境
|
|
9
9
|
*/
|
|
10
|
-
export function resetEnv() {
|
|
10
|
+
export function resetEnv(): void {
|
|
11
11
|
resetDecoderEnv();
|
|
12
12
|
resetEncoderEnv();
|
|
13
13
|
resetEncoder();
|
|
@@ -15,25 +15,26 @@ export function resetEnv() {
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* 输入转为数字数组以便比较
|
|
18
|
-
* @param
|
|
19
|
-
* @returns
|
|
18
|
+
* @param args 输入
|
|
19
|
+
* @returns 数字数组
|
|
20
20
|
*/
|
|
21
|
-
export function toArray(...args) {
|
|
21
|
+
export function toArray(...args: [ArrayBuffer] | [Uint8Array] | Array<number | string>): number[] {
|
|
22
22
|
if (args[0] instanceof ArrayBuffer) {
|
|
23
23
|
return Array.from(new Uint8Array(args[0]));
|
|
24
24
|
}
|
|
25
25
|
if (args[0] instanceof Uint8Array) {
|
|
26
26
|
return Array.from(args[0]);
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
29
|
+
return args.map((x) => (typeof x == 'number' ? x : (x as string).charCodeAt(0)));
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* 将数字或字符串转换为 Uint8Array
|
|
33
|
-
* @param
|
|
34
|
-
* @returns
|
|
34
|
+
* @param args 数字或 char 的数组
|
|
35
|
+
* @returns Uint8Array
|
|
35
36
|
*/
|
|
36
|
-
export function toBuffer(...args) {
|
|
37
|
+
export function toBuffer(...args: Array<string | number>): Uint8Array<ArrayBuffer> {
|
|
37
38
|
const data = [];
|
|
38
39
|
for (const x of args) {
|
|
39
40
|
if (typeof x == 'number') {
|
package/tests/decode.ts
CHANGED
|
@@ -141,6 +141,7 @@ test('decode huge string (unexpected eof) [error]', () => {
|
|
|
141
141
|
|
|
142
142
|
test('decode ascii string', () => {
|
|
143
143
|
const header = toBuffer('S', 'I', 0x3f, 0xff);
|
|
144
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
144
145
|
const payload = new Uint8Array(0x3fff + header.byteLength).fill('a'.charCodeAt(0));
|
|
145
146
|
payload.set(header);
|
|
146
147
|
expect(decode(payload)).toBe('a'.repeat(0x3fff));
|
|
@@ -148,6 +149,7 @@ test('decode ascii string', () => {
|
|
|
148
149
|
|
|
149
150
|
test('decode ascii string [huge]', () => {
|
|
150
151
|
const header = toBuffer('S', 'I', 0x7f, 0xff);
|
|
152
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
151
153
|
const payload = new Uint8Array(0x7fff + header.byteLength).fill('a'.charCodeAt(0));
|
|
152
154
|
payload.set(header);
|
|
153
155
|
expect(decode(payload)).toBe('a'.repeat(0x7fff));
|
|
@@ -507,19 +509,16 @@ test('decode (eof at key)', () => {
|
|
|
507
509
|
|
|
508
510
|
describe('proto poisoning attack', () => {
|
|
509
511
|
it('should remove __proto__ key', () => {
|
|
510
|
-
const obj =
|
|
512
|
+
const obj = decode(
|
|
511
513
|
toBuffer('{', 'i', 9, '__proto__', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'),
|
|
512
|
-
)
|
|
514
|
+
) as Record<string, unknown>;
|
|
513
515
|
expect(Object.hasOwn(obj, '__proto__')).toBe(false);
|
|
514
516
|
expect(obj['__proto__']).toBe(Object.prototype);
|
|
515
517
|
});
|
|
516
518
|
it('should allow __proto__ key', () => {
|
|
517
|
-
const obj =
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
protoAction: 'allow',
|
|
521
|
-
},
|
|
522
|
-
);
|
|
519
|
+
const obj = decode(toBuffer('{', 'i', 9, '__proto__', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'), {
|
|
520
|
+
protoAction: 'allow',
|
|
521
|
+
}) as Record<string, unknown>;
|
|
523
522
|
expect(Object.hasOwn(obj, '__proto__')).toBe(true);
|
|
524
523
|
expect(obj['__proto__']).toEqual({ a: 'abc' });
|
|
525
524
|
});
|
|
@@ -534,19 +533,16 @@ describe('proto poisoning attack', () => {
|
|
|
534
533
|
|
|
535
534
|
describe('constructor poisoning attack', () => {
|
|
536
535
|
it('should remove constructor key', () => {
|
|
537
|
-
const obj =
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
constructorAction: 'remove',
|
|
541
|
-
},
|
|
542
|
-
);
|
|
536
|
+
const obj = decode(toBuffer('{', 'i', 11, 'constructor', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'), {
|
|
537
|
+
constructorAction: 'remove',
|
|
538
|
+
}) as Record<string, unknown>;
|
|
543
539
|
expect(Object.hasOwn(obj, 'constructor')).toBe(false);
|
|
544
540
|
expect(obj.constructor).toBe(Object);
|
|
545
541
|
});
|
|
546
542
|
it('should allow constructor key', () => {
|
|
547
|
-
const obj =
|
|
543
|
+
const obj = decode(
|
|
548
544
|
toBuffer('{', 'i', 11, 'constructor', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'),
|
|
549
|
-
)
|
|
545
|
+
) as Record<string, unknown>;
|
|
550
546
|
expect(Object.hasOwn(obj, 'constructor')).toBe(true);
|
|
551
547
|
expect(obj.constructor).toEqual({ a: 'abc' });
|
|
552
548
|
});
|
package/tests/e2e/stream.ts
CHANGED
|
@@ -8,15 +8,15 @@ describe('stream', () => {
|
|
|
8
8
|
const expected = EXPECTED[name] ?? input;
|
|
9
9
|
if (expected instanceof Error) {
|
|
10
10
|
await expect(async () => {
|
|
11
|
-
const encoded = await Readable.fromWeb(
|
|
11
|
+
const encoded = await Readable.fromWeb(encodeStream(input) as never).toArray();
|
|
12
12
|
const decoded = await decodeStream(
|
|
13
|
-
|
|
13
|
+
Readable.toWeb(Readable.from(encoded)) as ReadableStream<Uint8Array<ArrayBuffer>>,
|
|
14
14
|
);
|
|
15
15
|
expect(decoded).toEqual(expected);
|
|
16
16
|
}).rejects.toThrow(expected);
|
|
17
17
|
} else {
|
|
18
|
-
const encoded = await Readable.fromWeb(
|
|
19
|
-
const data = encoded.flatMap((
|
|
18
|
+
const encoded = await Readable.fromWeb(encodeStream(input) as never).toArray();
|
|
19
|
+
const data = encoded.flatMap((chunk: Buffer<ArrayBuffer>) => {
|
|
20
20
|
if (chunk.length < 2) return [chunk];
|
|
21
21
|
// split to random chunks
|
|
22
22
|
const chunks = [];
|
|
@@ -29,7 +29,7 @@ describe('stream', () => {
|
|
|
29
29
|
return chunks;
|
|
30
30
|
});
|
|
31
31
|
const decoded = await decodeStream(
|
|
32
|
-
|
|
32
|
+
Readable.toWeb(Readable.from(data)) as ReadableStream<Uint8Array<ArrayBuffer>>,
|
|
33
33
|
);
|
|
34
34
|
expect(decoded).toEqual(expected);
|
|
35
35
|
}
|
package/tests/encode.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { getEncoder } from '../dist/encoder.js';
|
|
|
7
7
|
import { toArray } from './.utils.ts';
|
|
8
8
|
|
|
9
9
|
// @ts-expect-error Access private property
|
|
10
|
-
const poolInit = getEncoder().pool
|
|
10
|
+
const poolInit = getEncoder().pool as Uint8Array<ArrayBuffer>;
|
|
11
11
|
|
|
12
12
|
test('encode function', () => {
|
|
13
13
|
expect(() =>
|
|
@@ -444,10 +444,10 @@ test('encode object (only null values)', () => {
|
|
|
444
444
|
});
|
|
445
445
|
|
|
446
446
|
test('encode object (skip prototype)', () => {
|
|
447
|
-
const obj = Object.create({ a: 2, x: 'xx' })
|
|
448
|
-
obj
|
|
449
|
-
obj
|
|
450
|
-
obj
|
|
447
|
+
const obj = Object.create({ a: 2, x: 'xx' }) as Record<string, unknown>;
|
|
448
|
+
obj['a'] = 1;
|
|
449
|
+
obj['b'] = 'a';
|
|
450
|
+
obj['c'] = true;
|
|
451
451
|
expect(toArray(encode(obj))).toEqual(
|
|
452
452
|
toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'C', 'a', 'i', 1, 'c', 'T', '}'),
|
|
453
453
|
);
|
package/tests/huge-string.ts
CHANGED
|
@@ -6,11 +6,8 @@ const STR_BYTE_LENGTH = 128 * 1024 * 1024 - 20;
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* 构造测试字符串
|
|
9
|
-
* @param {string} char 使用的字符
|
|
10
|
-
* @param {number} byteLength 需要的长度
|
|
11
|
-
* @returns {[Uint8Array, string]}
|
|
12
9
|
*/
|
|
13
|
-
function makeString(char, byteLength) {
|
|
10
|
+
function makeString(char: string, byteLength: number): [Uint8Array<ArrayBuffer>, string] {
|
|
14
11
|
const encoded = new TextEncoder().encode(char);
|
|
15
12
|
return [encoded, char.repeat(byteLength / encoded.byteLength)];
|
|
16
13
|
}
|
package/tests/rxjs/decode.ts
CHANGED
|
@@ -2,28 +2,24 @@
|
|
|
2
2
|
* Tests from https://bitbucket.org/shelacek/ubjson
|
|
3
3
|
*/
|
|
4
4
|
import { jest } from '@jest/globals';
|
|
5
|
-
import { firstValueFrom, of, Subject } from 'rxjs';
|
|
5
|
+
import { firstValueFrom, type Observable, of, Subject } from 'rxjs';
|
|
6
6
|
import { decode as decodePipe } from '../../dist/rxjs/index.js';
|
|
7
7
|
import { toBuffer } from '../.utils.ts';
|
|
8
8
|
import { UnexpectedEofError as UnexpectedEof } from '../../dist/helper/errors.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* 包装为 promise
|
|
12
|
-
* @param {Uint8Array} data ubjson 数据
|
|
13
|
-
* @returns {Promise<unknown>}
|
|
14
12
|
*/
|
|
15
|
-
async function decode(data) {
|
|
13
|
+
async function decode(data: BufferSource): Promise<unknown> {
|
|
16
14
|
const readable = of(data);
|
|
17
15
|
return firstValueFrom(readable.pipe(decodePipe()), { defaultValue: undefined });
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
/**
|
|
21
19
|
* 包装为 promise
|
|
22
|
-
* @param {import("rxjs").Observable<Uint8Array>} observable ubjson 数据流
|
|
23
|
-
* @param {(data: unknown) => void} onData 数据回调
|
|
24
20
|
*/
|
|
25
|
-
async function decodeStream(observable
|
|
26
|
-
return
|
|
21
|
+
async function decodeStream(observable: Observable<BufferSource>, onData: (data: unknown) => void) {
|
|
22
|
+
return new Promise<void>((resolve, reject) => {
|
|
27
23
|
observable.pipe(decodePipe()).subscribe({
|
|
28
24
|
next: onData,
|
|
29
25
|
error: reject,
|
|
@@ -115,6 +111,7 @@ test('decode string (unexpected eof) [error]', async () => {
|
|
|
115
111
|
|
|
116
112
|
test('decode ascii string', async () => {
|
|
117
113
|
const header = toBuffer('S', 'I', 0x3f, 0xff);
|
|
114
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
118
115
|
const payload = new Uint8Array(0x3fff + header.byteLength).fill('a'.charCodeAt(0));
|
|
119
116
|
payload.set(header);
|
|
120
117
|
expect(await decode(payload)).toBe('a'.repeat(0x3fff));
|
|
@@ -123,6 +120,7 @@ test('decode ascii string', async () => {
|
|
|
123
120
|
test('decode ascii string 32kiB [huge]', async () => {
|
|
124
121
|
const size = 0x7fff;
|
|
125
122
|
const header = toBuffer('S', 'I', 0x7f, 0xff);
|
|
123
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
126
124
|
const payload = new Uint8Array(size + header.byteLength).fill('a'.charCodeAt(0));
|
|
127
125
|
payload.set(header);
|
|
128
126
|
expect(await decode(payload)).toBe('a'.repeat(size));
|
|
@@ -131,6 +129,7 @@ test('decode ascii string 32kiB [huge]', async () => {
|
|
|
131
129
|
test('decode ascii string 64MB [huge]', async () => {
|
|
132
130
|
const size = 0x03d0_9000;
|
|
133
131
|
const header = toBuffer('S', 'l', 0x03, 0xd0, 0x90, 0x00);
|
|
132
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
134
133
|
const payload = new Uint8Array(size + header.byteLength).fill('a'.charCodeAt(0));
|
|
135
134
|
payload.set(header);
|
|
136
135
|
expect(await decode(payload)).toBe('a'.repeat(size));
|
|
@@ -467,7 +466,7 @@ test('decode object (empty key, optimized)', async () => {
|
|
|
467
466
|
});
|
|
468
467
|
|
|
469
468
|
test('decode stream', async () => {
|
|
470
|
-
const stream = new Subject();
|
|
469
|
+
const stream = new Subject<BufferSource>();
|
|
471
470
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
472
471
|
const onData = jest.fn();
|
|
473
472
|
const result = decodeStream(stream, onData);
|
|
@@ -485,7 +484,7 @@ test('decode stream', async () => {
|
|
|
485
484
|
});
|
|
486
485
|
|
|
487
486
|
test('decode bad stream [error]', async () => {
|
|
488
|
-
const stream = new Subject();
|
|
487
|
+
const stream = new Subject<BufferSource>();
|
|
489
488
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
490
489
|
const onData = jest.fn();
|
|
491
490
|
const result = decodeStream(stream, onData);
|
|
@@ -504,7 +503,7 @@ test('decode bad stream [error]', async () => {
|
|
|
504
503
|
});
|
|
505
504
|
|
|
506
505
|
test('decode partial stream [error]', async () => {
|
|
507
|
-
const stream = new Subject();
|
|
506
|
+
const stream = new Subject<BufferSource>();
|
|
508
507
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
509
508
|
const onData = jest.fn();
|
|
510
509
|
const result = decodeStream(stream, onData);
|
|
@@ -520,7 +519,7 @@ test('decode partial stream [error]', async () => {
|
|
|
520
519
|
});
|
|
521
520
|
|
|
522
521
|
test('decode error stream [error]', async () => {
|
|
523
|
-
const stream = new Subject();
|
|
522
|
+
const stream = new Subject<BufferSource>();
|
|
524
523
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
525
524
|
const onData = jest.fn();
|
|
526
525
|
const result = decodeStream(stream, onData);
|
package/tests/rxjs/encode.ts
CHANGED
|
@@ -8,10 +8,8 @@ import { toArray } from '../.utils.ts';
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 包装为 promise
|
|
11
|
-
* @param {unknown} value 要编码的值
|
|
12
|
-
* @returns {Promise<Buffer>}
|
|
13
11
|
*/
|
|
14
|
-
async function encodeAsync(value) {
|
|
12
|
+
async function encodeAsync(value: unknown): Promise<Buffer<ArrayBuffer>> {
|
|
15
13
|
return firstValueFrom(
|
|
16
14
|
of(value).pipe(
|
|
17
15
|
encode(),
|
|
@@ -304,7 +302,7 @@ test('encode object (only null values)', async () => {
|
|
|
304
302
|
});
|
|
305
303
|
|
|
306
304
|
test('encode object (skip prototype)', async () => {
|
|
307
|
-
const obj =
|
|
305
|
+
const obj = Object.create({ a: 2, x: 'xx' }) as Record<string, unknown>;
|
|
308
306
|
obj['a'] = 1;
|
|
309
307
|
obj['b'] = 'a';
|
|
310
308
|
obj['c'] = true;
|
package/tests/stream/decode.ts
CHANGED
|
@@ -9,20 +9,16 @@ import { UnexpectedEofError as UnexpectedEof } from '../../dist/helper/errors.js
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* 包装为 promise
|
|
12
|
-
* @param {Uint8Array} data ubjson 数据
|
|
13
|
-
* @returns {Promise<unknown>}
|
|
14
12
|
*/
|
|
15
|
-
async function decode(data) {
|
|
13
|
+
async function decode(data: Uint8Array<ArrayBuffer>): Promise<unknown> {
|
|
16
14
|
const readable = Readable.from([data], { objectMode: false });
|
|
17
|
-
return decodeAsync(
|
|
15
|
+
return decodeAsync(Readable.toWeb(readable) as ReadableStream<Uint8Array<ArrayBuffer>>);
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
/**
|
|
21
19
|
* 包装为 promise
|
|
22
|
-
* @param {import("stream").Readable} stream ubjson 流
|
|
23
|
-
* @returns {Promise<void>}
|
|
24
20
|
*/
|
|
25
|
-
async function eos(stream) {
|
|
21
|
+
async function eos(stream: Readable): Promise<void> {
|
|
26
22
|
return new Promise((resolve, reject) => {
|
|
27
23
|
stream.on('error', reject);
|
|
28
24
|
stream.on('end', resolve);
|
|
@@ -113,6 +109,7 @@ test('decode string (unexpected eof) [error]', async () => {
|
|
|
113
109
|
|
|
114
110
|
test('decode ascii string', async () => {
|
|
115
111
|
const header = toBuffer('S', 'I', 0x3f, 0xff);
|
|
112
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
116
113
|
const payload = new Uint8Array(0x3fff + header.byteLength).fill('a'.charCodeAt(0));
|
|
117
114
|
payload.set(header);
|
|
118
115
|
expect(await decode(payload)).toBe('a'.repeat(0x3fff));
|
|
@@ -120,6 +117,7 @@ test('decode ascii string', async () => {
|
|
|
120
117
|
|
|
121
118
|
test('decode ascii string [huge]', async () => {
|
|
122
119
|
const header = toBuffer('S', 'I', 0x7f, 0xff);
|
|
120
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
123
121
|
const payload = new Uint8Array(0x7fff + header.byteLength).fill('a'.charCodeAt(0));
|
|
124
122
|
payload.set(header);
|
|
125
123
|
expect(await decode(payload)).toBe('a'.repeat(0x7fff));
|
|
@@ -456,7 +454,7 @@ test('decode object (empty key, optimized)', async () => {
|
|
|
456
454
|
});
|
|
457
455
|
|
|
458
456
|
test('decode stream', async () => {
|
|
459
|
-
const stream = Transform.fromWeb(
|
|
457
|
+
const stream = Transform.fromWeb(decodeStream() as never, { objectMode: true });
|
|
460
458
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
461
459
|
const onData = jest.fn();
|
|
462
460
|
stream.on('data', onData);
|
|
@@ -499,7 +497,7 @@ test('decode bad stream [error]', async () => {
|
|
|
499
497
|
});
|
|
500
498
|
|
|
501
499
|
test('decode partial stream [error]', async () => {
|
|
502
|
-
const stream = Transform.fromWeb(
|
|
500
|
+
const stream = Transform.fromWeb(decodeStream() as never, { objectMode: true });
|
|
503
501
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
504
502
|
const onData = jest.fn();
|
|
505
503
|
stream.on('data', onData);
|
package/tests/stream/encode.ts
CHANGED
|
@@ -9,11 +9,9 @@ import { Transform } from 'node:stream';
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* 包装为 promise
|
|
12
|
-
* @param {unknown} value 值
|
|
13
|
-
* @returns {Promise<Buffer>} 返回值
|
|
14
12
|
*/
|
|
15
|
-
async function encodeAsync(value) {
|
|
16
|
-
return buffer(encode(value))
|
|
13
|
+
async function encodeAsync(value: unknown): Promise<Buffer<ArrayBuffer>> {
|
|
14
|
+
return (await buffer(encode(value))) as Buffer<ArrayBuffer>;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
test('encode function', async () => {
|
|
@@ -299,10 +297,10 @@ test('encode object (only null values)', async () => {
|
|
|
299
297
|
});
|
|
300
298
|
|
|
301
299
|
test('encode object (skip prototype)', async () => {
|
|
302
|
-
const obj = Object.create({ a: 2, x: 'xx' })
|
|
303
|
-
obj
|
|
304
|
-
obj
|
|
305
|
-
obj
|
|
300
|
+
const obj = Object.create({ a: 2, x: 'xx' }) as Record<string, unknown>;
|
|
301
|
+
obj['a'] = 1;
|
|
302
|
+
obj['b'] = 'a';
|
|
303
|
+
obj['c'] = true;
|
|
306
304
|
expect(toArray(await encodeAsync(obj))).toEqual(
|
|
307
305
|
toArray('{', 'i', 1, 'a', 'U', 1, 'i', 1, 'b', 'C', 'a', 'i', 1, 'c', 'T', '}'),
|
|
308
306
|
);
|
|
@@ -364,7 +362,7 @@ test('encode huge data (~128M)', async () => {
|
|
|
364
362
|
});
|
|
365
363
|
|
|
366
364
|
test('encode stream', async () => {
|
|
367
|
-
const stream = Transform.fromWeb(
|
|
365
|
+
const stream = Transform.fromWeb(encoder() as never, { objectMode: true });
|
|
368
366
|
stream.write(undefined);
|
|
369
367
|
stream.write(true);
|
|
370
368
|
stream.write(false);
|
package/tests/stream/many.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
|
+
import type { ReadableStream as ReadableStream2 } from 'node:stream/web';
|
|
2
3
|
import { encodeMany, decodeMany } from '../../dist/stream/index.js';
|
|
3
4
|
import { buffer } from 'node:stream/consumers';
|
|
4
5
|
import { finished } from 'node:stream/promises';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* iterableToAsyncIterable
|
|
8
|
-
* @template T
|
|
9
|
-
* @param {Iterable<T>} iterable - iterable
|
|
10
|
-
* @returns {AsyncIterable<T>} async iterable
|
|
11
9
|
*/
|
|
12
|
-
function iterableToAsyncIterable(iterable) {
|
|
10
|
+
function iterableToAsyncIterable<T>(iterable: Iterable<T>): AsyncIterable<T> {
|
|
13
11
|
return {
|
|
14
12
|
[Symbol.asyncIterator]: () => {
|
|
15
13
|
const iterator = iterable[Symbol.iterator]();
|
|
@@ -23,12 +21,9 @@ function iterableToAsyncIterable(iterable) {
|
|
|
23
21
|
|
|
24
22
|
/**
|
|
25
23
|
* asyncIterableToArray
|
|
26
|
-
* @template T
|
|
27
|
-
* @param {AsyncIterable<T>} asyncIterable - async iterable
|
|
28
|
-
* @returns {Promise<Array<T>>} array
|
|
29
24
|
*/
|
|
30
|
-
async function asyncIterableToArray(asyncIterable) {
|
|
31
|
-
const array = [];
|
|
25
|
+
async function asyncIterableToArray<T>(asyncIterable: AsyncIterable<T>): Promise<T[]> {
|
|
26
|
+
const array: T[] = [];
|
|
32
27
|
for await (const item of asyncIterable) {
|
|
33
28
|
array.push(item);
|
|
34
29
|
}
|
|
@@ -53,7 +48,7 @@ test('encode/decode many', async () => {
|
|
|
53
48
|
];
|
|
54
49
|
const encoded = await buffer(encodeMany(iterableToAsyncIterable(data)));
|
|
55
50
|
const decoded = await asyncIterableToArray(
|
|
56
|
-
decodeMany(
|
|
51
|
+
decodeMany(Readable.toWeb(Readable.from([encoded])) as ReadableStream<Uint8Array<ArrayBuffer>>),
|
|
57
52
|
);
|
|
58
53
|
expect(decoded).toEqual([
|
|
59
54
|
{
|
|
@@ -74,7 +69,7 @@ test('encode/decode many', async () => {
|
|
|
74
69
|
|
|
75
70
|
test('encode/decode many with invalid value', async () => {
|
|
76
71
|
await expect(async () => {
|
|
77
|
-
const readable = Readable.fromWeb(
|
|
72
|
+
const readable = Readable.fromWeb(encodeMany(iterableToAsyncIterable([1, () => 1])) as ReadableStream2);
|
|
78
73
|
const f = finished(readable);
|
|
79
74
|
readable.resume();
|
|
80
75
|
await f;
|
|
@@ -82,31 +77,25 @@ test('encode/decode many with invalid value', async () => {
|
|
|
82
77
|
});
|
|
83
78
|
|
|
84
79
|
test('encode/decode many with error', async () => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// }
|
|
98
|
-
// await f;
|
|
99
|
-
// } catch (ex) {
|
|
100
|
-
// console.log(ex);
|
|
101
|
-
// }
|
|
102
|
-
// }).rejects.toThrow('xx');
|
|
80
|
+
await expect(async () => {
|
|
81
|
+
const stream = encodeMany(
|
|
82
|
+
(async function* () {
|
|
83
|
+
yield 1;
|
|
84
|
+
await Promise.resolve();
|
|
85
|
+
throw new Error('test error');
|
|
86
|
+
})(),
|
|
87
|
+
);
|
|
88
|
+
for await (const _ of stream) {
|
|
89
|
+
//
|
|
90
|
+
}
|
|
91
|
+
}).rejects.toThrow('test error');
|
|
103
92
|
});
|
|
104
93
|
|
|
105
94
|
test('encode/decode many with undefined', async () => {
|
|
106
95
|
const data = [1, null, undefined, [undefined]];
|
|
107
96
|
const encoded = await buffer(encodeMany(iterableToAsyncIterable(data)));
|
|
108
97
|
const decoded = await asyncIterableToArray(
|
|
109
|
-
decodeMany(
|
|
98
|
+
decodeMany(Readable.toWeb(Readable.from([encoded])) as ReadableStream<Uint8Array<ArrayBuffer>>),
|
|
110
99
|
);
|
|
111
100
|
expect(decoded).toEqual([
|
|
112
101
|
1,
|
package/tests/string-encoding.ts
CHANGED
|
@@ -2,11 +2,9 @@ import { Encoder } from '../dist/encoder.js';
|
|
|
2
2
|
import { decode, jsDecode } from '../dist/helper/string-decoder.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* @param {Pick<TextEncoder, 'encode'>} encoder encoder
|
|
7
|
-
* @param {Pick<TextDecoder, 'decode'>} decoder decoder
|
|
5
|
+
* 测试编码器和解码器
|
|
8
6
|
*/
|
|
9
|
-
function testEncoding(encoder, decoder) {
|
|
7
|
+
function testEncoding(encoder: Pick<TextEncoder, 'encode'>, decoder: Pick<TextDecoder, 'decode'>) {
|
|
10
8
|
expect(decoder.decode(encoder.encode(''))).toEqual('');
|
|
11
9
|
expect(decoder.decode(encoder.encode('a'))).toEqual('a');
|
|
12
10
|
expect(decoder.decode(encoder.encode('p4'))).toEqual('p4');
|
|
@@ -46,6 +44,7 @@ function testEncoding(encoder, decoder) {
|
|
|
46
44
|
bad.fill(0xff);
|
|
47
45
|
expect(decoder.decode(bad)).toEqual('\uFFFD'.repeat(length));
|
|
48
46
|
|
|
47
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
49
48
|
bad.fill('a'.charCodeAt(0), 0, length - 1);
|
|
50
49
|
expect(decoder.decode(bad)).toEqual('a'.repeat(length - 1) + '\uFFFD');
|
|
51
50
|
}
|
|
@@ -55,6 +54,7 @@ function testEncoding(encoder, decoder) {
|
|
|
55
54
|
for (let index = 0; index < 0xffff; index++) {
|
|
56
55
|
// 跳过 Surrogate
|
|
57
56
|
if (index >= 0xd800 && index <= 0xdfff) continue;
|
|
57
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
58
58
|
const expected = String.fromCharCode(index);
|
|
59
59
|
const encoded = encoder.encode(expected);
|
|
60
60
|
const actual = decoder.decode(encoded);
|
|
@@ -77,6 +77,7 @@ function testEncoding(encoder, decoder) {
|
|
|
77
77
|
// 检查所有 2 字节 ASCII
|
|
78
78
|
for (let index = 0; index < 0x80; index++) {
|
|
79
79
|
for (let index2 = 0; index2 < 0x80; index2++) {
|
|
80
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
80
81
|
const expected = String.fromCharCode(index, index2);
|
|
81
82
|
const actual = decoder.decode(encoder.encode(expected));
|
|
82
83
|
if (expected !== actual) expect(actual).toEqual(expected);
|
|
@@ -121,6 +122,8 @@ test('decode string js', () => {
|
|
|
121
122
|
});
|
|
122
123
|
|
|
123
124
|
test('decode malformed', () => {
|
|
125
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
124
126
|
expect(decode(new Uint8Array([0xff, 'a'.charCodeAt(0)]), 0, 2)).toEqual('\uFFFDa');
|
|
127
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
125
128
|
expect(jsDecode(new Uint8Array([0xff, 'a'.charCodeAt(0)]), 0, 2)).toEqual('\uFFFDa');
|
|
126
129
|
});
|