funk-lib

ci npm module

FP for Vanilla JavaScript

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

Features

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

Install

npm i -P funk-lib
# or: es-module compatible build
npm i -P funk-lib-es

Import

const { mapKeys } = require('funk-lib/object');
// or: es-module compatible build
import { mapKeys } from 'funk-lib-es/object';

Development

Commands

$ 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
array

array

code

Functions for working with Array

const { array } = require('funk-lib');
array.clear

array/clear

code
[a] → []

Delete all items. Mutating + identity

const { clear } = require('funk-lib/array');

const arr = [1, 2, 3];
clear(arr); // arr === []
array.sample

array/sample

code
[a] → a

Select a random array item

const { sample } = require('funk-lib/array');

sample([0, 1, 2, 3, 4, 5]); // 2
array.shuffle

array/shuffle

code
[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]
array.toObj

array/toObj

code
[ 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 }
async

async

code

Functions for working with promises, async + await, and parallelism

const { async } = require('funk-lib');
async.all

async/all

code
[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),
]);
async.allSettled

async/allSettled

code
[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')),
]);
async.callbackify

async/callbackify

code

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
});
async.defer

async/defer

code
(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
async.deferWith

async/deferWith

code
[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
async.deferred

async/deferred

code
* → Object

Creates an externally controlled promise

const { deferred } = require('funk-lib/async');

const { promise, resolve, reject } = deferred();
resolve(123);
await promise; // 123
async.delay

async/delay

code
Number → Promise<undefined>

Creates a promise that resolves in n ms

const { delay } = require('funk-lib/async');

await delay(100); // resolved in 100ms
async.every

async/every

code
(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]);
async.everyLimit

async/everyLimit

code
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]);
async.everySeries

async/everySeries

code
(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]);
async.evolve

async/evolve

code
{ 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);
async.filter

async/filter

code
(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);
async.filterLimit

async/filterLimit

code
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]);
async.filterSeries

async/filterSeries

code
(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);
async.find

async/find

code
(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);
async.findLimit

async/findLimit

code
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);
async.findSeries

async/findSeries

code
(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);
async.flatMap

async/flatMap

code
(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]);
async.flatMapLimit

async/flatMapLimit

code
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]);
async.flatMapPairs

async/flatMapPairs

code
([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 });
async.flatMapPairsLimit

async/flatMapPairsLimit

code
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 });
async.flatMapPairsSeries
([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 });
async.flatMapSeries

async/flatMapSeries

code
(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]);
async.forEach

async/forEach

code
(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]);
async.forEachLimit

async/forEachLimit

code
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]);
async.forEachSeries

async/forEachSeries

code
(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]);
async.fromCallback

async/fromCallback

code

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')
async.map

async/map

code
(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);
async.mapLimit

async/mapLimit

code
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]);
async.mapPairs

async/mapPairs

code
([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 });
async.mapPairsLimit

async/mapPairsLimit

code
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 });
async.mapPairsSeries

async/mapPairsSeries

code
([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 });
async.mapSeries

async/mapSeries

code
(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);
async.pipe

async/pipe

code
(...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);
async.pipeC

async/pipeC

code
(...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;
async.promisify

async/promisify

code

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
async.props

async/props

code
{ 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),
});
async.race

async/race

code
[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') }),
]);
async.reduce

async/reduce

code
((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]);
async.reject

async/reject

code
Error → Promise<Error>

Create a rejected promise

const { reject } = require('funk-lib/async');

// Promise<Error('oops')>
reject(Error('oops'));
async.resolve

async/resolve

code
a → Promise<a>

Create a resolved promise

const { resolve } = require('funk-lib/async');

// Promise<1>
resolve(1);
async.retryWith

async/retryWith

code
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');
async.some

async/some

code
(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]);
async.someLimit

async/someLimit

code
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]);
async.someSeries

async/someSeries

code
(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]);
async.timeout

async/timeout

code
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
async.toAsync

async/toAsync

