10.0.0-alpha.0 • Published 3 months ago

rambda v10.0.0-alpha.0

Weekly downloads
18,439
License
MIT
Repository
github
Last release
3 months ago

Rambda

Rambda is TypeScript-focused alternative to the popular functional programming library Ramda alternative. It also has better speed and smaller size. - Documentation

Commit activity Library size install size PR's Welcome GitHub contributors

❯ Example use

import { piped, map, filter } from 'rambda'

const result = piped(
	[1, 2, 3, 4],
  filter(x => x > 2),
  map(x => x * 2),
)
// => [6, 8]

You can test this example in Rambda's REPL

---------------

❯ Rambda'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.

undefined

Understandable source code due to little usage of internals

Ramda uses a lot of internals, which hides a lot of logic. Reading the full source code of a method can be challenging.

Better VSCode experience

If the project is written in Javascript, then go to source definition action will lead you to actual implementation of the method.

Immutable TS definitions

You can use immutable version of Rambda definitions, which is linted with ESLint functional/prefer-readonly-type plugin.

import {add} from 'rambda/immutable'

Deno support

Latest version of Ramba available for Deno users is 3 years old. This is not the case with Rambda as most of recent releases are available for Deno users.

Also, Rambda provides you with included TS definitions:

// Deno extension(https://marketplace.visualstudio.com/items?itemName=denoland.vscode-deno)
// is installed and initialized
import * as R from "https://deno.land/x/rambda/mod.ts";
import * as Ramda from "https://deno.land/x/ramda/mod.ts";

R.add(1)('foo') // => will trigger warning in VSCode as it should
Ramda.add(1)('foo') // => will not trigger warning in VSCode

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} })

Please note that since path input is turned into array, i.e. if you want R.path(['a','1', 'b'], {a: {'1': {b: 2}}}) to return 2, you will have to pass array path, not string path. If you pass a.1.b, it will turn path input to ['a', 1, 'b']. The other side effect is in R.assocPath and R.dissocPath, where inputs such as ['a', '1', 'b'] will be turned into ['a', 1, 'b'].

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

Speed

Rambda is generally more performant than Ramda as the benchmarks can prove that.

Support

One of the main issues with Ramda is the slow process of releasing new versions. This is not the case with Rambda as releases are made on regular basis.

---------------

❯ Install

  • yarn add rambda

  • For UMD usage either use ./dist/rambda.umd.js or the following CDN link:

https://unpkg.com/rambda@CURRENT_VERSION/dist/rambda.umd.js
  • with deno
import {add} from "https://deno.land/x/rambda/mod.ts";

---------------

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 or undefined), 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.

{{suggestPR}} ---------------

Benchmarks

TODO

API

add

It adds a and b.

const result = R.pipe(
	2,
	R.add(3)
) // =>  5

Try this R.add example in Rambda REPL

---------------

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.pipe(
	list,
	R.all(predicate)
) // => true

Try this R.all example in Rambda REPL

all<T>(predicate: (x: T) => boolean): (list: T[]) => boolean;
export function all(predicate) {
  return list => {
    for (let i = 0; i < list.length; i++) {
      if (!predicate(list[i])) {
        return false
      }
    }

    return true
  }
}
import { all } from './all.js'

const list = [0, 1, 2, 3, 4]

test('when true', () => {
  const fn = x => x > -1

  expect(all(fn)(list)).toBeTruthy()
})

test('when false', () => {
  const fn = x => x > 2

  expect(all(fn)(list)).toBeFalsy()
})
import * as R from 'rambda'

describe('all', () => {
  it('happy', () => {
    const result = R.pipe(
      [1, 2, 3],
      R.all(x => {
        x // $ExpectType number
        return x > 0
      }),
    )
    result // $ExpectType boolean
  })
})

---------------

allPass

allPass<F extends (...args: any[]) => boolean>(predicates: readonly F[]): F

It returns true, if all functions of predicates return true, when input is their argument.

const list = [[1, 2, 3, 4], [3, 4, 5]]
const result = R.pipe(
	list,
	R.filter(R.allPass([R.includes(2), R.includes(3)]))
) // => [[1, 2, 3, 4]]

Try this R.allPass example in Rambda REPL

allPass<F extends (...args: any[]) => boolean>(predicates: readonly F[]): F;
export function allPass(predicates) {
  return input => {
    let counter = 0
    while (counter < predicates.length) {
      if (!predicates[counter](input)) {
        return false
      }
      counter++
    }

    return true
  }
}
import { pipe } from './pipe.js'
import { filter } from './filter.js'
import { includes } from './includes.js'
import { allPass } from './allPass.js'

const list = [
  [1, 2, 3, 4],
  [3, 4, 5],
]
test('happy', () => {
  const result = pipe(list, filter(allPass([includes(2), includes(3)])))
  expect(result).toEqual([[1, 2, 3, 4]])
})

test('when returns false', () => {
  const result = pipe(list, filter(allPass([includes(12), includes(31)])))
  expect(result).toEqual([])
})
import * as R from 'rambda'

describe('allPass', () => {
  it('happy', () => {
    const list = [
      [1, 2, 3, 4],
      [3, 4, 5],
    ]
    const result = R.pipe(list, R.map(R.allPass([R.includes(3), R.includes(4)])))
    result // $ExpectType boolean[]
  })
})

---------------

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

any<T>(predicate: (x: T) => boolean): (list: T[]) => boolean;
export function any(predicate) {
  return list => {
    let counter = 0
    while (counter < list.length) {
      if (predicate(list[counter], counter)) {
        return true
      }
      counter++
    }

    return false
  }
}
import { any } from './any.js'

const list = [1, 2, 3]

test('happy', () => {
  expect(any(x => x > 2)(list)).toBeTruthy()
})
import { any, pipe } from 'rambda'

it('R.any', () => {
	let result= pipe(
		[1, 2, 3],
		any(x => {
			x // $ExpectType number
			return x > 2
		})
	)
	result // $ExpectType boolean
	})

---------------

anyPass

