Skip to content

Commit

Permalink
feat: ComposedKeyLabelSet and functions
Browse files Browse the repository at this point in the history
- also ComposedKeyLabelSetSerialized to have default generic
- also ensuring we use the publicly exported within our tests
  • Loading branch information
eturino committed Jan 8, 2025
1 parent 32b3bf9 commit 0a91908
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 16 deletions.
86 changes: 86 additions & 0 deletions src/lib/__tests__/serialize.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";

import {
type ComposedKeyLabelSetSerialized,
type ComposedKeySetSerialized,
type IKeyLabel,
InvalidKeySetError,
Expand All @@ -10,6 +11,7 @@ import {
type KeyLabelSetAllSerialized,
type KeyLabelSetNone,
type KeyLabelSetNoneSerialized,
type KeyLabelSetSerialized,
type KeyLabelSetSome,
type KeyLabelSetSomeSerialized,
type KeySet,
Expand All @@ -26,6 +28,7 @@ import {
all,
allExceptSome,
composedKeySetFrom,
isComposedKeyLabelSetSerialized,
isComposedKeySetSerialized,
isKeyLabelSetSerialized,
isKeySetAllExceptSomeSerialized,
Expand All @@ -34,9 +37,11 @@ import {
isKeySetSerialized,
isKeySetSomeSerialized,
none,
parseComposedKeyLabelSet,
parseComposedKeySet,
parseKeyLabelSet,
parseKeySet,
serializeComposedKeyLabelSet,
serializeComposedKeySet,
serializeKeyLabelSet,
serializeKeySet,
Expand Down Expand Up @@ -652,4 +657,85 @@ describe("serialize KeySet", () => {
});
});
});

describe("composedKeyLabelSet", () => {
const keySet1 = allExceptSome([
{ key: "a", label: "A" },
{ key: "b", label: "B" },
]);
const keySetSerialized1 = {
type: KeySetTypes.allExceptSome,
elements: [
{ key: "a", label: "A" },
{ key: "b", label: "B" },
],
};
const keySet2 = some([
{ key: "a", label: "A" },
{ key: "b", label: "B" },
{ key: "c", label: "C" },
]);
const keySetSerialized2 = {
type: KeySetTypes.some,
elements: [
{ key: "a", label: "A" },
{ key: "b", label: "B" },
{ key: "c", label: "C" },
],
};

const composedSerialized: KeyLabelSetSerialized[] = [keySetSerialized1, keySetSerialized2];
const composedKeyLabelSet = composedKeySetFrom([keySet1, keySet2]);

describe("isComposedKeyLabelSetSerialized()", () => {
it("isComposedKeyLabelSetSerialized(composedSerialized) -> OK", () => {
expect(isComposedKeyLabelSetSerialized(composedSerialized)).toBeTruthy();
});
it("isComposedKeyLabelSetSerialized([]) -> OK", () => {
expect(isComposedKeyLabelSetSerialized([])).toBeTruthy();
});
it("isComposedKeyLabelSetSerialized(keySet) -> NOPE", () => {
expect(isComposedKeyLabelSetSerialized(keySet1)).toBeFalsy();
});
it("isComposedKeyLabelSetSerialized(keySetSerialized) -> NOPE", () => {
expect(isComposedKeyLabelSetSerialized(keySetSerialized1)).toBeFalsy();
});
it("isComposedKeyLabelSetSerialized(composedKeyLabelSet) -> NOPE", () => {
expect(isComposedKeyLabelSetSerialized(composedKeyLabelSet)).toBeFalsy();
});
it("isComposedKeyLabelSetSerialized(composedKeyLabelSet) -> NOPE", () => {
expect(isComposedKeyLabelSetSerialized(keySet1)).toBeFalsy();
});
});

describe("serializeComposedKeyLabelSet()", () => {
it("serializeComposedKeyLabelSet(composedSerialized) -> return same", () => {
expect(serializeComposedKeyLabelSet(composedSerialized)).toBe(composedSerialized);
});
it("serializeComposedKeyLabelSet(composedKeyLabelSet) -> serialize each", () => {
expect(serializeComposedKeyLabelSet(composedKeyLabelSet)).toEqual(composedSerialized);
});
it("composedKeyLabelSet.serialized() -> serialize each", () => {
expect(composedKeyLabelSet.serialized()).toEqual(composedSerialized);
});
});

describe("parseComposedKeyLabelSet()", () => {
it("parseComposedKeyLabelSet() with key sets", () => {
expect(parseComposedKeyLabelSet(composedSerialized)).toEqual(composedKeyLabelSet);
});
it("parseComposedKeyLabelSet() with empty list", () => {
expect(parseComposedKeyLabelSet([])).toEqual(composedKeySetFrom([]));
});
it("parseComposedKeyLabelSet() with an already composedKeyLabelSet", () => {
expect(parseComposedKeyLabelSet(composedKeyLabelSet)).toBe(composedKeyLabelSet);
});

it("parseComposedKeyLabelSet() with empty list", () => {
expect(() =>
parseComposedKeyLabelSet([{ invalid: "stuff" }] as unknown as ComposedKeyLabelSetSerialized),
).toThrow();
});
});
});
});
2 changes: 1 addition & 1 deletion src/lib/__tests__/to-string.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";

