@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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Serializer } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* createRememberedValue lets you save and recall a value when serializing
|
|
4
|
+
*
|
|
5
|
+
* This is useful for checksums and other values calculated from a writen value
|
|
6
|
+
*
|
|
7
|
+
* ```
|
|
8
|
+
* const data = st.createRememberedValue<ArrayBuffer>()
|
|
9
|
+
* st.object({
|
|
10
|
+
* data: data.save(st.bytes(1024))
|
|
11
|
+
* checksum: crc32(data.load())
|
|
12
|
+
* })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function createRememberedValue<T>(): {
|
|
16
|
+
save: (serializer: Serializer<T>) => Serializer<T>;
|
|
17
|
+
load: (behaviour?: "pop" | "retain") => Serializer<T>;
|
|
18
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createRememberedValue lets you save and recall a value when serializing
|
|
3
|
+
*
|
|
4
|
+
* This is useful for checksums and other values calculated from a writen value
|
|
5
|
+
*
|
|
6
|
+
* ```
|
|
7
|
+
* const data = st.createRememberedValue<ArrayBuffer>()
|
|
8
|
+
* st.object({
|
|
9
|
+
* data: data.save(st.bytes(1024))
|
|
10
|
+
* checksum: crc32(data.load())
|
|
11
|
+
* })
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function createRememberedValue() {
|
|
15
|
+
const stack = [];
|
|
16
|
+
/**
|
|
17
|
+
* Transparently writes/reads the underlying value but stores the value written.
|
|
18
|
+
*
|
|
19
|
+
* ---
|
|
20
|
+
* ```
|
|
21
|
+
* const data = st.createRememberedValue<ArrayBuffer>()
|
|
22
|
+
* st.object({
|
|
23
|
+
* data: data.save(st.bytes(1024))
|
|
24
|
+
* checksum: crc32(data.load())
|
|
25
|
+
* })
|
|
26
|
+
* ```
|
|
27
|
+
* */
|
|
28
|
+
function save(serializer) {
|
|
29
|
+
return {
|
|
30
|
+
size: serializer.size,
|
|
31
|
+
read: (ctx) => {
|
|
32
|
+
const value = serializer.read(ctx);
|
|
33
|
+
stack.push(value);
|
|
34
|
+
return value;
|
|
35
|
+
},
|
|
36
|
+
write: (ctx, value) => {
|
|
37
|
+
serializer.write(ctx, value);
|
|
38
|
+
stack.push(value);
|
|
39
|
+
return value;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Retrieves the last value written by `.save()`
|
|
45
|
+
*
|
|
46
|
+
* By default, the value is forgotten when written so that memory isn't leaked.
|
|
47
|
+
* It can be retained by setting `behaviour` to `"retain"`
|
|
48
|
+
*
|
|
49
|
+
* When writing this type does nothing
|
|
50
|
+
*
|
|
51
|
+
* ---
|
|
52
|
+
* ```
|
|
53
|
+
* const data = st.createRememberedValue<ArrayBuffer>()
|
|
54
|
+
* st.object({
|
|
55
|
+
* data: data.save(st.bytes(1024))
|
|
56
|
+
* checksum: crc32(data.load())
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
function load(behaviour = "pop") {
|
|
61
|
+
return {
|
|
62
|
+
size: 0,
|
|
63
|
+
read: () => {
|
|
64
|
+
if (behaviour === "pop") {
|
|
65
|
+
return stack.pop();
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
return stack.at(-1);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
write: () => { },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { save: save, load: load };
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { encodeTest, encodeSnapshotTest } from "../utils.test";
|
|
3
|
+
import * as st from "../index";
|
|
4
|
+
describe("st.remember", () => {
|
|
5
|
+
it("encodes correctly", () => {
|
|
6
|
+
const v = st.createRememberedValue();
|
|
7
|
+
const spec = st.object({
|
|
8
|
+
a: v.save(st.u32()),
|
|
9
|
+
b: st.list(v.load(), st.u8()),
|
|
10
|
+
});
|
|
11
|
+
encodeTest(spec, {
|
|
12
|
+
a: 3,
|
|
13
|
+
b: [1, 3, 4],
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
it("multiple runs function", () => {
|
|
17
|
+
const v = st.createRememberedValue();
|
|
18
|
+
const spec = st.object({
|
|
19
|
+
a: v.save(st.u32()),
|
|
20
|
+
b: st.list(v.load(), st.u8()),
|
|
21
|
+
});
|
|
22
|
+
encodeTest(spec, { a: 3, b: [1, 3, 4] });
|
|
23
|
+
encodeTest(spec, { a: 3, b: [1, 3, 4] });
|
|
24
|
+
encodeTest(spec, { a: 3, b: [1, 3, 4] });
|
|
25
|
+
});
|
|
26
|
+
it("omitted serializer doesn't write data ", () => {
|
|
27
|
+
const v = st.createRememberedValue();
|
|
28
|
+
const spec = st.object({
|
|
29
|
+
a: v.save(st.u32()),
|
|
30
|
+
b: v.load(),
|
|
31
|
+
});
|
|
32
|
+
const output = st.write(spec, { a: 3, b: 0 });
|
|
33
|
+
expect(spec.size).toBe(4);
|
|
34
|
+
expect(output.byteLength).toBe(4);
|
|
35
|
+
});
|
|
36
|
+
it("serializer is used write data ", () => {
|
|
37
|
+
const v = st.createRememberedValue();
|
|
38
|
+
const spec = st.object({
|
|
39
|
+
a: v.save(st.u32()),
|
|
40
|
+
b: v.load(),
|
|
41
|
+
});
|
|
42
|
+
encodeTest(spec, { a: 3, b: 0 }, { a: 3, b: 3 });
|
|
43
|
+
});
|
|
44
|
+
it("handles recursive objects", () => {
|
|
45
|
+
const size = st.createRememberedValue();
|
|
46
|
+
//@ts-expect-error, recursive types
|
|
47
|
+
const Node = st.lazy(() => st.object({
|
|
48
|
+
size: size.save(st.u32()),
|
|
49
|
+
children: st.list(size.load(), Node),
|
|
50
|
+
}));
|
|
51
|
+
encodeTest(Node, {
|
|
52
|
+
size: 2,
|
|
53
|
+
children: [
|
|
54
|
+
{ size: 0, children: [] },
|
|
55
|
+
{
|
|
56
|
+
size: 1,
|
|
57
|
+
children: [{ size: 0, children: [] }],
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
it("snapshots are correct", () => {
|
|
63
|
+
const v = st.createRememberedValue();
|
|
64
|
+
encodeSnapshotTest(st.object({
|
|
65
|
+
a: v.save(st.u32()),
|
|
66
|
+
b: st.list(v.load(), st.u8()),
|
|
67
|
+
}), {
|
|
68
|
+
a: 3,
|
|
69
|
+
b: [1, 3, 4],
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
package/dist/utils.test.d.ts
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import * as st from "./index";
|
|
2
|
+
export declare const randint: (start: number, end: number) => number;
|
|
3
|
+
export declare const randbigint: (start: bigint, end: bigint) => bigint;
|
|
4
|
+
export declare const encodeTest: <TIn, TOut>(serializer: st.Serializer<TIn, TOut>, value: TIn, expected?: TOut) => void;
|
|
5
|
+
export declare const encodeFailTest: <TIn, TOut>(serializer: st.Serializer<TIn, TOut>, value: TIn) => void;
|
|
6
|
+
export declare const expectEncodeSize: <TIn, TOut>(serializer: st.Serializer<TIn, TOut>, size: number, value: TIn) => void;
|
|
7
|
+
export declare const encodeSnapshotTest: <T>(serializer: st.Serializer<T>, value: T) => void;
|
|
8
|
+
export declare const expectError: (callback: () => void) => void;
|
|
9
|
+
export declare const bytes: (bytes: number[]) => ArrayBuffer;
|
package/dist/utils.test.js
CHANGED
|
@@ -1 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
//@ts-ignore TODO
|
|
2
|
+
import { describe, it, expect } from "bun:test";
|
|
3
|
+
import * as st from "./index";
|
|
4
|
+
export const randint = (start, end) => {
|
|
5
|
+
const range = end - start;
|
|
6
|
+
return Math.floor(start + range * Math.random());
|
|
7
|
+
};
|
|
8
|
+
export const randbigint = (start, end) => {
|
|
9
|
+
const range = end - start;
|
|
10
|
+
const offset = BigInt(Math.floor(Number(range) * Math.random()));
|
|
11
|
+
return start + offset;
|
|
12
|
+
};
|
|
13
|
+
export const encodeTest = (serializer, value, expected) => {
|
|
14
|
+
const data = st.write(serializer, value);
|
|
15
|
+
const newValue = st.read(serializer, data);
|
|
16
|
+
expect(newValue).toEqual((expected ?? value));
|
|
17
|
+
};
|
|
18
|
+
export const encodeFailTest = (serializer, value) => {
|
|
19
|
+
expectError(() => {
|
|
20
|
+
st.write(serializer, value);
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
export const expectEncodeSize = (serializer, size, value) => {
|
|
24
|
+
const data = st.write(serializer, value);
|
|
25
|
+
expect(data.byteLength).toEqual(size);
|
|
26
|
+
};
|
|
27
|
+
export const encodeSnapshotTest = (serializer, value) => {
|
|
28
|
+
const data = st.write(serializer, value);
|
|
29
|
+
expect(data).toMatchSnapshot();
|
|
30
|
+
};
|
|
31
|
+
export const expectError = (callback) => {
|
|
32
|
+
try {
|
|
33
|
+
callback();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
throw new Error("Expected Error");
|
|
39
|
+
};
|
|
40
|
+
export const bytes = (bytes) => {
|
|
41
|
+
return new Uint8Array(bytes).buffer;
|
|
42
|
+
};
|
package/dist/write.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export function write(serializer, value) {
|
|
2
2
|
const ctx = createdWriterContext(serializer);
|
|
3
|
-
|
|
3
|
+
try {
|
|
4
|
+
serializer.write(ctx, value);
|
|
5
|
+
}
|
|
6
|
+
catch (e) {
|
|
7
|
+
const path = ctx.stack.join("") ?? "root";
|
|
8
|
+
throw new Error(`Serialization error at value${path}`, { cause: e });
|
|
9
|
+
}
|
|
4
10
|
if (ctx.buffer.byteLength === ctx.offset) {
|
|
5
11
|
return ctx.buffer;
|
|
6
12
|
}
|
|
@@ -13,6 +19,7 @@ export function createdWriterContext(type) {
|
|
|
13
19
|
let buffer = new ArrayBuffer(type.size);
|
|
14
20
|
const view = new DataView(buffer);
|
|
15
21
|
return {
|
|
22
|
+
stack: [],
|
|
16
23
|
offset: 0,
|
|
17
24
|
buffer,
|
|
18
25
|
view,
|
|
@@ -24,6 +31,7 @@ export function createdWriterContext(type) {
|
|
|
24
31
|
let buffer = new ArrayBuffer(bufferLength);
|
|
25
32
|
const view = new DataView(buffer);
|
|
26
33
|
return {
|
|
34
|
+
stack: [],
|
|
27
35
|
offset: 0,
|
|
28
36
|
buffer,
|
|
29
37
|
view,
|
package/package.json
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nnilky/structo",
|
|
3
3
|
"description": "A library for serializing and deserializing binary content",
|
|
4
|
-
"keywords": [
|
|
4
|
+
"keywords": [
|
|
5
|
+
"binary",
|
|
6
|
+
"library",
|
|
7
|
+
"utility",
|
|
8
|
+
"web",
|
|
9
|
+
"node"
|
|
10
|
+
],
|
|
5
11
|
"license": "ISC",
|
|
6
|
-
"version": "1.0.
|
|
12
|
+
"version": "1.0.8",
|
|
7
13
|
"author": "Ben Brady",
|
|
8
14
|
"private": false,
|
|
9
|
-
"publishConfig": {
|
|
10
|
-
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
11
18
|
"repository": {
|
|
12
19
|
"type": "git",
|
|
13
20
|
"url": "git+https://github.com/Ben-Brady/structo-ts.git"
|
|
14
21
|
},
|
|
15
|
-
|
|
16
22
|
"readme": "README.md",
|
|
17
23
|
"type": "module",
|
|
18
24
|
"main": "./dist/index.js",
|
|
@@ -38,13 +44,6 @@
|
|
|
38
44
|
"./dist/**/*.js.map",
|
|
39
45
|
"./dist/**/*.js"
|
|
40
46
|
],
|
|
41
|
-
|
|
42
|
-
"scripts": {
|
|
43
|
-
"build": "tsc",
|
|
44
|
-
"prepublish": "tsc",
|
|
45
|
-
"check": "tsc --noEmit",
|
|
46
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
47
|
-
},
|
|
48
47
|
"devDependencies": {
|
|
49
48
|
"@types/bun": "^1.3.14",
|
|
50
49
|
"@types/node": "^25.9.2",
|
|
@@ -52,5 +51,11 @@
|
|
|
52
51
|
"jest": "^30.4.2",
|
|
53
52
|
"typescript": "^6.0.3"
|
|
54
53
|
},
|
|
55
|
-
"
|
|
56
|
-
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsc",
|
|
56
|
+
"prepublish": "tsc",
|
|
57
|
+
"check": "tsc --noEmit",
|
|
58
|
+
"test": "bun test src --only-failures",
|
|
59
|
+
"test:coverage": "bun test src --only-failures --coverage"
|
|
60
|
+
}
|
|
61
|
+
}
|