ENUMS: Initial Enum Helper rework + Reorganization (#596)

This commit is contained in:
Snarling
2023-06-12 00:34:20 -04:00
committed by GitHub
parent 6ed8ea9796
commit 6732549196
224 changed files with 2126 additions and 2171 deletions
+74
View File
@@ -0,0 +1,74 @@
import type { Member } from "../types";
import type { NetscriptContext } from "../Netscript/APIWrapper";
import * as allEnums from "../Enums";
import { assertString, helpers } from "../Netscript/NetscriptHelpers";
import { getRandomInt } from "./helpers/getRandomInt";
class EnumHelper<EnumObj extends object, EnumMember extends Member<EnumObj> & string> {
name: string; // Name, for including in error text
defaultArgName: string; // Used as default for for validating ns arg name
valueArray: Array<EnumMember>;
valueSet: Set<EnumMember>; // For quick isMember typecheck
fuzzMap: Map<string, EnumMember>; // For fuzzy lookup
constructor(obj: EnumObj, name: string) {
this.name = name;
this.defaultArgName = name.charAt(0).toLowerCase() + name.slice(1);
this.valueArray = Object.values(obj);
this.valueSet = new Set(this.valueArray);
this.fuzzMap = new Map(this.valueArray.map((val) => [val.toLowerCase().replace(/[ -]+/g, ""), val]));
}
/** Provide a boolean indication for whether a */
isMember(toValidate: unknown): toValidate is EnumMember {
// Asserting that Set.has actually takes in arbitrary values, which it does.
return (this.valueSet.has as (value: unknown) => boolean)(toValidate);
}
/** Take an unknown input from a player script, either return an enum member or throw */
nsGetMember(ctx: NetscriptContext, toValidate: unknown, argName = this.defaultArgName): EnumMember {
if (this.isMember(toValidate)) return toValidate;
// assertString is just called so if the user didn't even pass in a string, they get a different error message
assertString(ctx, argName, toValidate);
throw helpers.makeRuntimeErrorMsg(
ctx,
`Argument ${argName} should be a ${
this.name
} enum member.\nProvided value: "${toValidate}".\nAllowable values: ${this.valueArray
.map((val) => `"${val}"`)
.join(", ")}`,
);
}
/** Provides case insensitivty and ignores spaces and dashes, and can always match the input */
fuzzyGetMember(input: string): EnumMember | undefined;
fuzzyGetMember(input: string, alwaysMatch: true): EnumMember;
fuzzyGetMember(input: string, alwaysMatch = false) {
return this.fuzzMap.get(input.toLowerCase().replace(/[ -]+/g, "")) ?? alwaysMatch ? this.valueArray[0] : undefined;
}
/** Provide a case sensitive match, or undefined if */
getMember(input: unknown): EnumMember | undefined {
return this.isMember(input) ? input : undefined;
}
// Get a random enum member
random() {
const index = getRandomInt(0, this.valueArray.length - 1);
return this.valueArray[index];
}
}
// Creating and populating the enum helpers map
type EnumName = keyof typeof allEnums;
const enumHelpers = new Map();
// Ensure all enums get helpers assigned to them.
Object.entries(allEnums).forEach(([enumName, enumObj]) => {
enumHelpers.set(enumName, new EnumHelper(enumObj, enumName));
});
// This function is just adding types to enumHelpers.get, and is all that gets exposed for use in other files.
export const getEnumHelper: <Name extends EnumName, Enum extends typeof allEnums[Name]>(
name: Name,
) => EnumHelper<Enum, Member<Enum>> = enumHelpers.get.bind(enumHelpers);
export const isMember = <Name extends EnumName, Enum extends typeof allEnums[Name]>(
name: Name,
value: unknown,
): value is Member<Enum> => getEnumHelper(name).isMember(value);