code
(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>
color

color

code

Functions for generating and transforming colors

const { color } = require('funk-lib');
color.hexToHsl

color/hexToHsl

code
String → { h, s, l }

Hex to HSL

const { hexToHsl } = require('funk-lib/color');
color.hexToRgb

color/hexToRgb

code
String → { r, g, b }

Hex to RGB

const { hexToRgb } = require('funk-lib/color');
color.hslToHex

color/hslToHex

code
{ h, s, l } → String

HSL to hex

const { hslToHex } = require('funk-lib/color');
color.hslToRgb

color/hslToRgb

code
{ h, s, l } → { r, g, b }

HSL to RGB

const { hslToRgb } = require('funk-lib/color');
color.randomHex

color/randomHex

code
* → String

Get a random hex string

const { randomHex } = require('funk-lib/color');

randomHex(); // #b3a95a
color.randomHsl

color/randomHsl

code
* → { h, s, l }

Get a random HSL value

const { randomHsl } = require('funk-lib/color');
color.randomRgb

color/randomRgb

code
* → { r, g, b }

Get a random RGB value

const { randomRgb } = require('funk-lib/color');

randomRgb(); // { r: 35, g: 125, b: 106 }
color.rgbToHex

color/rgbToHex

code
{ r, g, b } → String

RGB to hex

const { rgbToHex } = require('funk-lib/color');
color.rgbToHsl

color/rgbToHsl

code
{ r, g, b } → { h, s, l }

RGB to HSL

const { rgbToHsl } = require('funk-lib/color');
crypto

crypto

code

Functions for cryptography

const { crypto } = require('funk-lib');
crypto.hashWith

crypto/hashWith

code
String → String → String

Hash with variable algorithm

const { hashWith } = require('funk-lib/crypto');

hashWith('md5', 'hello'); // '5d41402abc4b2a76b9719d911017c592'
crypto.md5

crypto/md5

code
String → String

md5 hash a string

const { md5 } = require('funk-lib/crypto');

md5('hello'); // '5d41402abc4b2a76b9719d911017c592'
crypto.sha256

crypto/sha256

code
String → String

sha256 hash a string

const { sha256 } = require('funk-lib/crypto');

sha256('hello'); // '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
crypto.sha512

crypto/sha512

code
String → String

sha512 hash a string

const { sha512 } = require('funk-lib/crypto');

sha512('hello'); // 'E7C22B994C59D9CF2B48E549B1E24666636045930D3DA7C1ACB299D1C3B7F931F94AAE41EDDA2C2B207A36E10F8BCB8D45223E54878F5B316E7CE3B6BC019629'
datetime

datetime

code

Functions for date and time

const { datetime } = require('funk-lib');
datetime.now

datetime/now

code
a → Date

Get the current unix epoch (in ms)

const { now } = require('funk-lib/datetime');
function

function

code

Functions for working with Function

const { function } = require('funk-lib');
function.Y

function/Y

code
((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
function.debounce

function/debounce

code
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);
function.noop

function/noop

code
a → undefined

A function that does nothing. "no-op"

const { noop } = require('funk-lib/function');

noop(); // undefined
function.on

function/on

code
(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);
function.once

function/once

code
(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)
function.pipeC

function/pipeC

code
...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;
function.throttle

function/throttle

code
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);
http

http

code

Functions for working with HTTP interfaces

const { http } = require('funk-lib');
http.parseContentType

http/parseContentType

code
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');
is

is

code

Functions for typechecking

const { is } = require('funk-lib');
is.is

is/is

code
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
is.isArray

is/isArray

code
a → Boolean

Is a value an Array?

const { isArray } = require('funk-lib/is');

isArray([]); // true
is.isAsyncIterable

is/isAsyncIterable

code
a → Boolean

Is a value an async iterable?

const { isAsyncIterable } = require('funk-lib/is');

isAsyncIterable((async function* () {})()); // true
isAsyncIterable({ [Symbol.asyncIterator]: () => {} }); // true
is.isBoolean

is/isBoolean

code
a → Boolean

Is a value a Boolean?

const { isBoolean } = require('funk-lib/is');

isBoolean(false); // true
is.isBuffer

is/isBuffer

code
a → Boolean

Is a value a Buffer?

const { isBuffer } = require('funk-lib/is');

isBuffer(Buffer.from([])); // true
is.isDate

is/isDate

code
a → Boolean

Is a value a Date?

const { isDate } = require('funk-lib/is');

isDate(new Date()); // true
is.isEven

is/isEven

code
a → Boolean

Is a value even?

const { isEven } = require('funk-lib/is');

isEven(2); // true
isEven(3); // false
is.isFalsey

is/isFalsey

code
a → Boolean

Is a value falsey?

const { isFalsey } = require('funk-lib/is');

isFalsey(0); // true
is.isFinite

is/isFinite

code
a → Boolean

Is a value finite?

const { isFinite } = require('funk-lib/is');

isFinite(10); // true
isFinite(Infinity); // false
is.isFloat

is/isFloat

code
a → Boolean

Is a value a float?

const { isFloat } = require('funk-lib/is');

isFloat(1.23); // true
isFloat(1); // false
is.isFunction

is/isFunction

code
a → Boolean

Is a value a function?

const { isFunction } = require('funk-lib/is');

isFunction(() => {}); // true
is.isInstanceOf

is/isInstanceOf

code
String → a → Boolean

Is a value an instance of a class?

const { isInstanceOf } = require('funk-lib/is');

isInstanceOf(Array, []); // true
is.isInteger

is/isInteger

code
a → Boolean

Is a value an integer?

const { isInteger } = require('funk-lib/is');

isInteger(1); // true
isInteger(1.23); // false
is.isIterable

is/isIterable

code
a → Boolean

Is a value an iterable?

const { isIterable } = require('funk-lib/is');

isIterable([]); // true
isIterable({ [Symbol.iterator]: () => {} }); // true
is.isIterator

is/isIterator

code
a → Boolean

Is a value an iterator?

const { isIterator } = require('funk-lib/is');

const iterator = [][Symbol.iterator]();
isIterator(iterator); // true
is.isNaN

is/isNaN

code
a → Boolean

Is a value NaN?

const { isNaN } = require('funk-lib/is');

isNaN(NaN); // true
is.isNegative

is/isNegative

code
a → Boolean

Is a value negative?

const { isNegative } = require('funk-lib/is');

isNumber(-10); // true
isNumber(10); // false
is.isNot

is/isNot

code
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
is.isNull

is/isNull

code
a → Boolean

Is a value null?

const { isNull } = require('funk-lib/is');

isNull(null); // true
is.isNumber

is/isNumber

code
a → Boolean

Is a value a number?

const { isNumber } = require('funk-lib/is');

isNumber(10); // true
isNumber(NaN); // false
is.isObject

is/isObject

code
a → Boolean

Is a value an object?

const { isObject } = require('funk-lib/is');

isObject({}); // true
isObject([]]); // false
isObject(null); // false
is.isOdd

