@unction/complete
TypeScript icon, indicating that this package has built-in type declarations

21.4.0 • Public • Published

unction.js

unction.js is a collection of many functions. THese functions are bound by a set of three principles that are detailed below.

Raison d'exister

There are a few similar libraries out there and they all have good standing with the community, so why make unctionjs? Well the original package started off as ramda-extra, a set of functions in a package that ramda seemed to never want to implement (like at the time mapKeys). Then eventually I got to the point where I wanted to have functions be curried for clarity and found that many ramda functions don't fully support only currying. While ramda is amazing and I still use it to this day I knew I had to fork off and write my own path.

Here's a list of (I believe) fair reasons why I don't use these popular and really good libraries:

  • ramda: Ramda has all functions in a single package, it relies on internal private functions to ensure compatibility, does not have real type checking, prefers "autocurrying" which can lead to issues with curried functions, and finally as described above ramda has an interest in retaining a small surface layer.
  • lodash: Lodash only does curried as a second class citizen, doesn't have type checking, prefers "autocurrying" when it has support for it, and doesn't have a very clear picture about what some of the functions are polymorphic.

That said every unctionjs function will work with every ramda and lodash function where currying is allowed.

Using unction libraries

You can install a package individually:

npm install --save @unction/treeify
import treeify from "@unction/treeify"

Or you can install the complete package:

npm install --save @unction/complete

and import the function from package:

import {treeify} from "@unction/complete"

Principle 1

All functions are curried. Due to the nature of functional programming it's exceedingly valuable to have functions that are, by default, curried. Here's an erxample:

// asStateTree.js
import treeify from "@unction/treeify"
import get from "@unction/get"
import dig from "@unction/dig"
import indexBy from "@unction/indexby"
import groupBy from "@unction/groupby"

export default treeify(
  [
    // Group by type
    groupBy(get("type")),
    // Index by id
    indexBy(get("id")),
  ]
)

We can use this function like so:

// resources.js
import asStateTree from "./asStateTree"

// Take resources from the HTTP API, turn it into a state tree
pipe([fetchResources, asStateTree])

Principle 2

All functions know how to deal with a finite set of primitives. When using a unctionjs function you can be sure that we'll be able to handle all 6 enumerable types:

  • Array
  • Object
  • Set
  • Map
  • String
  • Stream (see: most.js)

Principle 3

All functions are pure by default. No function will ever have any side-effects (unless otherwise noted with a I suffix like shuffleI()) and are referentially transparent.

Principle 4

All functions are immutable by default. These functions do not mutate (unless otherwise noted with a M suffix like appendM()) the original values.

Functions

allObjectP()

Tests Stability Dependencies

StringRecord<string | number | symbol, T> => Promise<StringRecord<string | number | symbol, T>>

This takes an object where the values are probably promises and returns a promise that has that same object but with the resolved values.

Here's a good example of this function in use:

await allObjectP({
  merge: mergeResource(session),
  current: storeCurrent(session.id),
  account: pullAccount(session.relationship.account.data.id, client),
})
// {merge, current, account}

If we use allP or Promise.all we're getting an array back, but that's annoying to destructure. The allObjectP function gives us the concurrency we want with a named interface for the returned resolutions.

allP()

Tests Stability Dependencies

Array<T> => Promise<Array<T>>

A port of the Promise.all() function.

Credit: @keithamus

allP([fetchUser, fetchToken])

always()

Tests Stability Dependencies

T => any => T

Always returns the value given when called

always(1)() // 1
always(1)(0) // 1

append()

Tests Stability Dependencies

A => OrderedArray<B> | Set<B> | Record<string | number | symbol, unknown> | Map<B, unknown> | string => Array<C> | string

Takes a value and puts it at the end of the given list.

append(4)([5]) // => [5, 4]
append("c")("ab") // => "abc"
NOTE: While there is a type annotation in the README, this function cannot have type annotations due to a bug in flow.

appendM()

Tests Stability Dependencies

A => Array<B> => Array<A | B>

Takes an array and an item and returns the combination of both, appended.

NOTE: This mutates the array

const data = [1, 2, 3]

appendM(4)(data)

Would return:

[1, 2, 3, 4]

applicator()

Tests Stability Dependencies

((A) => B) => A => B

Takes a function and a value and applies that function to that value.

applicator(inc)(1) // 1

applicators()

Tests Stability Dependencies

Array<MapperFunctionType<A, B>> | Set<MapperFunctionType<A, B>> | RecordType<C, MapperFunctionType<A, B>> => Record<string | number | symbol, A> | Map<C, A> => Record<string | number | symbol, B> | Map<C, B>

Takes a list of functions and a list of values and applies the values to the functions.

applicators([
  recordfrom(["point", "x"]),
  recordfrom(["point", "y"]),
  recordfrom(["point", "z"]),
])([
  40.453,
  2.2,
  423.0,
])

returns

[
  {point: {x: 40.453}},
  {point: {y: 2.2}},
  {point: {z: 423.0}},
]
applicators({
  x: inc,
  y: dec
})({
  x: -1,
  y: 1
})

returns

{
  x: 0,
  y: 0
}

arrayify()

Tests Stability Dependencies

A => [A] | A

Takes a value and turns it into an array of that value, unless the value is already an array.

arrayify("a")

returns

["a"]
arrayify(["a"])

returns

["a"]

aside()

Tests Stability Dependencies

Array<MapperFunctionType<A, B>> => A => A

Takes a stack of functions, like pipe(), but always returns the second argument.

pipe(
  aside([(value) => value.toLowerCase(), console.log]),
  processData
)(
  "Hello, world"
) // "Hello, world"

But also logs:

"hello, world"

attach()

Tests Stability Dependencies

A => B => Record<string | number | symbol, B> | Map<A, B> => Record<string | number | symbol, B> | Map<A, B>
ObjectKeyType => ValueType => ObjectType => ObjectType
MapKeyType => ValueType => MapType => MapType
ArrayKeyType => ValueType => ArrayType => ArrayType
null => ValueType => SetType => SetType
null => ValueType => StreamType => StreamType

A polymorphic way to attach a value to the key on a keyed enumerator. When dealing with a sorted list type and the key is larger than the list, it will append to the list. When the key is an index that already exists it will place the value at that index and shift remaining values to the right.

attach("hello")("world")({}) // => {hello: "world"}
attach(3)("x")([1, 2, 3]) // => [1, 2, 3, "x"]
attach(1)("x")([1, 2, 3]) // => [1, "x", 2, 3]
attach(null)("x")(new Set([1, 2, 3])) // => {1 2 3 "x"}
attach(10)("x")([]) // => ["x"]
attach(0)("a")("bc") // => "abc"
attach(null)("a")(xstream.of("b")) // => a---b--=>

catchP()

Tests Stability Dependencies

