Skip to content

Commit

Permalink
feat: record codec (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay committed Mar 29, 2023
1 parent 12b671d commit 6d846f7
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 19 deletions.
1 change: 1 addition & 0 deletions codecs/mod.ts
Expand Up @@ -16,6 +16,7 @@ export * from "./object.ts"
export * from "./option.ts"
export * from "./optionBool.ts"
export * from "./promise.ts"
export * from "./record.ts"
export * from "./result.ts"
export * from "./str.ts"
export * from "./transform.ts"
Expand Down
13 changes: 13 additions & 0 deletions codecs/record.ts
@@ -0,0 +1,13 @@
import { Codec } from "../common/mod.ts"
import { array } from "./array.ts"
import { str } from "./str.ts"
import { transform } from "./transform.ts"
import { tuple } from "./tuple.ts"

export function record<V>($value: Codec<V>) {
return transform<[string, V][], Record<string, V>>({
$base: array(tuple(str, $value)),
encode: Object.entries,
decode: Object.fromEntries,
})
}
4 changes: 2 additions & 2 deletions codecs/test/__snapshots__/bitSequence.test.ts.snap
@@ -1,8 +1,8 @@
export const snapshot = {};

snapshot[`\$.bitSequence BitSequence { data: Uint8Array(0) [], length: 0 } 1`] = `00`;
snapshot[`\$.bitSequence BitSequence { length: 0, data: Uint8Array(0) [] } 1`] = `00`;

snapshot[`\$.bitSequence BitSequence { data: Uint8Array(2) [ 106, 40 ], length: 13 } 1`] = `
snapshot[`\$.bitSequence BitSequence { length: 13, data: Uint8Array(2) [ 106, 40 ] } 1`] = `
34
6a
28
Expand Down
2 changes: 1 addition & 1 deletion codecs/test/__snapshots__/object.test.ts.snap
Expand Up @@ -58,7 +58,7 @@ snapshot[`\$person invalid undefined 1`] = `ScaleAssertError: typeof value !== "

snapshot[`\$person invalid 123 1`] = `ScaleAssertError: typeof value !== "object"`;

snapshot[`\$person invalid [Function] 1`] = `ScaleAssertError: typeof value !== "object"`;
snapshot[`\$person invalid [Function (anonymous)] 1`] = `ScaleAssertError: typeof value !== "object"`;

snapshot[`\$person invalid {} 1`] = `ScaleAssertError: !("name" in value)`;

Expand Down
167 changes: 167 additions & 0 deletions codecs/test/__snapshots__/record.test.ts.snap
@@ -0,0 +1,167 @@
export const snapshot = {};

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.str)),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) { a: "hi", b: "sup", c: "yo" } 1`] = `
0c
04
61
08
68
69
04
62
0c
73
75
70
04
63
08
79
6f
`;

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.str)),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) { the: "quick", brown: "fox", jumped: "over", theLazy: "hen" } 1`] = `
10
0c
74
68
65
14
71
75
69
63
6b
14
62
72
6f
77
6e
0c
66
6f
78
18
6a
75
6d
70
65
64
10
6f
76
65
72
1c
74
68
65
4c
61
7a
79
0c
68
65
6e
`;

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.transform(Array))),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) { one: { two: 3 }, four: { five: 6 }, seven: { eight: 9 } } 1`] = `
0c
0c
6f
6e
65
04
0c
74
77
6f
03
10
66
6f
75
72
04
10
66
69
76
65
06
14
73
65
76
65
6e
04
14
65
69
67
68
74
09
`;

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.str)),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) invalid [ true, false ] 1`] = `ScaleAssertError: typeof value#encode[0][1] !== "string"`;

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.str)),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) invalid [ 1, 2, 3, -1, 4 ] 1`] = `ScaleAssertError: typeof value#encode[0][1] !== "string"`;

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.u8)),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) invalid { this: "should" } 1`] = `ScaleAssertError: typeof value#encode[0][1] !== "number"`;

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.u8)),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) invalid { be: "invalid" } 1`] = `ScaleAssertError: typeof value#encode[0][1] !== "number"`;

snapshot[`\$.transform(
{
"\$base": \$.array(\$.tuple(\$.str, \$.u8)),
encode: [Function: entries],
decode: [Function: fromEntries]
}
) invalid { and: "this" } 1`] = `ScaleAssertError: typeof value#encode[0][1] !== "number"`;
12 changes: 6 additions & 6 deletions codecs/test/__snapshots__/result.test.ts.snap
@@ -1,24 +1,24 @@
export const snapshot = {};

snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function])) "ok" 1`] = `
snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function (anonymous)])) "ok" 1`] = `
00
08
6f
6b
`;

snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function])) StrErr: err 1`] = `
snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function (anonymous)])) StrErr: err 1`] = `
01
0c
65
72
72
`;

snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function])) invalid null 1`] = `ScaleAssertError: typeof value !== "string"`;
snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function (anonymous)])) invalid null 1`] = `ScaleAssertError: typeof value !== "string"`;

snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function])) invalid undefined 1`] = `ScaleAssertError: typeof value !== "string"`;
snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function (anonymous)])) invalid undefined 1`] = `ScaleAssertError: typeof value !== "string"`;

snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function])) invalid Error: foo 1`] = `ScaleAssertError: !(value instanceof StrErr)`;
snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function (anonymous)])) invalid Error: foo 1`] = `ScaleAssertError: !(value instanceof StrErr)`;

snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function])) invalid StrErr: null 1`] = `ScaleAssertError: typeof value#arguments[0] !== "string"`;
snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Function (anonymous)])) invalid StrErr: null 1`] = `ScaleAssertError: typeof value#arguments[0] !== "string"`;
16 changes: 16 additions & 0 deletions codecs/test/record.test.ts
@@ -0,0 +1,16 @@
import * as $ from "../../mod.ts"
import { testCodec, testInvalid } from "../../test-util.ts"

testCodec($.record($.str), [
{ a: "hi", b: "sup", c: "yo" },
{ the: "quick", brown: "fox", jumped: "over", theLazy: "hen" },
])

testCodec($.record($.record($.u8)), [{
one: { two: 3 },
four: { five: 6 },
seven: { eight: 9 },
}])

testInvalid($.record($.str), [[true, false], [1, 2, 3, -1, 4]])
testInvalid($.record($.u8), [{ this: "should" }, { be: "invalid" }, { and: "this" }])
1 change: 1 addition & 0 deletions examples/assertions.eg.ts
@@ -1,3 +1,4 @@
// import * as $ from "https://deno.land/x/scale/mod.ts";
import * as $ from "../mod.ts"

// using `$.assert` (no explicit typing required)
Expand Down
11 changes: 1 addition & 10 deletions examples/collections.eg.ts
Expand Up @@ -5,13 +5,4 @@ $.set($.u32) // Codec<Set<number>>

$.map($.str, $.u32) // Codec<Map<string, number>>

export const $record = $.transform<
[string, number][],
Record<string, number>
>({
$base: $.array($.tuple($.str, $.u32)),
encode: Object.entries,
decode: Object.fromEntries,
})

$record // Codec<Record<string, number>>
$.record($.u8) // Codec<Partial<Record<string, number>>>

0 comments on commit 6d846f7

Please sign in to comment.