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
JavaScript
;
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