anyPass<T, TF1 extends T, TF2 extends T>(
  predicates: [(a: T) => a is TF1, (a: T) => a is TF2],
): (a: T) => a is TF1 | TF2

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

anyPass<T, TF1 extends T, TF2 extends T>(
  predicates: [(a: T) => a is TF1, (a: T) => a is TF2],
): (a: T) => a is TF1 | TF2;
anyPass<T, TF1 extends T, TF2 extends T, TF3 extends T>(
  predicates: [(a: T) => a is TF1, (a: T) => a is TF2, (a: T) => a is TF3],
): (a: T) => a is TF1 | TF2 | TF3;
anyPass<T, TF1 extends T, TF2 extends T, TF3 extends T>(
  predicates: [(a: T) => a is TF1, (a: T) => a is TF2, (a: T) => a is TF3],
): (a: T) => a is TF1 | TF2 | TF3;
anyPass<T, TF1 extends T, TF2 extends T, TF3 extends T, TF4 extends T>(
  predicates: [(a: T) => a is TF1, (a: T) => a is TF2, (a: T) => a is TF3, (a: T) => a is TF4],
): (a: T) => a is TF1 | TF2 | TF3 | TF4;
anyPass<T, TF1 extends T, TF2 extends T, TF3 extends T, TF4 extends T, TF5 extends T>(
  predicates: [
    (a: T) => a is TF1,
    (a: T) => a is TF2,
    (a: T) => a is TF3,
    (a: T) => a is TF4,
    (a: T) => a is TF5
  ],
): (a: T) => a is TF1 | TF2 | TF3 | TF4 | TF5;
anyPass<T, TF1 extends T, TF2 extends T, TF3 extends T, TF4 extends T, TF5 extends T, TF6 extends T>(
  predicates: [
    (a: T) => a is TF1,
    (a: T) => a is TF2,
    (a: T) => a is TF3,
    (a: T) => a is TF4,
    (a: T) => a is TF5,
    (a: T) => a is TF6
  ],
): (a: T) => a is TF1 | TF2 | TF3 | TF4 | TF5 | TF6;
anyPass<F extends (...args: any[]) => boolean>(predicates: readonly F[]): F;
export function anyPass(predicates) {
  return input => {
    let counter = 0
    while (counter < predicates.length) {
      if (predicates[counter](input)) {
        return true
      }
      counter++
    }

    return false
  }
}
import { anyPass } from './anyPass.js'

test('happy', () => {
  const rules = [x => typeof x === 'string', x => x > 10]
  const predicate = anyPass(rules)
  expect(predicate('foo')).toBeTruthy()
  expect(predicate(6)).toBeFalsy()
})

test('happy', () => {
  const rules = [x => typeof x === 'string', x => x > 10]

  expect(anyPass(rules)(11)).toBeTruthy()
  expect(anyPass(rules)(undefined)).toBeFalsy()
})

const obj = {
  a: 1,
  b: 2,
}

test('when returns true', () => {
  const conditionArr = [val => val.a === 1, val => val.a === 2]

  expect(anyPass(conditionArr)(obj)).toBeTruthy()
})

test('when returns false + curry', () => {
  const conditionArr = [val => val.a === 2, val => val.b === 3]

  expect(anyPass(conditionArr)(obj)).toBeFalsy()
})

test('with empty predicates list', () => {
  expect(anyPass([])(3)).toBeFalsy()
})
import { anyPass, filter } from 'rambda'

describe('anyPass', () => {
  it('issue #604', () => {
    const plusEq = (w: number, x: number, y: number, z: number) => w + x === y + z
    const result = anyPass([plusEq])(3, 3, 3, 3)

    result // $ExpectType boolean
  })
  it('issue #642', () => {
    const isGreater = (num: number) => num > 5
    const pred = anyPass([isGreater])
    const xs = [0, 1, 2, 3]

    const filtered1 = filter(pred)(xs)
    filtered1 // $ExpectType number[]
    const filtered2 = xs.filter(pred)
    filtered2 // $ExpectType number[]
  })
  it('functions as a type guard', () => {
    const isString = (x: unknown): x is string => typeof x === 'string'
    const isNumber = (x: unknown): x is number => typeof x === 'number'
    const isBoolean = (x: unknown): x is boolean => typeof x === 'boolean'

    const isStringNumberOrBoolean = anyPass([isString, isNumber, isBoolean])

    const aValue: unknown = 1

    if (isStringNumberOrBoolean(aValue)) {
      aValue // $ExpectType string | number | boolean
    }
  })
})

---------------

append

append<T>(el: T): (list: T[]) => T[]

It adds element x at the end of iterable.

const x = 'foo'

const result = R.append(x, ['bar', 'baz'])
// => ['bar', 'baz', 'foo']

Try this R.append example in Rambda REPL

append<T>(el: T): (list: T[]) => T[];
append<T>(el: T): (list: readonly T[]) => T[];
import { cloneList } from './_internals/cloneList.js'

export function append(x) {
  return list=> {
		const clone = cloneList(list)
  clone.push(x)

  return clone
	}
}
import { append } from './append.js'

test('happy', () => {
  expect(append('tests')( ['write', 'more'])).toEqual(['write', 'more', 'tests'])
})

test('append to empty array', () => {
  expect(append('tests')([])).toEqual(['tests'])
})
import {pipe,append, prepend} from 'rambda'

const listOfNumbers = [1, 2, 3]

describe('R.append/R.prepend', () => {
	it('happy', () => {
	const result = pipe(
		listOfNumbers,
		append(4),
		prepend(0)
	)
	result // $ExpectType number[]
	})
	it('with object', () => {
	const result = pipe(
		[{a:1}],
		append({a:10}),
		prepend({a:20})
	)
	result // $ExpectType { a: number; }[]
	})
})

---------------

checkObjectWithSpec

checkObjectWithSpec<T>(spec: T): <U>(testObj: U) => boolean

It returns true if all each property in conditions returns true when applied to corresponding property in input object.

