@nnilky/structo 1.0.5 → 1.0.8
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/README.md +3 -3
- package/dist/datatypes/containers/array.js +9 -0
- package/dist/datatypes/containers/array.test.js +6 -10
- package/dist/datatypes/containers/exhuastiveArray.d.ts +2 -2
- package/dist/datatypes/containers/exhuastiveArray.js +13 -2
- package/dist/datatypes/containers/exhuastiveArray.test.js +9 -12
- package/dist/datatypes/containers/fastObject.d.ts +3 -1
- package/dist/datatypes/containers/fastObject.js +3 -1
- package/dist/datatypes/containers/fastObject.test.js +18 -6
- package/dist/datatypes/containers/list.js +14 -2
- package/dist/datatypes/containers/list.test.js +6 -12
- package/dist/datatypes/containers/object.js +8 -2
- package/dist/datatypes/containers/object.test.js +22 -10
- package/dist/datatypes/containers/taggedUnion.d.ts +12 -8
- package/dist/datatypes/containers/taggedUnion.js +4 -2
- package/dist/datatypes/containers/taggedUnion.test.js +22 -18
- package/dist/datatypes/index.d.ts +2 -9
- package/dist/datatypes/index.js +2 -9
- package/dist/datatypes/numbers/bigints.test.js +11 -11
- package/dist/datatypes/numbers/floats.test.js +6 -6
- package/dist/datatypes/numbers/sints.test.js +11 -11
- package/dist/datatypes/numbers/uints.test.js +11 -11
- package/dist/datatypes/values/bytes.test.js +6 -8
- package/dist/datatypes/values/json.d.ts +10 -0
- package/dist/datatypes/values/json.js +21 -0
- package/dist/datatypes/values/sizedbytes.d.ts +2 -0
- package/dist/datatypes/values/sizedbytes.js +17 -0
- package/dist/datatypes/values/sizedbytes.test.d.ts +1 -0
- package/dist/datatypes/values/sizedbytes.test.js +25 -0
- package/dist/datatypes/values/string.d.ts +14 -0
- package/dist/datatypes/values/string.js +36 -0
- package/dist/datatypes/values/string.test.d.ts +1 -0
- package/dist/datatypes/values/string.test.js +21 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/read.d.ts +2 -6
- package/dist/read.js +9 -1
- package/dist/transforms/encode.d.ts +5 -0
- package/dist/transforms/encode.js +8 -0
- package/dist/transforms/enum.d.ts +2 -0
- package/dist/transforms/enum.js +16 -0
- package/dist/transforms/enum.test.d.ts +1 -0
- package/dist/transforms/enum.test.js +21 -0
- package/dist/transforms/fixedOffset.d.ts +2 -0
- package/dist/transforms/fixedOffset.js +18 -0
- package/dist/transforms/index.d.ts +11 -0
- package/dist/transforms/index.js +11 -0
- package/dist/transforms/literal.d.ts +1 -0
- package/dist/transforms/literal.js +15 -0
- package/dist/transforms/literal.test.d.ts +1 -0
- package/dist/transforms/literal.test.js +23 -0
- package/dist/transforms/modify.d.ts +20 -0
- package/dist/transforms/modify.js +27 -0
- package/dist/transforms/modify.test.d.ts +1 -0
- package/dist/transforms/modify.test.js +17 -0
- package/dist/transforms/noAdvance.d.ts +16 -0
- package/dist/transforms/noAdvance.js +30 -0
- package/dist/transforms/noAdvance.test.d.ts +1 -0
- package/dist/transforms/noAdvance.test.js +17 -0
- package/dist/transforms/offset.d.ts +2 -0
- package/dist/transforms/offset.js +20 -0
- package/dist/transforms/offset.test.d.ts +1 -0
- package/dist/transforms/offset.test.js +39 -0
- package/dist/transforms/pipe.d.ts +11 -0
- package/dist/transforms/pipe.js +16 -0
- package/dist/transforms/toAscii.d.ts +1 -0
- package/dist/transforms/toAscii.js +14 -0
- package/dist/transforms/toAscii.test.d.ts +1 -0
- package/dist/transforms/toAscii.test.js +25 -0
- package/dist/transforms/toBase64.d.ts +1 -0
- package/dist/transforms/toBase64.js +7 -0
- package/dist/transforms/toBase64.test.d.ts +1 -0
- package/dist/transforms/toBase64.test.js +27 -0
- package/dist/transforms/toBytes.d.ts +13 -0
- package/dist/transforms/toBytes.js +24 -0
- package/dist/transforms/toBytes.test.d.ts +1 -0
- package/dist/transforms/toBytes.test.js +27 -0
- package/dist/transforms/toHex.d.ts +13 -0
- package/dist/transforms/toHex.js +19 -0
- package/dist/transforms/toHex.test.d.ts +1 -0
- package/dist/transforms/toHex.test.js +23 -0
- package/dist/transforms/toTypedArray.d.ts +16 -0
- package/dist/transforms/toTypedArray.js +17 -0
- package/dist/transforms/toTypedArray.test.d.ts +1 -0
- package/dist/transforms/toTypedArray.test.js +29 -0
- package/dist/types.d.ts +3 -0
- package/dist/utilities/index.d.ts +3 -0
- package/dist/utilities/index.js +3 -0
- package/dist/utilities/lazy.d.ts +2 -0
- package/dist/utilities/lazy.js +25 -0
- package/dist/utilities/lazy.test.d.ts +1 -0
- package/dist/utilities/lazy.test.js +36 -0
- package/dist/utilities/reference.d.ts +18 -0
- package/dist/utilities/reference.js +91 -0
- package/dist/utilities/reference.test.d.ts +1 -0
- package/dist/utilities/reference.test.js +63 -0
- package/dist/utilities/remember.d.ts +18 -0
- package/dist/utilities/remember.js +75 -0
- package/dist/utilities/remember.test.d.ts +1 -0
- package/dist/utilities/remember.test.js +72 -0
- package/dist/utils.test.d.ts +9 -1
- package/dist/utils.test.js +42 -1
- package/dist/write.js +9 -1
- package/package.json +19 -14
package/README.md
CHANGED
|
@@ -21,9 +21,9 @@ const Entity = st.object({
|
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
- Lightweight, base size is <1KB and each datatype is a few hundred bytes
|
|
24
|
-
- Fast
|
|
25
|
-
-
|
|
26
|
-
- Easily
|
|
24
|
+
- Fast show only 1.5-5x slower than ideal implementaiton
|
|
25
|
+
- Designed for both Web/Node.js compatible
|
|
26
|
+
- Easily implement your own serializers
|
|
27
27
|
|
|
28
28
|
Each serializer is completely seperate from the base library, meaning you only pay for what you use.
|
|
29
29
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
export function array(size, type) {
|
|
10
|
+
const SHOW_ERRORS = size < 4096;
|
|
10
11
|
const { read: readType, write: writeType, size: typeSize } = type;
|
|
11
12
|
return {
|
|
12
13
|
size: type.size ? size * type.size : undefined,
|
|
@@ -16,13 +17,21 @@ export function array(size, type) {
|
|
|
16
17
|
if (typeSize)
|
|
17
18
|
ctx.alloc(size * typeSize);
|
|
18
19
|
for (let i = 0; i < size; i++) {
|
|
20
|
+
if (SHOW_ERRORS)
|
|
21
|
+
ctx.stack.push(`[${i}]`);
|
|
19
22
|
writeType(ctx, value[i]);
|
|
23
|
+
if (SHOW_ERRORS)
|
|
24
|
+
ctx.stack.pop();
|
|
20
25
|
}
|
|
21
26
|
},
|
|
22
27
|
read: (ctx) => {
|
|
23
28
|
const arr = new Array(size);
|
|
24
29
|
for (let i = 0; i < size; i++) {
|
|
30
|
+
if (SHOW_ERRORS)
|
|
31
|
+
ctx.stack.push(`[${i}]`);
|
|
25
32
|
arr[i] = readType(ctx);
|
|
33
|
+
if (SHOW_ERRORS)
|
|
34
|
+
ctx.stack.pop();
|
|
26
35
|
}
|
|
27
36
|
return arr;
|
|
28
37
|
},
|
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { describe, it } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import { encodeTest, encodeFailTest } from "../../utils.test";
|
|
3
3
|
import * as st from "../../index";
|
|
4
4
|
describe("st.array", () => {
|
|
5
5
|
it("encode correctly", () => {
|
|
6
|
-
|
|
7
|
-
expectEncode(spec, [1, 2, 3, 4]);
|
|
6
|
+
encodeTest(st.array(4, st.u16()), [1, 2, 3, 4]);
|
|
8
7
|
});
|
|
9
8
|
it("works on empty lists", () => {
|
|
10
|
-
|
|
11
|
-
expectEncode(spec, []);
|
|
9
|
+
encodeTest(st.array(0, st.u16()), []);
|
|
12
10
|
});
|
|
13
11
|
it("throws error on invalid size", () => {
|
|
14
|
-
|
|
15
|
-
expectError(() => st.write(spec, [1]));
|
|
12
|
+
encodeFailTest(st.array(2, st.u16()), [1]);
|
|
16
13
|
});
|
|
17
14
|
it("throws error on invalid value", () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
expectError(() => st.write(spec, [2 ** 16 + 1, 0]));
|
|
15
|
+
encodeFailTest(st.array(2, st.u16()), [1, -1]);
|
|
16
|
+
encodeFailTest(st.array(2, st.u16()), [2 ** 16 + 1, 0]);
|
|
21
17
|
});
|
|
22
18
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as st from "
|
|
1
|
+
import * as st from "../../index";
|
|
2
2
|
/**
|
|
3
3
|
* exhuastiveArray is read until the end of the data
|
|
4
4
|
*
|
|
5
5
|
* ```py
|
|
6
|
-
* exhuastiveArray(st.
|
|
6
|
+
* exhuastiveArray(st.string(st.u8()))
|
|
7
7
|
* ```
|
|
8
8
|
*/
|
|
9
9
|
export declare function exhuastiveArray<T>(type: st.Serializer<T>): st.Serializer<T[]>;
|
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
import * as st from "
|
|
1
|
+
import * as st from "../../index";
|
|
2
2
|
/**
|
|
3
3
|
* exhuastiveArray is read until the end of the data
|
|
4
4
|
*
|
|
5
5
|
* ```py
|
|
6
|
-
* exhuastiveArray(st.
|
|
6
|
+
* exhuastiveArray(st.string(st.u8()))
|
|
7
7
|
* ```
|
|
8
8
|
*/
|
|
9
9
|
export function exhuastiveArray(type) {
|
|
10
10
|
return {
|
|
11
11
|
read(ctx) {
|
|
12
12
|
let arr = [];
|
|
13
|
+
let i = 0;
|
|
13
14
|
while (ctx.offset < ctx.view.byteLength) {
|
|
15
|
+
const TRACK_STACK = i++ < 4096;
|
|
16
|
+
if (TRACK_STACK)
|
|
17
|
+
ctx.stack.push(`[${arr.length - 1}]`);
|
|
14
18
|
arr.push(type.read(ctx));
|
|
19
|
+
if (TRACK_STACK)
|
|
20
|
+
ctx.stack.pop();
|
|
15
21
|
}
|
|
16
22
|
return arr;
|
|
17
23
|
},
|
|
18
24
|
write(ctx, value) {
|
|
25
|
+
const TRACK_STACK = value.length < 4096;
|
|
19
26
|
for (let i = 0; i < value.length; i++) {
|
|
27
|
+
if (TRACK_STACK)
|
|
28
|
+
ctx.stack.push(`[${i}]`);
|
|
20
29
|
type.write(ctx, value[i]);
|
|
30
|
+
if (TRACK_STACK)
|
|
31
|
+
ctx.stack.pop();
|
|
21
32
|
}
|
|
22
33
|
},
|
|
23
34
|
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { describe, it } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import { encodeTest, encodeSnapshotTest, encodeFailTest } from "../../utils.test";
|
|
3
3
|
import * as st from "../../index";
|
|
4
4
|
describe("st.exhuastiveArray", () => {
|
|
5
5
|
it("encode correctly", () => {
|
|
6
6
|
const spec = st.exhuastiveArray(st.u32());
|
|
7
|
-
|
|
7
|
+
encodeTest(spec, [1, 2, 3, 4]);
|
|
8
8
|
});
|
|
9
9
|
it("works on empty arrays", () => {
|
|
10
10
|
const spec = st.exhuastiveArray(st.u32());
|
|
11
|
-
|
|
11
|
+
encodeTest(spec, []);
|
|
12
12
|
});
|
|
13
13
|
it("accepts large array", () => {
|
|
14
14
|
const spec = st.exhuastiveArray(st.u32());
|
|
15
|
-
|
|
15
|
+
encodeTest(spec, Array.from({ length: 10000 }, (_, i) => i));
|
|
16
16
|
});
|
|
17
17
|
it("works composed", () => {
|
|
18
18
|
const spec = st.object({
|
|
@@ -20,22 +20,19 @@ describe("st.exhuastiveArray", () => {
|
|
|
20
20
|
b: st.u8(),
|
|
21
21
|
c: st.exhuastiveArray(st.u32()),
|
|
22
22
|
});
|
|
23
|
-
|
|
23
|
+
encodeTest(spec, { a: 1, b: 2, c: [3, 4, 5, 6, 7] });
|
|
24
24
|
});
|
|
25
25
|
it("throws error on invalid value", () => {
|
|
26
|
-
|
|
27
|
-
expectError(() => {
|
|
28
|
-
st.write(spec, [-1]);
|
|
29
|
-
});
|
|
26
|
+
encodeFailTest(st.exhuastiveArray(st.u16()), [-1]);
|
|
30
27
|
});
|
|
31
28
|
it("nested arrays encode correctly", () => {
|
|
32
|
-
|
|
29
|
+
encodeTest(st.exhuastiveArray(st.exhuastiveArray(st.u16())), //
|
|
33
30
|
[[1, 2]]);
|
|
34
31
|
});
|
|
35
32
|
it(`matches snapshots`, () => {
|
|
36
|
-
|
|
33
|
+
encodeSnapshotTest(st.exhuastiveArray(st.string(st.u16())), //
|
|
37
34
|
["foo", "bar", "baz"]);
|
|
38
|
-
|
|
35
|
+
encodeSnapshotTest(st.exhuastiveArray(st.u8()), //
|
|
39
36
|
[0, 1, 2, 3]);
|
|
40
37
|
});
|
|
41
38
|
});
|
|
@@ -3,7 +3,7 @@ type InferObject<T> = T extends Record<string, Serializer<any>> ? {
|
|
|
3
3
|
[Key in keyof T]: InferInput<T[Key]>;
|
|
4
4
|
} : never;
|
|
5
5
|
/**
|
|
6
|
-
* `fastObject` is equivelent to object but it uses eval to improve performance
|
|
6
|
+
* `fastObject` is equivelent to object but it uses eval to improve performance, additionally it omits error reporting
|
|
7
7
|
*
|
|
8
8
|
* This means that is should be avoided in scenarios where CSP is required (so can't be the default), but should be fine for all other cases
|
|
9
9
|
*
|
|
@@ -14,6 +14,8 @@ type InferObject<T> = T extends Record<string, Serializer<any>> ? {
|
|
|
14
14
|
* createdAt: st.f64(),
|
|
15
15
|
* })
|
|
16
16
|
* ```
|
|
17
|
+
*
|
|
18
|
+
* Note: Using `st.lazy` affects the performance of fastObject as it prevents discovery of subobjects, avoid when performance is a requirement
|
|
17
19
|
*/
|
|
18
20
|
export declare function fastObject<T extends Record<string, Serializer<any>>>(definition: T): Serializer<InferObject<T>>;
|
|
19
21
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const definitionSymbol = Symbol();
|
|
2
2
|
/**
|
|
3
|
-
* `fastObject` is equivelent to object but it uses eval to improve performance
|
|
3
|
+
* `fastObject` is equivelent to object but it uses eval to improve performance, additionally it omits error reporting
|
|
4
4
|
*
|
|
5
5
|
* This means that is should be avoided in scenarios where CSP is required (so can't be the default), but should be fine for all other cases
|
|
6
6
|
*
|
|
@@ -11,6 +11,8 @@ const definitionSymbol = Symbol();
|
|
|
11
11
|
* createdAt: st.f64(),
|
|
12
12
|
* })
|
|
13
13
|
* ```
|
|
14
|
+
*
|
|
15
|
+
* Note: Using `st.lazy` affects the performance of fastObject as it prevents discovery of subobjects, avoid when performance is a requirement
|
|
14
16
|
*/
|
|
15
17
|
export function fastObject(definition) {
|
|
16
18
|
let serializers = [];
|
|
@@ -1,26 +1,38 @@
|
|
|
1
1
|
//@ts-ignore TODO
|
|
2
2
|
import { describe, it, expect } from "bun:test";
|
|
3
|
-
import { bytes,
|
|
3
|
+
import { bytes, encodeTest, encodeSnapshotTest } from "../../utils.test";
|
|
4
4
|
import * as st from "../../index";
|
|
5
5
|
describe("st.fastObject", () => {
|
|
6
|
-
const
|
|
6
|
+
const spec = st.fastObject({
|
|
7
7
|
a: st.u8(),
|
|
8
8
|
b: st.u8(),
|
|
9
9
|
});
|
|
10
10
|
it("encodes correctly", () => {
|
|
11
|
-
st.write(
|
|
11
|
+
st.write(spec, { b: 2, a: 1 });
|
|
12
|
+
});
|
|
13
|
+
it("encodes nest correctly", () => {
|
|
14
|
+
st.write(st.fastObject({
|
|
15
|
+
a: st.fastObject({
|
|
16
|
+
cat: st.u8(),
|
|
17
|
+
puppy: st.string(st.u8()),
|
|
18
|
+
}),
|
|
19
|
+
b: st.u8(),
|
|
20
|
+
}), {
|
|
21
|
+
a: { cat: 1, puppy: "woof" },
|
|
22
|
+
b: 3,
|
|
23
|
+
});
|
|
12
24
|
});
|
|
13
25
|
it("encode in correct order", () => {
|
|
14
|
-
const data = st.write(
|
|
26
|
+
const data = st.write(spec, { b: 2, a: 1 });
|
|
15
27
|
const arr = new Uint8Array(data);
|
|
16
28
|
expect(arr[0]).toBe(1);
|
|
17
29
|
expect(arr[1]).toBe(2);
|
|
18
30
|
});
|
|
19
31
|
it("encodes empty", () => {
|
|
20
|
-
|
|
32
|
+
encodeTest(st.fastObject({}), {});
|
|
21
33
|
});
|
|
22
34
|
it(`matches snapshots`, () => {
|
|
23
|
-
|
|
35
|
+
encodeSnapshotTest(st.fastObject({
|
|
24
36
|
number: st.u32(),
|
|
25
37
|
puppy: st.string(st.s32()),
|
|
26
38
|
buffer: st.bytes(4),
|
|
@@ -12,17 +12,29 @@ export function list(length, type) {
|
|
|
12
12
|
return {
|
|
13
13
|
write: (ctx, value) => {
|
|
14
14
|
length.write(ctx, value.length);
|
|
15
|
-
|
|
15
|
+
const TRACK_STACK = value.length < 4096;
|
|
16
|
+
if (type.size) {
|
|
16
17
|
ctx.alloc(value.length * type.size);
|
|
17
|
-
|
|
18
|
+
}
|
|
19
|
+
for (let i = 0; i < value.length; i++) {
|
|
20
|
+
if (TRACK_STACK)
|
|
21
|
+
ctx.stack.push(`[${i}]`);
|
|
22
|
+
const v = value[i];
|
|
18
23
|
type.write(ctx, v);
|
|
24
|
+
if (TRACK_STACK)
|
|
25
|
+
ctx.stack.pop();
|
|
19
26
|
}
|
|
20
27
|
},
|
|
21
28
|
read: (ctx) => {
|
|
22
29
|
const size = length.read(ctx);
|
|
30
|
+
const TRACK_STACK = size < 4096;
|
|
23
31
|
const arr = new Array(size);
|
|
24
32
|
for (let i = 0; i < size; i++) {
|
|
33
|
+
if (TRACK_STACK)
|
|
34
|
+
ctx.stack.push(`[${i}]`);
|
|
25
35
|
arr[i] = type.read(ctx);
|
|
36
|
+
if (TRACK_STACK)
|
|
37
|
+
ctx.stack.pop();
|
|
26
38
|
}
|
|
27
39
|
return arr;
|
|
28
40
|
},
|
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
import { describe, it } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import { encodeTest, encodeSnapshotTest, encodeFailTest } from "../../utils.test";
|
|
3
3
|
import * as st from "../../index";
|
|
4
4
|
describe("st.list", () => {
|
|
5
5
|
it("encode correctly", () => {
|
|
6
6
|
const spec = st.list(st.u8(), st.u32());
|
|
7
|
-
|
|
7
|
+
encodeTest(spec, [1, 2, 3, 4]);
|
|
8
8
|
});
|
|
9
9
|
it("works on empty lists", () => {
|
|
10
10
|
const spec = st.list(st.u8(), st.u32());
|
|
11
|
-
|
|
11
|
+
encodeTest(spec, []);
|
|
12
12
|
});
|
|
13
13
|
it("throws error on too large array", () => {
|
|
14
|
-
|
|
15
|
-
expectError(() => {
|
|
16
|
-
st.write(spec, Array.from({ length: 10000 }, () => 0));
|
|
17
|
-
});
|
|
14
|
+
encodeFailTest(st.list(st.u8(), st.u32()), Array.from({ length: 10000 }, () => 0));
|
|
18
15
|
});
|
|
19
16
|
it("throws error on invalid value", () => {
|
|
20
|
-
|
|
21
|
-
expectError(() => {
|
|
22
|
-
st.write(spec, [-1]);
|
|
23
|
-
});
|
|
17
|
+
encodeFailTest(st.list(st.u8(), st.u16()), [-1]);
|
|
24
18
|
});
|
|
25
19
|
it(`matches snapshots`, () => {
|
|
26
|
-
|
|
20
|
+
encodeSnapshotTest(st.list(st.s32(), st.string(st.u16())), //
|
|
27
21
|
["foo", "bar", "baz"]);
|
|
28
22
|
});
|
|
29
23
|
});
|
|
@@ -21,13 +21,19 @@ export function object(definition) {
|
|
|
21
21
|
if (size)
|
|
22
22
|
ctx.alloc(size);
|
|
23
23
|
for (let i = 0; i < entires.length; i++) {
|
|
24
|
-
|
|
24
|
+
const [key, serializer] = entires[i];
|
|
25
|
+
ctx.stack.push(`.${key}`);
|
|
26
|
+
serializer.write(ctx, value[key]);
|
|
27
|
+
ctx.stack.pop();
|
|
25
28
|
}
|
|
26
29
|
},
|
|
27
30
|
read: (ctx) => {
|
|
28
31
|
const output = new Array(entires.length);
|
|
29
32
|
for (let i = 0; i < entires.length; i++) {
|
|
30
|
-
|
|
33
|
+
const [key, serializer] = entires[i];
|
|
34
|
+
ctx.stack.push(`.${key}`);
|
|
35
|
+
output[i] = [key, serializer.read(ctx)];
|
|
36
|
+
ctx.stack.pop();
|
|
31
37
|
}
|
|
32
38
|
return Object.fromEntries(output);
|
|
33
39
|
},
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
//@ts-ignore TODO
|
|
2
|
-
import { describe, it, expect } from "bun:test";
|
|
3
|
-
import { bytes,
|
|
2
|
+
import { describe, it, expect, expectTypeOf } from "bun:test";
|
|
3
|
+
import { bytes, encodeTest, encodeSnapshotTest } from "../../utils.test";
|
|
4
4
|
import * as st from "../../index";
|
|
5
5
|
describe("st.object", () => {
|
|
6
|
-
const test = st.object({
|
|
7
|
-
a: st.u8(),
|
|
8
|
-
b: st.u8(),
|
|
9
|
-
});
|
|
10
6
|
it("encodes correctly", () => {
|
|
11
|
-
st.
|
|
7
|
+
encodeTest(st.object({ a: st.u8(), b: st.u8() }), //
|
|
8
|
+
{ b: 2, a: 1 });
|
|
9
|
+
});
|
|
10
|
+
it("encodes nested correctly", () => {
|
|
11
|
+
encodeTest(st.object({
|
|
12
|
+
a: st.object({ a: st.u8() }),
|
|
13
|
+
b: st.u8(),
|
|
14
|
+
}), //
|
|
15
|
+
{ a: { a: 2 }, b: 1 });
|
|
12
16
|
});
|
|
13
17
|
it("encode in correct order", () => {
|
|
14
|
-
const data = st.write(
|
|
18
|
+
const data = st.write(st.object({
|
|
19
|
+
a: st.u8(),
|
|
20
|
+
b: st.u8(),
|
|
21
|
+
}), { b: 2, a: 1 });
|
|
15
22
|
const arr = new Uint8Array(data);
|
|
16
23
|
expect(arr[0]).toBe(1);
|
|
17
24
|
expect(arr[1]).toBe(2);
|
|
18
25
|
});
|
|
19
26
|
it("encodes empty", () => {
|
|
20
|
-
|
|
27
|
+
encodeTest(st.object({}), {});
|
|
21
28
|
});
|
|
22
29
|
it(`matches snapshots`, () => {
|
|
23
|
-
|
|
30
|
+
encodeSnapshotTest(st.object({
|
|
24
31
|
number: st.u32(),
|
|
25
32
|
puppy: st.string(st.s32()),
|
|
26
33
|
buffer: st.bytes(4),
|
|
@@ -30,4 +37,9 @@ describe("st.object", () => {
|
|
|
30
37
|
buffer: bytes([19, 87, 19, 83]),
|
|
31
38
|
});
|
|
32
39
|
});
|
|
40
|
+
// Type Tests
|
|
41
|
+
expectTypeOf(st.object({
|
|
42
|
+
number: st.u32(),
|
|
43
|
+
string: st.string(st.u32()),
|
|
44
|
+
})).toEqualTypeOf();
|
|
33
45
|
});
|
|
@@ -11,12 +11,16 @@ import type { InferInput, InferOutput, Serializer } from "../../types";
|
|
|
11
11
|
* 2: MouseMovePacket,
|
|
12
12
|
* })
|
|
13
13
|
* ```
|
|
14
|
-
*
|
|
15
14
|
*/
|
|
16
|
-
export declare function taggedUnion<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
15
|
+
export declare function taggedUnion<Tag extends PropertyKey, //
|
|
16
|
+
Variants extends Record<Tag, Serializer<any>>>(tag: Serializer<Tag>, variants: Variants & Record<Exclude<keyof Variants, Tag>, never>): Serializer<{
|
|
17
|
+
[K in keyof Variants]: {
|
|
18
|
+
type: K;
|
|
19
|
+
value: InferInput<Variants[K]>;
|
|
20
|
+
};
|
|
21
|
+
}[keyof Variants], {
|
|
22
|
+
[K in keyof Variants]: {
|
|
23
|
+
type: K;
|
|
24
|
+
value: InferOutput<Variants[K]>;
|
|
25
|
+
};
|
|
26
|
+
}[keyof Variants]>;
|
|
@@ -10,15 +10,16 @@
|
|
|
10
10
|
* 2: MouseMovePacket,
|
|
11
11
|
* })
|
|
12
12
|
* ```
|
|
13
|
-
*
|
|
14
13
|
*/
|
|
15
14
|
export function taggedUnion(tag, variants) {
|
|
16
15
|
return {
|
|
17
16
|
write: (ctx, value) => {
|
|
18
17
|
if (!(value.type in variants))
|
|
19
|
-
throw new Error(`Unknown type ${value.type}`);
|
|
18
|
+
throw new Error(`Unknown type ${String(value.type)}`);
|
|
19
|
+
//@ts-expect-error
|
|
20
20
|
tag.write(ctx, value.type);
|
|
21
21
|
const variant = variants[value.type];
|
|
22
|
+
//@ts-expect-error
|
|
22
23
|
variant.write(ctx, value.value);
|
|
23
24
|
},
|
|
24
25
|
read: (ctx) => {
|
|
@@ -26,6 +27,7 @@ export function taggedUnion(tag, variants) {
|
|
|
26
27
|
if (!(type in variants))
|
|
27
28
|
throw new Error(`Unknown type ${tag}`);
|
|
28
29
|
const variant = variants[type];
|
|
30
|
+
//@ts-expect-error
|
|
29
31
|
const value = variant.read(ctx);
|
|
30
32
|
return { type, value };
|
|
31
33
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { describe, it } from "bun:test";
|
|
2
|
-
import {
|
|
1
|
+
import { describe, expectTypeOf, it } from "bun:test";
|
|
2
|
+
import { encodeTest, expectEncodeSize, encodeSnapshotTest, encodeFailTest } from "../../utils.test";
|
|
3
3
|
import * as st from "../../index";
|
|
4
4
|
describe("st.taggedUnion", () => {
|
|
5
5
|
it("encode correctly", () => {
|
|
@@ -7,57 +7,61 @@ describe("st.taggedUnion", () => {
|
|
|
7
7
|
1: st.string(st.u8()),
|
|
8
8
|
2: st.u8(),
|
|
9
9
|
});
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
encodeTest(spec, { type: 1, value: "s" });
|
|
11
|
+
encodeTest(spec, { type: 2, value: 52 });
|
|
12
12
|
});
|
|
13
13
|
it("encode with string tag", () => {
|
|
14
14
|
const spec = st.taggedUnion(st.string(st.u8()), {
|
|
15
15
|
foo: st.string(st.u8()),
|
|
16
16
|
bar: st.u8(),
|
|
17
17
|
});
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
encodeTest(spec, { type: "foo", value: "woof" });
|
|
19
|
+
encodeTest(spec, { type: "bar", value: 52 });
|
|
20
20
|
});
|
|
21
21
|
it("throws error on invalid tag", () => {
|
|
22
22
|
const spec = st.taggedUnion(st.string(st.u8()), {
|
|
23
23
|
foo: st.string(st.u8()),
|
|
24
24
|
bar: st.u8(),
|
|
25
25
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
});
|
|
26
|
+
//@ts-expect-error, intended
|
|
27
|
+
encodeFailTest(spec, { type: "unknown", value: "woof" });
|
|
29
28
|
});
|
|
30
29
|
it("throws error on invalid type", () => {
|
|
31
30
|
const spec = st.taggedUnion(st.string(st.u8()), {
|
|
32
31
|
foo: st.string(st.u8()),
|
|
33
32
|
bar: st.u8(),
|
|
34
33
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
34
|
+
//@ts-expect-error, intended
|
|
35
|
+
encodeFailTest(spec, { type: "unknown", value: "woof" });
|
|
38
36
|
});
|
|
39
37
|
it("throws error on invalid value", () => {
|
|
40
38
|
const spec = st.taggedUnion(st.string(st.u8()), {
|
|
41
39
|
foo: st.string(st.u8()),
|
|
42
40
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
st.write(spec, { type: "foo", value: 0 });
|
|
46
|
-
});
|
|
41
|
+
//@ts-expect-error, intended
|
|
42
|
+
encodeFailTest(spec, { type: "foo", value: 0 });
|
|
47
43
|
});
|
|
48
44
|
it("encodes varying sizes", () => {
|
|
49
45
|
const spec = st.taggedUnion(st.u8(), {
|
|
50
46
|
1: st.string(st.u8()),
|
|
51
47
|
2: st.u8(),
|
|
52
48
|
});
|
|
53
|
-
|
|
49
|
+
encodeTest(spec, { type: 1, value: "s" });
|
|
54
50
|
expectEncodeSize(spec, 5, { type: 1, value: "foo" });
|
|
55
51
|
expectEncodeSize(spec, 2, { type: 2, value: 52 });
|
|
56
52
|
});
|
|
57
53
|
it("encodes snapshots", () => {
|
|
58
|
-
|
|
54
|
+
encodeSnapshotTest(st.taggedUnion(st.u32(), {
|
|
59
55
|
0: st.list(st.u8(), st.f64()),
|
|
60
56
|
3: st.u32(),
|
|
61
57
|
}), { type: 0, value: [1] });
|
|
62
58
|
});
|
|
59
|
+
expectTypeOf(st.taggedUnion(st.u32(), {
|
|
60
|
+
0: st.u8(),
|
|
61
|
+
1: st.string(st.u32()),
|
|
62
|
+
})).toEqualTypeOf();
|
|
63
|
+
() => {
|
|
64
|
+
//@ts-expect-error, must be same type as tags
|
|
65
|
+
st.taggedUnion(st.string(st.u8()), { 0: st.u8(), 1: st.string(st.u32()) });
|
|
66
|
+
};
|
|
63
67
|
});
|
|
@@ -6,15 +6,8 @@ export { array } from "./containers/array";
|
|
|
6
6
|
export { fastObject } from "./containers/fastObject";
|
|
7
7
|
export { object } from "./containers/object";
|
|
8
8
|
export { list } from "./containers/list";
|
|
9
|
-
export { sizedBytes } from "./containers/sizedbytes";
|
|
10
9
|
export { taggedUnion } from "./containers/taggedUnion";
|
|
11
10
|
export { exhuastiveArray } from "./containers/exhuastiveArray";
|
|
12
|
-
export { string } from "./containers/string";
|
|
13
11
|
export { bytes } from "./values/bytes";
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export { fixedOffset } from "./transforms/fixedOffset";
|
|
17
|
-
export { modify } from "./transforms/modify";
|
|
18
|
-
export { encode } from "./transforms/encode";
|
|
19
|
-
export { noAdvance } from "./transforms/noAdvance";
|
|
20
|
-
export { createRememberedValue } from "./utilities/remember";
|
|
12
|
+
export { sizedBytes } from "./values/sizedbytes";
|
|
13
|
+
export { string } from "./values/string";
|
package/dist/datatypes/index.js
CHANGED
|
@@ -6,15 +6,8 @@ export { array } from "./containers/array";
|
|
|
6
6
|
export { fastObject } from "./containers/fastObject";
|
|
7
7
|
export { object } from "./containers/object";
|
|
8
8
|
export { list } from "./containers/list";
|
|
9
|
-
export { sizedBytes } from "./containers/sizedbytes";
|
|
10
9
|
export { taggedUnion } from "./containers/taggedUnion";
|
|
11
10
|
export { exhuastiveArray } from "./containers/exhuastiveArray";
|
|
12
|
-
export { string } from "./containers/string";
|
|
13
11
|
export { bytes } from "./values/bytes";
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export { fixedOffset } from "./transforms/fixedOffset";
|
|
17
|
-
export { modify } from "./transforms/modify";
|
|
18
|
-
export { encode } from "./transforms/encode";
|
|
19
|
-
export { noAdvance } from "./transforms/noAdvance";
|
|
20
|
-
export { createRememberedValue } from "./utilities/remember";
|
|
12
|
+
export { sizedBytes } from "./values/sizedbytes";
|
|
13
|
+
export { string } from "./values/string";
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { describe, it, expect } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import { encodeTest, encodeSnapshotTest, randbigint, encodeFailTest } from "../../utils.test";
|
|
3
3
|
import * as st from "../../index";
|
|
4
4
|
function test_bigint(options) {
|
|
5
5
|
const { name, range: [start, end], serializer, size, } = options;
|
|
6
6
|
describe(name, () => {
|
|
7
7
|
it("works in bounds", () => {
|
|
8
|
-
|
|
8
|
+
encodeTest(serializer, start);
|
|
9
9
|
for (let i = 0; i < 100; i++) {
|
|
10
|
-
|
|
10
|
+
encodeTest(serializer, randbigint(start, end));
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
encodeTest(serializer, end);
|
|
13
13
|
});
|
|
14
14
|
it("outside bounds", () => {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
encodeFailTest(serializer, start - 1n);
|
|
16
|
+
encodeFailTest(serializer, end + 1n);
|
|
17
17
|
});
|
|
18
18
|
it(`is right size`, () => {
|
|
19
19
|
const expectValueSize = (value) => {
|
|
@@ -27,11 +27,11 @@ function test_bigint(options) {
|
|
|
27
27
|
expectValueSize(end);
|
|
28
28
|
});
|
|
29
29
|
it(`matches snapshots`, () => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
encodeSnapshotTest(serializer, 0n);
|
|
31
|
+
encodeSnapshotTest(serializer, start);
|
|
32
|
+
encodeSnapshotTest(serializer, start + 10n);
|
|
33
|
+
encodeSnapshotTest(serializer, end - 10n);
|
|
34
|
+
encodeSnapshotTest(serializer, end);
|
|
35
35
|
});
|
|
36
36
|
});
|
|
37
37
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//@ts-ignore TODO
|
|
2
2
|
import { describe, it, expect } from "bun:test";
|
|
3
|
-
import {
|
|
3
|
+
import { encodeTest, expectEncodeSize } from "../../utils.test";
|
|
4
4
|
import * as st from "../../index";
|
|
5
5
|
function test_float(options) {
|
|
6
6
|
const { name, serializer, size } = options;
|
|
@@ -22,17 +22,17 @@ function test_float(options) {
|
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
it(`works on Infinty`, () => {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
encodeTest(serializer, Infinity);
|
|
26
|
+
encodeTest(serializer, -Infinity);
|
|
27
27
|
});
|
|
28
28
|
it(`works on NaN`, () => {
|
|
29
|
-
|
|
29
|
+
encodeTest(serializer, NaN);
|
|
30
30
|
});
|
|
31
31
|
it(`works on 0`, () => {
|
|
32
|
-
|
|
32
|
+
encodeTest(serializer, 0);
|
|
33
33
|
});
|
|
34
34
|
it(`works on -0`, () => {
|
|
35
|
-
|
|
35
|
+
encodeTest(serializer, -0);
|
|
36
36
|
});
|
|
37
37
|
it(`is right size`, () => {
|
|
38
38
|
for (let i = 0; i < 100; i++) {
|