UNPKG

js-awe

Version:

Awesome js utils including - plan: An Asynchronous control flow with a functional taste - Chrono: record and visualize timelines in the console

1,209 lines (1,208 loc) 76.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _EnumMap_instances, _EnumMap_validateAndTransform; Object.defineProperty(exports, "__esModule", { value: true }); exports.fillWith = exports.memoize = exports.pushAt = exports.pushUniqueKeyOrChange = exports.pushUniqueKey = exports.transition = exports.Enum = exports.EnumMap = exports.copyPropsWithValueUsingRules = exports.copyPropsWithValue = exports.project = exports.traverseVertically = exports.traverse = exports.removeDuplicates = exports.arrayOfObjectsToObject = exports.arrayToObject = exports.notTo = exports.sleepWithFunction = exports.sleepWithValue = exports.sleep = exports.isPromise = exports.arraySorter = exports.filterFlatMap = exports.defaultValue = exports.findIndexOrNextInSortedArray = exports.findIndexOrPreviousInSortedArray = exports.findIndexInSortedArray = exports.sorterByFields = exports.sorterByPaths = exports.stripDollarRoot = exports.pathReplacingArrayIndexWithAsterisk = exports.setAt = exports.getAt = exports.deepFreeze = exports.findDeepKey = exports.colorByStatus = exports.colorMessageByStatus = exports.colorMessage = exports.colors = exports.indexOfNthMatch = exports.urlDecompose = exports.urlCompose = exports.isBasicType = exports.createCustomErrorClass = exports.CustomError = exports.summarizeError = exports.queryObjToStr = exports.varSubsDoubleBracket = exports.firstCapital = exports.logWithPrefix = void 0; exports.processExit = exports.retryWithSleep = exports.loopIndexGenerator = exports.oneIn = exports.repeat = exports.cleanString = exports.replaceAll = exports.setDateToMidnight = exports.isDateMidnight = exports.getSameDateOrPreviousFridayForWeekends = exports.dayOfWeek = exports.nextDayOfWeek = exports.previousDayOfWeek = exports.addDays = exports.subtractDays = exports.diffInDaysYYYY_MM_DD = exports.dateToObj = exports.YYYY_MM_DD_hh_mm_ss_ToUtcDate = exports.dateFormatter = exports.MONTHS = exports.DAYS = exports.formatDate = exports.isStringADate = exports.isALeaf = exports.isEmpty = exports.isDate = exports.numberToFixedString = void 0; const just_clone_1 = __importDefault(require("just-clone")); const jsonpath_plus_1 = require("jsonpath-plus"); // biome-ignore lint/style/useNodejsImportProtocol: <explanation> const path_1 = require("path"); const logWithPrefix = (title, displayFunc) => (message) => { let finalMessage = message; if (typeof displayFunc === 'function') { finalMessage = displayFunc(message); } console.log(`${title}: ${finalMessage}`); return message; }; exports.logWithPrefix = logWithPrefix; let processCwd; function transformStackTraceLine(line) { const processCwd = process.cwd(); let starPathPos = line.indexOf('(file://', ''); if (starPathPos === -1) starPathPos = line.indexOf('file://', ''); if (starPathPos === -1) starPathPos = line.indexOf('(', ''); if (starPathPos === -1) return line; const cleanLine = line .replace('(file://', '') .replace('file://', '') .replace('(', '') .replace(')', ''); const resultPositionMatch = cleanLine.match(/[0-9]+:[0-9]+/); if (resultPositionMatch === null) return line; const position = resultPositionMatch[0]; const filePath = cleanLine.substring(starPathPos, resultPositionMatch.index - 1); const relativePath = (0, path_1.relative)(processCwd, filePath); return `${line.substring(0, starPathPos - 1)} ${relativePath}:${position}`; } function summarizeError(error, maxStackTraces = 5) { var _a; if (error instanceof Error === false) return 'Not an error object'; const stackTraceLines = error.stack.split('\n'); const filteredStackTrace = stackTraceLines .filter(line => !line.includes('node_modules') && !line.includes('node:internal')) .map(line => line.trim()) .filter(line => line.startsWith('at')) .map(transformStackTraceLine); const condensedStackTrace = []; const totalTraces = filteredStackTrace.length; if (totalTraces > maxStackTraces) { condensedStackTrace.push(...filteredStackTrace.slice(0, maxStackTraces - 1)); condensedStackTrace.push('...skipped...'); condensedStackTrace.push(filteredStackTrace[totalTraces - 1]); } else { condensedStackTrace.push(...filteredStackTrace); } const condensedStackTraceString = condensedStackTrace.join(' -> '); const ErrorString = `${error.name}: ${error.message} ${((_a = error.cause) === null || _a === void 0 ? void 0 : _a.message) ? `[cause]: ${error.cause.message}` : ''}`; return `${ErrorString}\nStack Trace: ${condensedStackTraceString}`; } exports.summarizeError = summarizeError; // function a(){b()} // function b(){c()} // function c(){d()} // function d(){e()} // function e(){f()} // function f(){g()} // function g(){throw new Error('This is an error')} // try{ // a() // }catch(e) // { // console.log(e) // console.log(summarizeError(e)) // } class CustomError extends Error { constructor(name = 'GENERIC', message = name, data = { status: 500 }) { super(message); super.name = name; if (Error.captureStackTrace) { Error.captureStackTrace(this, CustomError); } this.data = data; } map(func) { return this; } chain(func) { return this; } summarizeError(error) { return summarizeError(error); } } exports.CustomError = CustomError; CustomError.of = CustomError; // try { // throw new CustomError('aa','bb',{a:1,b:2}) // }catch(e) // { // console.log(`name: ${e.name}, message: ${e.message}, data: ${JSON.stringify(e.data)}, stack: ${e.stack}`) // } // // mapping a function to CustomError should return the CustomError without exeecuting the function // import { pipeWithChain, R } from './ramdaExt.js' // let divide = (dividend, divisor) => // divisor !== 0 // ? dividend/divisor // : new CustomError('ZERO_DIVISION_EXC','Division by zero',{dividend,divisor}) // R.map(a => { // console.log(`It shouldn't print this`) // return a +2 // })(divide(8,0)) //? function createCustomErrorClass(errorName) { const errorClass = class extends CustomError { constructor(name, message, data) { super(name, message, data); this.name = errorName; } }; return errorClass; } exports.createCustomErrorClass = createCustomErrorClass; function isBasicType(variableToCheck) { const type = typeof variableToCheck; return (type !== 'object' && type !== 'undefined' && type !== 'function'); } exports.isBasicType = isBasicType; // isBasicType(null) //? // isBasicType(undefined) //? // isBasicType(new Map()) //? // isBasicType({}) //? // isBasicType(Symbol()) //? // isBasicType('22') //? // isBasicType(Number(2)) //? class Enum { constructor(values, rules) { // It will contain the active key for example 'OFF'. Once initialized activeObjectKey[activeKey] should be always equal to true let activeKey; let stateRules; if (Array.isArray(values) === false) throw new CustomError('NOT_AN_ARRAY', 'Only Array composed of non objects are permitted'); if (values.filter((elem) => elem === 'object').length > 0) throw new CustomError('ARRAY_VALUES_MUST_BE_OF_BASIC_TYPE', 'Only basic types are allowed'); const valuesNotAllowed = values.filter(elem => elem === 'get' || elem === 'set' || elem === 'getValue'); if (valuesNotAllowed.length > 0) { throw new CustomError('ENUM_INVALID_ENUM_VALUE', `The following ENUM value/s are not allowed: ${valuesNotAllowed} as they are reserved words for enum`); } const valuesWithoutDuplicates = removeDuplicates(values); // activeObjectKey will be an object with keys from values array and only one current key active: {ON:false,OFF:true} const activeObjectKey = arrayToObject(valuesWithoutDuplicates, function defaultValue() { return false; }); activeKey = values[0]; activeObjectKey[activeKey] = true; if (rules !== undefined) setupRules(rules); this.get = get; this.set = set; this.getValue = getValue; // biome-ignore lint/correctness/noConstructorReturn: <explanation> return new Proxy(activeObjectKey, this); /// function setupRules(rules) { if (rules === null || typeof rules !== 'object' || Array.isArray(rules) === true) { throw new CustomError('ENUM_RULES_BAD_FORMAT', `rules is not an object: ${rules}`); } for (const elem in rules) { if (activeObjectKey[elem] === undefined || Array.isArray(rules[elem]) === false) { throw new CustomError('ENUM_RULES_BAD_FORMAT', `Each attribute of rules must be an element in the ENUM and its value should be an array: ${activeObjectKey[elem]}${rules[elem]}`); } const valuesWithProblems = rules[elem].filter(itemTo => activeObjectKey[itemTo] === undefined); if (valuesWithProblems.length > 0) { throw new CustomError('ENUM_RULES_BAD_FORMAT', `All elements in a rule entry must be one of the list values in the ENUM. The following values dont exist: ${valuesWithProblems}`); } } stateRules = (0, just_clone_1.default)(rules); } function get(_target, prop) { if (prop === 'getValue') { return getValue; } if (activeObjectKey[prop] == null) throw new CustomError('ENUM_INVALID_PROPERTY', `.${prop} is none of the possible values ${this}`); return activeObjectKey[prop]; } function set(_undefined, prop, value) { if (value !== true) { throw new CustomError('ENUM_ACTIVATION_NO_TRUE', `Tryng to set ${prop} with ${value} but activation only admits true`); } if (activeObjectKey[prop] === undefined) { throw new CustomError('ENUM_INVALID_PROPERTY', `.${prop} is none of the possible values ${this}`); } if (validateChange(activeKey, prop)) { activeObjectKey[activeKey] = false; activeObjectKey[prop] = true; activeKey = prop; } else throw new CustomError('ENUM_TRANSITION_NOT_ALLOWED', `.From: ${activeKey} --> To: ${prop}`); return true; } function validateChange(activeElement, prop) { if (stateRules === undefined) return true; return stateRules[activeElement] !== undefined && stateRules[activeElement].indexOf(prop) !== -1; } function getValue() { return activeKey; } } } exports.Enum = Enum; // const ENGINE = new Enum( // ['UNDEFINED', 'START', 'SPEED', 'BREAK', 'STOP','ABANDONED'], // { // 'UNDEFINED':['START'], // 'START':['SPEED', 'BREAK', 'STOP'], // 'SPEED':['BREAK', 'STOP'], // } // ) // ENGINE.START = true // ENGINE.START //? // ENGINE.SPEED = true // ENGINE.SPEED // try { // ENGINE.SPEED = true // }catch(e) // { // e //? ENUM_TRANSITION_NOT_ALLOWED It is not defined to go to itself. // } // try { // const result = new Enum( // ['UNDEFINED', 'START', 'SPEED', 'BREAK', 'STOP','ABANDONED'], // { // 'UNDEFINED':['START'], // 'START':['SPEED', 'BREAK', 'STOP'], // 'SPEEDRT':['BREAK', 'STOP'], // } // ) // } catch (e) { // e //? ENUM_RULES_BAD_FORMAT SPEEDRT is not valid // } class EnumMap { constructor(values) { _EnumMap_instances.add(this); const objLiteral = __classPrivateFieldGet(this, _EnumMap_instances, "m", _EnumMap_validateAndTransform).call(this, (0, just_clone_1.default)(values)); // biome-ignore lint/correctness/noConstructorReturn: <explanation> return new Proxy(objLiteral, this); } get(target, prop) { if (target[prop] == null && this[prop] == null) throw new CustomError('ENUM_OUT_OF_RANGE', `.${prop} is none of the possible values ${this}`); if (this[prop] != null) return this[prop]; return target[prop]; } set(_undefined, prop) { throw new CustomError('ENUM_NOT_MODIFIABLE', `Object of .${prop} is not modifiable`); } invert() { const invertedValues = {}; for (const elem in this) { // biome-ignore lint/suspicious/noPrototypeBuiltins: <explanation> if (this.hasOwnProperty(elem)) { if (isBasicType(this[elem]) === false) throw new CustomError('INVERT_VALUES_NOT_BASIC_TYPE', 'EnumMap values should be basic types'); invertedValues[this[elem]] = elem; } } return new EnumMap((0, just_clone_1.default)(invertedValues)); } } exports.EnumMap = EnumMap; _EnumMap_instances = new WeakSet(), _EnumMap_validateAndTransform = function _EnumMap_validateAndTransform(values) { if (values === undefined || values === null) throw new Error('Null or undefined is not permitted to construct a EnumMap instance.'); const valuesProtoName = Object.getPrototypeOf(values).constructor.name; if (valuesProtoName === 'Map') { return Object.fromEntries(values); } if (valuesProtoName === 'Object') { return values; } let typeOfValue; const objectResult = []; if (valuesProtoName === 'Array') { for (let i = 0; i < values.length; i++) { // basicTypes: ['SUNDAY', 'MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY','SATURDAY'] if (isBasicType(values[i])) { objectResult[values[i]] = i; if (typeOfValue !== undefined && typeOfValue !== 'basicType') throw new CustomError('ENUMMAP_VALUES_NOT_VALID', 'EnumMap values should be consistent...'); typeOfValue = 'basicType'; } // elements are [key, value]: [['SUNDAY',1],['MONDAY',5], ['TUESDAY',2],['WEDNESDAY',3],['THURSDAY',9],['FRIDAY',6],['SATURDAY',4]] if (Array.isArray(values[i]) && values[i].length === 2) { objectResult[values[i][0]] = values[i][1]; if (typeOfValue !== undefined && typeOfValue !== 'array') throw new CustomError('ENUMMAP_VALUES_NOT_VALID', 'EnumMap values should be consistent...'); typeOfValue = 'array'; } // elements are object with {key:value} [{SUNDAY:1},{MONDAY:5}, {TUESDAY:2},{WEDNESDAY:3},{THURSDAY:9},{FRIDAY:6},{SATURDAY:4}] if (values[i] !== null && typeof values[i] === 'object' && Object.keys(values[i]).length === 1) { const key = Object.keys(values[i])[0]; objectResult[key] = values[i][key]; if (typeOfValue !== undefined && typeOfValue !== 'object') throw new CustomError('ENUMMAP_VALUES_NOT_VALID', 'EnumMap values should be consistent...'); typeOfValue = 'object'; } } if (typeOfValue === undefined) { throw new CustomError('ENUM_VALUES_NOT_VALID', 'Values must be an array of strings, an array of arrays, an array of objects or an array of maps'); } } return objectResult; }; // { // const SWITCHER = new EnumMap({ON:0,OFF:1}) // SWITCHER.ON //? 0 // SWITCHER.OFF //? 1 // try { SWITCHER.ONFF // }catch(e){ // e // ENUM_OUT_OF_RANGE // } // const INVERT_SWITCHER = SWITCHER.invert() // INVERT_SWITCHER['0'] //? // const value = SWITCHER.ON // value === 0 //? true // } function transition(states, events, transitions) { states.forEach(validateStateFormat); events.forEach(validateEventFormat); let state = states[0]; const finalTransitions = Object.entries(transitions).reduce((acum, [stateKey, stateValue]) => { // validations validateState(stateKey); let newStateValue = stateValue; if (typeof stateValue === 'string') { validateState(stateValue); newStateValue = events.reduce((acum, current) => { acum[current] = stateValue; return acum; }, {}); } else { for (const [key, value] of Object.entries(newStateValue)) { validateEvent(key); validateState(value); } } acum[stateKey] = Object.assign(Object.assign({}, acum[stateKey]), newStateValue); return acum; }, states.reduce((acum, current) => { acum[current] = events.reduce((acum2, el2) => { acum2[el2] = el2.toUpperCase(); return acum2; }, {}); return acum; }, {})); function sendEvent(event) { validateEvent(event); state = finalTransitions[state][event]; return state; } sendEvent.valueOf = () => state; return sendEvent; function validateStateFormat(state) { if (state !== state.toUpperCase()) throw new CustomError('STATE_MUST_BE_UPPERCASE', `The state: ${state} does not have all characters in uppercase`); } function validateState(state) { if (states.some(el => el === state) === false) throw new CustomError('STATE_NOT_FOUND', `The state: ${state} was not found in the list of states supplied: ${states}`); } function validateEventFormat(event) { if (event !== event.toLowerCase()) throw new CustomError('EVENT_MUST_BE_LOWERCASE', `The event: ${event} does not have all characters in lowercase`); } function validateEvent(event) { if (events.some(el => el === event) === false) throw new CustomError('EVENT_NOT_FOUND', `The event: ${event} was not found in the list of events supplied: ${events}`); } } exports.transition = transition; // const tranDef = [ // ['SYNC', 'PROMISE', 'FUTURE', 'PROMISE_AND_FUTURE'], // ['sync','promise','future'], // // STATE:{event:NEW_STATE} // // if a event is not defined within a STATE then the default value is selected STATE:{missing_event: NEW_STATE(missing_event.toUpperCase())} // { // PROMISE:{ // sync:'PROMISE', // future: 'PROMISE_AND_FUTURE' // //by default: promise: 'PROMISE' // }, // FUTURE:{ // sync:'FUTURE', // promise: 'PROMISE_AND_FUTURE', // }, // PROMISE_AND_FUTURE: 'PROMISE_AND_FUTURE' // same as {sync: 'PROMISE_AND_FUTURE', promise: 'PROMISE_AND_FUTURE', future: 'PROMISE_AND_FUTURE'} // } // ] // const typeOfList = transition(...tranDef) // typeOfList('future') //? // typeOfList('future') //? // typeOfList('promise') //? // typeOfList('sync') //? // try{ // typeOfList('sync2') //? // }catch(e) {console.log(e)} // typeOfList('sync') //? // typeOfList.valueOf() //? function arrayToObject(arr, defaultValueFunction) { return arr.reduce((acum, current, index) => { acum[current] = defaultValueFunction(current, index); return acum; }, {}); } exports.arrayToObject = arrayToObject; function arrayOfObjectsToObject(iterable) { if (typeof (iterable === null || iterable === void 0 ? void 0 : iterable[Symbol.iterator]) === 'function') { const acum = {}; for (const elem of iterable) { for (const key in elem) { acum[key] = elem[key]; } } return acum; } return arr.reduce((acum, current, index) => { for (const key in current) { acum[key] = current[key]; } return acum; }, {}); } exports.arrayOfObjectsToObject = arrayOfObjectsToObject; function removeDuplicates(arr) { return [...new Set(arr)]; } exports.removeDuplicates = removeDuplicates; function reviverPromiseForCloneDeep(value) { if (jsUtils.isPromise(value)) return value; } // reviver is called for each node as: reviver(nodeRef, currentPath, parent, key). // For example: being objIni={a:{b:{c:3}},d:4} the reviver to call node a.b will be // reviver({c:3}, ['a','b'], {b:{c:3}}, 'b') currentPath=['$', 'parent', 'son', '0', 'jose'] // reviver return value will impact traverse: // undefined: do nothing. // Any value: assign this value (parent[key]) // traverse.stop: stop inmediatly traverse // traverse.skip: skip node. It doesnt look at children of node. // prune: if true remove node. function traverse(objIni, reviver, pureFunction = true) { const currentPath = ['$']; const objClone = pureFunction ? (0, just_clone_1.default)(objIni, reviverPromiseForCloneDeep) : objIni; let exitVar = false; const objForReviver = {}; // biome-ignore lint/complexity/useLiteralKeys: <explanation> objForReviver['$'] = objClone; const isSkipNodeOnce = reviverProcess(reviver, objForReviver, '$', currentPath); // biome-ignore lint/complexity/useLiteralKeys: <explanation> if (objClone !== objForReviver['$']) return objForReviver['$']; // biome-ignore lint/complexity/useLiteralKeys: <explanation> if (exitVar === true) return objForReviver['$']; if (isSkipNodeOnce === false) { // biome-ignore lint/complexity/useLiteralKeys: <explanation> traverseRec(objForReviver['$']); } // biome-ignore lint/complexity/useLiteralKeys: <explanation> return objForReviver['$']; function traverseRec(obj) { if (obj && obj instanceof Object && exitVar === false) { for (const prop in obj) { // biome-ignore lint/suspicious/noPrototypeBuiltins: <explanation> if (obj.hasOwnProperty(prop)) { currentPath.push(prop); const isSkipNodeOnce = reviverProcess(reviver, obj, prop, currentPath); if (exitVar === true) return; if (isSkipNodeOnce === false) { traverseRec(obj[prop]); } currentPath.pop(); } } } } function reviverProcess(reviver, obj, prop, currentPath) { let isSkipNodeOnce = false; if (reviver) { const resultReviver = reviver(obj[prop], currentPath, obj, prop); if (resultReviver !== undefined && resultReviver !== traverse.stop && resultReviver !== traverse.skip && resultReviver !== traverse.delete) { obj[prop] = resultReviver; // to avoid infinite loops of reviver. reviver example: changing a string for an object having a string. // (node)=>{if(typeof node === 'string') return {name:node}} isSkipNodeOnce = true; } if (resultReviver === traverse.stop) { exitVar = true; } if (resultReviver === traverse.skip) { isSkipNodeOnce = true; } if (resultReviver === traverse.delete) { obj[prop] = undefined; isSkipNodeOnce = true; } } return isSkipNodeOnce; } } exports.traverse = traverse; traverse.skip = Symbol(); traverse.stop = Symbol(); traverse.delete = Symbol(); traverse.matchPath = (pathStringQuery, reviverPath) => { const pathStringArr = pathStringQuery.split('.'); if (pathStringArr.length !== reviverPath.length) { return false; } return pathStringArr.every((el, index) => el === '*' || el === reviverPath[index]); }; function traverseVertically(functionToRun, verFields, toTraverse) { var _a, _b, _c, _d; if (Array.isArray(toTraverse) === false) return; let runIndex = 0; let maxLength = 0; let firstTime = true; for (let i = 0; firstTime || i < maxLength; i++) { const toReturn = []; for (let j = 0; j < toTraverse.length; j++) { toReturn[j] = Object.assign({}, toTraverse[j]); for (const field of verFields) { if (firstTime) { maxLength = ((_b = (_a = toTraverse[j]) === null || _a === void 0 ? void 0 : _a[field]) === null || _b === void 0 ? void 0 : _b.length) > maxLength ? toTraverse[j][field].length : maxLength; } toReturn[j][field] = (_d = (_c = toTraverse[j]) === null || _c === void 0 ? void 0 : _c[field]) === null || _d === void 0 ? void 0 : _d[i]; } } if (maxLength !== 0) { functionToRun(toReturn, runIndex); runIndex++; } firstTime = false; } } exports.traverseVertically = traverseVertically; function project(paths, json, removeWithDelete = true) { const toDelete = Symbol(); let copy; if (json === null || json === undefined) return json; if (Array.isArray(json)) copy = []; else if (Object.getPrototypeOf(json) === Object.prototype) copy = {}; else if (Array.isArray(paths) === false) throw new Error('paths must be an array'); else if (paths.filter(el => el === '+$').length - paths.filter(el => el === '-$').length > 0) return json; else return undefined; for (const pathWithSign of paths) { if (pathWithSign[0] !== '+' && pathWithSign[0] !== '-') { throw new Error('ivanlid format'); } const isInclude = pathWithSign[0] === '+'; const path = pathWithSign.substring(1); const result = (0, jsonpath_plus_1.JSONPath)({ resultType: 'all', path, json }); const pendingToFilter = new Map(); for (const { pointer, value } of result) { const setAtPath = pointer.substring(1).split('/'); if (setAtPath.length === 1 && setAtPath[0] === '') copy = isInclude ? (0, just_clone_1.default)(value) : undefined; else { if (removeWithDelete === true && isInclude === false) { const parentPath = setAtPath.slice(0, -1); const parent = getAt(copy, parentPath); if (Array.isArray(parent) === true) { // Arrays are stored in a map to be reviewed later to filter out the items mark for deletion. pendingToFilter.set(parentPath.join('/'), parent); // mark element for deletion setAt(copy, setAtPath, toDelete); } else { const fieldToDelete = setAtPath[setAtPath.length - 1]; delete parent[fieldToDelete]; setAt(copy, parentPath, parent); } } else setAt(copy, setAtPath, isInclude ? (0, just_clone_1.default)(value) : undefined); } } for (const [parentPath, parent] of pendingToFilter) { const compactingDeleteItems = parent.filter(el => el !== toDelete); setAt(copy, parentPath.split('/'), compactingDeleteItems); } } return copy; } exports.project = project; // { // const users = [ // { // name: 'Jose', // age: 47, // salary: 52000, // posts: [ // { id: 1, message: 'test', likes: 2 }, // { id: 2, message: 'test1', likes: 2 }, // { id: 3, message: 'test2', likes: 2 }, // ], // }, // { // name: 'Luchi', // age: 49, // salary: 52000, // twoLevels: {a:3}, // posts: [ // { id: 1, message: 'testL', likes: 2 }, // { id: 2, message: 'testL1', likes: 2 }, // { id: 3, message: 'testL2', likes: 2 }, // ], // }, // ] // const pathToSelect = ['+$', '-$[*].age', '-$[*].twoLevels.a', '-$[*].posts[:-1]'] //, '-$[*].age']; // console.log( // JSON.stringify(project(pathToSelect, users),undefined,2), // JSON.stringify(project(['+$[*].posts[0,2]', '-$[*].posts[1]'], users),undefined, 2), // JSON.stringify(project(['+$.a.b','-$.a.b.d'], {a:{b:{c:3,d:5,e:9}}}),undefined,2), // JSON.stringify(project(['+$'], 2),undefined,2) // ) // } function copyPropsWithValueUsingRules(objDest, copyRules, shouldUpdateOnlyEmptyFields = false) { return (inputObj) => { copyRules.map((rule) => { let from; let to; if (typeof rule === 'object') { from = rule.from; to = rule.to; } else { from = rule; to = rule; } let valueToCopy = getAt(inputObj, from); if (typeof rule.transform === 'function') { valueToCopy = rule.transform(valueToCopy); } if (valueToCopy === undefined || valueToCopy === null) return; if (shouldUpdateOnlyEmptyFields === true && isEmpty(getAt(objDest, to))) setAt(objDest, to, valueToCopy); if (shouldUpdateOnlyEmptyFields === false) setAt(objDest, to, valueToCopy); }); return objDest; }; } exports.copyPropsWithValueUsingRules = copyPropsWithValueUsingRules; // { // let objTo = {a:{b:2},c:3} // let objFrom = {a:{b:4},c:8,d:{e:{f:12}},l:5} // copyPropsWithValueUsingRules(objTo, [{from:'a.b', to:'c'}, {from:'d.e.f', to:'d'}])(objFrom) // objTo // } // { // let objTo = {a:{b:2},c:3} // let objFrom = {a:{b:4},c:8,d:{e:{f:12}}, l:5} // copyPropsWithValueUsingRules(objTo, // [ // {from:'a.b', to:'c'}, // {from:'d.e.f', to:'d.f'}, // {from:'d.e.g', to:'d.g'} // ], // true // )(objFrom) // objTo // } // { // let objTo = {a:{b:2},c:12} // let objFrom = {a:{b:4},g:"2228",d:{e:{f:12}}, l:5} // copyPropsWithValueUsingRules(objTo, // [ // {from:'g', to:'e', transform: parseInt}, // {from:'d.e.f', to:'d.f'}, // {from:'d.e.g', to:'d.g'} // ], // true // )(objFrom) // objTo // } function copyPropsWithValue(objDest, shouldUpdateOnlyEmptyFields = false) { return (inputObj) => { traverse(inputObj, (nodeValue, currentPath) => { if (isALeaf(nodeValue) === false) return; if (nodeValue === undefined || nodeValue === null || currentPath.length === 1) return; const destPath = currentPath.slice(1 - currentPath.length); if (shouldUpdateOnlyEmptyFields === true) { const valueAtDest = getAt(objDest, destPath); if (isEmpty(valueAtDest)) setAt(objDest, destPath, nodeValue); return; } setAt(objDest, destPath, nodeValue); //? }); return objDest; }; } exports.copyPropsWithValue = copyPropsWithValue; // { // let objTo = { a: { b: 2 }, c: 3, h: { i: 3 } } // let objFrom = { a: { b: 4 }, c: undefined, d: { e: { f: 12 } } } // copyPropsWithValue(objTo)(objFrom) //? // objTo // } // { // let objTo = { a: { b: 2 }, c: 3, h: { i: 3 } } // let objFrom = { a: { b: 4 }, c: '', d: { e: { f: 12 } } } // copyPropsWithValue(objTo, undefined, true)(objFrom) //? // objTo // } function isALeaf(node) { const isABranch = ((node === null || node === void 0 ? void 0 : node.constructor.name) === 'Object' && Object.keys(node).length > 0) || ((node === null || node === void 0 ? void 0 : node.constructor.name) === 'Array' && node.length > 0); return !isABranch; } exports.isALeaf = isALeaf; // isALeaf(undefined) //? // isALeaf({a:'this is a leaf'}.a) //? // isALeaf(new Date()) //? // isALeaf([]) //? // isALeaf({}) //? // isALeaf({a:3}) //? // isALeaf([undefined]) //? function isEmpty(value) { if (value === undefined || value === null || value === '' || value === 0 || value === 0n || Number.isNaN(value) || (Array.isArray(value) && (value === null || value === void 0 ? void 0 : value.length) === 0) || (typeof value === 'object' && Object.keys(value).length === 0)) return true; return false; } exports.isEmpty = isEmpty; //isEmpty(0) //? function firstCapital(str) { return typeof str === 'string' ? str[0].toUpperCase() + str.substring(1).toLowerCase() : str; } exports.firstCapital = firstCapital; function queryObjToStr(query) { return Object.keys(query).reduce((acum, current) => { const newAcum = acum ? `${acum}&` : acum; return `${newAcum}${current}=${query[current]}`; }, ''); } exports.queryObjToStr = queryObjToStr; function varSubsDoubleBracket(strToResolveVars, state, mode) { if (typeof strToResolveVars !== 'string') { return strToResolveVars; } // regex to deal with the case the entire value is a substitution group // let regexVar = /"{{(.*?)(?:=(.*?))?}}"/g // ask ChatGPT to do a more performant regex without look ahead const regexVar = /"{{([^=}]+)(?:=([^}]+))?}}"/g; const resultStr = strToResolveVars.replace(regexVar, (_notused, group1, group2) => { if (state && state[group1] !== undefined) { if (typeof state[group1] === 'string') return `"${state[group1]}"`; if (typeof state[group1] === 'object') { if (mode === 'url' && Array.isArray(state[group1])) return arrayToListQuery(state[group1]); if (mode === 'url' && !Array.isArray(state[group1])) return objToQueryParams(state[group1]); if (!mode) return JSON.stringify(state[group1]); } return state[group1]; } if (group2 === undefined) return null; //else if(group2.substring(0,2) === '\\"' && group2.substring([group2.length -1],2) === '\\"') return ('"' + group2 + '"') return group2.replace(/\\"/g, '"'); }); // regex to do partial substitution of a group inside of a string value // let regexVarPartial = /{{(.*?)(?:=(.*?))?}}/g // ask ChatGPT to do a more performant regex without look ahead const regexVarPartial = /{{([^=}]+)(?:=([^}]+))?}}/g; const resultStrFinal = resultStr.replace(regexVarPartial, (_notused, group1, group2) => { if (state && state[group1] !== undefined) { if (typeof state[group1] === 'object') { if (mode === 'url' && Array.isArray(state[group1])) return arrayToListQuery(state[group1]); if (mode === 'url' && !Array.isArray(state[group1])) return objToQueryParams(state[group1]); if (!mode) return JSON.stringify(state[group1]); } else return state[group1]; } else { if (group2 === undefined) return null; return group2.replace(/\\"/g, ''); } }); return resultStrFinal; } exports.varSubsDoubleBracket = varSubsDoubleBracket; // varSubsDoubleBracket(` // { // "response": { // "id": 1231, // "description": "{{description=\"This is a test\"}}", // "slot": "{{slotNumber}}", // "active": "{{active=true}}", // "ratenumber": "{{rate=10}}" // } // }`, {slotNumber:{a:3}, active:false}) //? // varSubsDoubleBracket('https://bank.account?accounts={{accounts}}&c=3', {accounts:['10232-1232','2331-1233']},'url') //? // varSubsDoubleBracket('https://bank.account?{{params=a=1&b=2}}&c=3', {params:{a:'10232-1232',b:'2331-1233'}},'url') //? // varSubsDoubleBracket('https://bank.account?{{params=a=1&b=2}}&c=3', {},'url') //? function arrayToListQuery(arr) { return arr.reduce((prev, curr) => `${prev},${curr}`); } function objToQueryParams(obj) { return Object.keys(obj) .reduce((acum, curr) => `${acum}${curr}=${obj[curr]}&`, '') .slice(0, -1); } function urlCompose(gatewayUrl, serviceName, servicePath) { return { gatewayUrl, serviceName, servicePath, url: `${gatewayUrl}${serviceName}${servicePath}` }; } exports.urlCompose = urlCompose; function urlDecompose(url, listOfServiceNames) { return listOfServiceNames .filter(elem => url.split(elem).length >= 2) .map(elem => { const [part1, ...restParts] = url.split(elem); return { gatewayUrl: part1, serviceName: elem, servicePath: restParts.join(elem) }; }); } exports.urlDecompose = urlDecompose; function indexOfNthMatch(stringToInspect, toMatch, nth) { if (nth > 0 === false) return -1; let index = -1; for (let i = 0; i < nth; i++) { index = stringToInspect.indexOf(toMatch, index + 1); } return index; } exports.indexOfNthMatch = indexOfNthMatch; // indexOfNthMatch('', '£', 0) //? // indexOfNthMatch('£', '£', 3.12) //? // indexOfNthMatch('£', '£', 1) //? // indexOfNthMatch('It will not find', 'loop', 0) //? // indexOfNthMatch('It will not find', 'loop', 1) //? // indexOfNthMatch('a.b.c.d.e.f', '£', 3) //? // indexOfNthMatch('a.b.c.d.e.f', '.', 3) //? // indexOfNthMatch('a.b.c.d.e.f', '.', 2) //? // indexOfNthMatch('a.b.c.d.e.f', '.', 1) //? function toDate(date) { return date ? date instanceof Date ? date : new Date(date) : new Date(); } function isDate(d) { return d instanceof Date && !Number.isNaN(d); } exports.isDate = isDate; function isStringADate(stringDate) { if (typeof stringDate !== 'string') return false; return isDate(new Date(stringDate)); } exports.isStringADate = isStringADate; function dateFormatter(format) { return (date) => formatDate(format, date); } exports.dateFormatter = dateFormatter; function formatDate(format, date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return undefined; const months = new EnumMap({ 'January': '01', 'February': '02', 'March': '03', 'April': '04', 'May': '05', 'June': '06', 'July': '07', 'August': '08', 'September': '09', 'October': '10', 'November': '11', 'December': '12' }); const indexMonths = months.invert(); const days = new EnumMap({ 'Sunday': '0', 'Monday': '1', 'Tuesday': '2', 'Wednesday': '3', 'Thursday': '4', 'Friday': '5', 'Saturday': '6' }); const indexDays = days.invert(); const dateIsoString = dateToProcess.toISOString(); const YYYY = dateIsoString.substring(0, 4); const YY = dateIsoString.substring(2, 4); const MM = dateIsoString.substring(5, 7); const DD = dateIsoString.substring(8, 10); const D = Number.parseInt(DD, 10).toString(); const hh = dateIsoString.substring(11, 13); const h = Number.parseInt(hh, 10).toString(); const mm = dateIsoString.substring(14, 16); const ss = dateIsoString.substring(17, 19); const mil = dateIsoString.substring(20, 23); const mi = dateIsoString.substring(20, 22); const month = indexMonths[MM]; const dayOfWeek = indexDays[dateToProcess.getUTCDay()]; return format .replace(/\$YYYY/g, YYYY) .replace(/\$YY/g, YY) .replace(/\$MM/g, MM) .replace(/\$DD/g, DD) .replace(/\$D/g, D) .replace(/\$hh/g, hh) .replace(/\$h/g, h) .replace(/\$mm/g, mm) .replace(/\$ss/g, ss) .replace(/\$mil/g, mil) .replace(/\$mi/g, mi) .replace(/\$month/g, month) .replace(/\$dayOfWeek/g, dayOfWeek); } exports.formatDate = formatDate; //formatDate('$YYYY-$MM-$DD', new Date('2021-02-28')) //? function YYYY_MM_DD_hh_mm_ss_ToUtcDate(dateYYYY_MM_DD_hh_mm_ss) { // Input format has 1 char (any could work) between each elements: years, months, days, hours, minutes and seconds const dateYYYY = Number.parseInt(dateYYYY_MM_DD_hh_mm_ss.substring(0, 4)); const dateMM = Number.parseInt(dateYYYY_MM_DD_hh_mm_ss.substring(5, 7)) - 1; // Months start with 0 const dateDD = Number.parseInt(dateYYYY_MM_DD_hh_mm_ss.substring(8, 10)); const datehh = Number.parseInt(dateYYYY_MM_DD_hh_mm_ss.substring(11, 13)); const datemm = Number.parseInt(dateYYYY_MM_DD_hh_mm_ss.substring(14, 16)); const datess = Number.parseInt(dateYYYY_MM_DD_hh_mm_ss.substring(17, 19)); return Date.UTC(dateYYYY, dateMM, dateDD, datehh, datemm, datess); } exports.YYYY_MM_DD_hh_mm_ss_ToUtcDate = YYYY_MM_DD_hh_mm_ss_ToUtcDate; const DAYS = new EnumMap(['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY']); exports.DAYS = DAYS; const MONTHS = new EnumMap(['JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER']); exports.MONTHS = MONTHS; function dateToObj(date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return undefined; const ISODate = dateToProcess.toISOString(); return { YYYY: Number.parseInt(ISODate.substring(0, 4)), MM: Number.parseInt(ISODate.substring(5, 7)), DD: Number.parseInt(ISODate.substring(8, 10)), hh: Number.parseInt(ISODate.substring(11, 13)), mm: Number.parseInt(ISODate.substring(14, 16)), ss: Number.parseInt(ISODate.substring(17, 19)), mil: Number.parseInt(ISODate.substring(20, 23)) }; } exports.dateToObj = dateToObj; //dateToObj() //? // const toPeriod = new Date() // const fromPeriod = `${dateToObj(toPeriod).YYYY - 3}${formatDate('-$MM-$DD', toPeriod)}` // fromPeriod //? function diffInDaysYYYY_MM_DD(iniDate, endDate) { return Math.ceil((new Date(endDate) - new Date(iniDate)) / (1000 * 60 * 60 * 24)); //? } exports.diffInDaysYYYY_MM_DD = diffInDaysYYYY_MM_DD; function addDays(daysToAdd, date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return dateToProcess; // 864e5 is a valid JavaScript number that represents the number of milliseconds in a 24h return new Date(dateToProcess.valueOf() + 864E5 * daysToAdd); } exports.addDays = addDays; // addDays(2, "2023-03-24").toISOString() //? // addDays(3, "2023-03-24").toISOString() //? // addDays(9, "2023-03-24").toISOString() //? function subtractDays(daysToSubtract, date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return dateToProcess; return new Date(dateToProcess.valueOf() - 864E5 * daysToSubtract); } exports.subtractDays = subtractDays; // subtractDays(2, "2023-03-26").toISOString() //? // subtractDays(3, "2023-03-27").toISOString() //? // subtractDays(9, "2023-04-02").toISOString() //? function previousDayOfWeek(dayOfWeek, date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return dateToProcess; const diffInDaysOfWeek = dateToProcess.getUTCDay() - dayOfWeek; const toSubtract = diffInDaysOfWeek >= 0 ? diffInDaysOfWeek : 7 + diffInDaysOfWeek; return subtractDays(toSubtract, dateToProcess); } exports.previousDayOfWeek = previousDayOfWeek; //previousDayOfWeek(6,new Date('2021-05-07')) //? //previousDayOfWeek(1,new Date('2021-03-25')) //? function nextDayOfWeek(dayOfWeek, date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return dateToProcess; const diffInDaysOfWeek = dayOfWeek - dateToProcess.getUTCDay(); diffInDaysOfWeek; const toAdd = diffInDaysOfWeek >= 0 ? diffInDaysOfWeek : 7 + diffInDaysOfWeek; return addDays(toAdd, dateToProcess); } exports.nextDayOfWeek = nextDayOfWeek; // nextDayOfWeek(0,new Date('2025-02-01')) //? // nextDayOfWeek(1,new Date('2021-03-25')) //? function dayOfWeek(dayOfWeek, date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return dateToProcess; const diffInDaysOfWeek = (dayOfWeek === 0 ? 7 : dayOfWeek) - (dateToProcess.getUTCDay() === 0 ? 7 : dateToProcess.getUTCDay()); diffInDaysOfWeek; const toSubtract = diffInDaysOfWeek; // diffInDaysOfWeek >= 0 // ? diffInDaysOfWeek // : 7 + diffInDaysOfWeek return addDays(toSubtract, dateToProcess); } exports.dayOfWeek = dayOfWeek; // dayOfWeek(0,new Date('2025-02-06')) //? // dayOfWeek(6,new Date('2025-02-09')) //? function getSameDateOrPreviousFridayForWeekends(date) { const dateToProcess = toDate(date); if (isDate(dateToProcess) === false) return dateToProcess; const dayOfWeek = dateToProcess.getUTCDay(); if (dayOfWeek > 0 && dayOfWeek < 6) return dateToProcess; //Sunday if (dayOfWeek === 0) return subtractDays(2, dateToProcess); //Saturday (dayOfWeek === 6) return subtractDays(1, dateToProcess); } exports.getSameDateOrPreviousFridayForWeekends = getSameDateOrPreviousFridayForWeekends; // getSameDateOrPreviousFridayForWeekends() //? // //2021-05-14T00:00:00.000Z // getSameDateOrPreviousFridayForWeekends(new Date('2021-05-15')).toISOString() //? // ////2021-05-14T00:00:00.000Z // getSameDateOrPreviousFridayForWeekends(new Date('2021-05-16')).toISOString() //? function isDateMidnight(date) { var _a, _b; return ((_b = (_a = date === null || date === void 0 ? void 0 : date.toISOString) === null || _a === void 0 ? void 0 : _a.call(date)) === null || _b === void 0 ? void 0 : _b.substring(10, 24)) === 'T00:00:00.000Z'; } exports.isDateMidnight = isDateMidnight; function setDateToMidnight(date) { if (typeof date === 'string' && date.match(/\d{4}\D\d{2}\D\d{2}/)) return new Date(`${date.substring(0, 10)} UTC`); if (typeof date === 'string') return new Date(`${date} UTC`); const dateToProcess = ( // biome-ignore lint/style/noArguments: <explanation> arguments.length === 0 ? new Date() : new Date(date)); if (Number.isNaN(+dateToProcess)) return dateToProcess; if (isDateMidnight(dateToProcess)) return dateToProcess; return new Date(`${dateToProcess.toISOString().substring(0, 10)} UTC`); } exports.setDateToMidnight = setDateToMidnight; const { colors, colorMessage, colorMessageByStatus, colorByStatus } = (() => { //alias const colors = { red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', cyan: '\x1b[36m', blue: '\x1b[34m', //most importants reset: '\x1b[0m', reverse: '\x1b[7m', fgBlack: '\x1b[30m', fgRed: '\x1b[31m', fgGreen: '\x1b[32m', fgYellow: '\x1b[33m', //Others fgBlue: '\x1b[34m', fgMagenta: '\x1b[35m', fgCyan: '\x1b[36m', fgWhite: '\x1b[37m', bgBlack: '\x1b[40m', bgRed: '\x1b[41m', bgGreen: '\x1b[42m', bgYellow: '\x1b[43m', bgBlue: '\x1b[44m', bgMagenta: '\x1b[45m', bgCyan: '\x1b[46m', bgWhite: '\x1b[47m', bright: '\x1b[1m', dim: '\x1b[2m', underscore: '\x1b[4m', blink: '\x1b[5m', hidden: '\x1b[8m' }; const colorMessage = (message, color) => `${colors[color]}${message}${colors.reset}`; const colorMessageByStatus = (_message, status) => { return (status >= 200) & (status < 300) ? colors.green : (status >= 300) & (status < 400) ? colors.cyan : (status >= 400) & (status < 500) ? colors.yellow : colors.red; }; const colorByStatus = status => { return (status >= 200) & (status < 300) ? colors.green : (status >= 300) & (status < 400) ? colors.cyan : (status >= 400) & (status < 500) ? colors.yellow : colors.red; }; return { colors, colorMessage, colorMessageByStatus, colorByStatus }; })(); exports.colors = colors; exports.colorMessage = colorMessage; exports.colorMessageByStatus = colorMessageByStatus; exports.colorByStatus = colorByStatus; function findDeepKey(objIni, keyToFind) { const currentPath = []; const result = []; traverse(objIni); function traverse(obj) { for (const prop in obj) { if (prop === keyToFind) { result.push([...currentPath]); result[result.length - 1].push(prop); result.push(obj[prop]); } if (obj[prop] !== null && typeof obj[prop] === 'object') { currentPath.push(prop); traverse(obj[prop]); currentPath.pop(); }