mirror of
https://github.com/Kir-Antipov/mc-publish.git
synced 2024-11-29 03:40:56 -05:00
Implemented enum descriptor instantiation logic
This commit is contained in:
parent
41d4de590e
commit
1afbf2483e
2 changed files with 84 additions and 0 deletions
|
@ -1,4 +1,8 @@
|
||||||
import { NamedType, TypeOf, TypeOfResult } from "@/utils/types";
|
import { NamedType, TypeOf, TypeOfResult } from "@/utils/types";
|
||||||
|
import { BigIntDescriptor } from "./bigint-descriptor";
|
||||||
|
import { BooleanDescriptor } from "./boolean-descriptor";
|
||||||
|
import { NumberDescriptor } from "./number-descriptor";
|
||||||
|
import { StringDescriptor } from "./string-descriptor";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that defines operations that should be implemented by an underlying type of an `Enum`.
|
* Interface that defines operations that should be implemented by an underlying type of an `Enum`.
|
||||||
|
@ -46,3 +50,50 @@ export interface EnumDescriptor<T> {
|
||||||
*/
|
*/
|
||||||
removeFlag(value: T, flag: T): T;
|
removeFlag(value: T, flag: T): T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of known `EnumDescriptor`s, keyed by the string representation of their underlying type.
|
||||||
|
*/
|
||||||
|
const KNOWN_ENUM_DESCRIPTORS = new Map<TypeOfResult, EnumDescriptor<unknown>>([
|
||||||
|
["bigint", new BigIntDescriptor()],
|
||||||
|
["boolean", new BooleanDescriptor()],
|
||||||
|
["number", new NumberDescriptor()],
|
||||||
|
["string", new StringDescriptor()],
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link EnumDescriptor} for the provided type name.
|
||||||
|
*
|
||||||
|
* @template T - The type of the result to return
|
||||||
|
* @param type - The name of the type to get the descriptor for
|
||||||
|
*
|
||||||
|
* @returns The descriptor for the specified type, or `undefined` if there is no such descriptor.
|
||||||
|
*/
|
||||||
|
export function getEnumDescriptorByUnderlyingType<T extends TypeOfResult>(type: T): EnumDescriptor<NamedType<T>> | undefined {
|
||||||
|
return KNOWN_ENUM_DESCRIPTORS.get(type) as EnumDescriptor<NamedType<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infers the descriptor for an enum based on its values.
|
||||||
|
*
|
||||||
|
* @template T - Type of the enum.
|
||||||
|
*
|
||||||
|
* @param values - The values of the enum.
|
||||||
|
*
|
||||||
|
* @returns The inferred descriptor for the enum.
|
||||||
|
*
|
||||||
|
* @throws An error if the enum contains objects of different types or an invalid underlying type.
|
||||||
|
*/
|
||||||
|
export function inferEnumDescriptorOrThrow<T>(values: readonly T[]): EnumDescriptor<T> | never {
|
||||||
|
if (!values.every((x, i, self) => i === 0 || typeof x === typeof self[i - 1])) {
|
||||||
|
throw new Error("The enum must contain objects of the same type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const underlyingType = values.length ? typeof values[0] : "number";
|
||||||
|
const descriptor = getEnumDescriptorByUnderlyingType(underlyingType) as EnumDescriptor<T>;
|
||||||
|
if (!descriptor) {
|
||||||
|
throw new Error(`'${underlyingType}' is not an acceptable enum type.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
33
tests/unit/utils/enum/descriptors/enum-descriptor.spec.ts
Normal file
33
tests/unit/utils/enum/descriptors/enum-descriptor.spec.ts
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { getEnumDescriptorByUnderlyingType, inferEnumDescriptorOrThrow } from "@/utils/enum/descriptors/enum-descriptor";
|
||||||
|
|
||||||
|
describe("getEnumDescriptorByUnderlyingType", () => {
|
||||||
|
test("returns the correct descriptor for a known type", () => {
|
||||||
|
const knownTypes = ["number", "bigint", "boolean", "string"] as const;
|
||||||
|
for (const knowType of knownTypes) {
|
||||||
|
expect(getEnumDescriptorByUnderlyingType(knowType)?.name).toBe(knowType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns undefined for an unknown type", () => {
|
||||||
|
expect(getEnumDescriptorByUnderlyingType("unknownType" as "string")).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("inferEnumDescriptorOrThrow", () => {
|
||||||
|
test("infers correct descriptor based on enum values", () => {
|
||||||
|
expect(inferEnumDescriptorOrThrow([1, 2, 3]).name).toBe("number");
|
||||||
|
expect(inferEnumDescriptorOrThrow(["a", "b", "c"]).name).toBe("string");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("throws error if enum contains objects of different types", () => {
|
||||||
|
expect(() => inferEnumDescriptorOrThrow([1, "b", 3])).toThrow("The enum must contain objects of the same type.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("throws error if enum has an invalid underlying type", () => {
|
||||||
|
expect(() => inferEnumDescriptorOrThrow([{}])).toThrow("'object' is not an acceptable enum type.");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns a number descriptor for an empty array", () => {
|
||||||
|
expect(inferEnumDescriptorOrThrow([]).name).toBe("number");
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue