This repository has been archived on 2023-01-14. You can view files and clone it, but cannot push or open issues or pull requests.
libsiaweb/dist/validateObjPropTypes.js

99 lines
3.5 KiB
JavaScript

import { addContextToErr } from "./err.js";
// validateObjPropTypes takes an object as input, along with a list of checks
// that should performed on the properties of the object. If all of the
// properties are present in the object and adhere to the suggested types,
// `null` is returned. Otherwise a string is returned indicating the first
// property that failed a check.
//
// This function is intended to be used on objects that were decoded from JSON
// after being received by an untrusted source.
//
// validateObjProperties supports all of the basic types, as well as arrays for
// types boolean, number, bigint, and string. In the future, support for more
// types may be added as well.
//
// Below is an example object, followed by the call that you would make to
// checkObj to verify the object.
//
// const expectedObj = {
// aNum: 35,
// aStr: "hi",
// aBig: 10n,
// aArr: [1, 2, 3],
// };
//
// const err = validateObjPropTypes(expectedObj, [
// ["aNum", "number"],
// ["aStr", "string"],
// ["aBig", "bigint"],
// ["aArr", "numberArray"],
// ["aUint8Array", "Uint8Array"],
// ]);
function validateObjPropTypes(obj, checks) {
for (let i = 0; i < checks.length; i++) {
const [property, expectedType] = checks[i];
// Loop through the array cases.
const arrayCases = [
["booleanArray", "boolean"],
["numberArray", "number"],
["bigintArray", "bigint"],
["stringArray", "string"],
];
let checkPassed = false;
for (let j = 0; j < arrayCases.length; j++) {
// If this is not an array case, ignore it.
const [arrCaseType, arrType] = arrayCases[j];
if (expectedType !== arrCaseType) {
continue;
}
// Check every element in the array.
const err = validateArrayTypes(obj[property], arrType);
if (err !== null) {
return addContextToErr(err, `check failed for array property '${property}'`);
}
// We found the expected type for this check, we can stop checking the
// rest.
checkPassed = true;
break;
}
// If the type was an array type, we don't need to perform the next check.
if (checkPassed === true) {
continue;
}
// Uint8Array check.
if (expectedType === "Uint8Array") {
if (obj[property] instanceof Uint8Array) {
continue;
}
else {
return `check failed for property '${property};, expecting Uint8Array`;
}
}
// Generic typeof check.
const type = typeof obj[property];
if (type !== expectedType) {
return `check failed for property '${property}', expecting ${expectedType} got ${type}`;
}
}
return null;
}
// validateArrayTypes takes an array as input and validates that every element
// in the array matches the provided type.
//
// This is a helper function for validateObjPropTypes, the property is provided
// as an input to produce a more coherent error message.
function validateArrayTypes(arr, expectedType) {
// Check that the provided input is actually an array.
if (!Array.isArray(arr)) {
return `not an array`;
}
for (let i = 0; i < arr.length; i++) {
const type = typeof arr[i];
if (type !== expectedType) {
return `element ${i} is expected to be ${expectedType}, got ${type}`;
}
}
return null;
}
export { validateObjPropTypes };