- refactor array equality check and add tests - remove OperatingSystem.Unknown causing extra logic, return undefined instead - refactor enum validation to share same logic - refactor scripting language factories to share same logic - refactor too many args in runCodeAsync - refactor ScriptCode constructor to reduce complexity - fix writing useless write to member object since another property write always override it
55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
// Because we cannot do "T extends enum" 😞 https://github.com/microsoft/TypeScript/issues/30611
|
|
export type EnumType = number | string;
|
|
export type EnumVariable<T extends EnumType, TEnumValue extends EnumType> = { [key in T]: TEnumValue };
|
|
|
|
export interface IEnumParser<TEnum> {
|
|
parseEnum(value: string, propertyName: string): TEnum;
|
|
}
|
|
export function createEnumParser<T extends EnumType, TEnumValue extends EnumType>(
|
|
enumVariable: EnumVariable<T, TEnumValue>): IEnumParser<TEnumValue> {
|
|
return {
|
|
parseEnum: (value, propertyName) => parseEnumValue(value, propertyName, enumVariable),
|
|
};
|
|
}
|
|
function parseEnumValue<T extends EnumType, TEnumValue extends EnumType>(
|
|
value: string,
|
|
enumName: string,
|
|
enumVariable: EnumVariable<T, TEnumValue>): TEnumValue {
|
|
if (!value) {
|
|
throw new Error(`undefined ${enumName}`);
|
|
}
|
|
if (typeof value !== 'string') {
|
|
throw new Error(`unexpected type of ${enumName}: "${typeof value}"`);
|
|
}
|
|
const casedValue = getEnumNames(enumVariable)
|
|
.find((enumValue) => enumValue.toLowerCase() === value.toLowerCase());
|
|
if (!casedValue) {
|
|
throw new Error(`unknown ${enumName}: "${value}"`);
|
|
}
|
|
return enumVariable[casedValue as keyof typeof enumVariable];
|
|
}
|
|
|
|
export function getEnumNames<T extends EnumType, TEnumValue extends EnumType>(
|
|
enumVariable: EnumVariable<T, TEnumValue>): string[] {
|
|
return Object
|
|
.values(enumVariable)
|
|
.filter((enumMember) => typeof enumMember === 'string') as string[];
|
|
}
|
|
|
|
export function getEnumValues<T extends EnumType, TEnumValue extends EnumType>(
|
|
enumVariable: EnumVariable<T, TEnumValue>): TEnumValue[] {
|
|
return getEnumNames(enumVariable)
|
|
.map((level) => enumVariable[level]) as TEnumValue[];
|
|
}
|
|
|
|
export function assertInRange<T extends EnumType, TEnumValue extends EnumType>(
|
|
value: TEnumValue,
|
|
enumVariable: EnumVariable<T, TEnumValue>) {
|
|
if (value === undefined) {
|
|
throw new Error('undefined enum value');
|
|
}
|
|
if (!(value in enumVariable)) {
|
|
throw new RangeError(`enum value "${value}" is out of range`);
|
|
}
|
|
}
|