From d9064b608f8969db4e1cdb2d5070066ea1d338a1 Mon Sep 17 00:00:00 2001 From: TheMas3212 Date: Mon, 10 Jan 2022 05:50:11 +1100 Subject: [PATCH] PoC for save validation on load via hooking the Reviver function and static property validationData on classes PoC/example implemented with HacknetNode: validates cores is a number in the range between 1 and HacknetNodeConstants.MaxCores validates level is a number in range between 1 and HacknetNodeConstants.MaxLevel validates ram is a number in range between 1 and HacknetNodeConstants.MaxRam validates onlineTimeSeconds in non negative number validates totalMoneyGenerated is a non negative number --- src/Hacknet/HacknetNode.ts | 28 ++++++++++++++++++++++++++++ src/utils/JSONReviver.ts | 8 +++++++- src/utils/Validator.ts | 31 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/utils/Validator.ts diff --git a/src/Hacknet/HacknetNode.ts b/src/Hacknet/HacknetNode.ts index 4982b606b..9d79f334d 100644 --- a/src/Hacknet/HacknetNode.ts +++ b/src/Hacknet/HacknetNode.ts @@ -18,8 +18,36 @@ import { HacknetNodeConstants } from "./data/Constants"; import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; +import { ObjectValidator } from "src/utils/Validator"; export class HacknetNode implements IHacknetNode { + + static validationData: ObjectValidator = { + cores: { + default: 1, + min: 1, + max: HacknetNodeConstants.MaxCores + }, + level: { + default: 1, + min: 1, + max: HacknetNodeConstants.MaxLevel + }, + ram: { + default: 1, + min: 1, + max: HacknetNodeConstants.MaxRam + }, + onlineTimeSeconds: { + default: 0, + min: 0 + }, + totalMoneyGenerated: { + default: 0, + min: 0 + } + } + // Node's number of cores cores = 1; diff --git a/src/utils/JSONReviver.ts b/src/utils/JSONReviver.ts index eeb832cec..5b7447d09 100644 --- a/src/utils/JSONReviver.ts +++ b/src/utils/JSONReviver.ts @@ -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; diff --git a/src/utils/Validator.ts b/src/utils/Validator.ts new file mode 100644 index 000000000..a97b5b039 --- /dev/null +++ b/src/utils/Validator.ts @@ -0,0 +1,31 @@ +export type ObjectValidator = { + [key in keyof T]?: ParameterValidator; +} + +interface ParameterValidator { + default?: any; + min?: number; + max?: number; + func?: (obj: T, validator: ObjectValidator, key: U) => void; +} + +export function validateObject, U extends keyof T>(obj: T, validator: ObjectValidator): void { + for (const key of Object.keys(validator) as U[]) { + const paramValidator = validator[key]; + if (paramValidator !== undefined) { + 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 T[U]; + } + if (typeof obj[key] === 'number' && paramValidator.max !== undefined) { + if (obj[key] > paramValidator.max) obj[key] = paramValidator.max as T[U]; + } + } + } + } +} \ No newline at end of file