import { allExceptSomeKeySetForced, allKeySet, composedKeySetFrom, noneKeySet, someKeySetForced } from "../key-set";
import { allExceptSomeKeySetForced, allKeySet, composedKeySetFrom, noneKeySet, someKeySetForced } from "../..";

describe("toString KeySet", () => {
it("KeySetAll", () => {
Expand Down
15 changes: 14 additions & 1 deletion src/lib/key-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,30 @@ import {
isKeySetSerializedOfStringKeyLabels,
isKeySetSerializedOfStrings,
} from "./key-set/check-serialized-element-type";
import { ComposedKeyLabelSet, ComposedKeySet, composedKeySetFrom, isComposedKeySet } from "./key-set/composed";
import {
ComposedKeyLabelSet,
ComposedKeySet,
composedKeySetFrom,
isComposedKeyLabelSet,
isComposedKeySet,
} from "./key-set/composed";
import { InvalidEmptySetError } from "./key-set/invalid-empty-set-error";
import { InvalidKeySetError } from "./key-set/invalid-key-set-error";
import { KeySetNone, none, noneKeySet } from "./key-set/none";
import {
isComposedKeyLabelSetSerialized,
isComposedKeySetSerialized,
isKeyLabelSetSerialized,
isKeySetAllExceptSomeSerialized,
isKeySetAllSerialized,
isKeySetNoneSerialized,
isKeySetSerialized,
isKeySetSomeSerialized,
parseComposedKeyLabelSet,
parseComposedKeySet,
parseKeyLabelSet,
parseKeySet,
serializeComposedKeyLabelSet,
serializeComposedKeySet,
serializeKeyLabelSet,
serializeKeySet,
Expand Down Expand Up @@ -127,6 +136,8 @@ export {
serializeComposedKeySet,
parseKeyLabelSet,
serializeKeyLabelSet,
parseComposedKeyLabelSet,
serializeComposedKeyLabelSet,
// set utils
setByKeys,
sortKeys,
Expand All @@ -137,6 +148,7 @@ export {
isEmptyArray,
isNonEmptyArray,
isComposedKeySet,
isComposedKeyLabelSet,
isKeySet,
isKeySetAll,
isKeySetNone,
Expand All @@ -149,6 +161,7 @@ export {
isKeySetAllExceptSomeSerialized,
isKeySetType,
isComposedKeySetSerialized,
isComposedKeyLabelSetSerialized,
isKeyLabelSetSerialized,
// utils
isValidKey,
Expand Down
4 changes: 3 additions & 1 deletion src/lib/key-set/-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ export type KeyLabelSetSerialized<T extends string | number = string | number> =
| KeyLabelSetAllExceptSomeSerialized<T>;

export type ComposedKeySetSerialized<T extends Key = Key> = Array<KeySetSerialized<T>>;
export type ComposedKeyLabelSetSerialized = Array<KeyLabelSetSerialized>;
export type ComposedKeyLabelSetSerialized<T extends string | number = string | number> = Array<
KeyLabelSetSerialized<T>
>;

export interface IKeySetClass<T extends Key> {
/**
Expand Down
42 changes: 35 additions & 7 deletions src/lib/key-set/__tests__/composed.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { sortBy } from "es-toolkit/compat";
import { describe, expect, it } from "vitest";
import type { KeySet } from "../-base";
import { KeySetAll, all } from "../all";
import { KeySetAllExceptSome, allExceptSome } from "../all-except-some";
import { ComposedKeySet, composedKeySetFrom, isComposedKeySet } from "../composed";
import { KeySetNone, none } from "../none";
import { serializeKeySet } from "../serialize";
import { KeySetSome, some } from "../some";
import type { KeySet } from "../../..";
import {
ComposedKeySet,
KeySetAll,
KeySetAllExceptSome,
KeySetNone,
KeySetSome,
all,
allExceptSome,
composedKeySetFrom,
isComposedKeyLabelSet,
isComposedKeySet,
none,
serializeKeyLabelSet,
serializeKeySet,
some,
} from "../../..";

describe("ComposedKeySet", () => {
describe("isComposedKeySet", () => {
Expand All @@ -27,6 +37,24 @@ describe("ComposedKeySet", () => {
});
});

describe("isComposedKeyLabelSet", () => {
it("returns true if the object is a ComposedKeyLabelSet", () => {
const ks = new ComposedKeySet([]);
expect(isComposedKeyLabelSet(ks)).toBeTruthy();
});
it("returns false with a KeyLabelSet", () => {
const ks = all<string>();
expect(isComposedKeyLabelSet(ks)).toBeFalsy();
});
it("returns false with a serialized KeyLabelSet", () => {
const ks = serializeKeyLabelSet(all());
expect(isComposedKeyLabelSet(ks)).toBeFalsy();
});
it("returns false with null", () => {
expect(isComposedKeyLabelSet(null)).toBeFalsy();
});
});

describe("construction", () => {
it("with an empty list => returns Composed([All])", () => {
const actual = composedKeySetFrom([]);
Expand Down
13 changes: 11 additions & 2 deletions src/lib/key-set/composed.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { uniqWith } from "es-toolkit";
import { sortBy } from "es-toolkit/compat";
import type { IKeyLabel } from "../util/object-utils";
import type { ComposedKeySetSerialized, Key, KeySet } from "./-base";
import { type ComposedKeySetSerialized, type Key, type KeySet, isKeyLabelSet } from "./-base";
import { INSPECT } from "./-is-node-env";
import { KeySetAll, all } from "./all";
import { KeySetAllExceptSome } from "./all-except-some";
Expand Down Expand Up @@ -235,7 +235,16 @@ export function isComposedKeySet(x: unknown): x is ComposedKeySet {
return x instanceof ComposedKeySet;
}

export type ComposedKeyLabelSet<T extends string | number> = ComposedKeySet<IKeyLabel<T>>;
export type ComposedKeyLabelSet<T extends string | number = string | number> = ComposedKeySet<IKeyLabel<T>>;

export function isComposedKeyLabelSet<T extends string | number>(
x: ComposedKeyLabelSet<T>,
): x is ComposedKeyLabelSet<T>;
export function isComposedKeyLabelSet(x: unknown): x is ComposedKeyLabelSet;
export function isComposedKeyLabelSet(x: unknown): x is ComposedKeyLabelSet {
if (!isComposedKeySet(x)) return false;
return x.list.every((y) => isKeyLabelSet(y));
}

/**
* creates a new ComposedKeySet with the given list
Expand Down
36 changes: 33 additions & 3 deletions src/lib/key-set/serialize.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type IKeyLabel, isKeyLabel, isObject } from "../util/object-utils";
import {
type ComposedKeyLabelSetSerialized,
type ComposedKeySetSerialized,
type Key,
type KeyLabelSet,
Expand All @@ -25,7 +26,13 @@ import {
} from "./-base";
import { type KeySetAll, all } from "./all";
import { type KeySetAllExceptSome, allExceptSome } from "./all-except-some";
import { type ComposedKeySet, composedKeySetFrom, isComposedKeySet } from "./composed";
import {
type ComposedKeyLabelSet,
type ComposedKeySet,
composedKeySetFrom,
isComposedKeyLabelSet,
isComposedKeySet,
} from "./composed";
import { InvalidKeySetError } from "./invalid-key-set-error";
import { type KeySetNone, none } from "./none";
import { type KeySetSome, some } from "./some";
Expand Down Expand Up @@ -114,14 +121,25 @@ export function isComposedKeySetSerialized(x: unknown): x is ComposedKeySetSeria
return x.every((y) => isKeySetSerialized(y));
}

export function isComposedKeyLabelSetSerialized<T extends string | number>(
x: ComposedKeyLabelSetSerialized<T>,
): x is ComposedKeyLabelSetSerialized<T>;
export function isComposedKeyLabelSetSerialized(x: unknown): x is ComposedKeyLabelSetSerialized;
export function isComposedKeyLabelSetSerialized(x: unknown): x is ComposedKeyLabelSetSerialized {
if (!x || !Array.isArray(x)) return false;

return x.every((y) => isKeyLabelSetSerialized(y));
}

export function serializeComposedKeySet<T extends Key>(
x: ComposedKeySet<T> | ComposedKeySetSerialized<T>,
): ComposedKeySetSerialized<T> {
if (isComposedKeySetSerialized(x)) return x;

return x.list.map((y) => serializeKeySet(y));
return x.serialized();
}

export const serializeComposedKeyLabelSet = serializeComposedKeySet;

export function serializeKeySet<T extends string | number>(
x: KeyLabelSetAllSerialized<T> | KeyLabelSetAll<T>,
): KeyLabelSetAllSerialized<T>;
Expand Down Expand Up @@ -165,6 +183,18 @@ export function parseComposedKeySet<T extends Key>(
return composedKeySetFrom(x.map((y) => parseKeySet(y)));
}

export function parseComposedKeyLabelSet<T extends string | number>(
x: ComposedKeyLabelSetSerialized<T> | ComposedKeyLabelSet<T>,
): ComposedKeyLabelSet<T> {
if (isComposedKeyLabelSet(x)) return x;

if (!isComposedKeySetSerialized(x)) {
throw new InvalidKeySetError(`composedKeySetSerialized expected, given ${JSON.stringify(x)}`);
}

return composedKeySetFrom(x.map((y) => parseKeyLabelSet(y)));
}

export function parseKeySet<T extends Key>(x: KeySetAllSerialized<T> | KeySetAll<T>): KeySetAll<T>;
export function parseKeySet<T extends Key>(x: KeySetNoneSerialized<T> | KeySetNone<T>): KeySetNone<T>;
export function parseKeySet<T extends Key>(x: KeySetSomeSerialized<T> | KeySetSome<T>): KeySetSome<T>;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/util/__tests__/sort-keys.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { sortKeys } from "../sort-keys";
import { sortKeys } from "../../..";

describe("sortKeys", () => {
describe("with strings", () => {
Expand Down

0 comments on commit 0a91908

Please sign in to comment.