funk-lib
is a collection of functions for working with native JavaScript types in a consistent, functional way. It is heavily inspired by Ramda
, but does not duplicate Ramda's functionality.
For a full list of functions see the Documentation For The Latest Release
Pure functions
Mostly. There are a few documented exceptions
Currying
All functions are curried, and arguments are arranged "data last" for useful partial application
Isomorphic
Packages are available for both
Node.js
(CommonJS) - npm/funk-lib
Browser
(ES Modules) - npm/funk-lib-es
npm i -P funk-lib
# or: es-module compatible build
npm i -P funk-lib-es
const { mapKeys } = require('funk-lib/object');
// or: es-module compatible build
import { mapKeys } from 'funk-lib-es/object';
$ npm run <command>
command | description |
---|---|
build |
Transpile source |
cover |
Run test coverage |
init |
Re/Install deps |
init:hard |
init with a fresh package-lock |
docs |
Parse docs to JSON |
lint |
Lint the source |
test |
Run tests |
test:watch |
Run tests on change |
verify |
Verify linting, tests, coverage |
Functions for working with Array
const { array } = require('funk-lib');
[a] → []
Delete all items. Mutating + identity
const { clear } = require('funk-lib/array');
const arr = [1, 2, 3];
clear(arr); // arr === []
[a] → a
Select a random array item
const { sample } = require('funk-lib/array');
sample([0, 1, 2, 3, 4, 5]); // 2
[a] → [a]
Immutably randomize array element order Fisher-Yates shuffle
const { shuffle } = require('funk-lib/array');
shuffle([1, 2, 3, 4, 5]); // [4, 1, 2, 5, 3]
[ k: v ] → { k: v }
Transform an array into an object, where keys are indices, and values are elements
const { toObj } = require('funk-lib/array');
toObj(['a', 'b', 'c']); // { 0: a, 1: b, 2: c }
Functions for working with promises, async
+ await
, and parallelism
const { async } = require('funk-lib');
[Promise<a>] → Promise<[a]>
Resolve promises in parallel
const { all } = require('funk-lib/async');
// [1, 2, 3]
await all([
Promise.resolve(1),
2,
Promise.resolve(3),
]);
[Promise] → Promise<[{ status, value, reason }]>
Returns the resolved / rejected status of multiple promises
const { allSettled } = require('funk-lib/async');
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: Error('oops') },
// ]
await allSettled([
Promise.resolve(1),
Promise.reject(Error('oops')),
]);
Make a promise-returning function errback-yielding. Inverse of promisify
const { callbackify } = require('funk-lib/async');
const func = async n => n + 1;
await callbackify(func)(1, (err, res) => {
// err = null, res = 2
});
(a → b) → Promise<b>
Defers invoking a function until the current call stack has cleared
const { defer } = require('funk-lib/async');
await defer(_ => 3); // 3
[a] → (a → b) → Promise<b>
Defers invoking a function until the current call stack has cleared. Passes args to deferred function.
const { deferWith } = require('funk-lib/async');
await deferWith([1, 2], (a, b) => a + b); // 3
* → Object
Creates an externally controlled promise
const { deferred } = require('funk-lib/async');
const { promise, resolve, reject } = deferred();
resolve(123);
await promise; // 123
Number → Promise<undefined>
Creates a promise that resolves in n
ms
const { delay } = require('funk-lib/async');
await delay(100); // resolved in 100ms
(a → Promise<Boolean>) → [a] → Promise<Boolean>
Does every item in the array satisfy the predicate? (parallel)
const { every } = require('funk-lib/async');
// false
await every(async n => (n > 5), [4, 5, 6, 7]);
Number → (a → Promise<Boolean>) → [a] → Promise<Boolean>
Does every item in the array satisfy the predicate? (variable parallelization)
const { everyLimit } = require('funk-lib/async');
// false
await everyLimit(2, async n => (n > 4), [1, 2, 3, 4, 5]);
(a → Promise<Boolean>) → [a] → Promise<Boolean>
Does every item in the array satisfy the predicate? (serial)
const { everySeries } = require('funk-lib/async');
// false
await everySeries(async n => (n > 5), [4, 5, 6, 7]);
{ k: (a → Promise<b>) } → { k: a } → Promise<{ k: b }>
Async R.evolve
const { evolve } = require('funk-lib/async');
const data = { a: 1, b: 2, c: 3 };
// { a: 2, b: 4, c: 3 }
await evolve({
a: async a => a + 1,
b: async b => b * 2,
}, data);
(a → Promise<Boolean>) → [a] → Promise<[a]>
Keep only array items that pass the predicate. (parallel)
const { filter } = require('funk-lib/async');
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// [0, 1, 2, 3, 4, 5]
await filter(async n => (n <= 5), array);
Number → (a → Promise<Boolean>) → [a] → Promise<[a]>
Keep only array items that pass the predicate. (variable parallelization)
const { filterLimit } = require('funk-lib/async');
// [1, 2]
await filterLimit(2, async n => (n < 3), [1, 2, 3, 4, 5]);
(a → Promise<Boolean>) → [a] → Promise<[a]>
Keep only array items that pass the predicate. (serial)
const { filterSeries } = require('funk-lib/async');
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// [0, 1, 2, 3, 4, 5]
await filterSeries(async n => (n <= 5), array);
(a → Promise<Boolean>) → [a] → Promise<a>
Returns the first item that satisfies the predicate. (parallel)
const { find } = require('funk-lib/async');
const records = [{ id: 1 }, { id: 2 }, { id: 3 }];
// { id: 2 }
await find(async ({ id }) => (id === 2), records);
Number → (a → Promise<Boolean>) → [a] → Promise<a>
Returns the first item that passes the predicate. (variable parallelization)
const { findLimit } = require('funk-lib/async');
const records = [{ id: 1 }, { id: 2 }, { id: 3 }];
// { id: 2 }
await findLimit(2, async ({ id }) => (id === 2), records);
(a → Promise<Boolean>) → [a] → Promise<a>
Returns the first item that satisfies the predicate. (serial)
const { findSeries } = require('funk-lib/async');
const records = [{ id: 1 }, { id: 2 }, { id: 3 }];
// { id: 2 }
await findSeries(async ({ id }) => (id === 2), records);
(a → Promise<[b]>) → [a] → Promise<[b]>
Parallel flatMap (a.k.a. "chain")
const { flatMap } = require('funk-lib/async');
// [1, 2, 2, 4, 3, 6]
await flatMap(async n => [n, n * 2], [1, 2, 3]);
Number → (a → Promise<[b]>) → [a] → Promise<[b]>
Flat map (a.k.a. "chain"). (variable parallelization)
const { flatMapLimit } = require('funk-lib/async');
// [1, 2, 2, 4, 3, 6]
await flatMapLimit(2, async n => [n, n * 2], [1, 2, 3]);
([a, b] → Promise<[[c, d]]>) → { a: b } → Promise<{ c: d }>
Parallel flat map pairs
const { flatMapPairs } = require('funk-lib/async');
// { 2: 2, b: b }
flatMapPairs(([a, b]) => {
return (b > 1) ? [[a, a], [b, b]] : [];
}, { a: 1, b: 2 });
Number → ([a, b] → Promise<[[c, d]]>) → { a: b } → Promise<{ c: d }>
Flat map pairs. (variable parallelization)
const { flatMapPairsLimit } = require('funk-lib/async');
// { 2: 2, b: b }
flatMapPairsLimit(10, ([a, b]) => {
return (b > 1) ? [[a, a], [b, b]] : [];
}, { a: 1, b: 2 });
([a, b] → Promise<[[c, d]]>) → { a: b } → Promise<{ c: d }>
Serial flat map pairs
const { flatMapPairsSeries } = require('funk-lib/async');
// { 2: 2, b: b }
flatMapPairsSeries(([a, b]) => {
return (b > 1) ? [[a, a], [b, b]] : [];
}, { a: 1, b: 2 });
(a → Promise<[b]>) → [a] → Promise<[b]>
Serial flatMap (a.k.a. "chain")
const { flatMapSeries } = require('funk-lib/async');
// [1, 2, 2, 4, 3, 6]
await flatMapSeries(async n => [n, n * 2], [1, 2, 3]);
(a → Promise<b>) → [a] → Promise<[a]>
Call a side-effecting function once for each item in the array. (parallel)
const { forEach } = require('funk-lib/async');
// log 1
// log 2
// log 3
// [1, 2, 3]
await forEach(async n => console.log(n), [1, 2, 3]);
Number → (a → Promise<b>) → [a] → Promise<[a]>
Call a side-effecting function once for each item in the array. (variable parallelization)
const { forEachLimit } = require('funk-lib/async');
// 1
// 2
// 3
await forEachLimit(2, async n => console.log(n), [1, 2, 3]);
(a → Promise<b>) → [a] → Promise<[a]>
Call a side-effecting function once for each item in the array. (serial)
const { forEachSeries } = require('funk-lib/async');
// log 1
// log 2
// log 3
// [1, 2, 3]
await forEachSeries(async n => console.log(n), [1, 2, 3]);
Returns a promise that is resolved by an err-back function
const { fromCallback } = require('funk-lib/async');
await fromCallback(cb => cb(null, 123)); // 123
await fromCallback(cb => cb(Error('oops'))); // Error('oops')
(a → Promise<b>) → [a] → Promise<[b]>
Transform each item in an array. (parallel)
const { map } = require('funk-lib/async');
const array = [1, 2, 3, 4, 5];
// [2, 4, 6, 8, 10]
await map(async n => (n * 2), array);
Number → (a → Promise<b>) → [a] → Promise<[b]>
Transform each item in an array. (variable parallelization)
const { mapLimit } = require('funk-lib/async');
// [2, 4, 6, 8, 10]
await mapLimit(2, async n => (n * 2), [1, 2, 3, 4, 5]);
([a, b] → Promise<[c, d]>) → { a: b } → Promise<{ c: d }>
Transform object keys and values. (parallel)
const { mapPairs } = require('funk-lib/async');
// { 1: 'a', 2: 'b', 3: 'c' }
await mapPairs(async pair => pair.reverse(), { a: 1, b: 2, c: 3 });
Number → ([a, b] → Promise<[c, d]>) → { a: b } → Promise<{ c: d }>
Transform object keys and values. (variable parallelization)
const { mapPairsLimit } = require('funk-lib/async');
// { 1: 'a', 2: 'b', 3: 'c' }
await mapPairsLimit(2, async pair => pair.reverse(), { a: 1, b: 2, c: 3 });
([a, b] → Promise<[c, d]>) → { a: b } → Promise<{ c: d }>
Transform object keys and values. (serial)
const { mapPairsSeries } = require('funk-lib/async');
// { 1: 'a', 2: 'b', 3: 'c' }
await mapPairsSeries(async pair => pair.reverse(), { a: 1, b: 2, c: 3 });
(a → Promise<b>) → [a] → Promise<[b]>
Transform each item in an array. (serial)
const { mapSeries } = require('funk-lib/async');
const array = [1, 2, 3, 4, 5];
// [2, 4, 6, 8, 10]
await mapSeries(async n => (n * 2), array);
(...f) → f
Left-to-right function composition of sync and / or async functions
const { pipe } = require('funk-lib/async');
// 4
await pipe(
async n => n + 1,
async n => n * 2,
)(1);
(...f) → f
Curried left-to-right function composition of sync and / or async functions
const { pipeC } = require('funk-lib/async');
const math = pipeC(
async (a, b) => a + b,
c => (c * 2),
async c => (c + 1),
);
await math(2)(5) // 21;
Make an errback-calling function promise-returning. Inverse of callbackify
const { promisify } = require('funk-lib/async');
const callback = (n, cb) => cb(null, n + 1);
await promisify(callback)(1); // 2
{ k: Promise<v> } → Promise<{ k: v }>
Resolve object values in parallel
const { props } = require('funk-lib/async');
// { one: 1, two: 2, three: 3 }
await props({
one: Promise.resolve(1),
two: 2,
three: Promise.resolve(3),
});
[Promise<a>] → Promise<a>
Returns a promise that resolves or rejects as soon as one of the promises in an iterable resolves or rejects, with the value or reason from that promise.
const { race } = require('funk-lib/async');
// true
await race([
delay(1).then(_ => true),
delay(10).then(_ => false),
delay(100).then(_ => { throw Error('oops') }),
]);
((a, b) → Promise<a>) → a → [b] → Promise<a>
Reduce an array of items to a single item. (serial)
const { reduce } = require('funk-lib/async');
// 15
await reduce(async (a, n) => a + n, 0, [1, 2, 3, 4, 5]);
Error → Promise<Error>
Create a rejected promise
const { reject } = require('funk-lib/async');
// Promise<Error('oops')>
reject(Error('oops'));
a → Promise<a>
Create a resolved promise
const { resolve } = require('funk-lib/async');
// Promise<1>
resolve(1);
Number → (a → b) → (a → Promise<b>)
Wrap a function to retry based on a predicate function
const { retryWith } = require('funk-lib/async');
// retry 10 times with exponential backoff
const retry = retryWith(i => {
return (i < 10)
? return 50 * Math.pow(2, i)
: false;
});
const data = await retry(getData)('https://foo.bar');
(a → Promise<Boolean>) → [a] → Promise<Boolean>
Does any item in the array satisfy the predicate? (parallel)
const { some } = require('funk-lib/async');
// true
await some(async n => (n > 5), [4, 5, 6, 7]);
Number → (a → Promise<Boolean>) → [a] → Promise<Boolean>
Does any item in the array satisfy the predicate? (variable parallelization)
const { someLimit } = require('funk-lib/async');
// true
await someLimit(2, async n => (n > 4), [1, 2, 3, 4, 5]);
(a → Promise<Boolean>) → [a] → Promise<Boolean>
Does any item in the array satisfy the predicate? (serial)
const { someSeries } = require('funk-lib/async');
// true
await someSeries(async n => (n > 5), [4, 5, 6, 7]);
Number → Promise<a> → Promise<a>
Throws a TimeoutError if the promise takes longer than n
ms to resolve
const { timeout } = require('funk-lib/async');
await timeout(2000, delay(100)); // undefined
await timeout(100, delay(2000)); // TimeoutError
(a → b) → (a → Promise<b>)
Wraps a function to always return a promise
const { toAsync } = require('funk-lib/async');
const pred = n => n > 5;
const asyncPred = toAsync(pred);
asyncPred(2); // Promise<false>
Functions for generating and transforming colors
const { color } = require('funk-lib');
String → { h, s, l }
Hex to HSL
const { hexToHsl } = require('funk-lib/color');
String → { r, g, b }
Hex to RGB
const { hexToRgb } = require('funk-lib/color');
{ h, s, l } → String
HSL to hex
const { hslToHex } = require('funk-lib/color');
{ h, s, l } → { r, g, b }
HSL to RGB
const { hslToRgb } = require('funk-lib/color');
* → String
Get a random hex string
const { randomHex } = require('funk-lib/color');
randomHex(); // #b3a95a
* → { h, s, l }
Get a random HSL value
const { randomHsl } = require('funk-lib/color');
* → { r, g, b }
Get a random RGB value
const { randomRgb } = require('funk-lib/color');
randomRgb(); // { r: 35, g: 125, b: 106 }
{ r, g, b } → String
RGB to hex
const { rgbToHex } = require('funk-lib/color');
{ r, g, b } → { h, s, l }
RGB to HSL
const { rgbToHsl } = require('funk-lib/color');
Functions for cryptography
const { crypto } = require('funk-lib');
String → String → String
Hash with variable algorithm
const { hashWith } = require('funk-lib/crypto');
hashWith('md5', 'hello'); // '5d41402abc4b2a76b9719d911017c592'
String → String
md5 hash a string
const { md5 } = require('funk-lib/crypto');
md5('hello'); // '5d41402abc4b2a76b9719d911017c592'
String → String
sha256 hash a string
const { sha256 } = require('funk-lib/crypto');
sha256('hello'); // '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
String → String
sha512 hash a string
const { sha512 } = require('funk-lib/crypto');
sha512('hello'); // 'E7C22B994C59D9CF2B48E549B1E24666636045930D3DA7C1ACB299D1C3B7F931F94AAE41EDDA2C2B207A36E10F8BCB8D45223E54878F5B316E7CE3B6BC019629'
Functions for date
and time
const { datetime } = require('funk-lib');
a → Date
Get the current unix epoch (in ms)
const { now } = require('funk-lib/datetime');
Functions for working with Function
const { function } = require('funk-lib');
((a → b) → (a → b)) → (a → b)
Y combinator. Define recursive functions without variable assignment
const { Y } = require('funk-lib/function');
const fib = Y(f => n => {
return (n <= 2) ? 1 : f(n - 1) + f(n - 2);
});
fib(7); // 13
Number → (a → b) → (a → undefined)
Wrap a function to delay invocation until after n
ms
have elapsed since the last call
const { debounce } = require('funk-lib/function');
const debounce = debounce(100, expensiveMath);
debounced(1, 2);
a → undefined
A function that does nothing. "no-op"
const { noop } = require('funk-lib/function');
noop(); // undefined
(b → b → c) → (a → b) → a → a → c
Transforms two inputs and combines the outputs
const { on } = require('funk-lib/function');
const records = [{ age: 9 }, { age: 1 }, { age: 3 }];
// [{ age: 1 }, { age: 3 }, { age: 9 }]
R.sort(on(R.subtract, R.prop('age'))), records);
(a → b) → (a → b)
Creates a function that is restricted to invoking func once. Repeat calls to the function return the value of the first invocation
const { once } = require('funk-lib/function');
const pred = n => n > 5;
const oncePred = once(pred);
oncePred(10); // true
oncePred(1); // true (cached. pred not called again)
...f → f
Curried left-to-right function composition
const { pipeC } = require('funk-lib/function');
const math = pipeC(
(a, b) => a + b,
c => (c * 2),
c => (c + 1),
);
math(2)(5) // 21;
Number → (a → b) → (a → b)
Wraps a function so that it is only invoked at most once every n
ms
const { throttle } = require('funk-lib/function');
const throttled = throttle(100, expensiveMath);
throttled(1, 2);
Functions for working with HTTP
interfaces
const { http } = require('funk-lib');
String → { mimeType, charset, boundary }
Parse a content-type HTTP header into its parts
const { parseContentType } = require('funk-lib/http');
// {
// mimeType: 'multipart/form-data',
// boundary: 'abc',
// charset: 'utf-8',
// }
parseContentType('multipart/form-data; boundary=abc; charset=utf-8');
// { mimeType: 'multipart/form-data' }
parseContentType('multipart/form-data');
Functions for typechecking
const { is } = require('funk-lib');
a → b → Boolean
Are two values equal by strict reference equality?
const { is } = require('funk-lib/is');
const sym = Symbol();
is(sym, sym); // true
is(1, true); // false
a → Boolean
Is a value an Array
?
const { isArray } = require('funk-lib/is');
isArray([]); // true
a → Boolean
Is a value an async iterable?
const { isAsyncIterable } = require('funk-lib/is');
isAsyncIterable((async function* () {})()); // true
isAsyncIterable({ [Symbol.asyncIterator]: () => {} }); // true
a → Boolean
Is a value a Boolean
?
const { isBoolean } = require('funk-lib/is');
isBoolean(false); // true
a → Boolean
Is a value a Buffer
?
const { isBuffer } = require('funk-lib/is');
isBuffer(Buffer.from([])); // true
a → Boolean
Is a value a Date
?
const { isDate } = require('funk-lib/is');
isDate(new Date()); // true
a → Boolean
Is a value even?
const { isEven } = require('funk-lib/is');
isEven(2); // true
isEven(3); // false
a → Boolean
Is a value falsey?
const { isFalsey } = require('funk-lib/is');
isFalsey(0); // true
a → Boolean
Is a value finite?
const { isFinite } = require('funk-lib/is');
isFinite(10); // true
isFinite(Infinity); // false
a → Boolean
Is a value a float?
const { isFloat } = require('funk-lib/is');
isFloat(1.23); // true
isFloat(1); // false
a → Boolean
Is a value a function?
const { isFunction } = require('funk-lib/is');
isFunction(() => {}); // true
String → a → Boolean
Is a value an instance of a class?
const { isInstanceOf } = require('funk-lib/is');
isInstanceOf(Array, []); // true
a → Boolean
Is a value an integer?
const { isInteger } = require('funk-lib/is');
isInteger(1); // true
isInteger(1.23); // false
a → Boolean
Is a value an iterable?
const { isIterable } = require('funk-lib/is');
isIterable([]); // true
isIterable({ [Symbol.iterator]: () => {} }); // true
a → Boolean
Is a value an iterator?
const { isIterator } = require('funk-lib/is');
const iterator = [][Symbol.iterator]();
isIterator(iterator); // true
a → Boolean
Is a value NaN?
const { isNaN } = require('funk-lib/is');
isNaN(NaN); // true
a → Boolean
Is a value negative?
const { isNegative } = require('funk-lib/is');
isNumber(-10); // true
isNumber(10); // false
a → b → Boolean
Are two values not equal by strict reference equality?
const { isNot } = require('funk-lib/is');
const sym = Symbol();
isNot(1, true); // true
isNot(sym, sym); // false
a → Boolean
Is a value null
?
const { isNull } = require('funk-lib/is');
isNull(null); // true
a → Boolean
Is a value a number?
const { isNumber } = require('funk-lib/is');
isNumber(10); // true
isNumber(NaN); // false
a → Boolean
Is a value an object?
const { isObject } = require('funk-lib/is');
isObject({}); // true
isObject([]]); // false
isObject(null); // false
a → Boolean
Is a value odd?
const { isOdd } = require('funk-lib/is');
isOdd(1); // true
isOdd(2); // false
a → Boolean
Is a value a "plain old javascript object"?
const { isPojo } = require('funk-lib/is');
isPojo({}); // true
a → Boolean
Is a value positive?
const { isPositive } = require('funk-lib/is');
isNumber(10); // true
isNumber(-10); // false
a → Boolean
Is a value a promise?
const { isPromise } = require('funk-lib/is');
isPromise(Promise.resolve(1)); // true
a → Boolean
Is a value a regular expression?
const { isRegExp } = require('funk-lib/is');
isRegExp(/[a-z]/); // true
a → Boolean
Is a value a stream?
const { isStream } = require('funk-lib/is');
isStream(new Stream.Readable()); // true
a → Boolean
Is a value a string?
const { isString } = require('funk-lib/is');
isString('hello'); // true
a → Boolean
Is a value a symbol?
const { isSymbol } = require('funk-lib/is');
isSymbol(Symbol('foo')); // true
a → Boolean
Is a value a "thenable"?
const { isThenable } = require('funk-lib/is');
isThenable({ then: _ => {} }); // true
a → Boolean
Is a value truthy?
const { isTruthy } = require('funk-lib/is');
isTruthy(1); // true
String → a → Boolean
Does a value have a certin type (via typeof
)?
const { isTypeOf } = require('funk-lib/is');
isTypeOf('boolean', true); // true
a → Boolean
Is a value undefined
?
const { isUndefined } = require('funk-lib/is');
isUndefined(undefined); // true
A Module
containing functions for working with sync and async iterables.
Contains two symmetrical child modules: iterable/sync
and iterable/async
const { iterable } = require('funk-lib');
Functions for working with async iterables
const { async } = require('funk-lib/iterable');
a → Iterable<a> → AsyncIterator<a>
Appends an item a
const { append } = require('funk-lib/iterable/async');
append(4, from([1, 2, 3])); // AsyncIterator<1, 2, 3, 4>
Iterable<a> → Iterable<a> → AsyncIterator<a>
Concatenate two async iterables
const { concat } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3, 4, 5, 6>
concat(from([1, 2, 3]), from([4, 5, 6]));
((a, b) → Promise<Boolean>) → Iterable<a> → Iterable<b> → Promise<Boolean>
Check if two async iterables match at every index as determined by a custom comparator
const { correspondsWith } = require('funk-lib/iterable/async');
const one = from([{ id: 1 }, { id: 2 }, { id: 3 }]);
const two = from([{ id: 1 }, { id: 2 }, { id: 3 }]);
// true
await correspondsWith(R.prop('id'), one, two);
(a → Promise<Boolean>) → Iterable<a> → Promise<Integer>
Return the number of items in an iterable. Exhasts the input iterator
const { count } = require('funk-lib/iterable/async');
// 4
await count(async n => (n > 3), from([1, 2, 3, 4, 5, 6, 7]));
Iterable<a> → AsyncIterator<a>
Yield iterable items cyclically, infinitely looping when the input is exhausted
const { cycle } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3, 1, 2, 3, ...>
cycle(from([1, 2, 3]));
Integer → Iterable<a> → AsyncIterator<a>
Yield all items from an async iterable, n
times. Requires caching all items in the iterable
const { cycleN } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 1, 2, 1, 2>
cycleN(3, from([1, 2]));
Integer → Iterable<a> → AsyncIterator<a>
Yield all but the first n
items
const { drop } = require('funk-lib/iterable/async');
// AsyncIterator<4, 5>
drop(3, from(1, 2, 3, 4, 5));
Number → Iterable<a> → AsyncIterator<a>
Yield all but the last n items. note: caches n + 1 items
const { dropLast } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3>
dropLast(2, from([1, 2, 3, 4, 5]));
(a → Promise<Boolean>) → Iterable<a> → AsyncIterator<a>
Drop items until the predicate returns false
const { dropWhile } = require('funk-lib/iterable/async');
// AsyncIterator<5, 6, 1>
dropWhile(async n => (n < 5), from([2, 3, 4, 5, 6, 1]));
Iterable<a> → AsyncIterator<[Integer, a]>
Yield [index, item] pairs
const { enumerate } = require('funk-lib/iterable/async');
// AsyncIterator<[0, 'zero'], [1, 'one'], [2, 'two']>
enumerate(from(['zero', 'one', 'two']));
(a → Promise<Boolean>) → Iterable<a> → Promise<Boolean>
Do all items pass the predicate?
const { every } = require('funk-lib/iterable/async');
// false
await every(async n => (n < 4), from([1, 2, 3, 4]));
Iterable<a> → Promise<undefined>
Yield all items
const { exhaust } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3>
const iterator = from([1, 2, 3]);
// AsyncIterator<>
await exhaust(iterator);
(a → Promise<Boolean>) → Iterable<a> → AsyncIterator<a>
Yield only items that pass the predicate
const { filter } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3, 4>
filter(async n => (n < 5), from([1, 2, 3, 4, 5, 6, 7, 8]));
(a → Promise<Boolean>) → Iterable<a> → Promise<a>
Returns the first item that passes the predicate
const { find } = require('funk-lib/iterable/async');
const records = [{ id: 1 }, { id: 2 }, { id: 3 }];
// { id: 2 }
await find(async record => (record.id === 2), records);
(a → Promise<Boolean>) → Iterable<a> → Promise<Integer>
Returns the first index at which the item passes the predicate
const { findIndex } = require('funk-lib/iterable/async');
const records = [{ id: 1 }, { id: 2 }, { id: 3 }];
// 1
await find(async record => (record.id === 2), records);
(a → Iterable<a>) → a → AsyncIterator<a>
Recursively call a function, yielding items from each resulting iterable
const { flatIterate } = require('funk-lib/iterable/async');
// AsyncIterator<0, 0, 1, 2, 2, 4, 3, 6, 4, 8, ...>
flatIterate(async function* (n) {
yield await n;
yield await (n * 2);
return n + 1;
}, 0));
(a → Iterable<b>) → Iterable<a> → AsyncIterator<b>
Maps a function over an iterable and concatenates the results. a.k.a. "chain"
const { flatMap } = require('funk-lib/iterable/async');
const iterator = from([1, 2, 3]);
// AsyncIterator<1, 2, 2, 4, 3, 6>
flatMap(async function* (n) {
yield await n;
yield await n * 2;
}, iterator);
Iterable<Iterable<a>> → AsyncIterator<a>
Flattens a nested iterable of iterables into a single iterable
const { flatten } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3, 4>
unnest(from([1, [2, [3, [4]]]]));
Number → Iterable<Iterable<a>> → AsyncIterator<a>
Flattens n-levels of a nested iterable of iterables
const { flattenN } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3, [4]>
flattenN(2, from([1, [2, [3, [4]]]]))
(a → Promise<b>) → Iterable<a> → AsyncIterator<a>
Run a function (side-effect) once for each item
const { forEach } = require('funk-lib/iterable/async');
// log 1
// log 2
// log 3
// AsyncIterator<1, 2, 3>
forEach(console.log, from([1, 2, 3]));
Integer → Iterable<a> → AsyncIterator<[a]>
Yield a sliding "window" of length n
. Caches n
items
const { frame } = require('funk-lib/iterable/async');
// AsyncIterator<[0, 1, 2], [1, 2, 3], [2, 3, 4], [4, 5, 6]>
frame(3, from([0, 1, 2, 3, 4, 5, 6]));
Iterable<a> → AsyncIterator<a>
Transforms any iterable into an async iterator
const { from } = require('funk-lib/iterable/async');
from([1, 2, 3]); // AsyncIterator<1, 2, 3>
Iterable<a> → AsyncIterator<[a]>
Yield groups of items where the adjacent items are strictly equal
const { group } = require('funk-lib/iterable/async');
// AsyncIterator<[1, 1, 1], [2, 2], [3]>
group(from([1, 1, 1, 2, 2, 3]));
((a, a) → Promise<Boolean>) → Iterable<a> → AsyncIterator<[a]>
Yield groups of items where the predicate returns truthy for adjacent items
const { groupWith } = require('funk-lib/iterable/async');
// AsyncIterator<[1, 1, 1], [2, 2], [3]>
groupWith(async n => n, from([1, 1, 1, 2, 2, 3]));
Iterable<a> → AsyncIterator<Integer>
Get an iterator of indices (0 to length - 1)
const { indices } = require('funk-lib/iterable/async');
// AsyncIterator<0, 1, 2>
indices(from(['a', 'b', 'c']));
Iterable<a> → AsyncIterator<a>
Yield all but the last item
const { init } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3, 4>
init(from([1, 2, 3, 4, 5]));
a → Iterable<a> → AsyncIterator<a>
Insert an item a
between every item in the iterable
const { intersperse } = require('funk-lib/iterable/async');
// AsyncIterator<'a', '-', 'b', '-', 'c'>
intersperse('-', from('a', 'b', 'c'));
Iterable<a> → Promise<Boolean>
Is an iterable empty? (done or length = 0)
const { isEmpty } = require('funk-lib/iterable/async');
await isEmpty(from([])); // true
await isEmpty(from([1])); // false
(a → Promise<a>) → a → AsyncIterator<a>
Recursively call a function, yielding each result
const { iterate } = require('funk-lib/iterable/async');
// AsyncIterator<0, 2, 4, 6, 8, 10, ...>
iterate(async n => n + 2, 0);
Iterable<a> → Promise<String>
Serialize items to a string
const { join } = require('funk-lib/iterable/async');
// 'abcde'
await join(from(['a', 'b', 'c', 'd', 'e']));
String → Iterable<a> → Promise<String>
Serialize items to a string with an arbitrary spacer
const { joinWith } = require('funk-lib/iterable/async');
// 'some-slug-parts';
await joinWith('-', from(['some', 'slug', 'parts']));
Iterable<a> → Promise<a>
Returns the last item
const { last } = require('funk-lib/iterable/async');
await last(from(1, 2, 3)); // 3
Iterable<a> → Promise<Integer>
Returns the number of items in the iterable. Exhausts input
const { length } = require('funk-lib/iterable/async');
// 5
await length(from([1, 2, 3, 4, 5]));
(a → Promise<b>) → Iterable<a> → AsyncIterator<b>
Apply a function to each yielded item
const { map } = require('funk-lib/iterable/async');
// AsyncIterator<2, 4, 6>
map(async n => n * 2, from([1, 2, 3]));
Iterable<Number> → Promise<Number>
Get the maximumm value
const { max } = require('funk-lib/iterable/async');
await max(from([1, 2, 3])); // 3
(a → Promise<Number>) → Iterable<a> → Promise<Number>
Max by
const { maxBy } = require('funk-lib/iterable/async');
const iterator = from([{ total: 1 }, { total: 2 }, { total: 3 }]);
// 3
await maxBy(R.prop('total'), iterator);
Iterable<Number> → Promise<Number>
Get the minimum value
const { min } = require('funk-lib/iterable/async');
await min(from([1, 2, 3])); // 1
(a → Promise<Number>) → Iterable<a> → Promise<Number>
Min by
const { minBy } = require('funk-lib/iterable/async');
const iterator = from([{ total: 1 }, { total: 2 }, { total: 3 }]);
// 1
await minBy(R.prop('total'), iterator);
Iterable<a> → Promise<a>
Returns the first or "next" item. a.k.a. "head". Throws StopIterationError if empty
const { next } = require('funk-lib/iterable/async');
await next(from([1, 2, 3])); // 1
await next(from([])); // StopIterationError()
a → Iterable<a> → Promise<a>
Return the next item, or a default value if iterable is empty
const { nextOr } = require('funk-lib/iterable/async');
await nextOr(10, from([1, 2, 3])); // 1
await nextOr(10, from([])); // 10
(a → Promise<Boolean>) → Iterable<a> → Promise<Boolean>
Do all items fail the predicate?
const { none } = require('funk-lib/iterable/async');
// true
await none(async n => (n > 5), from([1, 2, 3, 4, 5]));
Integer → Iterable<a> → Promise<a>
Returns the item at the nth index
const { nth } = require('funk-lib/iterable/async');
// 'b'
await nth(1, from(['a', 'b', 'c', 'd']));
...a → AsyncIterator<a>
Create an async iterator from one or more (variadic) arguments
const { of } = require('funk-lib/iterable/async');
of(1, 2, 3); // AsyncIterator<1, 2, 3>
a → Iterable<a> → AsyncIterator<a>
Pad iterable with an infinite number of items a
const { pad } = require('funk-lib/iterable/async');
// AsyncIterator<'a', 'b', 'c', 'd', 'd', 'd', ...>
pad('d', from(['a', 'b', 'c']));
Integer → a → Iterable<a> → AsyncIterator<a>
Pad an iterable with with a finite number of items a
const { padTo } = require('funk-lib/iterable/async');
// AsyncIterator<'a', 'b', 'c', 'd', 'd', 'd'>
padTo(6, 'd', from(['a', 'b', 'c']));
(a → Promise<Boolean>) → Iterable<a> → [AsyncIterator<a>, AsyncIterator<a>]
Split an async iterable into a pair of iterables based on the truthiness of their predicate
const { partition } = require('funk-lib/iterable/async');
// [AsyncIterator<0, 1, 2>, AsyncIterator<3, 4, 5, 6>]
partition(async n => n < 3, from([0, 1, 2, 3, 4, 5, 6]));
a → Iterable<a> → AsyncIterator<a>
Prepends an item a
const { prepend } = require('funk-lib/iterable/async');
// AsyncIterator<0, 1, 2, 3>
prepend(0, from([1, 2, 3]));
Number → Number → AsyncIterator<Number>
Iterates between two numbers. Inclusive start, exclusive stop
const { range } = require('funk-lib/iterable/async');
range(0, 5); // AsyncIterator<0, 1, 2, 3, 4>
Number → Number → Number → AsyncIterator<Number>
Iterates between two numbers with variable step. Inclusive start, exclusive stop
const { rangeStep } = require('funk-lib/iterable/async');
// AsyncIterator<0, 15, 30, 45, 60, 75, 90>
rangeStep(15, 0, 100);
((a, b) → Promise<a>) → a → Iterable<b> → Promise<a>
Reduce all items to a single item
const { reduce } = require('funk-lib/iterable/async');
// 6
await reduce(async (a, b) => a + b, 0, from([1, 2, 3]));
(a → Promise<Boolean>) → Iterable<a> → AsyncIterator<a>
Yield only items that do not pass the predicate
const { reject } = require('funk-lib/iterable/async');
// AsyncIterator<6, 7, 8>
reject(async n => (n < 5), from(1, 2, 3, 4, 5, 6, 7, 8));
a → AsyncIterator<a>
Infinitely yield an item a
const { repeat } = require('funk-lib/iterable/async');
// AsyncIterator<'hi', 'hi', 'hi', ...>
repeat('hi');
Iterable<a> → AsyncIterator<a>
Reverse an iterable. Requires storing all items in memory
const { reverse } = require('funk-lib/iterable/async');
reverse(from([1, 2, 3])); // AsyncIterator<3, 2, 1>
((a, b) → Promise<a>) → a → Iterable<b> → AsyncIterator<a>
Like reduce
, but yields each intermediate result
const { scan } = require('funk-lib/iterable/async');
// AsyncIterator<1, 1, 2, 6, 24>
scan(R.multiply, 1, from([1, 2, 3, 4]));
Integer → Integer → Iterable<a> → AsyncIterator<a>
Slice an iterator between two indices. Inclusive start, exclusive stop
const { slice } = require('funk-lib/iterable/async');
// AsyncIterator<3, 4, 5>
slice(2, 5, from([1, 2, 3, 4, 5, 6, 7, 8]));
(a → Promise<Boolean>) → Iterable<a> → Promise<Boolean>
Does any item pass the predicate?
const { some } = require('funk-lib/iterable/async');
// true
await some(async n => (n > 5), from([1, 2, 3, 4, 5, 6]));
((a, a) → Promise<Number>) → Iterable<a> → AsyncIterator<a>
Sort items. Requires storing all items in memory
const { sort } = require('funk-lib/iterable/async');
// AsyncIterator<'c', 'b', 'a'>
sort(async (a, b) => b.localeCompare(a), from(['a', 'b', 'c']));
Integer → Iterable<a> → [AsyncIterator<a>, AsyncIterator<a>]
Split an async iterable into a pair of iterables at a particular index
const { splitAt } = require('funk-lib/iterable/async');
// [AsyncIterator<0, 1, 2, 3, 4>, AsyncIterator<5, 6>]
splitAt(4, from([0, 1, 2, 3, 4, 5, 6]));
Integer → Iterable<a> → AsyncIterator<[a]>
Yield groups of length n
const { splitEvery } = require('funk-lib/iterable/async');
// AsyncIterator<[0, 1, 2], [3, 4, 5], [6, 7, 8]>
splitEvery(3, from([0, 1, 2, 3, 4, 5, 6, 7, 8]));
Iterable<Number> → Promise<Number>
Sum of all items
const { sum } = require('funk-lib/iterable/async');
await sum(from([1, 2, 3])); // 6
(a → Promise<Number>) → Iterable<a> → Promise<Number>
Sum by
const { sumBy } = require('funk-lib/iterable/async');
const iterator = from([{ total: 1 }, { total: 2 }, { total: 3 }]);
// 6
await sumBy(R.prop('total'), iterator);
Iterable<a> → AsyncIterator<a>
Yield all but the first item
const { tail } = require('funk-lib/iterable/async');
// AsyncIterator<2, 3, 4, 5>
tail(from(1, 2, 3, 4, 5));
Integer → Iterable<a> → AsyncIterator<a>
Yield only the first n
items
const { take } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3>
take(3, from(1, 2, 3, 4, 5));
(a → Promise<Boolean>) → Iterable<a> → AsyncIterator<a>
Yield items until the predicate returns false
const { takeWhile } = require('funk-lib/iterable/async');
// AsyncIterator<2, 3, 4>
takeWhile(async n => (n < 5), from([2, 3, 4, 5, 6, 1]));
Integer → Iterable<a> → [AsyncIterator<a>]
Copy an async iterator n
times. Exhausts input iterators
const { tee } = require('funk-lib/iterable/async');
// [AsyncIterator<1, 2, 3>, AsyncIterator<1, 2, 3>, AsyncIterator<1, 2, 3>]
tee(3, from([1, 2, 3]));
Integer → a → AsyncIterator<a>
Yield an item a
, n
times. a.k.a. "replicate"
const { times } = require('funk-lib/iterable/async');
// AsyncIterator<'hi', 'hi', 'hi', 'hi'>
times(4, 'hi');
Iterable<a> → Promise<[a]>
Resolves an async iterable to an array. Exhausts input iterator
const { toArray } = require('funk-lib/iterable/async');
await toArray(from([1, 2, 3])); // [1, 2, 3]
(a → Promise<[a, a]>) → a → AsyncIterator<a>
Unfold
const { unfold } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 4, 8>
unfold(async n => (n < 10 ? [n, n * 2] : false), 1);
Iterable<a> → AsyncIterator<a>
Drop duplicate items. Duplicates determined by strict equality
const { unique } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, 3, 4>
unique(from([1, 1, 2, 3, 4, 4, 4]));
((a, a) → Promise<Boolean>) → Iterable<a> → AsyncIterator<a>
Drop duplicate items. Duplicates determined by custom comparator
const { uniqueWith } = require('funk-lib/iterable/async');
const records = from([{ id: 1 }, { id: 2 }, { id: 1 }]);
// AsyncIterator<{ id: 1 }, { id: 2 }>
uniqueWith(async (a, b) => (a.id === b.id), records);
Iterable<Iterable<a>> → AsyncIterator<a>
Flattens one level of a nested iterable of iterables
const { unnest } = require('funk-lib/iterable/async');
// AsyncIterator<1, 2, [3, [4]]>
unnest(from([1, [2, [3, [4]]]]));
Iterable<[A, B]> → [AsyncIterator<A>, AsyncIterator<B>]
Transforms an iterable of pairs into a pair of AsyncIterator
const { unzip } = require('funk-lib/iterable/async');
// [AsyncIterator<1, 3, 5>, AsyncIterator<2, 4, 6>]
unzip(from([[1, 2], [3, 4], [5, 6]]));
Number → Iterable<[A, B, ...Z]> → [AsyncIterator<A>, AsyncIterator<B>, ...AsyncIterator<Z>]
Transforms an iterable of n-tuple into an n-tuple of async iterators
const { unzipN } = require('funk-lib/iterable/async');
// [AsyncIterator<1, 4, 7>, AsyncIterator<2, 5, 8>, AsyncIterator<3, 6, 9>]
unzipN(3, from([[1, 2, 3], [4, 5, 6], [7, 8, 9]]));
(a → Promise<b>) → AsyncIterator<a> → Promise<b>
Create coroutines with custom behavior by transforming yielded values and
returning them as the results of the yield. Works with async
and sync
iterators
const { yieldWith } = require('funk-lib/iterable/async');
// arguments arranged fs-last
const readFile = path => fs => fs.readFile(path);
// write filesystem logic without specifying *which* filesystem
const combineFiles = async function* (paths) {
let files = [];
for await (const path of paths) {
files = [...files, yield readFile(path)];
}
return files.join('\n');
}
// mock filesystem
const fs = {
readFile: async file => `I am ${ file }!`,
};
// apply filesystem to each yielded function
// "I am hello.txt!\nI am world.text!"
await yieldWith(fn => fn(fs), combineFiles(['hello.txt', 'world.text']));
Iterable<a> → Iterable<b> → AsyncIterator<[a, b]>
Zips two iterables into pairs of items from corresponding indices of the input iterables. Truncated to shorter of two iterables
const { zip } = require('funk-lib/iterable/async');
// AsyncIterator<[1, 4], [2, 5], [3, 6]>
zip(from([1, 2, 3]), from([4, 5, 6]));
[Iterable<a>, Iterable<b>, Iterable<c>] → AsyncIterator<[a, b, c]>
Zip an array of iterables into an async iterator of arrays of items from corresponding indices of the input iterables
const { zipAll } = require('funk-lib/iterable/async');
// AsyncIterator<[1, 4, 7], [2, 5, 8], [3, 6, 9]>
zipAll([
from([1, 2, 3]),
from([4, 5, 6]),
from([7, 8, 9]),
]);
((...a) → Promise<b>) → [Iterable<a>] → AsyncIterator<b>
Zip multiple async iterators with custom zipping function
const { zipAllWith } = require('funk-lib/iterable/async');
// AsyncIterator<[7, 4, 1], [8, 5, 2], [9, 6, 3]>
zipAllWith(async (a, b, c) => [c, b, a], [
from([1, 2, 3]),
from([4, 5, 6]),
from([7, 8, 9]),
]);
((a, b) → Promise<c>) → Iterable<a> → Iterable<b> → AsyncIterator<c>
Zip two async iterables with a custom zipping function
const { zipWith } = require('funk-lib/iterable/async');
// AsyncIterator<[4, 1], [5, 2], [6, 3]>
zipWith(async (a, b) => [b, a])(from([1, 2, 3]), from([4, 5, 6]));
Zip n
async iterables with a custom zipping function
const { zipWithN } = require('funk-lib/iterable/async');
// AsyncIterator<[4, 1], [5, 2], [6, 3]>
zipWithN(2)(async (a, b) => [b, a])(
from([1, 2, 3]),
from([4, 5, 6]),
);
Functions for working with sync iterables
const { sync } = require('funk-lib/iterable');
a → Iterable<a> → Iterator<a>
Append an item a
const { append } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, 4>
append(4, from([1, 2, 3]));
Iterable<a> → Iterable<a> → Iterator<a>
Concatenate two iterables
const { concat } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, 4, 5, 6>
concat(from([1, 2, 3]), from([4, 5, 6]));
((a, b) → Boolean) → Iterable<a> → Iterable<b> → Boolean
Check if two iterables match at every index as determined by a custom comparator
const { correspondsWith } = require('funk-lib/iterable/sync');
const one = from([{ id: 1 }, { id: 2 }, { id: 3 }]);
const two = from([{ id: 1 }, { id: 2 }, { id: 3 }]);
// true
correspondsWith(R.prop('id'), one, two);
(a → Boolean) → Iterable<a> → Integer
Return the number of items in an iterable. Exhasts the input iterator
const { count } = require('funk-lib/iterable/sync');
// 4
count(n => (n > 3), from([1, 2, 3, 4, 5, 6, 7]));
Iterable<a> → Iterator<a>
Yield iterable items cyclically, infinitely looping when the input is exhausted
const { cycle } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, 1, 2, 3, ...>
cycle(from([1, 2, 3]));
Integer → Iterable<a> → Iterator<a>
Yield all items from an iterable, n
times. Requires caching all items in the iterable
const { cycleN } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 1, 2, 1, 2>
cycleN(3, from([1, 2]));
Integer → Iterable<a> → Iterator<a>
Drop the first n
items
const { drop } = require('funk-lib/iterable/sync');
// Iterator<4, 5>
drop(3, from(1, 2, 3, 4, 5));
Number → Iterable<a> → Iterator<a>
Yield all but the last n items. note: caches n + 1 items
const { dropLast } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3>
dropLast(2, from([1, 2, 3, 4, 5]));
(a → Boolean) → Iterable<a> → Iterator<a>
Drop items until the predicate returns false
const { dropWhile } = require('funk-lib/iterable/sync');
// Iterator<5, 6, 1>
dropWhile(n => (n < 5), from([2, 3, 4, 5, 6, 1]));
Iterable<a> → Iterator<[Integer, a]>
Yield [index, item] pairs
const { enumerate } = require('funk-lib/iterable/sync');
// Iterator<[0, 'zero'], [1, 'one'], [2, 'two']>
enumerate(from(['zero', 'one', 'two']));
(a → Boolean) → Iterable<a> → Boolean
Do all items pass the predicate?
const { every } = require('funk-lib/iterable/sync');
// false
every(n => (n < 4), from([1, 2, 3, 4]));
Iterable<a> → undefined
Yield all items
const { exhaust } = require('funk-lib/iterable/sync');
const iterator = from([1, 2, 3]);
exhaust(iterator);
toArray(iterator); // []
(a → Boolean) → Iterable<a> → Iterator<a>
Yield only items that pass the predicate
const { filter } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, 4>
filter(n => (n < 5), from([1, 2, 3, 4, 5, 6, 7, 8]));
(a → Boolean) → Iterable<a> → a|undefined
Returns the first item that passes the predicate
const { find } = require('funk-lib/iterable/sync');
const records = [{ id: 1 }, { id: 2 }, { id: 3 }];
// { id: 2 }
find(record => (record.id === 2), records);
(a → Boolean) → Iterable<a> → Integer
Returns the first index at which the item passes the predicate
const { findIndex } = require('funk-lib/iterable/sync');
const records = [{ id: 1 }, { id: 2 }, { id: 3 }];
// 1
find(record => (record.id === 2), records);
(a → Iterable<a>) → a → Iterator<a>
Recursively call a function, yielding items from each resulting iterable
const { flatIterate } = require('funk-lib/iterable/sync');
// Iterator<0, 0, 1, 2, 2, 4, 3, 6, 4, 8, ...>
flatIterate(function* (n) {
yield n;
yield (n * 2);
return n + 1;
}, 0));
(a → Iterable<b>) → Iterable<a> → Iterator<b>
Maps a function over an iterable and concatenates the results. a.k.a. "chain"
const { flatMap } = require('funk-lib/iterable/sync');
const iterator = from([1, 2, 3]);
// Iterator<1, 2, 2, 4, 3, 6>
flatMap(function* (n) {
yield n;
yield n * 2;
}, iterator);
Iterable<Iterable<a>> → Iterator<a>
Flattens a nested iterable of iterables into a single iterable
const { flatten } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, 4>
unnest(from([1, [2, [3, [4]]]]));
Number → Iterable<Iterable<a>> → Iterator<a>
Flattens n-levels of a nested iterable of iterables
const { flattenN } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, [4]>
flattenN(2, from([1, [2, [3, [4]]]]))
(a → b) → Iterable<a> → Iterator<a>
Run a function (side-effect) once for each item
const { forEach } = require('funk-lib/iterable/sync');
// log 1
// log 2
// log 3
// Iterator<1, 2, 3>
forEach(console.log, from([1, 2, 3]));
Integer → Iterable<a> → Iterator<[a]>
Yield a sliding "window" of length n
. Caches n
items
const { frame } = require('funk-lib/iterable/sync');
// Iterator<[0, 1, 2], [1, 2, 3], [2, 3, 4], [4, 5, 6]>
frame(3, from([0, 1, 2, 3, 4, 5, 6]));
Iterable<a> → Iterator<a>
Transforms any iterable into an iterator
const { from } = require('funk-lib/iterable/sync');
from([1, 2, 3]); // Iterator<1, 2, 3>
Iterable<a> → Iterator<[a]>
Yield groups of items where the adjacent items are strictly equal
const { group } = require('funk-lib/iterable/sync');
// Iterator<[1, 1, 1], [2, 2], [3]>
group(from([1, 1, 1, 2, 2, 3]));
((a, a) → Boolean) → Iterable<a> → Iterator<[a]>
Yield groups of items where the predicate returns truthy for adjacent items
const { groupWith } = require('funk-lib/iterable/sync');
// Iterator<[1, 1, 1], [2, 2], [3]>
groupWith(n => n, from([1, 1, 1, 2, 2, 3]));
Iterable<a> → Iterator<Integer>
Get an iterator of indices (0 to length - 1)
const { indices } = require('funk-lib/iterable/sync');
// Iterator<0, 1, 2>
indices(from(['a', 'b', 'c']));
Iterable<a> → Iterator<a>
Yield all but the last item
const { init } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, 4>
init(from([1, 2, 3, 4, 5]));
a → Iterable<a> → Iterator<a>
Insert an item a
between every item in the iterable
const { intersperse } = require('funk-lib/iterable/sync');
// Iterator<'a', '-', 'b', '-', 'c'>
intersperse('-', from('a', 'b', 'c'));
Iterable<a> → Boolean
Is an iterable empty? (done or length = 0)
const { isEmpty } = require('funk-lib/iterable/sync');
isEmpty(from([])); // true
isEmpty(from([1])); // false
(a → a) → a → Iterator<a>
Recursively call a function, yielding each result
const { iterate } = require('funk-lib/iterable/sync');
// Iterator<0, 2, 4, 6, 8, 10, ...>
iterate(n => n + 2, 0);
Iterable<a> → String
Serialize items to a string
const { join } = require('funk-lib/iterable/sync');
// 'abcde'
join(from(['a', 'b', 'c', 'd', 'e']));
String → Iterable<a> → String
Serialize items to a string with an arbitrary spacer
const { joinWith } = require('funk-lib/iterable/sync');
// 'some-slug-parts';
joinWith('-', from(['some', 'slug', 'parts']));
Iterable<a> → a
Returns the last item
const { last } = require('funk-lib/iterable/sync');
last(from(1, 2, 3)); // 3
Iterable<a> → Integer
Returns the number of items in the iterable. Exhausts input
const { length } = require('funk-lib/iterable/sync');
// 5
length(from([1, 2, 3, 4, 5]));
(a → b) → Iterable<a> → Iterator<b>
Apply a function to each yielded item
const { map } = require('funk-lib/iterable/sync');
// Iterator<2, 4, 6>
map(n => n * 2, from([1, 2, 3]));
Iterable<Number> → Number
Get the maximumm value
const { max } = require('funk-lib/iterable/sync');
max(from([1, 2, 3])); // 3
(a → Number) → Iterable<a> → Number
Max by
const { maxBy } = require('funk-lib/iterable/sync');
const iterator = from([{ total: 1 }, { total: 2 }, { total: 3 }]);
// 3
maxBy(R.prop('total'), iterator);
Iterable<Number> → Number
Get the minimum value
const { min } = require('funk-lib/iterable/sync');
min(from([1, 2, 3])); // 1
(a → Number) → Iterable<a> → Number
Min by
const { minBy } = require('funk-lib/iterable/sync');
const iterator = from([{ total: 1 }, { total: 2 }, { total: 3 }]);
// 1
minBy(R.prop('total'), iterator);
Iterable<a> → a
Returns the first or "next" item. a.k.a. "head". Throws StopIterationError if empty
const { next } = require('funk-lib/iterable/sync');
next(from([1, 2, 3])); // 1
next(from([])); // StopIterationError()
a → Iterable<a> → a
Return the next item, or a default value if iterable is empty
const { nextOr } = require('funk-lib/iterable/sync');
nextOr(10, from([1, 2, 3])); // 1
nextOr(10, from([])); // 10
(a → Boolean) → Iterable<a> → Boolean
Do all items fail the predicate?
const { none } = require('funk-lib/iterable/sync');
// true
none(n => (n > 5), from([1, 2, 3, 4, 5]));
Integer → Iterable<a> → a|undefined
Returns the item at the nth index
const { nth } = require('funk-lib/iterable/sync');
// 'b'
nth(1, from(['a', 'b', 'c', 'd']));
...a → Iterator<a>
Create an iterator from one or more (variadic) arguments
const { of } = require('funk-lib/iterable/sync');
of(1, 2, 3); // Iterator<1, 2, 3>
a → Iterable<a> → Iterator<a>
Pad iterable with an infinite number of items a
const { pad } = require('funk-lib/iterable/sync');
// Iterator<'a', 'b', 'c', 'd', 'd', 'd', ...>
pad('d', from(['a', 'b', 'c']));
Integer → a → Iterable<a> → Iterator<a>
Pad an iterable with with a finite number of items a
const { padTo } = require('funk-lib/iterable/sync');
// Iterator<'a', 'b', 'c', 'd', 'd', 'd'>
padTo(6, 'd', from(['a', 'b', 'c']));
(a → Boolean) → Iterable<a> → [Iterator<a>, Iterator<a>]
Split an iterable into a pair of iterables based on the truthiness of their predicate
const { partition } = require('funk-lib/iterable/sync');
// [Iterator<0, 1, 2>, Iterator<3, 4, 5, 6>]
partition(n => n < 3, from([0, 1, 2, 3, 4, 5, 6]));
a → Iterable<a> → Iterator<a>
Prepend an item a
const { prepend } = require('funk-lib/iterable/sync');
// Iterator<0, 1, 2, 3>
prepend(0, from([1, 2, 3]));
Number → Number → Iterator<Number>
Iterates between two numbers. Inclusive start, exclusive stop
const { range } = require('funk-lib/iterable/sync');
range(0, 5); // Iterator<0, 1, 2, 3, 4>
Number → Number → Number → Iterator<Number>
Iterates between two numbers with variable step. Inclusive start, exclusive stop
const { rangeStep } = require('funk-lib/iterable/sync');
// Iterator<0, 15, 30, 45, 60, 75, 90>
rangeStep(15, 0, 100);
((a, b) → a) → a → Iterable<b> → a
Reduce all items to a single item
const { reduce } = require('funk-lib/iterable/sync');
// 6
reduce((a, b) => a + b, 0, from([1, 2, 3]));
(a → Boolean) → Iterable<a> → Iterator<a>
Yield only items that do not pass the predicate
const { reject } = require('funk-lib/iterable/sync');
// Iterator<6, 7, 8>
reject(n => (n < 5), from(1, 2, 3, 4, 5, 6, 7, 8));
a → Iterator<a>
Infinitely yield an item a
const { repeat } = require('funk-lib/iterable/sync');
// Iterator<'hi', 'hi', 'hi', ...>
repeat('hi');
Iterable<a> → Iterator<a>
Reverse an iterable. Requires storing all items in memory
const { reverse } = require('funk-lib/iterable/sync');
reverse(from([1, 2, 3])); // Iterator<3, 2, 1>
((a, b) → a) → a → Iterable<b> → Iterator<a>
Like reduce
, but yields each intermediate result
const { scan } = require('funk-lib/iterable/sync');
// Iterator<1, 1, 2, 6, 24>
scan(R.multiply, 1, from([1, 2, 3, 4]));
Integer → Integer → Iterable<a> → Iterator<a>
Slice an iterator between two indices. Inclusive start, exclusive stop
const { slice } = require('funk-lib/iterable/sync');
// Iterator<3, 4, 5>
slice(2, 5, from([1, 2, 3, 4, 5, 6, 7, 8]));
((a, a) → Number) → Iterable<a> → Iterator<a>
Sort items. Requires storing all items in memory
const { sort } = require('funk-lib/iterable/sync');
// Iterator<'c', 'b', 'a'>
sort((a, b) => b.localeCompare(a), from(['a', 'b', 'c']));
Integer → Iterable<a> → [Iterator<a>, Iterator<a>]
Split an iterable into a pair of iterables at a particular index
const { splitAt } = require('funk-lib/iterable/sync');
// [Iterator<0, 1, 2, 3, 4>, Iterator<5, 6>]
splitAt(4, from([0, 1, 2, 3, 4, 5, 6]));
Integer → Iterable<a> → Iterator<[a]>
Yield groups of length n
const { splitEvery } = require('funk-lib/iterable/sync');
// Iterator<[0, 1, 2], [3, 4, 5], [6, 7, 8]>
splitEvery(3, from([0, 1, 2, 3, 4, 5, 6, 7, 8]));
Iterable<Number> → Number
Sum of all items
const { sum } = require('funk-lib/iterable/sync');
sum(from([1, 2, 3])); // 6
(a → Number) → Iterable<a> → Number
Sum by
const { sumBy } = require('funk-lib/iterable/sync');
const iterator = from([{ total: 1 }, { total: 2 }, { total: 3 }]);
// 6
sumBy(R.prop('total'), iterator);
Iterable<a> → Iterator<a>
Yield all but the first item
const { tail } = require('funk-lib/iterable/sync');
// Iterator<2, 3, 4, 5>
tail(from(1, 2, 3, 4, 5));
Integer → Iterable<a> → Iterator<a>
Yield only the first n
items
const { take } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3>
take(3, from(1, 2, 3, 4, 5));
(a → Boolean) → Iterable<a> → Iterator<a>
Take while
const { takeWhile } = require('funk-lib/iterable/sync');
// Iterator<2, 3, 4>
takeWhile(n => (n < 5), from([2, 3, 4, 5, 6, 1]));
Integer → Iterable<a> → [Iterator<a>]
Copy an iterator n
times. Exhausts input iterators
const { tee } = require('funk-lib/iterable/sync');
// [Iterator<1, 2, 3>, Iterator<1, 2, 3>, Iterator<1, 2, 3>]
tee(3, from([1, 2, 3]));
Integer → a → Iterator<a>
Yield an item a
, n
times. a.k.a. "replicate"
const { times } = require('funk-lib/iterable/sync');
// Iterator<'hi', 'hi', 'hi', 'hi'>
times(4, 'hi');
Iterable<a> → [a]
Resolves an iterable to an array. Exhausts input iterator
const { toArray } = require('funk-lib/iterable/sync');
toArray(from([1, 2, 3])); // [1, 2, 3]
(a → [a, a]) → a → Iterator<a>
Unfold
const { unfold } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 4, 8>
unfold(n => (n < 10 ? [n, n * 2] : false), 1);
Iterable<a> → Iterator<a>
Drop duplicate items. Duplicates determined by strict equality
const { unique } = require('funk-lib/iterable/sync');
// Iterator<1, 2, 3, 4>
unique(from([1, 1, 2, 3, 4, 4, 4]));
((a, a) → Boolean) → Iterable<a> → Iterator<a>
Drop duplicate items. Duplicates determined by custom comparator
const { uniqueWith } = require('funk-lib/iterable/sync');
const records = from([{ id: 1 }, { id: 2 }, { id: 1 }]);
// Iterator<{ id: 1 }, { id: 2 }>
uniqueWith((a, b) => (a.id === b.id), records);
Iterable<Iterable<a>> → Iterator<a>
Flattens one level of a nested iterable of iterables
const { unnest } = require('funk-lib/iterable/sync');
// Iterator<1, 2, [3, [4]]>
unnest(from([1, [2, [3, [4]]]]));
Iterable<[A, B]> → [Iterator<A>, Iterator<B>]
Transforms an iterable of pairs into a pair of iterators
const { unzip } = require('funk-lib/iterable/sync');
// [Iterator<1, 3, 5>, Iterator<2, 4, 6>]
unzip(from([[1, 2], [3, 4], [5, 6]]));
Number → Iterable<[A, B, ...Z]> → [Iterator<A>, Iterator<B>, ...Iterator<Z>]
Transforms an iterable of n-tuple into an n-tuple of iterators
const { unzipN } = require('funk-lib/iterable/sync');
// [AsyncIterator<1, 4, 7>, AsyncIterator<2, 5, 8>, AsyncIterator<3, 6, 9>]
unzipN(3, from([[1, 2, 3], [4, 5, 6], [7, 8, 9]]));
(a → b) → Iterator<a> → b
Create coroutines with custom behavior by transforming yielded values and returning them as the results of the yield
const { yieldWith } = require('funk-lib/iterable/sync');
// arguments arranged fs-last
const readFile = path => fs => fs.readFile(path);
// write filesystem logic without specifying *which* filesystem
const combineFiles = function* (paths) {
let files = [];
for await (const path of paths) {
files = [...files, yield readFile(path)];
}
return files.join('\n');
}
// mock filesystem
const fs = {
readFile: file => `I am ${ file }!`,
};
// apply filesystem to each yielded function
// "I am hello.txt!\nI am world.text!"
yieldWith(fn => fn(fs), combineFiles(['hello.txt', 'world.text']));
Iterable<a> → Iterable<b> → Iterator<[a, b]>
Zips two iterables into pairs of items from corresponding indices of the input iterables. Truncated to shorter of two iterables
const { zip } = require('funk-lib/iterable/sync');
// Iterator<[1, 4], [2, 5], [3, 6]>
zip(from([1, 2, 3]), from([4, 5, 6]));
[Iterable<a>, Iterable<b>, Iterable<c>] → Iterator<[a, b, c]>
Zip an array of iterables into an async iterator of arrays of items from corresponding indices of the input iterables
const { zipAll } = require('funk-lib/iterable/sync');
// Iterator<[1, 4, 7], [2, 5, 8], [3, 6, 9]>
zipAll([
from([1, 2, 3]),
from([4, 5, 6]),
from([7, 8, 9]),
]);
((...a) → Promise<b>) → [Iterable<a>] → Iterator<b>
Zip multiple iterators with custom zipping function
const { zipAllWith } = require('funk-lib/iterable/sync');
// Iterator<[7, 4, 1], [8, 5, 2], [9, 6, 3]>
zipAllWith((a, b, c) => [c, b, a], [
from([1, 2, 3]),
from([4, 5, 6]),
from([7, 8, 9]),
]);
((a, b) → Promise<c>) → Iterable<a> → Iterable<b> → Iterator<c>
Zip two iterables with a custom zipping function
const { zipWith } = require('funk-lib/iterable/sync');
// Iterator<[4, 1], [5, 2], [6, 3]>
zipWith((a, b) => [b, a])(from([1, 2, 3]), from([4, 5, 6]));
Zip n
iterables with a custom zipping function
const { zipWithN } = require('funk-lib/iterable/sync');
// Iterator<[4, 1], [5, 2], [6, 3]>
zipWithN(2)((a, b) => [b, a])(
from([1, 2, 3]),
from([4, 5, 6]),
);
Functions for working with Number
const { number } = require('funk-lib');
Number → Number → Integer
Get a random integer between two inclusive bounds
const { random } = require('funk-lib/number');
random(0, 100); // 42
Number → Number → Float
Get a random float between two inclusive bounds
const { randomFloat } = require('funk-lib/number');
randomFloat(0, 100); // 42.38076848431584
Functions for working with Object
const { object } = require('funk-lib');
{a} → {}
Delete all object properties. Mutating + identity
const { clear } = require('funk-lib/object');
const obj = { a: 1, b: 2 };
clear(obj); // obj === {}
{*} → {*}
Recursive freeze a nested object. Mutating + identity
const { deepFreeze } = require('funk-lib/object');
const obj = { a: 1 };
deepFreeze(obj); // { a: 1 }
obj.a = 2; // TypeError
String → {a} → {a}
Delete an object property. Mutating + identity
const { del } = require('funk-lib/object');
const obj = { a: 1, b: 2 };
del('a', obj); // obj === { b: 2 }
{ k: v } → k
Get an object's first key
const { firstKey } = require('funk-lib/object');
firstKey({ a: 1 }); // 'a'
{ k: v } → [k, v]
Get an object's first [key, value] pair
const { firstPair } = require('funk-lib/object');
firstPair({ a: 1 }); // ['a', 1]
{ k: v } → v
Get an object's first value
const { firstValue } = require('funk-lib/object');
firstValue({ a: 1 }); // 1
((k, k) → l) → { k: v } → { l: v }
Flatten a deeply nested object, joining keys with with a binary function. Inverse of object/nestWith
const { flattenWith } = require('funk-lib/object');
// { 'src/one': 1, 'src/two/three': 3 }
flattenWith(R.unapply(R.join('/')), { src: { one: 1, two: { three: 3 } } });
{a} -> Boolean
Is an object empty?
const { isEmpty } = require('funk-lib/object');
isEmpty({}); // true
(a → b) → { k: a } → { k: b }
Recursively map a deep object's leaf nodes
const { mapDeep } = require('funk-lib/object');
// { a: { b: 2, c: { d: 3 } } }
mapDeep(n => (n + 1), { a: { b: 1, c: { d: 2 } } });
(k → k) → { k: v } → { k: v }
Map object keys
const { mapKeys } = require('funk-lib/object');
mapKeys(R.reverse, { one: 1, two: 2 }); // { eno: 1, owt: 2 }
([a, b] → [c, d]) → { a: b } → { c: d }
Map object key / value pairs
const { mapPairs } = require('funk-lib/object');
mapPairs(R.reverse, { a: 1, b: 2 }); // { 1: 'a', 2: 'b' }
(k → [l]) → { k: v } → { l: v }
Deeply nest a flattened object, splitting keys with a unary function. Inverse of object/flattenWith
const { nestWith } = require('funk-lib/object');
// { src: { one: 1, two: { three: 3 } } }
nestWith(R.split('/'), { 'src/one': 1, 'src/two/three': 3 });
{ k: w } → { k: v } → { w: v }
Pick and rename object keys in a single operation
const { pickAs } = require('funk-lib/object');
// { b: 1, c: 2 }
pickAs({ a: 'b', b: 'c' }, { a: 1, b: 2 });
JSON → String
Serialize to JSON with newlines and 2-space indentation
const { toHumanJSON } = require('funk-lib/object');
// '{
// "one": {
// "two": 2
// }
// }'
toHumanJSON({ one: { two: 2 } });
Functions for working with Process
const { process } = require('funk-lib');
On SIGINT
const { onSigInt } = require('funk-lib/process');
const offSigInt = onSigInt(_ => {
console.log('SIGINT');
offSigInt(); // unsubscribe
});
Functions for working with Stream
const { stream } = require('funk-lib');
Iterable<a> → Stream<a>
Readable stream from iterable
const { from } = require('funk-lib/stream');
from([1, 2, 3]); // ReadableStream<1, 2, 3>
String → Stream<String>
String to stream
const { fromString } = require('funk-lib/stream');
fromString('hello'); // ReadableStream<'hello'>
Stream<String> → String
Stream to string
const { toString } = require('funk-lib/stream');
await toString(from(['a', 'b', 'c'])); // 'abc'
Functions for working with String
const { string } = require('funk-lib');
String → String
Capitalize the first letter of a string
const { capitalize } = require('funk-lib/string');
capitalize('hello'); // 'Hello'
String → String
Escape a string for use with the RegExp
constructor
const { escapeRegExpStr } = require('funk-lib/string');
const rx = '^a';
new RegExp(escapeRegExpStr(rx)).test('a'); // false
new RegExp(rx).test('a'); // true
String → String → Number
Locale compare
const { localeCompare } = require('funk-lib/string');
localeCompare('b', 'a'); // -1
String → String
Decode a string from base64
const { parseBase64 } = require('funk-lib/string');
parseBase64('aGVsbG8='); // 'hello'
String → String
Slugify a string
const { slugify } = require('funk-lib/string');
slugify('Hello World!'); // 'hello-world'
String → {*} → String
String interpolation. Reasonably similar to JavaScript template literals.
const { template } = require('funk-lib/string');
// 'Hello Pat!'
template('Hello ${ name }!', { name: 'Pat' });
String → String
Encode a string to base64
const { toBase64 } = require('funk-lib/string');
toBase64('hello'); // 'aGVsbG8='
String → String
Lowercase the first letter of a string
const { uncapitalize } = require('funk-lib/string');
uncapitalize('FooBar'); // 'fooBar'
Functions for working with urls, and querystrings
const { url } = require('funk-lib');
a → Boolean
Is a string a data url
const { isDataUrl } = require('funk-lib/url');
isDataUrl('data:,Hello%2C%20World!'); // true
isDataUrl('https://foo.bar'); // false
String → { mediatype, data, base64 }
Parse a data url into its parts
const { parseDataUrl } = require('funk-lib/url');
// {
// base64: true,
// data: 'eyJ0ZXN0IjoidGV4dCJ9',
// mediatype: 'application/json',
// }
parseDataUrl('data:application/json;base64,eyJ0ZXN0IjoidGV4dCJ9');
Functions for working with UUIDs
const { uuid } = require('funk-lib');
a → Boolean
Is UUID v4?
const { isUuid } = require('funk-lib/uuid');
isUuid('c4f2e775-a5f9-4796-bd31-46e544bfab06'); // true
a → String
Random UUID v4
const { uuid } = require('funk-lib/uuid');
uuid(); // 'c4f2e775-a5f9-4796-bd31-46e544bfab06'