UNPKG

@slck/utils

Version:

utils library - Utility functions for common development.

421 lines 14.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.hasValidDateFn = exports.trimObjectValues = exports.isEndpointConfig = exports.addSpacesToCamelCase = exports.constructTreeRecursively = exports.convertFirstLetterToUpper = exports.convertMinutesToTimeText = exports.checkObjectPropValueExistsInCollection = exports.shiftToFristWith = exports.compareObjectArraysWithTypeSafe = exports.genericObjectTypeFn = exports.objectDifferenceByProps = exports.camelCaseKeysHelper = exports.toCamelCaseKeys = exports.isEmptyInDepth = exports.isNullOrUndefinedEmpty = exports.hasValidLength = exports.isEmpty = exports.remainingDaysHoursFormSeconds = exports.remainingDaysHoursFormTwoDates = exports.daysTimeFromSeconds = exports.objectNonShadowCopy = exports.leadZeroForMonthOrDay = exports.isObject = exports.isDate = exports.isNullOrUndefined = void 0; const lodash_1 = require("lodash"); /** * verifies object is null or undefined, if 'yes' return true. * @param value type any * @returns boolean */ const isNullOrUndefined = (value) => { return value === null || value === undefined; }; exports.isNullOrUndefined = isNullOrUndefined; /** * * @param value * @returns */ const isDate = (value) => { try { return !isNaN(new Date(value).getTime()); } catch (e) { return false; } }; exports.isDate = isDate; /** * * @param value * @returns */ const isObject = (value) => { return !(0, exports.isNullOrUndefined)(value) ? typeof value === 'object' : false; }; exports.isObject = isObject; /** * Add leading '0' to the either to month or day * @param value type number * @returns number or string */ const leadZeroForMonthOrDay = (value) => { return value < 10 ? `0${value}` : value; }; exports.leadZeroForMonthOrDay = leadZeroForMonthOrDay; /** * * @param value * @returns */ const objectNonShadowCopy = (value) => { return JSON.parse(JSON.stringify(value)); }; exports.objectNonShadowCopy = objectNonShadowCopy; /** * Calculate number of days, hours, minutes and seconds remaining for given seconds * @param value type 'number' * @returns an object consists number of days, hours, minutes and seconds remaining */ const daysTimeFromSeconds = (seconds) => { return { days: Math.floor(seconds / 86400), hours: Math.floor(seconds / 3600) % 24, minutes: Math.floor(seconds / 60) % 60, seconds: seconds % 60, }; }; exports.daysTimeFromSeconds = daysTimeFromSeconds; /** * * @param value * @returns */ const remainingDaysHoursFormTwoDates = (startDate, finish) => { try { if (finish.getTime() > startDate.getTime()) { return (0, exports.daysTimeFromSeconds)((finish.getTime() - startDate.getTime()) / 1000); } else { return null; } } catch (error) { return null; } }; exports.remainingDaysHoursFormTwoDates = remainingDaysHoursFormTwoDates; /** * * @param value * @returns */ const remainingDaysHoursFormSeconds = (seconds) => { try { return (0, exports.daysTimeFromSeconds)(seconds); } catch (error) { return null; } }; exports.remainingDaysHoursFormSeconds = remainingDaysHoursFormSeconds; /** * verifies object length equals to 0, if 'yes' return true. * @param value type any * @returns boolean */ const isEmpty = (value) => { // we don't check for string here so it also works with arrays return value == null || value.length === 0; }; exports.isEmpty = isEmpty; const hasValidLength = (value) => { // non-strict comparison is intentional, to check for both `null` and `undefined` values return value != null && typeof value.length === 'number'; }; exports.hasValidLength = hasValidLength; /** * verifies object is null or undefined and length equals to 0, if 'yes' return true. * @param value type any * @returns boolean */ const isNullOrUndefinedEmpty = (value) => { return (0, exports.isNullOrUndefined)(value) || (0, exports.isEmpty)(value); }; exports.isNullOrUndefinedEmpty = isNullOrUndefinedEmpty; /** * verifies object is empty & it's props, if 'yes' return true. * @param value type any * @returns boolean */ const isEmptyInDepth = (value) => { if ((0, exports.isNullOrUndefined)(value)) { return true; } else { let emptyValues = 0; Object.entries(value).forEach(([key, v]) => { switch (typeof v) { case 'boolean': emptyValues += v === false ? 1 : 0; break; case 'string': emptyValues += v.length <= 0 ? 1 : 0; break; case 'object': if ((0, exports.isNullOrUndefined)(v)) { emptyValues += 1; } else { emptyValues += Object.entries(value).length <= 0 ? 1 : 0; } break; } }); return Object.entries(value).length === emptyValues; } }; exports.isEmptyInDepth = isEmptyInDepth; /** * * @param obj * @returns camelCase notation object */ const toCamelCaseKeys = (obj) => { return (0, lodash_1.isArray)(obj) ? obj.map((o) => (0, exports.toCamelCaseKeys)(o)) : (0, exports.camelCaseKeysHelper)(obj); }; exports.toCamelCaseKeys = toCamelCaseKeys; const camelCaseKeysHelper = (obj) => { const entries = Object.entries(obj); const mappedEntries = entries.map(([k, v]) => [ `${k.slice(0, 1).toLowerCase()}${k.slice(1)}`, (0, exports.isObject)(v) ? (0, exports.toCamelCaseKeys)(v) : v, ]); return Object.fromEntries(mappedEntries); }; exports.camelCaseKeysHelper = camelCaseKeysHelper; /** difference between two objects * return an array object with differed property its source object * and its destination object values respectively */ const objectDifferenceByProps = (sourceObject, destinationObject) => { const diffProps = []; if ((0, exports.isNullOrUndefinedEmpty)(sourceObject) && (0, exports.isNullOrUndefinedEmpty)(destinationObject)) { return diffProps; } for (const prop in sourceObject) { if ( // eslint-disable-next-line no-prototype-builtins sourceObject.hasOwnProperty(prop) && // eslint-disable-next-line no-prototype-builtins destinationObject.hasOwnProperty(prop)) { switch (typeof sourceObject[prop]) { case 'object': (0, exports.objectDifferenceByProps)(sourceObject[prop], destinationObject[prop]); break; default: if (sourceObject[prop] !== destinationObject[prop]) { diffProps.push({ property: prop, sourceValue: sourceObject[prop], destinationValue: destinationObject[prop], }); } break; } } } return diffProps; }; exports.objectDifferenceByProps = objectDifferenceByProps; const genericObjectTypeFn = (key, rValue) => ({ [key]: rValue }); exports.genericObjectTypeFn = genericObjectTypeFn; /** * * @param arr1 * @param arr2 * @returns { result: boolean; error: ErrorType } */ const compareObjectArraysWithTypeSafe = (arr1, arr2) => { if (arr1.length !== arr2.length) { return { result: false, error: `Array lengths do not match`, }; } for (let i = 0; i < arr1.length; i++) { const obj1 = arr1[i]; const obj2 = arr2[i]; if (Object.keys(obj1).length !== Object.keys(obj2).length) { return { result: false, error: `Object at index ${i} has a different number of keys.`, }; } for (const key in obj1) { if (!(key in obj2)) { return { result: false, error: `Key "${key}" in object at index ${i} does not exist in the other object.`, }; } if (typeof obj1[key] !== typeof obj2[key]) { return { result: false, error: `Key "${key}" in object at index ${i} has a type mismatch.`, }; } } } return { result: true, error: null }; }; exports.compareObjectArraysWithTypeSafe = compareObjectArraysWithTypeSafe; /** * @description bring the element to the first by searchWith * @param items Type of array * @param key key of the object inside the array * @param searchWith search key either string, number or boolean * @param isConvertStringToLowerCase by default is true * @returns modified object array */ const shiftToFristWith = (items, key, searchWith, isConvertStringToLowerCase = true) => { items.forEach((value, index) => { switch (typeof value[key]) { case 'string': if (isConvertStringToLowerCase ? value[key].toLowerCase() === searchWith.toLowerCase() : value[key] === searchWith) { items.splice(index, 1); items.unshift(value); } break; case 'boolean': if (value[key] === searchWith) { items.splice(index, 1); items.unshift(value); } break; case 'number': if (value[key] === searchWith) { items.splice(index, 1); items.unshift(value); } break; default: break; } }); return items; }; exports.shiftToFristWith = shiftToFristWith; /** * @description Return `true` if the property values match in the collection of objects. * @param object T * @param collection T[] * @param prop key of T * @returns boolean */ const checkObjectPropValueExistsInCollection = (object, collection, prop) => collection.some((c) => c[prop] === object[prop]); exports.checkObjectPropValueExistsInCollection = checkObjectPropValueExistsInCollection; /** * * @param minutes number of minutes * @param unitOfHours like 'h', 'hrs' * @param unitOfminutes like 'min', 'm' * @returns */ const convertMinutesToTimeText = (minutes, unitOfHours, unitOfminutes) => { return `${Math.floor(minutes / 60)} ${unitOfHours} ${Math.floor(minutes % 60)} ${unitOfminutes}`; }; exports.convertMinutesToTimeText = convertMinutesToTimeText; /** * * @param text * @param seperator * @returns */ const convertFirstLetterToUpper = (text, seperator = ' ') => { return text ? text .split(`${seperator}`) .map((s) => (s ? s[0].toUpperCase() : '')) .join('') : ``; }; exports.convertFirstLetterToUpper = convertFirstLetterToUpper; /** * * @param data is a collection of T * @param childrenKey children key property in K * @param valueKey value key which used for split or run logic * @param valueKeyForTree value to holds the conversion value from valueKey * @param delimiter string spearator * @returns a collection of K */ const constructTreeRecursively = (data, childrenKey, valueKey, valueKeyForTree, delimiter = '.') => { const root = []; data.forEach((obj) => { const parts = obj[valueKey].split(delimiter); addPathToTreeRecursively(parts, obj, root, childrenKey, valueKeyForTree); }); return root; }; exports.constructTreeRecursively = constructTreeRecursively; const addPathToTreeRecursively = (parts, rootobjectReference, nodeList, childrenKey, valueKey, delimiter = '.') => { if (parts.length === 0) { return; } const [current, ...rest] = parts; // Find the current node in the existing tree let node = nodeList.find((n) => n[valueKey] === current); if (!node) { // If the node doesn't exist, create it node = Object.assign(Object.assign({}, rootobjectReference), { [valueKey]: current, [childrenKey]: [] }); nodeList.push(node); } const children = node[childrenKey]; // Recurse for the rest of the parts addPathToTreeRecursively(rest, rootobjectReference, children, childrenKey, valueKey, delimiter); }; const addSpacesToCamelCase = (input) => { return input.replace(/([A-Z])/g, ' $1').trim(); }; exports.addSpacesToCamelCase = addSpacesToCamelCase; const isEndpointConfig = (value) => { return (typeof value === 'object' && typeof value.uri === 'string' && ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'].includes(value.verb) && (value.pathParams === undefined || (Array.isArray(value.pathParams) && value.pathParams.every((param) => typeof param.key === 'string' && Object.prototype.hasOwnProperty.call(param, 'value')))) && (value.queryParams === undefined || (Array.isArray(value.queryParams) && value.queryParams.every((param) => typeof param.key === 'string' && Object.prototype.hasOwnProperty.call(param, 'value')))) && (value.body === undefined || typeof value.body === 'object' || typeof value.body === 'string' || value.body === null)); }; exports.isEndpointConfig = isEndpointConfig; const trimObjectValues = (obj, seen = new WeakSet()) => { if (typeof obj !== 'object' || obj === null) { return obj; } if (seen.has(obj)) { return obj; } seen.add(obj); const result = Array.isArray(obj) ? [] : {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { const value = obj[key]; if (typeof value === 'string') { result[key] = value.trim(); } else if (typeof value === 'object' && value !== null) { result[key] = (0, exports.trimObjectValues)(value, seen); } else { result[key] = value; } } } return result; }; exports.trimObjectValues = trimObjectValues; /** * * @param date * @returns */ const hasValidDateFn = (date) => { return date !== '0001-01-01T00:00:00'; }; exports.hasValidDateFn = hasValidDateFn; //# sourceMappingURL=utils.js.map