From 87a1455f07073c29f0b49fc8a86fb1192ae40496 Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Wed, 19 Jul 2023 14:33:53 +0300 Subject: [PATCH 1/8] feat: new methods base --- files/index.d.ts | 126 +++++++++++++++++++++++++++++++++++++ source/binary.js | 7 +++ source/binary.spec.js | 32 ++++++++++ source/call.js | 7 +++ source/call.spec.js | 35 +++++++++++ source/collectBy.js | 7 +++ source/collectBy.spec.js | 58 +++++++++++++++++ source/comparator.js | 7 +++ source/comparator.spec.js | 21 +++++++ source/composeWith.js | 7 +++ source/composeWith.spec.js | 58 +++++++++++++++++ source/construct.js | 7 +++ source/construct.spec.js | 77 +++++++++++++++++++++++ source/constructN.js | 7 +++ source/constructN.spec.js | 63 +++++++++++++++++++ 15 files changed, 519 insertions(+) create mode 100644 source/binary.js create mode 100644 source/binary.spec.js create mode 100644 source/call.js create mode 100644 source/call.spec.js create mode 100644 source/collectBy.js create mode 100644 source/collectBy.spec.js create mode 100644 source/comparator.js create mode 100644 source/comparator.spec.js create mode 100644 source/composeWith.js create mode 100644 source/composeWith.spec.js create mode 100644 source/construct.js create mode 100644 source/construct.spec.js create mode 100644 source/constructN.js create mode 100644 source/constructN.spec.js diff --git a/files/index.d.ts b/files/index.d.ts index 78d6a483..2acf6df3 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -5458,6 +5458,132 @@ 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(x: T): T; + +/* +Method: call + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function call(x: T): T; + +/* +Method: collectBy + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function collectBy(x: T): T; + +/* +Method: comparator + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function comparator(x: T): T; + +/* +Method: composeWith + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function composeWith(x: T): T; + +/* +Method: construct + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function construct(x: T): T; + +/* +Method: constructN + +Explanation: + +Example: + +``` +``` + +Categories: + +Notes: + +*/ +// @SINGLE_MARKER +export function constructN(x: T): T; + // RAMBDAX_MARKER_START /* diff --git a/source/binary.js b/source/binary.js new file mode 100644 index 00000000..35ed0f30 --- /dev/null +++ b/source/binary.js @@ -0,0 +1,7 @@ +export function binary(foo, bar) { + if (arguments.length === 1){ + return (_bar) => binary(foo, _bar); + } + + return +} \ No newline at end of file diff --git a/source/binary.spec.js b/source/binary.spec.js new file mode 100644 index 00000000..77da47b5 --- /dev/null +++ b/source/binary.spec.js @@ -0,0 +1,32 @@ +import { binary } from './binary' +import { binary as binaryRamda } from 'ramda' + +test('happy', () => { + const result = binary() + console.log(result) +}) + +/* +var R = require('../source/index.js'); +var eq = require('./shared/eq.js'); + + +describe('binary', function() { + it('turns multiple-argument function into binary one', function() { + R.binary(function(x, y, z) { + eq(arguments.length, 2); + eq(typeof z, 'undefined'); + })(10, 20, 30); + }); + + it('initial arguments are passed through normally', function() { + R.binary(function(x, y, z) { + eq(x, 10); + eq(y, 20); + void z; + })(10, 20, 30); + }); + +}); + +*/ \ No newline at end of file diff --git a/source/call.js b/source/call.js new file mode 100644 index 00000000..9b031f12 --- /dev/null +++ b/source/call.js @@ -0,0 +1,7 @@ +export function call(foo, bar) { + if (arguments.length === 1){ + return (_bar) => call(foo, _bar); + } + + return +} \ No newline at end of file diff --git a/source/call.spec.js b/source/call.spec.js new file mode 100644 index 00000000..23b0ca97 --- /dev/null +++ b/source/call.spec.js @@ -0,0 +1,35 @@ +import { call } from './call' +import { call as callRamda } from 'ramda' + +test('happy', () => { + const result = call() + console.log(result) +}) + +/* +var R = require('../source/index.js'); +var eq = require('./shared/eq.js'); + + +describe('call', function() { + it('returns the result of calling its first argument with the remaining arguments', function() { + eq(R.call(Math.max, 1, 2, 3, -99, 42, 6, 7), 42); + }); + + it('accepts one or more arguments', function() { + var fn = function() { return arguments.length; }; + eq(R.call(fn), 0); + eq(R.call(fn, 'x'), 1); + eq(R.call(fn, 'x', 'y'), 2); + eq(R.call(fn, 'x', 'y', 'z'), 3); + }); + + it('provides no way to specify context', function() { + var obj = {method: function() { return this === obj; }}; + eq(R.call(obj.method), false); + eq(R.call(R.bind(obj.method, obj)), true); + }); + +}); + +*/ \ No newline at end of file diff --git a/source/collectBy.js b/source/collectBy.js new file mode 100644 index 00000000..9a1a78ba --- /dev/null +++ b/source/collectBy.js @@ -0,0 +1,7 @@ +export function collectBy(foo, bar) { + if (arguments.length === 1){ + return (_bar) => collectBy(foo, _bar); + } + + return +} \ No newline at end of file diff --git a/source/collectBy.spec.js b/source/collectBy.spec.js new file mode 100644 index 00000000..9916daae --- /dev/null +++ b/source/collectBy.spec.js @@ -0,0 +1,58 @@ +import { collectBy } from './collectBy' +import { collectBy as collectByRamda } from 'ramda' + +test('happy', () => { + const result = collectBy() + console.log(result) +}) + +/* +var {all, compose , difference , equals , head , identity , is , isEmpty , length , uniq , unnest , collectBy} = require('../source/index.js'); +var fc = require('fast-check'); +var {spy} = require('sinon'); + +describe('collectBy', function() { + + it('returns a list of lists', function() { + fc.assert(fc.property(fc.array(fc.nat()), function(xs) { + var check = all(is(Array)); + var ys = collectBy(identity)(xs); + return check(ys); + })); + }); + + it('groups items but neither adds new ones nor removes any', function() { + fc.assert(fc.property(fc.array(fc.nat()), function(xs) { + var check = compose(isEmpty, difference(xs), unnest); + var ys = collectBy(identity)(xs); + return check(ys); + })); + }); + + it('groups related items together', function() { + fc.assert(fc.property(fc.array(fc.boolean()), function(xs) { + var ys = collectBy(identity)(xs); + var check = all(compose(equals(1), length, uniq)); + return check(ys); + })); + }); + + it('invokes the tag function for each item in the list', function() { + fc.assert(fc.property(fc.array(fc.nat()), function(xs) { + var id = spy(x => 42); + collectBy(id)(xs); + var check = compose(isEmpty, difference(xs)); + return check(id.getCalls().map(call => call.args[0])); + })); + }); + + it('groups items according to the tag value', function() { + fc.assert(fc.property(fc.array(fc.nat()), function(xs) { + var ys = collectBy(x => 42)(xs); + var check = compose(isEmpty, difference(xs), head); + return isEmpty(xs) && isEmpty(ys) ? true : check(ys); + })); + }); +}); + +*/ \ No newline at end of file diff --git a/source/comparator.js b/source/comparator.js new file mode 100644 index 00000000..3d20d1ee --- /dev/null +++ b/source/comparator.js @@ -0,0 +1,7 @@ +export function comparator(foo, bar) { + if (arguments.length === 1){ + return (_bar) => comparator(foo, _bar); + } + + return +} \ No newline at end of file diff --git a/source/comparator.spec.js b/source/comparator.spec.js new file mode 100644 index 00000000..2f5aafd9 --- /dev/null +++ b/source/comparator.spec.js @@ -0,0 +1,21 @@ +import { comparator } from './comparator' +import { comparator as comparatorRamda } from 'ramda' + +test('happy', () => { + const result = comparator() + console.log(result) +}) + +/* +var R = require('../source/index.js'); +var eq = require('./shared/eq.js'); + + +describe('comparator', function() { + it('builds a comparator function for sorting out of a simple predicate that reports whether the first param is smaller', function() { + eq([3, 1, 8, 1, 2, 5].sort(R.comparator(function(a, b) {return a < b;})), [1, 1, 2, 3, 5, 8]); + }); + +}); + +*/ \ No newline at end of file diff --git a/source/composeWith.js b/source/composeWith.js new file mode 100644 index 00000000..fbe714ef --- /dev/null +++ b/source/composeWith.js @@ -0,0 +1,7 @@ +export function composeWith(foo, bar) { + if (arguments.length === 1){ + return (_bar) => composeWith(foo, _bar); + } + + return +} \ No newline at end of file diff --git a/source/composeWith.spec.js b/source/composeWith.spec.js new file mode 100644 index 00000000..e009cf69 --- /dev/null +++ b/source/composeWith.spec.js @@ -0,0 +1,58 @@ +import { composeWith } from './composeWith' +import { composeWith as composeWithRamda } from 'ramda' + +test('happy', () => { + const result = composeWith() + console.log(result) +}) + +/* +var R = require('../source/index.js'); +var eq = require('./shared/eq.js'); + + +describe('composeWith', function() { + + it('performs right-to-left function composition with function applying', function() { + // f :: (String, Number?) -> ([Number] -> [Number]) + var f = R.composeWith(function(f, res) { + return f(res); + })([R.map, R.multiply, parseInt]); + + eq(f.length, 2); + eq(f('10')([1, 2, 3]), [10, 20, 30]); + eq(f('10', 2)([1, 2, 3]), [2, 4, 6]); + }); + + it('performs right-to-left function while not nil result', function() { + var isOdd = R.flip(R.modulo)(2); + var composeWhenNotNil = R.composeWith(function(f, res) { + return R.isNil(res) ? null : f(res); + }); + + var f = composeWhenNotNil([R.inc, R.ifElse(isOdd, R.identity, R.always(null)), parseInt]); + + eq(f.length, 2); + eq(f('1'), 2); + eq(f('2'), null); + }); + + it('performs right-to-left function using promise chaining', function() { + var then = function(f, p) { return p.then(f); }; + var composeP = R.composeWith(then); + var toListPromise = function(a) { return new Promise(function(res) { res([a]); }); }; + var doubleListPromise = function(a) { return new Promise(function(res) { res(R.concat(a, a)); }); }; + var f = composeP([ + doubleListPromise, + toListPromise + ]); + + return f(1) + .then(function(res) { + eq(res, [1, 1]); + }); + }); + +}); + +*/ \ No newline at end of file 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 From 9964790554a4246c9b22abea8c24f5ec350b089a Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Wed, 19 Jul 2023 17:35:47 +0300 Subject: [PATCH 2/8] binary --- files/index.d.ts | 2 +- rambda.js | 6 +++--- source/binary-spec.ts | 14 ++++++++++++++ source/binary.js | 10 ++++------ source/binary.spec.js | 43 ++++++++++++++----------------------------- 5 files changed, 36 insertions(+), 39 deletions(-) create mode 100644 source/binary-spec.ts diff --git a/files/index.d.ts b/files/index.d.ts index 2acf6df3..47092ad9 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -5474,7 +5474,7 @@ Notes: */ // @SINGLE_MARKER -export function binary(x: T): T; +export function binary any>(fn: T): (...args: any[]) => ReturnType; /* Method: call diff --git a/rambda.js b/rambda.js index de648510..2c32a4a8 100644 --- a/rambda.js +++ b/rambda.js @@ -1,6 +1,4 @@ /// -export * from './src/F.js' -export * from './src/T.js' export * from './src/add.js' export * from './src/addIndex.js' export * from './src/addIndexRight.js' @@ -52,6 +50,7 @@ export * from './src/endsWith.js' export * from './src/eqProps.js' export * from './src/equals.js' export * from './src/evolve.js' +export * from './src/F.js' export * from './src/filter.js' export * from './src/find.js' export * from './src/findIndex.js' @@ -137,8 +136,8 @@ export * from './src/prop.js' export * from './src/propEq.js' export * from './src/propIs.js' export * from './src/propOr.js' -export * from './src/propSatisfies.js' export * from './src/props.js' +export * from './src/propSatisfies.js' export * from './src/range.js' export * from './src/reduce.js' export * from './src/reject.js' @@ -157,6 +156,7 @@ export * from './src/startsWith.js' export * from './src/subtract.js' export * from './src/sum.js' export * from './src/symmetricDifference.js' +export * from './src/T.js' export * from './src/tail.js' export * from './src/take.js' export * from './src/takeLast.js' 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 index 35ed0f30..d98f4aae 100644 --- a/source/binary.js +++ b/source/binary.js @@ -1,7 +1,5 @@ -export function binary(foo, bar) { - if (arguments.length === 1){ - return (_bar) => binary(foo, _bar); - } +export function binary(fn){ + if (fn.length <= 2) return fn - return -} \ No newline at end of file + return (a, b) => fn(a, b) +} diff --git a/source/binary.spec.js b/source/binary.spec.js index 77da47b5..f3f53019 100644 --- a/source/binary.spec.js +++ b/source/binary.spec.js @@ -1,32 +1,17 @@ -import { binary } from './binary' -import { binary as binaryRamda } from 'ramda' +import { binary } from './binary.js' test('happy', () => { - const result = binary() - console.log(result) -}) - -/* -var R = require('../source/index.js'); -var eq = require('./shared/eq.js'); - - -describe('binary', function() { - it('turns multiple-argument function into binary one', function() { - R.binary(function(x, y, z) { - eq(arguments.length, 2); - eq(typeof z, 'undefined'); - })(10, 20, 30); - }); + const result = binary(function ( + x, y, z + ){ + expect(arguments).toHaveLength(2) + expect(z).toBeUndefined() + expect(x).toBe(10) + expect(y).toBe(20) - it('initial arguments are passed through normally', function() { - R.binary(function(x, y, z) { - eq(x, 10); - eq(y, 20); - void z; - })(10, 20, 30); - }); - -}); - -*/ \ No newline at end of file + return x + y + })( + 10, 20, 30 + ) + expect(result).toBe(30) +}) From 957554f469b8c9788256b6fe161924804fbd9789 Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Thu, 20 Jul 2023 10:00:14 +0300 Subject: [PATCH 3/8] feat: fix issue 93 --- NEXT_VERSION_CHECKLIST.md | 1 + files/index.d.ts | 15 ++++----------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/NEXT_VERSION_CHECKLIST.md b/NEXT_VERSION_CHECKLIST.md index 77860ae1..01843bb8 100644 --- a/NEXT_VERSION_CHECKLIST.md +++ b/NEXT_VERSION_CHECKLIST.md @@ -1,3 +1,4 @@ +fix https://github.com/selfrefactor/rambdax/issues/93 --- - binary - call diff --git a/files/index.d.ts b/files/index.d.ts index 47092ad9..89719e69 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -3281,17 +3281,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 From 4f552bacf6bdc0a0a44b3295a405cc8a4633943f Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Sat, 22 Jul 2023 13:44:56 +0300 Subject: [PATCH 4/8] r.call --- NEXT_VERSION_CHECKLIST.md | 6 ++++- files/index.d.ts | 2 +- source/call.js | 8 +----- source/call.spec.js | 57 +++++++++++++++++++-------------------- 4 files changed, 34 insertions(+), 39 deletions(-) diff --git a/NEXT_VERSION_CHECKLIST.md b/NEXT_VERSION_CHECKLIST.md index 01843bb8..f6eb4902 100644 --- a/NEXT_VERSION_CHECKLIST.md +++ b/NEXT_VERSION_CHECKLIST.md @@ -1,6 +1,10 @@ fix https://github.com/selfrefactor/rambdax/issues/93 ---- + +release X + - binary + +--- - call - collectBy - comparator diff --git a/files/index.d.ts b/files/index.d.ts index 89719e69..de35728a 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -5485,7 +5485,7 @@ Notes: */ // @SINGLE_MARKER -export function call(x: T): T; +export function call any>(fn: T, ...args: Parameters): ReturnType; /* Method: collectBy diff --git a/source/call.js b/source/call.js index 9b031f12..8a35bed7 100644 --- a/source/call.js +++ b/source/call.js @@ -1,7 +1 @@ -export function call(foo, bar) { - if (arguments.length === 1){ - return (_bar) => call(foo, _bar); - } - - return -} \ No newline at end of file +export const call = (fn, ...inputs) => fn(...inputs) diff --git a/source/call.spec.js b/source/call.spec.js index 23b0ca97..ed8412e1 100644 --- a/source/call.spec.js +++ b/source/call.spec.js @@ -1,35 +1,32 @@ -import { call } from './call' -import { call as callRamda } from 'ramda' +import { bind } from './bind.js' +import { call } from './call.js' test('happy', () => { - const result = call() - console.log(result) + expect(call( + Math.max, 1, 2, 3, -99, 42, 6, 7 + )).toBe(42) }) -/* -var R = require('../source/index.js'); -var eq = require('./shared/eq.js'); - - -describe('call', function() { - it('returns the result of calling its first argument with the remaining arguments', function() { - eq(R.call(Math.max, 1, 2, 3, -99, 42, 6, 7), 42); - }); - - it('accepts one or more arguments', function() { - var fn = function() { return arguments.length; }; - eq(R.call(fn), 0); - eq(R.call(fn, 'x'), 1); - eq(R.call(fn, 'x', 'y'), 2); - eq(R.call(fn, 'x', 'y', 'z'), 3); - }); - - it('provides no way to specify context', function() { - var obj = {method: function() { return this === obj; }}; - eq(R.call(obj.method), false); - eq(R.call(R.bind(obj.method, obj)), true); - }); - -}); +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) +}) -*/ \ No newline at end of file +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) +}) From fb0f6b6e0d9357e01d36d3416e8237925bf871b3 Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Sun, 23 Jul 2023 11:58:47 +0300 Subject: [PATCH 5/8] collectBy --- NEXT_VERSION_CHECKLIST.md | 2 +- files/index.d.ts | 3 +- package.json | 1 + source/collectBy.js | 28 +++++++-- source/collectBy.spec.js | 120 +++++++++++++++++++++----------------- yarn.lock | 16 ++--- 6 files changed, 101 insertions(+), 69 deletions(-) diff --git a/NEXT_VERSION_CHECKLIST.md b/NEXT_VERSION_CHECKLIST.md index f6eb4902..608e9f65 100644 --- a/NEXT_VERSION_CHECKLIST.md +++ b/NEXT_VERSION_CHECKLIST.md @@ -3,9 +3,9 @@ fix https://github.com/selfrefactor/rambdax/issues/93 release X - binary +- call --- -- call - collectBy - comparator - composeWith diff --git a/files/index.d.ts b/files/index.d.ts index de35728a..24ac3771 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -5503,7 +5503,8 @@ Notes: */ // @SINGLE_MARKER -export function collectBy(x: T): T; +export function collectBy(keyFn: (value: T) => K, list: T[]): T[][]; +export function collectBy(keyFn: (value: T) => K): (list: T[]) => T[][]; /* Method: comparator 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/source/collectBy.js b/source/collectBy.js index 9a1a78ba..26f5a8e7 100644 --- a/source/collectBy.js +++ b/source/collectBy.js @@ -1,7 +1,27 @@ -export function collectBy(foo, bar) { +import { reduce } from './reduce.js' + +export function collectBy(fn, list){ if (arguments.length === 1){ - return (_bar) => collectBy(foo, _bar); + 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 -} \ No newline at end of file + return newList +} diff --git a/source/collectBy.spec.js b/source/collectBy.spec.js index 9916daae..0ab34d1b 100644 --- a/source/collectBy.spec.js +++ b/source/collectBy.spec.js @@ -1,58 +1,68 @@ -import { collectBy } from './collectBy' -import { collectBy as collectByRamda } from 'ramda' +import fc from 'fast-check' +import { + all, + compose, + difference, + equals, + head, + identity, + is, + isEmpty, + length, + uniq, + unnest, +} from 'rambdax' -test('happy', () => { - const result = collectBy() - console.log(result) +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) + })) }) -/* -var {all, compose , difference , equals , head , identity , is , isEmpty , length , uniq , unnest , collectBy} = require('../source/index.js'); -var fc = require('fast-check'); -var {spy} = require('sinon'); - -describe('collectBy', function() { - - it('returns a list of lists', function() { - fc.assert(fc.property(fc.array(fc.nat()), function(xs) { - var check = all(is(Array)); - var ys = collectBy(identity)(xs); - return check(ys); - })); - }); - - it('groups items but neither adds new ones nor removes any', function() { - fc.assert(fc.property(fc.array(fc.nat()), function(xs) { - var check = compose(isEmpty, difference(xs), unnest); - var ys = collectBy(identity)(xs); - return check(ys); - })); - }); - - it('groups related items together', function() { - fc.assert(fc.property(fc.array(fc.boolean()), function(xs) { - var ys = collectBy(identity)(xs); - var check = all(compose(equals(1), length, uniq)); - return check(ys); - })); - }); - - it('invokes the tag function for each item in the list', function() { - fc.assert(fc.property(fc.array(fc.nat()), function(xs) { - var id = spy(x => 42); - collectBy(id)(xs); - var check = compose(isEmpty, difference(xs)); - return check(id.getCalls().map(call => call.args[0])); - })); - }); - - it('groups items according to the tag value', function() { - fc.assert(fc.property(fc.array(fc.nat()), function(xs) { - var ys = collectBy(x => 42)(xs); - var check = compose(isEmpty, difference(xs), head); - return isEmpty(xs) && isEmpty(ys) ? true : check(ys); - })); - }); -}); - -*/ \ No newline at end of file +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/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== From 9e30277af913b9962b9260791a321a82435ed21a Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Sun, 23 Jul 2023 12:49:36 +0300 Subject: [PATCH 6/8] comparator --- NEXT_VERSION_CHECKLIST.md | 2 +- files/index.d.ts | 2 +- source/comparator.js | 10 ++++------ source/comparator.spec.js | 22 ++++------------------ 4 files changed, 10 insertions(+), 26 deletions(-) diff --git a/NEXT_VERSION_CHECKLIST.md b/NEXT_VERSION_CHECKLIST.md index 608e9f65..9bbb21e3 100644 --- a/NEXT_VERSION_CHECKLIST.md +++ b/NEXT_VERSION_CHECKLIST.md @@ -4,9 +4,9 @@ release X - binary - call +- collectBy --- -- collectBy - comparator - composeWith - construct diff --git a/files/index.d.ts b/files/index.d.ts index 24ac3771..1b2efb11 100644 --- a/files/index.d.ts +++ b/files/index.d.ts @@ -5522,7 +5522,7 @@ Notes: */ // @SINGLE_MARKER -export function comparator(x: T): T; +export function comparator(pred: (a: T, b: T) => boolean): (x: T, y: T) => Ordering; /* Method: composeWith diff --git a/source/comparator.js b/source/comparator.js index 3d20d1ee..ac046d02 100644 --- a/source/comparator.js +++ b/source/comparator.js @@ -1,7 +1,5 @@ -export function comparator(foo, bar) { - if (arguments.length === 1){ - return (_bar) => comparator(foo, _bar); +export function comparator(fn){ + return function (a, b){ + return fn(a, b) ? -1 : fn(b, a) ? 1 : 0 } - - return -} \ No newline at end of file +} diff --git a/source/comparator.spec.js b/source/comparator.spec.js index 2f5aafd9..9cbcb0c1 100644 --- a/source/comparator.spec.js +++ b/source/comparator.spec.js @@ -1,21 +1,7 @@ -import { comparator } from './comparator' -import { comparator as comparatorRamda } from 'ramda' +import { comparator } from './comparator.js' test('happy', () => { - const result = comparator() - console.log(result) + expect([ 3, 1, 8, 1, 2, 5 ].sort(comparator((a, b) => a < b))).toEqual([ + 1, 1, 2, 3, 5, 8, + ]) }) - -/* -var R = require('../source/index.js'); -var eq = require('./shared/eq.js'); - - -describe('comparator', function() { - it('builds a comparator function for sorting out of a simple predicate that reports whether the first param is smaller', function() { - eq([3, 1, 8, 1, 2, 5].sort(R.comparator(function(a, b) {return a < b;})), [1, 1, 2, 3, 5, 8]); - }); - -}); - -*/ \ No newline at end of file From 33e289bc11408f5f82dbc84bcbf1d50ee9bf686b Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Sun, 23 Jul 2023 16:08:27 +0300 Subject: [PATCH 7/8] compose.with --- NEXT_VERSION_CHECKLIST.md | 5 +- files/index.d.ts | 13 ++++- source/_internals/_arity.js | 64 ++++++++++++++++++++++++ source/composeWith.js | 36 ++++++++++++-- source/composeWith.spec.js | 99 +++++++++++++++++-------------------- source/curryN.js | 67 +------------------------ source/pipe.js | 68 +------------------------ 7 files changed, 159 insertions(+), 193 deletions(-) create mode 100644 source/_internals/_arity.js diff --git a/NEXT_VERSION_CHECKLIST.md b/NEXT_VERSION_CHECKLIST.md index 9bbb21e3..54b00c2d 100644 --- a/NEXT_VERSION_CHECKLIST.md +++ b/NEXT_VERSION_CHECKLIST.md @@ -1,14 +1,15 @@ fix https://github.com/selfrefactor/rambdax/issues/93 +remove ramda imports in tests release X - binary - call - collectBy - ---- - comparator - composeWith + +--- - construct - constructN diff --git a/files/index.d.ts b/files/index.d.ts index 1b2efb11..f03e5818 100644 --- a/files/index.d.ts +++ b/files/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; @@ -5540,7 +5543,15 @@ Notes: */ // @SINGLE_MARKER -export function composeWith(x: T): T; +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; /* Method: construct 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/composeWith.js b/source/composeWith.js index fbe714ef..e50762b0 100644 --- a/source/composeWith.js +++ b/source/composeWith.js @@ -1,7 +1,33 @@ -export function composeWith(foo, bar) { - if (arguments.length === 1){ - return (_bar) => composeWith(foo, _bar); +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 } - return -} \ No newline at end of file + 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 index e009cf69..bbd7e768 100644 --- a/source/composeWith.spec.js +++ b/source/composeWith.spec.js @@ -1,58 +1,51 @@ -import { composeWith } from './composeWith' -import { composeWith as composeWithRamda } from 'ramda' +import { always, identity, inc, isNil, map, modulo, multiply } from 'rambdax' +import { composeWith as composeWithRamda, concat, flip, ifElse } from 'ramda' -test('happy', () => { - const result = composeWith() - console.log(result) -}) - -/* -var R = require('../source/index.js'); -var eq = require('./shared/eq.js'); - - -describe('composeWith', function() { - - it('performs right-to-left function composition with function applying', function() { - // f :: (String, Number?) -> ([Number] -> [Number]) - var f = R.composeWith(function(f, res) { - return f(res); - })([R.map, R.multiply, parseInt]); - - eq(f.length, 2); - eq(f('10')([1, 2, 3]), [10, 20, 30]); - eq(f('10', 2)([1, 2, 3]), [2, 4, 6]); - }); +import { composeWith } from './composeWith.js' - it('performs right-to-left function while not nil result', function() { - var isOdd = R.flip(R.modulo)(2); - var composeWhenNotNil = R.composeWith(function(f, res) { - return R.isNil(res) ? null : f(res); - }); +test('performs right-to-left function composition with function applying', () => { + const f = composeWith((f, res) => f(res))([ map, multiply, parseInt ]) - var f = composeWhenNotNil([R.inc, R.ifElse(isOdd, R.identity, R.always(null)), parseInt]); - - eq(f.length, 2); - eq(f('1'), 2); - eq(f('2'), null); - }); - - it('performs right-to-left function using promise chaining', function() { - var then = function(f, p) { return p.then(f); }; - var composeP = R.composeWith(then); - var toListPromise = function(a) { return new Promise(function(res) { res([a]); }); }; - var doubleListPromise = function(a) { return new Promise(function(res) { res(R.concat(a, a)); }); }; - var f = composeP([ - doubleListPromise, - toListPromise - ]); - - return f(1) - .then(function(res) { - eq(res, [1, 1]); - }); - }); + 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() +}) -*/ \ No newline at end of file +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/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)) From 82f1a664b50d64bc6298c34dd9460cfa01fd531f Mon Sep 17 00:00:00 2001 From: Deyan Totev Date: Mon, 24 Jul 2023 20:41:22 +0300 Subject: [PATCH 8/8] prepare mr --- .github/README.md | 54 ++++++---- CHANGELOG.md | 10 ++ NEXT_VERSION_CHECKLIST.md | 9 +- README.md | 54 ++++++---- dist/rambda.js | 205 +++++++++++++++++++------------------- dist/rambda.umd.js | 2 +- files/index.d.ts | 36 ------- immutable.d.ts | 37 +++++-- index.d.ts | 37 +++++-- rambda.js | 11 +- src/_internals/_arity.js | 64 ++++++++++++ src/binary.js | 5 + src/call.js | 1 + src/collectBy.js | 27 +++++ src/comparator.js | 5 + src/composeWith.js | 33 ++++++ src/curryN.js | 67 +------------ src/pipe.js | 68 +------------ 18 files changed, 388 insertions(+), 337 deletions(-) create mode 100644 src/_internals/_arity.js create mode 100644 src/binary.js create mode 100644 src/call.js create mode 100644 src/collectBy.js create mode 100644 src/comparator.js create mode 100644 src/composeWith.js 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 54b00c2d..33ac0797 100644 --- a/NEXT_VERSION_CHECKLIST.md +++ b/NEXT_VERSION_CHECKLIST.md @@ -2,15 +2,10 @@ fix https://github.com/selfrefactor/rambdax/issues/93 remove ramda imports in tests release X - -- binary -- call -- collectBy -- comparator -- composeWith +replace missing ramda methods with text that argument is missing --- -- 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, ) => (...args: TArgs) => TResult; -/* -Method: construct - -Explanation: - -Example: - -``` -``` - -Categories: - -Notes: - -*/ -// @SINGLE_MARKER -export function construct(x: T): T; - -/* -Method: constructN - -Explanation: - -Example: - -``` -``` - -Categories: - -Notes: - -*/ -// @SINGLE_MARKER -export function constructN(x: T): T; - // 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/rambda.js b/rambda.js index 2c32a4a8..8e72dd19 100644 --- a/rambda.js +++ b/rambda.js @@ -1,4 +1,6 @@ /// +export * from './src/F.js' +export * from './src/T.js' export * from './src/add.js' export * from './src/addIndex.js' export * from './src/addIndexRight.js' @@ -18,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' @@ -50,7 +57,6 @@ export * from './src/endsWith.js' export * from './src/eqProps.js' export * from './src/equals.js' export * from './src/evolve.js' -export * from './src/F.js' export * from './src/filter.js' export * from './src/find.js' export * from './src/findIndex.js' @@ -136,8 +142,8 @@ export * from './src/prop.js' export * from './src/propEq.js' export * from './src/propIs.js' export * from './src/propOr.js' -export * from './src/props.js' export * from './src/propSatisfies.js' +export * from './src/props.js' export * from './src/range.js' export * from './src/reduce.js' export * from './src/reject.js' @@ -156,7 +162,6 @@ export * from './src/startsWith.js' export * from './src/subtract.js' export * from './src/sum.js' export * from './src/symmetricDifference.js' -export * from './src/T.js' export * from './src/tail.js' export * from './src/take.js' export * from './src/takeLast.js' 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))