@augment-vir/common
Version:
A collection of augments, helpers types, functions, and classes for any JavaScript environment.
127 lines (126 loc) • 3.96 kB
JavaScript
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);
}
}