MapperFunctionType<C, B> => Promise<A> => Promise<A | B>

A port of the Promise.prototype.catch() function.

catchP(
  (exception) => console.error(exception)
)(Promise.all([fetchUser, fetchProject]))

Credit: @keithamus

compact()

Tests Stability Dependencies

ListType<A | null> | RecordType<unknown, A | null> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes a collection (Array or Object) and returns a copy of that value without null or undefined values.

avatarUrls // => [null, "/1.jpg", null, "/3.jpg"]
compact(avatarUrls)  // => ["/1.jpg", "/3.jpg"]

user // {"avatar": null, "name": "Kurtis Rainbolt-Greene"}
compact(head(user)) // {"name": "Kurtis Rainbolt-Greene"}

compose()

Tests Stability Dependencies

Array<A> => B => C

Takes a list of functions and runs a value through that stack from right to left.

compose([toInteger, toString])(0) // 0
compose([append("b"), append("a")])("c") // "cab"

computedProp()

Tests Stability Dependencies

MapperFunctionType<A, B> => KeyChainType<C> => Array<A> | Set<A> | RecordType<C | B, A> | string => Array<A> | Set<A> | RecordType<C | B, A> | string

Given an object this function will return that object but with a new property, where the value is computed. The computation is given the object you'll be copying.

const computer = ({id, attributes: {username}}) => `${username}#${id}`
const key = "tag"
const payload = {
  id: "1",
  attributes: {
    username: "krainboltgreene"
  }
}

computedProp(computer)(key)(payload)

Would return:

{
  id: "1",
  tag: "krainboltgreene#1",
  attributes: {
    username: "krainboltgreene"
  }
}
const multiKey = ["attributes", "tag"]

computedProp(computer)(key)(payload)

Would return:

{
  id: "1",
  attributes: {
    tag: "krainboltgreene#1",
    username: "krainboltgreene"
  }
}

couple()

Tests Stability Dependencies

L => R => [L, R]

Takes any value and then any value and returns an array containing those values.

couple(4)(5) // => [4, 5]

dig()

Tests Stability Dependencies

Array<A> => B => C

Takes a chain of keys and a tree, traversing down and reaching the last value. If any part of the chain is undefined or not an object the result will always be undefined.

dig(["aaa", "bbb", "ccc"])({aaa: {bbb: {ccc: "1"}}}) // "1"
dig(["aaa", "ddd", "ccc"])({aaa: {bbb: {ccc: "1"}}}) // undefined

domEvents()

Tests Stability Dependencies

DOMEventsConfigurationType => DOMEventNameType => DOMStreamType => DOMEventStreamType

Takes a configuration, an event name, and a DOM source and returns an observable of that event type

domEvents({})("click")(DOM)

returns

--click--click--click-=>

domEventsMany()

Tests Stability Dependencies

DOMEventsManyConfigurationType => Array<DOMEventNameType> => DOMEventStreamType

Takes many event names and returns an observable of those events.

domEventsMany({})(["click", "input"])(DOM)

returns

--click--input--input--click--input--|

dropFirst()

Tests Stability Dependencies

number => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Returns all but the first N of a list of ordered values.

dropFirst(2)([1, 2, 3]) // [3]
dropFirst(1)([1, 2, 3]) // [2, 3]
dropFirst(2)("abc") // "c"
dropFirst(1)("abc") // "bc"

dropLast()

Tests Stability Dependencies

number => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Returns all but the last N of a list of ordered values.

dropLast(2)([1, 2, 3]) // [1]
dropLast(1)([1, 2, 3]) // [1, 2]
dropLast(2)("abc") // "a"
dropLast(1)("abc") // "ab"

endsWith()

Tests Stability Dependencies

string => string => boolean

Determines if a given subset of text is at the end of another set of text.

endsWith("!")("Hello, world!") // true

equals()

Tests Stability Dependencies

L => R => boolean

Compares two values and attempts to discern if they are truly equal.

equals(true)(true) // true
equals([1, 2, 3])([1, 2, 3]) // true
equals({aaa: "aaa", bbb: "bbb"})({aaa: "aaa", bbb: "bbb"}) // true
equals("abc")("abc") // true
equals(null)(null) // true
equals(undefined)(undefined) // true
equals(false)(true) // false
equals([1, 2, 3])([3, 2, 1]) // false
equals([1, 2, 3])([1]) // false
equals([1, 2, 3])([]) // false
equals({aaa: "aaa", bbb: "bbb"})({aaa: "aaa"}) // false
equals({aaa: "aaa", bbb: "bbb"})({}) // false
equals({aaa: "aaa", bbb: "bbb"})({aaa: "bbb", bbb: "ccc"}) // false
equals("abc")("bac") // false
equals(null)(undefined) // false
equals(undefined)(null) // false

everyP()

Tests Stability Dependencies

Array<Promise<A>> => Promise<[Array<A>, Array<B>]>

Returns both resolved and rejected promises as distinct lists.

exceptKey()

Tests Stability Dependencies

B => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes a key and a keyed functor, returning the keyed functor without the key given.

exceptKey(1)([1, 2, 3]) // [1, 3]
exceptKey(1)("abc") // "ac"
exceptKey("aaa")({aaa: "aaa", bbb: "bbb", ccc: "ccc"}) // {bbb: "bbb", ccc: "ccc"}
exceptKey("aaa")(new Map([["aaa", "aaa"], ["bbb", "bbb"], ["ccc", "ccc"]])) // new Map([["bbb", "bbb"], ["ccc", "ccc"]])

first()

Tests Stability Dependencies

OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => A | string | void

Returns the first item of an ordered list.

first([1, 2, 3]) // 1
first("abc") // "a"

flatten()

Tests Stability Dependencies

ListType<Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string | A> | RecordType<unknown, Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string | A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes a multi-dimensional enumerable and decreases the nesting by one.

import {from} from "most"

flatten([["a", "b"], ["c", "d"]]) // ["a", "b", "c", "d"]
flatten(["a", "b", ["c", "d"]]) // ["a", "b", "c", "d"]
flatten(
  from([
    from(["a", "b"]),
    from(["c", "d"]),
  ])
) // ---a---b---c---d---|

flattenTree()

Tests Stability Dependencies

string => Record<string | number | symbol, B> | Map<A, B> => Record<string | number | symbol, B> | Map<A, B>

Takes a tree and creates a single object where the root keys are conjoined nested keys.

flattenTree(
  "-"
)(
  {
    data: {
      profile: {
        name: "Kurtis Rainbolt-Greene",
        age: 24,
      },
      metadata: {
        interval: "10s",
      },
      location: "http://api.example.com/profiles/24",
    }
  }
)

Would return:

{
  "data-profile-name": "Kurtis Rainbolt-Greene",
  "data-profile-age": 24,
  "data-metadata-interval": "10s",
  "data-location": "http://api.example.com/profiles/24"
}

