From 5a6465ac7bf6135f12ef5392a6782343b7f88697 Mon Sep 17 00:00:00 2001 From: T6 Date: Mon, 20 Feb 2023 10:10:17 -0500 Subject: [PATCH] feat: rename `$.stringUnion` to `$.literalUnion` (#137) --- codecs/test/__snapshots__/union.test.ts.snap | 28 ++++++++++---------- codecs/test/union.test.ts | 4 +-- codecs/union.ts | 18 ++++++------- common/util.ts | 16 ++++++++--- examples/unions.eg.ts | 2 +- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/codecs/test/__snapshots__/union.test.ts.snap b/codecs/test/__snapshots__/union.test.ts.snap index a1521dd..74182cb 100644 --- a/codecs/test/__snapshots__/union.test.ts.snap +++ b/codecs/test/__snapshots__/union.test.ts.snap @@ -44,33 +44,33 @@ e7 00 `; -snapshot[`\$.stringUnion(names) "Ross" 1`] = `00`; +snapshot[`\$.literalUnion(names) "Ross" 1`] = `00`; -snapshot[`\$.stringUnion(names) "Alisa" 1`] = `01`; +snapshot[`\$.literalUnion(names) "Alisa" 1`] = `01`; -snapshot[`\$.stringUnion(names) "Stefan" 1`] = `02`; +snapshot[`\$.literalUnion(names) "Stefan" 1`] = `02`; -snapshot[`\$.stringUnion(names) "Raoul" 1`] = `03`; +snapshot[`\$.literalUnion(names) "Raoul" 1`] = `03`; -snapshot[`\$.stringUnion(names) "James" 1`] = `04`; +snapshot[`\$.literalUnion(names) "James" 1`] = `04`; -snapshot[`\$.stringUnion(names) "David" 1`] = `05`; +snapshot[`\$.literalUnion(names) "David" 1`] = `05`; -snapshot[`\$.stringUnion(names) "Pierre" 1`] = `06`; +snapshot[`\$.literalUnion(names) "Pierre" 1`] = `06`; -snapshot[`\$.stringUnion(interestingU8s) "Min" 1`] = `00`; +snapshot[`\$.literalUnion(interestingU8s) "Min" 1`] = `00`; -snapshot[`\$.stringUnion(interestingU8s) "Unit" 1`] = `01`; +snapshot[`\$.literalUnion(interestingU8s) "Unit" 1`] = `01`; -snapshot[`\$.stringUnion(interestingU8s) "EvenPrime" 1`] = `02`; +snapshot[`\$.literalUnion(interestingU8s) "EvenPrime" 1`] = `02`; -snapshot[`\$.stringUnion(interestingU8s) "LargestPerfect" 1`] = `1c`; +snapshot[`\$.literalUnion(interestingU8s) "LargestPerfect" 1`] = `1c`; -snapshot[`\$.stringUnion(interestingU8s) "FirstUninteresting" 1`] = `81`; +snapshot[`\$.literalUnion(interestingU8s) "FirstUninteresting" 1`] = `81`; -snapshot[`\$.stringUnion(interestingU8s) "LargestSquare" 1`] = `e1`; +snapshot[`\$.literalUnion(interestingU8s) "LargestSquare" 1`] = `e1`; -snapshot[`\$.stringUnion(interestingU8s) "Max" 1`] = `ff`; +snapshot[`\$.literalUnion(interestingU8s) "Max" 1`] = `ff`; snapshot[`\$abc invalid null 1`] = `ScaleAssertError: value == null`; diff --git a/codecs/test/union.test.ts b/codecs/test/union.test.ts index 269ce06..2ea7140 100644 --- a/codecs/test/union.test.ts +++ b/codecs/test/union.test.ts @@ -22,7 +22,7 @@ const interestingU8s = { 255: "Max", } as const -const $interestingU8s = $.withMetadata(metadata("$.stringUnion(interestingU8s)"), $.stringUnion(interestingU8s)) +const $interestingU8s = $.withMetadata(metadata("$.literalUnion(interestingU8s)"), $.literalUnion(interestingU8s)) const names = [ "Ross", @@ -34,7 +34,7 @@ const names = [ "Pierre", ] as const -const $names = $.withMetadata(metadata("$.stringUnion(names)"), $.stringUnion(names)) +const $names = $.withMetadata(metadata("$.literalUnion(names)"), $.literalUnion(names)) testCodec($abc, [ { _tag: "A" }, diff --git a/codecs/union.ts b/codecs/union.ts index 82dc586..12bc080 100644 --- a/codecs/union.ts +++ b/codecs/union.ts @@ -26,8 +26,8 @@ export type NativeTaggedUnion< export function taggedUnion< K extends keyof any, - M extends Record>, ->(tagKey: K, members: Narrow): Codec> { + M extends [] | Record>, +>(tagKey: K, members: M): Codec> { const tagToDiscriminant: Record = Object.create(null) const discriminantToMember: Record> = Object.create(null) for (const _discriminant in members) { @@ -65,19 +65,19 @@ export function taggedUnion< }) } -export function stringUnion(members: Record): Codec { - const keyToDiscriminant: Record = Object.create(null) +export function literalUnion(members: Record): Codec { + const keyToDiscriminant: Map = new Map() for (const _discriminant in members) { const discriminant = +_discriminant if (isNaN(discriminant)) continue - const key = members[discriminant]! - keyToDiscriminant[key] = discriminant + const key = members[discriminant] as T + keyToDiscriminant.set(key, discriminant) } return createCodec({ - _metadata: metadata("$.stringUnion", stringUnion, members), + _metadata: metadata("$.literalUnion", literalUnion, members), _staticSize: 1, _encode(buffer, value) { - const discriminant = keyToDiscriminant[value]! + const discriminant = keyToDiscriminant.get(value)! buffer.array[buffer.index++] = discriminant }, _decode(buffer) { @@ -86,7 +86,7 @@ export function stringUnion(members: Record): Codec }, _assert(assert) { assert.typeof(this, "string") - if (!((assert.value as string) in keyToDiscriminant)) { + if (!keyToDiscriminant.has(assert.value as T)) { throw new ScaleAssertError(this, assert.value, `${assert.path} invalid value`) } }, diff --git a/common/util.ts b/common/util.ts index 73ef74a..cf10ab9 100644 --- a/common/util.ts +++ b/common/util.ts @@ -30,7 +30,15 @@ export class ScaleDecodeError extends ScaleError { export type Expand = T extends T ? { [K in keyof T]: T[K] } : never export type U2I = (U extends U ? (u: U) => 0 : never) extends (i: infer I) => 0 ? Extract : never -export type Narrow = - | (T extends infer U ? U : never) - | Extract - | ([T] extends [[]] ? [] : { [K in keyof T]: Narrow }) + +type _Narrow = [U] extends [T] ? U : Extract +export type Narrow = + | _Narrow + | _Narrow + | _Narrow + | _Narrow + | _Narrow + | _Narrow + | _Narrow + | (T extends object ? { [K in keyof T]: Narrow } : never) + | Extract<{} | null | undefined, T> diff --git a/examples/unions.eg.ts b/examples/unions.eg.ts index 920529f..e98382a 100644 --- a/examples/unions.eg.ts +++ b/examples/unions.eg.ts @@ -31,7 +31,7 @@ $pet // | { type: "cat"; purr: string; name: string } // > -export const $dinosaur = $.stringUnion([ +export const $dinosaur = $.literalUnion([ "Liopleurodon", "Kosmoceratops", "Psittacosaurus",