UNPKG

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.

144 lines 7.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.recursiveGenericFunctionSync = exports.recursiveGenericFunction = exports.forIasync = exports.forI = void 0; const error_utils_1 = require("./error-utils"); const is_object_1 = require("./is-object"); /** * Iterates over a specified number of times, passing each iteration's result to the next callback * @returns Array containing results from all iterations * * @example * ```typescript * // Generate Fibonacci sequence * forI(8, (i, prev, results) => { * if (i <= 1) return 1 * return results[i-1] + results[i-2] * }) * ``` * // Returns: [1, 1, 2, 3, 5, 8, 13, 21] */ function forI( /** Number of times to iterate */ nbIterations, /** Function called for each iteration with: * - number: Current iteration index (0-based) * - previousValue: Result from previous iteration * - arrayOfPreviousValues: Array of all previous results */ callback) { const results = []; for (let i = 0; i < nbIterations; i++) { const prevValue = results[results.length - 1]; results.push(callback(i, prevValue, results)); } return results; } exports.forI = forI; /** * Iterates over a specified number of times, passing each iteration's result to the next callback * @returns Array containing results from all iterations * * @example * ```typescript * // Generate Fibonacci sequence ASYNC * await forI(8, async (i, prev, results) => { * if (i <= 1) return 1 * return new Promise(resolve => setTimeout(() => resolve(results[i-1] + results[i-2]), 100)) * }) * ``` * // Returns: [1, 1, 2, 3, 5, 8, 13, 21] */ async function forIasync(nbIterations, callback) { const results = []; for (let i = 0; i < nbIterations; i++) { results.push(await callback(i)); } return results; } exports.forIasync = forIasync; /** * @param {any} item the first array or object or whatever you want to recursively browse * @param {function} callback the callback you want to apply on items including the main one * * this callback has 2 arguments: (item, address) => * * `item` => the actual item * * `addr` => the address of the item, not including root (Eg: subItem1.sub2.[3].[2]) array indexes are juste written as numbers * * `lastElementKey` => the key of last item. May be a number if last item is an array * * `parent` => reference the parent object as this is the only way of reassigning a value for the item. Eg: parent[lastElementKey] = myNewItem * * **NOTE** => if a key of an item contains dots, they will be replaced by '%' in `addr` * * **NOTE2** => if false is returned by the callback it will stop all other iterations (but not in an array) * @param {string} addr$ optional, the base address for the callback function * @param lastElementKey technical field * NOTE: will remove circular references * /!\ check return values */ async function recursiveGenericFunction( /** The object or array you want to recursively browse */ item, /** The callback you want to apply on items including the main one */ callback, /** Optional configuration object */ config = {}, /** Optional base address for the callback function */ addr$ = '', /** Technical field */ lastElementKey = '', parent, techFieldToAvoidCircularDependency = []) { (0, error_utils_1.err500IfNotSet)({ callback }); if (!config.isObjectTestFunction) config.isObjectTestFunction = is_object_1.isObject; if (!techFieldToAvoidCircularDependency.includes(item)) { const result = addr$ === '' ? true : await callback(item, addr$, lastElementKey, parent); if (result !== false) { if (Array.isArray(item)) { if (config?.disableCircularDependencyRemoval !== true) techFieldToAvoidCircularDependency.push(item); await Promise.all(item.map((e, i) => recursiveGenericFunction(e, callback, config, addr$ + '[' + i + ']', i, item, techFieldToAvoidCircularDependency))); } else if (config.isObjectTestFunction(item)) { if (config?.disableCircularDependencyRemoval !== true) techFieldToAvoidCircularDependency.push(item); await Promise.all(Object.entries(item).map(([key, val]) => recursiveGenericFunction(val, callback, config, (addr$ ? addr$ + '.' : '') + key.replace(/\./g, '%'), key, item, techFieldToAvoidCircularDependency))); } } } return item; } exports.recursiveGenericFunction = recursiveGenericFunction; /** * @param {any} item the first array or object or whatever you want to recursively browse * @param {function} callback the callback you want to apply on items including the main one * * this callback has 2 arguments: (item, address) => * * `item` => the actual item * * `addr` => the address of the item, not including root (Eg: subItem1.sub2.[3].[2]) array indexes are juste written as numbers * * `lastElementKey` => the key of last item. May be a number if last item is an array * * `parent` => reference the parent object as this is the only way of reassigning a value for the item. Eg: parent[lastElementKey] = myNewItem * * **NOTE** => if a key of an item contains dots, they will be replaced by '%' in `addr` * * **NOTE2** => if false is returned by the callback it will stop all other iterations (but not in an array) * * **NOTE3** => to reassign a key use => parent[lastElementKey] = myNewItem * @param {string} addr$ optional, the base address for the callback function * @param lastElementKey technical field * NOTE: will remove circular references * /!\ check return values */ function recursiveGenericFunctionSync(item, callback, config = {}, addr$ = '', lastElementKey = '', parent, techFieldToAvoidCircularDependency = []) { (0, error_utils_1.err500IfNotSet)({ callback }); if (!config.isObjectTestFunction) config.isObjectTestFunction = is_object_1.isObject; if (!techFieldToAvoidCircularDependency.includes(item)) { const result = addr$ === '' ? true : callback(item, addr$, lastElementKey, parent); if (result !== false) { if (Array.isArray(item)) { if (config?.disableCircularDependencyRemoval !== true) techFieldToAvoidCircularDependency.push(item); // do not up one level item.forEach((e, i) => recursiveGenericFunctionSync(e, callback, config, addr$ + '[' + i + ']', i, item, techFieldToAvoidCircularDependency)); } else if (config.isObjectTestFunction(item)) { if (config?.disableCircularDependencyRemoval !== true) techFieldToAvoidCircularDependency.push(item); Object.entries(item).forEach(([key, val]) => recursiveGenericFunctionSync(val, callback, config, (addr$ ? addr$ + '.' : '') + key.replace(/\./g, '%'), key, item, techFieldToAvoidCircularDependency)); } } } return item; } exports.recursiveGenericFunctionSync = recursiveGenericFunctionSync; //# sourceMappingURL=loop-utils.js.map