@cloudpss/ubjson 0.5.55 → 0.6.0-alpha.10
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/dist/base/decoder.js +2 -5
- package/dist/base/decoder.js.map +1 -1
- package/dist/base/encoder.js +6 -8
- package/dist/base/encoder.js.map +1 -1
- package/dist/encoder.js +8 -5
- package/dist/encoder.js.map +1 -1
- package/dist/helper/encode.d.ts.map +1 -1
- package/dist/helper/encode.js +5 -2
- package/dist/helper/encode.js.map +1 -1
- package/dist/helper/string-decoder.d.ts +2 -0
- package/dist/helper/string-decoder.d.ts.map +1 -1
- package/dist/helper/string-decoder.js +16 -4
- package/dist/helper/string-decoder.js.map +1 -1
- package/dist/helper/string-encoder.d.ts +5 -0
- package/dist/helper/string-encoder.d.ts.map +1 -1
- package/dist/helper/string-encoder.js +28 -8
- package/dist/helper/string-encoder.js.map +1 -1
- package/dist/stream/decoder.js +0 -2
- package/dist/stream/decoder.js.map +1 -1
- package/dist/stream/encoder.js +0 -2
- package/dist/stream/encoder.js.map +1 -1
- package/dist/stream-helper/encoder.js +0 -1
- package/dist/stream-helper/encoder.js.map +1 -1
- package/package.json +2 -2
- package/src/helper/encode.ts +5 -2
- package/src/helper/string-decoder.ts +22 -6
- package/src/helper/string-encoder.ts +35 -8
- package/tests/{.utils.js → .utils.ts} +9 -8
- package/tests/{decode.js → decode.ts} +15 -17
- package/tests/e2e/{.data.js → .data.ts} +2 -4
- package/tests/e2e/{no-buffer-text.js → no-buffer-text.ts} +2 -2
- package/tests/e2e/{no-buffer.js → no-buffer.ts} +2 -2
- package/tests/e2e/{no-encode-into.js → no-encode-into.ts} +2 -2
- package/tests/e2e/{no-textencoder-decoder.js → no-textencoder-decoder.ts} +2 -2
- package/tests/e2e/{normal.js → normal.ts} +1 -1
- package/tests/e2e/{stream.js → stream.ts} +6 -6
- package/tests/{encode.js → encode.ts} +6 -6
- package/tests/{huge-string.js → huge-string.ts} +2 -5
- package/tests/rxjs/{decode.js → decode.ts} +18 -21
- package/tests/rxjs/{encode.js → encode.ts} +3 -5
- package/tests/stream/{decode.js → decode.ts} +8 -10
- package/tests/stream/{encode.js → encode.ts} +8 -10
- package/tests/stream/{many.js → many.ts} +19 -30
- package/tests/{string-encoding.js → string-encoding.ts} +7 -4
- package/jest.config.js +0 -3
- package/tests/tsconfig.json +0 -3
- package/tsconfig.json +0 -7
- /package/tests/{many.js → many.ts} +0 -0
|
@@ -114,12 +114,32 @@ export function nativeEncodeInto(v: string, buf: Uint8Array, offset: number): nu
|
|
|
114
114
|
const encoded = TEXT_ENCODER!.encodeInto(v, buf.subarray(offset));
|
|
115
115
|
return encoded.written;
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
/** Undocumented */
|
|
119
|
+
type BufferUndocumented = Buffer & {
|
|
120
|
+
utf8Write: (this: Uint8Array, v: string, offset: number, byteLength: number) => number;
|
|
121
|
+
};
|
|
122
|
+
let utf8Write: ((this: Uint8Array, v: string, offset: number, byteLength: number) => number) | null;
|
|
123
|
+
/**
|
|
124
|
+
* Encode string into utf-8.
|
|
125
|
+
* Provided `buf` MUST have enough space.
|
|
126
|
+
*/
|
|
127
|
+
export function nodeEncodeInto(v: string, buf: Uint8Array, offset: number): number {
|
|
128
|
+
const encoded = utf8Write!.call(buf, v, offset, buf.byteLength - offset);
|
|
129
|
+
return encoded;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 默认编码器阈值
|
|
134
|
+
* @see /benchmark/string-encoder.js
|
|
135
|
+
*/
|
|
136
|
+
const DEFAULT_TEXT_ENCODER_THRESHOLD = 45;
|
|
117
137
|
/**
|
|
118
138
|
* Encode string into utf-8.
|
|
119
139
|
* Provided `buf` MUST have enough space.
|
|
120
140
|
*/
|
|
121
141
|
export function myEncodeInto(v: string, buf: Uint8Array, offset: number): number {
|
|
122
|
-
if (v.length <
|
|
142
|
+
if (v.length < DEFAULT_TEXT_ENCODER_THRESHOLD) {
|
|
123
143
|
return jsEncodeInto(v, buf, offset);
|
|
124
144
|
}
|
|
125
145
|
return nativeEncodeInto(v, buf, offset);
|
|
@@ -137,14 +157,21 @@ export let encode: (v: string) => Uint8Array<ArrayBuffer>;
|
|
|
137
157
|
/** 重设环境 */
|
|
138
158
|
export function resetEnv(): void {
|
|
139
159
|
TEXT_ENCODER = typeof TextEncoder == 'function' ? new TextEncoder() : null;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
encodeInto =
|
|
160
|
+
const hasBuffer = typeof Buffer == 'function';
|
|
161
|
+
stringByteLength = hasBuffer && typeof Buffer.byteLength == 'function' ? nodeStringByteLength : jsStringByteLength;
|
|
162
|
+
|
|
163
|
+
utf8Write = hasBuffer ? (Buffer.prototype as BufferUndocumented).utf8Write : null;
|
|
164
|
+
encodeInto =
|
|
165
|
+
typeof utf8Write == 'function'
|
|
166
|
+
? nodeEncodeInto
|
|
167
|
+
: typeof TEXT_ENCODER?.encodeInto == 'function'
|
|
168
|
+
? myEncodeInto
|
|
169
|
+
: jsEncodeInto;
|
|
170
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
171
|
+
const from = hasBuffer ? Buffer.from : null;
|
|
145
172
|
encode =
|
|
146
|
-
typeof
|
|
147
|
-
? (v) =>
|
|
173
|
+
typeof from == 'function'
|
|
174
|
+
? (v) => from(v, 'utf8')
|
|
148
175
|
: TEXT_ENCODER
|
|
149
176
|
? (v) => TEXT_ENCODER!.encode(v)
|
|
150
177
|
: (v) => {
|
|
@@ -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') {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { decode, UnexpectedEof } from '../dist/index.js';
|
|
6
|
-
import { toBuffer } from './.utils.
|
|
6
|
+
import { toBuffer } from './.utils.ts';
|
|
7
7
|
|
|
8
8
|
test('decode unsupported type', () => {
|
|
9
9
|
expect(() => decode(toBuffer('!'))).toThrow();
|
|
@@ -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,18 +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 =
|
|
511
|
-
|
|
512
|
-
)
|
|
512
|
+
const obj = decode(
|
|
513
|
+
toBuffer('{', 'i', 9, '__proto__', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'),
|
|
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
|
-
})
|
|
521
|
-
);
|
|
519
|
+
const obj = decode(toBuffer('{', 'i', 9, '__proto__', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'), {
|
|
520
|
+
protoAction: 'allow',
|
|
521
|
+
}) as Record<string, unknown>;
|
|
522
522
|
expect(Object.hasOwn(obj, '__proto__')).toBe(true);
|
|
523
523
|
expect(obj['__proto__']).toEqual({ a: 'abc' });
|
|
524
524
|
});
|
|
@@ -533,18 +533,16 @@ describe('proto poisoning attack', () => {
|
|
|
533
533
|
|
|
534
534
|
describe('constructor poisoning attack', () => {
|
|
535
535
|
it('should remove constructor key', () => {
|
|
536
|
-
const obj =
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
})
|
|
540
|
-
);
|
|
536
|
+
const obj = decode(toBuffer('{', 'i', 11, 'constructor', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'), {
|
|
537
|
+
constructorAction: 'remove',
|
|
538
|
+
}) as Record<string, unknown>;
|
|
541
539
|
expect(Object.hasOwn(obj, 'constructor')).toBe(false);
|
|
542
540
|
expect(obj.constructor).toBe(Object);
|
|
543
541
|
});
|
|
544
542
|
it('should allow constructor key', () => {
|
|
545
|
-
const obj =
|
|
546
|
-
|
|
547
|
-
)
|
|
543
|
+
const obj = decode(
|
|
544
|
+
toBuffer('{', 'i', 11, 'constructor', '{', 'i', 1, 'a', 'S', 'i', 3, 'abc', '}', '}'),
|
|
545
|
+
) as Record<string, unknown>;
|
|
548
546
|
expect(Object.hasOwn(obj, 'constructor')).toBe(true);
|
|
549
547
|
expect(obj.constructor).toEqual({ a: 'abc' });
|
|
550
548
|
});
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export const
|
|
3
|
-
/** @type {Record<string, unknown>} */
|
|
4
|
-
export const EXPECTED = {};
|
|
1
|
+
export const INPUTS: Record<string, unknown> = {};
|
|
2
|
+
export const EXPECTED: Record<string, unknown> = {};
|
|
5
3
|
|
|
6
4
|
INPUTS['number 0'] = 0;
|
|
7
5
|
INPUTS['number 1'] = 1;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resetEnv } from '../.utils.
|
|
2
|
-
import { INPUTS, EXPECTED } from './.data.
|
|
1
|
+
import { resetEnv } from '../.utils.ts';
|
|
2
|
+
import { INPUTS, EXPECTED } from './.data.ts';
|
|
3
3
|
import { encode, decode } from '../../dist/index.js';
|
|
4
4
|
|
|
5
5
|
describe('no Buffer and no textencoder/decoder', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resetEnv } from '../.utils.
|
|
2
|
-
import { INPUTS, EXPECTED } from './.data.
|
|
1
|
+
import { resetEnv } from '../.utils.ts';
|
|
2
|
+
import { INPUTS, EXPECTED } from './.data.ts';
|
|
3
3
|
import { encode, decode } from '../../dist/index.js';
|
|
4
4
|
|
|
5
5
|
describe('no Buffer', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resetEnv } from '../.utils.
|
|
2
|
-
import { INPUTS, EXPECTED } from './.data.
|
|
1
|
+
import { resetEnv } from '../.utils.ts';
|
|
2
|
+
import { INPUTS, EXPECTED } from './.data.ts';
|
|
3
3
|
import { encode, decode } from '../../dist/index.js';
|
|
4
4
|
|
|
5
5
|
describe('no encodeInto', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resetEnv } from '../.utils.
|
|
2
|
-
import { INPUTS, EXPECTED } from './.data.
|
|
1
|
+
import { resetEnv } from '../.utils.ts';
|
|
2
|
+
import { INPUTS, EXPECTED } from './.data.ts';
|
|
3
3
|
import { encode, decode } from '../../dist/index.js';
|
|
4
4
|
|
|
5
5
|
describe('no textencoder/decoder', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
2
|
import { encode as encodeStream, decode as decodeStream } from '../../dist/stream/index.js';
|
|
3
|
-
import { EXPECTED, INPUTS } from './.data.
|
|
3
|
+
import { EXPECTED, INPUTS } from './.data.ts';
|
|
4
4
|
|
|
5
5
|
describe('stream', () => {
|
|
6
6
|
it.each(Object.keys(INPUTS))('%s', async (name) => {
|
|
@@ -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
|
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { encode, decode } from '../dist/index.js';
|
|
6
6
|
import { getEncoder } from '../dist/encoder.js';
|
|
7
|
-
import { toArray } from './.utils.
|
|
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
|
);
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { encode } from '../dist/index.js';
|
|
3
|
-
import { toArray, resetEnv } from './.utils.
|
|
3
|
+
import { toArray, resetEnv } from './.utils.ts';
|
|
4
4
|
|
|
5
5
|
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
|
}
|
|
@@ -2,36 +2,30 @@
|
|
|
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
|
-
import { toBuffer } from '../.utils.
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
34
|
-
);
|
|
21
|
+
async function decodeStream(observable: Observable<BufferSource>, onData: (data: unknown) => void) {
|
|
22
|
+
return new Promise<void>((resolve, reject) => {
|
|
23
|
+
observable.pipe(decodePipe()).subscribe({
|
|
24
|
+
next: onData,
|
|
25
|
+
error: reject,
|
|
26
|
+
complete: resolve,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
test('decode unsupported type', async () => {
|
|
@@ -117,6 +111,7 @@ test('decode string (unexpected eof) [error]', async () => {
|
|
|
117
111
|
|
|
118
112
|
test('decode ascii string', async () => {
|
|
119
113
|
const header = toBuffer('S', 'I', 0x3f, 0xff);
|
|
114
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
120
115
|
const payload = new Uint8Array(0x3fff + header.byteLength).fill('a'.charCodeAt(0));
|
|
121
116
|
payload.set(header);
|
|
122
117
|
expect(await decode(payload)).toBe('a'.repeat(0x3fff));
|
|
@@ -125,6 +120,7 @@ test('decode ascii string', async () => {
|
|
|
125
120
|
test('decode ascii string 32kiB [huge]', async () => {
|
|
126
121
|
const size = 0x7fff;
|
|
127
122
|
const header = toBuffer('S', 'I', 0x7f, 0xff);
|
|
123
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
128
124
|
const payload = new Uint8Array(size + header.byteLength).fill('a'.charCodeAt(0));
|
|
129
125
|
payload.set(header);
|
|
130
126
|
expect(await decode(payload)).toBe('a'.repeat(size));
|
|
@@ -133,6 +129,7 @@ test('decode ascii string 32kiB [huge]', async () => {
|
|
|
133
129
|
test('decode ascii string 64MB [huge]', async () => {
|
|
134
130
|
const size = 0x03d0_9000;
|
|
135
131
|
const header = toBuffer('S', 'l', 0x03, 0xd0, 0x90, 0x00);
|
|
132
|
+
// eslint-disable-next-line unicorn/prefer-code-point
|
|
136
133
|
const payload = new Uint8Array(size + header.byteLength).fill('a'.charCodeAt(0));
|
|
137
134
|
payload.set(header);
|
|
138
135
|
expect(await decode(payload)).toBe('a'.repeat(size));
|
|
@@ -469,7 +466,7 @@ test('decode object (empty key, optimized)', async () => {
|
|
|
469
466
|
});
|
|
470
467
|
|
|
471
468
|
test('decode stream', async () => {
|
|
472
|
-
const stream = new Subject();
|
|
469
|
+
const stream = new Subject<BufferSource>();
|
|
473
470
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
474
471
|
const onData = jest.fn();
|
|
475
472
|
const result = decodeStream(stream, onData);
|
|
@@ -487,7 +484,7 @@ test('decode stream', async () => {
|
|
|
487
484
|
});
|
|
488
485
|
|
|
489
486
|
test('decode bad stream [error]', async () => {
|
|
490
|
-
const stream = new Subject();
|
|
487
|
+
const stream = new Subject<BufferSource>();
|
|
491
488
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
492
489
|
const onData = jest.fn();
|
|
493
490
|
const result = decodeStream(stream, onData);
|
|
@@ -506,7 +503,7 @@ test('decode bad stream [error]', async () => {
|
|
|
506
503
|
});
|
|
507
504
|
|
|
508
505
|
test('decode partial stream [error]', async () => {
|
|
509
|
-
const stream = new Subject();
|
|
506
|
+
const stream = new Subject<BufferSource>();
|
|
510
507
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
511
508
|
const onData = jest.fn();
|
|
512
509
|
const result = decodeStream(stream, onData);
|
|
@@ -522,7 +519,7 @@ test('decode partial stream [error]', async () => {
|
|
|
522
519
|
});
|
|
523
520
|
|
|
524
521
|
test('decode error stream [error]', async () => {
|
|
525
|
-
const stream = new Subject();
|
|
522
|
+
const stream = new Subject<BufferSource>();
|
|
526
523
|
// while decoding streaming, N will be regarded as a no-op, rather than an undefined value
|
|
527
524
|
const onData = jest.fn();
|
|
528
525
|
const result = decodeStream(stream, onData);
|
|
@@ -4,14 +4,12 @@
|
|
|
4
4
|
import { firstValueFrom, of, map, reduce, Subject, toArray as rxjsToArray } from 'rxjs';
|
|
5
5
|
import { encode } from '../../dist/rxjs/index.js';
|
|
6
6
|
import { decode, encode as encodeRef } from '../../dist/index.js';
|
|
7
|
-
import { toArray } from '../.utils.
|
|
7
|
+
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;
|
|
@@ -4,25 +4,21 @@
|
|
|
4
4
|
import { jest } from '@jest/globals';
|
|
5
5
|
import { Readable, Transform } from 'node:stream';
|
|
6
6
|
import { decoder as decodeStream, decode as decodeAsync } from '../../dist/stream/index.js';
|
|
7
|
-
import { toBuffer } from '../.utils.
|
|
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: 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);
|
|
@@ -4,16 +4,14 @@
|
|
|
4
4
|
import { buffer } from 'node:stream/consumers';
|
|
5
5
|
import { encode, encoder } from '../../dist/stream/index.js';
|
|
6
6
|
import { decode, encode as encodeRef } from '../../dist/index.js';
|
|
7
|
-
import { toArray } from '../.utils.
|
|
7
|
+
import { toArray } from '../.utils.ts';
|
|
8
8
|
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);
|