flip()

Tests Stability Dependencies

MapperFunctionType<A, MapperFunctionType<B, C>> => B => A => C

Flips a function's first and second arguments.

flip(key)({aaa: "1"})("aaa") // "1"

forEach()

Tests Stability Dependencies

 MapperFunctionType<A, B> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes any kind of enumerable and figures out the best way to iterate over it.

forEach((x) => y)([])
forEach((x) => y)(new Map)
forEach((x) => y)({})

fresh()

Tests Stability Dependencies

A => A

Takes a value and returns an empty fresh version of that value.

fresh({aaa: "aaa"}) // {}
fresh(["aaa"]) // []
fresh({}) // {}
fresh([]) // []

fromArrayToObject()

Tests Stability Dependencies

Array<[string | number, A]> => ObjectType<A>

Takes an array that looks like a primitive Object and turns it into a proper object. Duplicate keys get overwritten.

fromArrayToObject([["aaa", "1"], ["bbb", "2"]]) // {aaa: 1, bbb: 2}

fromFunctorToPairs()

NOTE: This library has been deprecated in favor of unction/pairsFrom

Tests Stability Dependencies

FunctorType => Array<[KeyType?, ValueType?]>

Takes a functor and tries to transform it into a list of key-value pairs.

fromFunctorToPairs({aaa: "a", bbb: "b", ccc: "c"})) // [["aaa", "a"], ["bbb", "b"], ["ccc", "c"]]
fromFunctorToPairs(["a", "b", "c"]) // [[0, "a"], [1, "b"], [2, "c"]]
fromFunctorToPairs(new Map([["aaa", "a"], ["bbb", "b"], ["ccc", "c"]])) // [["aaa", "a"], ["bbb", "b"], ["ccc", "c"]]
fromFunctorToPairs(new Set(["a", "b", "c"])) // [[undefined, "a"], [undefined, "b"], [undefined, "c"]]

fromIteratorToArray()

Tests Stability Dependencies

Map<A, B> => Array<[A, B]>

Takes an Iterator (SetIterator, MapIterator, etc) and turns it into an array.

fromIteratorToArray(new Set([1, 2, 3]).entries()) // [[1, 1], [2, 2], [3, 3]]
fromIteratorToArray(new Map([["aaa", "a"], ["bbb", "b"], ["ccc", "c"]]).entries()) // [["aaa", "a"], ["bbb", "b"], ["ccc", "c"]]

get()

Tests Stability Dependencies

KeyType => unknown => ValueType

Returns the value of a specific key on an iterable. If no key is found it returns undefined. If the second argument isn't an iterable we return undefined, to allow for graceful failure.

get("aaa")({aaa: "1"}) // "1"
get("bbb")({aaa: "1"}) // undefined
get("bbb")(undefined) // undefined
get(0)(["aaa"]) // "aaa"

getMany()

Tests Stability Dependencies

Array<A> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<B>

Takes a list of keys and a keyed enumerable, and returns the values for those keys. If no key exists, the value is undefined.

getMany(["aaa", "bbb"])({aaa: "111", bbb: "222"}) // ["111", "222"]
getMany(["aaa", "ccc"])({aaa: "111", bbb: "222"}) // ["111", undefined]

greaterThan()

Tests Stability Dependencies

number => number => boolean

Determines if one number is greater than another number.

greaterThan(1)(0) // true
greaterThan(0)(1) // false

groupBy()

Tests Stability Dependencies

MapperFunctionType<A, B> => Array<A> | Set<A> => Map<B, Array<A> | Set<A>>

Creates a record tree where the key is a computation on the value and the value is a list of the values that match with that computation.

groupBy(
  key("type")
)([
  {
    id: "aaa",
    name: "Kurtis Rainbolt-Greene",
    type: "person",
  },
  {
    id: "bbb",
    name: "Angela Rainbolt-Greene",
    type: "person",
  },
])

Which returns:

Map {
  "person" => [
    {
      id: "aaa",
      name: "Kurtis Rainbolt-Greene",
      type: "person",
    },
    {
      id: "bbb",
      name: "Angela Rainbolt-Greene",
      type: "person",
    },
  ],
}
groupBy(
  key("type")
)(
  Set [
    Map {
      "id" => "aaa",
      "name" => "Kurtis Rainbolt-Greene"
      "type" => "person",
    },
    Map {
      "id" => "bbb",
      "name" => "Angela Rainbolt-Greene"
      "type" => "person",
    }
  ]
)

Which returns:

Map {
  "person" => Set [
    Map {
      "id" => "aaa",
      "name" => "Kurtis Rainbolt-Greene",
      "type" => "person",
    },
    Map {
      "id" => "bbb",
      "name" => "Angela Rainbolt-Greene",
      "type" => "person",
    }
  ],
}

hammer()

Tests Stability Dependencies

A => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Use this to de-nest a nested keyed enumerable.

const payload = {
  id: 1
  attributes: {
    name: "Kurtis Rainbolt-Greene",
    age: 26
  }
}

hammer("attributes")(payload)

Which returns:

{
  id: 1,
  name: "Kurtis Rainbolt-Greene",
  age: 26
}

ifThenElse()

Tests Stability Dependencies

PredicateFunctionType<A> => MapperFunctionType<A, B> => MapperFunctionType<A, C> => B | C

Based on a predicate it passes the value to a consequent or alternative function

ifThenElse(isEven)(toString)(toFloat)(1) // 1.0
ifThenElse(isEven)(toString)(toFloat)(2) // "2"

indexBy()

Tests Stability Dependencies

MapperFunctionType<A, B> => Array<A> | Set<A> => Map<B, A>

Creates a record tree where the key is a computation on the value and the value is the original value.

indexBy(
  key("id")
)([
  {
    id: "aaa",
    name: "Kurtis Rainbolt-Greene",
  },
  {
    id: "bbb",
    name: "Angela Rainbolt-Greene",
  },
])

Which returns:

{
  aaa: {
    id: "aaa",
    name: "Kurtis Rainbolt-Greene",
  },
  bbb: {
    id: "bbb",
    name: "Angela Rainbolt-Greene",
  },
}
indexBy(
  key("id")
)(
  new Set([
    new Map([
      ["id", "aaa"],
      ["name", "Kurtis Rainbolt-Greene"]
    ]),
    new Map([
      ["id", "bbb"],
      ["name", "Angela Rainbolt-Greene"]
    ])
  ])
)

Which returns:

new Map([
  ["aaa", new Map([
    ["id", "aaa"],
    ["name", "Kurtis Rainbolt-Greene"]
  ])],
  ["bbb", new Map([
    ["id", "bbb"],
    ["name", "Angela Rainbolt-Greene"]
  ])],
])

inflateTree()