is/isOdd

code
a → Boolean

Is a value odd?

const { isOdd } = require('funk-lib/is');

isOdd(1); // true
isOdd(2); // false
is.isPojo

is/isPojo

code
a → Boolean

Is a value a "plain old javascript object"?

const { isPojo } = require('funk-lib/is');

isPojo({}); // true
is.isPositive

is/isPositive

code
a → Boolean

Is a value positive?

const { isPositive } = require('funk-lib/is');

isNumber(10); // true
isNumber(-10); // false
is.isPromise

is/isPromise

code
a → Boolean

Is a value a promise?

const { isPromise } = require('funk-lib/is');

isPromise(Promise.resolve(1)); // true
is.isRegExp

is/isRegExp

code
a → Boolean

Is a value a regular expression?

const { isRegExp } = require('funk-lib/is');

isRegExp(/[a-z]/); // true
is.isStream

is/isStream

code
a → Boolean

Is a value a stream?

const { isStream } = require('funk-lib/is');

isStream(new Stream.Readable()); // true
is.isString

is/isString

code
a → Boolean

Is a value a string?

const { isString } = require('funk-lib/is');

isString('hello'); // true
is.isSymbol

is/isSymbol

code
a → Boolean

Is a value a symbol?

const { isSymbol } = require('funk-lib/is');

isSymbol(Symbol('foo')); // true
is.isThenable

is/isThenable

code
a → Boolean

Is a value a "thenable"?

const { isThenable } = require('funk-lib/is');

isThenable({ then: _ => {} }); // true
is.isTruthy

is/isTruthy

code
a → Boolean

Is a value truthy?

const { isTruthy } = require('funk-lib/is');

isTruthy(1); // true
is.isTypeOf

is/isTypeOf

code
String → a → Boolean

Does a value have a certin type (via typeof)?

