UNPKG

flooent

Version:

Fluent interface to provide an expressive syntax for common manipulations.

378 lines (377 loc) 11.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.toKeyedMap = exports.toMap = exports.sortAsc = exports.sortDesc = exports.append = exports.prepend = exports.partition = exports.shuffle = exports.unique = exports.pluck = exports.omit = exports.sized = exports.sum = exports.keyBy = exports.mutate = exports.filled = exports.whereNotIn = exports.whereIn = exports.whereNot = exports.where = exports.point = exports.pad = exports.forPage = exports.chunk = exports.move = exports.reject = exports.until = void 0; const utils_1 = require("./utils"); /** * Returns the items until either the given value is found, or the given callback returns `true`. */ function until(value, comparison) { const newArray = []; for (const [index, item] of value.entries()) { const reachedEnd = typeof comparison === "function" ? comparison(item, index) : item === comparison; if (reachedEnd) { break; } newArray.push(item); } return newArray; } exports.until = until; /** * Return all items that don't pass the given truth test. Inverse of `Array.filter`. */ function reject(value, callback) { return value.filter((item, index) => !callback(item, index)); } exports.reject = reject; /** * Moves an item in the array using the given source index to either "before" or "after" the given target. */ function move(value, source, position, target) { if (source === 'first') { source = 0; } else if (source === 'last') { source = value.length - 1; } if (target === 'first') { target = 0; } else if (target === 'last') { target = value.length - 1; } if (source === target) { return value; } const comparison = position === 'before' ? (_, index) => index < target : (_, index) => index <= target; const [before, after] = partition(value, comparison); const result = before.concat(value[source], ...after); const newSourceIndex = source > target ? source + 1 : source; result.splice(newSourceIndex, 1); return result; } exports.move = move; /** * Breaks the array into multiple, smaller arrays of a given size. */ function chunk(value, n) { const remaining = [...value]; const chunks = []; while (remaining.length > 0) { chunks.push(remaining.splice(0, n)); } return chunks; } exports.chunk = chunk; /** * Returns the items for the given page and size. */ function forPage(value, page, size) { const from = ((page - 1) * size); return value.slice(from, from + size); } exports.forPage = forPage; /** * Fills up the array with the given value. */ function pad(value, size, paddedValue) { const copy = value.constructor.from(value); while (copy.length < size) copy.push(paddedValue); return copy; } exports.pad = pad; /** * Points to a specific index inside the array to do further actions on it. */ function point(value, indexOrFn) { const index = utils_1.getNthIndex(value, indexOrFn); const array = value; const pointer = { /** * Sets the value at the current index and returns a new array. */ set(callback) { const copy = array.constructor.from(array); copy[index] = callback(copy[index]); return copy; }, /** * Appends given value to array in between the currently pointed item and its next item and returns a new array. */ append(...items) { const [before, after] = partition(array, (item, i) => i <= index); return [...before, ...items, ...after]; }, /** * Prepends given value to array in between the currently pointed item and its previous item and returns a new array. */ prepend(...items) { const [before, after] = partition(array, (item, i) => i < index); return [...before, ...items, ...after]; }, /** * Removes the current index and returns a new array. */ remove() { return array.filter((_, i) => index !== i); }, /** * Returns value for current pointer position. */ value() { return array[index]; }, index() { return index; }, /** * Splits the array at the current index */ split() { const left = array.slice(0, index); const right = array.slice(index + 1); return [left, right]; }, /** * Steps forward or backward given the number of steps. */ step(steps) { return point(array, index + steps); } }; return pointer; } exports.point = point; /** * Filters array by given value or key/value pair. */ function where(array, keyOrValue, value) { if (value === undefined) { return array.filter((item) => item === keyOrValue); } return array.filter((item) => item[keyOrValue] === value); } exports.where = where; /** * Removes items from array by the given key or key/value pair. */ function whereNot(array, keyOrValue, value) { if (value === undefined) { return array.filter((item) => item !== keyOrValue); } return array.filter((item) => item[keyOrValue] !== value); } exports.whereNot = whereNot; /** * Filters array by given values or key/values pair. */ function whereIn(array, keyOrValue, value) { if (value === undefined) { return array.filter((item) => keyOrValue.includes(item)); } return array.filter((item) => value.includes(item[keyOrValue])); } exports.whereIn = whereIn; /** * Removes items from array by the given value or key/values pair. */ function whereNotIn(array, keyOrValue, value) { if (value === undefined) { return array.filter((item) => !keyOrValue.includes(item)); } return array.filter((item) => !value.includes(item[keyOrValue])); } exports.whereNotIn = whereNotIn; /** * Only returns items which are not empty. */ function filled(value, key) { if (!key) { return value.filter((value) => !!value); } return value.filter((item) => !!item[key]); } exports.filled = filled; /** * Mutates the original array with the return value of the given callback. */ function mutate(value, callback) { const mutation = callback(value); value.splice(0); value.splice(0, 0, ...mutation); return value; } exports.mutate = mutate; /** * Keys the collection by the given key. If multiple items have the same key, only the last one will appear in the new collection. */ function keyBy(value, key) { return value.reduce((result, item, index) => { const group = typeof key === "function" ? key(item, index) : item[key]; result.set(group, item); return result; }, new Map()); } exports.keyBy = keyBy; /** * Returns the sum of the array. * For arrays of objects: Pass field or callback as argument. */ function sum(value, key) { return value.reduce((result, item, index) => { let number = item; if (key) { number = typeof key === "function" ? key(item, index) : item[key]; } return result + number; }, 0); } exports.sum = sum; /** * Creates an array of the specified length and populates it using the callback function. */ function sized(length, callback) { return Array.from({ length }, (value, i) => callback(i)); } exports.sized = sized; /** * Omits given keys from all objects in the array. */ function omit(value, keys) { return value.map((item) => { const copy = { ...item }; keys.forEach(key => delete copy[key]); return copy; }); } exports.omit = omit; /** * Pluck the given field out of each object in the array. */ function pluck(value, key) { return value.map((item) => item[key]); } exports.pluck = pluck; /** * Returns array of unique values. * For array ob objects: Pass key or callback to use it for the comparison. */ function unique(value, comparison) { if (!comparison) { return [...new Set(value)]; } const cache = new Map(); const unique = []; if (typeof comparison === "function") { for (const [index, item] of value.entries()) { const value = comparison(item, index); if (!cache.has(value)) { cache.set(value, 1); unique.push(item); } } return unique; } for (const item of value) { if (cache.has(item[comparison])) continue; cache.set(item[comparison], 1); unique.push(item); } return unique; } exports.unique = unique; /** * Shuffles and returns a new array. */ function shuffle(value) { const array = value.constructor.from(value); for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } exports.shuffle = shuffle; /** * Returns a tuple separating the items that pass the given truth test. */ function partition(value, callback) { const tuple = [[], []]; value.forEach((item, index) => { const tupleIndex = callback(item, index) ? 0 : 1; tuple[tupleIndex].push(item); }); return tuple; } exports.partition = partition; /** * Prepends the given items to the array. Unlike `unshift`, it is immutable and returns a new array. */ function prepend(value, ...items) { return [...items, ...value]; } exports.prepend = prepend; /** * Appends the given items to the array. Unlike `push`, it is immutable and returns a new array. */ function append(value, ...items) { return [...value, ...items]; } exports.append = append; /** * Sorts an array in descending order and **returns a new array**. * For array of objects: Pass index, field or callback to use it for sorting. */ function sortDesc(value, key) { return sortAsc(value, key).reverse(); } exports.sortDesc = sortDesc; /** * Sorts an array in ascending order and **returns a new array**. * For array of objects: Pass index, field or callback to use it for sorting. */ function sortAsc(value, key) { if (!key) { return [...value].sort((a, b) => { if (typeof a === 'string') { return a.localeCompare(b); } return a - b; }); } const compare = (a, b) => { if (typeof a === 'string') { return a.localeCompare(b); } // This also works on dates return a - b; }; if (typeof key === 'function') { return value.map((item, index) => { return { sortKey: key(item, index), item }; }) .sort((a, b) => compare(a.sortKey, b.sortKey)) .map(item => item.item); } return [...value].sort((a, b) => compare(a[key], b[key])); } exports.sortAsc = sortAsc; /** * Turns an array in the structure of `[ ['key', 'value'] ]` into a map. */ function toMap(value) { return new Map(value); } exports.toMap = toMap; /** * Turns the given array into a map with each element becoming a key in the map. */ function toKeyedMap(array, defaultValueOrCallback) { return new Map(array.map(item => { const value = typeof defaultValueOrCallback === 'function' ? defaultValueOrCallback(item) : defaultValueOrCallback; return [item, value]; })); } exports.toKeyedMap = toKeyedMap;