@nnilky/structo 1.0.4 → 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.
Files changed (140) hide show
  1. package/README.md +1 -1
  2. package/dist/datatypes/containers/array.d.ts +8 -0
  3. package/dist/datatypes/containers/array.js +8 -0
  4. package/dist/datatypes/containers/array.test.js +6 -10
  5. package/dist/datatypes/containers/exhuastiveArray.d.ts +9 -0
  6. package/dist/datatypes/containers/exhuastiveArray.js +24 -0
  7. package/dist/datatypes/containers/exhuastiveArray.test.js +38 -0
  8. package/dist/datatypes/containers/fastObject.d.ts +2 -0
  9. package/dist/datatypes/containers/fastObject.js +2 -0
  10. package/dist/datatypes/containers/fastObject.test.js +45 -0
  11. package/dist/datatypes/containers/list.d.ts +11 -4
  12. package/dist/datatypes/containers/list.js +17 -9
  13. package/dist/datatypes/containers/list.test.js +9 -17
  14. package/dist/datatypes/containers/object.js +7 -1
  15. package/dist/datatypes/containers/object.test.js +23 -11
  16. package/dist/datatypes/containers/sizedbytes.d.ts +2 -0
  17. package/dist/datatypes/containers/{sizedbuffer.js → sizedbytes.js} +1 -1
  18. package/dist/datatypes/containers/{sizedbuffer.test.js → sizedbytes.test.js} +5 -5
  19. package/dist/datatypes/containers/string.d.ts +2 -0
  20. package/dist/datatypes/containers/string.js +24 -0
  21. package/dist/datatypes/containers/string.test.js +24 -0
  22. package/dist/datatypes/containers/taggedUnion.d.ts +26 -0
  23. package/dist/datatypes/containers/taggedUnion.js +35 -0
  24. package/dist/datatypes/containers/taggedUnion.test.js +67 -0
  25. package/dist/datatypes/index.d.ts +5 -8
  26. package/dist/datatypes/index.js +5 -8
  27. package/dist/datatypes/numbers/bigints.d.ts +10 -0
  28. package/dist/datatypes/numbers/bigints.js +10 -0
  29. package/dist/datatypes/numbers/bigints.test.js +11 -11
  30. package/dist/datatypes/numbers/floats.d.ts +4 -0
  31. package/dist/datatypes/numbers/floats.js +18 -0
  32. package/dist/datatypes/numbers/floats.test.js +49 -47
  33. package/dist/datatypes/numbers/sints.d.ts +4 -0
  34. package/dist/datatypes/numbers/sints.js +4 -0
  35. package/dist/datatypes/numbers/sints.test.js +11 -11
  36. package/dist/datatypes/numbers/uints.d.ts +4 -0
  37. package/dist/datatypes/numbers/uints.js +4 -0
  38. package/dist/datatypes/numbers/uints.test.js +11 -11
  39. package/dist/datatypes/transforms/encode.d.ts +2 -0
  40. package/dist/datatypes/transforms/encode.js +7 -0
  41. package/dist/datatypes/transforms/fixedOffset.d.ts +2 -0
  42. package/dist/datatypes/transforms/{readOffset.js → fixedOffset.js} +1 -1
  43. package/dist/datatypes/transforms/modify.d.ts +2 -0
  44. package/dist/datatypes/transforms/modify.js +7 -0
  45. package/dist/datatypes/transforms/noAdvance.d.ts +16 -0
  46. package/dist/datatypes/transforms/noAdvance.js +30 -0
  47. package/dist/datatypes/transforms/pipe.js +12 -0
  48. package/dist/datatypes/utilities/remember.d.ts +11 -1
  49. package/dist/datatypes/utilities/remember.js +15 -5
  50. package/dist/datatypes/utilities/remember.test.d.ts +1 -0
  51. package/dist/datatypes/utilities/remember.test.js +44 -0
  52. package/dist/datatypes/utils.test.d.ts +2 -1
  53. package/dist/datatypes/utils.test.js +6 -2
  54. package/dist/datatypes/values/byteliteral.d.ts +1 -1
  55. package/dist/datatypes/values/byteliteral.js +1 -1
  56. package/dist/datatypes/values/bytes.d.ts +9 -0
  57. package/dist/datatypes/values/{buffer.js → bytes.js} +8 -1
  58. package/dist/datatypes/values/bytes.test.d.ts +1 -0
  59. package/dist/datatypes/values/{buffer.test.js → bytes.test.js} +12 -14
  60. package/dist/datatypes/values/json.d.ts +10 -0
  61. package/dist/datatypes/values/json.js +21 -0
  62. package/dist/datatypes/values/sizedbytes.d.ts +2 -0
  63. package/dist/datatypes/values/sizedbytes.js +17 -0
  64. package/dist/datatypes/values/sizedbytes.test.d.ts +1 -0
  65. package/dist/datatypes/values/sizedbytes.test.js +25 -0
  66. package/dist/datatypes/values/string.d.ts +12 -0
  67. package/dist/datatypes/values/string.js +22 -8
  68. package/dist/datatypes/values/string.test.js +8 -8
  69. package/dist/index.d.ts +3 -1
  70. package/dist/index.js +3 -1
  71. package/dist/read.d.ts +1 -1
  72. package/dist/transforms/encode.d.ts +2 -0
  73. package/dist/transforms/encode.js +7 -0
  74. package/dist/transforms/enum.d.ts +2 -0
  75. package/dist/transforms/enum.js +13 -0
  76. package/dist/transforms/enum.test.d.ts +1 -0
  77. package/dist/transforms/enum.test.js +21 -0
  78. package/dist/transforms/fixedOffset.d.ts +2 -0
  79. package/dist/transforms/fixedOffset.js +18 -0
  80. package/dist/transforms/index.d.ts +12 -0
  81. package/dist/transforms/index.js +12 -0
  82. package/dist/transforms/literal.d.ts +1 -0
  83. package/dist/transforms/literal.js +12 -0
  84. package/dist/transforms/literal.test.d.ts +1 -0
  85. package/dist/transforms/literal.test.js +23 -0
  86. package/dist/transforms/modify.d.ts +2 -0
  87. package/dist/transforms/modify.js +7 -0
  88. package/dist/transforms/noAdvance.d.ts +16 -0
  89. package/dist/transforms/noAdvance.js +30 -0
  90. package/dist/transforms/noAdvance.test.d.ts +1 -0
  91. package/dist/transforms/noAdvance.test.js +17 -0
  92. package/dist/transforms/pipe.d.ts +11 -0
  93. package/dist/transforms/pipe.js +16 -0
  94. package/dist/transforms/toAscii.d.ts +1 -0
  95. package/dist/transforms/toAscii.js +11 -0
  96. package/dist/transforms/toAscii.test.d.ts +1 -0
  97. package/dist/transforms/toAscii.test.js +25 -0
  98. package/dist/transforms/toBase64.d.ts +1 -0
  99. package/dist/transforms/toBase64.js +4 -0
  100. package/dist/transforms/toBase64.test.d.ts +1 -0
  101. package/dist/transforms/toBase64.test.js +27 -0
  102. package/dist/transforms/toBytes.d.ts +13 -0
  103. package/dist/transforms/toBytes.js +21 -0
  104. package/dist/transforms/toBytes.test.d.ts +1 -0
  105. package/dist/transforms/toBytes.test.js +27 -0
  106. package/dist/transforms/toHex.d.ts +13 -0
  107. package/dist/transforms/toHex.js +16 -0
  108. package/dist/transforms/toHex.test.d.ts +1 -0
  109. package/dist/transforms/toHex.test.js +23 -0
  110. package/dist/transforms/toTypedArray.d.ts +16 -0
  111. package/dist/transforms/toTypedArray.js +14 -0
  112. package/dist/transforms/toTypedArray.test.d.ts +1 -0
  113. package/dist/transforms/toTypedArray.test.js +29 -0
  114. package/dist/utilities/index.d.ts +2 -0
  115. package/dist/utilities/index.js +2 -0
  116. package/dist/utilities/lazy.d.ts +2 -0
  117. package/dist/utilities/lazy.js +25 -0
  118. package/dist/utilities/lazy.test.d.ts +1 -0
  119. package/dist/utilities/lazy.test.js +36 -0
  120. package/dist/utilities/remember.d.ts +17 -0
  121. package/dist/utilities/remember.js +38 -0
  122. package/dist/utilities/remember.test.d.ts +1 -0
  123. package/dist/utilities/remember.test.js +76 -0
  124. package/dist/utils.test.d.ts +9 -1
  125. package/dist/utils.test.js +42 -1
  126. package/dist/write.d.ts +1 -1
  127. package/package.json +12 -7
  128. package/dist/datatypes/containers/sizedbuffer.d.ts +0 -2
  129. package/dist/datatypes/transforms/pipe.test.js +0 -13
  130. package/dist/datatypes/transforms/readOffset.d.ts +0 -2
  131. package/dist/datatypes/transforms/transform.d.ts +0 -2
  132. package/dist/datatypes/transforms/transform.js +0 -13
  133. package/dist/datatypes/utilities/constant.d.ts +0 -2
  134. package/dist/datatypes/utilities/constant.js +0 -13
  135. package/dist/datatypes/values/buffer.d.ts +0 -2
  136. /package/dist/datatypes/containers/{sizedbuffer.test.d.ts → exhuastiveArray.test.d.ts} +0 -0
  137. /package/dist/datatypes/{lazy.d.ts → containers/fastObject.test.d.ts} +0 -0
  138. /package/dist/datatypes/{lazy.js → containers/sizedbytes.test.d.ts} +0 -0
  139. /package/dist/datatypes/{transforms/pipe.test.d.ts → containers/string.test.d.ts} +0 -0
  140. /package/dist/datatypes/{values/buffer.test.d.ts → containers/taggedUnion.test.d.ts} +0 -0
