UNPKG

deleight

Version:

A library with 9 modules for writing more expressive web applications with traditional HTML, CSS and JavaScript.

291 lines (290 loc) 8.52 kB
"use strict"; /** * Functions for creating and manipulating objects. Objects here are * the targets of the operations performed by the functions in this module. * * API Table of Contents * * * * @module */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getWhile = exports.getUntil = exports.assign = exports.reduce = exports.filter = exports.map = exports.mapKeys = exports.mapValues = exports.zip = exports.object = void 0; const own_js_1 = require("../member/own/own.js"); /** * Converts an iterable of key-value pairs into an object. This is * the inverse of `Object.entries`. it is a bit similar to {@link zip} * but the object is created by joining in the other axis. * * Values that map to the same keys are combined into an array. The check * for this incurs a performance penalty. If you are sure there are * no repetitions, pass the `noRepeat` flag (as a truthy value) * to skip the checks. * * @example * import { object } from 'deleight/object/operations' * const obj = object([['a', 1], ['b', 2], ['c', 3]]); * console.log(obj) // { a: 1, b: 2, c: 3 } * * @param pairs * @param noRepeat * @returns the created object */ function object(pairs, noRepeat = false) { const result = {}; const repeated = new Set(); if (noRepeat) { for (let [key, value] of pairs) result[key] = value; } else { for (let [key, value] of pairs) { if (result.hasOwnProperty(key)) { if (!repeated.has(key)) { repeated.add(key); result[key] = [result[key]]; } result[key].push(value); } else result[key] = value; } } return result; } exports.object = object; /** * Combine `keys` with corresponding items in `values` to form and return an object. * `values` could be `undefined` may not have items corresponding to some keys but * all keys must be provided. * * Values that map to the same keys are combined into an array. The check * for this incurs a performance penalty. If you are sure there are * no repetitions, pass the `noRepeat` flag (as a truthy value) * to skip the checks. * * @example * import { zip } from 'deleight/object/operations' * const obj = zip(['a', 'b', 'c'], [1, 2, 3]); * console.log(obj) // { a: 1, b: 2, c: 3 } * * @param keys * @param values * @returns */ function zip(keys, values, noRepeat = false) { if (!values) values = []; const result = {}; const repeated = new Set(); const keysIt = keys[Symbol.iterator](); const valuesIt = values[Symbol.iterator](); let key, keyValue; let value; if (noRepeat) { while (!(key = keysIt.next()).done) { result[key.value] = valuesIt.next().value; } } else { while (!(key = keysIt.next()).done) { keyValue = key.value; value = valuesIt.next().value; if (result.hasOwnProperty(keyValue)) { if (!repeated.has(key)) { repeated.add(key); result[keyValue] = [result[keyValue]]; } result[keyValue].push(value); } else result[keyValue] = value; } } return result; } exports.zip = zip; /** * Transform the values of the input object using the mapper and return the mapped object. * The returned object will be the same as the input if `inPlace` is truthy. * * @example * import { mapValues } from 'deleight/object/operations' * const obj = mapValues({ a: 1, b: 2, c: 3 }, (obj, key) => obj[key] * 3); * console.log(obj) // { a: 3, b: 6, c: 9 } * * @param object * @param mapper * @param inPlace * @returns */ function mapValues(object, mapper, inPlace) { const result = inPlace ? object : {}; for (let key of (0, own_js_1.ownKeys)(object)) result[key] = mapper(object, key); return result; } exports.mapValues = mapValues; /** * Transform the keys of the input object using the mapper and return the mapped object. * The returned object will be the same as the input if `inPlace` is truthy. * * @example * import { mapKeys } from 'deleight/object/operations' * const obj = mapKeys({ a: 1, b: 2, c: 3 }, (obj, key) => `${key}1`); * console.log(obj) // { a1: 1, b1: 2, c1: 3 } * * @param object * @param mapper * @param inPlace * @returns */ function mapKeys(object, mapper, inPlace) { const result = inPlace ? object : {}; for (let key of (0, own_js_1.ownKeys)(object)) result[mapper(object, key)] = object[key]; return result; } exports.mapKeys = mapKeys; /** * Transform the keys and values of the input object using the mapper and return the mapped object. * The returned object will be the same as the input if `inPlace` is truthy. * * @example * import { map } from 'deleight/object/operations' * const obj = map({ a: 1, b: 2, c: 3 }, (obj, key) => [`${key}1`, obj[key] * 3]); * console.log(obj) // { a1: 3, b1: 6, c1: 9 } * * @param object * @param mapper * @param inPlace * @returns */ function map(object, mapper, inPlace) { const result = inPlace ? object : object instanceof Array ? [] : {}; let value; for (let key of (0, own_js_1.ownKeys)(object)) { [key, value] = mapper(object, key); result[key] = value; } return result; } exports.map = map; /** * Filters the input object using the test function * and returns the filtered object. * * * @example * import { filter } from 'deleight/object/operations' * const r = filter({ a: 1, b: 2, c: 3 }, (obj, key) => obj[key] > 1); * console.log(r) // { b: 2, c: 3 } * * @param object * @param test * @returns */ function filter(object, test) { const result = (object instanceof Array ? [] : {}); for (let key of (0, own_js_1.ownKeys)(object)) if (test(object, key)) result[key] = object[key]; return result; } exports.filter = filter; /** * Reduces the input object using the reducer (and optional initial value) * and return the reduced value. * * * @example * import { reduce } from 'deleight/object/operations' * const r = reduce({ a: 1, b: 2, c: 3 }, (r, k, v) => r + (v * v), 0); * console.log(r) // 14 * * @param object * @param reducer * @param result * @returns */ function reduce(object, reducer, result = null) { for (let key of (0, own_js_1.ownKeys)(object)) result = reducer(object, key, result); return result; } exports.reduce = reduce; /** * Similar to `Object.assign` but will avoid replacing existing values * of `object` type. Only primitives and nested primitives are assigned. * * A getter function may be used to retrieve existing target properties * in cases where we want some indirection. * * @example * * * @param target * @param sources * @param options */ function assign(target, sources, options) { const getter = options?.getter, setter = options?.setter; let oldValue, value; for (let source of sources) { for (let key of (0, own_js_1.ownKeys)(source)) { value = source[key]; if (typeof value === 'object' && typeof (oldValue = getter?.(target, key) || target[key]) === 'object') { assign(oldValue, [value], options); } else { if (setter) setter(target, key, value); else target[key] = value; } } } return target; } exports.assign = assign; /** * Recursively fetches the same property from the object until the fetched * value matches the `test` condition or there is nothing left to fetch. * * @example * * * @param object * @param key * @param test * @returns */ function getUntil(object, key, test) { const value = object[key]; if (test(value)) return value; else if (typeof value === 'object') return getUntil(value, key, test); } exports.getUntil = getUntil; /** * Recursively fetches the same property from the object while the fetched * value passes the test or there is nothing left to fetch. * * @example * * * @param object * @param key * @param test * @returns */ function getWhile(object, key, test) { const value = object[key]; if (!test(value)) return value; else if (typeof value === 'object') return getWhile(value, key, test); } exports.getWhile = getWhile;