const condition = R.checkObjectWithSpec({
  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.checkObjectWithSpec example in Rambda REPL

checkObjectWithSpec<T>(spec: T): <U>(testObj: U) => boolean;
export function checkObjectWithSpec(conditions) {
  return input => {
    let shouldProceed = true
    for (const prop in conditions) {
      if (!shouldProceed) {
        continue
      }
      const result = conditions[prop](input[prop])
      if (shouldProceed && result === false) {
        shouldProceed = false
      }
    }

    return shouldProceed
  }
}
import { checkObjectWithSpec } from './checkObjectWithSpec.js'
import { equals } from './equals.js'

test('when true', () => {
  const result = checkObjectWithSpec({
    a: equals('foo'),
    b: equals('bar'),
  })({
    a: 'foo',
    b: 'bar',
    x: 11,
    y: 19,
  })

  expect(result).toBeTruthy()
})

test('when false | early exit', () => {
  let counter = 0
  const equalsFn = expected => input => {
    counter++

    return input === expected
  }
  const predicate = checkObjectWithSpec({
    a: equalsFn('foo'),
    b: equalsFn('baz'),
  })
  expect(
    predicate({
      a: 'notfoo',
      b: 'notbar',
    }),
  ).toBeFalsy()
  expect(counter).toBe(1)
})
import { checkObjectWithSpec, equals } from 'rambda'

describe('R.checkObjectWithSpec', () => {
  it('happy', () => {
    const input = {
      a: 'foo',
      b: 'bar',
      x: 11,
      y: 19,
    }
    const conditions = {
      a: equals('foo'),
      b: equals('bar'),
    }
    const result = checkObjectWithSpec(conditions)(input)
    result // $ExpectType boolean
  })
})

---------------

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

---------------

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

---------------

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>(fn: (a: T) => string | number): (list: T[]) => { [index: 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

countBy<T>(fn: (a: T) => string | number): (list: T[]) => { [index: string]: number };
export function countBy(fn) {
	return list => {
  const willReturn = {}

  list.forEach(item => {
    const key = fn(item)
    if (!willReturn[key]) {
      willReturn[key] = 1
    } else {
      willReturn[key]++
    }
  })

  return willReturn
}
}
import { countBy } from './countBy.js'

const list = ['a', 'A', 'b', 'B', 'c', 'C']

test('happy', () => {
  const result = countBy(x => x.toLowerCase())(list)
  expect(result).toEqual({
    a: 2,
    b: 2,
    c: 2,
  })
})
import { countBy, pipe } from 'rambda'

const list = ['a', 'A', 'b', 'B', 'c', 'C']

it('R.countBy', () => {
	let result = pipe(
		list,
		countBy((x) => x.toLowerCase())
	)
	result.a // $ExpectType number
	result.foo // $ExpectType number
	result // $ExpectType { [index: string]: number; }
})

---------------

dec

It decrements a number.

const result = R.dec(2) // => 1

Try this R.dec example in Rambda REPL

---------------

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).

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

defaultTo<T>(defaultValue: T, input: T | null | undefined): T;
defaultTo<T>(defaultValue: T): <U>(input: U | null | undefined) => EqualTypes<U, T> extends true ? T : never
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
}
import { defaultTo } from './defaultTo.js'

test('with undefined', () => {
  expect(defaultTo('foo')(undefined)).toBe('foo')
})

test('with null', () => {
  expect(defaultTo('foo')(null)).toBe('foo')
})

test('with NaN', () => {
  expect(defaultTo('foo')(Number.NaN)).toBe('foo')
})

test('with empty string', () => {
  expect(defaultTo('foo', '')).toBe('')
})

test('with false', () => {
  expect(defaultTo('foo', false)).toBeFalsy()
})

test('when inputArgument passes initial check', () => {
  expect(defaultTo('foo', 'bar')).toBe('bar')
})
import { defaultTo } from 'rambda'

describe('R.defaultTo with Ramda spec', () => {
  it('happy', () => {
    const result = defaultTo('foo', '')
    result // $ExpectType "" | "foo"
  })
  it('with explicit type', () => {
    const result = defaultTo<string>('foo', null)
    result // $ExpectType string
  })
})

---------------

drop

drop<T>(howMany: number): (list: T[]) => T[]

It returns howMany items dropped from beginning of list or string input.

R.drop(2, ['foo', 'bar', 'baz']) // => ['baz']

Try this R.drop example in Rambda REPL

drop<T>(howMany: number): (list: T[]) => T[];
export function drop(howManyToDrop, listOrString) {
  if (arguments.length === 1) {
    return _list => drop(howManyToDrop, _list)
  }

  return listOrString.slice(howManyToDrop > 0 ? howManyToDrop : 0)
}
import assert from 'node:assert'

import { drop } from './drop.js'

test('with array', () => {
  expect(drop(2)(['foo', 'bar', 'baz'])).toEqual(['baz'])
  expect(drop(3, ['foo', 'bar', 'baz'])).toEqual([])
  expect(drop(4, ['foo', 'bar', 'baz'])).toEqual([])
})

test('with string', () => {
  expect(drop(3, 'rambda')).toBe('bda')
})

test('with non-positive count', () => {
  expect(drop(0, [1, 2, 3])).toEqual([1, 2, 3])
  expect(drop(-1, [1, 2, 3])).toEqual([1, 2, 3])
  expect(drop(Number.NEGATIVE_INFINITY, [1, 2, 3])).toEqual([1, 2, 3])
})

test('should return copy', () => {
  const xs = [1, 2, 3]

  assert.notStrictEqual(drop(0, xs), xs)
  assert.notStrictEqual(drop(-1, xs), xs)
})
import { drop, pipe } from 'rambda'

it('R.drop', () => {
		let result = pipe(
			[1, 2, 3, 4],
			drop(2)
		)
		result // $ExpectType number[]
})

---------------

dropLast

dropLast<T>(howMany: number): (list: T[]) => T[]

It returns howMany items dropped from the end of list or string input.

R.dropLast(2)(['foo', 'bar', 'baz']) // => ['foo']

Try this R.dropLast example in Rambda REPL

dropLast<T>(howMany: number): (list: T[]) => T[];
export function dropLast(numberItems) {
	return list => numberItems > 0
    ? list.slice(0, -numberItems)
    : list.slice()
}
import { dropLast } from './dropLast.js'

test('with array', () => {
  expect(dropLast(2)(['foo', 'bar', 'baz'])).toEqual(['foo'])
  expect(dropLast(3)( ['foo', 'bar', 'baz'])).toEqual([])
  expect(dropLast(4)(['foo', 'bar', 'baz'])).toEqual([])
})

test('with non-positive count', () => {
  expect(dropLast(0)([1, 2, 3])).toEqual([1, 2, 3])
  expect(dropLast(-1)( [1, 2, 3])).toEqual([1, 2, 3])
  expect(dropLast(Number.NEGATIVE_INFINITY)([1, 2, 3])).toEqual([1, 2, 3])
})

---------------

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

---------------

dropRepeatsBy

const result = R.dropRepeatsBy(
  Math.abs,
  [1, -1, 2, 3, -3]
)
// => [1, 2, 3]

Try this R.dropRepeatsBy example in Rambda REPL

---------------

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

---------------

eqBy

const result = R.eqBy(Math.abs, 5)(-5)
// => true

Try this R.eqBy example in Rambda REPL

---------------

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.

R.equals(
  [1, {a:2}, [{b: 3}]],
  [1, {a:2}, [{b: 3}]]
) // => true

Try this R.equals example in Rambda REPL

equals<T>(x: T, y: T): boolean;
equals<T>(x: T): (y: T) => boolean;
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 (!['Array', 'NaN', 'Object', 'RegExp'].includes(typeOfValue)) {
    return list.lastIndexOf(valueToFind)
  }

  const { length } = list
  let index = length
  let foundIndex = -1

  while (--index > -1 && foundIndex === -1) {
    if (equalsFn(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 (!['Array', 'NaN', 'Object', 'RegExp'].includes(typeOfValue)) {
    return list.indexOf(valueToFind)
  }

  let index = -1
  let foundIndex = -1
  const { length } = list

  while (++index < length && foundIndex === -1) {
    if (equalsFn(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 _compareSets(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 compareErrors(a, b) {
  if (a.message !== b.message) {
    return false
  }
  if (a.toString !== b.toString) {
    return false
  }

  return a.toString() === b.toString()
}

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()]
}

export function equalsFn(a, b) {
	if (Object.is(a, b)) {
    return true
  }

  const aType = type(a)

  if (aType !== type(b)) {
    return false
  }
  if (aType === 'Function') {
    return a.name === undefined ? false : a.name === b.name
  }

  if (['NaN', 'Null', 'Undefined'].includes(aType)) {
    return true
  }

  if (['BigInt', 'Number'].includes(aType)) {
    if (Object.is(-0, a) !== Object.is(-0, b)) {
      return false
    }

    return a.toString() === b.toString()
  }

  if (['Boolean', 'String'].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] &&
          !equalsFn(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
  }
  if (bRegex[0]) {
    return false
  }

  const aDate = parseDate(a)
  const bDate = parseDate(b)

  if (aDate[0]) {
    return bDate[0] ? aDate[1] === bDate[1] : false
  }
  if (bDate[0]) {
    return false
  }

  if (a instanceof Error) {
    if (!(b instanceof Error)) {
      return false
    }

    return compareErrors(a, b)
  }

  if (aType === 'Set') {
    return _compareSets(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 && !equalsFn(aValue, bValue)) {
          loopObjectFlag = false
        }
      }
    })

    return loopObjectFlag
  }

  return false
}
export function equals(a) {
	return b => equalsFn(a, b)
}
import {equalsFn } from './equals.js'

test('compare functions', () => {
  function foo() {}
  function bar() {}
  const baz = () => {}

  const expectTrue = equalsFn(foo, foo)
  const expectFalseFirst = equalsFn(foo, bar)
  const expectFalseSecond = equalsFn(foo, baz)

  expect(expectTrue).toBeTruthy()
  expect(expectFalseFirst).toBeFalsy()
  expect(expectFalseSecond).toBeFalsy()
})

test('with array of objects', () => {
  const list1 = [{ a: 1 }, [{ b: 2 }]]
  const list2 = [{ a: 1 }, [{ b: 2 }]]
  const list3 = [{ a: 1 }, [{ b: 3 }]]

  expect(equalsFn(list1, list2)).toBeTruthy()
  expect(equalsFn(list1, list3)).toBeFalsy()
})

test('with regex', () => {
  expect(equalsFn(/s/, /s/)).toBeTruthy()
  expect(equalsFn(/s/, /d/)).toBeFalsy()
  expect(equalsFn(/a/gi, /a/gi)).toBeTruthy()
  expect(equalsFn(/a/gim, /a/gim)).toBeTruthy()
  expect(equalsFn(/a/gi, /a/i)).toBeFalsy()
})

test('not a number', () => {
  expect(equalsFn([Number.NaN], [Number.NaN])).toBeTruthy()
})

test('new number', () => {
  expect(equalsFn(new Number(0), new Number(0))).toBeTruthy()
  expect(equalsFn(new Number(0), new Number(1))).toBeFalsy()
  expect(equalsFn(new Number(1), new Number(0))).toBeFalsy()
})

test('new string', () => {
  expect(equalsFn(new String(''), new String(''))).toBeTruthy()
  expect(equalsFn(new String(''), new String('x'))).toBeFalsy()
  expect(equalsFn(new String('x'), new String(''))).toBeFalsy()
  expect(equalsFn(new String('foo'), new String('foo'))).toBeTruthy()
  expect(equalsFn(new String('foo'), new String('bar'))).toBeFalsy()
  expect(equalsFn(new String('bar'), new String('foo'))).toBeFalsy()
})

test('new Boolean', () => {
  expect(equalsFn(new Boolean(true), new Boolean(true))).toBeTruthy()
  expect(equalsFn(new Boolean(false), new Boolean(false))).toBeTruthy()
  expect(equalsFn(new Boolean(true), new Boolean(false))).toBeFalsy()
  expect(equalsFn(new Boolean(false), new Boolean(true))).toBeFalsy()
})

test('new Error', () => {
  expect(equalsFn(new Error('XXX'), {})).toBeFalsy()
  expect(equalsFn(new Error('XXX'), new TypeError('XXX'))).toBeFalsy()
  expect(equalsFn(new Error('XXX'), new Error('YYY'))).toBeFalsy()
  expect(equalsFn(new Error('XXX'), new Error('XXX'))).toBeTruthy()
  expect(equalsFn(new Error('XXX'), new TypeError('YYY'))).toBeFalsy()
  expect(equalsFn(new Error('XXX'), new Error('XXX'))).toBeTruthy()
})

test('with dates', () => {
  expect(equalsFn(new Date(0), new Date(0))).toBeTruthy()
  expect(equalsFn(new Date(1), new Date(1))).toBeTruthy()
  expect(equalsFn(new Date(0), new Date(1))).toBeFalsy()
  expect(equalsFn(new Date(1), new Date(0))).toBeFalsy()
  expect(equalsFn(new Date(0), {})).toBeFalsy()
  expect(equalsFn({}, new Date(0))).toBeFalsy()
})

test('ramda spec', () => {
  expect(equalsFn({}, {})).toBeTruthy()

  expect(
    equalsFn(
      {
        a: 1,
        b: 2,
      },
      {
        a: 1,
        b: 2,
      },
    ),
  ).toBeTruthy()

  expect(
    equalsFn(
      {
        a: 2,
        b: 3,
      },
      {
        a: 2,
        b: 3,
      },
    ),
  ).toBeTruthy()

  expect(
    equalsFn(
      {
        a: 2,
        b: 3,
      },
      {
        a: 3,
        b: 3,
      },
    ),
  ).toBeFalsy()

  expect(
    equalsFn(
      {
        a: 2,
        b: 3,
        c: 1,
      },
      {
        a: 2,
        b: 3,
      },
    ),
  ).toBeFalsy()
})

test('works with boolean tuple', () => {
  expect(equalsFn([true, false], [true, false])).toBeTruthy()
  expect(equalsFn([true, false], [true, true])).toBeFalsy()
})

test('works with equal objects within array', () => {
  const objFirst = {
    a: {
      b: 1,
      c: 2,
      d: [1],
    },
  }
  const objSecond = {
    a: {
      b: 1,
      c: 2,
      d: [1],
    },
  }

  const x = [1, 2, objFirst, null, '', []]
  const y = [1, 2, objSecond, null, '', []]
  expect(equalsFn(x, y)).toBeTruthy()
})

test('works with different objects within array', () => {
  const objFirst = { a: { b: 1 } }
  const objSecond = { a: { b: 2 } }

  const x = [1, 2, objFirst, null, '', []]
  const y = [1, 2, objSecond, null, '', []]
  expect(equalsFn(x, y)).toBeFalsy()
})

test('works with undefined as second argument', () => {
  expect(equalsFn(1, undefined)).toBeFalsy()

  expect(equalsFn(undefined, undefined)).toBeTruthy()
})

test('compare sets', () => {
  const toCompareDifferent = new Set([{ a: 1 }, { a: 2 }])
  const toCompareSame = new Set([{ a: 1 }, { a: 2 }, { a: 1 }])
  const testSet = new Set([{ a: 1 }, { a: 2 }, { a: 1 }])
  expect(equalsFn(toCompareSame, testSet)).toBeTruthy()
  expect(equalsFn(toCompareDifferent, testSet)).toBeFalsy()
})

test('compare simple sets', () => {
  const testSet = new Set(['2', '3', '3', '2', '1'])
  expect(equalsFn(new Set(['3', '2', '1']), testSet)).toBeTruthy()
  expect(equalsFn(new Set(['3', '2', '0']), testSet)).toBeFalsy()
})

test('various examples', () => {
  expect(equalsFn([1, 2, 3],[1, 2, 3])).toBeTruthy()
  expect(equalsFn([1, 2, 3],[1, 2])).toBeFalsy()
  expect(equalsFn({},{})).toBeTruthy()
})
import { equals } from 'rambda'

describe('R.equals', () => {
  it('happy', () => {
    const result = equals(4, 1)
    result // $ExpectType boolean
  })
  it('with object', () => {
    const foo = { a: 1 }
    const bar = { a: 2 }
    const result = equals(foo, bar)
    result // $ExpectType boolean
  })
  it('curried', () => {
    const result = equals(4)(1)

    result // $ExpectType boolean
  })
})

---------------

evolve

evolve<E extends Evolver>(rules: E): <V extends Evolvable<E>>(obj: V) => Evolve<V, E>

It takes object of functions as set of rules. These rules are applied to the iterable input to produce the result.

const rules = {
  foo : add(1),
  bar : add(-1),
}
const input = {
  a   : 1,
  foo : 2,
  bar : 3,
}
const result = R.evolve(rules)(input)
const expected = {
  a   : 1,
  foo : 3,
  bar : 2,
})
// => `result` is equal to `expected`

Try this R.evolve example in Rambda REPL

evolve<E extends Evolver>(rules: E): <V extends Evolvable<E>>(obj: V) => Evolve<V, E>;
import { mapObject } from './mapObject.js'
import { type } from './type.js'

export function evolveFn(rules, obj) {
    return mapObject((x, prop) => {
      if (type(x) === 'Object') {
        const typeRule = type(rules[prop])
        if (typeRule === 'Function') {
          return rules[prop](x)
        }
        if (typeRule === 'Object') {
          return evolveFn(rules[prop], x)
        }

        return x
      }
      if (type(rules[prop]) === 'Function') {
        return rules[prop](x)
      }

      return x
    })(obj)
}

export function evolve(rules) {
  return obj =>	evolveFn(rules, obj)
		}
import { evolve } from './evolve.js'

let add = x => y => x + y

test('happy', () => {
  const rules = {
    foo: add(1),
    nested: { bar: x => Object.keys(x).length },
  }
  const input = {
    a: 1,
    foo: 2,
    nested: { bar: { z: 3 } },
  }
  const result = evolve(rules)(input)
  expect(result).toEqual({
    a: 1,
    foo: 3,
    nested: { bar: 1 },
  })
})

test('nested rule is wrong', () => {
  const rules = {
    foo: add(1),
    nested: { bar: 10 },
  }
  const input = {
    a: 1,
    foo: 2,
    nested: { bar: { z: 3 } },
  }
  const result = evolve(rules)(input)
  expect(result).toEqual({
    a: 1,
    foo: 3,
    nested: { bar: { z: 3 } },
  })
})

test('is recursive', () => {
  const rules = {
    nested: {
      second: add(-1),
      third: add(1),
    },
  }
  const object = {
    first: 1,
    nested: {
      second: 2,
      third: 3,
    },
  }
  const expected = {
    first: 1,
    nested: {
      second: 1,
      third: 4,
    },
  }
  const result = evolve(rules)(object)
  expect(result).toEqual(expected)
})

test('ignores primitive values', () => {
  const rules = {
    n: 2,
    m: 'foo',
  }
  const object = {
    n: 0,
    m: 1,
  }
  const expected = {
    n: 0,
    m: 1,
  }
  const result = evolve(rules)(object)
  expect(result).toEqual(expected)
})
import { add, evolve, pipe } from 'rambda'

it('R.evolve', () => {
    const input = {
      foo: 2,
      nested: {
        a: 1,
        bar: 3,
      },
    }
    const rules = {
      foo: add(1),
      nested: {
        a: add(-1),
        bar: add(1),
      },
    }
    const result = pipe(
			input,
			evolve(rules)
		)
    result.nested.a // $ExpectType number
    result.nested.bar // $ExpectType number
    result.foo // $ExpectType number
})

---------------

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

---------------

filter

filter<T, S extends T>(
  predicate: (value: T) => value is S,
): (list: T[]) => S[]

It filters list or object input using a predicate function.

const predicate = x => x > 1
const list = [1, 2, 3]
const result = R.filter(predicate)(list)
// => [2, 3]

Try this R.filter example in Rambda REPL

filter<T, S extends T>(
  predicate: (value: T) => value is S,
): (list: T[]) => S[];
filter<T>(
	predicate: BooleanConstructor,
): (list: readonly T[]) => NonNullable<T>[];
filter<T>(
	predicate: BooleanConstructor,
): (list: T[]) => NonNullable<T>[];
filter<T>(
	predicate: (value: T) => boolean,
): (list: T[]) => T[];
export function filter(predicate) {
	return list => {
  if (!list) {
    throw new Error('Incorrect iterable input')
  }
	let index = 0
  const len = list.length
  const willReturn = []

  while (index < len) {
    if (predicate(list[index], index)) {
      willReturn.push(list[index])
    }

    index++
  }
	
  return willReturn
	}
}
import { filter } from './filter.js'

test('happy', () => {
  const isEven = n => n % 2 === 0

  expect(filter(isEven)([1, 2, 3, 4])).toEqual([2, 4])
})
import { filter, map, pipe } from 'rambda'

const list = [1, 2, 3]

describe('R.filter with array', () => {
  it('within pipe', () => {
    const result = pipe(
      list,
      filter(x => {
        x // $ExpectType number
        return x > 1
      }),
    )
    result // $ExpectType number[]
  })
  it('narrowing type', () => {
    interface Foo {
      a: number
    }
    interface Bar extends Foo {
      b: string
    }

    const testList = [{ a: 1 }, { a: 2 }, { a: 3 }]
    const filterBar = (x: unknown): x is Bar => {
      return typeof (x as Bar).b === 'string'
    }
    const result = pipe(
      testList,
      map((x, i) => {
        return { a: x.a, b: `${i}` }
      }),
      filter(filterBar),
    )
    result // $ExpectType Bar[]
  })
  it('narrowing type - readonly', () => {
    interface Foo {
      a: number
    }
    interface Bar extends Foo {
      b: string
    }

    const testList = [{ a: 1 }, { a: 2 }, { a: 3 }] as const
    const filterBar = (x: unknown): x is Bar => {
      return typeof (x as Bar).b === 'string'
    }
    const result = pipe(
      testList,
      map((x, i) => {
        return { a: x.a, b: `${i}` }
      }),
      filter(filterBar),
    )
    result // $ExpectType Bar[]
  })
  it('filtering NonNullable', () => {
    const testList = [1, 2, null, undefined, 3]
    const result = pipe(testList, filter(Boolean))
    result // $ExpectType number[]
  })
  it('filtering NonNullable - readonly', () => {
    const testList = [1, 2, null, undefined, 3] as const
    const result = pipe(testList, filter(Boolean))
    result // $ExpectType NonNullable<1 | 2 | 3 | null | undefined>[]
    // @ts-expect-error
    result.includes(null)
  })
})

---------------

filterObject

filterObject<T extends object>(
  valueMapper: (
    value: EnumerableStringKeyedValueOf<T>,
    key: EnumerableStringKeyOf<T>,
    data: T,
  ) => boolean,
): <U extends T>(data: T) => U

It loops over each property of obj and returns a new object with only those properties that satisfy the predicate.

const result = R.filterObject(
	(val, prop) => prop === 'a' || val > 1
)({a: 1, b: 2, c:3})
// => {a: 1, c: 3}

Try this R.filterObject example in Rambda REPL

filterObject<T extends object>(
  valueMapper: (
    value: EnumerableStringKeyedValueOf<T>,
    key: EnumerableStringKeyOf<T>,
    data: T,
  ) => boolean,
): <U extends T>(data: T) => U;
export function filterObject(predicate) {
  return obj => {
    const willReturn = {}

    for (const prop in obj) {
      if (predicate(obj[prop], prop, obj)) {
        willReturn[prop] = obj[prop]
      }
    }

    return willReturn
  }
}
import { filterObject, pipe } from 'rambda'

describe('R.filterObject', () => {
  it('require explicit type', () => {
    const result = pipe(
      { a: 1, b: 2 },
      filterObject<{ b: number }>(a => {
        a // $ExpectType number
        return a > 1
      }),
    )
    result.b // $ExpectType number
  })
})

---------------

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

find<T>(predicate: (x: T) => boolean): (list: T[]) => T | undefined;
export function find(predicate) {
	return list => {
  let index = 0
  const len = list.length

  while (index < len) {
    const x = list[index]
    if (predicate(x)) {
      return x
    }

    index++
  }
}
}
import { find } from './find.js'
import { propEq } from './propEq.js'

const list = [{ a: 1 }, { a: 2 }, { a: 3 }]

test('happy', () => {
  const fn = propEq(2, 'a')
  expect(find(fn)(list)).toEqual({ a: 2 })
})

test('with curry', () => {
  const fn = propEq(4, 'a')
  expect(find(fn)(list)).toBeUndefined()
})

test('with empty list', () => {
  expect(find(() => true)([])).toBeUndefined()
})
import { find, pipe } from 'rambda'

const list = [1, 2, 3]

describe('R.find', () => {
  it('happy', () => {
    const predicate = (x: number) => x > 2
		let result = pipe(
			list,
			find(predicate)
		)
		result // $ExpectType number | undefined
  })
})

---------------

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

findIndex<T>(predicate: (x: T) => boolean): (list: T[]) => number;
export function findIndex(predicate) {
	return list => {
  const len = list.length
  let index = -1

  while (++index < len) {
    if (predicate(list[index])) {
      return index
    }
  }

  return -1
}
}
import { findIndex } from './findIndex.js'
import { propEq } from './propEq.js'

const list = [{ a: 1 }, { a: 2 }, { a: 3 }]

test('happy', () => {
  expect(findIndex(propEq(2, 'a'))(list)).toBe(1)
  expect(findIndex(propEq(1, 'a'))(list)).toBe(0)
  expect(findIndex(propEq(4, 'a'))(list)).toBe(-1)
})
import { findIndex, pipe } from 'rambda'

const list = [1, 2, 3]

it('R.findIndex', () => {
	let result = pipe(
		list,
		findIndex(x => x > 2)
	)
	result // $ExpectType number
})

---------------

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

findLast<T>(fn: (x: T) => boolean): (list: T[]) => T | undefined;
export function findLast(predicate) {
	return 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

findLastIndex<T>(predicate: (x: T) => boolean): (list: T[]) => number;
export function findLastIndex(fn) {
	return list => {
  let index = list.length

  while (--index >= 0) {
    if (fn(list[index])) {
      return index
    }
  }

  return -1
}
}
import { findLastIndex } from './findLastIndex.js'

test('happy', () => {
  const result = findLastIndex(x => x > 1)([1, 1, 1, 2, 3, 4, 1])
  expect(result).toBe(5)
  expect(findLastIndex(x => x === 0)([0, 1, 1, 2, 3, 4, 1])).toBe(0)
})
import { findLastIndex, pipe } from 'rambda'

const list = [1, 2, 3]

describe('R.findLastIndex', () => {
  it('happy', () => {
    const predicate = (x: number) => x > 2
    const result = pipe(
			list,
			findLastIndex(predicate)
		)
		result // $ExpectType number
  })
})

---------------

flatMap

flatMap<T, U extends unknown>(transformFn: (x: T extends any[] ? T[number]: never) => U): (listOfLists: T[]) => U[]

It maps fn over list and then flatten the result by one-level.

const duplicate = n => [ n, n ]
const list = [ 1, 2, 3 ]

const result = R.flatMap(duplicate, list)
// => [ 1, 1, 2, 2, 3, 3 ]

Try this R.flatMap example in Rambda REPL

flatMap<T, U extends unknown>(transformFn: (x: T extends any[] ? T[number]: never) => U): (listOfLists: T[]) => U[];
export function flatMap(
chrome-headlessdo-fn@mrmld/utilsreact-mindee@comparaonlineprivate/quote-lib@comparaonline/quote-lib@mindee/react-web-essentials@mrmld/m-utilsnassetsupdate-propertygoogle-serpvideopass-ctmsreact-notificatorselfrefactorserp-helperserp-rescraperprotractor-nightmarereddit-voterjustdonightmare-helper@everything-registry/sub-chunk-2524svelte-typewriter-transitionsvelte-store-routerswaggernautwhat-figure-drawn-game-cliweb-toolkitwq2spinner-memory-game-clispecimen02testcafe-browser-provider-crossbrowsertesting-updatedvalor-framework-mobxvalor-hooksvalor-prosemirror-editorvalor-random-uivalor-sheetvalor-sheet-pro@ditto-network/core@csound/browser@csu-ims/ims-frontend-core@czisis/pgconv@callumtw42/utils@callumtw42/vue-charts@callumtw42/toolkit@rpg-village/coreeslint-config-rel1cxitu-utilsjson-validityjscodeshift-adaptersjsnixkeyv-cached-withlanguinelaradasolid-base-componentsuber-lensts-actorstypescript-essential-pluginstrader.tstrappertweets-to-json@arn4v/meerkat@authentik8/es-eventstore@authentik8/event-sourcing-kit@agentin/stan@axelarjs/api@axelarjs/ui@bett3r-dev/server-http@bett3r-dev/server-utils@bett3r-dev/server-watermark@digital-ai/devops-page-object-deployyapi2interfacewatch-fnwebpack-tsunused-packages@greenbot/cli@iamfk/react-agrid@emigrad/announce@logfire-sh/koa@logtail/koa@leviafan/boilerplate@lewis-campbell/dmt@eredzik/generic-typed-admin@mindee/web-elements@miyauci/vue-data-table@miyauci/data-table-core@module-federation/native-federation-typescript@module-federation/dev-kit@module-federation/dts-kit@module-federation/dts-plugin@module-federation/native-federation-tests@iwatakeshi/apollo-next@kibeo/mst-decorators@hieuquang2212/form@prismify/ko@ps-aux/api-client-axios@ps-aux/api-client-common@ps-aux/nclif@r26d/absinthe-apollo-link@sap/cloud-sdk-core@sap/cloud-sdk-generator@sap/cloud-sdk-util
9.3.0

10 months ago

9.4.2

5 months ago

9.4.1

6 months ago

9.4.0

7 months ago

10.0.0-alpha.0

3 months ago

9.2.1

12 months ago

9.2.0

1 year ago

9.1.1

1 year ago

9.1.0

1 year ago

9.0.1

1 year ago

9.0.0

1 year ago

8.5.0

2 years ago

8.6.0

2 years ago

8.4.0

2 years ago

8.1.0

2 years ago

8.2.0

2 years ago

8.3.0

2 years ago

8.0.0

2 years ago

7.5.0

2 years ago

7.4.0

3 years ago

7.3.0

3 years ago

7.2.1

3 years ago

7.2.0

3 years ago

7.1.4

3 years ago

7.1.3

3 years ago

7.1.2

3 years ago

7.1.1

3 years ago

7.1.0

3 years ago

7.0.0

3 years ago

7.0.3

3 years ago

7.0.2

3 years ago

7.0.1

3 years ago

6.9.0

4 years ago

6.8.3

4 years ago

6.8.1

4 years ago

6.8.0

4 years ago

6.8.2

4 years ago

6.6.0

4 years ago

6.7.0

4 years ago

6.7.0-beta.0

4 years ago

6.5.3

4 years ago

6.5.2

4 years ago

6.5.0

4 years ago

6.5.1

4 years ago

6.4.0

5 years ago

6.3.1

5 years ago

6.3.0

5 years ago

6.2.0

5 years ago

6.1.0

5 years ago

6.0.1

5 years ago

6.0.0

5 years ago

5.13.1

5 years ago

5.13.0

5 years ago

5.12.1

5 years ago

5.12.0

5 years ago

5.11.0

5 years ago

5.10.0

5 years ago

5.9.0

5 years ago

5.8.0

5 years ago

5.7.0

5 years ago

5.6.3

5 years ago

5.6.2

5 years ago

5.6.1

5 years ago

5.6.0

5 years ago

5.5.0

5 years ago

5.4.3

5 years ago

5.4.2

5 years ago

5.4.1

5 years ago

5.3.0

5 years ago

5.4.0

5 years ago

5.2.1

5 years ago

5.2.0

5 years ago

5.1.1

5 years ago

5.1.0

5 years ago

5.0.0

5 years ago

4.6.0

5 years ago

4.5.0

5 years ago

4.4.0

6 years ago

4.3.0

6 years ago

4.2.0

6 years ago

4.1.0

6 years ago

4.0.2

6 years ago

4.0.1

6 years ago

4.0.0

6 years ago

3.3.0

6 years ago

3.2.5

6 years ago

3.2.1

6 years ago

3.2.0

6 years ago

3.1.1

6 years ago

3.1.0

6 years ago

3.0.1

6 years ago

3.0.0

6 years ago

2.14.5

6 years ago

2.14.4

6 years ago

2.14.3

6 years ago

2.14.2

6 years ago

2.14.1

6 years ago

2.14.0

6 years ago

2.13.1

6 years ago

2.13.0

6 years ago

2.12.0

6 years ago

2.11.2

6 years ago

2.11.1

6 years ago

2.11.0

6 years ago

2.10.2

6 years ago

2.10.1

6 years ago

2.10.0

6 years ago

2.9.0

6 years ago

2.8.0

6 years ago

2.7.1

6 years ago

2.7.0

6 years ago

2.6.0

6 years ago

2.5.0

6 years ago

2.4.1

6 years ago

2.4.0

6 years ago

2.3.2

6 years ago

2.3.1

6 years ago

2.3.0

6 years ago

2.2.0

6 years ago

2.1.1

7 years ago

2.1.0

7 years ago

2.0.0

7 years ago

1.2.6

7 years ago

1.2.5

7 years ago

1.2.4

7 years ago

1.2.2

7 years ago

1.2.1

7 years ago

1.2.0

7 years ago

1.1.5

7 years ago

1.1.4

7 years ago

1.1.3

7 years ago

1.1.2

7 years ago

1.1.1

7 years ago

1.1.0

7 years ago

1.0.13

7 years ago

1.0.12

7 years ago

1.0.11

7 years ago

1.0.10

7 years ago

1.0.9

7 years ago

1.0.8

7 years ago

1.0.7

7 years ago

1.0.6

8 years ago

1.0.5

8 years ago

1.0.4

8 years ago

1.0.3

8 years ago

1.0.0

8 years ago

0.9.8

8 years ago

0.9.7

8 years ago

0.9.6

8 years ago

0.9.5

8 years ago

0.9.4

8 years ago

0.9.3

8 years ago

0.9.2

8 years ago

0.9.1

8 years ago

0.8.10

8 years ago

0.9.0

8 years ago

0.8.9

8 years ago

0.8.8

8 years ago

0.8.7

8 years ago

0.8.6

8 years ago

0.8.5

8 years ago

0.8.4

8 years ago

0.8.3

8 years ago

0.8.2

8 years ago

0.8.1

8 years ago

0.8.0

8 years ago

0.7.6

8 years ago

0.7.5

8 years ago

0.7.4

8 years ago

0.7.3

8 years ago

0.7.2

8 years ago

0.7.1

8 years ago

0.7.0

8 years ago

0.6.1

8 years ago

0.5.13

8 years ago

0.6.0

8 years ago

0.5.12

8 years ago

0.5.11

8 years ago

0.5.10

8 years ago

0.5.9

8 years ago

0.5.8

8 years ago

0.5.7

8 years ago

0.5.6

8 years ago

0.5.5

8 years ago

0.5.4

8 years ago

0.5.3

8 years ago

0.5.2

8 years ago

0.5.1

8 years ago

0.5.0

8 years ago

0.4.3

8 years ago

0.4.2

8 years ago

0.4.1

8 years ago

0.4.0

8 years ago

0.3.4

8 years ago

0.3.3

8 years ago

0.3.2

8 years ago

0.3.1

8 years ago

0.3.0

8 years ago

0.2.1

8 years ago

0.2.0

8 years ago

0.1.5

8 years ago

0.1.4

8 years ago

0.1.3

8 years ago

0.1.2

8 years ago

0.1.1

8 years ago

0.1.0

8 years ago