map-fns
Version:
<h1 align="center"> <code>map-fns</code> </h1>
341 lines (327 loc) • 10.9 kB
JavaScript
/**
* Creates a new `map` populated with every key in the original `map` except the
* keys that exist in the `keys` array.
*
* ```tsx
* const out = removeKeysFromMap({ a: 1, b: 2 }, ["b"]);
* console.log(out); // { a: 1 }
* ```
*
* @param map - The map to remove keys from.
* @param keys - The keys to remove from the map.
* @returns A new map with the removed.
*/
function removeKeysFromMap(map, keys) {
var mapKeys = Object.keys(map);
var originalKeyList = Array.isArray(keys) ? keys : [keys];
var stringifiedKeyList = originalKeyList.map(String);
var removeKeySet = new Set(stringifiedKeyList);
return mapKeys.reduce(function (newMap, key) {
if (!removeKeySet.has(key)) {
newMap[key] = map[key];
}
return newMap;
}, {});
}
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
/**
* Creates a new `map` populated with every key in the original `map` where the
* value behind each `k` in `keys` is the return value of `fn(map[k])`
*
* ```tsx
* const out = modifyInMap({ a: 1, b: 2 }, "b", n => n + 1);
* console.log(out); // { a: 1, b: 3 }
* ```
*
* The original `map` is not modified.
*
* An error is thrown if any key in `keys` does not exist in the map.
*
* @param map - The map to copy and modify.
* @param keys - The keys to modify within the map.
* @returns A new map with modified values.
*/
function modifyInMap(map, keys, fn) {
var obj = __assign({}, map);
var keyList = (Array.isArray(keys) ? keys : [keys]);
for (var _i = 0, keyList_1 = keyList; _i < keyList_1.length; _i++) {
var key = keyList_1[_i];
if (!obj.hasOwnProperty(key)) {
throw new Error("Key '".concat(key, "' does not exist in map."));
}
obj[key] = fn(obj[key]);
}
return obj;
}
function isNotMergable(value) {
return (typeof value !== "object" || // Primitives
!value || // null
value.constructor !== Object // Arrays, Sets, etc
);
}
function deepMerge(target, toMerge) {
if (typeof toMerge === "function") {
return deepMerge(target, toMerge(target));
}
var out = __assign({}, target);
var kList = Object.keys(toMerge);
for (var _i = 0, kList_1 = kList; _i < kList_1.length; _i++) {
var k = kList_1[_i];
var valueToMerge = toMerge[k];
if (typeof valueToMerge === "function" && typeof out[k] !== "function") {
// The value to merge is a function, but the target is not a function.
//
// The value is a function that returns the actual value to merge.
valueToMerge = valueToMerge(out[k]);
}
if (isNotMergable(valueToMerge)) {
out[k] = valueToMerge;
continue;
}
out[k] = deepMerge(out[k], valueToMerge);
}
return out;
}
/**
* Creates a new `map` populated with every key in the original `map` where the
* value behind each `k` in `keys` is the value `map[k]` shallowly merged with
* the return value of `fn(map[k])`.
*
* ```tsx
* newMap[k] = { ...map[k], ...fn(map[k]) };
* ```
*
* Example usage:
*
* ```tsx
* const out = modifyInMap(
* { alice: { age: 34, gender: "f" }, bob: { age: 42, gender: "m" } },
* "alice",
* person => ({ age: person.age + 1 }),
* );
* console.log(out.alice); // { age: 35, gender: "f" }
* console.log(out.bob); // { age: 42, gender: "m" }
* ```
*
* The original `map` is not modified.
*
* An error is thrown if any key in `keys` does not exist in the map.
*
* @param map - The map to copy and modify.
* @param keys - The keys to merge within the map.
* @returns A new map with modified values.
*/
function mergeInMap(map, keys,
/**
* Expects a partial value of `map[key]`.
*
* Supports returning functions to compute properties like so:
*
* ```tsx
* const map = { key: { count: 1 } };
*
* // "Normal" syntax
* mergeInMap(map, "key", (item) => ({
* count: item.count + 1,
* }));
*
* // Compute function
* mergeInMap(map, "key", () => ({
* count: (count) => count + 1,
* }));
* ```
*/
toMerge) {
var obj = __assign({}, map);
var keyList = (Array.isArray(keys) ? keys : [keys]);
for (var _i = 0, keyList_1 = keyList; _i < keyList_1.length; _i++) {
var key = keyList_1[_i];
if (!obj.hasOwnProperty(key)) {
throw new Error("Key '".concat(key, "' does not exist in map."));
}
obj[key] = deepMerge(obj[key], toMerge);
}
return obj;
}
/**
* Creates a new `map` populated with every item in the original `map` with every item in
* `items` added to the map. The key that items behind are determined by the `keyProperty`.
*
* ```tsx
* const map: Record<string, { id: string, value: number } }> = {
* a: { id: "a", value: 1 },
* };
*
* const result = addListToMap(map, [{ id: "b", value: 2 }], "id");
*
* console.log(result); // { a: { id: "a", value: 1 }, b: { id: "b", value: 2 } };
* ```
*
* The original `map` is not modified.
*
* @param map - The map to copy and modify.
* @param items - The items to add to the map
* @param keyProperty - The property of the items that contains the map key to use (e.g. `id`).
* @returns A new map with the items added to it.
*/
function addListToMap(map, items, keyProperty) {
var obj = __assign({}, map);
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
var item = items_1[_i];
obj[item[keyProperty]] = item;
}
return obj;
}
/**
* Creates a new `map` populated with every key in the original `map` where the
* value of each key `k` in the new map is the return value of `fn(map[k])`.
*
* @param map The original map.
* @param fn A function that takes a single argument `map[k]` and returns the value of `newMap[k]`.
* @returns A new `map` where `map[k]` is the result of `fn(map[k])`.
*/
function mapMap(map, fn) {
var obj = {};
var keys = Object.keys(map);
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
obj[key] = fn(map[key]);
}
return obj;
}
/**
* Creates a new map populated with every key in `keys` where the value
* behind each `k` in `keys` is `callback(map[k])`.
*
* ```tsx
* mapPartialMap({ a: 1, b: 2, c: 3 }, ["a", "c"], (n) => n * 2);
* //=> {
* // a: 2,
* // c: 6,
* // }
* ```
*
* @param map The original map.
* @param keys The keys to include in the new map.
* @param callback A function that takes a single argument `map[k]` and returns the value of `newMap[k]`.
* @returns A new `map` where `map[k]` is the result of `callback(map[k])`.
*/
function mapPartialMap(map, keys, callback) {
var obj = {};
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
if (!map.hasOwnProperty(key)) {
throw new Error("Key '".concat(key, "' does not exist in map."));
}
obj[key] = callback(map[key]);
}
return obj;
}
/**
* Returns a new array of key, value entries from the provided map. The keys of the entries
* to return may be provided via the `keys` argument.
*
* ```tsx
* const entries = mapEntries({ a: 1, b: 2, c: 3 });
* // > [["a", 1], ["b", 2] ["c", 3]]
*
* const entries = mapEntries({ a: 1, b: 2, c: 3 }, ["b", "a"]);
* // > [["b", 2], ["a", 1]]
* ```
*
* @param map The map to get the entries of.
* @param keys The keys in the map to return as entries.
* @returns An array of key, value pairs for every entry in the map. If `keys` is provided, only the entries for those keys are included.
*/
function mapEntries(map, keys) {
var keysToUse = keys || Object.keys(map);
var entries = [];
for (var _i = 0, keysToUse_1 = keysToUse; _i < keysToUse_1.length; _i++) {
var key = keysToUse_1[_i];
if (!map.hasOwnProperty(key)) {
throw new Error("Key '".concat(key, "' does not exist in map."));
}
entries.push([key, map[key]]);
}
return entries;
}
/**
* Takes in two maps and returns true if they contain the same keys and the
* values behind their keys are shallowly equal. Returns false otherwise.
*
* This function can be useful to check if changes have occurred in any of
* the items in the map.
*
* The order that the maps are provided in does not matter.
*
* @param a First map to compare
* @param b Second map to compare
* @returns True if they are equal, False if they are not
*/
function areMapsShallowEqual(a, b) {
var aKeys = Object.keys(a);
var bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) {
return false;
}
for (var i = 0; i < aKeys.length; i += 1) {
var key = aKeys[i];
if (!b.hasOwnProperty(key)) {
return false;
}
if (a[key] !== b[key]) {
return false;
}
}
return true;
}
/**
* Creates a new map populated with every key in `keys` where the value
* behind each `k` in `keys` is `map[k]`.
*
* ```tsx
* partialMap({ a: 1, b: 2, c: 3 }, ["a", "c"]);
* //=> {
* // a: 1,
* // c: 3,
* // }
* ```
*
* @param map The original map.
* @param keys The keys to include in the new map.
* @returns a new `map` populated with every key in `keys` where the value
* behind each `k` in `keys` is `map[k]`.
*/
function partialMap(map, keys) {
var obj = {};
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
if (!map.hasOwnProperty(key)) {
throw new Error("Key '".concat(key, "' does not exist in map."));
}
obj[key] = map[key];
}
return obj;
}
export { addListToMap, areMapsShallowEqual, mapEntries, mapMap, mapPartialMap, mergeInMap, modifyInMap, partialMap, removeKeysFromMap };