Skip to content

Instantly share code, notes, and snippets.

@jeff-kilbride
Last active December 11, 2016 00:16
Show Gist options
  • Save jeff-kilbride/68fea43614235bf7ff9ebb9be804e070 to your computer and use it in GitHub Desktop.
Save jeff-kilbride/68fea43614235bf7ff9ebb9be804e070 to your computer and use it in GitHub Desktop.
/**
* checkParams tests the params object against the required object.
* The required object can take the following forms:
*
* { paramName: true }
*
* paramName in params is ONLY tested for existence.
*
* {
* paramName: {
* value: requiredValue | RegExp,
* type: requiredType,
* cast: true | 'return'
* }
* }
*
* If value is provided, paramName is tested for strict equality with requiredValue. The
* requiredValue may also be a regular expression object, in which case paramName must
* be a string and must pass the RegExp.test() method.
*
* If type is provided, paramName must match requiredType or, if cast is also provided,
* be castable to requiredType. If cast is set to 'return' and paramName is successfully
* cast to requiredType, the value in the params object will reflect the requiredType.
* Valid requiredType values are string, number, boolean, array, object, function, date,
* map, and set. The cast property is only valid with string, number, boolean, and
* array types. For all other types, it is ignored.
*
* If an error occurs, checkParams will throw the appropriate CustomError. If no error
* occurs, there is no explicit return value.
*
* @param {Object} params
* @param {Object} required
* @throws CustomError
*/
function checkParams(params, required) {
// Ahem... make sure checkParams gets valid params...
if (!params)
throw this.MPError.get('params');
else if (!_.isPlainObject(params))
throw this.IPError.get(['params', params]);
else if (!required)
throw this.MPError.get('required');
else if (!_.isPlainObject(required))
throw this.IPError.get(['required', required]);
const names = Object.keys(required);
for (let name of names) {
const param = params[name];
// Doesn't exist, throw a missing param error.
if (param == undefined)
throw this.MPError.get(name);
// If required[name] is boolean true (not an object), we're done.
if (required[name] === true) continue;
// Doesn't match required value, throw invalid param error.
const rVal = required[name].value;
if (rVal && _.isRegExp(rVal)) {
if (!_.isString(param) || !rVal.test(param))
throw this.IPError.get([name, param]);
}
else if (rVal && param !== required[name].value)
throw this.IPError.get([name, param]);
// Doesn't match required type, throw invalid param error.
if (required[name].type) {
const cast = required[name].cast;
let err = false, test, value;
switch (required[name].type) {
case 'string':
test = _.isString(param);
if (cast && !test)
value = String(param);
else if (!test)
err = true;
break;
case 'number':
test = _.isNumber(param);
if (cast && !test)
value = Number(param);
else if (!test)
err = true;
break;
case 'boolean':
test = _.isBoolean(param);
if (cast && !test)
value = Boolean(param);
else if (!test)
err = true;
break;
case 'array':
test = Array.isArray(param);
if (cast && !test) {
value = Array.from(param);
if (!value.length) err = true;
}
else if (!test) {
err = true;
}
break;
case 'object':
if (!_.isPlainObject(param))
err = true;
break;
case 'function':
if (!_.isFunction(param))
err = true;
break;
case 'date':
if (!_.isDate(param))
err = true;
break;
case 'map':
if (!(param instanceof Map))
err = true;
break;
case 'set':
if (!(param instanceof Set))
err = true;
break;
}
// Handle errors and values that couldn't be cast first.
if (err || (cast && !value && value !== false))
throw this.IPError.get([name, param]);
// Set the newly cast value in the params object, if requested.
else if (cast === 'return' && (value || value === false))
params[name] = value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment