Merge pull request #2550 from TheMas3212/feature-save-validator

Feature save validator
This commit is contained in:
hydroflame 2022-01-15 17:52:17 -05:00 committed by GitHub
commit 2ff7639b79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 1 deletions

@ -18,8 +18,18 @@ import { HacknetNodeConstants } from "./data/Constants";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { ObjectValidator, minMax } from "../utils/Validator";
export class HacknetNode implements IHacknetNode {
static validationData: ObjectValidator<HacknetNode> = {
cores: minMax(1, 1, HacknetNodeConstants.MaxCores),
level: minMax(1, 1, HacknetNodeConstants.MaxLevel),
ram: minMax(1, 1, HacknetNodeConstants.MaxRam),
onlineTimeSeconds: minMax(0, 0, Infinity),
totalMoneyGenerated: minMax(0, 0, Infinity)
}
// Node's number of cores
cores = 1;

@ -1,5 +1,7 @@
/* Generic Reviver, toJSON, and fromJSON functions used for saving and loading objects */
import { validateObject } from "./Validator";
interface IReviverValue {
ctor: string;
data: any;
@ -26,7 +28,11 @@ export function Reviver(key: string, value: IReviverValue | null): any {
const ctor = Reviver.constructors[value.ctor];
if (typeof ctor === "function" && typeof ctor.fromJSON === "function") {
return ctor.fromJSON(value);
const obj = ctor.fromJSON(value);
if (ctor.validationData !== undefined) {
validateObject(obj, ctor.validationData);
}
return obj;
}
}
return value;

78
src/utils/Validator.ts Normal file

@ -0,0 +1,78 @@
export type ObjectValidator<T> = {
[key in keyof T]?: ParameterValidator<T, keyof T>;
}
interface ParameterValidatorObject<Type, Key extends keyof Type> {
default?: any;
min?: number;
max?: number;
func?: (obj: Type, validator: ObjectValidator<Type>, key: Key) => void;
}
type ParameterValidatorFunction<Type, Key extends keyof Type> = (obj: Type, key: Key) => void;
type ParameterValidator<Type, Key extends keyof Type> = ParameterValidatorObject<Type, Key> | ParameterValidatorFunction<Type, Key>
export function validateObject<Type extends Record<string, unknown>, Key extends keyof Type>(obj: Type, validator: ObjectValidator<Type>): void {
for (const key of Object.keys(validator) as Key[]) {
const paramValidator = validator[key];
if (paramValidator !== undefined) {
if (typeof paramValidator === 'function') {
paramValidator(obj, key);
} else {
if (paramValidator.func !== undefined) {
paramValidator.func(obj, validator, key);
} else {
if ((typeof obj[key]) !== (typeof paramValidator.default)) {
obj[key] = paramValidator.default
}
if (typeof obj[key] === 'number' && paramValidator.min !== undefined) {
if (obj[key] < paramValidator.min) obj[key] = paramValidator.min as Type[Key];
}
if (typeof obj[key] === 'number' && paramValidator.max !== undefined) {
if (obj[key] > paramValidator.max) obj[key] = paramValidator.max as Type[Key];
}
}
}
}
}
}
export function minMax<Type, Key extends keyof Type>(def: number, min: number, max: number): (obj: Type, key: Key & keyof Type) => void {
return (obj, key) => {
if (typeof obj[key] !== 'number') {
obj[key] = def as unknown as Type[Key];
return;
}
if ((obj[key] as unknown as number) < min) {
obj[key] = min as unknown as Type[Key];
}
if ((obj[key] as unknown as number) > max) {
obj[key] = max as unknown as Type[Key];
}
};
}
export function oneOf<Type, Key extends keyof Type, Value>(def: Value, options: Value[]): (obj: Type, key: Key & keyof Type) => void {
return (obj, key) => {
if (typeof obj[key] !== typeof def) {
obj[key] = def as unknown as Type[Key];
return;
}
if (!options.includes(obj[key] as unknown as Value)) {
obj[key] = def as unknown as Type[Key];
}
};
}
export function subsetOf<Type, Key extends keyof Type, Value>(options: Value[]): (obj: Type, key: Key & keyof Type) => void {
return (obj, key) => {
if (typeof obj[key] !== 'object' || !Array.isArray(obj[key])) {
obj[key] = [] as unknown as Type[Key];
return;
}
const validValues: Value[] = [];
for (const value of obj[key] as unknown as Value[]) {
if (options.includes(value)) validValues.push(value);
}
obj[key] = validValues as unknown as Type[Key];
};
}