rambdax
rambdax copied to clipboard
Extended version of Rambda
Rambdax
Extended version of Rambda(utility library) - Documentation
Rambda
is smaller and faster alternative to the popular functional programming library Ramda. - Documentation
❯ Differences between Rambda and Rambdax
Rambdax passthrough all Rambda methods and introduce some new functions.
The idea of Rambdax is to extend Rambda without worring for Ramda compatibility.
❯ Example use
import { composeAsync, filter, delay, mapAsync } from 'rambdax'
const result = await composeAsync(
mapAsync(async x => {
await delay(100)
return x + 1
}),
filter(x => x > 1)
)([1, 2, 3])
// => [3, 4]
You can test this example in Rambda's REPL
- Differences between Rambda and Ramda
- API
- Changelog
❯ Rambdax's advantages
Typescript included
Typescript definitions are included in the library, in comparison to Ramda, where you need to additionally install @types/ramda
.
Still, you need to be aware that functional programming features in Typescript
are in development, which means that using R.compose/R.pipe can be problematic.
Important - Rambdax version 9.0.0
(or higher) requires Typescript version 4.3.3
(or higher).
Dot notation for R.path
, R.paths
, R.assocPath
and R.lensPath
Standard usage of R.path
is R.path(['a', 'b'], {a: {b: 1} })
.
In Rambda you have the choice to use dot notation(which is arguably more readable):
R.path('a.b', {a: {b: 1} })
Comma notation for R.pick
and R.omit
Similar to dot notation, but the separator is comma(,
) instead of dot(.
).
R.pick('a,b', {a: 1 , b: 2, c: 3} })
// No space allowed between properties
Extendable with Ramda community projects
Rambdax
implements some methods from Ramda
community projects, such as R.lensSatisfies
, R.lensEq
and R.viewOr
.
Alternative TS definitions
Alternative TS definitions are available as rambdax/immutable
. These are Rambdax definitions linted with ESLint functional/prefer-readonly-type
plugin.
❯ Missing Ramda methods
Click to see the full list of 78 Ramda methods not implemented in Rambda
- __
- addIndex
- ap
- aperture
- applyTo
- ascend
- binary
- call
- collectBy
- comparator
- composeWith
- construct
- constructN
- descend
- differenceWith
- dissocPath
- empty
- eqBy
- forEachObjIndexed
- gt
- gte
- hasIn
- innerJoin
- insert
- insertAll
- into
- invert
- invertObj
- invoker
- keysIn
- lift
- liftN
- lt
- lte
- mapAccum
- mapAccumRight
- memoizeWith
- mergeDeepLeft
- mergeDeepWith
- mergeDeepWithKey
- mergeWithKey
- modify
- nAry
- nthArg
- o
- otherwise
- pair
- partialRight
- pathSatisfies
- pickBy
- pipeWith
- project
- promap
- reduceBy
- reduceRight
- reduceWhile
- reduced
- remove
- scan
- sequence
- sortWith
- splitWhenever
- symmetricDifferenceWith
- andThen
- toPairsIn
- transduce
- traverse
- unary
- uncurryN
- unfold
- unionWith
- unnest
- until
- useWith
- valuesIn
- xprod
- thunkify
- default
❯ Install
-
yarn add rambdax
-
For UMD usage either use
./dist/rambdax.umd.js
or the following CDN link:
https://unpkg.com/rambdax@CURRENT_VERSION/dist/rambdax.umd.js
- with deno
import {compose, add} from 'https://raw.githubusercontent.com/selfrefactor/rambdax/master/dist/rambdax.esm.js'
Differences between Rambda and Ramda
-
Rambda's type detects async functions and unresolved
Promises
. The returned values are'Async'
and'Promise'
. -
Rambda's type handles NaN input, in which case it returns
NaN
. -
Rambda's forEach can iterate over objects not only arrays.
-
Rambda's map, filter, partition when they iterate over objects, they pass property and input object as predicate's argument.
-
Rambda's filter returns empty array with bad input(
null
orundefined
), while Ramda throws. -
Ramda's clamp work with strings, while Rambda's method work only with numbers.
-
Ramda's indexOf/lastIndexOf work with strings and lists, while Rambda's method work only with lists as iterable input.
-
Error handling, when wrong inputs are provided, may not be the same. This difference will be better documented once all brute force tests are completed.
-
Typescript definitions between
rambda
and@types/ramda
may vary.
❯ Benchmarks
Click to expand all benchmark results
There are methods which are benchmarked only with Ramda
and Rambda
(i.e. no Lodash
).
Note that some of these methods, are called with and without curring. This is done in order to give more detailed performance feedback.
The benchmarks results are produced from latest versions of Rambda, Lodash(4.17.21) and Ramda(0.28.0).
Ramda
and Rambda
(i.e. no Lodash
).method | Rambda | Ramda | Lodash |
---|---|---|---|
add | 🚀 Fastest | 21.52% slower | 82.15% slower |
adjust | 8.48% slower | 🚀 Fastest | 🔳 |
all | 🚀 Fastest | 1.81% slower | 🔳 |
allPass | 🚀 Fastest | 91.09% slower | 🔳 |
allPass | 🚀 Fastest | 98.56% slower | 🔳 |
and | 🚀 Fastest | 89.09% slower | 🔳 |
any | 🚀 Fastest | 92.87% slower | 45.82% slower |
anyPass | 🚀 Fastest | 98.25% slower | 🔳 |
append | 🚀 Fastest | 2.07% slower | 🔳 |
applySpec | 🚀 Fastest | 80.43% slower | 🔳 |
assoc | 72.32% slower | 60.08% slower | 🚀 Fastest |
clone | 🚀 Fastest | 91.86% slower | 86.48% slower |
compose | 🚀 Fastest | 32.45% slower | 13.68% slower |
converge | 78.63% slower | 🚀 Fastest | 🔳 |
curry | 🚀 Fastest | 28.86% slower | 🔳 |
curryN | 🚀 Fastest | 41.05% slower | 🔳 |
defaultTo | 🚀 Fastest | 48.91% slower | 🔳 |
drop | 🚀 Fastest | 82.35% slower | 🔳 |
dropLast | 🚀 Fastest | 86.74% slower | 🔳 |
equals | 58.37% slower | 96.73% slower | 🚀 Fastest |
filter | 6.7% slower | 72.03% slower | 🚀 Fastest |
find | 🚀 Fastest | 85.14% slower | 42.65% slower |
findIndex | 🚀 Fastest | 86.48% slower | 72.27% slower |
flatten | 🚀 Fastest | 95.26% slower | 10.27% slower |
ifElse | 🚀 Fastest | 58.56% slower | 🔳 |
includes | 🚀 Fastest | 84.63% slower | 🔳 |
indexOf | 🚀 Fastest | 76.63% slower | 🔳 |
indexOf | 🚀 Fastest | 82.2% slower | 🔳 |
init | 🚀 Fastest | 92.24% slower | 13.3% slower |
is | 🚀 Fastest | 57.69% slower | 🔳 |
isEmpty | 🚀 Fastest | 97.14% slower | 54.99% slower |
last | 🚀 Fastest | 93.43% slower | 5.28% slower |
lastIndexOf | 🚀 Fastest | 85.19% slower | 🔳 |
map | 🚀 Fastest | 86.6% slower | 11.73% slower |
match | 🚀 Fastest | 44.83% slower | 🔳 |
merge | 🚀 Fastest | 12.21% slower | 55.76% slower |
none | 🚀 Fastest | 96.48% slower | 🔳 |
objOf | 🚀 Fastest | 38.05% slower | 🔳 |
omit | 🚀 Fastest | 69.95% slower | 97.34% slower |
over | 🚀 Fastest | 56.23% slower | 🔳 |
path | 37.81% slower | 77.81% slower | 🚀 Fastest |
pick | 🚀 Fastest | 19.07% slower | 80.2% slower |
pipe | 0.87% slower | 🚀 Fastest | 🔳 |
prop | 🚀 Fastest | 87.95% slower | 🔳 |
propEq | 🚀 Fastest | 91.92% slower | 🔳 |
range | 🚀 Fastest | 61.8% slower | 57.44% slower |
reduce | 60.48% slower | 77.1% slower | 🚀 Fastest |
repeat | 48.57% slower | 68.98% slower | 🚀 Fastest |
replace | 33.45% slower | 33.99% slower | 🚀 Fastest |
set | 🚀 Fastest | 50.35% slower | 🔳 |
sort | 🚀 Fastest | 40.23% slower | 🔳 |
sortBy | 🚀 Fastest | 25.29% slower | 56.88% slower |
split | 🚀 Fastest | 55.37% slower | 17.64% slower |
splitEvery | 🚀 Fastest | 71.98% slower | 🔳 |
take | 🚀 Fastest | 91.96% slower | 4.72% slower |
takeLast | 🚀 Fastest | 93.39% slower | 19.22% slower |
test | 🚀 Fastest | 82.34% slower | 🔳 |
type | 🚀 Fastest | 48.6% slower | 🔳 |
uniq | 🚀 Fastest | 90.24% slower | 🔳 |
uniqWith | 18.09% slower | 🚀 Fastest | 🔳 |
uniqWith | 14.23% slower | 🚀 Fastest | 🔳 |
update | 🚀 Fastest | 52.35% slower | 🔳 |
view | 🚀 Fastest | 76.15% slower | 🔳 |
❯ Used by
-
Walmart Canada reported by w-b-dev
API
add
add(a: number, b: number): number
It adds a
and b
.
:boom: It doesn't work with strings, as the inputs are parsed to numbers before calculation.
R.add(2, 3) // => 5
Try this R.add example in Rambda REPL
R.add source
export function add(a, b){
if (arguments.length === 1) return _b => add(a, _b)
return Number(a) + Number(b)
}
adjust
adjust<T>(index: number, replaceFn: (x: T) => T, list: T[]): T[]
It replaces index
in array list
with the result of replaceFn(list[i])
.
R.adjust(
0,
a => a + 1,
[0, 100]
) // => [1, 100]
Try this R.adjust example in Rambda REPL
R.adjust source
import { cloneList } from './_internals/cloneList.js'
import { curry } from './curry.js'
function adjustFn(
index, replaceFn, list
){
const actualIndex = index < 0 ? list.length + index : index
if (index >= list.length || actualIndex < 0) return list
const clone = cloneList(list)
clone[ actualIndex ] = replaceFn(clone[ actualIndex ])
return clone
}
export const adjust = curry(adjustFn)
all
all<T>(predicate: (x: T) => boolean, list: T[]): boolean
It returns true
, if all members of array list
returns true
, when applied as argument to predicate
function.
const list = [ 0, 1, 2, 3, 4 ]
const predicate = x => x > -1
const result = R.all(predicate, list)
// => true
Try this R.all example in Rambda REPL
R.all source
export function all(predicate, list){
if (arguments.length === 1) return _list => all(predicate, _list)
for (let i = 0; i < list.length; i++){
if (!predicate(list[ i ])) return false
}
return true
}
allFalse
allFalse(...inputs: any[]): boolean
It returns true
if all inputs
arguments are falsy(empty objects and empty arrays are considered falsy).
Functions are valid inputs, but these functions cannot have their own arguments.
This method is very similar to R.anyFalse
, R.anyTrue
and R.allTrue
R.allFalse(0, null, [], {}, '', () => false)
// => true
Try this R.allFalse example in Rambda REPL
R.allFalse source
import { isTruthy } from './_internals/isTruthy.js'
import { type } from './type.js'
export function allFalse(...inputs){
let counter = 0
while (counter < inputs.length){
const x = inputs[ counter ]
if (type(x) === 'Function'){
if (isTruthy(x())){
return false
}
} else if (isTruthy(x)){
return false
}
counter++
}
return true
}
allPass
allPass<T>(predicates: ((x: T) => boolean)[]): (input: T) => boolean
It returns true
, if all functions of predicates
return true
, when input
is their argument.
const input = {
a : 1,
b : 2,
}
const predicates = [
x => x.a === 1,
x => x.b === 2,
]
const result = R.allPass(predicates)(input) // => true
Try this R.allPass example in Rambda REPL
R.allPass source
export function allPass(predicates){
return (...input) => {
let counter = 0
while (counter < predicates.length){
if (!predicates[ counter ](...input)){
return false
}
counter++
}
return true
}
}
allTrue
allTrue(...input: any[]): boolean
It returns true
if all inputs
arguments are truthy(empty objects and empty arrays are considered falsy).
R.allTrue(1, true, {a: 1}, [1], 'foo', () => true)
// => true
Try this R.allTrue example in Rambda REPL
R.allTrue source
import { isFalsy } from './_internals/isFalsy.js'
import { type } from './type.js'
export function allTrue(...inputs){
let counter = 0
while (counter < inputs.length){
const x = inputs[ counter ]
if (type(x) === 'Function'){
if (isFalsy(x())){
return false
}
} else if (isFalsy(x)){
return false
}
counter++
}
return true
}
allType
allType(targetType: RambdaTypes): (...input: any[]) => boolean
It returns a function which will return true
if all of its inputs
arguments belong to targetType
.
:boom:
targetType
is one of the possible returns ofR.type
const targetType = 'String'
const result = R.allType(
targetType
)('foo', 'bar', 'baz')
// => true
Try this R.allType example in Rambda REPL
R.allType source
import { type } from './type.js'
export function allType(targetType){
return (...inputs) => {
let counter = 0
while (counter < inputs.length){
if (type(inputs[ counter ]) !== targetType){
return false
}
counter++
}
return true
}
}
always
always<T>(x: T): (...args: unknown[]) => T
It returns function that always returns x
.
const fn = R.always(7)
const result = fn()
// => 7
Try this R.always example in Rambda REPL
R.always source
export function always(x){
return _ => x
}
and
Logical AND
R.and(true, true); // => true
R.and(false, true); // => false
R.and(true, 'foo'); // => 'foo'
Try this R.and example in Rambda REPL
any
any<T>(predicate: (x: T) => boolean, list: T[]): boolean
It returns true
, if at least one member of list
returns true, when passed to a predicate
function.
const list = [1, 2, 3]
const predicate = x => x * x > 8
R.any(fn, list)
// => true
Try this R.any example in Rambda REPL
R.any source
export function any(predicate, list){
if (arguments.length === 1) return _list => any(predicate, _list)
let counter = 0
while (counter < list.length){
if (predicate(list[ counter ], counter)){
return true
}
counter++
}
return false
}
anyFalse
anyFalse(...input: any[]): boolean
It returns true
if any of inputs
is falsy(empty objects and empty arrays are considered falsy).
R.anyFalse(1, {a: 1}, [1], () => false)
// => true
Try this R.anyFalse example in Rambda REPL
R.anyFalse source
import { isFalsy } from './_internals/isFalsy.js'
import { type } from './type.js'
export function anyFalse(...inputs){
let counter = 0
while (counter < inputs.length){
const x = inputs[ counter ]
if (type(x) === 'Function'){
if (isFalsy(x())){
return true
}
} else if (isFalsy(x)){
return true
}
counter++
}
return false
}
anyPass
anyPass<T>(predicates: ((x: T) => boolean)[]): (input: T) => boolean
It accepts list of predicates
and returns a function. This function with its input
will return true
, if any of predicates
returns true
for this input
.
const isBig = x => x > 20
const isOdd = x => x % 2 === 1
const input = 11
const fn = R.anyPass(
[isBig, isOdd]
)
const result = fn(input)
// => true
Try this R.anyPass example in Rambda REPL
R.anyPass source
export function anyPass(predicates){
return (...input) => {
let counter = 0
while (counter < predicates.length){
if (predicates[ counter ](...input)){
return true
}
counter++
}
return false
}
}
anyTrue
anyTrue(...input: any[]): boolean
It returns true
if any of inputs
arguments are truthy(empty objects and empty arrays are considered falsy).
R.anyTrue(0, null, [], {}, '', () => true)
// => true
Try this R.anyTrue example in Rambda REPL
R.anyTrue source
import { isTruthy } from './_internals/isTruthy.js'
import { type } from './type.js'
export function anyTrue(...inputs){
let counter = 0
while (counter < inputs.length){
const x = inputs[ counter ]
if (type(x) === 'Function'){
if (isTruthy(x())){
return true
}
} else if (isTruthy(x)){
return true
}
counter++
}
return false
}
anyType
anyType(targetType: RambdaTypes): (...input: any[]) => boolean
It returns a function which will return true
if at least one of its inputs
arguments belongs to targetType
.
targetType
is one of the possible returns of R.type
:boom:
targetType
is one of the possible returns ofR.type
const targetType = 'String'
const result = R.anyType(
targetType
)(1, {}, 'foo')
// => true
Try this R.anyType example in Rambda REPL
R.anyType source
import { type } from './type.js'
export function anyType(targetType){
return (...inputs) => {
let counter = 0
while (counter < inputs.length){
if (type(inputs[ counter ]) === targetType){
return true
}
counter++
}
return false
}
}
append
append<T>(x: T, list: T[]): T[]
It adds element x
at the end of list
.
const x = 'foo'
const result = R.append(x, ['bar', 'baz'])
// => ['bar', 'baz', 'foo']
Try this R.append example in Rambda REPL
R.append source
import { cloneList } from './_internals/cloneList.js'
export function append(x, input){
if (arguments.length === 1) return _input => append(x, _input)
if (typeof input === 'string') return input.split('').concat(x)
const clone = cloneList(input)
clone.push(x)
return clone
}
apply
apply<T = any>(fn: (...args: any[]) => T, args: any[]): T
It applies function fn
to the list of arguments.
This is useful for creating a fixed-arity function from a variadic function. fn
should be a bound function if context is significant.
const result = R.apply(Math.max, [42, -Infinity, 1337])
// => 1337
Try this R.apply example in Rambda REPL
R.apply source
export function apply(fn, args){
if (arguments.length === 1){
return _args => apply(fn, _args)
}
return fn.apply(this, args)
}
applyDiff
applyDiff<Output>(rules: ApplyDiffRule[], obj: object): Output
It changes paths in an object according to a list of operations. Valid operations are add
, update
and delete
. Its use-case is while writing tests and you need to change the test data.
Note, that you cannot use update
operation, if the object path is missing in the input object.
Also, you cannot use add
operation, if the object path has a value.
const obj = {a: {b:1, c:2}}
const rules = [
{op: 'remove', path: 'a.c'},
{op: 'add', path: 'a.d', value: 4},
{op: 'update', path: 'a.b', value: 2},
]
const result = R.applyDiff(rules, Record<string, unknown>)
const expected = {a: {b: 2, d: 4}}
// => `result` is equal to `expected`
Try this R.applyDiff example in Rambda REPL
R.applyDiff source
import { createPath } from './_internals/createPath.js'
import { assocPath } from './assocPath.js'
import { path as pathModule } from './path.js'
const ALLOWED_OPERATIONS = [ 'remove', 'add', 'update' ]
export function removeAtPath(path, obj){
const p = createPath(path)
const len = p.length
if (len === 0) return
if (len === 1) return delete obj[ p[ 0 ] ]
if (len === 2) return delete obj[ p[ 0 ] ][ p[ 1 ] ]
if (len === 3) return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ]
if (len === 4) return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ]
if (len === 5) return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ]
if (len === 6){
return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ]
}
if (len === 7){
return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ]
}
if (len === 8){
return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ][ p[ 7 ] ]
}
if (len === 9){
return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ][ p[ 7 ] ][ p[ 8 ] ]
}
if (len === 10){
return delete obj[ p[ 0 ] ][ p[ 1 ] ][ p[ 2 ] ][ p[ 3 ] ][ p[ 4 ] ][ p[ 5 ] ][ p[ 6 ] ][ p[ 7 ] ][ p[ 8 ] ][
p[ 9 ]
]
}
}
export function applyDiff(rules, obj){
if (arguments.length === 1) return _obj => applyDiff(rules, _obj)
let clone = { ...obj }
rules.forEach(({ op, path, value }) => {
if (!ALLOWED_OPERATIONS.includes(op)) return
if (op === 'add' && path && value !== undefined){
if (pathModule(path, obj)) return
return clone = assocPath(
path, value, clone
)
}
if (op === 'remove'){
if (pathModule(path, obj) === undefined) return
return removeAtPath(path, clone)
}
if (op === 'update' && path && value !== undefined){
if (pathModule(path, obj) === undefined) return
return clone = assocPath(
path, value, clone
)
}
})
return clone
}
applySpec
applySpec<Spec extends Record<string, AnyFunction>>(
spec: Spec
): (
...args: Parameters<ValueOfRecord<Spec>>
) => { [Key in keyof Spec]: ReturnType<Spec[Key]> }
:boom: The currying in this function works best with functions with 4 arguments or less. (arity of 4)
const fn = R.applySpec({
sum: R.add,
nested: { mul: R.multiply }
})
const result = fn(2, 4)
// => { sum: 6, nested: { mul: 8 } }
Try this R.applySpec example in Rambda REPL
R.applySpec source
import { _isArray } from './_internals/_isArray.js'
// recursively traverse the given spec object to find the highest arity function
export function __findHighestArity(spec, max = 0){
for (const key in spec){
if (spec.hasOwnProperty(key) === false || key === 'constructor') continue
if (typeof spec[ key ] === 'object'){
max = Math.max(max, __findHighestArity(spec[ key ]))
}
if (typeof spec[ key ] === 'function'){
max = Math.max(max, spec[ key ].length)
}
}
return max
}
function __filterUndefined(){
const defined = []
let i = 0
const l = arguments.length
while (i < l){
if (typeof arguments[ i ] === 'undefined') break
defined[ i ] = arguments[ i ]
i++
}
return defined
}
function __applySpecWithArity(
spec, arity, cache
){
const remaining = arity - cache.length
if (remaining === 1)
return x =>
__applySpecWithArity(
spec, arity, __filterUndefined(...cache, x)
)
if (remaining === 2)
return (x, y) =>
__applySpecWithArity(
spec, arity, __filterUndefined(
...cache, x, y
)
)
if (remaining === 3)
return (
x, y, z
) =>
__applySpecWithArity(
spec, arity, __filterUndefined(
...cache, x, y, z
)
)
if (remaining === 4)
return (
x, y, z, a
) =>
__applySpecWithArity(
spec,
arity,
__filterUndefined(
...cache, x, y, z, a
)
)
if (remaining > 4)
return (...args) =>
__applySpecWithArity(
spec, arity, __filterUndefined(...cache, ...args)
)
// handle spec as Array
if (_isArray(spec)){
const ret = []
let i = 0
const l = spec.length
for (; i < l; i++){
// handle recursive spec inside array
if (typeof spec[ i ] === 'object' || _isArray(spec[ i ])){
ret[ i ] = __applySpecWithArity(
spec[ i ], arity, cache
)
}
// apply spec to the key
if (typeof spec[ i ] === 'function'){
ret[ i ] = spec[ i ](...cache)
}
}
return ret
}
// handle spec as Object
const ret = {}
// apply callbacks to each property in the spec object
for (const key in spec){
if (spec.hasOwnProperty(key) === false || key === 'constructor') continue
// apply the spec recursively
if (typeof spec[ key ] === 'object'){
ret[ key ] = __applySpecWithArity(
spec[ key ], arity, cache
)
continue
}
// apply spec to the key
if (typeof spec[ key ] === 'function'){
ret[ key ] = spec[ key ](...cache)
}
}
return ret
}
export function applySpec(spec, ...args){
// get the highest arity spec function, cache the result and pass to __applySpecWithArity
const arity = __findHighestArity(spec)
if (arity === 0){
return () => ({})
}
const toReturn = __applySpecWithArity(
spec, arity, args
)
return toReturn
}
assoc
assoc<T, U, K extends string>(prop: K, val: T, obj: U): Record<K, T> & Omit<U, K>
It makes a shallow clone of obj
with setting or overriding the property prop
with newValue
.
:boom: This copies and flattens prototype properties onto the new object as well. All non-primitive properties are copied by reference.
R.assoc('c', 3, {a: 1, b: 2})
// => {a: 1, b: 2, c: 3}
Try this R.assoc example in Rambda REPL
R.assoc source
import { curry } from './curry.js'
function assocFn(
prop, newValue, obj
){
return Object.assign(
{}, obj, { [ prop ] : newValue }
)
}
export const assoc = curry(assocFn)
assocPath
assocPath<Output>(path: Path, newValue: any, obj: object): Output
It makes a shallow clone of obj
with setting or overriding with newValue
the property found with path
.
const path = 'b.c'
const newValue = 2
const obj = { a: 1 }
R.assocPath(path, newValue, Record<string, unknown>)
// => { a : 1, b : { c : 2 }}
Try this R.assocPath example in Rambda REPL
R.assocPath source
import { _isArray } from './_internals/_isArray.js'
import { _isInteger } from './_internals/_isInteger.js'
import { cloneList } from './_internals/cloneList.js'
import { assoc } from './assoc.js'
import { curry } from './curry.js'
function assocPathFn(
path, newValue, input
){
const pathArrValue =
typeof path === 'string' ?
path.split('.').map(x => _isInteger(Number(x)) ? Number(x) : x) :
path
if (pathArrValue.length === 0){
return newValue
}
const index = pathArrValue[ 0 ]
if (pathArrValue.length > 1){
const condition =
typeof input !== 'object' ||
input === null ||
!input.hasOwnProperty(index)
const nextinput = condition ?
_isInteger(pathArrValue[ 1 ]) ?
[] :
{} :
input[ index ]
newValue = assocPathFn(
Array.prototype.slice.call(pathArrValue, 1),
newValue,
nextinput
)
}
if (_isInteger(index) && _isArray(input)){
const arr = cloneList(input)
arr[ index ] = newValue
return arr
}
return assoc(
index, newValue, input
)
}
export const assocPath = curry(assocPathFn)
bind
bind<F extends AnyFunction, T>(fn: F, thisObj: T): (...args: Parameters<F>) => ReturnType<F>
Creates a function that is bound to a context.
:boom: R.bind does not provide the additional argument-binding capabilities of
Function.prototype.bind
.
const log = R.bind(console.log, console)
const result = R.pipe(
R.assoc('a', 2),
R.tap(log),
R.assoc('a', 3)
)({a: 1});
// => result - `{a: 3}`
// => console log - `{a: 2}`
Try this R.bind example in Rambda REPL
R.bind source
import { curryN } from './curryN.js'
export function bind(fn, thisObj){
if (arguments.length === 1){
return _thisObj => bind(fn, _thisObj)
}
return curryN(fn.length, (...args) => fn.apply(thisObj, args))
}
both
both(pred1: Pred, pred2: Pred): Pred
It returns a function with input
argument.
This function will return true
, if both firstCondition
and secondCondition
return true
when input
is passed as their argument.
const firstCondition = x => x > 10
const secondCondition = x => x < 20
const fn = R.both(firstCondition, secondCondition)
const result = [fn(15), fn(30)]
// => [true, false]
Try this R.both example in Rambda REPL
R.both source
export function both(f, g){
if (arguments.length === 1) return _g => both(f, _g)
return (...input) => f(...input) && g(...input)
}
chain
chain<T, U>(fn: (n: T) => U[], list: T[]): U[]
The method is also known as flatMap
.
const duplicate = n => [ n, n ]
const list = [ 1, 2, 3 ]
const result = chain(duplicate, list)
// => [ 1, 1, 2, 2, 3, 3 ]
Try this R.chain example in Rambda REPL
R.chain source
export function chain(fn, list){
if (arguments.length === 1){
return _list => chain(fn, _list)
}
return [].concat(...list.map(fn))
}
clamp
Restrict a number input
to be within min
and max
limits.
If input
is bigger than max
, then the result is max
.
If input
is smaller than min
, then the result is min
.
const result = [
R.clamp(0, 10, 5),
R.clamp(0, 10, -1),
R.clamp(0, 10, 11)
]
// => [5, 0, 10]
Try this R.clamp example in Rambda REPL
clone
It creates a deep copy of the input
, which may contain (nested) Arrays and Objects, Numbers, Strings, Booleans and Dates.
const objects = [{a: 1}, {b: 2}];
const objectsClone = R.clone(objects);
const result = [
R.equals(objects, objectsClone),
R.equals(objects[0], objectsClone[0]),
] // => [ true, true ]
Try this R.clone example in Rambda REPL
complement
It returns inverted
version of origin
function that accept input
as argument.
The return value of inverted
is the negative boolean value of origin(input)
.
const origin = x => x > 5
const inverted = complement(origin)
const result = [
origin(7),
inverted(7)
] => [ true, false ]
Try this R.complement example in Rambda REPL
compose
It performs right-to-left function composition.
const result = R.compose(
R.map(x => x * 2),
R.filter(x => x > 2)
)([1, 2, 3, 4])
// => [6, 8]
Try this R.compose example in Rambda REPL
composeAsync
composeAsync<Out>(
...fns: (Async<any> | Func<any>)[]
): (input: any) => Promise<Out>
Asynchronous version of R.compose
:boom: It doesn't work with promises or function returning promises such as
const foo = input => new Promise(...)
.
const add = async x => {
await R.delay(100)
return x + 1
}
const multiply = async x => {
await R.delay(100)
return x * 2
}
const result = await R.composeAsync(
add,
multiply
)(1)
// `result` resolves to `3`
Try this R.composeAsync example in Rambda REPL
R.composeAsync source
import { type } from './type.js'
export function composeAsync(...inputArguments){
return async function (startArgument){
let argumentsToPass = startArgument
while (inputArguments.length !== 0){
const fn = inputArguments.pop()
const typeFn = type(fn)
if (typeFn === 'Async'){
argumentsToPass = await fn(argumentsToPass)
} else {
argumentsToPass = fn(argumentsToPass)
if (type(argumentsToPass) === 'Promise'){
argumentsToPass = await argumentsToPass
}
}
}
return argumentsToPass
}
}
concat
It returns a new string or array, which is the result of merging x
and y
.
R.concat([1, 2])([3, 4]) // => [1, 2, 3, 4]
R.concat('foo', 'bar') // => 'foobar'
Try this R.concat example in Rambda REPL
cond
It takes list with conditions
and returns a new function fn
that expects input
as argument.
This function will start evaluating the conditions
in order to find the first winner(order of conditions matter).
The winner is this condition, which left side returns true
when input
is its argument. Then the evaluation of the right side of the winner will be the final result.
If no winner is found, then fn
returns undefined
.
const fn = R.cond([
[ x => x > 25, R.always('more than 25') ],
[ x => x > 15, R.always('more than 15') ],
[ R.T, x => `${x} is nothing special` ],
])
const result = [
fn(30),
fn(20),
fn(10),
]
// => ['more than 25', 'more than 15', '10 is nothing special']
Try this R.cond example in Rambda REPL
contains
contains<T, U>(target: T, compareTo: U): boolean
It returns true
if all of target
object properties are R.equal
to compareTo
object.
const result = R.contains({a:1}, {a:1, b:2})
// => true
Try this R.contains example in Rambda REPL
R.contains source
import { equals } from './equals.js'
export function contains(target, toCompare){
if (arguments.length === 1){
return _toCompare => contains(target, _toCompare)
}
let willReturn = true
Object.keys(target).forEach(prop => {
if (!willReturn) return
if (
toCompare[ prop ] === undefined ||
!equals(target[ prop ], toCompare[ prop ])
){
willReturn = false
}
})
return willReturn
}
converge
Accepts a converging function and a list of branching functions and returns a new function. When invoked, this new function is applied to some arguments, each branching function is applied to those same arguments. The results of each branching function are passed as arguments to the converging function to produce the return value.
:boom: Explanation is taken from
Ramda
documentation
const result = R.converge(R.multiply)([ R.add(1), R.add(3) ])(2)
// => 15
Try this R.converge example in Rambda REPL
count
It counts how many times predicate
function returns true
, when supplied with iteration of list
.
const list = [{a: 1}, 1, {a:2}]
const result = R.count(x => x.a !== undefined, list)
// => 2
Try this R.count example in Rambda REPL
countBy
countBy<T extends unknown>(transformFn: (x: T) => any, list: T[]): Record<string, number>
It counts elements in a list after each instance of the input list is passed through transformFn
function.
const list = [ 'a', 'A', 'b', 'B', 'c', 'C' ]
const result = countBy(R.toLower, list)
const expected = { a: 2, b: 2, c: 2 }
// => `result` is equal to `expected`
Try this R.countBy example in Rambda REPL
R.countBy source
export function countBy(fn, list){
if (arguments.length === 1){
return _list => countBy(fn, _list)
}
const willReturn = {}
list.forEach(item => {
const key = fn(item)
if (!willReturn[ key ]){
willReturn[ key ] = 1
} else {
willReturn[ key ]++
}
})
return willReturn
}
curry
It expects a function as input and returns its curried version.
const fn = (a, b, c) => a + b + c
const curried = R.curry(fn)
const sum = curried(1,2)
const result = sum(3) // => 6
Try this R.curry example in Rambda REPL
curryN
It returns a curried equivalent of the provided function, with the specified arity.
debounce
debounce<T, U>(fn: (input: T) => U, ms: number, immediate?: boolean): (input: T) => void
let counter = 0
const increment = () => {
counter++
}
const debounced = R.debounce(increment, 1000)
async function fn(){
debounced()
await R.delay(500)
debounced()
await R.delay(800)
console.log(counter) // => 0
await R.delay(1200)
console.log(counter) // => 1
return counter
}
const result = await fn()
// `result` resolves to `1`
Try this R.debounce example in Rambda REPL
R.debounce source
export function debounce(
func, ms, immediate = false
){
let timeout
return function (...input){
const later = function (){
timeout = null
if (!immediate){
return func.apply(null, input)
}
}
const callNow = immediate && !timeout
clearTimeout(timeout)
timeout = setTimeout(later, ms)
if (callNow){
return func.apply(null, input)
}
}
}
dec
It decrements a number.
defaultTo
defaultTo<T>(defaultValue: T, input: T | null | undefined): T
It returns defaultValue
, if all of inputArguments
are undefined
, null
or NaN
.
Else, it returns the first truthy inputArguments
instance(from left to right).
:boom: Rambda's defaultTo accept indefinite number of arguments when non curried, i.e.
R.defaultTo(2, foo, bar, baz)
.
R.defaultTo('foo', 'bar') // => 'bar'
R.defaultTo('foo', undefined) // => 'foo'
// Important - emtpy string is not falsy value(same as Ramda)
R.defaultTo('foo', '') // => 'foo'
Try this R.defaultTo example in Rambda REPL
R.defaultTo source
function isFalsy(input){
return (
input === undefined || input === null || Number.isNaN(input) === true
)
}
export function defaultTo(defaultArgument, input){
if (arguments.length === 1){
return _input => defaultTo(defaultArgument, _input)
}
return isFalsy(input) ? defaultArgument : input
}
delay
delay(ms: number): Promise<'RAMBDAX_DELAY'>
setTimeout
as a promise that resolves to R.DELAY
variable after ms
milliseconds.
const result = R.delay(1000)
// `result` resolves to `RAMBDAX_DELAY`
Try this R.delay example in Rambda REPL
R.delay source
export const DELAY = 'RAMBDAX_DELAY'
export function delay(ms){
return new Promise(resolve => {
setTimeout(() => {
resolve(DELAY)
}, ms)
})
}
deletePath
deletePath<T>(path: string): T
R.deletePath source
import { createPath } from './_internals/createPath.js'
import { assocPath } from './assocPath.js'
import { path as pathModule } from './path.js'
function removeProperty(prop, obj){
const toReturn = {}
Object.keys(obj).forEach(key => {
if (key === prop) return
toReturn[ key ] = obj[ key ]
})
return toReturn
}
export function deletePath(pathInput, obj){
if (arguments.length === 1){
return _obj => deletePath(pathInput, _obj)
}
const path = createPath(pathInput)
if (path.length === 0){
return obj
}
if (path.length === 1){
return removeProperty(path[ 0 ], obj)
}
const lastIndex = path.length - 1
const newPath = path.filter((item, i) => i !== lastIndex)
const found = pathModule(newPath, obj)
if (!found) return obj
const newValue = deletePath(path[ lastIndex ], found)
return assocPath(
newPath, newValue, obj
)
}
difference
difference<T>(a: T[], b: T[]): T[]
It returns the uniq set of all elements in the first list a
not contained in the second list b
.
R.equals
is used to determine equality.
const a = [ 1, 2, 3, 4 ]
const b = [ 3, 4, 5, 6 ]
const result = difference(a, b)
// => [ 1, 2 ]
Try this R.difference example in Rambda REPL
R.difference source
import { includes } from './includes.js'
import { uniq } from './uniq.js'
export function difference(a, b){
if (arguments.length === 1) return _b => difference(a, _b)
return uniq(a).filter(aInstance => !includes(aInstance, b))
}
dissoc
It returns a new object that does not contain property prop
.
R.dissoc('b', {a: 1, b: 2, c: 3})
// => {a: 1, c: 3}
Try this R.dissoc example in Rambda REPL
divide
R.divide(71, 100) // => 0.71
Try this R.divide example in Rambda REPL
drop
drop<T>(howMany: number, input: T[]): T[]
It returns howMany
items dropped from beginning of list or string input
.
R.drop(2, ['foo', 'bar', 'baz']) // => ['baz']
R.drop(2, 'foobar') // => 'obar'
Try this R.drop example in Rambda REPL
R.drop source
export function drop(howManyToDrop, listOrString){
if (arguments.length === 1) return _list => drop(howManyToDrop, _list)
return listOrString.slice(howManyToDrop > 0 ? howManyToDrop : 0)
}
dropLast
dropLast<T>(howMany: number, input: T[]): T[]
It returns howMany
items dropped from the end of list or string input
.
R.dropLast(2, ['foo', 'bar', 'baz']) // => ['foo']
R.dropLast(2, 'foobar') // => 'foob'
Try this R.dropLast example in Rambda REPL
R.dropLast source
export function dropLast(howManyToDrop, listOrString){
if (arguments.length === 1){
return _listOrString => dropLast(howManyToDrop, _listOrString)
}
return howManyToDrop > 0 ?
listOrString.slice(0, -howManyToDrop) :
listOrString.slice()
}
dropLastWhile
const list = [1, 2, 3, 4, 5];
const predicate = x => x >= 3
const result = dropLastWhile(predicate, list);
// => [1, 2]
Try this R.dropLastWhile example in Rambda REPL
dropRepeats
dropRepeats<T>(list: T[]): T[]
It removes any successive duplicates according to R.equals
.
const result = R.dropRepeats([
1,
1,
{a: 1},
{a:1},
1
])
// => [1, {a: 1}, 1]
Try this R.dropRepeats example in Rambda REPL
R.dropRepeats source
import { _isArray } from './_internals/_isArray.js'
import { equals } from './equals.js'
export function dropRepeats(list){
if (!_isArray(list)){
throw new Error(`${ list } is not a list`)
}
const toReturn = []
list.reduce((prev, current) => {
if (!equals(prev, current)){
toReturn.push(current)
}
return current
}, undefined)
return toReturn
}
dropRepeatsWith
const list = [{a:1,b:2}, {a:1,b:3}, {a:2, b:4}]
const result = R.dropRepeatsWith(R.prop('a'), list)
// => [{a:1,b:2}, {a:2, b:4}]
Try this R.dropRepeatsWith example in Rambda REPL
dropWhile
const list = [1, 2, 3, 4]
const predicate = x => x < 3
const result = R.dropWhile(predicate, list)
// => [3, 4]
Try this R.dropWhile example in Rambda REPL
either
either(firstPredicate: Pred, secondPredicate: Pred): Pred
It returns a new predicate
function from firstPredicate
and secondPredicate
inputs.
This predicate
function will return true
, if any of the two input predicates return true
.
const firstPredicate = x => x > 10
const secondPredicate = x => x % 2 === 0
const predicate = R.either(firstPredicate, secondPredicate)
const result = [
predicate(15),
predicate(8),
predicate(7),
]
// => [true, true, false]
Try this R.either example in Rambda REPL
R.either source
export function either(firstPredicate, secondPredicate){
if (arguments.length === 1){
return _secondPredicate => either(firstPredicate, _secondPredicate)
}
return (...input) =>
Boolean(firstPredicate(...input) || secondPredicate(...input))
}
endsWith
endsWith(target: string, iterable: string): boolean
When iterable is a string, then it behaves as String.prototype.endsWith
.
When iterable is a list, then it uses R.equals to determine if the target list ends in the same way as the given target.
const str = 'foo-bar'
const list = [{a:1}, {a:2}, {a:3}]
const result = [
R.endsWith('bar', str),
R.endsWith([{a:1}, {a:2}], list)
]
// => [true, true]
Try this R.endsWith example in Rambda REPL
R.endsWith source
import { _isArray } from './_internals/_isArray.js'
import { equals } from './equals.js'
export function endsWith(target, iterable){
if (arguments.length === 1) return _iterable => endsWith(target, _iterable)
if (typeof iterable === 'string'){
return iterable.endsWith(target)
}
if (!_isArray(target)) return false
const diff = iterable.length - target.length
let correct = true
const filtered = target.filter((x, index) => {
if (!correct) return false
const result = equals(x, iterable[ index + diff ])
if (!result) correct = false
return result
})
return filtered.length === target.length
}
eqProps
It returns true
if property prop
in obj1
is equal to property prop
in obj2
according to R.equals
.
const obj1 = {a: 1, b:2}
const obj2 = {a: 1, b:3}
const result = R.eqProps('a', obj1, obj2)
// => true
Try this R.eqProps example in Rambda REPL
equals
equals<T>(x: T, y: T): boolean
It deeply compares x
and y
and returns true
if they are equal.
:boom: It doesn't handle cyclical data structures and functions
R.equals(
[1, {a:2}, [{b: 3}]],
[1, {a:2}, [{b: 3}]]
) // => true
Try this R.equals example in Rambda REPL
R.equals source
import { _isArray } from './_internals/_isArray.js'
import { type } from './type.js'
export function _lastIndexOf(valueToFind, list){
if (!_isArray(list)){
throw new Error(`Cannot read property 'indexOf' of ${ list }`)
}
const typeOfValue = type(valueToFind)
if (![ 'Object', 'Array', 'NaN', 'RegExp' ].includes(typeOfValue))
return list.lastIndexOf(valueToFind)
const { length } = list
let index = length
let foundIndex = -1
while (--index > -1 && foundIndex === -1){
if (equals(list[ index ], valueToFind)){
foundIndex = index
}
}
return foundIndex
}
export function _indexOf(valueToFind, list){
if (!_isArray(list)){
throw new Error(`Cannot read property 'indexOf' of ${ list }`)
}
const typeOfValue = type(valueToFind)
if (![ 'Object', 'Array', 'NaN', 'RegExp' ].includes(typeOfValue))
return list.indexOf(valueToFind)
let index = -1
let foundIndex = -1
const { length } = list
while (++index < length && foundIndex === -1){
if (equals(list[ index ], valueToFind)){
foundIndex = index
}
}
return foundIndex
}
function _arrayFromIterator(iter){
const list = []
let next
while (!(next = iter.next()).done){
list.push(next.value)
}
return list
}
function _equalsSets(a, b){
if (a.size !== b.size){
return false
}
const aList = _arrayFromIterator(a.values())
const bList = _arrayFromIterator(b.values())
const filtered = aList.filter(aInstance => _indexOf(aInstance, bList) === -1)
return filtered.length === 0
}
function parseError(maybeError){
const typeofError = maybeError.__proto__.toString()
if (![ 'Error', 'TypeError' ].includes(typeofError)) return []
return [ typeofError, maybeError.message ]
}
function parseDate(maybeDate){
if (!maybeDate.toDateString) return [ false ]
return [ true, maybeDate.getTime() ]
}
function parseRegex(maybeRegex){
if (maybeRegex.constructor !== RegExp) return [ false ]
return [ true, maybeRegex.toString() ]
}
function equalsSets(a, b){
if (a.size !== b.size){
return false
}
const aList = _arrayFromIterator(a.values())
const bList = _arrayFromIterator(b.values())
const filtered = aList.filter(aInstance => _indexOf(aInstance, bList) === -1)
return filtered.length === 0
}
export function equals(a, b){
if (arguments.length === 1) return _b => equals(a, _b)
const aType = type(a)
if (aType !== type(b)) return false
if (aType === 'Function'){
return a.name === undefined ? false : a.name === b.name
}
if ([ 'NaN', 'Undefined', 'Null' ].includes(aType)) return true
if (aType === 'Number'){
if (Object.is(-0, a) !== Object.is(-0, b)) return false
return a.toString() === b.toString()
}
if ([ 'String', 'Boolean' ].includes(aType)){
return a.toString() === b.toString()
}
if (aType === 'Array'){
const aClone = Array.from(a)
const bClone = Array.from(b)
if (aClone.toString() !== bClone.toString()){
return false
}
let loopArrayFlag = true
aClone.forEach((aCloneInstance, aCloneIndex) => {
if (loopArrayFlag){
if (
aCloneInstance !== bClone[ aCloneIndex ] &&
!equals(aCloneInstance, bClone[ aCloneIndex ])
){
loopArrayFlag = false
}
}
})
return loopArrayFlag
}
const aRegex = parseRegex(a)
const bRegex = parseRegex(b)
if (aRegex[ 0 ]){
return bRegex[ 0 ] ? aRegex[ 1 ] === bRegex[ 1 ] : false
} else if (bRegex[ 0 ]) return false
const aDate = parseDate(a)
const bDate = parseDate(b)
if (aDate[ 0 ]){
return bDate[ 0 ] ? aDate[ 1 ] === bDate[ 1 ] : false
} else if (bDate[ 0 ]) return false
const aError = parseError(a)
const bError = parseError(b)
if (aError[ 0 ]){
return bError[ 0 ] ?
aError[ 0 ] === bError[ 0 ] && aError[ 1 ] === bError[ 1 ] :
false
}
if (aType === 'Set'){
return _equalsSets(a, b)
}
if (aType === 'Object'){
const aKeys = Object.keys(a)
if (aKeys.length !== Object.keys(b).length){
return false
}
let loopObjectFlag = true
aKeys.forEach(aKeyInstance => {
if (loopObjectFlag){
const aValue = a[ aKeyInstance ]
const bValue = b[ aKeyInstance ]
if (aValue !== bValue && !equals(aValue, bValue)){
loopObjectFlag = false
}
}
})
return loopObjectFlag
}
return false
}
evolve
evolve<T, U>(rules: ((x: T) => U)[], list: T[]): U[]
It takes object or array of functions as set of rules. These rules
are applied to the iterable
input to produce the result.
:boom: Error handling of this method differs between Ramda and Rambda. Ramda for some wrong inputs returns result and for other - it returns one of the inputs. Rambda simply throws when inputs are not correct. Full details for this mismatch are listed in
source/_snapshots/evolve.spec.js.snap
file.
const rules = {
foo : add(1),
bar : add(-1),
}
const input = {
a : 1,
foo : 2,
bar : 3,
}
const result = evolve(rules, input)
const expected = {
a : 1,
foo : 3,
bar : 2,
})
// => `result` is equal to `expected`
Try this R.evolve example in Rambda REPL
R.evolve source
import { _isArray } from './_internals/_isArray.js'
import { mapArray, mapObject } from './map.js'
import { type } from './type.js'
export function evolveArray(rules, list){
return mapArray(
(x, i) => {
if (type(rules[ i ]) === 'Function'){
return rules[ i ](x)
}
return x
},
list,
true
)
}
export function evolveObject(rules, iterable){
return mapObject((x, prop) => {
if (type(x) === 'Object'){
const typeRule = type(rules[ prop ])
if (typeRule === 'Function'){
return rules[ prop ](x)
}
if (typeRule === 'Object'){
return evolve(rules[ prop ], x)
}
return x
}
if (type(rules[ prop ]) === 'Function'){
return rules[ prop ](x)
}
return x
}, iterable)
}
export function evolve(rules, iterable){
if (arguments.length === 1){
return _iterable => evolve(rules, _iterable)
}
const rulesType = type(rules)
const iterableType = type(iterable)
if (iterableType !== rulesType){
throw new Error('iterableType !== rulesType')
}
if (![ 'Object', 'Array' ].includes(rulesType)){
throw new Error(`'iterable' and 'rules' are from wrong type ${ rulesType }`)
}
if (iterableType === 'Object'){
return evolveObject(rules, iterable)
}
return evolveArray(rules, iterable)
}
excludes
Opposite of R.includes
R.equals
is used to determine equality.
const result = [
R.excludes('ar', 'foo'),
R.excludes({a: 2}, [{a: 1}])
]
// => [true, true ]
Try this R.excludes example in Rambda REPL
F
F(): boolean
F() // => false
Try this R.F example in Rambda REPL
R.F source
export function F(){
return false
}
filter
filter<T>(predicate: Predicate<T>): (input: T[]) => T[]
It filters list or object input
using a predicate
function.
const list = [3, 4, 3, 2]
const listPredicate = x => x > 2
const object = {abc: 'fo', xyz: 'bar', baz: 'foo'}
const objectPredicate = (x, prop) => x.length + prop.length > 5
const result = [
R.filter(listPredicate, list),
R.filter(objectPredicate, object)
]
// => [ [3, 4], { xyz: 'bar', baz: 'foo'} ]
Try this R.filter example in Rambda REPL
R.filter source
import { _isArray } from './_internals/_isArray.js'
export function filterObject(predicate, obj){
const willReturn = {}
for (const prop in obj){
if (predicate(
obj[ prop ], prop, obj
)){
willReturn[ prop ] = obj[ prop ]
}
}
return willReturn
}
export function filterArray(
predicate, list, indexed = false
){
let index = 0
const len = list.length
const willReturn = []
while (index < len){
const predicateResult = indexed ?
predicate(list[ index ], index) :
predicate(list[ index ])
if (predicateResult){
willReturn.push(list[ index ])
}
index++
}
return willReturn
}
export function filter(predicate, iterable){
if (arguments.length === 1)
return _iterable => filter(predicate, _iterable)
if (!iterable){
throw new Error('Incorrect iterable input')
}
if (_isArray(iterable)) return filterArray(
predicate, iterable, false
)
return filterObject(predicate, iterable)
}
filterArray
filterArray<T>(predicate: Predicate<T>): (input: T[]) => T[]
const result = R.filterArray(
x => x > 1,
[1, 2, 3]
)
// => [1, 3]
Try this R.filterArray example in Rambda REPL
filterAsync
filterAsync<T>(fn: AsyncPredicate<T>, list: T[]): Promise<T[]>
Asynchronous version of R.filter
const predicate = async x => {
await R.delay(100)
return x % 2 === 1
}
const result = await R.filterAsync(predicate, [ 1, 2, 3 ])
// => [ 1, 3 ]
Try this R.filterAsync example in Rambda REPL
R.filterAsync source
import { _isArray } from './_internals/_isArray.js'
import { filter } from './filter.js'
import { mapAsync } from './mapAsync.js'
export function filterAsyncFn(predicate, listOrObject){
return new Promise((resolve, reject) => {
mapAsync(predicate, listOrObject)
.then(predicateResult => {
if (_isArray(predicateResult)){
const filtered = listOrObject.filter((_, i) => predicateResult[ i ])
return resolve(filtered)
}
const filtered = filter((_, prop) => predicateResult[ prop ],
listOrObject)
return resolve(filtered)
})
.catch(reject)
})
}
export function filterAsync(predicate, listOrObject){
if (arguments.length === 1){
return async _listOrObject => filterAsyncFn(predicate, _listOrObject)
}
return new Promise((resolve, reject) => {
filterAsyncFn(predicate, listOrObject).then(resolve)
.catch(reject)
})
}
filterIndexed
Same as R.filter
, but it passes index/property as second argument to the predicate, when looping over arrays/objects.
filterObject
filterObject<T>(predicate: ObjectPredicate<T>): (x: Dictionary<T>) => Dictionary<T>
const obj = {a: 1, b:2}
const result = R.filterObject(
x => x > 1,
obj
)
// => {b: 2}
Try this R.filterObject example in Rambda REPL
find
find<T>(predicate: (x: T) => boolean, list: T[]): T | undefined
It returns the first element of list
that satisfy the predicate
.
If there is no such element, it returns undefined
.
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 'bar'}, {foo: 1}]
const result = R.find(predicate, list)
// => {foo: 1}
Try this R.find example in Rambda REPL
R.find source
export function find(predicate, list){
if (arguments.length === 1) return _list => find(predicate, _list)
let index = 0
const len = list.length
while (index < len){
const x = list[ index ]
if (predicate(x)){
return x
}
index++
}
}
findAsync
Asynchronous version of R.find
.
const predicate = x => {
await R.delay(100)
return R.type(x.foo) === 'Number'
}
const list = [{foo: 'bar'}, {foo: 1}]
const result = await R.findAsync(predicate, list)
// => {foo: 1}
Try this R.findAsync example in Rambda REPL
findIndex
findIndex<T>(predicate: (x: T) => boolean, list: T[]): number
It returns the index of the first element of list
satisfying the predicate
function.
If there is no such element, then -1
is returned.
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 'bar'}, {foo: 1}]
const result = R.findIndex(predicate, list)
// => 1
Try this R.findIndex example in Rambda REPL
R.findIndex source
export function findIndex(predicate, list){
if (arguments.length === 1) return _list => findIndex(predicate, _list)
const len = list.length
let index = -1
while (++index < len){
if (predicate(list[ index ])){
return index
}
}
return -1
}
findLast
findLast<T>(fn: (x: T) => boolean, list: T[]): T | undefined
It returns the last element of list
satisfying the predicate
function.
If there is no such element, then undefined
is returned.
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 0}, {foo: 1}]
const result = R.findLast(predicate, list)
// => {foo: 1}
Try this R.findLast example in Rambda REPL
R.findLast source
export function findLast(predicate, list){
if (arguments.length === 1) return _list => findLast(predicate, _list)
let index = list.length
while (--index >= 0){
if (predicate(list[ index ])){
return list[ index ]
}
}
return undefined
}
findLastIndex
findLastIndex<T>(predicate: (x: T) => boolean, list: T[]): number
It returns the index of the last element of list
satisfying the predicate
function.
If there is no such element, then -1
is returned.
const predicate = x => R.type(x.foo) === 'Number'
const list = [{foo: 0}, {foo: 1}]
const result = R.findLastIndex(predicate, list)
// => 1
Try this R.findLastIndex example in Rambda REPL
R.findLastIndex source
export function findLastIndex(fn, list){
if (arguments.length === 1) return _list => findLastIndex(fn, _list)
let index = list.length
while (--index >= 0){
if (fn(list[ index ])){
return index
}
}
return -1
}
flatten
flatten<T>(list: any[]): T[]
It deeply flattens an array.
const result = R.flatten([
1,
2,
[3, 30, [300]],
[4]
])
// => [ 1, 2, 3, 30, 300, 4 ]
Try this R.flatten example in Rambda REPL
R.flatten source
import { _isArray } from './_internals/_isArray.js'
export function flatten(list, input){
const willReturn = input === undefined ? [] : input
for (let i = 0; i < list.length; i++){
if (_isArray(list[ i ])){
flatten(list[ i ], willReturn)
} else {
willReturn.push(list[ i ])
}
}
return willReturn
}
flattenObject
It transforms object to object where each value is represented with its path.
flip
It returns function which calls fn
with exchanged first and second argument.
:boom: Rambda's flip will throw if the arity of the input function is greater or equal to 5.
const subtractFlip = R.flip(R.subtract)
const result = [
subtractFlip(1,7),
R.subtract(1, 6)
]
// => [6, -6]
Try this R.flip example in Rambda REPL
forEach
forEach<T>(fn: Iterator<T, void>, list: T[]): T[]
It applies iterable
function over all members of list
and returns list
.
:boom: It works with objects, unlike
Ramda
.
const sideEffect = {}
const result = R.forEach(
x => sideEffect[`foo${x}`] = x
)([1, 2])
sideEffect // => {foo1: 1, foo2: 2}
result // => [1, 2]
Try this R.forEach example in Rambda REPL
R.forEach source
import { _isArray } from './_internals/_isArray.js'
import { _keys } from './_internals/_keys.js'
export function forEach(fn, list){
if (arguments.length === 1) return _list => forEach(fn, _list)
if (list === undefined){
return
}
if (_isArray(list)){
let index = 0
const len = list.length
while (index < len){
fn(list[ index ])
index++
}
} else {
let index = 0
const keys = _keys(list)
const len = keys.length
while (index < len){
const key = keys[ index ]
fn(
list[ key ], key, list
)
index++
}
}
return list
}
forEachIndexed
fromPairs
It transforms a listOfPairs
to an object.
const listOfPairs = [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', [ 3, 4 ] ] ]
const expected = {
a : 1,
b : 2,
c : [ 3, 4 ],
}
const result = R.fromPairs(listOfPairs)
// => `result` is equal to `expected`
Try this R.fromPairs example in Rambda REPL
getter
getter<T>(keyOrKeys: string | string[] | undefined): T
The set of methods R.setter
, R.getter
and R.reset
allow different parts of your logic to access comminicate indirectly via shared cache object.
Usually these methods show that you might need to refactor to classes. Still, they can be helpful meanwhile.
R.getter
: It provides access to the cache object. If undefined
is used as a key, this method will return the whole cache object. If string
is passed, then it will return cache value for this key. If array of string
is passed, then it assume that this is array of keys and it will return the corresponding cache values for these keys.
R.setter
: It allows cache object's keys to be changed. You can either set individual key-value pairs with R.setter(key, value)
or you pass directly object, which will be merged with the cache object.
R.reset
: It resets the cache object.
R.setter('foo','bar')
R.setter('a', 1)
R.getter(['foo','a']) // => {foo: 'bar', a: 1}
R.setter('a', 2)
R.getter('a') // => 2
R.reset()
R.getter('a') // => undefined
Try this R.getter example in Rambda REPL
R.getter source
import { mergeRight } from './mergeRight.js'
import { pick } from './pick.js'
import { type } from './type.js'
let holder = {}
/**
* Pass string to get value
* Pass array to get object of values
* Pass undefined to get all data
*/
export function getter(key){
const typeKey = type(key)
if (typeKey === 'String') return holder[ key ]
if (typeKey === 'Array') return pick(key, holder)
return holder
}
export function setter(maybeKey, maybeValue){
const typeKey = type(maybeKey)
const typeValue = type(maybeValue)
if (typeKey === 'String'){
if (typeValue === 'Function'){
return holder[ maybeKey ] = maybeValue(holder[ maybeKey ])
}
return holder[ maybeKey ] = maybeValue
}
if (typeKey !== 'Object') return
holder = mergeRight(holder, maybeKey)
}
export function reset(){
holder = {}
}
glue
glue(input: string, glueString?: string): string
It transforms multiline string to single line by gluing together the separate lines with the glueString
and removing the empty spaces. By default glueString
is equal to single space, so if that is what you need, then you can just pass a single argument.
const result = R.glue(`
foo
bar
baz
`)
// => 'foo bar baz'
Try this R.glue example in Rambda REPL
R.glue source
export function glue(input, glueChar){
return input
.split('\n')
.filter(x => x.trim().length > 0)
.map(x => x.trim())
.join(glueChar === undefined ? ' ' : glueChar)
}
groupBy
It splits list
according to a provided groupFn
function and returns an object.
const list = [ 'a', 'b', 'aa', 'bb' ]
const groupFn = x => x.length
const result = R.groupBy(groupFn, list)
// => { '1': ['a', 'b'], '2': ['aa', 'bb'] }
Try this R.groupBy example in Rambda REPL
groupWith
It returns separated version of list or string input
, where separation is done with equality compareFn
function.
const compareFn = (x, y) => x === y
const list = [1, 2, 2, 1, 1, 2]
const result = R.groupWith(isConsecutive, list)
// => [[1], [2,2], [1,1], [2]]
Try this R.groupWith example in Rambda REPL
has
has<T>(prop: string, obj: T): boolean
It returns true
if obj
has property prop
.
const obj = {a: 1}
const result = [
R.has('a', Record<string, unknown>),
R.has('b', Record<string, unknown>)
]
// => [true, false]
Try this R.has example in Rambda REPL
R.has source
export function has(prop, obj){
if (arguments.length === 1) return _obj => has(prop, _obj)
if (!obj) return false
return obj.hasOwnProperty(prop)
}
hasPath
hasPath<T>(
path: string | string[],
input: object
): boolean
It will return true, if input
object has truthy path
(calculated with R.path
).
const path = 'a.b'
const pathAsArray = ['a', 'b']
const obj = {a: {b: []}}
const result = [
R.hasPath(path, Record<string, unknown>),
R.hasPath(pathAsArray, Record<string, unknown>),
R.hasPath('a.c', Record<string, unknown>),
]
// => [true, true, false]
Try this R.hasPath example in Rambda REPL
R.hasPath source
import { path } from './path.js'
export function hasPath(pathInput, obj){
if (arguments.length === 1){
return objHolder => hasPath(pathInput, objHolder)
}
return path(pathInput, obj) !== undefined
}
head
head(input: string): string
It returns the first element of list or string input
.
const result = [
R.head([1, 2, 3]),
R.head('foo')
]
// => [1, 'f']
Try this R.head example in Rambda REPL
R.head source
export function head(listOrString){
if (typeof listOrString === 'string') return listOrString[ 0 ] || ''
return listOrString[ 0 ]
}
identical
It returns true
if its arguments a
and b
are identical.
Otherwise, it returns false
.
:boom: Values are identical if they reference the same memory.
NaN
is identical toNaN
;0
and-0
are not identical.
const objA = {a: 1};
const objB = {a: 1};
R.identical(objA, objA); // => true
R.identical(objA, objB); // => false
R.identical(1, 1); // => true
R.identical(1, '1'); // => false
R.identical([], []); // => false
R.identical(0, -0); // => false
R.identical(NaN, NaN); // => true
Try this R.identical example in Rambda REPL
identity
identity<T>(input: T): T
It just passes back the supplied input
argument.
:boom: Logic
R.identity(7) // => 7
Try this R.identity example in Rambda REPL
R.identity source
export function identity(x){
return x
}
ifElse
ifElse<T, TFiltered extends T, TOnTrueResult, TOnFalseResult>(
pred: (a: T) => a is TFiltered,
onTrue: (a: TFiltered) => TOnTrueResult,
onFalse: (a: Exclude<T, TFiltered>) => TOnFalseResult,
): (a: T) => TOnTrueResult | TOnFalseResult
It expects condition
, onTrue
and onFalse
functions as inputs and it returns a new function with example name of fn
.
When fn`` is called with
inputargument, it will return either
onTrue(input)or
onFalse(input)depending on
condition(input)` evaluation.
const fn = R.ifElse(
x => x>10,
x => x*2,
x => x*10
)
const result = [ fn(8), fn(18) ]
// => [80, 36]
Try this R.ifElse example in Rambda REPL
R.ifElse source
import { curry } from './curry.js'
function ifElseFn(
condition, onTrue, onFalse
){
return (...input) => {
const conditionResult =
typeof condition === 'boolean' ? condition : condition(...input)
if (conditionResult === true){
return onTrue(...input)
}
return onFalse(...input)
}
}
export const ifElse = curry(ifElseFn)
ifElseAsync
ifElseAsync<T, U>(
condition: (x: T) => Promise<boolean>,
onTrue: (x: T) => U,
onFalse: (x: T) => U,
): (x: T) => Promise<U>
Asynchronous version of R.ifElse
. Any of condition
, ifFn
and elseFn
can be either asynchronous or synchronous function.
const condition = async x => {
await R.delay(100)
return x > 1
}
const ifFn = async x => {
await R.delay(100)
return x + 1
}
const elseFn = async x => {
await R.delay(100)
return x - 1
}
const result = await R.ifElseAsync(
condition,
ifFn,
elseFn
)(1)
// => 0
Try this R.ifElseAsync example in Rambda REPL
R.ifElseAsync source
function createThenable(fn){
return async function (...input){
return fn(...input)
}
}
export function ifElseAsync(
condition, ifFn, elseFn
){
return (...inputs) =>
new Promise((resolve, reject) => {
const conditionPromise = createThenable(condition)
const ifFnPromise = createThenable(ifFn)
const elseFnPromise = createThenable(elseFn)
conditionPromise(...inputs)
.then(conditionResult => {
const promised =
conditionResult === true ? ifFnPromise : elseFnPromise
promised(...inputs)
.then(resolve)
.catch(reject)
})
.catch(reject)
})
}
inc
It increments a number.
R.inc(1) // => 2
Try this R.inc example in Rambda REPL
includes
includes(valueToFind: string, input: string[] | string): boolean
If input
is string, then this method work as native String.includes
.
If input
is array, then R.equals
is used to define if valueToFind
belongs to the list.
const result = [
R.includes('oo', 'foo'),
R.includes({a: 1}, [{a: 1}])
]
// => [true, true ]
Try this R.includes example in Rambda REPL
R.includes source
import { _isArray } from './_internals/_isArray.js'
import { _indexOf } from './equals.js'
export function includes(valueToFind, iterable){
if (arguments.length === 1)
return _iterable => includes(valueToFind, _iterable)
if (typeof iterable === 'string'){
return iterable.includes(valueToFind)
}
if (!iterable){
throw new TypeError(`Cannot read property \'indexOf\' of ${ iterable }`)
}
if (!_isArray(iterable)) return false
return _indexOf(valueToFind, iterable) > -1
}
indexBy
It generates object with properties provided by condition
and values provided by list
array.
If condition
is a function, then all list members are passed through it.
If condition
is a string, then all list members are passed through R.path(condition)
.
const list = [ {id: 10}, {id: 20} ]
const withFunction = R.indexBy(
x => x.id,
list
)
const withString = R.indexBy(
'id',
list
)
const result = [
withFunction,
R.equals(withFunction, withString)
]
// => [ { 10: {id: 10}, 20: {id: 20} }, true ]
Try this R.indexBy example in Rambda REPL
indexOf
It returns the index of the first element of list
equals to valueToFind
.
If there is no such element, it returns -1
.
:boom: It uses
R.equals
for list of objects/arrays or nativeindexOf
for any other case.
const list = [0, 1, 2, 3]
const result = [
R.indexOf(2, list),
R.indexOf(0, list)
]
// => [2, -1]
Try this R.indexOf example in Rambda REPL
init
init<T extends unknown[]>(input: T): T extends readonly [...infer U, any] ? U : [...T]
It returns all but the last element of list or string input
.
const result = [
R.init([1, 2, 3]) ,
R.init('foo') // => 'fo'
]
// => [[1, 2], 'fo']
Try this R.init example in Rambda REPL
R.init source
import baseSlice from './_internals/baseSlice.js'
export function init(listOrString){
if (typeof listOrString === 'string') return listOrString.slice(0, -1)
return listOrString.length ?
baseSlice(
listOrString, 0, -1
) :
[]
}
interpolate
interpolate(inputWithTags: string, templateArguments: object): string
It generages a new string from inputWithTags
by replacing all {{x}}
occurances with values provided by templateArguments
.
const inputWithTags = 'foo is {{bar}} even {{a}} more'
const templateArguments = {"bar":"BAR", a: 1}
const result = R.interpolate(inputWithTags, templateArguments)
const expected = 'foo is BAR even 1 more'
// => `result` is equal to `expected`
Try this R.interpolate example in Rambda REPL
R.interpolate source
const getOccurrences = input => input.match(/{{\s*.+?\s*}}/g)
const getOccurrenceProp = occurrence =>
occurrence.replace(/{{\s*|\s*}}/g, '')
const replace = ({ inputHolder, prop, replacer }) => {
const regexBase = `{{${ prop }}}`
const regex = new RegExp(regexBase, 'g')
return inputHolder.replace(regex, replacer)
}
export function interpolate(input, templateInput){
if (arguments.length === 1){
return _templateInput => interpolate(input, _templateInput)
}
const occurrences = getOccurrences(input)
if (occurrences === null) return input
let inputHolder = input
for (const occurrence of occurrences){
const prop = getOccurrenceProp(occurrence)
inputHolder = replace({
inputHolder,
prop,
replacer : templateInput[ prop ],
})
}
return inputHolder
}
intersection
It loops throw listA
and listB
and returns the intersection of the two according to R.equals
.
:boom: There is slight difference between Rambda and Ramda implementation. Ramda.intersection(['a', 'b', 'c'], ['c', 'b']) result is "[ 'c', 'b' ]", but Rambda result is "[ 'b', 'c' ]".
const listA = [ { id : 1 }, { id : 2 }, { id : 3 }, { id : 4 } ]
const listB = [ { id : 3 }, { id : 4 }, { id : 5 }, { id : 6 } ]
const result = R.intersection(listA, listB)
// => [{ id : 3 }, { id : 4 }]
Try this R.intersection example in Rambda REPL
intersperse
It adds a separator
between members of list
.
const list = [ 0, 1, 2, 3 ]
const separator = '|'
const result = intersperse(separator, list)
// => [0, '|', 1, '|', 2, '|', 3]
Try this R.intersperse example in Rambda REPL
is
It returns true
if x
is instance of targetPrototype
.
const result = [
R.is(String, 'foo'),
R.is(Array, 1)
]
// => [true, false]
Try this R.is example in Rambda REPL
isEmpty
isEmpty<T>(x: T): boolean
It returns true
if x
is empty
.
const result = [
R.isEmpty(''),
R.isEmpty({ x : 0 })
]
// => [true, false]
Try this R.isEmpty example in Rambda REPL
R.isEmpty source
import { type } from './type.js'
export function isEmpty(input){
const inputType = type(input)
if ([ 'Undefined', 'NaN', 'Number', 'Null' ].includes(inputType))
return false
if (!input) return true
if (inputType === 'Object'){
return Object.keys(input).length === 0
}
if (inputType === 'Array'){
return input.length === 0
}
return false
}
isNil
isNil(x: any): x is null | undefined
It returns true
if x
is either null
or undefined
.
const result = [
R.isNil(null),
R.isNil(1),
]
// => [true, false]
Try this R.isNil example in Rambda REPL
R.isNil source
export function isNil(x){
return x === undefined || x === null
}
isPromise
isPromise(input: any): boolean
isType
isType(targetType: RambdaTypes, input: any): boolean
It returns true if targetType
is equal to type of input
according to R.type
.
R.isType('Async',R.delay(1000))
// => true
Try this R.isType example in Rambda REPL
R.isType source
import { type } from './type.js'
export function isType(xType, x){
if (arguments.length === 1){
return xHolder => isType(xType, xHolder)
}
return type(x) === xType
}
isValid
isValid({input: object, schema: Schema}: IsValid): boolean
It checks if input
is following schema
specifications.
If validation fails, it returns false
.
Please check the detailed explanation as it is hard to write a short description for this method.
:boom: Independently, somebody else came with very similar idea called superstruct
const input = {a: ['foo', 'bar']}
const invalidInput = {a: ['foo', 'bar', 1]}
const schema = {a: [String]}
const result = [
R.isValid({schema, input}),
R.isValid({schema, input: invalidInput})
]
// => [true, false]
Try this R.isValid example in Rambda REPL
R.isValid source
import { _isArray } from './_internals/_isArray.js'
import { all } from './all.js'
import { any } from './any.js'
import { includes } from './includes.js'
import { init } from './init.js'
import { test } from './test.js'
import { toLower } from './toLower.js'
import { type } from './type.js'
export function isPrototype(input){
const currentPrototype = input.prototype
const list = [ Number, String, Boolean, Promise ]
let toReturn = false
let counter = -1
while (++counter < list.length && !toReturn){
if (currentPrototype === list[ counter ].prototype) toReturn = true
}
return toReturn
}
export function prototypeToString(input){
const currentPrototype = input.prototype
const list = [ Number, String, Boolean, Promise ]
const translatedList = [ 'Number', 'String', 'Boolean', 'Promise' ]
let found
let counter = -1
while (++counter < list.length){
if (currentPrototype === list[ counter ].prototype) found = counter
}
return translatedList[ found ]
}
const typesWithoutPrototype = [ 'any', 'promise', 'async', 'function' ]
export function fromPrototypeToString(rule){
if (
_isArray(rule) ||
rule === undefined ||
rule === null ||
rule.prototype === undefined ||
typesWithoutPrototype.includes(rule)
){
return {
rule,
parsed : false,
}
}
if (String.prototype === rule.prototype){
return {
rule : 'string',
parsed : true,
}
}
if (Boolean.prototype === rule.prototype){
return {
rule : 'boolean',
parsed : true,
}
}
if (Number.prototype === rule.prototype){
return {
rule : 'number',
parsed : true,
}
}
return {
rule : type(rule.prototype).toLowerCase(),
parsed : true,
}
}
function getRuleAndType(schema, requirementRaw){
const ruleRaw = schema[ requirementRaw ]
const typeIs = type(ruleRaw)
const { rule, parsed } = fromPrototypeToString(ruleRaw)
return {
rule : rule,
ruleType : parsed ? 'String' : typeIs,
}
}
export function isValid({ input, schema }){
if (input === undefined || schema === undefined) return false
let flag = true
const boom = boomFlag => {
if (!boomFlag){
flag = false
}
}
for (const requirementRaw in schema){
if (flag){
const isOptional = requirementRaw.endsWith('?')
const requirement = isOptional ? init(requirementRaw) : requirementRaw
const { rule, ruleType } = getRuleAndType(schema, requirementRaw)
const inputProp = input[ requirement ]
const inputPropType = type(input[ requirement ])
const ok = isOptional && inputProp !== undefined || !isOptional
if (!ok || rule === 'any' && inputProp != null || rule === inputProp)
continue
if (ruleType === 'Object'){
/**
* This rule is standalone schema, so we recursevly call `isValid`
*/
const isValidResult = isValid({
input : inputProp,
schema : rule,
})
boom(isValidResult)
} else if (ruleType === 'String'){
/**
* Rule is actual rule such as 'number', so the two types are compared
*/
boom(toLower(inputPropType) === rule)
} else if (typeof rule === 'function'){
/**
* Rule is function so we pass to it the input
*/
boom(rule(inputProp))
} else if (ruleType === 'Array' && inputPropType === 'String'){
/**
* Enum case | rule is like a: ['foo', 'bar']
*/
boom(includes(inputProp, rule))
} else if (
ruleType === 'Array' &&
rule.length === 1 &&
inputPropType === 'Array'
){
/**
* 1. array of type | rule is like a: ['number']
* 2. rule is like a: [{foo: 'string', bar: 'number'}]
*/
const [ currentRule ] = rule
const currentRuleType = type(currentRule)
//Check if rule is invalid
boom(currentRuleType === 'String' ||
currentRuleType === 'Object' ||
isPrototype(currentRule))
if (currentRuleType === 'Object' && flag){
/**
* 2. rule is like a: [{from: 'string'}]
*/
const isValidResult = all(inputPropInstance =>
isValid({
input : inputPropInstance,
schema : currentRule,
}),
inputProp)
boom(isValidResult)
} else if (flag){
/**
* 1. array of type
*/
const actualRule =
currentRuleType === 'String' ?
currentRule :
prototypeToString(currentRule)
const isInvalidResult = any(inputPropInstance =>
type(inputPropInstance).toLowerCase() !==
actualRule.toLowerCase(),
inputProp)
boom(!isInvalidResult)
}
} else if (ruleType === 'RegExp' && inputPropType === 'String'){
boom(test(rule, inputProp))
} else {
boom(false)
}
}
}
return flag
}
isValidAsync
isValidAsync(x: IsValidAsync): Promise<boolean>
Asynchronous version of R.isValid
const input = {a: 1, b: 2}
const invalidInput = {a: 1, b: 'foo'}
const schema = {a: Number, b: async x => {
await R.delay(100)
return typeof x === 'number'
}}
const result = await Promise.all([
R.isValidAsync({schema, input}),
R.isValidAsync({schema, input: invalidInput})
])
// => [true, false]
Try this R.isValidAsync example in Rambda REPL
R.isValidAsync source
import { forEach } from './forEach.js'
import { isPromise } from './isPromise.js'
import { isValid } from './isValid.js'
export async function isValidAsync({ schema, input }){
const asyncSchema = {}
const simpleSchema = {}
forEach((rule, prop) => {
if (isPromise(rule)){
asyncSchema[ prop ] = rule
} else {
simpleSchema[ prop ] = rule
}
}, schema)
if (Object.keys(asyncSchema).length === 0)
return isValid({
input,
schema,
})
if (
!isValid({
input,
schema : simpleSchema,
})
)
return false
let toReturn = true
for (const singleRuleProp in asyncSchema){
if (toReturn){
const validated = await asyncSchema[ singleRuleProp ](input[ singleRuleProp ])
if (!validated) toReturn = false
}
}
return toReturn
}
join
join<T>(glue: string, list: T[]): string
It returns a string of all list
instances joined with a glue
.
R.join('-', [1, 2, 3]) // => '1-2-3'
Try this R.join example in Rambda REPL
R.join source
export function join(glue, list){
if (arguments.length === 1) return _list => join(glue, _list)
return list.join(glue)
}
juxt
juxt<A extends any[], R1>(fns: [(...a: A) => R1]): (...a: A) => [R1]
It applies list of function to a list of inputs.
const getRange = juxt([ Math.min, Math.max, Math.min ])
const result = getRange(
3, 4, 9, -3
)
// => [-3, 9, -3]
Try this R.juxt example in Rambda REPL
R.juxt source
export function juxt(listOfFunctions){
return (...args) => listOfFunctions.map(fn => fn(...args))
}
keys
keys<T extends object>(x: T): (keyof T)[]
It applies Object.keys
over x
and returns its keys.
R.keys({a:1, b:2}) // => ['a', 'b']
Try this R.keys example in Rambda REPL
R.keys source
export function keys(x){
return Object.keys(x)
}
last
last(str: string): string
It returns the last element of input
, as the input
can be either a string or an array.
const result = [
R.last([1, 2, 3]),
R.last('foo'),
]
// => [3, 'o']
Try this R.last example in Rambda REPL
R.last source
export function last(listOrString){
if (typeof listOrString === 'string'){
return listOrString[ listOrString.length - 1 ] || ''
}
return listOrString[ listOrString.length - 1 ]
}
lastIndexOf
lastIndexOf<T>(target: T, list: T[]): number
It returns the last index of target
in list
array.
R.equals
is used to determine equality between target
and members of list
.
If there is no such index, then -1
is returned.
const list = [1, 2, 3, 1, 2, 3]
const result = [
R.lastIndexOf(2, list),
R.lastIndexOf(4, list),
]
// => [4, -1]
Try this R.lastIndexOf example in Rambda REPL
R.lastIndexOf source
import { _lastIndexOf } from './equals.js'
export function lastIndexOf(valueToFind, list){
if (arguments.length === 1){
return _list => _lastIndexOf(valueToFind, _list)
}
return _lastIndexOf(valueToFind, list)
}
length
length<T>(input: T[]): number
It returns the length
property of list or string input
.
const result = [
R.length([1, 2, 3, 4]),
R.length('foo'),
]
// => [4, 3]
Try this R.length example in Rambda REPL
R.length source
import { _isArray } from './_internals/_isArray.js'
export function length(x){
if (_isArray(x)) return x.length
if (typeof x === 'string') return x.length
return NaN
}
lens
lens<T, U, V>(getter: (s: T) => U, setter: (a: U, s: T) => V): Lens
It returns a lens
for the given getter
and setter
functions.
The getter
gets the value of the focus; the setter
sets the value of the focus.
The setter should not mutate the data structure.
const xLens = R.lens(R.prop('x'), R.assoc('x'));
R.view(xLens, {x: 1, y: 2}) // => 1
R.set(xLens, 4, {x: 1, y: 2}) // => {x: 4, y: 2}
R.over(xLens, R.negate, {x: 1, y: 2}) // => {x: -1, y: 2}
Try this R.lens example in Rambda REPL
R.lens source
export function lens(getter, setter){
return function (functor){
return function (target){
return functor(getter(target)).map(focus => setter(focus, target))
}
}
}
lensEq
lensEq<T, U>(lens: Lens, target: T, input: U): boolean
It returns true
if data structure focused by the given lens equals to the target
value.
R.equals
is used to determine equality.
:boom: Idea for this method comes from
ramda-adjunct
library
const list = [ 1, 2, 3 ]
const lens = R.lensIndex(0)
const result = R.lensEq(
lens, 1, list
)
// => true
Try this R.lensEq example in Rambda REPL
R.lensEq source
import { curry } from './curry.js'
import { equals } from './equals.js'
import { view } from './view.js'
function lensEqFn(
lens, target, input
){
return equals(view(lens, input), target)
}
export const lensEq = curry(lensEqFn)
lensIndex
lensIndex(index: number): Lens
It returns a lens that focuses on specified index
.
const list = ['a', 'b', 'c']
const headLens = R.lensIndex(0)
R.view(headLens, list) // => 'a'
R.set(headLens, 'x', list) // => ['x', 'b', 'c']
R.over(headLens, R.toUpper, list) // => ['A', 'b', 'c']
Try this R.lensIndex example in Rambda REPL
R.lensIndex source
import { lens } from './lens.js'
import { nth } from './nth.js'
import { update } from './update.js'
export function lensIndex(index){
return lens(nth(index), update(index))
}
lensPath
lensPath(path: RamdaPath): Lens
It returns a lens that focuses on specified path
.
const lensPath = R.lensPath(['x', 0, 'y'])
const input = {x: [{y: 2, z: 3}, {y: 4, z: 5}]}
R.view(lensPath, input) // => 2
R.set(lensPath, 1, input)
// => {x: [{y: 1, z: 3}, {y: 4, z: 5}]}
R.over(xHeadYLens, R.negate, input)
// => {x: [{y: -2, z: 3}, {y: 4, z: 5}]}
Try this R.lensPath example in Rambda REPL
R.lensPath source
import { assocPath } from './assocPath.js'
import { lens } from './lens.js'
import { path } from './path.js'
export function lensPath(key){
return lens(path(key), assocPath(key))
}
lensProp
lensProp(prop: string): {
<T, U>(obj: T): U
It returns a lens that focuses on specified property prop
.
const xLens = R.lensProp('x');
const input = {x: 1, y: 2}
R.view(xLens, input) // => 1
R.set(xLens, 4, input)
// => {x: 4, y: 2}
R.over(xLens, R.negate, input)
// => {x: -1, y: 2}
Try this R.lensProp example in Rambda REPL
R.lensProp source
import { assoc } from './assoc.js'
import { lens } from './lens.js'
import { prop } from './prop.js'
export function lensProp(key){
return lens(prop(key), assoc(key))
}
lensSatisfies
lensSatisfies<T, U>(predicate: (x: T) => boolean, lens: Lens, input: U): boolean
It returns true
if data structure focused by the given lens satisfies the predicate.
:boom: Idea for this method comes from
ramda-adjunct
library
const fn = R.lensSatisfies(x => x > 5, R.lensIndex(0))
const result = [
fn([10, 20, 30]),
fn([1, 2, 3]),
]
// => [true, false]
Try this R.lensSatisfies example in Rambda REPL
R.lensSatisfies source
import { curry } from './curry.js'
import { view } from './view.js'
function lensSatisfiesFn(
predicate, lens, input
){
return Boolean(predicate(view(lens, input)))
}
export const lensSatisfies = curry(lensSatisfiesFn)
map
map<T, U>(fn: ObjectIterator<T, U>, iterable: Dictionary<T>): Dictionary<U>
It returns the result of looping through iterable
with fn
.
It works with both array and object.
:boom: Unlike Ramda's
map
, here property and input object are passed as arguments tofn
, wheniterable
is an object.
const fn = x => x * 2
const fnWhenObject = (val, prop)=>{
return `${prop}-${val}`
}
const iterable = [1, 2]
const obj = {a: 1, b: 2}
const result = [
R.map(fn, list),
R.map(fnWhenObject, Record<string, unknown>)
]
// => [ [1, 4], {a: 'a-1', b: 'b-2'}]
Try this R.map example in Rambda REPL
R.map source
import { _isArray } from './_internals/_isArray.js'
import { _keys } from './_internals/_keys.js'
export function mapArray(
fn, list, isIndexed = false
){
let index = 0
const willReturn = Array(list.length)
while (index < list.length){
willReturn[ index ] = isIndexed ? fn(list[ index ], index) : fn(list[ index ])
index++
}
return willReturn
}
export function mapObject(fn, obj){
if (arguments.length === 1){
return _obj => mapObject(fn, _obj)
}
let index = 0
const keys = _keys(obj)
const len = keys.length
const willReturn = {}
while (index < len){
const key = keys[ index ]
willReturn[ key ] = fn(
obj[ key ], key, obj
)
index++
}
return willReturn
}
export const mapObjIndexed = mapObject
export function map(fn, iterable){
if (arguments.length === 1) return _iterable => map(fn, _iterable)
if (!iterable){
throw new Error('Incorrect iterable input')
}
if (_isArray(iterable)) return mapArray(fn, iterable)
return mapObject(fn, iterable)
}
mapArray
mapArray<T>(fn: Iterator<T, T>, iterable: T[]): T[]
const result = R.mapArray(x => x + 1, [1, 2])
// => [2, 3]
Try this R.mapArray example in Rambda REPL
mapAsync
mapAsync<T, K>(fn: AsyncIterable<T, K>, list: T[]): Promise<K[]>
Sequential asynchronous mapping with fn
over members of list
.
async function fn(x){
await R.delay(1000)
return x+1
}
const result = await R.mapAsync(fn, [1, 2, 3])
// `result` resolves after 3 seconds to `[2, 3, 4]`
Try this R.mapAsync example in Rambda REPL
R.mapAsync source
import { _isArray } from './_internals/_isArray.js'
async function mapAsyncFn(fn, listOrObject){
if (_isArray(listOrObject)){
const willReturn = []
let i = 0
for (const a of listOrObject){
willReturn.push(await fn(a, i++))
}
return willReturn
}
const willReturn = {}
for (const prop in listOrObject){
willReturn[ prop ] = await fn(listOrObject[ prop ], prop)
}
return willReturn
}
export function mapAsync(fn, listOrObject){
if (arguments.length === 1){
return async _listOrObject => mapAsyncFn(fn, _listOrObject)
}
return new Promise((resolve, reject) => {
mapAsyncFn(fn, listOrObject).then(resolve)
.catch(reject)
})
}
mapAsyncLimit
mapAsyncLimit<T, K>(fn: AsyncIterable<T, K>, limit: number, list: T[]): Promise<K[]>
It is similar to R.mapFastAsync
in that it uses Promise.all
but not over the whole list, rather than with only slice from list
with length limit
.
:boom: For example usage, please check
R.mapAsyncLimit
tests.
R.mapAsyncLimit source
import { mapFastAsync, mapFastAsyncFn } from './mapFastAsync.js'
import { splitEvery } from './splitEvery.js'
async function mapAsyncLimitFn(
iterable, limit, list
){
if (list.length < limit) return mapFastAsync(iterable, list)
const slices = splitEvery(limit, list)
let toReturn = []
for (const slice of slices){
const iterableResult = await mapFastAsyncFn(iterable, slice)
toReturn = [ ...toReturn, ...iterableResult ]
}
return toReturn
}
export function mapAsyncLimit(
iterable, limit, list
){
if (arguments.length === 2){
return async _list => mapAsyncLimitFn(
iterable, limit, _list
)
}
return new Promise((resolve, reject) => {
mapAsyncLimitFn(
iterable, limit, list
).then(resolve)
.catch(reject)
})
}
mapcat
const result = R.mapcat()
// =>
Try this R.mapcat example in Rambda REPL
mapFastAsync
mapFastAsync<T, K>(fn: AsyncIterable<T, K>, list: T[]): Promise<K[]>
Parrallel asynchronous mapping with fn
over members of list
.
async function fn(x){
await R.delay(1000)
return x+1
}
const result = await R.mapFastAsync(fn, [1, 2, 3])
// `result` resolves after 1 second to `[2, 3, 4]`
Try this R.mapFastAsync example in Rambda REPL
R.mapFastAsync source
export async function mapFastAsyncFn(fn, arr){
const promised = arr.map((a, i) => fn(a, i))
return Promise.all(promised)
}
export function mapFastAsync(fn, arr){
if (arguments.length === 1){
return async holder => mapFastAsyncFn(fn, holder)
}
return new Promise((resolve, reject) => {
mapFastAsyncFn(fn, arr).then(resolve)
.catch(reject)
})
}
mapIndexed
Same as R.map
, but it passes index as second argument to the iterator, when looping over arrays.
mapKeys
mapKeys<T, U>(changeKeyFn: (x: string) => string, obj: { [key: string]: T}): U
It takes an object and returns a new object with changed keys according to changeKeyFn
function.
const obj = {a: 1, b: 2}
const changeKeyFn = prop => `{prop}_foo`
const result = R.mapKeys(changeKeyFn, Record<string, unknown>)
// => {a_foo: 1, b_foo: 2}
Try this R.mapKeys example in Rambda REPL
R.mapKeys source
export function mapKeys(changeKeyFn, obj){
if (arguments.length === 1) return _obj => mapKeys(changeKeyFn, _obj)
const toReturn = {}
Object.keys(obj).forEach(prop => toReturn[ changeKeyFn(prop) ] = obj[ prop ])
return toReturn
}
mapObject
mapObject<T>(fn: ObjectIterator<T, T>, iterable: Dictionary<T>): Dictionary<T>
const result = R.mapObject(x => x + 1, {a:1, b:2})
// => {a:2, b:3}
Try this R.mapObject example in Rambda REPL
mapObjIndexed
It works the same way as R.map
does for objects. It is added as Ramda also has this method.
const fn = (val, prop) => {
return `${prop}-${val}`
}
const obj = {a: 1, b: 2}
const result = R.map(mapObjIndexed, Record<string, unknown>)
// => {a: 'a-1', b: 'b-2'}
Try this R.mapObjIndexed example in Rambda REPL
mapToObject
mapToObject<T, U>(fn: (input: T) => object|false, list: T[]): U
This method allows to generate an object from a list using input function fn
.
This function must return either an object or false
for every member of list
input.
If false
is returned, then this element of list
will be skipped in the calculation of the result.
All of returned objects will be merged to generate the final result.
const list = [1, 2, 3, 12]
const fn = x => {
if(x > 10) return false
return x % 2 ? {[x]: x + 1}: {[x]: x + 10}
}
const result = mapToObject(fn, list)
const expected = {'1': 2, '2': 12, '3': 4}
// => `result` is equal to `expected`
Try this R.mapToObject example in Rambda REPL
R.mapToObject source
import { map } from './map.js'
import { mergeAll } from './mergeAll.js'
import { ok } from './ok.js'
import { type } from './type.js'
export function mapToObject(fn, list){
if (arguments.length === 1){
return listHolder => mapToObject(fn, listHolder)
}
ok(type(fn), type(list))('Function', 'Array')
return mergeAll(map(fn, list))
}
mapToObjectAsync
mapToObjectAsync<T, U>(fn: (input: T) => Promise<object|false>, list: T[]): Promise<U>
Asynchronous version of R.mapToObject
R.mapToObjectAsync source
import { mapAsync } from './mapAsync.js'
export async function mapToObjectAsyncFn(fn, list){
let toReturn = {}
const innerIterable = async x => {
const intermediateResult = await fn(x)
if (intermediateResult === false) return
toReturn = {
...toReturn,
...intermediateResult,
}
}
await mapAsync(innerIterable, list)
return toReturn
}
export function mapToObjectAsync(fn, list){
if (arguments.length === 1){
return async _list => mapToObjectAsyncFn(fn, _list)
}
return new Promise((resolve, reject) => {
mapToObjectAsyncFn(fn, list).then(resolve)
.catch(reject)
})
}
match
match(regExpression: RegExp, str: string): string[]
Curried version of String.prototype.match
which returns empty array, when there is no match.
const result = [
R.match('a', 'foo'),
R.match(/([a-z]a)/g, 'bananas')
]
// => [[], ['ba', 'na', 'na']]
Try this R.match example in Rambda REPL
R.match source
export function match(pattern, input){
if (arguments.length === 1) return _input => match(pattern, _input)
const willReturn = input.match(pattern)
return willReturn === null ? [] : willReturn
}
mathMod
R.mathMod
behaves like the modulo operator should mathematically, unlike the %
operator (and by extension, R.modulo
). So while -17 % 5
is -2
, mathMod(-17, 5)
is 3
.
:boom: Explanation is taken from
Ramda
documentation site.
const result = [
R.mathMod(-17, 5),
R.mathMod(17, 5),
R.mathMod(17, -5),
R.mathMod(17, 0)
]
// => [3, 2, NaN, NaN]
Try this R.mathMod example in Rambda REPL
max
It returns the greater value between x
and y
.
const result = [
R.max(5, 7),
R.max('bar', 'foo'),
]
// => [7, 'foo']
Try this R.max example in Rambda REPL
maxBy
It returns the greater value between x
and y
according to compareFn
function.
const compareFn = Math.abs
R.maxBy(compareFn, 5, -7) // => -7
Try this R.maxBy example in Rambda REPL
maybe
maybe<T>(ifRule: boolean, whenIf: T | Func<T>, whenElse: T | Func<T>): T
It acts as ternary operator and it is helpful when we have nested ternaries.
All of the inputs can be either direct values or anonymous functions. This is helpful if we don't want to evaluate certain paths as we can wrap this logic in a function.
const x = 4
const y = 8
const ifRule = x > 2
const whenIf = y > 10 ? 3 : 7
const whenElse = () => {
// just to show that it won't be evaluated
return JSON.parse('{a:')
}
const result = R.maybe(
ifRule,
whenIf,
whenElse,
)
// `result` is `7`
Try this R.maybe example in Rambda REPL
R.maybe source
import { type } from './type.js'
export function maybe(
ifRule, whenIf, whenElse
){
const whenIfInput =
ifRule && type(whenIf) === 'Function' ? whenIf() : whenIf
const whenElseInput =
!ifRule && type(whenElse) === 'Function' ? whenElse() : whenElse
return ifRule ? whenIfInput : whenElseInput
}
mean
mean(list: number[]): number
It returns the mean value of list
input.
R.mean([ 2, 7 ])
// => 4.5
Try this R.mean example in Rambda REPL
R.mean source
import { sum } from './sum.js'
export function mean(list){
return sum(list) / list.length
}
median
median(list: number[]): number
It returns the median value of list
input.
R.median([ 7, 2, 10, 9 ]) // => 8
Try this R.median example in Rambda REPL
R.median source
import { mean } from './mean.js'
export function median(list){
const len = list.length
if (len === 0) return NaN
const width = 2 - len % 2
const idx = (len - width) / 2
return mean(Array.prototype.slice
.call(list, 0)
.sort((a, b) => {
if (a === b) return 0
return a < b ? -1 : 1
})
.slice(idx, idx + width))
}
memoize
memoize<T, K extends any[]>(fn: (...inputs: K) => T): (...inputs: K) => T
When fn
is called for a second time with the same input, then the cache result is returned instead of calling again fn
.
let result = 0
const fn = (a,b) =>{
result++
return a + b
}
const memoized = R.memoize(fn)
memoized(1, 2)
memoized(1, 2)
// => `result` is equal to `1`
Try this R.memoize example in Rambda REPL
R.memoize source
import { compose } from './compose.js'
import { map } from './map.js'
import { replace } from './replace.js'
import { sort } from './sort.js'
import { take } from './take.js'
import { type } from './type.js'
const cache = {}
const normalizeObject = obj => {
const sortFn = (a, b) => a > b ? 1 : -1
const willReturn = {}
compose(map(prop => willReturn[ prop ] = obj[ prop ]),
sort(sortFn))(Object.keys(obj))
return willReturn
}
const stringify = a => {
if (type(a) === 'String'){
return a
} else if ([ 'Function', 'Async' ].includes(type(a))){
const compacted = replace(
/\s{1,}/g, ' ', a.toString()
)
return replace(
/\s/g, '_', take(15, compacted)
)
} else if (type(a) === 'Object'){
return JSON.stringify(normalizeObject(a))
}
return JSON.stringify(a)
}
const generateProp = (fn, ...inputArguments) => {
let propString = ''
inputArguments.forEach(inputArgument => {
propString += `${ stringify(inputArgument) }_`
})
return `${ propString }${ stringify(fn) }`
}
// with weakmaps
export function memoize(fn, ...inputArguments){
if (arguments.length === 1){
return (...inputArgumentsHolder) => memoize(fn, ...inputArgumentsHolder)
}
const prop = generateProp(fn, ...inputArguments)
if (prop in cache) return cache[ prop ]
if (type(fn) === 'Async'){
return new Promise(resolve => {
fn(...inputArguments).then(result => {
cache[ prop ] = result
resolve(result)
})
})
}
const result = fn(...inputArguments)
cache[ prop ] = result
return result
}
memoizeWith
memoizeWith<T, K extends any[]>(keyGen: any, fn: (...inputs: K) => T): (...inputs: K) => T
Creates a new function that, when invoked, caches the result of calling fn for a given argument set and returns the result.
const keyGen = (a,b) => a + b
let result = 0
const fn = (a,b) =>{
result++
return a + b
}
const memoized = R.memoizeWith(keyGen, fn)
memoized(1, 2)
memoized(1, 2)
// => `result` is equal to `1`
Try this R.memoizeWith example in Rambda REPL
R.memoizeWith source
export function memoizeWith(keyGen, fn){
if (arguments.length === 1){
return _fn => memoizeWith(keyGen, _fn)
}
const cache = new Map()
return function (){
const key = keyGen.apply(this, arguments)
if (!cache.has(key)){
cache.set(key, fn.apply(this, arguments))
}
return cache.get(key)
}
}
merge
Same as R.mergeRight
.
mergeAll
mergeAll<T>(list: object[]): T
It merges all objects of list
array sequentially and returns the result.
const list = [
{a: 1},
{b: 2},
{c: 3}
]
const result = R.mergeAll(list)
const expected = {
a: 1,
b: 2,
c: 3
}
// => `result` is equal to `expected`
Try this R.mergeAll example in Rambda REPL
R.mergeAll source
import { map } from './map.js'
import { mergeRight } from './mergeRight.js'
export function mergeAll(arr){
let willReturn = {}
map(val => {
willReturn = mergeRight(willReturn, val)
}, arr)
return willReturn
}
mergeDeepRight
mergeDeepRight<Output>(target: object, newProps: object): Output
Creates a new object with the own properties of the first object merged with the own properties of the second object. If a key exists in both objects:
- and both values are objects, the two values will be recursively merged
- otherwise the value from the second object will be used.
R.mergeDeepRight source
import { type } from './type.js'
export function mergeDeepRight(target, source){
if (arguments.length === 1){
return sourceHolder => mergeDeepRight(target, sourceHolder)
}
const willReturn = JSON.parse(JSON.stringify(target))
Object.keys(source).forEach(key => {
if (type(source[ key ]) === 'Object'){
if (type(target[ key ]) === 'Object'){
willReturn[ key ] = mergeDeepRight(target[ key ], source[ key ])
} else {
willReturn[ key ] = source[ key ]
}
} else {
willReturn[ key ] = source[ key ]
}
})
return willReturn
}
mergeLeft
mergeLeft<Output>(newProps: object, target: object): Output
Same as R.merge
, but in opposite direction.
const result = R.mergeLeft(
{a: 10},
{a: 1, b: 2}
)
// => {a:10, b: 2}
Try this R.mergeLeft example in Rambda REPL
R.mergeLeft source
import { mergeRight } from './mergeRight.js'
export function mergeLeft(x, y){
if (arguments.length === 1) return _y => mergeLeft(x, _y)
return mergeRight(y, x)
}
mergeRight
It creates a copy of target
object with overidden newProps
properties. Previously known as R.merge
but renamed after Ramda did the same.
const target = { 'foo': 0, 'bar': 1 }
const newProps = { 'foo': 7 }
const result = R.mergeRight(target, newProps)
// => { 'foo': 7, 'bar': 1 }
Try this R.mergeRight example in Rambda REPL
mergeWith
mergeWith(fn: (x: any, z: any) => any, a: Record<string, unknown>, b: Record<string, unknown>): Record<string, unknown>
It takes two objects and a function, which will be used when there is an overlap between the keys.
const result = R.mergeWith(
R.concat,
{values : [ 10, 20 ]},
{values : [ 15, 35 ]}
)
// => [ 10, 20, 15, 35 ]
Try this R.mergeWith example in Rambda REPL
R.mergeWith source
import { curry } from './curry.js'
function mergeWithFn(
mergeFn, a, b
){
const willReturn = {}
Object.keys(a).forEach(key => {
if (b[ key ] === undefined){
willReturn[ key ] = a[ key ]
} else {
willReturn[ key ] = mergeFn(a[ key ], b[ key ])
}
})
Object.keys(b).forEach(key => {
if (willReturn[ key ] !== undefined) return
if (a[ key ] === undefined){
willReturn[ key ] = b[ key ]
} else {
willReturn[ key ] = mergeFn(a[ key ], b[ key ])
}
})
return willReturn
}
export const mergeWith = curry(mergeWithFn)
min
It returns the lesser value between x
and y
.
const result = [
R.min(5, 7),
R.min('bar', 'foo'),
]
// => [5, 'bar']
Try this R.min example in Rambda REPL
minBy
It returns the lesser value between x
and y
according to compareFn
function.
const compareFn = Math.abs
R.minBy(compareFn, -5, 2) // => -5
Try this R.minBy example in Rambda REPL
modifyPath
modifyPath<T extends Record<string, unknown>>(path: Path, fn: (x: any) => unknown, object: Record<string, unknown>): T
It changes a property of object on the base of provided path and transformer function.
const result = R.modifyPath('a.b.c', x=> x+1, {a:{b: {c:1}}})
// => {a:{b: {c:2}}}
Try this R.modifyPath example in Rambda REPL
R.modifyPath source
import { _isArray } from './_internals/_isArray.js'
import { createPath } from './_internals/createPath.js'
import { assoc } from './assoc.js'
import { curry } from './curry.js'
import { path as pathModule } from './path.js'
export function modifyPathFn(
pathInput, fn, object
){
const path = createPath(pathInput)
if (path.length === 1){
return {
...object,
[ path[0] ] : fn(object[ path[0] ]),
}
}
if (pathModule(path, object) === undefined) return object
const val = modifyPath(
Array.prototype.slice.call(path, 1),
fn,
object[ path[ 0 ] ]
)
if (val === object[ path[ 0 ] ]){
return object
}
return assoc(
path[ 0 ], val, object
)
}
export const modifyPath = curry(modifyPathFn)
modulo
Curried version of x%y
.
R.modulo(17, 3) // => 2
Try this R.modulo example in Rambda REPL
move
It returns a copy of list
with exchanged fromIndex
and toIndex
elements.
:boom: Rambda.move doesn't support negative indexes - it throws an error.
const list = [1, 2, 3]
const result = R.move(0, 1, list)
// => [2, 1, 3]
Try this R.move example in Rambda REPL
multiply
Curried version of x*y
.
R.multiply(2, 4) // => 8
Try this R.multiply example in Rambda REPL
negate
R.negate(420)// => -420
Try this R.negate example in Rambda REPL
nextIndex
nextIndex(index: number, list: any[]): number
It returns the next index of the list.
If we have reached the end of the list, then it will return 0
.
const list = [1, 2, 3]
const result = [
R.nextIndex(0, list),
R.nextIndex(1, list),
R.nextIndex(2, list),
R.nextIndex(10, list)
]
// => [1, 2, 0, 0]
Try this R.nextIndex example in Rambda REPL
R.nextIndex source
export function nextIndex(index, list){
return index >= list.length - 1 ? 0 : index + 1
}
none
none<T>(predicate: (x: T) => boolean, list: T[]): boolean
It returns true
, if all members of array list
returns false
, when applied as argument to predicate
function.
const list = [ 0, 1, 2, 3, 4 ]
const predicate = x => x > 6
const result = R.none(predicate, arr)
// => true
Try this R.none example in Rambda REPL
R.none source
export function none(predicate, list){
if (arguments.length === 1) return _list => none(predicate, _list)
for (let i = 0; i < list.length; i++){
if (predicate(list[ i ])) return false
}
return true
}
not
not(input: any): boolean
It returns a boolean negated version of input
.
R.not(false) // true
Try this R.not example in Rambda REPL
R.not source
export function not(input){
return !input
}
nth
nth(index: number, input: string): string
Curried version of input[index]
.
const list = [1, 2, 3]
const str = 'foo'
const result = [
R.nth(2, list),
R.nth(6, list),
R.nth(0, str),
]
// => [3, undefined, 'f']
Try this R.nth example in Rambda REPL
R.nth source
export function nth(index, input){
if (arguments.length === 1) return _input => nth(index, _input)
const idx = index < 0 ? input.length + index : index
return Object.prototype.toString.call(input) === '[object String]' ?
input.charAt(idx) :
input[ idx ]
}
objOf
It creates an object with a single key-value pair.
const result = R.objOf('foo', 'bar')
// => {foo: 'bar'}
Try this R.objOf example in Rambda REPL
of
of<T>(x: T): T[]
R.of(null); // => [null]
R.of([42]); // => [[42]]
Try this R.of example in Rambda REPL
R.of source
export function of(value){
return [ value ]
}
ok
ok(...inputs: any[]): (...schemas: any[]) => void | never
It checks if inputs
are following schemas
specifications according to R.isValid
.
If validation fails, it throws.
:boom: It is same as
R.pass
but instead of returningfalse
, it throws an error.
const result = R.ok(
1,
['foo', 'bar']
)(
Number,
[String]
)
// => undefined
Try this R.ok example in Rambda REPL
R.ok source
import { any } from './any.js'
import { glue } from './glue.js'
import { fromPrototypeToString, isValid } from './isValid.js'
import { map } from './map.js'
import { type } from './type.js'
export function schemaToString(schema){
if (type(schema) !== 'Object'){
return fromPrototypeToString(schema).rule
}
return map(x => {
const { rule, parsed } = fromPrototypeToString(x)
const xType = type(x)
if (xType === 'Function' && !parsed) return 'Function'
return parsed ? rule : xType
}, schema)
}
export function check(singleInput, schema){
return isValid({
input : { singleInput },
schema : { singleInput : schema },
})
}
export function ok(...inputs){
return (...schemas) => {
let failedSchema
const anyError = any((singleInput, i) => {
const schema = schemas[ i ] === undefined ? schemas[ 0 ] : schemas[ i ]
const checked = check(singleInput, schema)
if (!checked){
failedSchema = JSON.stringify({
input : singleInput,
schema : schemaToString(schema),
})
}
return !checked
}, inputs)
if (anyError){
const errorMessage =
inputs.length > 1 ?
glue(`
Failed R.ok -
reason: ${ failedSchema }
all inputs: ${ JSON.stringify(inputs) }
all schemas: ${ JSON.stringify(schemas.map(schemaToString)) }
`,
'\n') :
`Failed R.ok - ${ failedSchema }`
throw new Error(errorMessage)
}
}
}
omit
omit<T, K extends string>(propsToOmit: K[], obj: T): Omit<T, K>
It returns a partial copy of an obj
without propsToOmit
properties.
:boom: When using this method with
TypeScript
, it is much easier to passpropsToOmit
as an array. If passing a string, you will need to explicitly declare the output type.
const obj = {a: 1, b: 2, c: 3}
const propsToOmit = 'a,c,d'
const propsToOmitList = ['a', 'c', 'd']
const result = [
R.omit(propsToOmit, Record<string, unknown>),
R.omit(propsToOmitList, Record<string, unknown>)
]
// => [{b: 2}, {b: 2}]
Try this R.omit example in Rambda REPL
R.omit source
import { createPath } from './_internals/createPath.js'
export function omit(propsToOmit, obj){
if (arguments.length === 1) return _obj => omit(propsToOmit, _obj)
if (obj === null || obj === undefined){
return undefined
}
const propsToOmitValue = createPath(propsToOmit, ',')
const willReturn = {}
for (const key in obj){
if (!propsToOmitValue.includes(key)){
willReturn[ key ] = obj[ key ]
}
}
return willReturn
}
on
It passes the two inputs through unaryFn
and then the results are passed as inputs the the binaryFn
to receive the final result(binaryFn(unaryFn(FIRST_INPUT), unaryFn(SECOND_INPUT))
).
This method is also known as P combinator.
const result = R.on((a, b) => a + b, R.prop('a'), {b:0, a:1}, {a:2})
// => 3
Try this R.on example in Rambda REPL
once
once<T extends AnyFunction>(func: T): T
It returns a function, which invokes only once fn
function.
let result = 0
const addOnce = R.once((x) => result = result + x)
addOnce(1)
addOnce(1)
// => 1
Try this R.once example in Rambda REPL
R.once source
import { curry } from './curry.js'
function onceFn(fn, context){
let result
return function (){
if (fn){
result = fn.apply(context || this, arguments)
fn = null
}
return result
}
}
export function once(fn, context){
if (arguments.length === 1){
const wrap = onceFn(fn, context)
return curry(wrap)
}
return onceFn(fn, context)
}
or
Logical OR
R.or(false, true); // => true
R.or(false, false); // => false
R.or(false, 'foo'); // => 'foo'
Try this R.or example in Rambda REPL
over
over<T>(lens: Lens, fn: Arity1Fn, value: T): T
It returns a copied Object or Array with modified value received by applying function fn
to lens
focus.
const headLens = R.lensIndex(0)
R.over(headLens, R.toUpper, ['foo', 'bar', 'baz']) // => ['FOO', 'bar', 'baz']
Try this R.over example in Rambda REPL
R.over source
import { curry } from './curry.js'
const Identity = x => ({
x,
map : fn => Identity(fn(x)),
})
function overFn(
lens, fn, object
){
return lens(x => Identity(fn(x)))(object).x
}
export const over = curry(overFn)
partial
partial<V0, V1, T>(fn: (x0: V0, x1: V1) => T, args: [V0]): (x1: V1) => T
It is very similar to R.curry
, but you can pass initial arguments when you create the curried function.
R.partial
will keep returning a function until all the arguments that the function fn
expects are passed.
The name comes from the fact that you partially inject the inputs.
:boom: Rambda's partial doesn't need the input arguments to be wrapped as array.
const fn = (title, firstName, lastName) => {
return title + ' ' + firstName + ' ' + lastName + '!'
}
const canPassAnyNumberOfArguments = R.partial(fn, 'Hello')
const ramdaStyle = R.partial(fn, ['Hello'])
const finalFn = canPassAnyNumberOfArguments('Foo')
finalFn('Bar') // => 'Hello, Foo Bar!'
Try this R.partial example in Rambda REPL
R.partial source
export function partial(fn, ...args){
const len = fn.length
return (...rest) => {
if (args.length + rest.length >= len){
return fn(...args, ...rest)
}
return partial(fn, ...[ ...args, ...rest ])
}
}
partialCurry
partialCurry<Input, PartialInput, Output>(
fn: (input: Input) => Output,
partialInput: PartialInput,
): (input: Pick<Input, Exclude<keyof Input, keyof PartialInput>>) => Output
Same as R.partialObject
.
When Ramda
introduced R.partialObject
, Rambdax
already had such method, i.e. R.partialCurry
. So this method is kept for backward compatibility.
:boom: Function input can be asynchronous
R.partialCurry source
export { partialObject as partialCurry } from './partialObject.js'
partialObject
partialObject<Input, PartialInput, Output>(
fn: (input: Input) => Output,
partialInput: PartialInput,
): (input: Pick<Input, Exclude<keyof Input, keyof PartialInput>>) => Output
R.partialObject
is a curry helper designed specifically for functions accepting object as a single argument.
Initially the function knows only a part from the whole input object and then R.partialObject
helps in preparing the function for the second part, when it receives the rest of the input.
:boom: Function input can be asynchronous
const fn = ({ a, b, c }) => a + b + c
const curried = R.partialObject(fn, { a : 1 })
const result = curried({
b : 2,
c : 3,
})
// => 6
Try this R.partialObject example in Rambda REPL
R.partialObject source
import { mergeDeepRight } from './mergeDeepRight.js'
import { type } from './type.js'
export function partialObject(fn, input){
return rest => {
if (type(fn) === 'Async'){
return new Promise((resolve, reject) => {
fn(mergeDeepRight(rest, input)).then(resolve)
.catch(reject)
})
}
return fn(mergeDeepRight(rest, input))
}
}
partition
partition<T>(
predicate: Predicate<T>,
input: T[]
): [T[], T[]]
It will return array of two objects/arrays according to predicate
function. The first member holds all instances of input
that pass the predicate
function, while the second member - those who doesn't.
const list = [1, 2, 3]
const obj = {a: 1, b: 2, c: 3}
const predicate = x => x > 2
const result = [
R.partition(predicate, list),
R.partition(predicate, Record<string, unknown>)
]
const expected = [
[[3], [1, 2]],
[{c: 3}, {a: 1, b: 2}],
]
// `result` is equal to `expected`
Try this R.partition example in Rambda REPL
R.partition source
import { _isArray } from './_internals/_isArray.js'
export function partitionObject(predicate, iterable){
const yes = {}
const no = {}
Object.entries(iterable).forEach(([ prop, value ]) => {
if (predicate(value, prop)){
yes[ prop ] = value
} else {
no[ prop ] = value
}
})
return [ yes, no ]
}
export function partitionArray(
predicate, list, indexed = false
){
const yes = []
const no = []
let counter = -1
while (counter++ < list.length - 1){
if (
indexed ? predicate(list[ counter ], counter) : predicate(list[ counter ])
){
yes.push(list[ counter ])
} else {
no.push(list[ counter ])
}
}
return [ yes, no ]
}
export function partition(predicate, iterable){
if (arguments.length === 1){
return listHolder => partition(predicate, listHolder)
}
if (!_isArray(iterable)) return partitionObject(predicate, iterable)
return partitionArray(predicate, iterable)
}
partitionIndexed
pass
pass(...inputs: any[]): (...rules: any[]) => boolean
It checks if inputs
are following schemas
specifications according to R.isValid
.
const result = R.pass(
1,
['foo','bar']
)(
Number,
[String]
)
// => true
Try this R.pass example in Rambda REPL
R.pass source
import { any } from './any.js'
import { check } from './ok.js'
export function pass(...inputs){
return (...schemas) =>
any((x, i) => {
const schema = schemas[ i ] === undefined ? schemas[ 0 ] : schemas[ i ]
return !check(x, schema)
}, inputs) === false
}
path
path<Input, T>(pathToSearch: Path, obj: Input): T | undefined
If pathToSearch
is 'a.b'
then it will return 1
if obj
is {a:{b:1}}
.
It will return undefined
, if such path is not found.
:boom: String anotation of
pathToSearch
is one of the differences betweenRambda
andRamda
.
const obj = {a: {b: 1}}
const pathToSearch = 'a.b'
const pathToSearchList = ['a', 'b']
const result = [
R.path(pathToSearch, Record<string, unknown>),
R.path(pathToSearchList, Record<string, unknown>),
R.path('a.b.c.d', Record<string, unknown>)
]
// => [1, 1, undefined]
Try this R.path example in Rambda REPL
R.path source
import { createPath } from './_internals/createPath.js'
export function path(pathInput, obj){
if (arguments.length === 1) return _obj => path(pathInput, _obj)
if (obj === null || obj === undefined){
return undefined
}
let willReturn = obj
let counter = 0
const pathArrValue = createPath(pathInput)
while (counter < pathArrValue.length){
if (willReturn === null || willReturn === undefined){
return undefined
}
if (willReturn[ pathArrValue[ counter ] ] === null) return undefined
willReturn = willReturn[ pathArrValue[ counter ] ]
counter++
}
return willReturn
}
pathEq
pathEq(pathToSearch: Path, target: any, input: any): boolean
It returns true
if pathToSearch
of input
object is equal to target
value.
pathToSearch
is passed to R.path
, which means that it can be either a string or an array. Also equality between target
and the found value is determined by R.equals
.
const path = 'a.b'
const target = {c: 1}
const input = {a: {b: {c: 1}}}
const result = R.pathEq(
path,
target,
input
)
// => true
Try this R.pathEq example in Rambda REPL
R.pathEq source
import { curry } from './curry.js'
import { equals } from './equals.js'
import { path } from './path.js'
function pathEqFn(
pathToSearch, target, input
){
return equals(path(pathToSearch, input), target)
}
export const pathEq = curry(pathEqFn)
pathOr
pathOr<T>(defaultValue: T, pathToSearch: Path, obj: any): T
It reads obj
input and returns either R.path(pathToSearch, Record<string, unknown>)
result or defaultValue
input.
const defaultValue = 'DEFAULT_VALUE'
const pathToSearch = 'a.b'
const pathToSearchList = ['a', 'b']
const obj = {
a : {
b : 1
}
}
const result = [
R.pathOr(DEFAULT_VALUE, pathToSearch, Record<string, unknown>),
R.pathOr(DEFAULT_VALUE, pathToSearchList, Record<string, unknown>),
R.pathOr(DEFAULT_VALUE, 'a.b.c', Record<string, unknown>)
]
// => [1, 1, 'DEFAULT_VALUE']
Try this R.pathOr example in Rambda REPL
R.pathOr source
import { curry } from './curry.js'
import { defaultTo } from './defaultTo.js'
import { path } from './path.js'
function pathOrFn(
defaultValue, pathInput, obj
){
return defaultTo(defaultValue, path(pathInput, obj))
}
export const pathOr = curry(pathOrFn)
paths
paths<Input, T>(pathsToSearch: Path[], obj: Input): (T | undefined)[]
It loops over members of pathsToSearch
as singlePath
and returns the array produced by R.path(singlePath, Record<string, unknown>)
.
Because it calls R.path
, then singlePath
can be either string or a list.
const obj = {
a : {
b : {
c : 1,
d : 2
}
}
}
const result = R.paths([
'a.b.c',
'a.b.d',
'a.b.c.d.e',
], Record<string, unknown>)
// => [1, 2, undefined]
Try this R.paths example in Rambda REPL
R.paths source
import { path } from './path.js'
export function paths(pathsToSearch, obj){
if (arguments.length === 1){
return _obj => paths(pathsToSearch, _obj)
}
return pathsToSearch.map(singlePath => path(singlePath, obj))
}
pick
pick<T, K extends string | number | symbol>(propsToPick: K[], input: T): Pick<T, Exclude<keyof T, Exclude<keyof T, K>>>
It returns a partial copy of an input
containing only propsToPick
properties.
input
can be either an object or an array.
String anotation of propsToPick
is one of the differences between Rambda
and Ramda
.
:boom: When using this method with
TypeScript
, it is much easier to passpropsToPick
as an array. If passing a string, you will need to explicitly declare the output type.
const obj = {
a : 1,
b : false,
foo: 'cherry'
}
const list = [1, 2, 3, 4]
const propsToPick = 'a,foo'
const propsToPickList = ['a', 'foo']
const result = [
R.pick(propsToPick, Record<string, unknown>),
R.pick(propsToPickList, Record<string, unknown>),
R.pick('a,bar', Record<string, unknown>),
R.pick('bar', Record<string, unknown>),
R.pick([0, 3, 5], list),
R.pick('0,3,5', list),
]
const expected = [
{a:1, foo: 'cherry'},
{a:1, foo: 'cherry'},
{a:1},
{},
{0: 1, 3: 4},
{0: 1, 3: 4},
]
// => `result` is equal to `expected`
Try this R.pick example in Rambda REPL
R.pick source
import { createPath } from './_internals/createPath.js'
export function pick(propsToPick, input){
if (arguments.length === 1) return _input => pick(propsToPick, _input)
if (input === null || input === undefined){
return undefined
}
const keys = createPath(propsToPick, ',')
const willReturn = {}
let counter = 0
while (counter < keys.length){
if (keys[ counter ] in input){
willReturn[ keys[ counter ] ] = input[ keys[ counter ] ]
}
counter++
}
return willReturn
}
pickAll
pickAll<T, U>(propsToPick: string[], input: T): U
Same as R.pick
but it won't skip the missing props, i.e. it will assign them to undefined
.
:boom: When using this method with
TypeScript
, it is much easier to passpropsToPick
as an array. If passing a string, you will need to explicitly declare the output type.
const obj = {
a : 1,
b : false,
foo: 'cherry'
}
const propsToPick = 'a,foo,bar'
const propsToPickList = ['a', 'foo', 'bar']
const result = [
R.pickAll(propsToPick, Record<string, unknown>),
R.pickAll(propsToPickList, Record<string, unknown>),
R.pickAll('a,bar', Record<string, unknown>),
R.pickAll('bar', Record<string, unknown>),
]
const expected = [
{a:1, foo: 'cherry', bar: undefined},
{a:1, foo: 'cherry', bar: undefined},
{a:1, bar: undefined},
{bar: undefined}
]
// => `result` is equal to `expected`
Try this R.pickAll example in Rambda REPL
R.pickAll source
import { createPath } from './_internals/createPath.js'
export function pickAll(propsToPick, obj){
if (arguments.length === 1) return _obj => pickAll(propsToPick, _obj)
if (obj === null || obj === undefined){
return undefined
}
const keysValue = createPath(propsToPick, ',')
const willReturn = {}
let counter = 0
while (counter < keysValue.length){
if (keysValue[ counter ] in obj){
willReturn[ keysValue[ counter ] ] = obj[ keysValue[ counter ] ]
} else {
willReturn[ keysValue[ counter ] ] = undefined
}
counter++
}
return willReturn
}
pipe
It performs left-to-right function composition.
const result = R.pipe(
R.filter(val => val > 2),
R.map(a => a * 2)
)([1, 2, 3, 4])
// => [6, 8]
Try this R.pipe example in Rambda REPL
pipeAsync
pipeAsync<Out>(
...fns: (Async<any> | Func<any>)[]
): (input: any) => Promise<Out>
Asynchronous version of R.pipe
:boom: It doesn't work with promises or function returning promises such as
const foo = input => new Promise(...)
.
const add = async x => {
await R.delay(100)
return x + 1
}
const multiply = async x => {
await R.delay(100)
return x * 2
}
const result = await R.pipeAsync(
add,
multiply
)(1)
// `result` resolves to `4`
Try this R.pipeAsync example in Rambda REPL
R.pipeAsync source
import { type } from './type.js'
export function pipeAsync(...inputArguments){
return async function (startArgument){
let argumentsToPass = startArgument
while (inputArguments.length !== 0){
const fn = inputArguments.shift()
const typeFn = type(fn)
if (typeFn === 'Async'){
argumentsToPass = await fn(argumentsToPass)
} else {
argumentsToPass = fn(argumentsToPass)
if (type(argumentsToPass) === 'Promise'){
argumentsToPass = await argumentsToPass
}
}
}
return argumentsToPass
}
}
piped
piped<A, B>(input: A, fn0: (x: A) => B) : B
It is basically R.pipe
, but instead of passing input
argument as R.pipe(...)(input)
, you pass it as the first argument.
const result = R.piped(
[1, 2, 3],
R.filter(x => x > 1),
R.map(x => x*10),
)
// => [20, 30]
Try this R.piped example in Rambda REPL
R.piped source
import { pipe } from './pipe.js'
export function piped(...inputs){
const [ input, ...fnList ] = inputs
return pipe(...fnList)(input)
}
pipedAsync
pipedAsync<T>(
input: any,
...fns: (Func<any> | Async<any>)[]
): Promise<T>
It accepts input as first argument and series of functions as next arguments. It is same as R.pipe
but with support for asynchronous functions.
:boom: Functions that return
Promise
will be handled as regular function not asynchronous. Such example isconst foo = input => new Promise(...)
.
const result = await R.pipedAsync(
100,
async x => {
await R.delay(100)
return x + 2
},
R.add(2),
async x => {
const delayed = await R.delay(100)
return delayed + x
}
)
// `result` resolves to `RAMBDAX_DELAY104`
Try this R.pipedAsync example in Rambda REPL
R.pipedAsync source
import { type } from './type.js'
export async function pipedAsync(...inputs){
const [ input, ...fnList ] = inputs
let argumentsToPass = input
while (fnList.length !== 0){
const fn = fnList.shift()
const typeFn = type(fn)
if (typeFn === 'Promise'){
argumentsToPass = await fn(argumentsToPass)
} else {
argumentsToPass = fn(argumentsToPass)
}
}
return argumentsToPass
}
pluck
pluck<K extends keyof T, T>(property: K, list: T[]): T[K][]
It returns list of the values of property
taken from the all objects inside list
.
const list = [{a: 1}, {a: 2}, {b: 3}]
const property = 'a'
const result = R.pluck(property, list)
// => [1, 2]
Try this R.pluck example in Rambda REPL
R.pluck source
import { map } from './map.js'
export function pluck(property, list){
if (arguments.length === 1) return _list => pluck(property, _list)
const willReturn = []
map(x => {
if (x[ property ] !== undefined){
willReturn.push(x[ property ])
}
}, list)
return willReturn
}
prepend
prepend<T>(x: T, input: T[]): T[]
It adds element x
at the beginning of list
.
const result = R.prepend('foo', ['bar', 'baz'])
// => ['foo', 'bar', 'baz']
Try this R.prepend example in Rambda REPL
R.prepend source
export function prepend(x, input){
if (arguments.length === 1) return _input => prepend(x, _input)
if (typeof input === 'string') return [ x ].concat(input.split(''))
return [ x ].concat(input)
}
prevIndex
prevIndex(index: number, list: any[]): number
It returns the next index of the list when the order is descending.
If we have reached the beginning of the list, then it will return the last index of the list.
:boom: Unlike
R.nextIndex
, which safeguards against index out of bounds, this method does not.
const list = [1, 2, 3]
const result = [
R.prevIndex(0, list),
R.prevIndex(1, list),
R.prevIndex(2, list),
]
// => [2, 0, 1]
Try this R.prevIndex example in Rambda REPL
R.prevIndex source
export function prevIndex(index, list){
return index === 0 ? list.length - 1 : index - 1
}
produce
produce<Input extends any, Output>(
rules: ProduceRules<Output, keyof Output, Input>,
input: Input
): Output
It returns an object created by applying each value of rules
to input
argument.
:boom: In Typescript context,
rules
functions can be only 1 level deep. In Javascript context, there is no such restriction.
const rules = {
foo: R.pipe(R.add(1), R.add(2)),
a: {b: R.add(3)}
}
const result = R.produce(rules, 1)
const expected = {
foo: 4,
a: {b: 4}
}
// => `result` is equal to `expected`
Try this R.produce example in Rambda REPL
R.produce source
import { map } from './map.js'
import { type } from './type.js'
export function produce(rules, input){
if (arguments.length === 1){
return _input => produce(rules, _input)
}
return map(singleRule =>
type(singleRule) === 'Object' ?
produce(singleRule, input) :
singleRule(input),
rules)
}
produceAsync
produceAsync<Input extends any, Output>(
rules: ProduceAsyncRules<Output, keyof Output, Input>,
input: Input
): Promise<Output>
It returns an object created by applying each value of rules
to input
argument.
rules
input is an object with synchronous or asynchronous functions as values.
The return value is wrapped in a promise, even if all rules
are synchronous functions.
const rules = {
foo: async x => {
await R.delay(100)
return x > 1
},
bar: x => ({baz: x})
}
const input = 2
const result = await R.produceAsync(rules, input)
const expected = {
foo: true,
bar: {baz: 2}
}
// => `result` is equal to `expected`
Try this R.produceAsync example in Rambda REPL
R.produceAsync source
import { map } from './map.js'
import { type } from './type.js'
function promisify({ condition, input, prop }){
return new Promise((resolve, reject) => {
if (type(condition) !== 'Promise'){
return resolve({
type : prop,
payload : condition(input),
})
}
condition(input)
.then(result => {
resolve({
type : prop,
payload : result,
})
})
.catch(err => reject(err))
})
}
function produceFn(conditions, input){
let asyncConditionsFlag = false
for (const prop in conditions){
if (
asyncConditionsFlag === false &&
type(conditions[ prop ]) === 'Promise'
){
asyncConditionsFlag = true
}
}
if (asyncConditionsFlag === false){
const willReturn = {}
for (const prop in conditions){
willReturn[ prop ] = conditions[ prop ](input)
}
return Promise.resolve(willReturn)
}
const promised = []
for (const prop in conditions){
const condition = conditions[ prop ]
promised.push(promisify({
input,
condition,
prop,
}))
}
return new Promise((resolve, reject) => {
Promise.all(promised)
.then(results => {
const willReturn = {}
map(result => willReturn[ result.type ] = result.payload, results)
resolve(willReturn)
})
.catch(err => reject(err))
})
}
export function produceAsync(conditions, input){
if (arguments.length === 1){
return async _input => produceFn(conditions, _input)
}
return new Promise((resolve, reject) => {
produceFn(conditions, input).then(resolve)
.catch(reject)
})
}
product
product(list: number[]): number
R.product([ 2, 3, 4 ])
// => 24)
Try this R.product example in Rambda REPL
R.product source
import { multiply } from './multiply.js'
import { reduce } from './reduce.js'
export const product = reduce(multiply, 1)
prop
prop<P extends keyof O, O>(propToFind: P, obj: O): O[P]
It returns the value of property propToFind
in obj
.
If there is no such property, it returns undefined
.
const result = [
R.prop('x', {x: 100}),
R.prop('x', {a: 1})
]
// => [100, undefined]
Try this R.prop example in Rambda REPL
R.prop source
export function prop(propToFind, obj){
if (arguments.length === 1) return _obj => prop(propToFind, _obj)
if (!obj) return undefined
return obj[ propToFind ]
}
propEq
propEq<K extends string | number>(propToFind: K, valueToMatch: any, obj: Record<K, any>): boolean
It returns true if obj
has property propToFind
and its value is equal to valueToMatch
.
const obj = { foo: 'bar' }
const secondObj = { foo: 1 }
const propToFind = 'foo'
const valueToMatch = 'bar'
const result = [
R.propEq(propToFind, valueToMatch, Record<string, unknown>),
R.propEq(propToFind, valueToMatch, secondRecord<string, unknown>)
]
// => [true, false]
Try this R.propEq example in Rambda REPL
R.propEq source
import { curry } from './curry.js'
import { equals } from './equals.js'
import { prop } from './prop.js'
function propEqFn(
propToFind, valueToMatch, obj
){
if (!obj) return false
return equals(valueToMatch, prop(propToFind, obj))
}
export const propEq = curry(propEqFn)
propIs
propIs<C extends AnyFunction, K extends keyof any>(type: C, name: K, obj: any): obj is Record<K, ReturnType<C>>
It returns true
if property
of obj
is from target
type.
const obj = {a:1, b: 'foo'}
const result = [
R.propIs(Number, 'a', Record<string, unknown>),
R.propIs(String, 'b', Record<string, unknown>),
R.propIs(Number, 'b', Record<string, unknown>),
]
// => [true, true, false]
Try this R.propIs example in Rambda REPL
R.propIs source
import { curry } from './curry.js'
import { is } from './is.js'
function propIsFn(
targetPrototype, property, obj
){
return is(targetPrototype, obj[ property ])
}
export const propIs = curry(propIsFn)
propOr
propOr<T, P extends string>(defaultValue: T, property: P, obj: Partial<Record<P, T>> | undefined): T
It returns either defaultValue
or the value of property
in obj
.
const obj = {a: 1}
const defaultValue = 'DEFAULT_VALUE'
const property = 'a'
const result = [
R.propOr(defaultValue, property, Record<string, unknown>),
R.propOr(defaultValue, 'foo', Record<string, unknown>)
]
// => [1, 'DEFAULT_VALUE']
Try this R.propOr example in Rambda REPL
R.propOr source
import { curry } from './curry.js'
import { defaultTo } from './defaultTo.js'
function propOrFn(
defaultValue, property, obj
){
if (!obj) return defaultValue
return defaultTo(defaultValue, obj[ property ])
}
export const propOr = curry(propOrFn)
props
props<P extends string, T>(propsToPick: P[], obj: Record<P, T>): T[]
It takes list with properties propsToPick
and returns a list with property values in obj
.
const result = R.props(
['a', 'b'],
{a:1, c:3}
)
// => [1, undefined]
Try this R.props example in Rambda REPL
R.props source
import { _isArray } from './_internals/_isArray.js'
import { mapArray } from './map.js'
export function props(propsToPick, obj){
if (arguments.length === 1){
return _obj => props(propsToPick, _obj)
}
if (!_isArray(propsToPick)){
throw new Error('propsToPick is not a list')
}
return mapArray(prop => obj[ prop ], propsToPick)
}
propSatisfies
propSatisfies<T>(predicate: Predicate<T>, property: string, obj: Record<string, T>): boolean
It returns true
if the object property satisfies a given predicate.
const obj = {a: {b:1}}
const property = 'a'
const predicate = x => x?.b === 1
const result = R.propSatisfies(predicate, property, Record<string, unknown>)
// => true
Try this R.propSatisfies example in Rambda REPL
R.propSatisfies source
import { curry } from './curry.js'
import { prop } from './prop.js'
function propSatisfiesFn(
predicate, property, obj
){
return predicate(prop(property, obj))
}
export const propSatisfies = curry(propSatisfiesFn)
random
random(minInclusive: number, maxInclusive: number): number
It returns a random number between min
inclusive and max
inclusive.
R.random source
export function random(min, max){
return Math.floor(Math.random() * (max - min + 1)) + min
}
range
range(startInclusive: number, endExclusive: number): number[]
It returns list of numbers between startInclusive
to endExclusive
markers.
R.range(0, 5)
// => [0, 1, 2, 3, 4]
Try this R.range example in Rambda REPL
R.range source
export function range(start, end){
if (arguments.length === 1) return _end => range(start, _end)
if (Number.isNaN(Number(start)) || Number.isNaN(Number(end))){
throw new TypeError('Both arguments to range must be numbers')
}
if (end < start) return []
const len = end - start
const willReturn = Array(len)
for (let i = 0; i < len; i++){
willReturn[ i ] = start + i
}
return willReturn
}
reduce
:boom: It passes index of the list as third argument to
reducer
function.
const list = [1, 2, 3]
const initialValue = 10
const reducer = (prev, current) => prev * current
const result = R.reduce(reducer, initialValue, list)
// => 60
Try this R.reduce example in Rambda REPL
reject
reject<T>(predicate: Predicate<T>, list: T[]): T[]
It has the opposite effect of R.filter
.
const list = [1, 2, 3, 4]
const obj = {a: 1, b: 2}
const predicate = x => x > 1
const result = [
R.reject(predicate, list),
R.reject(predicate, Record<string, unknown>)
]
// => [[1], {a: 1}]
Try this R.reject example in Rambda REPL
R.reject source
import { filter } from './filter.js'
export function reject(predicate, list){
if (arguments.length === 1) return _list => reject(predicate, _list)
return filter(x => !predicate(x), list)
}
rejectIndexed
Same as R.reject
, but it passes index/property as second argument to the predicate, when looping over arrays/objects.
const list = [1, 2, 3, 4]
const obj = {a: 1, b: 2}
const result = [
R.reject((x, index) => x > 1, list)
R.reject((x, property) => x > 1, Record<string, unknown>)
]
// => [[1], {a: 1}]
Try this R.rejectIndexed example in Rambda REPL
remove
remove(
toRemove: string | RegExp | (string | RegExp)[],
text: string
): string
It will remove all toRemove
entries from text
sequentially.
toRemove
argument can be either a list of strings/regular expressions or a single string/regular expression.
:boom: This is the only case where Rambdax exports clashes with Ramda API, as Ramda has
remove
method. IfRambda.remove
is introduced, then this method will be renamed.
const result = R.remove(
['foo','bar'],
'foo bar baz foo'
)
// => 'baz foo'
Try this R.remove example in Rambda REPL
R.remove source
import { replace } from './replace.js'
import { type } from './type.js'
export function remove(inputs, text){
if (arguments.length === 1){
return textHolder => remove(inputs, textHolder)
}
if (type(text) !== 'String'){
throw new Error(`R.remove requires string not ${ type(text) }`)
}
if (type(inputs) !== 'Array'){
return replace(
inputs, '', text
)
}
let textCopy = text
inputs.forEach(singleInput => {
textCopy = replace(
singleInput, '', textCopy
).trim()
})
return textCopy
}
removeIndex
removeIndex<T>(index: number, list: T[]): T[]
It returns a copy of list
input with removed index
.
const list = [1, 2, 3, 4]
const result = R.removeIndex(1, list)
// => [1, 3, 4]
Try this R.removeIndex example in Rambda REPL
R.removeIndex source
export function removeIndex(index, list){
if (arguments.length === 1) return _list => removeIndex(index, _list)
if (index <= 0) return list.slice(1)
if (index >= list.length - 1) return list.slice(0, list.length - 1)
return [ ...list.slice(0, index), ...list.slice(index + 1) ]
}
renameProps
renameProps(rules: object, input: object): object
If property prop
of rules
is also a property in input
, then rename input
property to rules[prop]
.
R.renameProps source
import { mergeRight } from './mergeRight.js'
import { omit } from './omit.js'
export function renameProps(conditions, inputObject){
if (arguments.length === 1){
return inputObjectHolder => renameProps(conditions, inputObjectHolder)
}
const renamed = {}
Object.keys(conditions).forEach(condition => {
if (Object.keys(inputObject).includes(condition)){
renamed[ conditions[ condition ] ] = inputObject[ condition ]
}
})
return mergeRight(renamed, omit(Object.keys(conditions), inputObject))
}
repeat
repeat<T>(x: T): (timesToRepeat: number) => T[]
R.repeat('foo', 3)
// => ['foo', 'foo', 'foo']
Try this R.repeat example in Rambda REPL
R.repeat source
export function repeat(x, timesToRepeat){
if (arguments.length === 1){
return _timesToRepeat => repeat(x, _timesToRepeat)
}
return Array(timesToRepeat).fill(x)
}
replace
replace(strOrRegex: RegExp | string, replacer: string, str: string): string
It replaces strOrRegex
found in str
with replacer
.
const strOrRegex = /o/g
const result = R.replace(strOrRegex, '|0|', 'foo')
// => 'f|0||0|'
Try this R.replace example in Rambda REPL
R.replace source
import { curry } from './curry.js'
function replaceFn(
pattern, replacer, str
){
return str.replace(pattern, replacer)
}
export const replace = curry(replaceFn)
replaceAll
replaceAll(patterns: (RegExp | string)[], replacer: string, input: string): string
Same as R.replace
but it accepts array of string and regular expressions instead of a single value.
const replacer = '|'
const patterns = [ /foo/g, 'bar' ]
const input = 'foo bar baz foo bar'
const result = R.replaceAll(patterns, replacer, input)
// => '| | baz | bar'
Try this R.replaceAll example in Rambda REPL
R.replaceAll source
import { curry } from './curry.js'
import { ok } from './ok.js'
function replaceAllFn(
patterns, replacer, input
){
ok(
patterns, replacer, input
)(
Array, String, String
)
let text = input
patterns.forEach(singlePattern => {
text = text.replace(singlePattern, replacer)
})
return text
}
export const replaceAll = curry(replaceAllFn)
reset
reset(): void
:boom:
R.getter
method contains explanations, tests and source information ofR.reset
,R.setter
andR.getter
methods.
reverse
reverse<T>(input: T[]): T[]
It returns a reversed copy of list or string input
.
const result = [
R.reverse('foo'),
R.reverse([1, 2, 3])
]
// => ['oof', [3, 2, 1]
Try this R.reverse example in Rambda REPL
R.reverse source
export function reverse(listOrString){
if (typeof listOrString === 'string'){
return listOrString.split('').reverse()
.join('')
}
const clone = listOrString.slice()
return clone.reverse()
}
set
set<T, U>(lens: Lens, replacer: U, obj: T): T
It returns a copied Object or Array with modified lens
focus set to replacer
value.
const input = {x: 1, y: 2}
const xLens = R.lensProp('x')
const result = [
R.set(xLens, 4, input),
R.set(xLens, 8, input)
]
// => [{x: 4, y: 2}, {x: 8, y: 2}]
Try this R.set example in Rambda REPL
R.set source
import { always } from './always.js'
import { curry } from './curry.js'
import { over } from './over.js'
function setFn(
lens, replacer, x
){
return over(
lens, always(replacer), x
)
}
export const set = curry(setFn)
setter
setter(keyOrObject: string | object, value?: any): void
:boom:
R.getter
method contains explanations, tests and source information ofR.reset
,R.setter
andR.getter
methods.
shuffle
shuffle<T>(list: T[]): T[]
It returns a randomized copy of array.
R.shuffle source
export function shuffle(arrayRaw){
const array = arrayRaw.concat()
let counter = array.length
while (counter > 0){
const index = Math.floor(Math.random() * counter)
counter--
const temp = array[ counter ]
array[ counter ] = array[ index ]
array[ index ] = temp
}
return array
}
slice
slice(from: number, to: number, input: string): string
const list = [0, 1, 2, 3, 4, 5]
const str = 'FOO_BAR'
const from = 1
const to = 4
const result = [
R.slice(from, to, str),
R.slice(from, to, list)
]
// => ['OO_', [1, 2, 3]]
Try this R.slice example in Rambda REPL
R.slice source
import { curry } from './curry.js'
function sliceFn(
from, to, list
){
return list.slice(from, to)
}
export const slice = curry(sliceFn)
sort
sort<T>(sortFn: (a: T, b: T) => number, list: T[]): T[]
It returns copy of list
sorted by sortFn
function, where sortFn
needs to return only -1
, 0
or 1
.
const list = [
{a: 2},
{a: 3},
{a: 1}
]
const sortFn = (x, y) => {
return x.a > y.a ? 1 : -1
}
const result = R.sort(sortFn, list)
const expected = [
{a: 1},
{a: 2},
{a: 3}
]
// => `result` is equal to `expected`
Try this R.sort example in Rambda REPL
R.sort source
import { cloneList } from './_internals/cloneList.js'
export function sort(sortFn, list){
if (arguments.length === 1) return _list => sort(sortFn, _list)
return cloneList(list).sort(sortFn)
}
sortBy
sortBy<T>(sortFn: (a: T) => Ord, list: T[]): T[]
It returns copy of list
sorted by sortFn
function, where sortFn
function returns a value to compare, i.e. it doesn't need to return only -1
, 0
or 1
.
const list = [
{a: 2},
{a: 3},
{a: 1}
]
const sortFn = x => x.a
const result = R.sortBy(sortFn, list)
const expected = [
{a: 1},
{a: 2},
{a: 3}
]
// => `result` is equal to `expected`
Try this R.sortBy example in Rambda REPL
R.sortBy source
import { cloneList } from './_internals/cloneList.js'
export function sortBy(sortFn, list){
if (arguments.length === 1) return _list => sortBy(sortFn, _list)
const clone = cloneList(list)
return clone.sort((a, b) => {
const aSortResult = sortFn(a)
const bSortResult = sortFn(b)
if (aSortResult === bSortResult) return 0
return aSortResult < bSortResult ? -1 : 1
})
}
sortByPath
sortByPath<T>(sortPath: Path, list: T[]): T[]
It returns copy of list
sorted by sortPath
value.
As sortPath
is passed to R.path
, it can be either a string or an array of strings.
const list = [
{a: {b: 2}},
{a: {b: 1}},
{a: {b: 3}}
]
const result = R.sortByPath('a.b', list)
const expected = [
{a: {b: 1}},
{a: {b: 2}},
{a: {b: 3}}
]
// => `result` is equal to `expected`
Try this R.sortByPath example in Rambda REPL
R.sortByPath source
import { path } from './path.js'
import { sortBy } from './sortBy.js'
export function sortByPath(sortPath, list){
if (arguments.length === 1) return _list => sortByPath(sortPath, _list)
return sortBy(path(sortPath), list)
}
sortByProps
sortByProps<T>(sortPaths: string[], list: T[]): T[]
It returns sorted copy of list
of objects.
Sorting is done using a list of strings, each representing a path. Two members a
and b
from list
can be sorted if both return a value for a given path. If the value is equal, then the next member of sortPaths
(if there is such) will be used in order to find difference between a
and b
.
const list = [
{a: {b: 2}},
{a: {b: 1}},
{a: {b: 3}}
]
const result = R.sortByProps(['a.b'], list)
const expected = [
{a: {b: 1}},
{a: {b: 2}},
{a: {b: 3}}
]
// => `result` is equal to `expected`
Try this R.sortByProps example in Rambda REPL
R.sortByProps source
import { path } from './path.js'
function singleSort(
a, b, sortPaths
){
let toReturn = 0
sortPaths.forEach(singlePath => {
if (toReturn !== 0) return
const aResult = path(singlePath, a)
const bResult = path(singlePath, b)
if ([ aResult, bResult ].includes(undefined)) return
if (aResult === bResult) return
toReturn = aResult > bResult ? 1 : -1
})
return toReturn
}
export function sortByProps(sortPaths, list){
if (arguments.length === 1) return _list => sortByProps(sortPaths, _list)
const clone = list.slice()
clone.sort((a, b) => singleSort(
a, b, sortPaths
))
return clone
}
sortObject
sortObject<T>(predicate: SortObjectPredicate<T>, input: { [key: string]: T }): { [keyOutput: string]: T }
It returns a sorted version of input
object.
const predicate = (propA, propB, valueA, valueB) => valueA > valueB ? -1 : 1
const result = R.sortObject(predicate, {a:1, b: 4, c: 2})
// => {b: 4, c: 2, a: 1}
Try this R.sortObject example in Rambda REPL
R.sortObject source
import { sort } from './sort.js'
export function sortObject(predicate, obj){
if (arguments.length === 1){
return _obj => sortObject(predicate, _obj)
}
const keys = Object.keys(obj)
const sortedKeys = sort((a, b) => predicate(
a, b, obj[ a ], obj[ b ]
), keys)
const toReturn = {}
sortedKeys.forEach(singleKey => {
toReturn[ singleKey ] = obj[ singleKey ]
})
return toReturn
}
split
split(separator: string | RegExp): (str: string) => string[]
Curried version of String.prototype.split
const str = 'foo|bar|baz'
const separator = '|'
const result = R.split(separator, str)
// => [ 'foo', 'bar', 'baz' ]
Try this R.split example in Rambda REPL
R.split source
export function split(separator, str){
if (arguments.length === 1) return _str => split(separator, _str)
return str.split(separator)
}
splitAt
splitAt<T>(index: number, input: T[]): [T[], T[]]
It splits string or array at a given index.
const list = [ 1, 2, 3 ]
const result = R.splitAt(2, list)
// => [[ 1, 2 ], [ 3 ]]
Try this R.splitAt example in Rambda REPL
R.splitAt source
import { _isArray } from './_internals/_isArray.js'
import { drop } from './drop.js'
import { maybe } from './maybe.js'
import { take } from './take.js'
export function splitAt(index, input){
if (arguments.length === 1){
return _list => splitAt(index, _list)
}
if (!input) throw new TypeError(`Cannot read property 'slice' of ${ input }`)
if (!_isArray(input) && typeof input !== 'string') return [ [], [] ]
const correctIndex = maybe(
index < 0,
input.length + index < 0 ? 0 : input.length + index,
index
)
return [ take(correctIndex, input), drop(correctIndex, input) ]
}
splitEvery
splitEvery<T>(sliceLength: number, input: T[]): (T[])[]
It splits input
into slices of sliceLength
.
const result = [
R.splitEvery(2, [1, 2, 3]),
R.splitEvery(3, 'foobar')
]
const expected = [
[[1, 2], [3]],
['foo', 'bar']
]
// => `result` is equal to `expected`
Try this R.splitEvery example in Rambda REPL
R.splitEvery source
export function splitEvery(sliceLength, listOrString){
if (arguments.length === 1){
return _listOrString => splitEvery(sliceLength, _listOrString)
}
if (sliceLength < 1){
throw new Error('First argument to splitEvery must be a positive integer')
}
const willReturn = []
let counter = 0
while (counter < listOrString.length){
willReturn.push(listOrString.slice(counter, counter += sliceLength))
}
return willReturn
}
splitWhen
splitWhen<T, U>(predicate: Predicate<T>, list: U[]): (U[])[]
It splits list
to two arrays according to a predicate
function.
The first array contains all members of list
before predicate
returns true
.
const list = [1, 2, 1, 2]
const result = R.splitWhen(R.equals(2), list)
// => [[1], [2, 1, 2]]
Try this R.splitWhen example in Rambda REPL
R.splitWhen source
export function splitWhen(predicate, input){
if (arguments.length === 1){
return _input => splitWhen(predicate, _input)
}
if (!input)
throw new TypeError(`Cannot read property 'length' of ${ input }`)
const preFound = []
const postFound = []
let found = false
let counter = -1
while (counter++ < input.length - 1){
if (found){
postFound.push(input[ counter ])
} else if (predicate(input[ counter ])){
postFound.push(input[ counter ])
found = true
} else {
preFound.push(input[ counter ])
}
}
return [ preFound, postFound ]
}
startsWith
startsWith(target: string, str: string): boolean
When iterable is a string, then it behaves as String.prototype.startsWith
.
When iterable is a list, then it uses R.equals to determine if the target list starts in the same way as the given target.
:boom: It doesn't work with arrays unlike its corresponding Ramda method.
const str = 'foo-bar'
const list = [{a:1}, {a:2}, {a:3}]
const result = [
R.startsWith('foo', str),
R.startsWith([{a:1}, {a:2}], list)
]
// => [true, true]
Try this R.startsWith example in Rambda REPL
R.startsWith source
import { _isArray } from './_internals/_isArray.js'
import { equals } from './equals.js'
export function startsWith(target, iterable){
if (arguments.length === 1)
return _iterable => startsWith(target, _iterable)
if (typeof iterable === 'string'){
return iterable.startsWith(target)
}
if (!_isArray(target)) return false
let correct = true
const filtered = target.filter((x, index) => {
if (!correct) return false
const result = equals(x, iterable[ index ])
if (!result) correct = false
return result
})
return filtered.length === target.length
}
subtract
Curried version of x - y
const x = 3
const y = 1
const result = R.subtract(x, y)
// => 2
Try this R.subtract example in Rambda REPL
sum
sum(list: number[]): number
R.sum([1, 2, 3, 4, 5])
// => 15
Try this R.sum example in Rambda REPL
R.sum source
export function sum(list){
return list.reduce((prev, current) => prev + current, 0)
}
switcher
switcher<T>(valueToMatch: any): Switchem<T>
Edited fork of Switchem library.
The method return a value if the matched option is a value.
If the matched option is a function, then R.switcher
returns a function which expects input. Tests of the method explain it better than this short description.
R.equals
is used to determine equality.
const valueToMatch = {foo: 1}
const result = R.switcher(valueToMatch)
.is('baz', 'is baz')
.is(x => typeof x === 'boolean', 'is boolean')
.is({foo: 1}, 'Property foo is 1')
.default('is bar')
// => 'Property foo is 1'
Try this R.switcher example in Rambda REPL
R.switcher source
import { equals } from './equals.js'
const NO_MATCH_FOUND = Symbol ? Symbol('NO_MATCH_FOUND') : undefined
const getMatchingKeyValuePair = (
cases, testValue, defaultValue
) => {
let iterationValue
for (let index = 0; index < cases.length; index++){
iterationValue = cases[ index ].test(testValue)
if (iterationValue !== NO_MATCH_FOUND){
return iterationValue
}
}
return defaultValue
}
const isEqual = (testValue, matchValue) => {
const willReturn =
typeof testValue === 'function' ?
testValue(matchValue) :
equals(testValue, matchValue)
return willReturn
}
const is = (testValue, matchResult = true) => ({
key : testValue,
test : matchValue =>
isEqual(testValue, matchValue) ? matchResult : NO_MATCH_FOUND,
})
class Switchem{
constructor(
defaultValue, cases, willMatch
){
if (cases === undefined && willMatch === undefined){
this.cases = []
this.defaultValue = undefined
this.willMatch = defaultValue
} else {
this.cases = cases
this.defaultValue = defaultValue
this.willMatch = willMatch
}
return this
}
default(defaultValue){
const holder = new Switchem(
defaultValue, this.cases, this.willMatch
)
return holder.match(this.willMatch)
}
is(testValue, matchResult){
return new Switchem(
this.defaultValue,
[ ...this.cases, is(testValue, matchResult) ],
this.willMatch
)
}
match(matchValue){
return getMatchingKeyValuePair(
this.cases, matchValue, this.defaultValue
)
}
}
export function switcher(input){
return new Switchem(input)
}
symmetricDifference
symmetricDifference<T>(x: T[], y: T[]): T[]
It returns a merged list of x
and y
with all equal elements removed.
R.equals
is used to determine equality.
const x = [ 1, 2, 3, 4 ]
const y = [ 3, 4, 5, 6 ]
const result = R.symmetricDifference(x, y)
// => [ 1, 2, 5, 6 ]
Try this R.symmetricDifference example in Rambda REPL
R.symmetricDifference source
import { concat } from './concat.js'
import { filter } from './filter.js'
import { includes } from './includes.js'
export function symmetricDifference(x, y){
if (arguments.length === 1){
return _y => symmetricDifference(x, _y)
}
return concat(filter(value => !includes(value, y), x),
filter(value => !includes(value, x), y))
}
T
T(): boolean
R.T()
// => true
Try this R.T example in Rambda REPL
R.T source
export function T(){
return true
}
tail
tail<T extends unknown[]>(input: T): T extends [any, ...infer U] ? U : [...T]
It returns all but the first element of input
.
const result = [
R.tail([1, 2, 3]),
R.tail('foo')
]
// => [[2, 3], 'oo']
Try this R.tail example in Rambda REPL
R.tail source
import { drop } from './drop.js'
export function tail(listOrString){
return drop(1, listOrString)
}
take
take<T>(howMany: number, input: T[]): T[]
It returns the first howMany
elements of input
.
const howMany = 2
const result = [
R.take(howMany, [1, 2, 3]),
R.take(howMany, 'foobar'),
]
// => [[1, 2], 'fo']
Try this R.take example in Rambda REPL
R.take source
import baseSlice from './_internals/baseSlice.js'
export function take(howMany, listOrString){
if (arguments.length === 1)
return _listOrString => take(howMany, _listOrString)
if (howMany < 0) return listOrString.slice()
if (typeof listOrString === 'string') return listOrString.slice(0, howMany)
return baseSlice(
listOrString, 0, howMany
)
}
takeLast
takeLast<T>(howMany: number, input: T[]): T[]
It returns the last howMany
elements of input
.
const howMany = 2
const result = [
R.takeLast(howMany, [1, 2, 3]),
R.takeLast(howMany, 'foobar'),
]
// => [[2, 3], 'ar']
Try this R.takeLast example in Rambda REPL
R.takeLast source
import baseSlice from './_internals/baseSlice.js'
export function takeLast(howMany, listOrString){
if (arguments.length === 1)
return _listOrString => takeLast(howMany, _listOrString)
const len = listOrString.length
if (howMany < 0) return listOrString.slice()
let numValue = howMany > len ? len : howMany
if (typeof listOrString === 'string')
return listOrString.slice(len - numValue)
numValue = len - numValue
return baseSlice(
listOrString, numValue, len
)
}
takeLastWhile
takeLastWhile(predicate: (x: string) => boolean, input: string): string
const result = R.takeLastWhile(
x => x > 2,
[1, 2, 3, 4]
)
// => [3, 4]
Try this R.takeLastWhile example in Rambda REPL
R.takeLastWhile source
import { _isArray } from './_internals/_isArray.js'
export function takeLastWhile(predicate, input){
if (arguments.length === 1){
return _input => takeLastWhile(predicate, _input)
}
if (input.length === 0) return input
let found = false
const toReturn = []
let counter = input.length
while (!found || counter === 0){
counter--
if (predicate(input[ counter ]) === false){
found = true
} else if (!found){
toReturn.push(input[ counter ])
}
}
return _isArray(input) ? toReturn.reverse() : toReturn.reverse().join('')
}
takeUntil
takeUntil<T>(predicate: (x: T) => boolean, list: T[]): T[]
const list = [1, 2, 3, 4, 5]
const predicate = x => x > 3
const result = R.takeUntil(predicate, list)
// => [1, 2, 3]
Try this R.takeUntil example in Rambda REPL
R.takeUntil source
export function takeUntil(predicate, list){
const toReturn = []
let stopFlag = false
let counter = -1
while (stopFlag === false && counter++ < list.length - 1){
if (predicate(list[ counter ])){
stopFlag = true
} else {
toReturn.push(list[ counter ])
}
}
return toReturn
}
takeWhile
const list = [1, 2, 3, 4]
const predicate = x => x < 3
const result = R.takeWhile(predicate, list)
// => [1, 2]
Try this R.takeWhile example in Rambda REPL
tap
tap<T>(fn: (x: T) => void, input: T): T
It applies function fn
to input x
and returns x
.
One use case is debuging in the middle of R.compose
.
const list = [1, 2, 3]
R.compose(
R.map(x => x * 2)
R.tap(console.log),
R.filter(x => x > 1)
)(list)
// => `2` and `3` will be logged
Try this R.tap example in Rambda REPL
R.tap source
export function tap(fn, x){
if (arguments.length === 1) return _x => tap(fn, _x)
fn(x)
return x
}
tapAsync
tapAsync<T>(fn: Func<any> | Promise<any>, input: T): T
Asynchronous version of R.tap
.
R.tapAsync source
async function tapAsyncFn(fn, input){
await fn(input)
return input
}
export function tapAsync(fn, input){
if (arguments.length === 1){
return async _input => tapAsyncFn(fn, _input)
}
return new Promise((resolve, reject) => {
tapAsyncFn(fn, input).then(resolve)
.catch(reject)
})
}
test
test(regExpression: RegExp): (str: string) => boolean
It determines whether str
matches regExpression
.
R.test(/^f/, 'foo')
// => true
Try this R.test example in Rambda REPL
R.test source
export function test(pattern, str){
if (arguments.length === 1) return _str => test(pattern, _str)
if (typeof pattern === 'string'){
throw new TypeError(`‘test’ requires a value of type RegExp as its first argument; received "${ pattern }"`)
}
return str.search(pattern) !== -1
}
throttle
throttle<T, U>(fn: (input: T) => U, ms: number): (input: T) => U
let counter = 0
const inc = () => {
counter++
}
const throttledInc = R.throttle(inc, 800)
const result = async () => {
throttledInc()
await R.delay(500)
throttledInc()
return counter
}
// `result` resolves to `1`
Try this R.throttle example in Rambda REPL
R.throttle source
export function throttle(fn, ms){
let wait = false
let result
return function (...input){
if (!wait){
result = fn.apply(null, input)
wait = true
setTimeout(() => {
wait = false
}, ms)
}
return result
}
}
times
times<T>(fn: (i: number) => T, howMany: number): T[]
It returns the result of applying function fn
over members of range array.
The range array includes numbers between 0
and howMany
(exclusive).
const fn = x => x * 2
const howMany = 5
R.times(fn, howMany)
// => [0, 2, 4, 6, 8]
Try this R.times example in Rambda REPL
R.times source
import { map } from './map.js'
import { range } from './range.js'
export function times(fn, howMany){
if (arguments.length === 1) return _howMany => times(fn, _howMany)
if (!Number.isInteger(howMany) || howMany < 0){
throw new RangeError('n must be an integer')
}
return map(fn, range(0, howMany))
}
toDecimal
toDecimal(num: number, charsAfterDecimalPoint?: number): number
R.toDecimal(2.45464,2) // => 2.45
Try this R.toDecimal example in Rambda REPL
R.toDecimal source
export function toDecimal(number, charsAfterDecimalPoint = 2){
return Number(parseFloat(String(number)).toFixed(charsAfterDecimalPoint))
}
toLower
toLower<S extends string>(str: S): Lowercase<S>
R.toLower('FOO')
// => 'foo'
Try this R.toLower example in Rambda REPL
R.toLower source
export function toLower(str){
return str.toLowerCase()
}
toPairs
toPairs<O extends object, K extends Extract<keyof O, string | number>>(obj: O): Array<{ [key in K]: [`${key}`, O[key]] }[K]>
It transforms an object to a list.
const list = {
a : 1,
b : 2,
c : [ 3, 4 ],
}
const expected = [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', [ 3, 4 ] ] ]
const result = R.toPairs(list)
// => `result` is equal to `expected`
Try this R.toPairs example in Rambda REPL
R.toPairs source
export function toPairs(obj){
return Object.entries(obj)
}
toString
toString(x: unknown): string
R.toString([1, 2])
// => '1,2'
Try this R.toString example in Rambda REPL
R.toString source
export function toString(x){
return x.toString()
}
toUpper
toUpper<S extends string>(str: S): Uppercase<S>
R.toUpper('foo')
// => 'FOO'
Try this R.toUpper example in Rambda REPL
R.toUpper source
export function toUpper(str){
return str.toUpperCase()
}
transpose
transpose<T>(list: (T[])[]): (T[])[]
const list = [[10, 11], [20], [], [30, 31, 32]]
const expected = [[10, 20, 30], [11, 31], [32]]
const result = R.transpose(list)
// => `result` is equal to `expected`
Try this R.transpose example in Rambda REPL
R.transpose source
import { _isArray } from './_internals/_isArray.js'
export function transpose(array){
return array.reduce((acc, el) => {
el.forEach((nestedEl, i) =>
_isArray(acc[ i ]) ? acc[ i ].push(nestedEl) : acc.push([ nestedEl ]))
return acc
}, [])
}
trim
trim(str: string): string
R.trim(' foo ')
// => 'foo'
Try this R.trim example in Rambda REPL
R.trim source
export function trim(str){
return str.trim()
}
tryCatch
It returns function that runs fn
in try/catch
block. If there was an error, then fallback
is used to return the result. Note that fn
can be value or asynchronous/synchronous function(unlike Ramda
where fallback can only be a synchronous function).
:boom: Please check the tests of
R.tryCatch
to fully understand how this method works.
const fn = x => x.foo
const result = [
R.tryCatch(fn, false)(null),
R.tryCatch(fn, false)({foo: 'bar'})
]
// => [false, 'bar']
Try this R.tryCatch example in Rambda REPL
tryCatchAsync
tryCatchAsync<T>(
fn: (input: any) => Promise<T>,
fallback: T
): (input: any) => Promise<T>
It returns function that runs fn
in try/catch
block. If there was an error, then fallback
is used to return the result.
const x = {foo: 1}
const fnFoo = async () => x.foo
const fnBar = async () => x.bar
const result = await Promise.all([
R.tryCatchAsync (fnFoo, false)(),
R.tryCatchAsync(fnBar, false)()
])
// => [1, false]
Try this R.tryCatchAsync example in Rambda REPL
R.tryCatchAsync source
import { type } from './type.js'
export function tryCatchAsync(fn, fallback){
return (...inputs) =>
new Promise(resolve => {
fn(...inputs)
.then(resolve)
.catch(err => {
if (type(fallback) !== 'Function'){
return resolve(fallback)
}
if (type(fallback) !== 'Promise'){
return resolve(fallback(err, ...inputs))
}
fallback(err, ...inputs)
.then(resolve)
.catch(resolve)
})
})
}
type
It accepts any input and it returns its type.
:boom:
NaN
,Promise
andAsync
are types specific for Rambda.
R.type(() => {}) // => 'Function'
R.type(async () => {}) // => 'Async'
R.type([]) // => 'Array'
R.type({}) // => 'Object'
R.type('foo') // => 'String'
R.type(1) // => 'Number'
R.type(true) // => 'Boolean'
R.type(null) // => 'Null'
R.type(/[A-z]/) // => 'RegExp'
R.type('foo'*1) // => 'NaN'
const delay = ms => new Promise(resolve => {
setTimeout(function () {
resolve()
}, ms)
})
R.type(delay) // => 'Promise'
Try this R.type example in Rambda REPL
unapply
unapply<T = any>(fn: (args: any[]) => T): (...args: any[]) => T
It calls a function fn
with the list of values of the returned function.
R.unapply
is the opposite of R.apply
method.
R.unapply(JSON.stringify)(1, 2, 3)
//=> '[1,2,3]'
Try this R.unapply example in Rambda REPL
R.unapply source
export function unapply(fn){
return function (...args){
return fn.call(this, args)
}
}
union
union<T>(x: T[], y: T[]): T[]
It takes two lists and return a new list containing a merger of both list with removed duplicates.
R.equals
is used to compare for duplication.
const result = R.union([1,2,3], [3,4,5]);
// => [1, 2, 3, 4, 5]
Try this R.union example in Rambda REPL
R.union source
import { cloneList } from './_internals/cloneList.js'
import { includes } from './includes.js'
export function union(x, y){
if (arguments.length === 1) return _y => union(x, _y)
const toReturn = cloneList(x)
y.forEach(yInstance => {
if (!includes(yInstance, x)) toReturn.push(yInstance)
})
return toReturn
}
uniq
uniq<T>(list: T[]): T[]
It returns a new array containing only one copy of each element of list
.
R.equals
is used to determine equality.
const list = [1, 1, {a: 1}, {a: 2}, {a:1}]
R.uniq(list)
// => [1, {a: 1}, {a: 2}]
Try this R.uniq example in Rambda REPL
R.uniq source
import { _Set } from './_internals/set.js'
export function uniq(list){
const set = new _Set()
const willReturn = []
list.forEach(item => {
if (set.checkUniqueness(item)){
willReturn.push(item)
}
})
return willReturn
}
uniqBy
const result = R.uniqBy(Math.abs, [ -2, 1, 0, -1, 2 ])
// => [-2, 1, 0]
Try this R.uniqBy example in Rambda REPL
uniqWith
uniqWith<T, U>(predicate: (x: T, y: T) => boolean, list: T[]): T[]
It returns a new array containing only one copy of each element in list
according to predicate
function.
This predicate should return true, if two elements are equal.
const list = [
{id: 0, title:'foo'},
{id: 1, title:'bar'},
{id: 2, title:'baz'},
{id: 3, title:'foo'},
{id: 4, title:'bar'},
]
const expected = [
{id: 0, title:'foo'},
{id: 1, title:'bar'},
{id: 2, title:'baz'},
]
const predicate = (x,y) => x.title === y.title
const result = R.uniqWith(predicate, list)
// => `result` is equal to `expected`
Try this R.uniqWith example in Rambda REPL
R.uniqWith source
function includesWith(
predicate, target, list
){
let willReturn = false
let index = -1
while (++index < list.length && !willReturn){
const value = list[ index ]
if (predicate(target, value)){
willReturn = true
}
}
return willReturn
}
export function uniqWith(predicate, list){
if (arguments.length === 1) return _list => uniqWith(predicate, _list)
let index = -1
const willReturn = []
while (++index < list.length){
const value = list[ index ]
if (!includesWith(
predicate, value, willReturn
)){
willReturn.push(value)
}
}
return willReturn
}
unless
unless<T, U>(predicate: (x: T) => boolean, whenFalseFn: (x: T) => U, x: T): T | U
The method returns function that will be called with argument input
.
If predicate(input)
returns false
, then the end result will be the outcome of whenFalse(input)
.
In the other case, the final output will be the input
itself.
const fn = R.unless(
x => x > 2,
x => x + 10
)
const result = [
fn(1),
fn(5)
]
// => [11, 5]
Try this R.unless example in Rambda REPL
R.unless source
export function unless(predicate, whenFalse){
if (arguments.length === 1){
return _whenFalse => unless(predicate, _whenFalse)
}
return input => predicate(input) ? input : whenFalse(input)
}
unwind
const obj = {
a: 1,
b: [2, 3],
}
const result = unwind('b', Record<string, unknown>)
const expected = [{a:1, b:2}, {a:1, b:3}]
// => `result` is equal to `expected`
Try this R.unwind example in Rambda REPL
update
update<T>(index: number, newValue: T, list: T[]): T[]
It returns a copy of list
with updated element at index
with newValue
.
const index = 2
const newValue = 88
const list = [1, 2, 3, 4, 5]
const result = R.update(index, newValue, list)
// => [1, 2, 88, 4, 5]
Try this R.update example in Rambda REPL
R.update source
import { cloneList } from './_internals/cloneList.js'
import { curry } from './curry.js'
function updateFn(
index, newValue, list
){
const clone = cloneList(list)
if (index === -1) return clone.fill(newValue, index)
return clone.fill(
newValue, index, index + 1
)
}
export const update = curry(updateFn)
updateObject
updateObject<Output>(rules: ([string, any])[], input: object): Output
Very similar to R.assocPath
but it applies list of updates instead of only a single update.
It returns a copy of obj
input with changed properties according to rules
input.
Each instance of rules
is a tuple of object path and the new value for this path. If such object path does not exist, then such object path is created.
As it uses R.path
underneath, object path can be either string or array of strings(in Typescript object path can be only a string).
const obj = {
a: {b: 1},
foo: {bar: 10},
}
const rules = [
['a.b', 2],
['foo.bar', 20],
['q.z', 300],
]
const result = R.updateObject(rules, Record<string, unknown>)
const expected = {
a: {b: 2},
foo: {bar: 20},
q: {z: 300},
}
// => `result` is equal to `expected`
Try this R.updateObject example in Rambda REPL
R.updateObject source
import { assocPath } from './assocPath.js'
export function updateObject(rules, obj){
if (arguments.length === 1) return _obj => updateObject(rules, _obj)
let clone = { ...obj } /*?.*/
rules.forEach(([ objectPath, newValue ]) => {
clone = assocPath(
objectPath, newValue, clone
)
})
return clone
}
values
values<T extends object, K extends keyof T>(obj: T): T[K][]
With correct input, this is nothing more than Object.values(Record<string, unknown>)
. If obj
is not an object, then it returns an empty array.
const obj = {a:1, b:2}
R.values(Record<string, unknown>)
// => [1, 2]
Try this R.values example in Rambda REPL
R.values source
import { type } from './type.js'
export function values(obj){
if (type(obj) !== 'Object') return []
return Object.values(obj)
}
view
view<T, U>(lens: Lens): (target: T) => U
It returns the value of lens
focus over target
object.
const lens = R.lensProp('x')
R.view(lens, {x: 1, y: 2}) // => 1
R.view(lens, {x: 4, y: 2}) // => 4
Try this R.view example in Rambda REPL
R.view source
const Const = x => ({
x,
map : fn => Const(x),
})
export function view(lens, target){
if (arguments.length === 1) return _target => view(lens, _target)
return lens(Const)(target).x
}
viewOr
viewOr<Input, Output>(fallback: Output, lens: Lens, input: Input): Output
A combination between R.defaultTo
and `R.view.
const lens = R.lensProp('a');
const input = {a: 'foo'}
const fallbackInput = {b: 'bar'}
const fallback = 'FALLBACK'
const result = [
R.viewOr(fallback, lens, input),
R.viewOr(fallback, lens, fallbackInput)
]
// => ['foo', 'FALLBACK']
Try this R.viewOr example in Rambda REPL
R.viewOr source
import { curry } from './curry.js'
import { defaultTo } from './defaultTo.js'
import { view } from './view.js'
function viewOrFn(
fallback, lens, input
){
return defaultTo(fallback, view(lens, input))
}
export const viewOr = curry(viewOrFn)
wait
wait<T>(fn: Promise<T>): Promise<[T, Error|undefined]>
It provides Golang
-like interface for handling promises.
const [result, err] = await R.wait(R.delay(1000))
// => err is undefined
// => result is `RAMBDAX_DELAY`
Try this R.wait example in Rambda REPL
R.wait source
export function wait(fn){
return new Promise(resolve => {
fn.then(result => resolve([ result, undefined ])).catch(e =>
resolve([ undefined, e ]))
})
}
waitFor
waitFor(
waitForTrueCondition: () => boolean,
howLong: number,
loops?: number
): () => Promise<boolean>
It returns true
, if condition
returns true
within howLong
milisececonds time period.
The method accepts an optional third argument loops
(default to 10), which is the number of times waitForTrueCondition
will be evaluated for howLong
period. Once this function returns a value different from false
, this value will be the final result.
Otherwise, R.waitFor
will return false
.
const howLong = 1000
let counter = 0
const waitForTrueCondition = async x => {
await R.delay(100)
counter = counter + x
return counter > 10
}
const result = await R.waitFor(waitForTrueCondition, howLong)(2)
// => true
Try this R.waitFor example in Rambda REPL
R.waitFor source
import { delay } from './delay.js'
import { range } from './range.js'
import { type } from './type.js'
export function waitFor(
condition, howLong, loops = 10
){
const typeCondition = type(condition)
const passPromise = typeCondition === 'Promise'
const passFunction = typeCondition === 'Function'
const interval = Math.floor(howLong / loops)
if (!(passPromise || passFunction)){
throw new Error('R.waitFor')
}
return async (...inputs) => {
for (const _ of range(0, loops)){
const resultCondition = await condition(...inputs)
if (resultCondition === false){
await delay(interval)
} else {
return resultCondition
}
}
return false
}
}
when
when<T, U>(predicate: (x: T) => boolean, whenTrueFn: (a: T) => U, input: T): T | U
R.when source
import { curry } from './curry.js'
function whenFn(
predicate, whenTrueFn, input
){
if (!predicate(input)) return input
return whenTrueFn(input)
}
export const when = curry(whenFn)
where
where<T, U>(conditions: T, input: U): boolean
It returns true
if all each property in conditions
returns true
when applied to corresponding property in input
object.
const condition = R.where({
a : x => typeof x === "string",
b : x => x === 4
})
const input = {
a : "foo",
b : 4,
c : 11,
}
const result = condition(input)
// => true
Try this R.where example in Rambda REPL
R.where source
export function where(conditions, input){
if (input === undefined){
return _input => where(conditions, _input)
}
let flag = true
for (const prop in conditions){
const result = conditions[ prop ](input[ prop ])
if (flag && result === false){
flag = false
}
}
return flag
}
whereAny
Same as R.where
, but it will return true
if at least one condition check returns true
.
const conditions = {
a: a => a > 1,
b: b => b > 2,
}
const result = [
R.whereAny(conditions, {b:3}),
R.whereAny(conditions, {c:4})
]
// => [true, false]
Try this R.whereAny example in Rambda REPL
whereEq
whereEq<T, U>(condition: T, input: U): boolean
It will return true
if all of input
object fully or partially include rule
object.
R.equals
is used to determine equality.
const condition = { a : { b : 1 } }
const input = {
a : { b : 1 },
c : 2
}
const result = whereEq(condition, input)
// => true
Try this R.whereEq example in Rambda REPL
R.whereEq source
import { equals } from './equals.js'
import { filter } from './filter.js'
export function whereEq(condition, input){
if (arguments.length === 1){
return _input => whereEq(condition, _input)
}
const result = filter((conditionValue, conditionProp) =>
equals(conditionValue, input[ conditionProp ]),
condition)
return Object.keys(result).length === Object.keys(condition).length
}
without
without<T>(matchAgainst: T[], source: T[]): T[]
It will return a new array, based on all members of source
list that are not part of matchAgainst
list.
R.equals
is used to determine equality.
const source = [1, 2, 3, 4]
const matchAgainst = [2, 3]
const result = R.without(matchAgainst, source)
// => [1, 4]
Try this R.without example in Rambda REPL
R.without source
import { _indexOf } from './equals.js'
import { reduce } from './reduce.js'
export function without(matchAgainst, source){
if (source === undefined){
return _source => without(matchAgainst, _source)
}
return reduce(
(prev, current) =>
_indexOf(current, matchAgainst) > -1 ? prev : prev.concat(current),
[],
source
)
}
xnor
xnor(x: boolean, y: boolean): boolean
Logical XNOR
const result = [
R.xnor(1, 0),
R.xnor(0, 1),
R.xnor(0, 0),
R.xnor(1, 1),
]
// => [true, false, false, true]
Try this R.xnor example in Rambda REPL
R.xnor source
export function xnor(x, y){
if (arguments.length === 1){
return _y => xnor(x, _y)
}
return Boolean(x && y || !x && !y)
}
xor
xor(x: boolean, y: boolean): boolean
Logical XOR
const result = [
xor(true, true),
xor(false, false),
xor(false, true),
]
// => [false, false, true]
Try this R.xor example in Rambda REPL
R.xor source
export function xor(a, b){
if (arguments.length === 1) return _b => xor(a, _b)
return Boolean(a) && !b || Boolean(b) && !a
}
zip
zip<K, V>(x: K[], y: V[]): KeyValuePair<K, V>[]
It will return a new array containing tuples of equally positions items from both x
and y
lists.
The returned list will be truncated to match the length of the shortest supplied list.
const x = [1, 2]
const y = ['A', 'B']
R.zip(x, y)
// => [[1, 'A'], [2, 'B']]
// truncates to shortest list
R.zip([...x, 3], ['A', 'B'])
// => [[1, 'A'], [2, 'B']]
Try this R.zip example in Rambda REPL
R.zip source
export function zip(left, right){
if (arguments.length === 1) return _right => zip(left, _right)
const result = []
const length = Math.min(left.length, right.length)
for (let i = 0; i < length; i++){
result[ i ] = [ left[ i ], right[ i ] ]
}
return result
}
zipObj
zipObj<T, K extends string>(keys: K[], values: T[]): { [P in K]: T }
It will return a new object with keys of keys
array and values of values
array.
const keys = ['a', 'b', 'c']
R.zipObj(keys, [1, 2, 3])
// => {a: 1, b: 2, c: 3}
// truncates to shortest list
R.zipObj(keys, [1, 2])
// => {a: 1, b: 2}
Try this R.zipObj example in Rambda REPL
R.zipObj source
import { take } from './take.js'
export function zipObj(keys, values){
if (arguments.length === 1) return yHolder => zipObj(keys, yHolder)
return take(values.length, keys).reduce((
prev, xInstance, i
) => {
prev[ xInstance ] = values[ i ]
return prev
}, {})
}
zipWith
zipWith<T, U, TResult>(fn: (x: T, y: U) => TResult, list1: T[], list2: U[]): TResult[]
const list1 = [ 10, 20, 30, 40 ]
const list2 = [ 100, 200 ]
const result = R.zipWith(
R.add, list1, list2
)
// => [110, 220]
Try this R.zipWith example in Rambda REPL
R.zipWith source
import { curry } from './curry.js'
import { take } from './take.js'
function zipWithFn(
fn, x, y
){
return take(x.length > y.length ? y.length : x.length, x).map((xInstance, i) => fn(xInstance, y[ i ]))
}
export const zipWith = curry(zipWithFn)
❯ CHANGELOG
8.1.0
-
Breaking change due to renaming of
R.partialCurry
toR.partialObject
. -
Wrong
R.update
if index is-1
- PR #593 -
Wrong curried typings in
R.anyPass
- Issue #642 -
R.modifyPath
not exported - Issue #640 -
Add new method
R.uniqBy
. Implementation is coming from Ramda MR#2641 -
Apply the following changes from
@types/rambda
:
-- [https://github.com/DefinitelyTyped/DefinitelyTyped/commit/bab47272d52fc7bb81e85da36dbe9c905a04d067](add AnyFunction
and AnyConstructor
)
-- Improve R.ifElse
typings - https://github.com/DefinitelyTyped/DefinitelyTyped/pull/59291
-- Make R.propEq
safe for null/undefined
arguments - https://github.com/ramda/ramda/pull/2594/files
-
Rambda's
pipe/compose
doesn't return proper length of composed function which leads to issue withR.applySpec
. It was fixed by alligning Rambda'spipe/compose
with Ramda logic - Issue #627 -
Replace
Async
withPromise
as return type ofR.type
. -
Add new types as Typescript output for
R.type
- "Map", "WeakMap", "Generator", "GeneratorFunction", "BigInt", "ArrayBuffer" -
Add new methods after
Ramda
version upgrade to0.28.0
:
-- R.count -- R.modifyPath -- R.on -- R.whereAny
-
Replace
Async
withPromise
as return type ofR.type
. -
Remove
isFunction
method -
Add
R.juxt
method -
Add
R.contains
method -
Add
R.mapcat
method WIP -
Add
R.flattenObject
method -
Add
R.deletePath
method WIP -
Change
R.count
logic to match the newRamda.count
method. Instead of counting for target value, the counting is done by predicate function.
8.0.1
- Rambdax doesn't work with
pnpm
due to wrong export configuration - Issue #619
8.0.0
- Breaking change - sync
R.compose
/R.pipe
with@types/ramda
. That is significant change so as safeguard, it will lead a major bump. Important - this lead to raising required Typescript version to4.2.2
. In other words, to useRambda
you'll need Typescript version4.2.2
or newer.
Related commit in @types/ramda
- https://github.com/DefinitelyTyped/DefinitelyTyped/commit/286eff4f76d41eb8f091e7437eabd8a60d97fc1f#diff-4f74803fa83a81e47cb17a7d8a4e46a7e451f4d9e5ce2f1bd7a70a72d91f4bc1
There are several other changes in @types/ramda
as stated in this comment. This leads to change of typings for the following methods in Rambda:
-- R.unless
-- R.toString
-- R.ifElse
-- R.always
-- R.complement
-- R.cond
-- R.is
-- R.sortBy
-- R.dissoc
-- R.toPairs
-- R.assoc
-- R.toLower
-- R.toUpper
-
One more reason for the breaking change is changing of export declarations in
package.json
based on this blog post and this merged Ramda's PR. This also led to renaming ofbabel.config.js
tobabel.config.cjs
. -
Add
R.apply
,R.bind
andR.unapply
-
Fix missing return value in
R.throttle
- Issue #76 -
Add
R.findAsync
- Issue #65 -
Fix
R.debounce
typings as the method actually doesn't return a result. -
R.startsWith/R.endsWith
now support lists as inputs. This way, it matches current Ramda behavior. -
Remove unused typing for
R.chain
. -
R.map
/R.filter
no longer accept bad inputs as iterable. This way, Rambda behaves more like Ramda, which also throws. -
Make
R.lastIndexOf
follow the logic ofR.indexOf
. -
Change
R.type
logic to Ramda logic. This way,R.type
can returnError
andSet
as results. -
Add missing logic in
R.equals
to compare sets - Issue #599 -
Improve list cloning - Issue #595
-
Handle multiple inputs with
R.allPass
andR.anyPass
- Issue #604 -
Fix
R.length
wrong logic with inputs as{length: 123}
- Issue #606. -
Improve non-curry typings of
R.merge
by using types from mobily/ts-belt. -
Improve performance of
R.uniqWith
. -
Wrong
R.update
if index is-1
- PR #593 -
Make
R.eqProps
safe for falsy inputs - based on this opened Ramda PR. -
Incorrect benchmarks for
R.pipe/R.compose
- Issue #608 -
Fix
R.last/R.head
typings - Issue #609
7.4.1
-
Fix corrupted Typescript definitions - Rambdax issue #72
-
Fix slow
R.uniq
methods - Issue #581
Fixing R.uniq
was done by improving R.indexOf
which has performance implication to all methods importing R.indexOf
:
- R.includes
- R.intersection
- R.difference
- R.excludes
- R.symmetricDifference
- R.union
7.4.0
-
Add
R.objOf
method -
Add
R.mapObjIndexed
method
7.3.0
-
Add
R.rejectIndexed
andR.partitionIndexed
methods - Rambdax issue #67 -
Expose
R.mapObject
,R.mapArray
,R.filterObject
andR.filterArray
- Issue #578 -
R.has
useObject.prototype.hasOwnProperty
- Issue #572 -
Fix
R.intersection
wrong order compared to Ramda. -
Expose
immutable.ts
typings which are Rambda typings withreadonly
statements - Issue #565, Rambdax issue #69 -
R.path
wrong return ofnull
instead ofundefined
when path value isnull
- PR #577 -
Wrong arguments order in
R.removeIndex
- Issue #66 -
Change
R.piped
typings to mimic that ofR.pipe
. Main difference is thatR.pipe
is focused on unary functions. -
Fix wrong logic when
R.without
useR.includes
while it should use array version ofR.includes
. -
Use uglify plugin for UMD bundle.
-
Remove
ts-toolbelt
types from Typescript definitions. Most affected are the following methods, which lose one of its curried definitions:
- R.maxBy
- R.minBy
- R.pathEq
- R.viewOr
- R.when
- R.merge
- R.mergeDeepRight
- R.mergeLeft
7.2.0
-
Approve PR #61 - fix wrong
R.isValid
typings -
R.produceAsync returns promise even if all rules are synchronous.
-
R.defaultTo
no longer accepts infinite inputs, thus it follows Ramda implementation. -
R.equals
supports equality of functions. -
R.pipe
doesn't useR.compose
. -
Close Issue #561 - export several internal TS interfaces and types
-
Add
CHANGELOG.md
file in release files list
7.1.0
-
Add
R.tryCatchAsync
-
Add
R.xnor
-
R.equals
supports equality of functions. -
Close Issue #559 - improve
R.propOr
typings -
Close Issue #560 - apply immutable lint to Typescript definitions
-
Close Issue #553 - fix problem with curried typings of
R.prop
-
Fix wrong
R.last
typing -
Upgrade all
rollup
related dependencies -
R.type
supportsSymbol
just like Ramda. -
Remove file extension in
main
property inpackage.json
in order to allowexperimental-modules
. See also this Ramda's PR - https://github.com/ramda/ramda/pull/2678/files -
Import
R.indexBy
/R.when
/R.zipObj
/R.propEq
/R.complement
changes from recent@types/ramda
release. -
R.tryCatch
stop supporting asynchronous functions; the previous behaviour is exported to Rambdax asR.tryCatchAsync
7.0.1
- Fix missing
Evolved
declaration in Typescript definition
7.0.0
-
Rename
R.produce
toR.produceAsync
-
Add
R.produce
which is synchronous version ofR.produceAsync
-
Stop supporting expression inside template's props. Also, spaces are no longer allowed between
{{
and}}
, i.e.R.interpolate('{{ foo }}', x)
should beR.interpolate('{{foo}}', x)
. -
Add typings for
R.takeWhile
when iterable is a string -
Add
R.takeLastWhile
-
Add
R.dropWhile
-
Add
R.eqProps
-
Add
R.dropLastWhile
-
Add
R.dropRepeats
-
Add
R.dropRepeatsWith
-
Add
R.evolve
6.2.0
-
R.switcher
acceptsundefined
as valid input -
Add
R.props
-
Add
R.zipWith
-
Add
R.splitAt
-
Add
R.splitWhen
-
Close Issue #547 - restore
readonly
declaration in Rambda Typescript definitions. -
R.append
/R.prepend
now work only with arrays just like Ramda. Previous behaviour was for them to work with both arrays and strings. -
Sync
R.pluck
typings with@types/ramda
as there was a tiny difference.
6.1.0
-
Add
R.mapIndexed
-
Add
R.filterIndexed
-
Add
R.forEachIndexed
-
Fix
R.and
wrong definition, because the function doesn't convert the result to boolean. This introduce another difference with@types/ramda
. -
Add
R.once
-
Add
R.or
6.0.0
-
Breaking change -
R.map
/R.filter
/R.reject
/R.forEach
/R.partition
doesn't pass index as second argument to the predicate, when looping over arrays. The old behaviour of map, filter and forEach can be found in Rambdax methods R.mapIndexed, R.filterIndexed and R.forEachIndexed(introduced in version6.1.0
). -
Breaking change -
R.all
/R.none
/R.any
/R.find
/R.findLast
/R.findIndex
/R.findLastIndex
doesn't pass index as second argument to the predicate. -
Add
R.applyDiff
method -
Change
R.assocPath
typings so the user can explicitly sets type of the new object -
Typings of
R.assoc
match its@types/ramda
counterpart. -
Simplify
R.forEach
typings -
Remove
ReadonlyArray<T>
pattern from Typescript definitions - not enough value for the noise it adds. -
Fix typing of
R.reject
as it wrongly declares that with object, it pass property to predicate.
5.1.0
-
Add
R.takeUntil
method -
Fix wrong
R.takeWhile
5.0.0
-
Deprecate
R.change
method - it does too much; partially replaced withR.updateObject
. -
Deprecate
R.compact
method - vague use case;R.filter
does the same job. -
R.produce
always returns a promise -
Add
R.updateObject
method -
Add
R.takeWhile
method -
Add
R.viewOr
method -
Add
R.pipeAsync
method -
Add
R.removeIndex
method -
Add
R.excludes
method -
R.includes
throws on wrong input, i.e.R.includes(1, null)
-
Close Issue #524 -
R.assocPath
wrong logic when number is used in array path input. -
R.mapToObjectAsync
supports currying -
R.mapAsyncLimit
supports currying -
Fix
R.mapAsync
to pass property to iterator, when input is an object. -
Fix currying for several async methods -
R.tapAsync
,R.produce
,R.filterAsync
*(extend typings)
4.2.0
-
Add
R.move
method -
Add
R.union
method -
Add
R.lensSatisfies
method -
Add
R.mapKeys
method -
Add
R.sortByPath
method -
Add
R.sortByProps
method -
Close Issue #519 -
ts-toolbelt
needs other type of export with--isolatedModules
flag
4.1.0
-
R.template
is renamed toR.interpolate
-
R.equals
now supports negative zero just likeRamda.equals
-
Add
R.replaceAll
method -
Add
R.lensEq
method
4.0.1
Forgot to export R.of
because of wrong marker in files/index.d.ts
4.0.0
Deprecate the following methods:
-
R.promiseAllObject
- becauseR.produce
serves the same purpose -
R.composed
- becauseR.piped
makes more sense, when we want to pass the input at the start of the function -
R.defaultToStrict
- confusing logic -
R.findInObject
- overestimated importance -
R.headObject
- overestimated importance -
R.includesType
- overestimated importance -
R.inject
- confusing logic -
R.isAttach
- confusing logic -
R.mergeRight
- overestimated importance -
R.opposite
- overestimated importance -
R.otherwise
- overestimated importance -
R.pushUniq
- overestimated importance -
R.resolve
- overestimated importance -
R.s
- overestimated importance -
R.toggle
- overestimated importance -
R.uuid
- not suitable -
R.whenAsync
- overestimated importance
Move the following methods to Rambda
and change their logic to match Ramda
implementation:
-
R.hasPath
-
R.unless
-
R.pathEq
-
R.tryCatch
-
R.where
-
R.whereEq
Also these changes:
-
R.flatMap
- renamed toR.chain
and moved toRambda
-
R.ifElseAsync
- accept any number of arguments for the returned function -
R.produce
,R.filterAsync
,R.debounce
,R.throttle
- fix typings -
R.mapAsyncLimit
- drop support for curring and therefore for usage withR.composeAsync
-
Improve
R.ok
throwed error message -
R.ok
returnsundefined
instead oftrue
when validation passes. -
R.mergeDeep
is renamed toR.mergeDeepLeft
-
Add
R.pipeAsync
-
Take
R.partialCurry
fromRambda
as it is deprecated there
3.7.0
Sync with Rambda
Add R.lens
Add R.lensIndex
Add R.lensPath
Add R.lensProp
Add R.over
Add R.set
Add R.view
Add R.paths
Add R.xor
Add R.cond
3.6.0
-
Add
R.mapAsyncLimit
-
Add
R.toggle
, match Ramda upcoming method specification -
Add
R.isValidAsync
-
Extend
R.template
without introducing breaking change
3.5.0 Sync with Rambda
- add methods descriptions to Typescript definitions
3.4.0 Sync with Rambda
and close Issue #42
3.3.0 Fix R.sortObject
typing
3.3.0 Add R.filterAsync
and R.sortObject
methods
3.2.0 R.uuid
accept second argument in order to return string only uuid
3.1.0 Dynamic set of exports lead to adding previously ommited Rambda exports such as R.identical
3.0.3 Sync with Rambda - new functionality of R.isEmpty
3.0.2 Add typings for R.mapToObject
3.0.1 Fix typings
3.0.0 Breaking change as Rambda
also has breaking changes
Read more about it in Rambda
changelog
Also with this versions, typings tests are provided and several definitions are changed.
-
R.anyTrue, R.anyFalse, R.allTrue, R.allFalse use internal
isTruthy
andisFalsy
methods. Empty array and object with zero length are considered falsy. -
Deprecate
R.contains
-
Deprecate
R.defaultToWhen
-
Moved
R.runTests
tohelpers
repo
2.17.0 Change in R.runTests
logic. It will be removed from Rambdax to helpers
repo.
2.16.0 Restore R.runTests
but without documentation
- export
getEvaluations
,getPositiveEvaluation
,getNegativeEvaluation
in the context ofR.runTests
2.15.0 Several changes
-
Typescript definitions have been updated and typings tests are introduced
-
R.mapAsync
andR.mapFastAsync
pass index as second argument
2.14.1 Restore R.contains
2.14.0 Several changes:
-
R.inject
accept before flag as fourth argument -
Remove
R.includesAny
-
Improve typing of
R.partition
-
R.nextIndex
andR.prevIndex
work also with number as second argument
2.13.1 Deprecate R.log
and R.runTests
2.12.3 Add 'dist' directory to files
2.12.2 Add R.mapToObject
typings
2.12.0 Sync with Rambda
2.11.1 Fix R.waitFor
2.11.0 Add R.toDecimal
2.10.2 Fix issue 32
2.10.0 deprecate R._
2.9.1 R.fromPairs/toPairs typing
2.9.0 npm doesn't update version on their site
2.8.2 R.map typing
2.8.0 Sync with Rambda | no need for create types script
2.7.0 Add R.prevIndex
2.6.2 Sync with Rambda
2.6.0 R.log
depends on RAMBDAX_LOG
2.5.0 Rambda's partial
2.4.0 Add R.uuid
2.3.0 R._
parse to constant case
This introduce breaking change for ie11 as noted in issue 31 which is fixed with
2.10.0
which deprecates this method
2.2.1 Add R.log
, R.logInit
and R.logHolder
2.1.0 Add R._
2.0.0 Add R.toggle
1.9.0 Add R.pushUniq
1.8.2 No need for sourcemaps
1.8.1 Fix building with regeneratorRuntime
1.8.0 Upgrade to new major Rollup release
-
Restore
R.headObject
-
Add
R.hasPath
method
1.7.2 R.memoize
contains dev console.logs
1.7.1 Forgot to build types
1.7.0 Rename R.then
to R.resolve
because of Ramda issue with R.then
(they rename it to R.andThen
)
- Add
R.isFalsy
,R.nextIndex
andR.mergeDeep
1.6.3 Forgot to export R.unless
(credit to @mobily for the PR)
1.6.0 Restore R.compact
method
1.5.6 R.maybe
accepts also anonymous functions as second and third argument
1.5.5 Add R.maybe
method
- Fix errors caugth by
DeepScan
service - Fix Typescript definitions for
R.then
andR.otherwise
-
R.change
increase nesting level to 4
1.4.1 R.isValid
didn't work with Number
prototype
1.4.0 Add multiple methods
-
Add
R.defaultToStrict
-
Add
R.defaultToWhen
-
Add
R.whereEq
-
Add
R.partition
-
Add
R.negate
is renamed toR.opposite
-
Add
R.then
-
Add
R.otherwise
-
R.isValid
accepts prototypes as rules, i.e.schema = {a: String}
-
The prevoious point leads to the same change applied to the methods depending on
R.isValid
, i.e.R.ok
,R.pass
andR.isAttach
1.3.0 Add
R.unless
-
R.when
accepts both function and value forwhenTrue
argument. The same is valid forR.unless
-
export
R.negate
which is the same asR.complement
1.2.0 Export
src
folder1.1.0 Restore
promiseAllObject
andflatMap
1.0.1 Fix typings
1.0.0 Deprecate the following methods:
-
compact
-
evolve
-
flatMap
-
greater
-
intersection
-
less
-
omitBy
-
pickBy
-
promiseAllObject
-
promiseAllSecure
-
rangeBy
Also pass deprecation of
addIndex
from[email protected]
0.24.0 add R.pipedAsync
, replace R.multiline
with R.glue
, remove R.validate
0.23.0 Add R.count
0.22.0 Add R.includesAny
0.21.0 Add R.includesType
0.20.1 R.pass
and R.ok
work with single schema.
0.20.0 Add R.pathEq
0.19.0 Add R.wait
, expose already complete R.waitFor
0.18.0 AddR.anyType
and R.allType
0.17.0 Rename R.is
to R.pass
and restore R.is
original functionality.
0.16.0 getter, setter, reset methods
0.15.3 No more prepublish
script
0.15.2 curry in remove
Last version with
lib
folder exposed
❯ Additional info
Most influential contributors
-
@farwayer - improving performance in R.find, R.filter; give the idea how to make benchmarks more reliable;
-
@thejohnfreeman - add R.assoc, R.chain;
-
@helmuthdu - add R.clone; help improve code style;
-
@jpgorman - add R.zip, R.reject, R.without, R.addIndex;
-
@ku8ar - add R.slice, R.propOr, R.identical, R.propIs and several math related methods; introduce the idea to display missing Ramda methods;
-
@romgrk - add R.groupBy, R.indexBy, R.findLast, R.findLastIndex;
-
@squidfunk - add R.assocPath, R.symmetricDifference, R.difference, R.intersperse;
-
@synthet1c - add all lenses methods; add R.applySpec, R.converge;
-
@vlad-zhukov - help with configuring Rollup, Babel; change export file to use ES module exports;
Rambda references
Links to Rambda
-
[https://mailchi.mp/webtoolsweekly/web-tools-280](Web Tools Weekly)
-
https://github.com/stoeffel/awesome-fp-js
-
https://github.com/docsifyjs/awesome-docsify
Deprecated from
Used by
section
-
SAP's Cloud SDK - This repo doesn't uses
Rambda
since October/2020 commit that removes Rambda
Releases
Rambda's releases before 6.4.0 were used mostly for testing purposes.
My other libraries
Niketa themeCollection of 9 light VSCode themes |
Niketa dark themeCollection of 9 dark VSCode themes |
String-fnString utility library |
Useful Javascript librariesLarge collection of JavaScript,Typescript and Angular related repos links |
Run-fnCLI commands for lint JS/TS files, commit git changes and upgrade of dependencies |