@anterior/brrr 0.1.1

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.
@@ -0,0 +1,69 @@
1
+ import { suite, test } from "node:test";
2
+ import { deepStrictEqual, ok } from "node:assert/strict";
3
+ import { throws } from "node:assert";
4
+ import { MalformedTaggedTupleError, TagMismatchError } from "./errors.ts";
5
+ import { TaggedTuple } from "./tagged-tuple.ts";
6
+
7
+ await suite(import.meta.filename, async () => {
8
+ class Foo {
9
+ public static readonly tag = 0;
10
+
11
+ public readonly bar: number;
12
+ public readonly baz: string;
13
+
14
+ public constructor(foo: number, bar: string) {
15
+ this.bar = foo;
16
+ this.baz = bar;
17
+ }
18
+ }
19
+
20
+ await suite("fromTuple", async () => {
21
+ await test("create instance", async () => {
22
+ const foo = TaggedTuple.fromTuple(Foo, [0, 42, "hello"]);
23
+ ok(foo instanceof Foo);
24
+ ok(foo.bar === 42);
25
+ ok(foo.baz === "hello");
26
+ });
27
+ await test("tag mismatch", async () => {
28
+ throws(
29
+ () => TaggedTuple.fromTuple(Foo, [1, 42, "hello"]),
30
+ TagMismatchError,
31
+ );
32
+ });
33
+ await test("too many args", async () => {
34
+ throws(
35
+ // @ts-expect-error testing runtime error
36
+ () => TaggedTuple.fromTuple(Foo, [0, 42, "hello", "a"]),
37
+ MalformedTaggedTupleError,
38
+ );
39
+ });
40
+ await test("too few args", async () => {
41
+ throws(
42
+ // @ts-expect-error testing runtime error
43
+ () => TaggedTuple.fromTuple(Foo, [0, 42]),
44
+ MalformedTaggedTupleError,
45
+ );
46
+ });
47
+ });
48
+
49
+ await suite("asTuple", async () => {
50
+ await test("basic", async () => {
51
+ const foo: Foo = TaggedTuple.fromTuple(Foo, [0, 42, "hello"]);
52
+ deepStrictEqual(TaggedTuple.asTuple(foo), [0, 42, "hello"]);
53
+ });
54
+ });
55
+
56
+ await suite("encode and decode", async () => {
57
+ const foo: Foo = TaggedTuple.fromTuple(Foo, [0, 42, "hello"]);
58
+ const encoded: Uint8Array = TaggedTuple.encode(foo);
59
+ const decoded = TaggedTuple.decode(Foo, encoded);
60
+ deepStrictEqual(decoded, foo);
61
+ });
62
+
63
+ await suite("encode and decode (string)", async () => {
64
+ const foo: Foo = TaggedTuple.fromTuple(Foo, [0, 42, "hello"]);
65
+ const encoded: string = TaggedTuple.encodeToString(foo);
66
+ const decoded = TaggedTuple.decodeFromString(Foo, encoded);
67
+ deepStrictEqual(decoded, foo);
68
+ });
69
+ });
@@ -0,0 +1,96 @@
1
+ import { bencoder, decoder, encoder, encoding } from "./internal-codecs.ts";
2
+ import { MalformedTaggedTupleError, TagMismatchError } from "./errors.ts";
3
+
4
+ export interface Tagged<T = any, A extends unknown[] = any[]> {
5
+ new (...args: A): T;
6
+
7
+ readonly tag: number;
8
+ }
9
+
10
+ function fromTuple<T, A extends unknown[]>(
11
+ tagged: Tagged<T, A>,
12
+ data: [number, ...A],
13
+ ): InstanceType<typeof tagged> {
14
+ if (data[0] !== tagged.tag) {
15
+ throw new TagMismatchError(tagged);
16
+ }
17
+ if (data.length - 1 !== tagged.length) {
18
+ throw new MalformedTaggedTupleError(tagged);
19
+ }
20
+ return new tagged(...(data.slice(1) as A));
21
+ }
22
+
23
+ function asTuple<T extends object, A extends unknown[]>(
24
+ obj: InstanceType<Tagged<T, A>>,
25
+ ): [number, ...A] {
26
+ return [(obj.constructor as Tagged<T, A>).tag, ...Object.values(obj)] as [
27
+ number,
28
+ ...A,
29
+ ];
30
+ }
31
+
32
+ function encode(obj: InstanceType<Tagged>): Uint8Array {
33
+ return bencoder.encode(asTuple(obj));
34
+ }
35
+
36
+ function encodeToString(obj: InstanceType<Tagged>): string {
37
+ return decoder.decode(encode(obj));
38
+ }
39
+
40
+ function decode<T, A extends unknown[]>(
41
+ tagged: Tagged<T, A>,
42
+ data: Uint8Array,
43
+ ): InstanceType<typeof tagged> {
44
+ const decoded = bencoder.decode(data, encoding) as [number, ...A];
45
+ return fromTuple(tagged, decoded);
46
+ }
47
+
48
+ function decodeFromString<T, A extends unknown[]>(
49
+ tagged: Tagged<T, A>,
50
+ data: string,
51
+ ): InstanceType<typeof tagged> {
52
+ return decode(tagged, encoder.encode(data));
53
+ }
54
+
55
+ export const TaggedTuple = {
56
+ fromTuple,
57
+ asTuple,
58
+ encode,
59
+ encodeToString,
60
+ decode,
61
+ decodeFromString,
62
+ } as const;
63
+
64
+ export class PendingReturn {
65
+ public static readonly tag = 1;
66
+
67
+ public readonly rootId: string;
68
+ public readonly callHash: string;
69
+ public readonly topic: string;
70
+
71
+ constructor(rootId: string, callHash: string, topic: string) {
72
+ this.rootId = rootId;
73
+ this.callHash = callHash;
74
+ this.topic = topic;
75
+ }
76
+
77
+ public isRepeatedCall(other: PendingReturn): boolean {
78
+ return (
79
+ this.rootId !== other.rootId &&
80
+ this.callHash === other.callHash &&
81
+ this.topic === other.topic
82
+ );
83
+ }
84
+ }
85
+
86
+ export class ScheduleMessage {
87
+ public static readonly tag = 2;
88
+
89
+ public readonly rootId: string;
90
+ public readonly callHash: string;
91
+
92
+ constructor(rootId: string, callHash: string) {
93
+ this.rootId = rootId;
94
+ this.callHash = callHash;
95
+ }
96
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "compilerOptions": {
3
+ /* Base Options */
4
+ "esModuleInterop": true,
5
+ "skipLibCheck": true,
6
+ "target": "esnext",
7
+ "moduleDetection": "force",
8
+ "isolatedModules": true,
9
+ "verbatimModuleSyntax": true,
10
+ "erasableSyntaxOnly": true,
11
+ "preserveSymlinks": true,
12
+
13
+ /* Strictness */
14
+ "strict": true,
15
+ "noUncheckedIndexedAccess": true,
16
+ "noUncheckedSideEffectImports": true,
17
+ "noImplicitOverride": true,
18
+ "exactOptionalPropertyTypes": true,
19
+ "useUnknownInCatchVariables": true,
20
+
21
+ /* Module Resolution */
22
+ "module": "nodenext",
23
+ "moduleResolution": "nodenext",
24
+ "allowImportingTsExtensions": true,
25
+ "rewriteRelativeImportExtensions": true,
26
+ "lib": ["esnext"],
27
+
28
+ /* Build */
29
+ "declaration": true,
30
+ "declarationMap": true,
31
+ "sourceMap": true,
32
+ "rootDir": "src",
33
+ "outDir": "dist",
34
+ "incremental": true
35
+ },
36
+ "include": ["src/**/*.ts"]
37
+ }