const { isTypeOf } = require('funk-lib/is');

isTypeOf('boolean', true); // true
is.isUndefined

is/isUndefined

code
a → Boolean

Is a value undefined?

const { isUndefined } = require('funk-lib/is');

isUndefined(undefined); // true
iterable

iterable

code

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');
iterable.async

iterable/async

code

Functions for working with async iterables

const { async } = require('funk-lib/iterable');
iterable.async.append

iterable/async/append

code
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.async.concat

iterable/async/concat

code
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]));
iterable.async.correspondsWith
((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);
iterable.async.count

iterable/async/count

code
(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.async.cycle

iterable/async/cycle

code
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]));
iterable.async.cycleN

iterable/async/cycleN

code
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]));
iterable.async.drop

iterable/async/drop

code
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));
iterable.async.dropLast

iterable/async/dropLast

code
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]));
iterable.async.dropWhile
(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.async.enumerate
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']));
iterable.async.every

iterable/async/every

code
(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.async.exhaust

iterable/async/exhaust

code
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);
iterable.async.filter

iterable/async/filter

code
(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]));
iterable.async.find

iterable/async/find

code
(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);
iterable.async.findIndex
(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);
iterable.async.flatIterate
(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));
iterable.async.flatMap

iterable/async/flatMap

code
(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.async.flatten

iterable/async/flatten

code
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]]]]));
iterable.async.flattenN

iterable/async/flattenN

code
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]]]]))
iterable.async.forEach

iterable/async/forEach

code
(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]));
iterable.async.frame

iterable/async/frame

code
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.async.from

iterable/async/from

code
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.async.group

iterable/async/group

code
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]));
iterable.async.groupWith
((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.async.indices

iterable/async/indices

code
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.async.init

iterable/async/init

code
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]));
iterable.async.intersperse
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.async.isEmpty

iterable/async/isEmpty

code
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
iterable.async.iterate

iterable/async/iterate

code
(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.async.join

iterable/async/join

code
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']));
iterable.async.joinWith

iterable/async/joinWith

code
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.async.last

iterable/async/last

code
Iterable<a> → Promise<a>

Returns the last item

const { last } = require('funk-lib/iterable/async');

await last(from(1, 2, 3)); // 3
iterable.async.length

iterable/async/length

code
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]));
iterable.async.map

iterable/async/map

code
(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.async.max

iterable/async/max

code
Iterable<Number> → Promise<Number>

Get the maximumm value

const { max } = require('funk-lib/iterable/async');

await max(from([1, 2, 3])); // 3
iterable.async.maxBy

iterable/async/maxBy

code
(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.async.min

iterable/async/min

code
Iterable<Number> → Promise<Number>

Get the minimum value

const { min } = require('funk-lib/iterable/async');

await min(from([1, 2, 3])); // 1
iterable.async.minBy

iterable/async/minBy

code
(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.async.next

iterable/async/next

code
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()
iterable.async.nextOr

iterable/async/nextOr

code
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
iterable.async.none

iterable/async/none

code
(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]));
iterable.async.nth

iterable/async/nth

code
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']));
iterable.async.of

iterable/async/of

code
...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>
iterable.async.pad

iterable/async/pad

code
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']));
iterable.async.padTo

iterable/async/padTo

code
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']));
iterable.async.partition
(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]));
iterable.async.prepend

iterable/async/prepend

code
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]));
iterable.async.range

iterable/async/range

code
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>
iterable.async.rangeStep
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);
iterable.async.reduce

iterable/async/reduce

code
((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]));
iterable.async.reject

iterable/async/reject

code
(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));
iterable.async.repeat

iterable/async/repeat

code
a → AsyncIterator<a>

Infinitely yield an item a

const { repeat } = require('funk-lib/iterable/async');

// AsyncIterator<'hi', 'hi', 'hi', ...>
repeat('hi');
iterable.async.reverse

iterable/async/reverse

code
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>
iterable.async.scan

iterable/async/scan

code
((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]));
iterable.async.slice

iterable/async/slice

code
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]));
iterable.async.some

iterable/async/some

code
(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]));
iterable.async.sort

iterable/async/sort

code
((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']));
iterable.async.splitAt

iterable/async/splitAt

code
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]));
iterable.async.splitEvery
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.async.sum