@@ -0,0 +1,9 @@
1
+ import type { Serializer } from "../../types";
2
+ /**
3
+ * Fixed length bytes
4
+ *
5
+ * ```
6
+ * st.bytes(4)
7
+ * ```
8
+ */
9
+ export declare function bytes(size: number): Serializer<ArrayBuffer>;
@@ -1,4 +1,11 @@
1
- export function buffer(size) {
1
+ /**
2
+ * Fixed length bytes
3
+ *
4
+ * ```
5
+ * st.bytes(4)
6
+ * ```
7
+ */
8
+ export function bytes(size) {
2
9
  return {
3
10
  size,
4
11
  write: (ctx, value) => {
@@ -0,0 +1 @@
1
+ export {};
@@ -1,43 +1,41 @@
1
1
  import { describe, it } from "bun:test";
2
- import { bytes, expectEncode, expectError } from "../utils.test";
2
+ import { bytes, encodeFailTest, encodeTest } from "../../utils.test";
3
3
  import * as st from "../../index";
4
- describe("st.buffer", () => {
5
- const buffer = st.buffer(2);
4
+ describe("st.bytes", () => {
5
+ const buffer = st.bytes(2);
6
6
  it("encode correctly", () => {
7
- expectEncode(buffer, bytes([1, 2]));
7
+ encodeTest(buffer, bytes([1, 2]));
8
8
  });
9
9
  it("encodes empty correctly", () => {
10
- const spec = st.buffer(0);
11
- expectEncode(spec, bytes([]));
10
+ const spec = st.bytes(0);
11
+ encodeTest(spec, bytes([]));
12
12
  });
13
13
  it("holds large data", () => {
14
14
  const size = 1024 * 1024 * 8; // 8MB
15
- const spec = st.buffer(size);
15
+ const spec = st.bytes(size);
16
16
  const data = new Uint8Array(size);
17
17
  data.set([3, 4], 1000);
18
18
  data.set([3, 4], 2000);
19
- expectEncode(spec, data.buffer);
19
+ encodeTest(spec, data.buffer);
20
20
  });
21
21
  it("large data writes work", () => {
22
22
  const size = 1024 * 1024 * 8; // 8MB
23
23
  const spec = st.object({
24
24
  before: st.u8(),
25
- data: st.buffer(size),
25
+ data: st.bytes(size),
26
26
  after: st.u8(),
27
27
  });
28
28
  const data = new Uint8Array(size);
29
29
  data.set([3, 4], 1000);
30
30
  data.set([3, 4], 2000);
31
- expectEncode(spec, {
31
+ encodeTest(spec, {
32
32
  before: 1,
33
33
  data: data.buffer,
34
34
  after: 2,
35
35
  });
36
36
  });
37
37
  it("errors on invalid length", () => {
38
- const spec = st.buffer(5);
39
- expectError(() => {
40
- st.write(spec, bytes([1, 2, 3, 4]));
41
- });
38
+ const spec = st.bytes(5);
39
+ encodeFailTest(spec, bytes([1, 2, 3, 4]));
42
40
  });
43
41
  });
@@ -0,0 +1,10 @@
1
+ import type { Serializer } from "../../types";
2
+ /**
3
+ * `st.json` stores JSON data using a string serializer
4
+ *
5
+ * ```
6
+ * st.json(st.string(st.u32()))
7
+ * ```
8
+ *
9
+ */
10
+ export declare function json(type: Serializer<string>): Serializer<any>;
@@ -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,2 @@
1
+ import type { Serializer } from "../../types";
2
+ export declare function sizedBytes(length: Serializer<number>): Serializer<ArrayBuffer>;
@@ -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
+ });
@@ -1,2 +1,14 @@
1
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
+ */
2
14
  export declare function string(length: Serializer<number>): Serializer<string>;
@@ -1,21 +1,35 @@
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
+ */
1
13
  export function string(length) {
2
- const { read: readLength, write: writeLength, size: lengthSize = 0 } = length;
3
14
  const encoder = new TextEncoder();
4
15
  const decoder = new TextDecoder();
16
+ const lengthSize = length.size ?? 0;
5
17
  return {
6
18
  write: (ctx, value) => {
19
+ if (typeof value !== "string")
20
+ throw new Error("Expected String");
7
21
  const bytes = encoder.encode(value);
8
- const length = bytes.byteLength;
9
- ctx.alloc(length + lengthSize);
10
- writeLength(ctx, length);
22
+ const size = bytes.byteLength;
23
+ ctx.alloc(size + lengthSize);
24
+ length.write(ctx, size);
11
25
  const arr = new Uint8Array(ctx.buffer, ctx.offset);
12
26
  arr.set(bytes);
13
- ctx.offset += length;
27
+ ctx.offset += size;
14
28
  },
15
29
  read: (ctx) => {
16
- const length = readLength(ctx);
17
- const section = ctx.buffer.slice(ctx.offset, ctx.offset + length);
18
- ctx.offset += length;
30
+ const size = length.read(ctx);
31
+ const section = ctx.buffer.slice(ctx.offset, ctx.offset + size);
32
+ ctx.offset += size;
19
33
  return decoder.decode(section);
20
34
  },
21
35
  };
@@ -1,18 +1,18 @@
1
1
  import { describe, it } from "bun:test";
2
- import { expectEncode, expectError } from "../utils.test";
2
+ import { encodeFailTest, encodeTest } from "../../utils.test";
3
3
  import * as st from "../../index";
4
4
  describe("st.string", () => {
5
- const string_u8 = st.string(st.u8());
6
- const string_u32 = st.string(st.u32());
7
5
  it("encode correctly", () => {
8
- expectEncode(string_u8, "foo");
6
+ encodeTest(st.string(st.u8()), "foo");
9
7
  });
10
8
  it("works on empty strings", () => {
11
- expectEncode(string_u32, "");
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);
12
14
  });
13
15
  it("errors on too long strings", () => {
14
- expectError(() => {
15
- st.write(string_u8, "A".repeat(256));
16
- });
16
+ encodeFailTest(st.string(st.u8()), "A".repeat(256));
17
17
  });
18
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";
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
@@ -1,3 +1,5 @@
1
- export * from "./datatypes";
2
1
  export { read, createReaderContext } from "./read";
3
2
  export { write, createdWriterContext } from "./write";
3
+ export * from "./datatypes/index";
4
+ export * from "./transforms/index";
5
+ export * from "./utilities/index";
package/dist/read.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Serializer } from "./types";
2
- export declare function read<T>(serializer: Serializer<T>, buffer: ArrayBuffer): T;
2
+ export declare function read<TIn, TOut>(serializer: Serializer<TIn, TOut>, buffer: ArrayBuffer): TOut;
3
3
  export declare function createReaderContext(buffer: ArrayBuffer): {
4
4
  offset: number;
5
5
  buffer: ArrayBuffer;
@@ -0,0 +1,2 @@
1
+ import type { Transform } from "./pipe";
2
+ export declare function encode<TIn, TOut>(encode: (value: TOut) => TIn, decode: (value: TIn) => TOut): Transform<TOut, TIn>;
@@ -0,0 +1,7 @@
1
+ export function encode(encode, decode) {
2
+ return (type) => ({
3
+ size: type.size,
4
+ read: (ctx) => decode(type.read(ctx)),
5
+ write: (ctx, value) => type.write(ctx, encode(value)),
6
+ });
7
+ }
@@ -0,0 +1,2 @@
1
+ export declare function enum_<const T>(values: T[]): import("./pipe").Transform<T, any>;
2
+ export { enum_ as enum };
@@ -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,2 @@
1
+ import type { Serializer } from "../types";
2
+ export declare function fixedOffset<T>(delta: number): (type: Serializer<T>) => Serializer<T>;
@@ -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,2 @@
1
+ import type { Transform } from "./pipe";
2
+ export declare function modify<T>(callback: (value: T) => T): Transform<T>;
@@ -0,0 +1,7 @@
1
+ export function modify(callback) {
2
+ return (type) => ({
3
+ size: type.size,
4
+ read: (ctx) => callback(type.read(ctx)),
5
+ write: (ctx, value) => type.write(ctx, callback(value)),
6
+ });
7
+ }
@@ -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,4 @@
1
+ import { encode } from "./encode";
2
+ export function toBase64() {
3
+ return encode((v) => Uint8Array.fromBase64(v).buffer, (v) => new Uint8Array(v).toBase64());
4
+ }
@@ -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
+ });