UNPKG

@augment-vir/common

Version:

A collection of augments, helpers types, functions, and classes for any JavaScript environment.

127 lines (126 loc) 3.96 kB
import { check } from '@augment-vir/assert'; import { ensureError } from '@augment-vir/core'; import { getOrSet } from '../object/get-or-set.js'; import { typedObjectFromEntries } from '../object/object-entries.js'; import { filterMap } from './filter.js'; /** * Polyfill for `Object.groupBy`: * https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy * * @category Array * @category Object * @category Package : @augment-vir/common * @example * * ```ts * import {groupArrayBy} from '@augment-vir/common'; * * const result = groupArrayBy( * [ * 'a', * 'b', * ], * (value) => `key-${value}`, * ); * // result is `{key-a: ['a'], key-b: ['b']}` * ``` * * @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common) */ export function groupArrayBy(inputArray, callback, // eslint-disable-next-line @typescript-eslint/no-unused-vars options = {}) { return inputArray.reduce((accum, entry, index, originalArray) => { const key = callback(entry, index, originalArray); const entryArray = getOrSet(accum, key, () => []); entryArray.push(entry); return accum; }, {}); } /** * Similar to {@link groupArrayBy} but maps array entries to a single key and requires `key` _and_ * `value` outputs from the callback. The resulting object does not have an array of elements * (unless the original array itself contains arrays). Automatically handles the case where the * callback returns a promise. * * @category Array * @category Object * @category Package : @augment-vir/common * @example * * ```ts * import {arrayToObject} from '@augment-vir/common'; * * const result = arrayToObject( * [ * 'a', * 'b', * ], * (value) => { * return {key: `key-${value}`, value}; * }, * ); * // result is `{key-a: 'a', key-b: 'b'}` * ``` * * @package [`@augment-vir/common`](https://www.npmjs.com/package/@augment-vir/common) */ export function arrayToObject(inputArray, callback, /** Optional. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars options = {}) { try { let gotAPromise = false; const mappedEntries = inputArray .map((entry, index, originalArray) => { const output = callback(entry, index, originalArray); if (output instanceof Promise) { gotAPromise = true; return output; } else if (output) { return [ output.key, output.value, ]; } else { return undefined; } }) .filter(check.isTruthy); if (gotAPromise) { return new Promise(async (resolve, reject) => { try { const entries = filterMap( /** This does contain promises. */ // eslint-disable-next-line @typescript-eslint/await-thenable await Promise.all(mappedEntries), (entry) => { if (!entry) { return undefined; } else if (Array.isArray(entry)) { return entry; } else { return [ entry.key, entry.value, ]; } }, check.isTruthy); resolve(typedObjectFromEntries(entries)); } catch (error) { reject(ensureError(error)); } }); } else { return typedObjectFromEntries(mappedEntries); } } catch (error) { throw ensureError(error); } }