iterable/async/sum

code
Iterable<Number> → Promise<Number>

Sum of all items

const { sum } = require('funk-lib/iterable/async');

await sum(from([1, 2, 3])); // 6
iterable.async.sumBy

iterable/async/sumBy

code
(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.async.tail

iterable/async/tail

code
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));
iterable.async.take

iterable/async/take

code
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));
iterable.async.takeWhile
(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]));
iterable.async.tee

iterable/async/tee

code
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]));
iterable.async.times

iterable/async/times

code
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.async.toArray

iterable/async/toArray

code
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]
iterable.async.unfold

iterable/async/unfold

code
(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.async.unique

iterable/async/unique

code
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]));
iterable.async.uniqueWith
((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.async.unnest

iterable/async/unnest

code
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.async.unzip

iterable/async/unzip

code
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]]));
iterable.async.unzipN

iterable/async/unzipN

code
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]]));
iterable.async.yieldWith
(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.async.zip

iterable/async/zip

code
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.async.zipAll

iterable/async/zipAll

code
[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]),
]);
iterable.async.zipAllWith
((...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]),
]);
iterable.async.zipWith

iterable/async/zipWith

code
((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]));
iterable.async.zipWithN

iterable/async/zipWithN

code

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]),
);
iterable.sync

iterable/sync

code

Functions for working with sync iterables

const { sync } = require('funk-lib/iterable');
iterable.sync.append

iterable/sync/append

code
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.sync.concat

iterable/sync/concat

code
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]));
iterable.sync.correspondsWith
((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);
iterable.sync.count

iterable/sync/count

code
(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.sync.cycle

iterable/sync/cycle

code
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]));
iterable.sync.cycleN

iterable/sync/cycleN

code
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]));
iterable.sync.drop

iterable/sync/drop

code
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));
iterable.sync.dropLast

iterable/sync/dropLast

code
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]));
iterable.sync.dropWhile

iterable/sync/dropWhile

code
(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.sync.enumerate

iterable/sync/enumerate

code
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']));
iterable.sync.every

iterable/sync/every

code
(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.sync.exhaust

iterable/sync/exhaust

code
Iterable<a> → undefined

Yield all items

const { exhaust } = require('funk-lib/iterable/sync');

const iterator = from([1, 2, 3]);
exhaust(iterator);
toArray(iterator); // []
iterable.sync.filter

iterable/sync/filter

code
(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]));
iterable.sync.find

iterable/sync/find

code
(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);
iterable.sync.findIndex

iterable/sync/findIndex

code
(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);
iterable.sync.flatIterate
(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));
iterable.sync.flatMap

iterable/sync/flatMap

code
(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.sync.flatten

iterable/sync/flatten

code
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]]]]));
iterable.sync.flattenN

iterable/sync/flattenN

code
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]]]]))
iterable.sync.forEach

iterable/sync/forEach

code
(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]));
iterable.sync.frame

iterable/sync/frame

code
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.sync.from

iterable/sync/from

code
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.sync.group

iterable/sync/group

code
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]));
iterable.sync.groupWith

iterable/sync/groupWith

code
((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.sync.indices

iterable/sync/indices

code
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.sync.init

iterable/sync/init

code
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]));
iterable.sync.intersperse
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.sync.isEmpty

iterable/sync/isEmpty

code
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
iterable.sync.iterate

iterable/sync/iterate

code
(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.sync.join

iterable/sync/join

code
Iterable<a> → String

Serialize items to a string

const { join } = require('funk-lib/iterable/sync');

// 'abcde'
join(from(['a', 'b', 'c', 'd', 'e']));
iterable.sync.joinWith

iterable/sync/joinWith

code
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.sync.last

iterable/sync/last

code
Iterable<a> → a

Returns the last item

const { last } = require('funk-lib/iterable/sync');

last(from(1, 2, 3)); // 3
iterable.sync.length

iterable/sync/length

code
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]));
iterable.sync.map

iterable/sync/map

