@nnilky/structo 1.0.5 → 1.0.7
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/datatypes/containers/array.test.js +6 -10
- package/dist/datatypes/containers/exhuastiveArray.test.js +9 -12
- package/dist/datatypes/containers/fastObject.d.ts +2 -0
- package/dist/datatypes/containers/fastObject.js +2 -0
- package/dist/datatypes/containers/fastObject.test.js +18 -6
- package/dist/datatypes/containers/list.test.js +6 -12
- package/dist/datatypes/containers/object.js +7 -1
- 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 +18 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/transforms/encode.d.ts +2 -0
- package/dist/transforms/encode.js +7 -0
- package/dist/transforms/enum.d.ts +2 -0
- package/dist/transforms/enum.js +13 -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 +12 -0
- package/dist/transforms/index.js +12 -0
- package/dist/transforms/literal.d.ts +1 -0
- package/dist/transforms/literal.js +12 -0
- package/dist/transforms/literal.test.d.ts +1 -0
- package/dist/transforms/literal.test.js +23 -0
- package/dist/transforms/modify.d.ts +2 -0
- package/dist/transforms/modify.js +7 -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/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 +11 -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 +4 -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 +21 -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 +16 -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 +14 -0
- package/dist/transforms/toTypedArray.test.d.ts +1 -0
- package/dist/transforms/toTypedArray.test.js +29 -0
- package/dist/utilities/index.d.ts +2 -0
- package/dist/utilities/index.js +2 -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/remember.d.ts +17 -0
- package/dist/utilities/remember.js +38 -0
- package/dist/utilities/remember.test.d.ts +1 -0
- package/dist/utilities/remember.test.js +76 -0
- package/dist/utils.test.d.ts +9 -1
- package/dist/utils.test.js +42 -1
- package/package.json +12 -7
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `st.json` stores JSON data using a string serializer
|
|
3
|
+
*
|
|
4
|
+
* ```
|
|
5
|
+
* st.json(st.string(st.u32()))
|
|
6
|
+
* ```
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
export function json(type) {
|
|
10
|
+
return {
|
|
11
|
+
size: type.size,
|
|
12
|
+
write: (ctx, value) => {
|
|
13
|
+
const json = JSON.stringify(value);
|
|
14
|
+
type.write(ctx, json);
|
|
15
|
+
},
|
|
16
|
+
read: (ctx) => {
|
|
17
|
+
const value = type.read(ctx);
|
|
18
|
+
return JSON.parse(value);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function sizedBytes(length) {
|
|
2
|
+
return {
|
|
3
|
+
write: (ctx, value) => {
|
|
4
|
+
length.write(ctx, value.byteLength);
|
|
5
|
+
const bytes = new Uint8Array(value);
|
|
6
|
+
ctx.alloc(value.byteLength);
|
|
7
|
+
new Uint8Array(ctx.view.buffer).set(bytes, ctx.offset);
|
|
8
|
+
ctx.offset += value.byteLength;
|
|
9
|
+
},
|
|
10
|
+
read: (ctx) => {
|
|
11
|
+
const size = length.read(ctx);
|
|
12
|
+
const slice = ctx.buffer.slice(ctx.offset, ctx.offset + size);
|
|
13
|
+
ctx.offset += size;
|
|
14
|
+
return slice;
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it } from "bun:test";
|
|
2
|
+
import { bytes, encodeFailTest, encodeTest } from "../../utils.test";
|
|
3
|
+
import * as st from "../../index";
|
|
4
|
+
describe("st.sizedBytes", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
const buffer = st.sizedBytes(st.u8());
|
|
7
|
+
encodeTest(buffer, bytes([1, 2]));
|
|
8
|
+
});
|
|
9
|
+
it("encodes empty correctly", () => {
|
|
10
|
+
const spec = st.sizedBytes(st.u8());
|
|
11
|
+
encodeTest(spec, bytes([]));
|
|
12
|
+
});
|
|
13
|
+
it("holds large data", () => {
|
|
14
|
+
const size = 1024 * 1024 * 8; // 8MB
|
|
15
|
+
const spec = st.sizedBytes(st.u32());
|
|
16
|
+
const data = new Uint8Array(size);
|
|
17
|
+
data.set([3, 4], 1000);
|
|
18
|
+
data.set([3, 4], 2000);
|
|
19
|
+
encodeTest(spec, data.buffer);
|
|
20
|
+
});
|
|
21
|
+
it("errors on invalid length", () => {
|
|
22
|
+
encodeFailTest(st.sizedBytes(st.u8()), //
|
|
23
|
+
bytes(Array.from({ length: 256 }, () => 0)));
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Serializer } from "../../types";
|
|
2
|
+
/**
|
|
3
|
+
* `st.json` stores string data by writing/reading the length and then reading that many bytes
|
|
4
|
+
*
|
|
5
|
+
* The type passed in is the type used to store it's length
|
|
6
|
+
*
|
|
7
|
+
* Note: The length stored is the byte length, not string length
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* st.string(st.u32())
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export declare function string(length: Serializer<number>): Serializer<string>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `st.json` stores string data by writing/reading the length and then reading that many bytes
|
|
3
|
+
*
|
|
4
|
+
* The type passed in is the type used to store it's length
|
|
5
|
+
*
|
|
6
|
+
* Note: The length stored is the byte length, not string length
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* st.string(st.u32())
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
export function string(length) {
|
|
14
|
+
const encoder = new TextEncoder();
|
|
15
|
+
const decoder = new TextDecoder();
|
|
16
|
+
const lengthSize = length.size ?? 0;
|
|
17
|
+
return {
|
|
18
|
+
write: (ctx, value) => {
|
|
19
|
+
if (typeof value !== "string")
|
|
20
|
+
throw new Error("Expected String");
|
|
21
|
+
const bytes = encoder.encode(value);
|
|
22
|
+
const size = bytes.byteLength;
|
|
23
|
+
ctx.alloc(size + lengthSize);
|
|
24
|
+
length.write(ctx, size);
|
|
25
|
+
const arr = new Uint8Array(ctx.buffer, ctx.offset);
|
|
26
|
+
arr.set(bytes);
|
|
27
|
+
ctx.offset += size;
|
|
28
|
+
},
|
|
29
|
+
read: (ctx) => {
|
|
30
|
+
const size = length.read(ctx);
|
|
31
|
+
const section = ctx.buffer.slice(ctx.offset, ctx.offset + size);
|
|
32
|
+
ctx.offset += size;
|
|
33
|
+
return decoder.decode(section);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, it } from "bun:test";
|
|
2
|
+
import { encodeFailTest, encodeTest } from "../../utils.test";
|
|
3
|
+
import * as st from "../../index";
|
|
4
|
+
describe("st.string", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.string(st.u8()), "foo");
|
|
7
|
+
});
|
|
8
|
+
it("works on empty strings", () => {
|
|
9
|
+
encodeTest(st.string(st.u32()), "");
|
|
10
|
+
});
|
|
11
|
+
it("errors on numbers", () => {
|
|
12
|
+
//@ts-expect-error, intentional mistake
|
|
13
|
+
encodeFailTest(st.string(st.u8()), 8);
|
|
14
|
+
});
|
|
15
|
+
it("errors on too long strings", () => {
|
|
16
|
+
encodeFailTest(st.string(st.u8()), "A".repeat(256));
|
|
17
|
+
});
|
|
18
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type { InferInput as Infer, InferInput, InferOutput, ReaderContext, WriterContext, Serializer, } from "./types";
|
|
2
|
-
export * from "./datatypes/index";
|
|
3
2
|
export { read, createReaderContext } from "./read";
|
|
4
3
|
export { write, createdWriterContext } from "./write";
|
|
4
|
+
export * from "./datatypes/index";
|
|
5
|
+
export * from "./transforms/index";
|
|
6
|
+
export * from "./utilities/index";
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { encode } from "./encode";
|
|
2
|
+
export function enum_(values) {
|
|
3
|
+
return encode((v) => {
|
|
4
|
+
if (!values.includes(v))
|
|
5
|
+
throw new Error(`Invalid enum variant: ${v}`);
|
|
6
|
+
return v;
|
|
7
|
+
}, (v) => {
|
|
8
|
+
if (!values.includes(v))
|
|
9
|
+
throw new Error(`Invalid enum variant: ${v}`);
|
|
10
|
+
return v;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export { enum_ as enum };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import * as st from "../index";
|
|
3
|
+
import { encodeTest, encodeFailTest } from "../utils.test";
|
|
4
|
+
describe("st.enum", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.pipe(st.u8(), st.enum([0, 1, 2])), //
|
|
7
|
+
1);
|
|
8
|
+
encodeTest(st.pipe(st.string(st.u8()), st.enum(["foo", "bar", "woof"])), //
|
|
9
|
+
"foo");
|
|
10
|
+
});
|
|
11
|
+
it("invalid union variants error", () => {
|
|
12
|
+
//@ts-expect-error
|
|
13
|
+
encodeFailTest(st.pipe(st.u8(), st.enum([0, 1, 2])), 4);
|
|
14
|
+
//@ts-expect-error
|
|
15
|
+
encodeFailTest(st.pipe(st.string(st.u8()), st.enum(["A", "B", "C"])), "D");
|
|
16
|
+
});
|
|
17
|
+
() => {
|
|
18
|
+
//@ts-expect-error, invalid union variant
|
|
19
|
+
st.write(st.pipe(st.u8(), st.enum([0, 1, 2])), 4);
|
|
20
|
+
};
|
|
21
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function fixedOffset(delta) {
|
|
2
|
+
return (type) => ({
|
|
3
|
+
size: type.size,
|
|
4
|
+
read: (ctx) => {
|
|
5
|
+
let start = ctx.offset;
|
|
6
|
+
ctx.offset += delta;
|
|
7
|
+
const value = type.read(ctx);
|
|
8
|
+
ctx.offset = start;
|
|
9
|
+
return value;
|
|
10
|
+
},
|
|
11
|
+
write: (ctx, value) => {
|
|
12
|
+
let start = ctx.offset;
|
|
13
|
+
ctx.offset += delta;
|
|
14
|
+
type.write(ctx, value);
|
|
15
|
+
ctx.offset = start;
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { type Transform as Pipeline, pipe } from "./pipe";
|
|
2
|
+
export { encode } from "./encode";
|
|
3
|
+
export { modify } from "./modify";
|
|
4
|
+
export { literal } from "./literal";
|
|
5
|
+
export { enum } from "./enum";
|
|
6
|
+
export { fixedOffset } from "./fixedOffset";
|
|
7
|
+
export { noAdvance } from "./noAdvance";
|
|
8
|
+
export { toAscii } from "./toAscii";
|
|
9
|
+
export { toBytes } from "./toBytes";
|
|
10
|
+
export { toHex } from "./toHex";
|
|
11
|
+
export { toBase64 } from "./toBase64";
|
|
12
|
+
export { toTypedArray } from "./toTypedArray";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { pipe } from "./pipe";
|
|
2
|
+
export { encode } from "./encode";
|
|
3
|
+
export { modify } from "./modify";
|
|
4
|
+
export { literal } from "./literal";
|
|
5
|
+
export { enum } from "./enum";
|
|
6
|
+
export { fixedOffset } from "./fixedOffset";
|
|
7
|
+
export { noAdvance } from "./noAdvance";
|
|
8
|
+
export { toAscii } from "./toAscii";
|
|
9
|
+
export { toBytes } from "./toBytes";
|
|
10
|
+
export { toHex } from "./toHex";
|
|
11
|
+
export { toBase64 } from "./toBase64";
|
|
12
|
+
export { toTypedArray } from "./toTypedArray";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function literal<const T>(value: T): import("./pipe").Transform<T, any>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { encode } from "./encode";
|
|
2
|
+
export function literal(value) {
|
|
3
|
+
return encode((v) => {
|
|
4
|
+
if (v !== value)
|
|
5
|
+
throw new Error(`Invalid literal variant: ${v}`);
|
|
6
|
+
return v;
|
|
7
|
+
}, (v) => {
|
|
8
|
+
if (v !== value)
|
|
9
|
+
throw new Error(`Invalid literal variant: ${v}`);
|
|
10
|
+
return v;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import * as st from "../index";
|
|
3
|
+
import { encodeTest, encodeFailTest } from "../utils.test";
|
|
4
|
+
describe("st.literal", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.pipe(st.u8(), st.literal(0)), //
|
|
7
|
+
0);
|
|
8
|
+
encodeTest(st.pipe(st.string(st.u8()), st.literal("foo")), //
|
|
9
|
+
"foo");
|
|
10
|
+
});
|
|
11
|
+
it("invalid literal errors", () => {
|
|
12
|
+
//@ts-expect-error
|
|
13
|
+
encodeFailTest(st.pipe(st.u8(), st.literal(0)), 2);
|
|
14
|
+
//@ts-expect-error
|
|
15
|
+
encodeFailTest(st.pipe(st.string(st.u8()), st.literal("A")), "B");
|
|
16
|
+
});
|
|
17
|
+
() => {
|
|
18
|
+
//@ts-expect-error, invalid union variant
|
|
19
|
+
st.write(st.pipe(st.u8(), st.literal(0)), 1);
|
|
20
|
+
//@ts-expect-error, invalid union variant
|
|
21
|
+
st.write(st.pipe(st.u8(), st.literal("foo")), "bar");
|
|
22
|
+
};
|
|
23
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Serializer } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Whilst reading this type, don't advance the offset after reading
|
|
4
|
+
*
|
|
5
|
+
* This can be useful for taggedUnions where they key is the first value in all the variants
|
|
6
|
+
*
|
|
7
|
+
* ```
|
|
8
|
+
* st.object({
|
|
9
|
+
* stringLength: st.pipe(
|
|
10
|
+
* st.u16(),
|
|
11
|
+
* st.noAdvance(),
|
|
12
|
+
* ),
|
|
13
|
+
* text: st.string(st.u16()),
|
|
14
|
+
* })
|
|
15
|
+
*/
|
|
16
|
+
export declare function noAdvance<T>(): (type: Serializer<T>) => Serializer<T>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whilst reading this type, don't advance the offset after reading
|
|
3
|
+
*
|
|
4
|
+
* This can be useful for taggedUnions where they key is the first value in all the variants
|
|
5
|
+
*
|
|
6
|
+
* ```
|
|
7
|
+
* st.object({
|
|
8
|
+
* stringLength: st.pipe(
|
|
9
|
+
* st.u16(),
|
|
10
|
+
* st.noAdvance(),
|
|
11
|
+
* ),
|
|
12
|
+
* text: st.string(st.u16()),
|
|
13
|
+
* })
|
|
14
|
+
*/
|
|
15
|
+
export function noAdvance() {
|
|
16
|
+
return (type) => ({
|
|
17
|
+
size: type.size,
|
|
18
|
+
read: (ctx) => {
|
|
19
|
+
let start = ctx.offset;
|
|
20
|
+
const value = type.read(ctx);
|
|
21
|
+
ctx.offset = start;
|
|
22
|
+
return value;
|
|
23
|
+
},
|
|
24
|
+
write: (ctx, value) => {
|
|
25
|
+
let start = ctx.offset;
|
|
26
|
+
type.write(ctx, value);
|
|
27
|
+
ctx.offset = start;
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import * as st from "../index";
|
|
3
|
+
import { encodeTest } from "../utils.test";
|
|
4
|
+
describe("st.noAdvance", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.object({
|
|
7
|
+
length: st.pipe(st.u8(), st.noAdvance()),
|
|
8
|
+
text: st.string(st.u8()),
|
|
9
|
+
}), //
|
|
10
|
+
{ length: 3, text: "foo" });
|
|
11
|
+
encodeTest(st.object({
|
|
12
|
+
a: st.pipe(st.u16(), st.noAdvance()),
|
|
13
|
+
b: st.f16(),
|
|
14
|
+
}), //
|
|
15
|
+
{ a: 0, b: 1 }, { a: 15360, b: 1 });
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Serializer } from "../types";
|
|
2
|
+
export type Transform<T = any, TNext = T> = (type: Serializer<TNext>) => Serializer<T>;
|
|
3
|
+
export declare function pipe<TStart, T1>(type: Serializer<TStart>, p1: Transform<T1, TStart>): Serializer<T1>;
|
|
4
|
+
export declare function pipe<TStart, T1, T2>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>): Serializer<T2>;
|
|
5
|
+
export declare function pipe<TStart, T1, T2, T3>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>): Serializer<T3>;
|
|
6
|
+
export declare function pipe<TStart, T1, T2, T3, T4>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>): Serializer<T4>;
|
|
7
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T4>): Serializer<T5>;
|
|
8
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>): Serializer<T6>;
|
|
9
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6, T7>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>, p6: Transform<T6, T7>): Serializer<T7>;
|
|
10
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6, T7, T8>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>, p6: Transform<T6, T7>, p7: Transform<T7, T8>): Serializer<T8>;
|
|
11
|
+
export declare function pipe<TStart, T1, T2, T3, T4, T5, T6, T7, T8, T9>(type: Serializer<TStart>, p1: Transform<T1, TStart>, p2: Transform<T2, T1>, p3: Transform<T3, T2>, p4: Transform<T4, T3>, p5: Transform<T5, T6>, p6: Transform<T6, T7>, p7: Transform<T7, T8>, p8: Transform<T8, T9>): Serializer<T9>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipe lets you chain modification functions together
|
|
3
|
+
* ```
|
|
4
|
+
* st.object({
|
|
5
|
+
* age: st.u32(),
|
|
6
|
+
* ageInMonths: st.pipe(
|
|
7
|
+
* st.u32(),
|
|
8
|
+
* st.modify(v => v * 12),
|
|
9
|
+
* st.offset(-8),
|
|
10
|
+
* )})
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function pipe(type, ...pipeline) {
|
|
14
|
+
//@ts-ignore
|
|
15
|
+
return pipeline.reduce((v, func) => func(v), type);
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toAscii(): import("./pipe").Transform<string, ArrayBuffer>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { encode } from "./encode";
|
|
2
|
+
export function toAscii() {
|
|
3
|
+
return encode((v) => new Uint8Array(Array.from(v).map((char) => validateAscii(char.charCodeAt(0)))).buffer, (v) => Array.from(new Uint8Array(v))
|
|
4
|
+
.map((v) => String.fromCharCode(v))
|
|
5
|
+
.join(""));
|
|
6
|
+
}
|
|
7
|
+
const validateAscii = (v) => {
|
|
8
|
+
if (v >= 0 && v <= 127)
|
|
9
|
+
return v;
|
|
10
|
+
throw new Error(`Invalid value: ${v}`);
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it } from "bun:test";
|
|
2
|
+
import { encodeTest, encodeSnapshotTest, encodeFailTest } from "../utils.test";
|
|
3
|
+
import * as st from "../index";
|
|
4
|
+
describe("st.toAscii", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.pipe(st.bytes(5), st.toAscii()), //
|
|
7
|
+
"a6534");
|
|
8
|
+
encodeTest(st.pipe(st.bytes(3), st.toAscii()), //
|
|
9
|
+
"-as");
|
|
10
|
+
});
|
|
11
|
+
it("invalid length throws error", () => {
|
|
12
|
+
encodeFailTest(st.pipe(st.bytes(4), st.toAscii()), //
|
|
13
|
+
"asd");
|
|
14
|
+
});
|
|
15
|
+
it("invalid character throws error", () => {
|
|
16
|
+
encodeFailTest(st.pipe(st.bytes(4), st.toAscii()), //
|
|
17
|
+
"asdé");
|
|
18
|
+
});
|
|
19
|
+
it("snapshots", () => {
|
|
20
|
+
encodeSnapshotTest(st.pipe(st.bytes(4), st.toAscii()), //
|
|
21
|
+
"634f");
|
|
22
|
+
encodeSnapshotTest(st.pipe(st.bytes(6), st.toAscii()), //
|
|
23
|
+
"hdjdp_");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toBase64(): import("./pipe").Transform<string, ArrayBuffer>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, it } from "bun:test";
|
|
2
|
+
import { encodeTest, encodeSnapshotTest, encodeFailTest } from "../utils.test";
|
|
3
|
+
import * as st from "../index";
|
|
4
|
+
describe("st.toBase64", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.pipe(st.bytes(1), st.toBase64()), //
|
|
7
|
+
"rw==");
|
|
8
|
+
encodeTest(st.pipe(st.bytes(2), st.toBase64()), //
|
|
9
|
+
"rx8=");
|
|
10
|
+
encodeTest(st.pipe(st.bytes(3), st.toBase64()), //
|
|
11
|
+
"rx9K");
|
|
12
|
+
});
|
|
13
|
+
it("invalid character error", () => {
|
|
14
|
+
encodeFailTest(st.pipe(st.bytes(3), st.toBase64()), //
|
|
15
|
+
"rx9-");
|
|
16
|
+
});
|
|
17
|
+
it("invalid length error", () => {
|
|
18
|
+
encodeFailTest(st.pipe(st.bytes(4), st.toBase64()), //
|
|
19
|
+
"rx9L");
|
|
20
|
+
});
|
|
21
|
+
it("snapshots", () => {
|
|
22
|
+
encodeSnapshotTest(st.pipe(st.bytes(3), st.toBase64()), //
|
|
23
|
+
"rx9K");
|
|
24
|
+
encodeSnapshotTest(st.pipe(st.bytes(6), st.toBase64()), //
|
|
25
|
+
"fR9KIj8V");
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an ArrayBuffer to the byte digits
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* st.pipe(
|
|
6
|
+
* st.bytes(3),
|
|
7
|
+
* st.toBytes()
|
|
8
|
+
* )
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* `ArrayBuffer([0, 255, c])` => `[0, 255, ArrayBuffer([0, 255, 0])]`
|
|
12
|
+
*/
|
|
13
|
+
export declare function toBytes(): import("./pipe").Transform<number[], ArrayBuffer>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { encode } from "./encode";
|
|
2
|
+
/**
|
|
3
|
+
* Converts an ArrayBuffer to the byte digits
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* st.pipe(
|
|
7
|
+
* st.bytes(3),
|
|
8
|
+
* st.toBytes()
|
|
9
|
+
* )
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* `ArrayBuffer([0, 255, c])` => `[0, 255, ArrayBuffer([0, 255, 0])]`
|
|
13
|
+
*/
|
|
14
|
+
export function toBytes() {
|
|
15
|
+
return encode((v) => new Uint8Array(v.map(validateByte)).buffer, (v) => Array.from(new Uint8Array(v)));
|
|
16
|
+
}
|
|
17
|
+
const validateByte = (v) => {
|
|
18
|
+
if (v >= 0 && v <= 255)
|
|
19
|
+
return v;
|
|
20
|
+
throw new Error(`Invalid value: ${v}`);
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, it } from "bun:test";
|
|
2
|
+
import { encodeTest, encodeSnapshotTest, encodeFailTest } from "../utils.test";
|
|
3
|
+
import * as st from "../index";
|
|
4
|
+
describe("st.toBytes", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.pipe(st.bytes(3), st.toBytes()), //
|
|
7
|
+
[0, 1, 2]);
|
|
8
|
+
encodeTest(st.pipe(st.bytes(3), st.toBytes()), //
|
|
9
|
+
[255, 0, 127]);
|
|
10
|
+
});
|
|
11
|
+
it("invalid length throws error", () => {
|
|
12
|
+
encodeFailTest(st.pipe(st.bytes(3), st.toBytes()), //
|
|
13
|
+
[0, 1]);
|
|
14
|
+
});
|
|
15
|
+
it("invalid values throws error", () => {
|
|
16
|
+
encodeFailTest(st.pipe(st.bytes(3), st.toBytes()), //
|
|
17
|
+
[256, 1, 1]);
|
|
18
|
+
encodeFailTest(st.pipe(st.bytes(3), st.toBytes()), //
|
|
19
|
+
[-1, 1, 1]);
|
|
20
|
+
});
|
|
21
|
+
it("snapshots", () => {
|
|
22
|
+
encodeSnapshotTest(st.pipe(st.bytes(3), st.toBytes()), //
|
|
23
|
+
[73, 12, 3]);
|
|
24
|
+
encodeSnapshotTest(st.pipe(st.bytes(6), st.toBytes()), //
|
|
25
|
+
[34, 10, 0, 74, 31, 23]);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts an ArrayBuffer to uppercase hex
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* st.pipe(
|
|
6
|
+
* st.bytes(3),
|
|
7
|
+
* st.toHex()
|
|
8
|
+
* )
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* `ArrayBuffer([0, 255, 0])` => `00FF00`
|
|
12
|
+
*/
|
|
13
|
+
export declare function toHex(): import("./pipe").Transform<string, ArrayBuffer>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { encode } from "./encode";
|
|
2
|
+
/**
|
|
3
|
+
* Converts an ArrayBuffer to uppercase hex
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* st.pipe(
|
|
7
|
+
* st.bytes(3),
|
|
8
|
+
* st.toHex()
|
|
9
|
+
* )
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* `ArrayBuffer([0, 255, 0])` => `00FF00`
|
|
13
|
+
*/
|
|
14
|
+
export function toHex() {
|
|
15
|
+
return encode((v) => Uint8Array.fromHex(v).buffer, (v) => new Uint8Array(v).toHex().toUpperCase());
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, it } from "bun:test";
|
|
2
|
+
import { encodeTest, encodeSnapshotTest, encodeFailTest } from "../utils.test";
|
|
3
|
+
import * as st from "../index";
|
|
4
|
+
describe("st.toHex", () => {
|
|
5
|
+
it("encode correctly", () => {
|
|
6
|
+
encodeTest(st.pipe(st.bytes(3), st.toHex()), //
|
|
7
|
+
"FFAB01");
|
|
8
|
+
});
|
|
9
|
+
it("invalid digits error", () => {
|
|
10
|
+
encodeFailTest(st.pipe(st.bytes(3), st.toHex()), //
|
|
11
|
+
"00000G");
|
|
12
|
+
});
|
|
13
|
+
it("invalid length error", () => {
|
|
14
|
+
encodeFailTest(st.pipe(st.bytes(3), st.toHex()), //
|
|
15
|
+
"0000");
|
|
16
|
+
});
|
|
17
|
+
it("snapshots", () => {
|
|
18
|
+
encodeSnapshotTest(st.pipe(st.bytes(3), st.toHex()), //
|
|
19
|
+
"FFAB01");
|
|
20
|
+
encodeSnapshotTest(st.pipe(st.bytes(5), st.toHex()), //
|
|
21
|
+
"0000000000");
|
|
22
|
+
});
|
|
23
|
+
});
|