Tests Stability Dependencies

string => Record<string | number | symbol, B> | Map<A, B> => RecordType<A, C>

Takes a flat record with a specific key pattern and turns it into a nested record.

inflateTree(
  "-"
)(
  {
    "data-profile-name": "Kurtis Rainbolt-Greene",
    "data-profile-age": 24,
    "data-metadata-interval": "10s",
    "data-location": "http://api.example.com/profiles/24",
  }
)

which returns

{
  data: {
    profile: {
      name: "Kurtis Rainbolt-Greene",
      age: 24,
    },
    metadata: {interval: "10s"},
    location: "http://api.example.com/profiles/24",
  },
}

initial()

Tests Stability Dependencies

OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Returns all but the last item in an ordered list.

initial([1, 2, 3]) // [1, 2]
initial("abc") // "ab"

isArray()

Tests Stability Dependencies

A => boolean

Takes any value and then any value and returns an array containing those values.

isArray([]) // => true
isArray({}) // => false
isArray("") // => false

isEnumerable()

Tests Stability Dependencies

A => Boolean

Determines if the value is an enumerable and if so returns true, else false.

isEnumerable(1) // false
isEnumerable("") // true
isEnumerable([]) // true
isEnumerable({}) // true
isEnumerable(new Map()) // true
isEnumerable(new Set()) // true
isEnumerable(most.from([])) // true
isEnumerable(most.from([])) // true

isNil()

Tests Stability Dependencies

A => boolean

Determines if a value is not a value.

isNil(null) // true
isNil(undefined) // true
isNil(0) // false
isNil("") // false
isNil([]) // false
isNil({}) // false

isObject()

Tests Stability Dependencies

A => boolean

Takes a value and determines if it's an object.

isObject({}) // => true
isObject([]) // => false
isObject("") // => false

isPopulated()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => boolean

Allows you to check if a enumerable has any items.

isPopulated([1]) // true
isPopulated({a: 'b'}) // true
isPopulated({}) // false
isPopulated([]) // false
isPopulated("") // false
isPopulated("a") // true

isPresent()

Tests Stability Dependencies

A => boolean

This lets you know if it's a non-null, non-undefined value.

isPresent('x') // true
isPresent([]) // true
isPresent(null) // false
isPresent(undefined) // false

isType()

Tests Stability Dependencies

string => A => boolean

Takes any value and then any value and returns an array containing those values.

isType("Object")({}) // => true
isType("Array")([]) // => true
isType("String")("") // => true

itself()

Tests Stability Dependencies

A => A

Always returns the value given when calling.

itself(1) // 1
itself(1) // 1

keyChainTree()

Tests Stability Dependencies

Record<string | number | symbol, B> | Map<A, B> => Array<KeyChainType<A>>

Takes a tree and returns all keychains for that tree. Note, it only follows record types (types with keys).

keyChainTree({
  id: "1",
  attributes: {
    name: "Kurtis Rainbolt-Greene",
    age: 24,
  },
  meta: new Map([
    ["version", "1.0.0"],
  ]),
  included: [
    {
      id: "2",
      attributes: {
        name: "Angela Englund",
      },
    },
  ],
})

which would return

[
  ["id"],
  ["attributes", "name"],
  ["attributes", "age"],
  ["meta", "version"],
  ["included"],
]

keys()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<B>

Takes a keyed iterable and returns the keys as an Array.

keys({aaa: "111", bbb: "222"}) // ["aaa", "bbb"]
keys(["111", "222"]) // [0, 1]

lacksText()

Tests Stability Dependencies

string => string => boolean

Determines if a set of text does not have a subset of text.

const data = "I love pies!"
const lacksBestFood = lacksText("pizza")

lacksBestFood(data) // false

last()

Tests Stability Dependencies

OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => A

Returns the last item of an ordered list.

last([1, 2, 3]) // 3
last("abc") // "c"

length()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => number

Returns the number of values contained in the enumerable.

length([1, 2, 3]) // 3
length({aaa: "aaa", bbb: "bbb"}) // 2
length(new Map([["aaa", "aaa"], ["bbb", "bbb"]])) // 2
length(new Set([1, 2, 3])) // 3

lessThan()

Tests Stability Dependencies

number => number => boolean

Determines if one number is greater than another number.

lessThan(0)(1) // true
lessThan(1)(0) // false

mapKeys()

Tests Stability Dependencies

MapperFunctionType<A, B> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => KeyedArray<B> | Set<B> | Record<string | number | symbol, unknown> | Map<B, unknown> | string

Map over a keyed functor's keys and return a new keyed functor having mapped the keys

const attributes = {
  name: "Kurtis Rainbolt-Greene",
  createdAt: new Date()
}

mapKeys(kebab)(attributes)

Would return:

{
  name: "Kurtis Rainbolt-Greene",
  "created-at": new Date()
}

mapKeysWithValueKey()

Tests Stability Dependencies

MapperFunctionType<A, MapperFunctionType<B, C>> =>
  Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string =>
    Array<B> | Set<B> | Record<string | number | symbol, B> | Map<C, B> | string

Map over keys with the context of the value and key.

const attributes = {
  name: "Kurtis Rainbolt-Greene",
  createdAt: new Date()
}

mapKeys((value) => (key) => )(attributes)

Would return:

{
  name: "Kurtis Rainbolt-Greene",
  "created-at": new Date()
}

mapValues()

Tests Stability Dependencies

MapperFunctionType<A, B> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<B> | Set<B> | Record<string | number | symbol, unknown> | Map<B, unknown> | string

A pretty standard mapValues(), but with enforced unary currying.

mapValues(
  (value) => value + 1
)(
  [1, 2, 3]
)

Which will return:

[2, 3, 4]

mapValuesWithValueKey()

Tests Stability Dependencies

MapperFunctionType<A, MapperFunctionType<B, C>> =>
  Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string =>
    Array<B> | Set<B> | Record<string | number | symbol, B> | Map<C, B> | string

Just like map, but gives back the index argument (as an integer, not a string if array)

mergeAllLeft()

Tests Stability Dependencies

Array<Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Merges a list of enumerables (of the same type) into a single enumerable.

mergeAllLeft([["0"], ["1"], ["2"]]) // ["2", "1", "0"]
mergeAllLeft([{aaa: "aaa"}, {bbb: "bbb"}, {ccc: "ccc"}]) // {aaa: "aaa", bbb: "bbb", ccc: "ccc",}

mergeAllRight()

Tests Stability Dependencies

Array<Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Merges a list of enumerables (of the same type) into a single enumerable.

mergeAllRight([["0"], ["1"], ["2"]]) // ["0", "1", "2"]
mergeAllRight([{aaa: "aaa"}, {bbb: "bbb"}, {ccc: "ccc"}]) // {aaa: "aaa", bbb: "bbb", ccc: "ccc",}