code
(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.sync.max

iterable/sync/max

code
Iterable<Number> → Number

Get the maximumm value

const { max } = require('funk-lib/iterable/sync');

max(from([1, 2, 3])); // 3
iterable.sync.maxBy

iterable/sync/maxBy

code
(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.sync.min

iterable/sync/min

code
Iterable<Number> → Number

Get the minimum value

const { min } = require('funk-lib/iterable/sync');

min(from([1, 2, 3])); // 1
iterable.sync.minBy

iterable/sync/minBy

code
(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.sync.next

iterable/sync/next

code
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()
iterable.sync.nextOr

iterable/sync/nextOr

code
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
iterable.sync.none

iterable/sync/none

code
(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]));
iterable.sync.nth

iterable/sync/nth

code
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']));
iterable.sync.of

iterable/sync/of

code
...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>
iterable.sync.pad

iterable/sync/pad

code
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']));
iterable.sync.padTo

iterable/sync/padTo

code
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']));
iterable.sync.partition

iterable/sync/partition

code
(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]));
iterable.sync.prepend

iterable/sync/prepend

code
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]));
iterable.sync.range

iterable/sync/range

code
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>
iterable.sync.rangeStep

iterable/sync/rangeStep

code
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);
iterable.sync.reduce

iterable/sync/reduce

code
((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]));
iterable.sync.reject

iterable/sync/reject

code
(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));
iterable.sync.repeat

iterable/sync/repeat

code
a → Iterator<a>

Infinitely yield an item a

const { repeat } = require('funk-lib/iterable/sync');

// Iterator<'hi', 'hi', 'hi', ...>
repeat('hi');
iterable.sync.reverse

iterable/sync/reverse

code
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>
iterable.sync.scan

iterable/sync/scan

code
((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]));
iterable.sync.slice

iterable/sync/slice

code
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]));
iterable.sync.sort

iterable/sync/sort

code
((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']));
iterable.sync.splitAt

iterable/sync/splitAt

code
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]));
iterable.sync.splitEvery
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.sync.sum

iterable/sync/sum

code
Iterable<Number> → Number

Sum of all items

const { sum } = require('funk-lib/iterable/sync');

sum(from([1, 2, 3])); // 6
iterable.sync.sumBy

iterable/sync/sumBy

code
(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.sync.tail

iterable/sync/tail

code
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));
iterable.sync.take

iterable/sync/take

code
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));
iterable.sync.takeWhile

iterable/sync/takeWhile

code
(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]));
iterable.sync.tee

iterable/sync/tee

code
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]));
iterable.sync.times

iterable/sync/times

code
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.sync.toArray

iterable/sync/toArray

code
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]
iterable.sync.unfold

iterable/sync/unfold

code
(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.sync.unique

iterable/sync/unique

code
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]));
iterable.sync.uniqueWith
((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.sync.unnest

iterable/sync/unnest

code
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.sync.unzip

iterable/sync/unzip

code
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]]));
iterable.sync.unzipN

iterable/sync/unzipN

code
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]]));
iterable.sync.yieldWith

iterable/sync/yieldWith

code
(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.sync.zip

iterable/sync/zip

code
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.sync.zipAll

iterable/sync/zipAll

code
[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]),
]);
iterable.sync.zipAllWith
((...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]),
]);
iterable.sync.zipWith

iterable/sync/zipWith

code
((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]));
iterable.sync.zipWithN

iterable/sync/zipWithN

code

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]),
);
number

number

code

Functions for working with Number

const { number } = require('funk-lib');
number.random

number/random

code
Number → Number → Integer

Get a random integer between two inclusive bounds

const { random } = require('funk-lib/number');

random(0, 100); // 42
number.randomFloat

number/randomFloat

code
Number → Number → Float

Get a random float between two inclusive bounds

const { randomFloat } = require('funk-lib/number');

randomFloat(0, 100); // 42.38076848431584
object

object

code

Functions for working with Object

const { object } = require('funk-lib');
object.clear

object/clear

code
{a} → {}

Delete all object properties. Mutating + identity

const { clear } = require('funk-lib/object');

const obj = { a: 1, b: 2 };
clear(obj); // obj === {}
object.deepFreeze

object/deepFreeze

code
{*} → {*}

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
object.del

object/del

code
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 }
object.firstKey

object/firstKey

code
{ k: v } → k

Get an object's first key

const { firstKey } = require('funk-lib/object');

firstKey({ a: 1 }); // 'a'
object.firstPair

object/firstPair

code
{ k: v } → [k, v]

Get an object's first [key, value] pair

