flooent
Version:
Fluent interface to provide an expressive syntax for common manipulations.
378 lines (377 loc) • 11.5 kB
JavaScript
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;
;