mergeDeepLeft()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Recursively merges two enumerables. Merges objects with merge and arrays with concat. Prefers left. THAT IS ALL.

const left = {
  alpha: "1"
}
const right = {
  beta: "2"
}

mergeDeepLeft(left)(right)
{
  alpha: "1",
  beta: "2"
}
const left = {
  alpha: {
    alpha1: "1"
  }
}
const right = {
  beta: {
    beta1: "1"
  }
}

mergeDeepLeft(left)(right)
{
  alpha: {
    alpha1: "1"
  },
  beta: {
    beta1: "1"
  }
}
const left = {
  alpha: [
    "1"
  ]
}
const right = {
  alpha: [
    "1"
  ]
}

mergeDeepLeft(left)(right)
{
  alpha: [
    "1",
    "1"
  ]
}

mergeDeepRight()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Recursively merges two enumerables. Merges objects with merge and arras with concat. Prefers right. THAT IS ALL.

const left = {
  alpha: "1"
}
const right = {
  beta: "2"
}

mergeDeepRight(left)(right)
{
  alpha: "1",
  beta: "2"
}
const left = {
  alpha: {
    alpha1: "1"
  }
}
const right = {
  beta: {
    beta1: "1"
  }
}

mergeDeepRight(left)(right)
{
  alpha: {
    alpha1: "1"
  },
  beta: {
    beta1: "1"
  }
}
const left = {
  alpha: [
    "1"
  ]
}
const right = {
  alpha: [
    "1"
  ]
}

mergeDeepRight(left)(right)
{
  alpha: [
    "1",
    "1"
  ]
}

mergeLeft()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Merges two enumerables, preferring left.

const left = {
  alpha: "1",
  beta: "1"
}
const right = {
  beta: "2",
  zeta: "3"
}

mergeLeft(left)(right)

Which returns:

{
  alpha: "1",
  beta: "1",
  zeta: "3"
}

mergeRight()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Merges two enumerables, preferring right.

const left = {
  alpha: "1",
  beta: "1"
}
const right = {
  beta: "2",
  zeta: "3"
}

mergeRight(left)(right)

Which returns:

{
  alpha: "1"
  beta: "2",
  zeta: "3"
}

mergeWith()

Tests Stability Dependencies

MapperFunctionType<A, MapperFunctionType<A, A>> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Merges two enumerables and uses a provided function to handle conflicts. The function is given the the left value and the right value.

const left = {
  alpha: "0",
  beta: "1",
  zeta: "3"
}
const right = {
  alpha: "0",
  beta: "2",
  zeta: "3"
}

mergeWith((l) => (r) => l+r)(left)(right)

Which returns:

{
  alpha: "0",
  beta: "12",
  zeta: "3"
}

mergeWithKey()

Tests Stability Dependencies

MapperFunctionType<L, MapperFunctionType<R, MapperFunctionType<K, V>>> =>
  KeyedEnumerableType<R, K> =>
    KeyedEnumerableType<L, K> =>
      ListType<V> | Record<string | number | symbol, V> | Map<K, V> | string

Merges two keyed enumerables and uses a function to handle conflicts. The function is given the left value, the right value, and the key.

const left = {
  beta: "1"
}
const right = {
  beta: "2"
}

mergeWithKey((left) => (right) => (key) => key+leftValue+rightValue)(left)(right)

Which returns:

{
  beta: "beta12"
}

nestedApply()

Tests Stability Dependencies

(MapperFunctionType<A, B> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<B> | Set<B> | Record<string | number | symbol, unknown> | Map<B, unknown> | string) =>
  MapperFunctionType<A, B> =>
    number =>
      Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string =>
        Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes a function (the application) that takes function(s) (later referred to as the inner) and value(s) (mapValues(), forEach(), selectValues()), a function (the inner) that will be applied to a value(s), and finally a number (depth) to apply that applicator around the inner.

In the below example we want to take two sets of records and index them by id:

const records = [
  [
    {
      id: "a1",
      type: "commercial",
    },
    {
      id: "a2",
      type: "commercial",
    }
  ],
  [
    {
      id: "b1",
      type: "residential",
    },
    {
      id: "b2",
      type: "residential",
    }
  ]
]

Normally we'd just do mapValues(indexBy(key("id"))), however we can make this easier and dynamic:

const nestedIndexById = nestedApply(mapValues)(indexBy(key("id")))(1)

nestedIndexById(records)

And the result:

[
  {
    a1: {
      id: "a1",
      type: "commercial",
    },
    a2: {
      id: "a2",
      type: "commercial",
    },
  },
  {
    b1: {
      id: "b1",
      type: "residential",
    },
    b2: {
      id: "b2",
      type: "residential",
    },
  },
]

objectFrom()

Tests Stability Dependencies

KeyChainType<A> => B => ObjectType<B>

Given a keychain and a value it creates an object that has keys based on the keychain.

objectFrom(["key", "subkey"])("value")

Which returns:

{
  key: {
    subkey: "value"
  }
}

of()

Tests Stability Dependencies

A => B => Record<string | number | symbol, C> | Map<D, C> => Record<string | number | symbol, B> | Map<B, A>

Creates a enumerable based on a value and optional key.

of("aaa")("bbb")({}) // {aaa: "bbb"}
of(null)("bbb")([]) // ["bbb"]

onlyKeys()

Tests Stability Dependencies

Array<A> | Set<A> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Reduces the keyed enumerable to an object with only the keys provided.

onlyKeys(
  ["alpha", "beta", "delta"]
)(
  {
    feta: "0",
    alpha: "1",
    beta: "2",
    delta: "3",
  }
)

// {
//   alpha: "1",
//   beta: "2",
//   delta: "3",
// }

optimisticP()

Tests Stability Dependencies

ListType<Promise<A>> => Promise<Array<A>>

Will take an array of promises and returns a promise of only the resolved promises.

pairsKeys()

Tests Stability Dependencies

ListType<[A, B]> => Array<A> | Set<A>

Takes an list that looks like a list of pairs (key, values) and returns all the keys.

Lets say you have this data:

const data = {
  a: 1,
  b: 2,
  c: 3,
}

And you turn it into pairs:

const pairings = toPairs(data)

You would end up with this:

[
  ['a', 1],
  ['b', 2],
  ['c', 3],
]

Now you just want the keys:

pairsKeys(pairings)

You would get the following:

[
  'a',
  'b',
  'c',
]

pairsValues()

Tests Stability Dependencies

ListType<[A, B]> => Array<B> | Set<B>

Takes an list that has pairs (key, values) and returns all the values.

Lets say you have this data:

const data = {
  a: 1,
  b: 2,
  c: 3,
}

And you turn it into pairs:

const pairings = toPairs(data)

You would end up with this:

[
  ['a', 1],
  ['b', 2],
  ['c', 3],
]