const { firstPair } = require('funk-lib/object');

firstPair({ a: 1 }); // ['a', 1]
object.firstValue

object/firstValue

code
{ k: v } → v

Get an object's first value

const { firstValue } = require('funk-lib/object');

firstValue({ a: 1 }); // 1
object.flattenWith

object/flattenWith

code
((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 } } });
object.isEmpty

object/isEmpty

warning Deprecated
code
{a} -> Boolean

Is an object empty?

const { isEmpty } = require('funk-lib/object');

isEmpty({}); // true
object.mapDeep

object/mapDeep

code
(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 } } });
object.mapKeys

object/mapKeys

code
(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 }
object.mapPairs

object/mapPairs

code
([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' }
object.nestWith

object/nestWith

code
(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 });
object.pickAs

object/pickAs

code
{ 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 });
object.toHumanJSON

object/toHumanJSON

code
JSON → String

Serialize to JSON with newlines and 2-space indentation

const { toHumanJSON } = require('funk-lib/object');

// '{
//   "one": {
//     "two": 2
//   }
// }'
toHumanJSON({ one: { two: 2 } });
process

process

code

Functions for working with Process

const { process } = require('funk-lib');
process.onSigInt

process/onSigInt

code

On SIGINT

const { onSigInt } = require('funk-lib/process');

const offSigInt = onSigInt(_ => {
 console.log('SIGINT');
 offSigInt(); // unsubscribe
});
stream

stream

code

Functions for working with Stream

const { stream } = require('funk-lib');
stream.from

stream/from

code
Iterable<a> → Stream<a>

Readable stream from iterable

const { from } = require('funk-lib/stream');

from([1, 2, 3]); // ReadableStream<1, 2, 3>
stream.fromString

stream/fromString

code
String → Stream<String>

String to stream

const { fromString } = require('funk-lib/stream');

fromString('hello'); // ReadableStream<'hello'>
stream.toString

stream/toString

code
Stream<String> → String

Stream to string

const { toString } = require('funk-lib/stream');

await toString(from(['a', 'b', 'c'])); // 'abc'
string

string

code

Functions for working with String

const { string } = require('funk-lib');
string.capitalize

string/capitalize

code
String → String

Capitalize the first letter of a string

const { capitalize } = require('funk-lib/string');

capitalize('hello'); // 'Hello'
string.escapeRegExpStr

string/escapeRegExpStr

code
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.localeCompare

string/localeCompare

code
String → String → Number

Locale compare

const { localeCompare } = require('funk-lib/string');

localeCompare('b', 'a'); // -1
string.parseBase64

string/parseBase64

code
String → String

Decode a string from base64

const { parseBase64 } = require('funk-lib/string');

parseBase64('aGVsbG8='); // 'hello'
string.slugify

string/slugify

code
String → String

Slugify a string

const { slugify } = require('funk-lib/string');

slugify('Hello World!'); // 'hello-world'
string.template

string/template

code
String → {*} → String

String interpolation. Reasonably similar to JavaScript template literals.

const { template } = require('funk-lib/string');

// 'Hello Pat!'
template('Hello ${ name }!', { name: 'Pat' });
string.toBase64

string/toBase64

code
String → String

Encode a string to base64

const { toBase64 } = require('funk-lib/string');

toBase64('hello'); // 'aGVsbG8='
string.uncapitalize

string/uncapitalize

code
String → String

Lowercase the first letter of a string

const { uncapitalize } = require('funk-lib/string');

uncapitalize('FooBar'); // 'fooBar'
url

url

code

Functions for working with urls, and querystrings

const { url } = require('funk-lib');
url.isDataUrl

url/isDataUrl

code
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
url.parseDataUrl

url/parseDataUrl

code
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');
uuid

uuid

code

Functions for working with UUIDs

const { uuid } = require('funk-lib');
uuid.isUuid

uuid/isUuid

code
a → Boolean

Is UUID v4?

const { isUuid } = require('funk-lib/uuid');

isUuid('c4f2e775-a5f9-4796-bd31-46e544bfab06'); // true
uuid.uuid

uuid/uuid

code
a → String

Random UUID v4

const { uuid } = require('funk-lib/uuid');

uuid(); // 'c4f2e775-a5f9-4796-bd31-46e544bfab06'