diff --git a/.github/README.md b/.github/README.md index 51213bd6..c6839e82 100644 --- a/.github/README.md +++ b/.github/README.md @@ -96,15 +96,10 @@ Closing the issue is usually accompanied by publishing a new patch version of `R
- Click to see the full list of 72 Ramda methods not implemented in Rambda + Click to see the full list of 67 Ramda methods not implemented in Rambda - __ -- binary -- call -- collectBy -- comparator -- composeWith - construct - constructN - dissocPath @@ -2120,6 +2115,10 @@ describe('R.assocPath - curried', () => { [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#assocPath) +### binary + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#binary) + ### bind ```typescript @@ -2450,6 +2449,10 @@ describe('R.both', () => { [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#both) +### call + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#call) + ### chain ```typescript @@ -2615,6 +2618,14 @@ It creates a deep copy of the `input`, which may contain (nested) Arrays and Obj [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#clone) +### collectBy + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#collectBy) + +### comparator + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#comparator) + ### complement It returns `inverted` version of `origin` function that accept `input` as argument. @@ -2633,6 +2644,10 @@ It performs right-to-left function composition. [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#compose) +### composeWith + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#composeWith) + ### concat It returns a new string or array, which is the result of merging `x` and `y`. @@ -12625,7 +12640,7 @@ describe('R.product', () => { ```typescript -prop

(propToFind: P, value: T): Prop +prop<_, P extends keyof never, T>(p: P, value: T): Prop ``` It returns the value of property `propToFind` in `obj`. @@ -12647,17 +12662,10 @@ const result = [

All TypeScript definitions ```typescript -prop

(propToFind: P, value: T): Prop; -prop

(propToFind: P): { - (value: Record): T; - (value: T): Prop; -}; -prop

(propToFind: P): { - (value: T): Prop; -}; -prop

(propToFind: P): { - (value: Record): T; -}; +prop<_, P extends keyof never, T>(p: P, value: T): Prop; +prop(p: keyof never, value: unknown): V; +prop<_, P extends keyof never>(p: P): (value: T) => Prop; +prop(p: keyof never): (value: unknown) => V; ```

@@ -18579,6 +18587,16 @@ describe('R.zipWith', () => { ## ❯ CHANGELOG +8.3.0 + +Add the following methods: + +- binary +- call +- collectBy +- comparator +- composeWith + 8.2.0 Add the following methods: diff --git a/CHANGELOG.md b/CHANGELOG.md index e7dd40ff..a2a262ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +8.3.0 + +Add the following methods: + +- binary +- call +- collectBy +- comparator +- composeWith + 8.2.0 Add the following methods: diff --git a/NEXT_VERSION_CHECKLIST.md b/NEXT_VERSION_CHECKLIST.md index 77860ae1..33ac0797 100644 --- a/NEXT_VERSION_CHECKLIST.md +++ b/NEXT_VERSION_CHECKLIST.md @@ -1,10 +1,11 @@ +fix https://github.com/selfrefactor/rambdax/issues/93 + +remove ramda imports in tests +release X +replace missing ramda methods with text that argument is missing + --- -- binary -- call -- collectBy -- comparator -- composeWith -- construct +- construct - it is class helper and classes are not very functional oriented - constructN - dissocPath diff --git a/README.md b/README.md index d1e34d84..b845e7a5 100644 --- a/README.md +++ b/README.md @@ -96,15 +96,10 @@ Closing the issue is usually accompanied by publishing a new patch version of `R
- Click to see the full list of 72 Ramda methods not implemented in Rambda + Click to see the full list of 67 Ramda methods not implemented in Rambda - __ -- binary -- call -- collectBy -- comparator -- composeWith - construct - constructN - dissocPath @@ -2030,6 +2025,10 @@ describe('R.assocPath - curried', () => { [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#assocPath) +### binary + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#binary) + ### bind ```typescript @@ -2338,6 +2337,10 @@ describe('R.both', () => { [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#both) +### call + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#call) + ### chain ```typescript @@ -2493,6 +2496,14 @@ It creates a deep copy of the `input`, which may contain (nested) Arrays and Obj [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#clone) +### collectBy + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#collectBy) + +### comparator + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#comparator) + ### complement It returns `inverted` version of `origin` function that accept `input` as argument. @@ -2511,6 +2522,10 @@ It performs right-to-left function composition. [![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#compose) +### composeWith + +[![---------------](https://raw.githubusercontent.com/selfrefactor/rambda/master/files/separator.png)](#composeWith) + ### concat It returns a new string or array, which is the result of merging `x` and `y`. @@ -11822,7 +11837,7 @@ describe('R.product', () => { ```typescript -prop

(propToFind: P, value: T): Prop +prop<_, P extends keyof never, T>(p: P, value: T): Prop ``` It returns the value of property `propToFind` in `obj`. @@ -11836,17 +11851,10 @@ If there is no such property, it returns `undefined`.

All TypeScript definitions ```typescript -prop

(propToFind: P, value: T): Prop; -prop

(propToFind: P): { - (value: Record): T; - (value: T): Prop; -}; -prop

(propToFind: P): { - (value: T): Prop; -}; -prop

(propToFind: P): { - (value: Record): T; -}; +prop<_, P extends keyof never, T>(p: P, value: T): Prop; +prop(p: keyof never, value: unknown): V; +prop<_, P extends keyof never>(p: P): (value: T) => Prop; +prop(p: keyof never): (value: unknown) => V; ```

@@ -17299,6 +17307,16 @@ describe('R.zipWith', () => { ## ❯ CHANGELOG +8.3.0 + +Add the following methods: + +- binary +- call +- collectBy +- comparator +- composeWith + 8.2.0 Add the following methods: diff --git a/dist/rambda.js b/dist/rambda.js index cb41ddcf..b862a725 100644 --- a/dist/rambda.js +++ b/dist/rambda.js @@ -33,26 +33,7 @@ function _concat(set1, set2) { return result; } -function _curryN(n, cache, fn) { - return function () { - let ci = 0; - let ai = 0; - const cl = cache.length; - const al = arguments.length; - const args = new Array(cl + al); - while (ci < cl) { - args[ci] = cache[ci]; - ci++; - } - while (ai < al) { - args[cl + ai] = arguments[ai]; - ai++; - } - const remaining = n - args.length; - return args.length >= n ? fn.apply(this, args) : _arity$1(remaining, _curryN(n, args, fn)); - }; -} -function _arity$1(n, fn) { +function _arity(n, fn) { switch (n) { case 0: return function () { @@ -100,12 +81,32 @@ function _arity$1(n, fn) { }; } } + +function _curryN(n, cache, fn) { + return function () { + let ci = 0; + let ai = 0; + const cl = cache.length; + const al = arguments.length; + const args = new Array(cl + al); + while (ci < cl) { + args[ci] = cache[ci]; + ci++; + } + while (ai < al) { + args[cl + ai] = arguments[ai]; + ai++; + } + const remaining = n - args.length; + return args.length >= n ? fn.apply(this, args) : _arity(remaining, _curryN(n, args, fn)); + }; +} function curryN(n, fn) { if (arguments.length === 1) return _fn => curryN(n, _fn); if (n > 10) { throw new Error('First argument to _arity must be a non-negative integer no greater than ten'); } - return _arity$1(n, _curryN(n, [], fn)); + return _arity(n, _curryN(n, [], fn)); } function addIndex(originalFunction, initialIndexFn = () => 0, loopIndexChange = x => x + 1) { @@ -356,6 +357,11 @@ function assocPathFn(path, newValue, input) { } const assocPath = curry(assocPathFn); +function binary(fn) { + if (fn.length <= 2) return fn; + return (a, b) => fn(a, b); +} + function bind(fn, thisObj) { if (arguments.length === 1) { return _thisObj => bind(fn, _thisObj); @@ -368,6 +374,8 @@ function both(f, g) { return (...input) => f(...input) && g(...input); } +const call = (fn, ...inputs) => fn(...inputs); + function chain(fn, list) { if (arguments.length === 1) { return _list => chain(fn, _list); @@ -395,10 +403,6 @@ function clone(input) { return out; } -function complement(fn) { - return (...input) => !fn(...input); -} - class ReduceStopper { constructor(value) { this.value = value; @@ -425,56 +429,35 @@ function reduceFn(reducer, acc, list) { const reduce = curry(reduceFn); const reduceStopper = value => new ReduceStopper(value); -function _arity(n, fn) { - switch (n) { - case 0: - return function () { - return fn.apply(this, arguments); - }; - case 1: - return function (a0) { - return fn.apply(this, arguments); - }; - case 2: - return function (a0, a1) { - return fn.apply(this, arguments); - }; - case 3: - return function (a0, a1, a2) { - return fn.apply(this, arguments); - }; - case 4: - return function (a0, a1, a2, a3) { - return fn.apply(this, arguments); - }; - case 5: - return function (a0, a1, a2, a3, a4) { - return fn.apply(this, arguments); - }; - case 6: - return function (a0, a1, a2, a3, a4, a5) { - return fn.apply(this, arguments); - }; - case 7: - return function (a0, a1, a2, a3, a4, a5, a6) { - return fn.apply(this, arguments); - }; - case 8: - return function (a0, a1, a2, a3, a4, a5, a6, a7) { - return fn.apply(this, arguments); - }; - case 9: - return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) { - return fn.apply(this, arguments); - }; - case 10: - return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { - return fn.apply(this, arguments); - }; - default: - throw new Error('First argument to _arity must be a non-negative integer no greater than ten'); +function collectBy(fn, list) { + if (arguments.length === 1) { + return _list => collectBy(fn, _list); } + const group = reduce((o, x) => { + const tag = fn(x); + if (o[tag] === undefined) { + o[tag] = []; + } + o[tag].push(x); + return o; + }, {}, list); + const newList = []; + for (const tag in group) { + newList.push(group[tag]); + } + return newList; } + +function comparator(fn) { + return function (a, b) { + return fn(a, b) ? -1 : fn(b, a) ? 1 : 0; + }; +} + +function complement(fn) { + return (...input) => !fn(...input); +} + function _pipe(f, g) { return function () { return g.call(this, f.apply(this, arguments)); @@ -494,6 +477,49 @@ function compose() { return pipe.apply(this, Array.prototype.slice.call(arguments, 0).reverse()); } +function head(listOrString) { + if (typeof listOrString === 'string') return listOrString[0] || ''; + return listOrString[0]; +} + +function identity(x) { + return x; +} + +function reverse(listOrString) { + if (typeof listOrString === 'string') { + return listOrString.split('').reverse().join(''); + } + const clone = listOrString.slice(); + return clone.reverse(); +} + +function drop(howManyToDrop, listOrString) { + if (arguments.length === 1) return _list => drop(howManyToDrop, _list); + return listOrString.slice(howManyToDrop > 0 ? howManyToDrop : 0); +} + +function tail(listOrString) { + return drop(1, listOrString); +} + +function pipeWith(xf, list) { + if (list.length <= 0) { + return identity; + } + const headList = head(list); + const tailList = tail(list); + return _arity(headList.length, function () { + return reduce(function (result, f) { + return xf.call(this, f, result); + }, headList.apply(this, arguments), tailList); + }); +} +function composeWith(xf, list) { + if (arguments.length === 1) return _list => composeWith(xf, _list); + return pipeWith.apply(this, [xf, reverse(list)]); +} + function concat(x, y) { if (arguments.length === 1) return _y => concat(x, _y); return typeof x === 'string' ? `${x}${y}` : [...x, ...y]; @@ -846,11 +872,6 @@ function divide(a, b) { return a / b; } -function drop(howManyToDrop, listOrString) { - if (arguments.length === 1) return _list => drop(howManyToDrop, _list); - return listOrString.slice(howManyToDrop > 0 ? howManyToDrop : 0); -} - function dropLast(howManyToDrop, listOrString) { if (arguments.length === 1) { return _listOrString => dropLast(howManyToDrop, _listOrString); @@ -1244,11 +1265,6 @@ function hasPath(pathInput, obj) { return path(pathInput, obj) !== undefined; } -function head(listOrString) { - if (typeof listOrString === 'string') return listOrString[0] || ''; - return listOrString[0]; -} - function _objectIs(a, b) { if (a === b) { return a !== 0 || 1 / a === 1 / b; @@ -1262,10 +1278,6 @@ function identical(a, b) { return objectIs(a, b); } -function identity(x) { - return x; -} - function ifElseFn(condition, onTrue, onFalse) { return (...input) => { const conditionResult = typeof condition === 'boolean' ? condition : condition(...input); @@ -1918,14 +1930,6 @@ function replaceFn(pattern, replacer, str) { } const replace = curry(replaceFn); -function reverse(listOrString) { - if (typeof listOrString === 'string') { - return listOrString.split('').reverse().join(''); - } - const clone = listOrString.slice(); - return clone.reverse(); -} - function setFn(lens, replacer, x) { return over(lens, always(replacer), x); } @@ -2045,10 +2049,6 @@ function symmetricDifference(x, y) { return concat(filter(value => !includes(value, y), x), filter(value => !includes(value, x), y)); } -function tail(listOrString) { - return drop(1, listOrString); -} - function takeLast(howMany, listOrString) { if (arguments.length === 1) return _listOrString => takeLast(howMany, _listOrString); const len = listOrString.length; @@ -2326,7 +2326,6 @@ const zipWith = curry(zipWithFn); exports.F = F; exports.T = T; exports.__findHighestArity = __findHighestArity; -exports._arity = _arity; exports._indexOf = _indexOf; exports._lastIndexOf = _lastIndexOf; exports._pipe = _pipe; @@ -2349,13 +2348,18 @@ exports.applyTo = applyTo; exports.ascend = ascend; exports.assoc = assoc; exports.assocPath = assocPath; +exports.binary = binary; exports.bind = bind; exports.both = both; +exports.call = call; exports.chain = chain; exports.clamp = clamp; exports.clone = clone; +exports.collectBy = collectBy; +exports.comparator = comparator; exports.complement = complement; exports.compose = compose; +exports.composeWith = composeWith; exports.concat = concat; exports.cond = cond; exports.converge = converge; @@ -2474,6 +2478,7 @@ exports.paths = paths; exports.pick = pick; exports.pickAll = pickAll; exports.pipe = pipe; +exports.pipeWith = pipeWith; exports.pluck = pluck; exports.prepend = prepend; exports.product = product; diff --git a/dist/rambda.umd.js b/dist/rambda.umd.js index c30ab608..9f39d359 100644 --- a/dist/rambda.umd.js +++ b/dist/rambda.umd.js @@ -1 +1 @@ -!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r((n="undefined"!=typeof globalThis?globalThis:n||self).R={})}(this,function(n){"use strict";function C(n,l){switch(n){case 0:return function(){return l.apply(this,arguments)};case 1:return function(n){return l.apply(this,arguments)};case 2:return function(n,r){return l.apply(this,arguments)};case 3:return function(n,r,t){return l.apply(this,arguments)};case 4:return function(n,r,t,e){return l.apply(this,arguments)};case 5:return function(n,r,t,e,u){return l.apply(this,arguments)};case 6:return function(n,r,t,e,u,i){return l.apply(this,arguments)};case 7:return function(n,r,t,e,u,i,o){return l.apply(this,arguments)};case 8:return function(n,r,t,e,u,i,o,f){return l.apply(this,arguments)};case 9:return function(n,r,t,e,u,i,o,f,c){return l.apply(this,arguments)};default:return function(n,r,t,e,u,i,o,f,c,a){return l.apply(this,arguments)}}}function t(r,n){if(1===arguments.length)return function(n){return t(r,n)};if(10>>0,r>>>=0,Array(u));++en(r)?t:r}var kn=f(Pn);function Sn(n){return n.reduce(function(n,r){return n+r},0)}function Tn(n){return Sn(n)/n.length}function W(r,n){return 1===arguments.length?function(n){return W(r,n)}:Object.assign({},r||{},n||{})}function R(r,t){var e;return 1===arguments.length?function(n){return R(r,n)}:(e=d(r),Object.keys(t).forEach(function(n){"Object"===E(t[n])&&"Object"===E(r[n])?e[n]=R(r[n],t[n]):e[n]=t[n]}),e)}var Fn=f(function(r,n,t){var e=null!=n?n:{},u=null!=t?t:{},i={};return Object.keys(e).forEach(function(n){i[n]=void 0===u[n]?e[n]:r(e[n],u[n])}),Object.keys(u).forEach(function(n){void 0===i[n]&&(i[n]=void 0===e[n]?u[n]:r(e[n],u[n]))}),i});function In(n,r,t){return n(t) 4")};var e},n.forEach=function r(t,n){if(1===arguments.length)return function(n){return r(t,n)};if(void 0!==n){if(s(n))for(var e=0,u=n.length;e>>0,r>>>=0,Array(u));++en(r)?t:r}var In=f(Fn);function Wn(n){return n.reduce(function(n,r){return n+r},0)}function Rn(n){return Wn(n)/n.length}function W(r,n){return 1===arguments.length?function(n){return W(r,n)}:Object.assign({},r||{},n||{})}function R(r,t){var e;return 1===arguments.length?function(n){return R(r,n)}:(e=m(r),Object.keys(t).forEach(function(n){"Object"===N(t[n])&&"Object"===N(r[n])?e[n]=R(r[n],t[n]):e[n]=t[n]}),e)}var qn=f(function(r,n,t){var e=null!=n?n:{},u=null!=t?t:{},i={};return Object.keys(e).forEach(function(n){i[n]=void 0===u[n]?e[n]:r(e[n],u[n])}),Object.keys(u).forEach(function(n){void 0===i[n]&&(i[n]=void 0===e[n]?u[n]:r(e[n],u[n]))}),i});function Bn(n,r,t){return n(t) 4")};var e},n.forEach=function r(t,n){if(1===arguments.length)return function(n){return r(t,n)};if(void 0!==n){if(p(n))for(var e=0,u=n.length;e { (val: T): (obj: U) => Record & U; (val: T, obj: U): Record & U; } +type AtLeastOneFunctionsFlowFromRightToLeft = + | [(...args: any) => TResult, ...Array<(args: any) => any>, (...args: TArgs) => any] + | [(...args: TArgs) => TResult]; type AnyFunction = (...args: any[]) => unknown; type AnyConstructor = new (...args: any[]) => unknown; @@ -3281,17 +3284,10 @@ Notes: */ // @SINGLE_MARKER -export function prop

(propToFind: P, value: T): Prop; -export function prop

(propToFind: P): { - (value: Record): T; - (value: T): Prop; -}; -export function prop

(propToFind: P): { - (value: T): Prop; -}; -export function prop

(propToFind: P): { - (value: Record): T; -}; +export function prop<_, P extends keyof never, T>(p: P, value: T): Prop; +export function prop(p: keyof never, value: unknown): V; +export function prop<_, P extends keyof never>(p: P): (value: T) => Prop; +export function prop(p: keyof never): (value: unknown) => V; /* Method: propEq @@ -5458,6 +5454,105 @@ Notes: export function descend(fn: (obj: T) => Ord, a: T, b: T): Ordering; export function descend(fn: (obj: T) => Ord): (a: T, b: T) => Ordering; +/* +Method: binary + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function binary any>(fn: T): (...args: any[]) => ReturnType; + +/* +Method: call + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function call any>(fn: T, ...args: Parameters): ReturnType; + +/* +Method: collectBy + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function collectBy(keyFn: (value: T) => K, list: T[]): T[][]; +export function collectBy(keyFn: (value: T) => K): (list: T[]) => T[][]; + +/* +Method: comparator + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function comparator(pred: (a: T, b: T) => boolean): (x: T, y: T) => Ordering; + +/* +Method: composeWith + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function composeWith( + transformer: (fn: (...args: any[]) => any, intermediatResult: any) => any, + fns: AtLeastOneFunctionsFlowFromRightToLeft, +): (...args: TArgs) => TResult; +export function composeWith( + transformer: (fn: (...args: any[]) => any, intermediatResult: any) => any, +): ( + fns: AtLeastOneFunctionsFlowFromRightToLeft, +) => (...args: TArgs) => TResult; + // RAMBDAX_MARKER_START /* diff --git a/immutable.d.ts b/immutable.d.ts index 24875d6a..6e0b4de1 100644 --- a/immutable.d.ts +++ b/immutable.d.ts @@ -95,6 +95,9 @@ interface AssocPartialOne { (val: T): (obj: U) => Record & U; (val: T, obj: U): Record & U; } +type AtLeastOneFunctionsFlowFromRightToLeft = + | readonly [(...args: any) => TResult, ...ReadonlyArray<(args: any) => any>, (...args: TArgs) => any] + | readonly [(...args: TArgs) => TResult]; type AnyFunction = (...args: readonly any[]) => unknown; type AnyConstructor = new (...args: readonly any[]) => unknown; @@ -277,6 +280,8 @@ export function assocPath(path: Path, newValue: any, obj: object): Outpu export function assocPath(path: Path, newValue: any): (obj: object) => Output; export function assocPath(path: Path): (newValue: any) => (obj: object) => Output; +export function binary any>(fn: T): (...args: readonly any[]) => ReturnType; + /** * Creates a function that is bound to a context. */ @@ -293,6 +298,8 @@ export function both(pred1: Predicate, pred2: Predicate): Predicate; export function both(pred1: Predicate): (pred2: Predicate) => Predicate; export function both(pred1: Pred): (pred2: Pred) => Pred; +export function call any>(fn: T, ...args: Parameters): ReturnType; + /** * The method is also known as `flatMap`. */ @@ -315,6 +322,11 @@ export function clamp(min: number, max: number): (input: number) => number; export function clone(input: T): T; export function clone(input: readonly T[]): readonly T[]; +export function collectBy(keyFn: (value: T) => K, list: readonly T[]): readonly (readonly T[])[]; +export function collectBy(keyFn: (value: T) => K): (list: readonly T[]) => readonly (readonly T[])[]; + +export function comparator(pred: (a: T, b: T) => boolean): (x: T, y: T) => Ordering; + /** * It returns `inverted` version of `origin` function that accept `input` as argument. * @@ -390,6 +402,16 @@ export function compose( f1: (...args: TArgs) => R1 ): (...args: TArgs) => R1; +export function composeWith( + transformer: (fn: (...args: readonly any[]) => any, intermediatResult: any) => any, + fns: AtLeastOneFunctionsFlowFromRightToLeft, +): (...args: TArgs) => TResult; +export function composeWith( + transformer: (fn: (...args: readonly any[]) => any, intermediatResult: any) => any, +): ( + fns: AtLeastOneFunctionsFlowFromRightToLeft, +) => (...args: TArgs) => TResult; + /** * It returns a new string or array, which is the result of merging `x` and `y`. */ @@ -1270,17 +1292,10 @@ export function product(list: readonly number[]): number; * * If there is no such property, it returns `undefined`. */ -export function prop

(propToFind: P, value: T): Prop; -export function prop

(propToFind: P): { - (value: Record): T; - (value: T): Prop; -}; -export function prop

(propToFind: P): { - (value: T): Prop; -}; -export function prop

(propToFind: P): { - (value: Record): T; -}; +export function prop<_, P extends keyof never, T>(p: P, value: T): Prop; +export function prop(p: keyof never, value: unknown): V; +export function prop<_, P extends keyof never>(p: P): (value: T) => Prop; +export function prop(p: keyof never): (value: unknown) => V; /** * It returns true if `obj` has property `propToFind` and its value is equal to `valueToMatch`. diff --git a/index.d.ts b/index.d.ts index c19e83d5..7f46356e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -95,6 +95,9 @@ interface AssocPartialOne { (val: T): (obj: U) => Record & U; (val: T, obj: U): Record & U; } +type AtLeastOneFunctionsFlowFromRightToLeft = + | [(...args: any) => TResult, ...Array<(args: any) => any>, (...args: TArgs) => any] + | [(...args: TArgs) => TResult]; type AnyFunction = (...args: any[]) => unknown; type AnyConstructor = new (...args: any[]) => unknown; @@ -277,6 +280,8 @@ export function assocPath(path: Path, newValue: any, obj: object): Outpu export function assocPath(path: Path, newValue: any): (obj: object) => Output; export function assocPath(path: Path): (newValue: any) => (obj: object) => Output; +export function binary any>(fn: T): (...args: any[]) => ReturnType; + /** * Creates a function that is bound to a context. */ @@ -293,6 +298,8 @@ export function both(pred1: Predicate, pred2: Predicate): Predicate; export function both(pred1: Predicate): (pred2: Predicate) => Predicate; export function both(pred1: Pred): (pred2: Pred) => Pred; +export function call any>(fn: T, ...args: Parameters): ReturnType; + /** * The method is also known as `flatMap`. */ @@ -315,6 +322,11 @@ export function clamp(min: number, max: number): (input: number) => number; export function clone(input: T): T; export function clone(input: T[]): T[]; +export function collectBy(keyFn: (value: T) => K, list: T[]): T[][]; +export function collectBy(keyFn: (value: T) => K): (list: T[]) => T[][]; + +export function comparator(pred: (a: T, b: T) => boolean): (x: T, y: T) => Ordering; + /** * It returns `inverted` version of `origin` function that accept `input` as argument. * @@ -390,6 +402,16 @@ export function compose( f1: (...args: TArgs) => R1 ): (...args: TArgs) => R1; +export function composeWith( + transformer: (fn: (...args: any[]) => any, intermediatResult: any) => any, + fns: AtLeastOneFunctionsFlowFromRightToLeft, +): (...args: TArgs) => TResult; +export function composeWith( + transformer: (fn: (...args: any[]) => any, intermediatResult: any) => any, +): ( + fns: AtLeastOneFunctionsFlowFromRightToLeft, +) => (...args: TArgs) => TResult; + /** * It returns a new string or array, which is the result of merging `x` and `y`. */ @@ -1270,17 +1292,10 @@ export function product(list: number[]): number; * * If there is no such property, it returns `undefined`. */ -export function prop

(propToFind: P, value: T): Prop; -export function prop

(propToFind: P): { - (value: Record): T; - (value: T): Prop; -}; -export function prop

(propToFind: P): { - (value: T): Prop; -}; -export function prop

(propToFind: P): { - (value: Record): T; -}; +export function prop<_, P extends keyof never, T>(p: P, value: T): Prop; +export function prop(p: keyof never, value: unknown): V; +export function prop<_, P extends keyof never>(p: P): (value: T) => Prop; +export function prop(p: keyof never): (value: unknown) => V; /** * It returns true if `obj` has property `propToFind` and its value is equal to `valueToMatch`. diff --git a/package.json b/package.json index ce01b8e2..724baa59 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "combinate": "1.1.11", "cross-env": "7.0.3", "dtslint": "4.2.1", + "fast-check": "^3.11.0", "helpers-fn": "1.8.1", "is-ci": "3.0.1", "jest": "29.5.0", diff --git a/rambda.js b/rambda.js index de648510..8e72dd19 100644 --- a/rambda.js +++ b/rambda.js @@ -20,13 +20,18 @@ export * from './src/applyTo.js' export * from './src/ascend.js' export * from './src/assoc.js' export * from './src/assocPath.js' +export * from './src/binary.js' export * from './src/bind.js' export * from './src/both.js' +export * from './src/call.js' export * from './src/chain.js' export * from './src/clamp.js' export * from './src/clone.js' +export * from './src/collectBy.js' +export * from './src/comparator.js' export * from './src/complement.js' export * from './src/compose.js' +export * from './src/composeWith.js' export * from './src/concat.js' export * from './src/cond.js' export * from './src/converge.js' diff --git a/source/_internals/_arity.js b/source/_internals/_arity.js new file mode 100644 index 00000000..d9cd3816 --- /dev/null +++ b/source/_internals/_arity.js @@ -0,0 +1,64 @@ +export function _arity(n, fn){ + switch (n){ + case 0: + return function (){ + return fn.apply(this, arguments) + } + case 1: + return function (_1){ + return fn.apply(this, arguments) + } + case 2: + return function (_1, _2){ + return fn.apply(this, arguments) + } + case 3: + return function ( + _1, _2, _3 + ){ + return fn.apply(this, arguments) + } + case 4: + return function ( + _1, _2, _3, _4 + ){ + return fn.apply(this, arguments) + } + case 5: + return function ( + _1, _2, _3, _4, _5 + ){ + return fn.apply(this, arguments) + } + case 6: + return function ( + _1, _2, _3, _4, _5, _6 + ){ + return fn.apply(this, arguments) + } + case 7: + return function ( + _1, _2, _3, _4, _5, _6, _7 + ){ + return fn.apply(this, arguments) + } + case 8: + return function ( + _1, _2, _3, _4, _5, _6, _7, _8 + ){ + return fn.apply(this, arguments) + } + case 9: + return function ( + _1, _2, _3, _4, _5, _6, _7, _8, _9 + ){ + return fn.apply(this, arguments) + } + default: + return function ( + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10 + ){ + return fn.apply(this, arguments) + } + } +} diff --git a/source/binary-spec.ts b/source/binary-spec.ts new file mode 100644 index 00000000..6c83e821 --- /dev/null +++ b/source/binary-spec.ts @@ -0,0 +1,14 @@ +import {binary} from 'rambda' + +describe('R.binary', () => { + it('happy', () => { + const result = binary(function(x: number, y: number, z) { + expect(arguments.length).toBe(2) + expect(z).toBeUndefined() + expect(x).toBe(10) + expect(y).toBe(20) + return x + y + })(10, 20, 30) + result // $ExpectType number + }) +}) diff --git a/source/binary.js b/source/binary.js new file mode 100644 index 00000000..d98f4aae --- /dev/null +++ b/source/binary.js @@ -0,0 +1,5 @@ +export function binary(fn){ + if (fn.length <= 2) return fn + + return (a, b) => fn(a, b) +} diff --git a/source/binary.spec.js b/source/binary.spec.js new file mode 100644 index 00000000..f3f53019 --- /dev/null +++ b/source/binary.spec.js @@ -0,0 +1,17 @@ +import { binary } from './binary.js' + +test('happy', () => { + const result = binary(function ( + x, y, z + ){ + expect(arguments).toHaveLength(2) + expect(z).toBeUndefined() + expect(x).toBe(10) + expect(y).toBe(20) + + return x + y + })( + 10, 20, 30 + ) + expect(result).toBe(30) +}) diff --git a/source/call.js b/source/call.js new file mode 100644 index 00000000..8a35bed7 --- /dev/null +++ b/source/call.js @@ -0,0 +1 @@ +export const call = (fn, ...inputs) => fn(...inputs) diff --git a/source/call.spec.js b/source/call.spec.js new file mode 100644 index 00000000..ed8412e1 --- /dev/null +++ b/source/call.spec.js @@ -0,0 +1,32 @@ +import { bind } from './bind.js' +import { call } from './call.js' + +test('happy', () => { + expect(call( + Math.max, 1, 2, 3, -99, 42, 6, 7 + )).toBe(42) +}) + +test('accepts one or more arguments', () => { + const fn = function (){ + return arguments.length + } + expect(call(fn)).toBe(0) + expect(call(fn, 'x')).toBe(1) + expect(call( + fn, 'x', 'y' + )).toBe(2) + expect(call( + fn, 'x', 'y', 'z' + )).toBe(3) +}) + +test('provides no way to specify context', () => { + var obj = { + method (){ + return this === obj + }, + } + expect(call(obj.method)).toBe(false) + expect(call(bind(obj.method, obj))).toBe(true) +}) diff --git a/source/collectBy.js b/source/collectBy.js new file mode 100644 index 00000000..26f5a8e7 --- /dev/null +++ b/source/collectBy.js @@ -0,0 +1,27 @@ +import { reduce } from './reduce.js' + +export function collectBy(fn, list){ + if (arguments.length === 1){ + return _list => collectBy(fn, _list) + } + + const group = reduce( + (o, x) => { + const tag = fn(x) + if (o[ tag ] === undefined){ + o[ tag ] = [] + } + o[ tag ].push(x) + + return o + }, + {}, + list + ) + const newList = [] + for (const tag in group){ + newList.push(group[ tag ]) + } + + return newList +} diff --git a/source/collectBy.spec.js b/source/collectBy.spec.js new file mode 100644 index 00000000..0ab34d1b --- /dev/null +++ b/source/collectBy.spec.js @@ -0,0 +1,68 @@ +import fc from 'fast-check' +import { + all, + compose, + difference, + equals, + head, + identity, + is, + isEmpty, + length, + uniq, + unnest, +} from 'rambdax' + +import { collectBy } from './collectBy.js' + +test('returns a list of lists', () => { + fc.assert(fc.property(fc.array(fc.nat()), xs => { + const check = all(is(Array)) + const ys = collectBy(identity)(xs) + + return check(ys) + })) +}) + +test('groups items but neither adds new ones nor removes any', () => { + fc.assert(fc.property(fc.array(fc.nat()), xs => { + const check = compose( + isEmpty, difference(xs), unnest + ) + const ys = collectBy(identity)(xs) + + return check(ys) + })) +}) + +test('groups related items together', () => { + fc.assert(fc.property(fc.array(fc.boolean()), xs => { + const ys = collectBy(identity)(xs) + const check = all(compose( + equals(1), length, uniq + )) + + return check(ys) + })) +}) + +test('invokes the tag function for each item in the list', () => { + fc.assert(fc.property(fc.array(fc.nat()), xs => { + const id = jest.fn(x => 42) + collectBy(id)(xs) + const check = compose(isEmpty, difference(xs)) + + return check(id.mock.calls.map(call => call[ 0 ])) + })) +}) + +test('groups items according to the tag value', () => { + fc.assert(fc.property(fc.array(fc.nat()), xs => { + const ys = collectBy(x => 42)(xs) + const check = compose( + isEmpty, difference(xs), head + ) + + return isEmpty(xs) && isEmpty(ys) ? true : check(ys) + })) +}) diff --git a/source/comparator.js b/source/comparator.js new file mode 100644 index 00000000..ac046d02 --- /dev/null +++ b/source/comparator.js @@ -0,0 +1,5 @@ +export function comparator(fn){ + return function (a, b){ + return fn(a, b) ? -1 : fn(b, a) ? 1 : 0 + } +} diff --git a/source/comparator.spec.js b/source/comparator.spec.js new file mode 100644 index 00000000..9cbcb0c1 --- /dev/null +++ b/source/comparator.spec.js @@ -0,0 +1,7 @@ +import { comparator } from './comparator.js' + +test('happy', () => { + expect([ 3, 1, 8, 1, 2, 5 ].sort(comparator((a, b) => a < b))).toEqual([ + 1, 1, 2, 3, 5, 8, + ]) +}) diff --git a/source/composeWith.js b/source/composeWith.js new file mode 100644 index 00000000..e50762b0 --- /dev/null +++ b/source/composeWith.js @@ -0,0 +1,33 @@ +import { _arity } from './_internals/_arity.js' +import { head } from './head.js' +import { identity } from './identity.js' +import { reduce } from './reduce.js' +import { reverse } from './reverse.js' +import { tail } from './tail.js' + +export function pipeWith(xf, list){ + if (list.length <= 0){ + return identity + } + + const headList = head(list) + const tailList = tail(list) + + return _arity(headList.length, function (){ + return reduce( + function (result, f){ + return xf.call( + this, f, result + ) + }, + headList.apply(this, arguments), + tailList + ) + }) +} + +export function composeWith(xf, list){ + if (arguments.length === 1) return _list => composeWith(xf, _list) + + return pipeWith.apply(this, [ xf, reverse(list) ]) +} diff --git a/source/composeWith.spec.js b/source/composeWith.spec.js new file mode 100644 index 00000000..bbd7e768 --- /dev/null +++ b/source/composeWith.spec.js @@ -0,0 +1,51 @@ +import { always, identity, inc, isNil, map, modulo, multiply } from 'rambdax' +import { composeWith as composeWithRamda, concat, flip, ifElse } from 'ramda' + +import { composeWith } from './composeWith.js' + +test('performs right-to-left function composition with function applying', () => { + const f = composeWith((f, res) => f(res))([ map, multiply, parseInt ]) + + expect(f).toHaveLength(2) + expect(f('10')([ 1, 2, 3 ])).toEqual([ 10, 20, 30 ]) + expect(f('10', 2)([ 1, 2, 3 ])).toEqual([ 2, 4, 6 ]) +}) + +test('performs right-to-left function while not nil result', () => { + const isOdd = flip(modulo)(2) + const composeWhenNotNil = composeWithRamda((f, res) => + isNil(res) ? null : f(res)) + + const f = composeWhenNotNil([ + inc, + ifElse( + isOdd, identity, always(null) + ), + parseInt, + ]) + expect(f).toHaveLength(2) + expect(f('1')).toBe(2) + expect(f('2')).toBeNull() +}) + +test('performs right-to-left function using promise chaining', () => { + const then = function (f, p){ + return p.then(f) + } + const composeP = composeWithRamda(then) + const toListPromise = function (a){ + return new Promise(res => { + res([ a ]) + }) + } + const doubleListPromise = function (a){ + return new Promise(res => { + res(concat(a, a)) + }) + } + const f = composeP([ doubleListPromise, toListPromise ]) + + return f(1).then(res => { + expect(res).toEqual([ 1, 1 ]) + }) +}) diff --git a/source/construct.js b/source/construct.js new file mode 100644 index 00000000..2f004529 --- /dev/null +++ b/source/construct.js @@ -0,0 +1,7 @@ +export function construct(foo, bar) { + if (arguments.length === 1){ + return (_bar) => construct(foo, _bar); + } + + return +} \ No newline at end of file diff --git a/source/construct.spec.js b/source/construct.spec.js new file mode 100644 index 00000000..3b853253 --- /dev/null +++ b/source/construct.spec.js @@ -0,0 +1,77 @@ +import { construct } from './construct' +import { construct as constructRamda } from 'ramda' + +test('happy', () => { + const result = construct() + console.log(result) +}) + +/* +var assert = require('assert'); + +var R = require('../source/index.js'); +var eq = require('./shared/eq.js'); + + +describe('construct', function() { + var Rectangle = function(w, h) {this.width = w; this.height = h;}; + Rectangle.prototype.area = function() {return this.width * this.height;}; + + it('turns a constructor function into one that can be called without `new`', function() { + var rect = R.construct(Rectangle); + var r1 = rect(3, 4); + eq(r1.constructor, Rectangle); + eq(r1.width, 3); + eq(r1.area(), 12); + + var regex = R.construct(RegExp); + var word = regex('word', 'gi'); + eq(word.constructor, RegExp); + eq(word.source, 'word'); + eq(word.global, true); + }); + + it('can be used to create Date object', function() { + var date = R.construct(Date)(1984, 3, 26, 0, 0, 0, 0); + eq(date.constructor, Date); + eq(date.getFullYear(), 1984); + }); + + it('supports constructors with no arguments', function() { + function Foo() {} + var foo = R.construct(Foo)(); + eq(foo.constructor, Foo); + }); + + it('does not support constructor with greater than ten arguments', function() { + assert.throws(function() { + function Foo($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) { + this.eleventh = $10; + } + R.construct(Foo); + }, function(err) { + return (err instanceof Error && + err.message === 'Constructor with greater than ten arguments'); + }); + }); + + it('returns a curried function', function() { + var rect = R.construct(Rectangle); + var rect3 = rect(3); + var r1 = rect3(4); + eq(r1.constructor, Rectangle); + eq(r1.width, 3); + eq(r1.height, 4); + eq(r1.area(), 12); + + var regex = R.construct(RegExp); + var word = regex('word'); + var complete = word('gi'); + eq(complete.constructor, RegExp); + eq(complete.source, 'word'); + eq(complete.global, true); + }); + +}); + +*/ \ No newline at end of file diff --git a/source/constructN.js b/source/constructN.js new file mode 100644 index 00000000..17603fa9 --- /dev/null +++ b/source/constructN.js @@ -0,0 +1,7 @@ +export function constructN(foo, bar) { + if (arguments.length === 1){ + return (_bar) => constructN(foo, _bar); + } + + return +} \ No newline at end of file diff --git a/source/constructN.spec.js b/source/constructN.spec.js new file mode 100644 index 00000000..2bd0503c --- /dev/null +++ b/source/constructN.spec.js @@ -0,0 +1,63 @@ +import { constructN } from './constructN' +import { constructN as constructNRamda } from 'ramda' + +test('happy', () => { + const result = constructN() + console.log(result) +}) + +/* +var assert = require('assert'); + +var R = require('../source/index.js'); +var eq = require('./shared/eq.js'); + + +describe('constructN', function() { + var Circle = function(r) { + this.r = r; + this.colors = Array.prototype.slice.call(arguments, 1); + }; + Circle.prototype.area = function() {return Math.PI * Math.pow(this.r, 2);}; + + it('turns a constructor function into a function with n arguments', function() { + var circle = R.constructN(2, Circle); + var c1 = circle(1, 'red'); + eq(c1.constructor, Circle); + eq(c1.r, 1); + eq(c1.area(), Math.PI); + eq(c1.colors, ['red']); + + var regex = R.constructN(1, RegExp); + var pattern = regex('[a-z]'); + eq(pattern.constructor, RegExp); + eq(pattern.source, '[a-z]'); + }); + + it('can be used to create Date object', function() { + var date = R.constructN(3, Date)(1984, 3, 26); + eq(date.constructor, Date); + eq(date.getFullYear(), 1984); + }); + + it('supports constructors with no arguments', function() { + function Foo() {} + var foo = R.constructN(0, Foo)(); + eq(foo.constructor, Foo); + }); + + it('does not support constructor with greater than ten arguments', function() { + assert.throws(function() { + function Foo($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) { + this.eleventh = $10; + } + R.constructN(11, Foo); + }, function(err) { + return (err instanceof Error && + err.message === 'Constructor with greater than ten arguments'); + }); + }); + +}); + +*/ \ No newline at end of file diff --git a/source/curryN.js b/source/curryN.js index d04c7509..5525f2bd 100644 --- a/source/curryN.js +++ b/source/curryN.js @@ -1,3 +1,5 @@ +import { _arity } from './_internals/_arity.js' + function _curryN( n, cache, fn ){ @@ -25,71 +27,6 @@ function _curryN( } } -function _arity(n, fn){ - switch (n){ - case 0: - return function (){ - return fn.apply(this, arguments) - } - case 1: - return function (_1){ - return fn.apply(this, arguments) - } - case 2: - return function (_1, _2){ - return fn.apply(this, arguments) - } - case 3: - return function ( - _1, _2, _3 - ){ - return fn.apply(this, arguments) - } - case 4: - return function ( - _1, _2, _3, _4 - ){ - return fn.apply(this, arguments) - } - case 5: - return function ( - _1, _2, _3, _4, _5 - ){ - return fn.apply(this, arguments) - } - case 6: - return function ( - _1, _2, _3, _4, _5, _6 - ){ - return fn.apply(this, arguments) - } - case 7: - return function ( - _1, _2, _3, _4, _5, _6, _7 - ){ - return fn.apply(this, arguments) - } - case 8: - return function ( - _1, _2, _3, _4, _5, _6, _7, _8 - ){ - return fn.apply(this, arguments) - } - case 9: - return function ( - _1, _2, _3, _4, _5, _6, _7, _8, _9 - ){ - return fn.apply(this, arguments) - } - default: - return function ( - _1, _2, _3, _4, _5, _6, _7, _8, _9, _10 - ){ - return fn.apply(this, arguments) - } - } -} - export function curryN(n, fn){ if (arguments.length === 1) return _fn => curryN(n, _fn) diff --git a/source/pipe.js b/source/pipe.js index 9ab95f12..2e862d2c 100644 --- a/source/pipe.js +++ b/source/pipe.js @@ -1,72 +1,6 @@ +import { _arity } from './_internals/_arity.js' import { reduceFn } from './reduce.js' -export function _arity(n, fn){ - switch (n){ - case 0: - return function (){ - return fn.apply(this, arguments) - } - case 1: - return function (a0){ - return fn.apply(this, arguments) - } - case 2: - return function (a0, a1){ - return fn.apply(this, arguments) - } - case 3: - return function ( - a0, a1, a2 - ){ - return fn.apply(this, arguments) - } - case 4: - return function ( - a0, a1, a2, a3 - ){ - return fn.apply(this, arguments) - } - case 5: - return function ( - a0, a1, a2, a3, a4 - ){ - return fn.apply(this, arguments) - } - case 6: - return function ( - a0, a1, a2, a3, a4, a5 - ){ - return fn.apply(this, arguments) - } - case 7: - return function ( - a0, a1, a2, a3, a4, a5, a6 - ){ - return fn.apply(this, arguments) - } - case 8: - return function ( - a0, a1, a2, a3, a4, a5, a6, a7 - ){ - return fn.apply(this, arguments) - } - case 9: - return function ( - a0, a1, a2, a3, a4, a5, a6, a7, a8 - ){ - return fn.apply(this, arguments) - } - case 10: - return function ( - a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 - ){ - return fn.apply(this, arguments) - } - default: - throw new Error('First argument to _arity must be a non-negative integer no greater than ten') - } -} - export function _pipe(f, g){ return function (){ return g.call(this, f.apply(this, arguments)) diff --git a/src/_internals/_arity.js b/src/_internals/_arity.js new file mode 100644 index 00000000..d9cd3816 --- /dev/null +++ b/src/_internals/_arity.js @@ -0,0 +1,64 @@ +export function _arity(n, fn){ + switch (n){ + case 0: + return function (){ + return fn.apply(this, arguments) + } + case 1: + return function (_1){ + return fn.apply(this, arguments) + } + case 2: + return function (_1, _2){ + return fn.apply(this, arguments) + } + case 3: + return function ( + _1, _2, _3 + ){ + return fn.apply(this, arguments) + } + case 4: + return function ( + _1, _2, _3, _4 + ){ + return fn.apply(this, arguments) + } + case 5: + return function ( + _1, _2, _3, _4, _5 + ){ + return fn.apply(this, arguments) + } + case 6: + return function ( + _1, _2, _3, _4, _5, _6 + ){ + return fn.apply(this, arguments) + } + case 7: + return function ( + _1, _2, _3, _4, _5, _6, _7 + ){ + return fn.apply(this, arguments) + } + case 8: + return function ( + _1, _2, _3, _4, _5, _6, _7, _8 + ){ + return fn.apply(this, arguments) + } + case 9: + return function ( + _1, _2, _3, _4, _5, _6, _7, _8, _9 + ){ + return fn.apply(this, arguments) + } + default: + return function ( + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10 + ){ + return fn.apply(this, arguments) + } + } +} diff --git a/src/binary.js b/src/binary.js new file mode 100644 index 00000000..d98f4aae --- /dev/null +++ b/src/binary.js @@ -0,0 +1,5 @@ +export function binary(fn){ + if (fn.length <= 2) return fn + + return (a, b) => fn(a, b) +} diff --git a/src/call.js b/src/call.js new file mode 100644 index 00000000..8a35bed7 --- /dev/null +++ b/src/call.js @@ -0,0 +1 @@ +export const call = (fn, ...inputs) => fn(...inputs) diff --git a/src/collectBy.js b/src/collectBy.js new file mode 100644 index 00000000..26f5a8e7 --- /dev/null +++ b/src/collectBy.js @@ -0,0 +1,27 @@ +import { reduce } from './reduce.js' + +export function collectBy(fn, list){ + if (arguments.length === 1){ + return _list => collectBy(fn, _list) + } + + const group = reduce( + (o, x) => { + const tag = fn(x) + if (o[ tag ] === undefined){ + o[ tag ] = [] + } + o[ tag ].push(x) + + return o + }, + {}, + list + ) + const newList = [] + for (const tag in group){ + newList.push(group[ tag ]) + } + + return newList +} diff --git a/src/comparator.js b/src/comparator.js new file mode 100644 index 00000000..ac046d02 --- /dev/null +++ b/src/comparator.js @@ -0,0 +1,5 @@ +export function comparator(fn){ + return function (a, b){ + return fn(a, b) ? -1 : fn(b, a) ? 1 : 0 + } +} diff --git a/src/composeWith.js b/src/composeWith.js new file mode 100644 index 00000000..e50762b0 --- /dev/null +++ b/src/composeWith.js @@ -0,0 +1,33 @@ +import { _arity } from './_internals/_arity.js' +import { head } from './head.js' +import { identity } from './identity.js' +import { reduce } from './reduce.js' +import { reverse } from './reverse.js' +import { tail } from './tail.js' + +export function pipeWith(xf, list){ + if (list.length <= 0){ + return identity + } + + const headList = head(list) + const tailList = tail(list) + + return _arity(headList.length, function (){ + return reduce( + function (result, f){ + return xf.call( + this, f, result + ) + }, + headList.apply(this, arguments), + tailList + ) + }) +} + +export function composeWith(xf, list){ + if (arguments.length === 1) return _list => composeWith(xf, _list) + + return pipeWith.apply(this, [ xf, reverse(list) ]) +} diff --git a/src/curryN.js b/src/curryN.js index d04c7509..5525f2bd 100644 --- a/src/curryN.js +++ b/src/curryN.js @@ -1,3 +1,5 @@ +import { _arity } from './_internals/_arity.js' + function _curryN( n, cache, fn ){ @@ -25,71 +27,6 @@ function _curryN( } } -function _arity(n, fn){ - switch (n){ - case 0: - return function (){ - return fn.apply(this, arguments) - } - case 1: - return function (_1){ - return fn.apply(this, arguments) - } - case 2: - return function (_1, _2){ - return fn.apply(this, arguments) - } - case 3: - return function ( - _1, _2, _3 - ){ - return fn.apply(this, arguments) - } - case 4: - return function ( - _1, _2, _3, _4 - ){ - return fn.apply(this, arguments) - } - case 5: - return function ( - _1, _2, _3, _4, _5 - ){ - return fn.apply(this, arguments) - } - case 6: - return function ( - _1, _2, _3, _4, _5, _6 - ){ - return fn.apply(this, arguments) - } - case 7: - return function ( - _1, _2, _3, _4, _5, _6, _7 - ){ - return fn.apply(this, arguments) - } - case 8: - return function ( - _1, _2, _3, _4, _5, _6, _7, _8 - ){ - return fn.apply(this, arguments) - } - case 9: - return function ( - _1, _2, _3, _4, _5, _6, _7, _8, _9 - ){ - return fn.apply(this, arguments) - } - default: - return function ( - _1, _2, _3, _4, _5, _6, _7, _8, _9, _10 - ){ - return fn.apply(this, arguments) - } - } -} - export function curryN(n, fn){ if (arguments.length === 1) return _fn => curryN(n, _fn) diff --git a/src/pipe.js b/src/pipe.js index 9ab95f12..2e862d2c 100644 --- a/src/pipe.js +++ b/src/pipe.js @@ -1,72 +1,6 @@ +import { _arity } from './_internals/_arity.js' import { reduceFn } from './reduce.js' -export function _arity(n, fn){ - switch (n){ - case 0: - return function (){ - return fn.apply(this, arguments) - } - case 1: - return function (a0){ - return fn.apply(this, arguments) - } - case 2: - return function (a0, a1){ - return fn.apply(this, arguments) - } - case 3: - return function ( - a0, a1, a2 - ){ - return fn.apply(this, arguments) - } - case 4: - return function ( - a0, a1, a2, a3 - ){ - return fn.apply(this, arguments) - } - case 5: - return function ( - a0, a1, a2, a3, a4 - ){ - return fn.apply(this, arguments) - } - case 6: - return function ( - a0, a1, a2, a3, a4, a5 - ){ - return fn.apply(this, arguments) - } - case 7: - return function ( - a0, a1, a2, a3, a4, a5, a6 - ){ - return fn.apply(this, arguments) - } - case 8: - return function ( - a0, a1, a2, a3, a4, a5, a6, a7 - ){ - return fn.apply(this, arguments) - } - case 9: - return function ( - a0, a1, a2, a3, a4, a5, a6, a7, a8 - ){ - return fn.apply(this, arguments) - } - case 10: - return function ( - a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 - ){ - return fn.apply(this, arguments) - } - default: - throw new Error('First argument to _arity must be a non-negative integer no greater than ten') - } -} - export function _pipe(f, g){ return function (){ return g.call(this, f.apply(this, arguments)) diff --git a/yarn.lock b/yarn.lock index b3ec98f3..2d5f24e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1438,13 +1438,6 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== -"@types/ramda@0.29.1": - version "0.29.1" - resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.29.1.tgz#c3d3842b9bc4aa5fbe03e90faa0c3eff9ba0f9f4" - integrity sha512-Ff5RRG9YRqMgWOqZVVavSjGEvYHUnXnGF0YPGbzIWhB3o8qiccSJZlFX2z8qm3G1H/IC5w0ozHmlezUeQCtGfQ== - dependencies: - types-ramda "^0.29.2" - "@types/resolve@1.20.2": version "1.20.2" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975" @@ -2312,6 +2305,13 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== +fast-check@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.11.0.tgz#bb3f7877c5ba7940b17f983afc412e4241b5aaee" + integrity sha512-H2tctb7AGfFQfz+DEr3UWhJ3s47LXsGp5g3jeJr5tHjnf4xUvpArIqiwcDmL2EXiv+auLHIpF5MqaIpIKvpxiA== + dependencies: + pure-rand "^6.0.0" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -4434,7 +4434,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -types-ramda@^0.29.2: +types-ramda@0.29.2: version "0.29.2" resolved "https://registry.yarnpkg.com/types-ramda/-/types-ramda-0.29.2.tgz#2bf33863a51498b43f616cd8cd98227efe9109eb" integrity sha512-HpLcR0ly2EfXQwG8VSI5ov6ml7PvtT+u+cp+7lZLu7q4nhnPDVW+rUTC1uy/SNs4aAyTUXri5M/LyhgvjEXJDg==