topkat-utils
Version:
A comprehensive collection of TypeScript/JavaScript utility functions for common programming tasks. Includes validation, object manipulation, date handling, string formatting, and more. Zero dependencies, fully typed, and optimized for performance.
209 lines • 11.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validatorReturnErrArray = exports.isType = exports.isValid = exports.validator = exports.checkCtxIntegrity = exports.checkAllObjectValuesAreEmpty = exports.isDateObject = exports.isEmptyOrNotSet = exports.issetOr = void 0;
//----------------------------------------
// VALIDATION UTILS
//----------------------------------------
const isset_1 = require("./isset");
const date_utils_1 = require("./date-utils");
const array_utils_1 = require("./array-utils");
const config_1 = require("./config");
const is_empty_1 = require("./is-empty");
const error_utils_1 = require("./error-utils");
const remove_circular_json_stringify_1 = require("./remove-circular-json-stringify");
function issetOr(...elms) { return elms.some(elm => typeof elm !== 'undefined' && elm !== null); }
exports.issetOr = issetOr;
function isEmptyOrNotSet(...elms) { return elms.some(elm => !(0, isset_1.isset)(elm) || (0, is_empty_1.isEmpty)(elm)); }
exports.isEmptyOrNotSet = isEmptyOrNotSet;
function isDateObject(variable) { return variable instanceof Date; }
exports.isDateObject = isDateObject;
/** Check all values are set */
function checkAllObjectValuesAreEmpty(o) { return Object.values(o).every(value => !(0, isset_1.isset)(value)); }
exports.checkAllObjectValuesAreEmpty = checkAllObjectValuesAreEmpty;
/** Throw an error in case data passed is not a valid ctx */
function checkCtxIntegrity(ctx) {
if (!(0, isset_1.isset)(ctx) || !(0, isset_1.isset)(ctx.user))
throw new error_utils_1.DescriptiveError('ctxNotSet', { code: 500 });
}
exports.checkCtxIntegrity = checkCtxIntegrity;
function validator(...paramsToValidate) {
const errArray = validatorReturnErrArray(...paramsToValidate);
if (errArray.length)
throw new error_utils_1.DescriptiveError(...errArray);
}
exports.validator = validator;
/** Same as validator but return a boolean
* See {@link validator}
*/
function isValid(...paramsToValidate) {
const errArray = validatorReturnErrArray(...paramsToValidate);
return errArray.length ? false : true;
}
exports.isValid = isValid;
function parseValueForDisplay(value) {
try {
if (value === undefined)
return 'undefined';
else if (value?.data?.data)
return { ...value, data: 'Buffer' };
else
return (0, remove_circular_json_stringify_1.removeCircularJSONstringify)(value).substring(0, 999);
}
catch (_) {
return value;
}
}
/** Default types + custom types
* 'objectId','dateInt6','dateInt','dateInt8','dateInt12','time','humanReadableTimestamp','date','array','object','buffer','string','function','boolean','number','bigint',
*/
function isType(value, type) { return isValid({ name: 'Is type check', value, type, emptyAllowed: true }); }
exports.isType = isType;
function validatorReturnErrArray(...paramsToValidate) {
const paramsFormatted = [];
// support for multiple names with multiple values for one rule. Eg: {name: [{startDate:'20180101'}, {endDate:'20180101'}], type: 'dateInt8'}
paramsToValidate.forEach(param => {
if (typeof param !== 'object' || Array.isArray(param))
throw new error_utils_1.DescriptiveError(`wrongTypeForDataValidatorArgument`, { code: 500, origin: 'Generic validator', expectedType: 'object', actualType: Array.isArray(param) ? 'array' : typeof param });
// parse => name: {myVar1: 'blah, myvar2: myvar2}
if (typeof param.name === 'object' && !Array.isArray(param.name))
Object.keys(param.name).forEach(name => paramsFormatted.push(Object.assign({}, param, { name: name, value: param?.name?.[name] })));
else
paramsFormatted.push(param);
});
for (const paramObj of paramsFormatted) {
let name = paramObj.name;
const hasValue = paramObj.hasOwnProperty('value');
let value = paramObj.value;
let optional = paramObj.optional || false;
const emptyAllowed = optional || paramObj.emptyAllowed || false;
if (paramObj.isset === false)
paramObj.mustNotBeSet = true; // ALIAS
const errMess = (msg, extraInfos = {}, errCode = 422) => [msg, { code: errCode, origin: 'Generic validator', varName: name, varType: typeof value, gotValue: parseValueForDisplay(value), ...extraInfos }];
// accept syntax { 'myVar.var2': myVar.var2, ... }
if (typeof name !== 'undefined' && !hasValue) {
name = Object.keys(paramObj).find(param => !['name', 'value', 'type', 'eq', 'neq', 'in', 'lt', 'gt', 'lte', 'gte', 'length', 'minLength', 'maxLength', 'emptyAllowed', 'regexp', 'mustNotBeSet', 'isset', 'optional', 'isArray'].includes(param));
if (typeof name !== 'undefined')
value = paramObj[name];
}
// if nameString ends by $ sign it is optional
if (typeof name !== 'undefined' && /.*\$$/.test(name)) {
name = name.substr(0, name.length - 1);
optional = true;
}
// DEFINED AND NOT EMPTY
if ((typeof value === 'undefined') && optional)
continue;
if (typeof value !== 'undefined' && value !== null && paramObj.mustNotBeSet)
return errMess('variableMustNotBeSet');
if (paramObj.mustNotBeSet)
continue; // exit
if (typeof value === 'undefined')
return errMess('requiredVariableEmptyOrNotSet');
if (!emptyAllowed && value === '')
return errMess('requiredVariableEmpty');
const isArray = paramObj.isArray;
if (isArray && !Array.isArray(value))
return errMess('wrongTypeForVar', { expectedType: 'array', gotType: typeof value });
// TYPE
if (typeof paramObj.type !== 'undefined') {
const types = (0, array_utils_1.asArray)(paramObj.type); // support for multiple type
const areSomeTypeValid = types.some(type => {
if (type.endsWith('[]')) {
if (!Array.isArray(value))
errMess('wrongTypeForVar', { expectedType: 'array', gotType: typeof value });
type = type.replace('[]', '');
}
const allTypes = [
'objectId',
'dateInt6',
'dateInt',
'dateInt8',
'dateInt12',
'time',
'humanReadableTimestamp',
'date',
'dateObject',
'array',
'object',
'buffer',
'string',
'function',
'boolean',
'number',
'bigint',
'year',
'any',
'email',
//...Object.keys(configFn().customTypes)
];
if (!allTypes.includes(type))
throw new error_utils_1.DescriptiveError('typeDoNotExist', { code: 500, type });
const basicTypeCheck = {
objectId: val => /^[0-9a-fA-F-]{24,}$/.test(val),
dateInt6: val => (0, date_utils_1.isDateIntOrStringValid)(parseInt(val + '01'), true, 8),
dateInt: val => (0, date_utils_1.isDateIntOrStringValid)(val, true, 8),
dateInt8: val => (0, date_utils_1.isDateIntOrStringValid)(val, true, 8),
dateInt12: val => (0, date_utils_1.isDateIntOrStringValid)(val, true, 12),
time: val => /^\d\d:\d\d$/.test(val) && (0, date_utils_1.isTimeStringValid)(val),
humanReadableTimestamp: val => (val + '').length === 17,
date: val => (0, date_utils_1.isDateIsoOrObjectValid)(val, true),
dateObject: val => (0, date_utils_1.isDateIsoOrObjectValid)(val, true),
array: val => Array.isArray(val),
object: val => !Array.isArray(val) && val !== null && typeof val === type,
buffer: val => Buffer.isBuffer(val),
year: val => /^\d\d\d\d$/.test(val),
email: val => /^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]+$/.test(val),
any: () => true,
};
return typeof basicTypeCheck?.[type] !== 'undefined' && basicTypeCheck?.[type](value) ||
typeof value === type && type !== 'object' || // for string, number, boolean...
typeof (0, config_1.configFn)()?.customTypes?.[type] !== 'undefined' && (0, config_1.configFn)()?.customTypes?.[type]?.test(value);
});
if (!areSomeTypeValid)
return errMess(`wrongTypeForVar`, { expectedTypes: types.join(', '), gotType: Object.prototype.toString.call(value), gotValue: parseValueForDisplay(value) });
}
// GREATER / LESS
if (typeof paramObj.gte !== 'undefined' && value < paramObj.gte)
return errMess(`valueShouldBeSuperiorOrEqualForVar`, { shouldBeSupOrEqTo: paramObj.gte });
if (typeof paramObj.lte !== 'undefined' && value > paramObj.lte)
return errMess(`valueShouldBeInferiorOrEqualForVar`, { shouldBeInfOrEqTo: paramObj.lte });
if (typeof paramObj.gt !== 'undefined' && value <= paramObj.gt)
return errMess(`valueShouldBeSuperiorForVar`, { shouldBeSupOrEqTo: paramObj.gt });
if (typeof paramObj.lt !== 'undefined' && value >= paramObj.lt)
return errMess(`valueShouldBeInferiorForVar`, { shouldBeInfOrEqTo: paramObj.lt });
// IN VALUES
if (typeof paramObj.in !== 'undefined') {
const equals = Array.isArray(paramObj.in) ? paramObj.in : [paramObj.in];
if (!equals.some(equalVal => equalVal === value))
return errMess(`wrongValueForVar`, { supportedValues: parseValueForDisplay(equals) });
}
// EQUAL (exact copy of .in)
if (paramObj.hasOwnProperty('eq')) {
const equals = Array.isArray(paramObj.eq) ? paramObj.eq : [paramObj.eq];
if (!equals.some(equalVal => equalVal === value))
return errMess(`wrongValueForVar`, { supportedValues: parseValueForDisplay(equals), });
}
// NOT EQUAL
if (paramObj.hasOwnProperty('neq')) {
const notEquals = Array.isArray(paramObj.neq) ? paramObj.neq : [paramObj.neq];
if (notEquals.some(equalVal => equalVal === value))
return errMess(`wrongValueForVar`, { NOTsupportedValues: parseValueForDisplay(notEquals) });
}
// INCLUDES
if (typeof paramObj.includes !== 'undefined' && !value.includes(paramObj.includes))
return errMess(`wrongValueForVar`, { shouldIncludes: paramObj.includes });
// REGEXP
if (typeof paramObj.regexp !== 'undefined' && !paramObj.regexp.test(value))
return errMess(`wrongValueForVar`, { shouldMatchRegexp: paramObj.regexp.toString() });
// MIN / MAX LENGTH works for number length. Eg: 20180101.length == 8
if (typeof paramObj.minLength !== 'undefined' && paramObj.minLength > (typeof value == 'number' ? value + '' : value).length)
return errMess(`wrongLengthForVar`, { minLength: paramObj.minLength });
if (typeof paramObj.maxLength !== 'undefined' && paramObj.maxLength < (typeof value == 'number' ? value + '' : value).length)
return errMess(`wrongLengthForVar`, { maxLength: paramObj.maxLength });
if (typeof paramObj.length !== 'undefined' && paramObj.length !== (typeof value == 'number' ? value + '' : value).length)
return errMess(`wrongLengthForVar`, { length: paramObj.length });
}
return [];
}
exports.validatorReturnErrArray = validatorReturnErrArray;
//# sourceMappingURL=validation-utils.js.map