Now you just want the keys:

pairsValues(pairings)

You would get the following:

[
  1,
  2,
  3,
]

partition()

Tests Stability Dependencies

PredicateFunctionType<A> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => [Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string, Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string]

This function takes an enumerable and returns an Array of two enumerables. The first of which contains elements which satisfy the predicate, the second of which contains element which do not.

partition(isOdd)([1,2,3,4]) // [[1,3],[2,4]]

pipe()

Tests Stability Dependencies

Array<A> => B => C

Takes a list of functions and runs a value through that stack from left to right.

pipe([toString, toInteger])(0) // 0
pipe([append("b"), append("a")])("c") // "cba"

pluck()

Tests Stability Dependencies

KeyChainType => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<B>

Given a keychain and records return the values at the keychain for each record.

pluck(
  ["attributes", "name"]
)(
  [
    {
      id: "1",
      attributes: {
        name: "Kurtis",
        age: 29,
        height: "5'10\"",
      },
    },
    {
      id: "2",
      attributes: {
        name: "Chris",
        age: 29,
        height: "5'8\"",
      },
    },
  ]
)

Which will return:

[
  "Kurtis",
  "Chris"
]

plucks()

Tests Stability Dependencies

Array<KeyChainType<A>> => KeyedEnumerabletype<B, A> => Array<B>

Given keychain and records, return the values at the keychain for each record.

plucks(
  [
    ["attributes", "name"],
    ["attributes", "age"],
    ["attributes", "friends"],
    ["id"]
  ]
)(
  [
    {
      id: "1",
      attributes: {
        name: "Kurtis",
        age: 29,
        height: "5'10\"",
      },
    },
    {
      id: "2",
      attributes: {
        name: "Chris",
        age: 29,
        height: "5'8\"",
      },
    },
  ]
)

Which will return:

[
  ["Kurtis", 29, null, "1"],
  ["Chris", 29, null, "2"]
]

prepend()

Tests Stability Dependencies

A => Array<A | B> | string => Array<A | B> | string

Takes a value and puts it at the beginning of the given list.

prepend(4)([5]) // => [4, 5]
prepend("c")("ab") // => "cab"

range()

Tests Stability Dependencies

number => number => number

Takes a minimum number, a maximum number, and returns a random value from that inclusive range.

range(1)(2) // Sometimes 1, sometimes 2
range(0)(0) // 0

reduceKeys()

Tests Stability Dependencies

ReducerFunctionType<A, B | C, D> => C => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => D

Reduce over a iterable's keys.

reduceValues(
  (accumulation) => (current) => `${accumulation}/${current}`
)(
  "~"
)(
  ["Users", "krainboltgreene", "Code"]
)

Which will return:

"~/0/1/2"

reduceValues()

Tests Stability Dependencies

ReducerFunctionType<A, B | C, D> => C => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => D

Reduce over a iterable's values.

reduceValues(
  (accumulation) => (current) => `${accumulation}/${current}`
)(
  "~"
)(
  ["Users", "krainboltgreene", "Code"]
)

Which will return:

"~/Users/krainboltgreene/Code"

reduceWithValueKey()

Tests Stability Dependencies

ReducerFunctionType<A, B | D, C> => D => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => E

Reduces over a functor, providing the reducer with the value and key.

reduceWithValueKey(
  (accumulation) => (current) => (key) => `${accumulation}/${current}:${key}`
)(
  "~"
)(
  ["Users", "krainboltgreene", "Code"]
)

Which will return:

"~/Users:0/krainboltgreene:1/Code:2"

rejectByValue()

Tests Stability Dependencies

PredicateFunctionType<A> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes an enumerable and a predicate, returning an enumerable with items that returned false from the predicate.

rejectByValue(type("Number"))([1, "A", 2, "B"]) // ["A", "B"]

rejectP()

Tests Stability Dependencies

A => Promise<A>

A port of the Promise.reject() function.

Credit: @keithamus

remaining()

Tests Stability Dependencies

OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Returns all but the first item in an ordered list

remaining([1, 2, 3]) // [2, 3]
remaining("abc") // "bc"

replaceWhen()

Tests Stability Dependencies

PredicateFunctionType<A> => B => Function

Replaces values in an functor with another value based on a predicate.

replaceWhen(isEven)(null)([1, 2, 3]) // [1, null, 3]

resolveP()

Tests Stability Dependencies

A => Promise<A>

A port of the Promise.resolve() function.

Credit: @keithamus

reversal()

Tests Stability Dependencies

PredicateFunctionType<A> => A => boolean

Takes a predicate and returns the reverse of that predicate.

reversal(isNull)(null) // false

reverse()

Tests Stability Dependencies

OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes an ordered enumerable type and returns the reverse version of it.

reverse([1, 2, 3]) // [3, 2, 1]
reverse("abc") // "cba"

sample()

Tests Stability Dependencies

OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => A

Takes an ordered enumerable and returns one random element.

users() // => [{"id": 1, "name": "Kurtis Rainbolt-Greene"}, {"id": 2, "name": "Angela Englund"}]

sample(users()) // => {"id": 2, "name": "Angela Englund"}

sample(users()) // => {"id": 2, "name": "Angela Englund"}

sample(users()) // => {"id": 1, "name": "Kurtis Rainbolt-Greene"}

sampleSize()

Tests Stability Dependencies

number => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes an Array or string and randomly picks n elements to return, but never the same one.

users() // => [{"id": 1, "name": "Kurtis Rainbolt-Greene"}, {"id": 2, "name": "Angela Englund"}]

sample(1)(users()) // => [{"id": 2, "name": "Angela Englund"}]

sample(2)(users()) // => [{"id": 2, "name": "Angela Englund"}, {"id": 1, "name": "Kurtis Rainbolt-Greene"}]

selectByValue()

Tests Stability Dependencies

PredicateFunctionType<A> => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Given an enumerable and a predicate and produce the set or subset of that based on the predicate matched to the values.

selectByValue(isOdd)([1, 2, 3, 4]) // [1, 3]

sequence()

Tests Stability Dependencies

Array<MapperFunctionType<A, B>> | Set<MapperFunctionType<A, B>> | Record<string | number | symbol, MapperFunctionType<A, B>> | Map<unknown, MapperFunctionType<A, B>> => A => Array<B> | Set<B> | Record<string | number | symbol, unknown> | Map<B, unknown> | string
Array<MapperFunctionType<A, B>> => A => Array<B>
Set<MapperFunctionType<A, B>> => A => Set<B>
ObjectType<unknown, MapperFunctionType<A, B>> => A => ObjectType<unknown, B>
Map<unknown, MapperFunctionType<A, B>> => A => Map<unknown, B>

Takes a list of functions, a value, and applies that value to each function, returning an array of results.

