@reldens/utils
Version:
716 lines (641 loc) • 18.8 kB
JavaScript
/**
*
* Reldens - Shortcuts
*
*/
class Shortcuts
{
hasOwn(obj, prop)
{
if(this.isArray(prop) && 0 < prop.length){
for(let value of prop){
if(!(obj && {}.hasOwnProperty.call(obj, value))){
return false;
}
}
return true;
}
return obj && {}.hasOwnProperty.call(obj, prop) && 'undefined' !== typeof obj[prop];
}
isTrue(obj, prop, strictValidation)
{
return (
obj && {}.hasOwnProperty.call(obj, prop)
&& 'undefined' !== typeof obj[prop]
&& (strictValidation ? true === obj[prop] : obj[prop])
);
}
isObject(obj)
{
return (obj && 'object' === typeof obj && !this.isArray(obj));
}
isArray(obj)
{
return Array.isArray(obj);
}
inArray(value, dataArray)
{
if(!this.isArray(dataArray)){
return false;
}
return -1 !== dataArray.indexOf(value);
}
isNotEmptyArray(dataArray)
{
return (this.isArray(dataArray) && 0 < dataArray.length);
}
isFunction(callback)
{
return (callback && 'function' === typeof callback);
}
isObjectFunction(obj, property)
{
return this.isObject(obj) && property && 'function' === typeof obj[property];
}
isSymbol(value)
{
return 'symbol' === typeof value;
}
isString(value)
{
return 'string' === typeof value;
}
isNumber(value)
{
return 'number' === typeof value;
}
isInt(value)
{
if(!this.isNumber(value)){
return false;
}
return Number.isInteger(value);
}
isFloat(value)
{
if(!this.isNumber(value)){
return false;
}
return Number(value) === value && 0 !== value % 1;
}
isBoolean(value)
{
return 'boolean' === typeof value;
}
isPromise(value)
{
return value && 'function' === typeof value.then;
}
hasDangerousKeys(obj, key = null)
{
let dangerousKeys = ['__proto__', 'constructor', 'prototype'];
if(key){
return -1 !== dangerousKeys.indexOf(key);
}
if(!this.isObject(obj)){
return false;
}
for(let dangerousKey of dangerousKeys){
if(this.hasOwn(obj, dangerousKey)){
return true;
}
}
return false;
}
deepMergeProperties(target, source)
{
if(!this.isObject(target) || !this.isObject(source)){
return false;
}
for(let key of Object.keys(source)){
if(this.hasDangerousKeys(null, key)){
continue;
}
if(this.isObject(source[key])){
if(!this.hasOwn(target, key)){
target[key] = source[key];
continue;
}
this.deepMergeProperties(target[key], source[key]);
continue;
}
target[key] = source[key];
}
return target;
}
length(obj)
{
if(!obj){
return 0;
}
return Object.keys(obj).length;
}
startsWith(term, startWith)
{
return this.isString(term) && 0 === term.indexOf(startWith);
}
contains(term, needle)
{
return this.isString(term) && -1 !== term.indexOf(needle);
}
convertObjectsArrayToObjectByKeys(dataArray, keyProperty)
{
if(!this.isArray(dataArray) || 0 === dataArray.length){
return {};
}
let objectByKeys = {};
for(let arrayItem of dataArray){
objectByKeys[arrayItem[keyProperty]] = arrayItem;
}
return objectByKeys;
}
sortObjectKeysBy(obj, sortField)
{
return Object.keys(obj).sort((a, b) => {
return (obj[a][sortField] > obj[b][sortField]) ? 1 : -1;
});
}
arraySort(collection, sortField, direction = 'asc')
{
if(!collection){
return collection;
}
if(!sortField){
return collection;
}
let directionValue = 'asc' === direction ? 1 : -1;
let directionOpposite = 'asc' === direction ? -1 : 1;
return collection.sort((a, b) => {
return a[sortField] > b[sortField] ? directionValue : directionOpposite;
});
}
propsAssign(from, to, props)
{
if(!this.isArray(props)){
return to;
}
for(let i of props){
to[i] = from[i];
}
return to;
}
toJson(jsonString, defaultReturn = false)
{
return this.parseJson(jsonString) || defaultReturn;
}
parseJson(jsonString, defaultReturn = false)
{
let parsed;
try {
parsed = JSON.parse(jsonString);
} catch (e) {
return defaultReturn;
}
if(this.hasDangerousKeys(parsed)){
return defaultReturn;
}
return parsed;
}
deepJsonClone(obj)
{
return JSON.parse(this.toJsonString(obj));
}
toJsonString(obj)
{
return JSON.stringify(obj);
}
get(obj, prop, defaultReturn)
{
return this.hasOwn(obj, prop) ? obj[prop] : defaultReturn;
}
getByPath(obj, propertyPath, defaultReturn)
{
if(!this.isObject(obj) || !this.isArray(propertyPath)){
return defaultReturn;
}
let property = propertyPath.shift();
if(0 === propertyPath.length){
return this.get(obj, property, defaultReturn);
}
return this.getByPath(obj[property], propertyPath, defaultReturn);
}
getByPriority(obj, propsArray)
{
if(!this.isArray(propsArray)){
return false;
}
for(let prop of propsArray){
if(this.hasOwn(obj, prop)){
return obj[prop];
}
}
return false;
}
fetchByProperty(itemsArray, propertyName, propertyValue)
{
if(!this.isArray(itemsArray)){
return false;
}
if(0 === itemsArray.length){
return false;
}
for(let item of itemsArray){
if(item[propertyName] === propertyValue){
return item;
}
}
return false;
}
fetchAllByProperty(itemsArray, propertyName, propertyValue)
{
if(!this.isArray(itemsArray)){
return [];
}
if(0 === itemsArray.length){
return [];
}
let foundItems = [];
for(let item of itemsArray){
if(item[propertyName] === propertyValue){
foundItems.push(item);
}
}
return foundItems;
}
fetchByPropertyOnObject(objectList, propertyName, propertyValue)
{
if(!objectList){
return false;
}
let objKeys = Object.keys(objectList);
if(0 === objKeys.length){
return false;
}
for(let i of objKeys){
let obj = objectList[i];
if(obj[propertyName] === propertyValue){
return obj;
}
}
return false;
}
fetchAllByPropertyOnObject(objectList, propertyName, propertyValue)
{
if(!objectList){
return [];
}
let objKeys = Object.keys(objectList);
if(0 === objKeys.length){
return [];
}
let results = [];
for(let i of objKeys){
let obj = objectList[i];
if(obj[propertyName] === propertyValue){
results.push(obj);
}
}
return results;
}
serializeFormData(formData)
{
if(0 === formData.length){
return {};
}
let obj = {};
for(let [key, value] of formData){
if(obj[key] !== undefined){
if(!this.isArray(obj[key])){
obj[key] = [obj[key]];
}
obj[key].push(value);
} else {
obj[key] = value;
}
}
return obj;
}
removeFromArray(valuesArray, removeValues)
{
return valuesArray.filter((value) => {
return -1 === removeValues.indexOf(value);
});
}
getCurrentDate()
{
return (new Date()).toISOString().slice(0, 19).replace('T', ' ');
}
getDateForFileName()
{
return (new Date()).toISOString().slice(0, 19).replace('T', '-').replace(/:/g, '-');
}
formatDate(date, format = 'Y-m-d H:i:s')
{
if(!(date instanceof Date)){
return date;
}
let map = {
Y: date.getFullYear(),
m: (date.getMonth() + 1).toString().padStart(2, '0'),
d: date.getDate().toString().padStart(2, '0'),
H: date.getHours().toString().padStart(2, '0'),
i: date.getMinutes().toString().padStart(2, '0'),
s: date.getSeconds().toString().padStart(2, '0')
};
return format.replace(/Y|m|d|H|i|s/g, matched => map[matched]);
}
getTime()
{
return (new Date()).getTime();
}
roundToPrecision(number, precision = 4)
{
return Number(Number(number).toFixed(precision));
}
randomValueFromArray(array)
{
if(!this.isArray(array) || 0 === array.length){
return null;
}
return array[Math.floor(Math.random() * array.length)];
}
randomInteger(min, max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}
randomChars(length)
{
if(0 >= length){
return '';
}
return this.randomString(length, false);
}
randomCharsWithSymbols(length)
{
if(0 >= length){
return '';
}
return this.randomString(length, true);
}
randomString(length, withSymbols = false)
{
let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
if(withSymbols){
characters += '!@#$%&*()_-=+[]{}:;<>,./?';
}
let charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
cleanMessage(message, characterLimit)
{
if(!message){
return '';
}
let text = message.replace(/\\/g, '').replace(/[\r\n\t]/g, ' ');
if(0 < characterLimit){
return text.substring(0, characterLimit);
}
return text;
}
slugify(text)
{
return (text || '').replace(/&/g, ' and ')
.replace(/[^a-zA-Z0-9]/g, ' ')
.trim()
.replace(/\s+/g, '-')
.toLowerCase();
}
isValidIsoCode(isoCode)
{
return (/^[a-zA-Z]{2}$/).test(isoCode);
}
sanitize(input)
{
if(!input){
return '';
}
return input.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\//g, '/')
.replace(/`/g, '`')
.replace(/\(/g, '(')
.replace(/\)/g, ')');
}
sanitizeUrl(url)
{
if(!url || !this.isString(url) || 2048 < url.length){
return '';
}
let sanitized = url.trim();
let urlPattern = /^https?:\/\/(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)(?::[1-9][0-9]{0,4})?(?:\/(?:[\w\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*(?:\?(?:[\w\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*)?(?:#(?:[\w\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*)?$/;
if(!urlPattern.test(sanitized)){
return '';
}
return sanitized.replace(/javascript:/gi, '')
.replace(/data:/gi, '')
.replace(/vbscript:/gi, '');
}
camelCase(str)
{
if(!this.isString(str) || 0 === str.length){
return str;
}
return str.replace(/[_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
}
capitalizedCamelCase(str)
{
if(!this.isString(str) || 0 === str.length){
return str;
}
let camelStr = this.camelCase(str);
return camelStr.charAt(0).toUpperCase() + camelStr.slice(1);
}
kebabCase(str)
{
return str.replace(/[_\s]+/g, '-');
}
capitalize(str)
{
if(!this.isString(str) || 0 === str.length){
return str;
}
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}
chunk(array, size)
{
if(!this.isArray(array) || 0 >= size){
return [];
}
let result = [];
for(let i = 0; i < array.length; i += size){
result.push(array.slice(i, i + size));
}
return result;
}
flatten(array, depth = 1)
{
if(!this.isArray(array)){
return [];
}
return array.flat(depth);
}
unique(array)
{
if(!this.isArray(array)){
return [];
}
return [...new Set(array)];
}
clamp(value, min, max)
{
if(!this.isNumber(value) || !this.isNumber(min) || !this.isNumber(max)){
return value;
}
return Math.min(Math.max(value, min), max);
}
truncate(str, length, suffix = '...')
{
if(!this.isString(str) || str.length <= length){
return str;
}
return str.substring(0, length) + suffix;
}
pickProps(obj, props)
{
if(!this.isObject(obj) || !this.isArray(props)){
return {};
}
let result = {};
for(let prop of props){
if(this.hasDangerousKeys(null, prop)){
continue;
}
if(this.hasOwn(obj, prop)){
result[prop] = obj[prop];
}
}
return result;
}
omitProps(obj, props)
{
if(!this.isObject(obj) || !this.isArray(props)){
return obj;
}
let result = {};
for(let key of Object.keys(obj)){
if(-1 === props.indexOf(key)){
result[key] = obj[key];
}
}
return result;
}
debounce(func, wait)
{
if(!this.isFunction(func) || !this.isNumber(wait)){
return func;
}
let timeout;
return function executedFunction(...args) {
let later = () => {
clearTimeout(timeout);
func.apply(this, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
throttle(func, limit)
{
if(!this.isFunction(func) || !this.isNumber(limit)){
return func;
}
let inThrottle;
return function executedFunction(...args) {
if(!inThrottle){
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
isValidUrl(url)
{
if(!this.isString(url) || 2048 < url.length){
return false;
}
let urlPattern = /^https?:\/\/(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)*[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)(?::[1-9][0-9]{0,4})?(?:\/(?:[\w\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*(?:\?(?:[\w\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*)?(?:#(?:[\w\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*)?$/;
return urlPattern.test(url);
}
isValidInteger(value, min, max)
{
if(!this.isNumber(value) || !Number.isInteger(value)){
return false;
}
if('number' === typeof min && value < min){
return false;
}
if('number' === typeof max && value > max){
return false;
}
return true;
}
parseNumber(value)
{
if(!isNaN(Number(value)) && '' !== value && null !== value){
return Number(value);
}
return null;
}
splitToArray(str, separator = ',')
{
if(!this.isString(str) || '' === str.trim()){
return null;
}
return str.split(separator).map(item => item.trim()).filter(item => '' !== item);
}
isSecurePath(filePath, dangerous = [], maxLength = 2048)
{
if(!this.isString(filePath)){
return false;
}
let normalized = filePath.replace(/\\/g, '/');
if(!this.isArray(dangerous) || 0 === dangerous.length){
dangerous = [
'../', '..\\', './', '.\\',
'/etc/', '/proc/', '/sys/',
'C:\\Windows\\', 'C:\\System32\\',
'%2e%2e%2f', '%2e%2e%5c'
];
}
for(let pattern of dangerous){
if(normalized.toLowerCase().includes(pattern.toLowerCase())){
return false;
}
}
return maxLength >= filePath.length;
}
validateInput(input, type)
{
if(!this.isString(input)){
return false;
}
let patterns = {
email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
username: /^[a-zA-Z0-9_-]{3,30}$/,
strongPassword: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
alphanumeric: /^[a-zA-Z0-9]+$/,
numeric: /^\d+$/,
hexColor: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
};
return patterns[type] ? patterns[type].test(input) : false;
}
}
module.exports = new Shortcuts();