diff --git a/codecs/mod.ts b/codecs/mod.ts index f8c231b..bf641fb 100644 --- a/codecs/mod.ts +++ b/codecs/mod.ts @@ -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" diff --git a/codecs/record.ts b/codecs/record.ts new file mode 100644 index 0000000..cb85aec --- /dev/null +++ b/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($value: Codec) { + return transform<[string, V][], Record>({ + $base: array(tuple(str, $value)), + encode: Object.entries, + decode: Object.fromEntries, + }) +} diff --git a/codecs/test/__snapshots__/bitSequence.test.ts.snap b/codecs/test/__snapshots__/bitSequence.test.ts.snap index dda7cc6..3fe2aee 100644 --- a/codecs/test/__snapshots__/bitSequence.test.ts.snap +++ b/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 diff --git a/codecs/test/__snapshots__/object.test.ts.snap b/codecs/test/__snapshots__/object.test.ts.snap index cd65e37..254998c 100644 --- a/codecs/test/__snapshots__/object.test.ts.snap +++ b/codecs/test/__snapshots__/object.test.ts.snap @@ -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)`; diff --git a/codecs/test/__snapshots__/record.test.ts.snap b/codecs/test/__snapshots__/record.test.ts.snap new file mode 100644 index 0000000..4247a02 --- /dev/null +++ b/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"`; diff --git a/codecs/test/__snapshots__/result.test.ts.snap b/codecs/test/__snapshots__/result.test.ts.snap index e7f13a6..627aaa3 100644 --- a/codecs/test/__snapshots__/result.test.ts.snap +++ b/codecs/test/__snapshots__/result.test.ts.snap @@ -1,13 +1,13 @@ 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 @@ -15,10 +15,10 @@ snapshot[`\$.result(\$.str, \$.instance([Class: StrErr], \$.tuple(\$.str), [Func 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"`; diff --git a/codecs/test/record.test.ts b/codecs/test/record.test.ts new file mode 100644 index 0000000..586a7ea --- /dev/null +++ b/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" }]) diff --git a/examples/assertions.eg.ts b/examples/assertions.eg.ts index fd879ea..1c8beab 100644 --- a/examples/assertions.eg.ts +++ b/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) diff --git a/examples/collections.eg.ts b/examples/collections.eg.ts index 1de8291..38c377b 100644 --- a/examples/collections.eg.ts +++ b/examples/collections.eg.ts @@ -5,13 +5,4 @@ $.set($.u32) // Codec> $.map($.str, $.u32) // Codec> -export const $record = $.transform< - [string, number][], - Record ->({ - $base: $.array($.tuple($.str, $.u32)), - encode: Object.entries, - decode: Object.fromEntries, -}) - -$record // Codec> +$.record($.u8) // Codec>>