sequence([increment, decrement])(1) // [2, 0]
sequence(new Set([increment, decrement]))(1) // {2 0}
sequence(new Map([["a", increment], ["b", decrement]]))(1) // {{"a" 2}, {"b" 0}}
sequence({x: increment, y: decrement, z: itself})(1) // {x: 2, y: 0, z: 1}

shuffle()

Tests Stability Dependencies

OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => OrderedArray<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string

Takes an Ordered Functor and returns an Ordered Functor with the same content, but in a random order.

users()

Would return:

[{"id": 1, "name": "Kurtis Rainbolt-Greene"}, {"id": 2, "name": "Angela Englund"}, {"id": 3, "name": "Joshua Benitez"}]
shuffle(users())

Would return:

[{"id": 1, "name": "Kurtis Rainbolt-Greene"}, {"id": 3, "name": "Joshua Benitez"}, {"id": 2, "name": "Angela Englund"}]
shuffle(users())

Would return:

[{"id": 3, "name": "Joshua Benitez"}, {"id": 1, "name": "Kurtis Rainbolt-Greene"}, {"id": 2, "name": "Angela Englund"}]
shuffle(users())

Would return:

[{"id": 2, "name": "Angela Englund"}, {"id": 3, "name": "Joshua Benitez"}, {"id": 1, "name": "Kurtis Rainbolt-Greene"}]

sortBy()

Tests Stability Dependencies

MapperFunctionType<A, B> => Array<C> => Array<C>

Sorts an array by a given computer function.

sortBy(({id}) => id)([{id: 3}, {id: 1}, {id: 2}]) // [{id: 1}, {id: 2}, {id: 3}]

splat()

Tests Stability Dependencies

A => Array<B> => C

Takes a curried function (of n depth) and a list of arguments for that function (of n size) and applies those arguments to that function.

splat((a) => (b) => a + b)([1, 2]) // 3

split()

Tests Stability Dependencies

string => (string | RegExp) => Array<string>

Splits up a string by a delimiter.

split(" ")("a b") // ["a", "b"]
split(/-+/)("a---b") // ["a", "b"]

startsWith()

Tests Stability Dependencies

string => string => boolean

Determines if a given subset of text is at the start of another set of text.

startsWith("Hello")("Hello, world!") // true

streamSatisfies()

Tests Stability Dependencies

(string | Array<A | string>) =>
 MapperFunctionType<B, PredicateFunctionType<A | string>> =>
   MapperFunctionType<unknown, C> =>
     MapperFunctionType<Array<A | string>, MapperFunctionType<number, D>> =>
       StreamType<B> =>
         any

Takes a marble string, an assertion, a final state callback, and a stream so that you can assert in tests how a stream will function. Each marble should be deliniated by a "---" notation. If the last marble node is a "|" then it will make sure the stream has ended. Each "marble" will be evaluated before being compared.

test("String diagram", ({equal, doesNotThrow, end}) => {
  const left = xstream.of("a")
  const right = xstream.of("b")

  streamSatisfies(
    "'b'---'a'---|"
  )(
    (given) => (expected) => equal(given, expected)
  )(
    doesNotThrow
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    mergeRight(left)(right)
  )
})

test("String diagram", ({equal, doesNotThrow, end}) => {
  const left = xstream.of(1)
  const right = xstream.of(2)

  streamSatisfies(
    "2---1---|"
  )(
    (given) => (expected) => equal(given, expected)
  )(
    doesNotThrow
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    mergeRight(left)(right)
  )
})

test("String diagram", ({same, equal, doesNotThrow, end}) => {
  const left = xstream.of({aaa: "aaa"})
  const right = xstream.of({bbb: "bbb"})

  streamSatisfies(
    "{bbb: \"bbb\"}---{aaa: \"aaa\"}---|"
  )(
    (given) => (expected) => same(given, expected)
  )(
    doesNotThrow
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    mergeRight(left)(right)
  )
})

test("String diagram", ({equal, doesNotThrow, end}) => {
  const left = xstream.of("a")
  const right = xstream.of("b")

  streamSatisfies(
    "'b'---'a'--=>"
  )(
    (given) => (expected) => equal(given, expected)
  )(
    doesNotThrow
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    mergeRight(left)(right)
  )
})

test("Array diagram", ({equal, doesNotThrow, end}) => {
  const left = xstream.of("a")
  const right = xstream.of("b")

  streamSatisfies(
    ["b", "a"]
  )(
    (given) => (expected) => equal(given, expected)
  )(
    doesNotThrow
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    mergeRight(left)(right)
  )
})

test("Array diagram", ({equal, doesNotThrow, end}) => {
  const left = xstream.of(1)
  const right = xstream.of(2)

  streamSatisfies(
    [2, 1]
  )(
    (given) => (expected) => equal(given, expected)
  )(
    doesNotThrow
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    mergeRight(left)(right)
  )
})

test("Array diagram", ({same, equal, doesNotThrow, end}) => {
  const left = xstream.of({aaa: "aaa"})
  const right = xstream.of({bbb: "bbb"})

  streamSatisfies(
    [{bbb: "bbb"}, {aaa: "aaa"}]
  )(
    (given) => (expected) => same(given, expected)
  )(
    doesNotThrow
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    mergeRight(left)(right)
  )
})


test("Array diagram with error", ({equal, match, end}) => {
  const stream = xstream
    .from([
      {unction: () => true},
      {unction: () => true},
      null,
    ])
    .map((object) => object.unction())

  streamSatisfies(
    [true, true]
  )(
    (given) => (expected) => equal(given, expected)
  )(
    (exception) => {
      match(exception, TypeError)
      end()
    }
  )(
    ({length}) => (size) => {
      equal(length, size)

      end()
    }
  )(
    stream
  )
})

supertype()

Tests Stability Dependencies

{constructor: {prototype: Object}} => string

Return the super type of an value.

class A {}
class B extends A {}

supertype(new B()) // "A"

takeFirst()

Tests Stability Dependencies

number => Array<V> | string => Array<V> | string

Returns the first N of a list of ordered values.

takeFirst(2)([1, 2, 3]) // [1, 2]
takeFirst(1)([1, 2, 3]) // [1]
takeFirst(2)("abc") // "ab"
takeFirst(1)("abc") // "a"

takeLast()

Tests Stability Dependencies

number => Array<V> | string => Array<V> | string

Returns the last N of a list of ordered values.

takeLast(2)([1, 2, 3]) // [2, 3]
takeLast(1)([1, 2, 3]) // [3]
takeLast(2)("abc") // "bc"
takeLast(1)("abc") // "c"

thenCatchP()

Tests Stability Dependencies

MapperFunctionType<A, B> => MapperFunctionType<C, B> => Promise<A> => Promise<D | B>

A port of the Promise.prototype.then() function, but with the extra catch argument.

