@slck/utils
Version:
utils library - Utility functions for common development.
421 lines • 14.5 kB
JavaScript
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
;