Credit: @keithamus

thenCatchP(
  ([user, project]) => console.log(user, project)
)(
  (exception) => console.error(exception)
)(Promise.all([fetchUser, fetchProject]))

thenP()

Tests Stability Dependencies

MapperFunctionType<A, B> => Promise<A> => Promise<D | B>

A port of the Promise.prototype.then() function.

Credit: @keithamus

thenP(
  ([user, project]) => console.log(user, project)
)(Promise.all([fetchUser, fetchProject]))

thrush()

Tests Stability Dependencies

A => MapperFunctionType<A, B> => B

One of the fantasy birds: it takes a value, a function, and then applies that value to as the first argument to that function.

thrush(0)((value) => `${value}`) // "0"

treeify()

Tests Stability Dependencies

Array<FoldFunctionType<A, B>> => Array<A> => TreeType<C>

This takes a list of functions (the folders) and an array of objects or an object of objects (the collection) to create a tree. Each function in the list of folders will in some way return a new object. All of the objects produced are then turned into a final tree.

const collection = [
  {
    id: "a1",
    type: "resources",
    attributes: {
      version: "v1",
      namespace: "accounts",
    }
  },
  {
    id: "a2",
    type: "resources",
    attributes: {
      version: "v1",
      namespace: "accounts",
    }
  },
  {
    id: "b1",
    type: "resources",
    attributes: {
      version: "v1",
      namespace: "profiles",
    }
  },
  {
    id: "b1",
    type: "resources",
    attributes: {
      version: "v2",
      namespace: "profiles",
    }
  }
]

The order goes from outer layer to deeper layer, so in this case the outer level properties will be based on key("type"), and the deepest layer properties will be based on key("id").

const functions =

treeify(
  [
    groupBy(key("type")),
    groupBy(keyChain(["attributes", "namespace"])),
    groupBy(keyChain(["attributes", "version"])),
    indexBy(key("id")),
  ]
)(
  collection
)

The resulting object looks like this:

{
  resources: {
    accounts: {
      v1: {
        a1: {
          id: "a1",
          type: "resources",
          attributes: {
            version: "v1",
            namespace: "accounts",
          }
        },
        a2: {
          id: "a2",
          type: "resources",
          attributes: {
            version: "v1",
            namespace: "accounts",
          }
        }
      }
    },
    profiles: {
      v1: {
        b1: {
          id: "b1",
          type: "resources",
          attributes: {
            version: "v1",
            namespace: "profiles",
          }
        }
      },
      v2: {
        b1: {
          id: "b1",
          type: "resources",
          attributes: {
            version: "v2",
            namespace: "profiles",
          }
        }
      }
    }
  }
}

type()

Tests Stability Dependencies

(null | void | {constructor: {name: string}}) => string

Returns the type name of the value provided.

type("a") // "String"
type(1) // "Number"
type({}) // "Object"
type([]) // "Array"
type(true) // "Boolean"
type(null) // "null"
type(undefined) // "undefined"

upTo()

Tests Stability Dependencies

number => Array<number>

Just takes a maximum and produces an array of 1 to that number.

upTo(10) // [1,2,3,4,5,6,7,8,9,10]

values()

Tests Stability Dependencies

Array<A> | Set<A> | Record<string | number | symbol, B> | Map<B, A> | string => Array<A>

Takes an iterable and returns it's values.

values({aaa: "111", bbb: "222"}) // ["111", "222"]
values(["aaa", "bbb"]) // ["aaa", "bbb"]

where()

Tests Stability Dependencies

PredicateFunctionType<A> => KeyedArray<B> | Set<B> | Record<string | number | symbol, unknown> | Map<B, unknown> | string => boolean

Compares a Keyed Enumerable of Predicate Functions to a Enumerable of values. It is partial and prefers truthiness (meaning it only checks a key on the Functor if there is a key on the matcher).

where(
  {name: equals("Kurtis Rainbolt-Greene")}
)({
  name: "Kurtis Rainbolt-Greene",
  age: 30,
}) // true
where(
  {name: equals("Kurtis Rainbolt-Greene")}
)(
  new Map([
    [
      "name",
      "Kurtis Rainbolt-Greene",
    ],
    [
      "age",
      30,
    ],
  ])
)
where(
  new Map([
    [
      [
        "attributes",
        "name",
      ],
      equals("Kurtis Rainbolt-Greene"),
    ],
  ])
)({
  attributes: {
    name: "Kurtis Rainbolt-Greene",
    age: 30,
  },
}) // true
where(
  [
    equals("Kurtis Rainbolt-Greene"),
  ]
)(
  [
    "Kurtis Rainbolt-Greene",
    30,
  ]
) // true

withoutKeyRecursive()

Tests Stability Dependencies

A => Record<string | number | symbol, B> | Map<A, B> => Record<string | number | symbol, B> | Map<A, B>

Returns a copy of an iterable without a key, no matter how deep the tree.

withoutKeyRecursive("__abstraction__")(
  {
    id: "1",
    name: "Kurtis Rainbolt-Greene",
    attributes: {
      version: "v1",
      namespace: "accounts",
      __abstraction__: {errors: []},
    },
    __abstraction__: {errors: []},
  }
)

Which will return:

{
  id: "1",
  name: "Kurtis Rainbolt-Greene",
  attributes: {
    version: "v1",
    namespace: "accounts",
  },
}

withoutKeys()

Tests Stability Dependencies

Array<A> => Record<string | number | symbol, B> | Map<A, B> => Record<string | number | symbol, B> | Map<A, B>

Takes a enumerable that has keys and returns the same type where all the given keys don't exist.

withoutKeys(["a", "b", "c"])({b: 2, d: 3}) // {d: 3}
withoutKeys(["a", "b", "c"])(new Map([["b", 2], ["d", 3]])) // Map([["d", 3]]))

zip()

Tests Stability Dependencies

ListType<R> | RecordType<unknown, R> | string => ListType<L> | RecordType<unknown, L> | string => ListType<[R, L]> | RecordType<unknown, [R, L]>

Takes two iterables and merges them together, combining their values into an array

zip([1, 2, 3])([4, 5, 6])

returns

[[1, 4], [2, 5], [3, 6]]
zip({x: 1, y: 2, z: 0})({x: 0, y: 0, z: 0})

returns

{x: [1, 0], y: [2, 0], z: [0, 0]}

matchesRegExp()

Tests Stability Dependencies

RegExp => string => Boolean

Compares a regular expression and a string.

matchesRegExp(/abcd/)("abcde") // true

Readme

Keywords

Package Sidebar

Install

npm i @unction/complete

Weekly Downloads

0

Version

21.4.0

License

SEE LICENSE IN LICENSE

Unpacked Size

195 kB

Total Files

7

Last publish

Collaborators

  • krainboltgreene