@@ -4103,6 +4103,8 @@ function parseRegex(maybeRegex){
41034103export function equals(a, b){
41044104 if (arguments.length === 1) return _b => equals(a, _b)
41054105
4106+ if (Object.is(a, b)) return true
4107+
41064108 const aType = type(a)
41074109
41084110 if (aType !== type(b)) return false
@@ -4507,7 +4509,7 @@ describe('brute force', () => {
45074509{
45084510 "ERRORS_MESSAGE_MISMATCH": 0,
45094511 "ERRORS_TYPE_MISMATCH": 0,
4510- "RESULTS_MISMATCH": 8 ,
4512+ "RESULTS_MISMATCH": 0 ,
45114513 "SHOULD_NOT_THROW": 0,
45124514 "SHOULD_THROW": 0,
45134515 "TOTAL_TESTS": 289,
@@ -7025,6 +7027,12 @@ export function isEmpty(input){
70257027 return false
70267028 if (!input) return true
70277029
7030+ if (type(input.isEmpty) === 'Function') {
7031+ return input.isEmpty();
7032+ } else if (input.isEmpty) {
7033+ return !!input.isEmpty;
7034+ }
7035+
70287036 if (inputType === 'Object'){
70297037 return Object.keys(input).length === 0
70307038 }
@@ -7059,6 +7067,10 @@ test('happy', () => {
70597067 expect(isEmpty(0)).toBeFalse()
70607068 expect(isEmpty(NaN)).toBeFalse()
70617069 expect(isEmpty([ '' ])).toBeFalse()
7070+ expect(isEmpty({ isEmpty: false})).toBeFalse()
7071+ expect(isEmpty({ isEmpty: () => false})).toBeFalse()
7072+ expect(isEmpty({ isEmpty: true})).toBeTrue()
7073+ expect(isEmpty({ isEmpty: () => true})).toBeTrue()
70627074})
70637075```
70647076
@@ -9831,7 +9843,7 @@ test('fallback to R.mapFastAsync', async () => {
98319843
98329844```typescript
98339845
9834- mapToObject<T, U>(fn: (input: T) => object |false, list: T[]): U
9846+ mapToObject<T, U extends object >(fn: (input: T) => U |false, list: readonly T[]): U
98359847```
98369848
98379849This method allows to generate an object from a list using input function `fn`.
@@ -9952,7 +9964,7 @@ test('bad path', () => {
99529964
99539965```typescript
99549966
9955- mapToObjectAsync<T, U>(fn: (input: T) => Promise<object |false>, list: T[]): Promise<U>
9967+ mapToObjectAsync<T, U extends object >(fn: (input: T) => Promise<U |false>, list: readonly T[]): Promise<U>
99569968```
99579969
99589970Asynchronous version of `R.mapToObject`
@@ -10371,222 +10383,10 @@ test('with empty array', () => {
1037110383
1037210384### memoize
1037310385
10374- ```typescript
10375-
10376- memoize<T, K extends any[]>(fn: (...inputs: K) => T): (...inputs: K) => T
10377- ```
10378-
1037910386When `fn` is called for a second time with the same input, then the cache result is returned instead of calling again `fn`.
1038010387
10381- ```javascript
10382- let result = 0
10383- const fn = (a,b) =>{
10384- result++
10385-
10386- return a + b
10387- }
10388- const memoized = R.memoize(fn)
10389- memoized(1, 2)
10390- memoized(1, 2)
10391-
10392- // => `result` is equal to `1`
10393- ```
10394-
1039510388<a title="redirect to Rambda Repl site" href="https://rambda.now.sh?let%20result%20%3D%200%0Aconst%20fn%20%3D%20(a%2Cb)%20%3D%3E%7B%0A%20%20result%2B%2B%0A%0A%20%20return%20a%20%2B%20b%0A%7D%0Aconst%20memoized%20%3D%20R.memoize(fn)%0Amemoized(1%2C%202)%0Amemoized(1%2C%202)%0Aconst%20result%20%3D%20%0A%2F%2F%20%3D%3E%20%60result%60%20is%20equal%20to%20%601%60">Try this <strong>R.memoize</strong> example in Rambda REPL</a>
1039610389
10397- <details>
10398-
10399- <summary><strong>R.memoize</strong> source</summary>
10400-
10401- ```javascript
10402- import { compose } from './compose.js'
10403- import { map } from './map.js'
10404- import { replace } from './replace.js'
10405- import { sort } from './sort.js'
10406- import { take } from './take.js'
10407- import { type } from './type.js'
10408-
10409- const cache = {}
10410-
10411- const normalizeObject = obj => {
10412- const sortFn = (a, b) => a > b ? 1 : -1
10413- const willReturn = {}
10414- compose(map(prop => willReturn[ prop ] = obj[ prop ]),
10415- sort(sortFn))(Object.keys(obj))
10416-
10417- return willReturn
10418- }
10419-
10420- const stringify = a => {
10421- const aType = type(a)
10422- if (aType === 'String'){
10423- return a
10424- } else if ([ 'Function', 'Promise' ].includes(aType)){
10425- const compacted = replace(
10426- /\s{1,}/g, ' ', a.toString()
10427- )
10428-
10429- return replace(
10430- /\s/g, '_', take(15, compacted)
10431- )
10432- } else if (aType === 'Object'){
10433- return JSON.stringify(normalizeObject(a))
10434- }
10435-
10436- return JSON.stringify(a)
10437- }
10438-
10439- const generateProp = (fn, ...inputArguments) => {
10440- let propString = ''
10441- inputArguments.forEach(inputArgument => {
10442- propString += `${ stringify(inputArgument) }_`
10443- })
10444-
10445- return `${ propString }${ stringify(fn) }`
10446- }
10447- // with weakmaps
10448- export function memoize(fn, ...inputArguments){
10449- if (arguments.length === 1){
10450- return (...inputArgumentsHolder) => memoize(fn, ...inputArgumentsHolder)
10451- }
10452-
10453- const prop = generateProp(fn, ...inputArguments)
10454- if (prop in cache) return cache[ prop ]
10455-
10456- if (type(fn) === 'Async'){
10457- return new Promise(resolve => {
10458- fn(...inputArguments).then(result => {
10459- cache[ prop ] = result
10460- resolve(result)
10461- })
10462- })
10463- }
10464-
10465- const result = fn(...inputArguments)
10466- cache[ prop ] = result
10467-
10468- return result
10469- }
10470- ```
10471-
10472- </details>
10473-
10474- <details>
10475-
10476- <summary><strong>Tests</strong></summary>
10477-
10478- ```javascript
10479- import { memoize } from './memoize.js'
10480-
10481- test('memoize function without input arguments', () => {
10482- const fn = () => 4
10483- const memoized = memoize(fn)
10484- expect(typeof memoized()).toBe('function')
10485- })
10486-
10487- test('happy', () => {
10488- let counter = 0
10489-
10490- const fn = ({ a, b, c }) => {
10491- counter++
10492-
10493- return a + b - c
10494- }
10495- const memoized = memoize(fn)
10496- expect(memoized({
10497- a : 1,
10498- c : 3,
10499- b : 2,
10500- })).toBe(0)
10501- expect(counter).toBe(1)
10502- expect(memoized({
10503- c : 3,
10504- a : 1,
10505- b : 2,
10506- })).toBe(0)
10507- expect(counter).toBe(1)
10508- })
10509-
10510- test('normal function', () => {
10511- let counter = 0
10512- const fn = (a, b) => {
10513- counter++
10514-
10515- return a + b
10516- }
10517- const memoized = memoize(fn)
10518- expect(memoized(1, 2)).toBe(3)
10519- expect(memoized(1, 2)).toBe(3)
10520- expect(memoized(1, 2)).toBe(3)
10521- expect(counter).toBe(1)
10522- expect(memoized(2, 2)).toBe(4)
10523- expect(counter).toBe(2)
10524- expect(memoized(1, 2)).toBe(3)
10525- expect(counter).toBe(2)
10526- })
10527-
10528- test('async function', async () => {
10529- let counter = 0
10530- const delay = ms =>
10531- new Promise(resolve => {
10532- setTimeout(resolve, ms)
10533- })
10534- const fn = async (
10535- ms, a, b
10536- ) => {
10537- await delay(ms)
10538- counter++
10539-
10540- return a + b
10541- }
10542-
10543- const memoized = memoize(fn)
10544- await expect(memoized(
10545- 100, 1, 2
10546- )).resolves.toBe(3)
10547- await expect(memoized(
10548- 100, 1, 2
10549- )).resolves.toBe(3)
10550- await expect(memoized(
10551- 100, 1, 2
10552- )).resolves.toBe(3)
10553- expect(counter).toBe(1)
10554- await expect(memoized(
10555- 100, 2, 2
10556- )).resolves.toBe(4)
10557- expect(counter).toBe(2)
10558- await expect(memoized(
10559- 100, 1, 2
10560- )).resolves.toBe(3)
10561- expect(counter).toBe(2)
10562- })
10563-
10564- test('string as argument', () => {
10565- let count = 0
10566- const foo = 'foo'
10567- const tester = memoize(n => {
10568- count++
10569-
10570- return `${ n }bar`
10571- })
10572- tester(foo)
10573- tester(foo)
10574- tester(foo)
10575-
10576- expect(tester(foo)).toBe('foobar')
10577-
10578- expect(count).toBe(1)
10579-
10580- tester('baz')
10581-
10582- expect(tester('baz')).toBe('bazbar')
10583-
10584- expect(count).toBe(2)
10585- })
10586- ```
10587-
10588- </details>
10589-
1059010390[](#memoize)
1059110391
1059210392### memoizeWith
@@ -11919,7 +11719,7 @@ This method is also known as P combinator.
1191911719
1192011720```typescript
1192111721
11922- once<T extends AnyFunction>(func : T): T
11722+ once<T extends AnyFunction, C = unknown>(fn : T, context?: C ): T
1192311723```
1192411724
1192511725It returns a function, which invokes only once `fn` function.
@@ -11999,6 +11799,17 @@ test('happy path', () => {
1199911799 )).toBe(60)
1200011800 expect(addOneOnce(40)).toBe(60)
1200111801})
11802+
11803+ test('with context', () => {
11804+ const context = { name: 'fris' }
11805+ const getNameOnce = once(function (){
11806+ return this.name
11807+ }, context)
11808+
11809+ expect(getNameOnce()).toBe('fris')
11810+ expect(getNameOnce()).toBe('fris')
11811+ expect(getNameOnce()).toBe('fris')
11812+ })
1200211813```
1200311814
1200411815</details>
@@ -18138,13 +17949,17 @@ const result = [
1813817949<summary><strong>R.unless</strong> source</summary>
1813917950
1814017951```javascript
18141- export function unless(predicate, whenFalse){
18142- if (arguments.length === 1){
18143- return _whenFalse => unless(predicate, _whenFalse)
18144- }
17952+ import { curry } from './curry.js'
1814517953
18146- return input => predicate(input) ? input : whenFalse(input)
17954+ function unlessFn(
17955+ predicate, whenFalseFn, input
17956+ ){
17957+ if (predicate(input)) return input
17958+
17959+ return whenFalseFn(input)
1814717960}
17961+
17962+ export const unless = curry(unlessFn)
1814817963```
1814917964
1815017965</details>
@@ -18168,6 +17983,11 @@ test('curried', () => {
1816817983 const safeIncCurried = unless(isNil)(inc)
1816917984 expect(safeIncCurried(null)).toBeNull()
1817017985})
17986+
17987+ test('with 3 inputs', () => {
17988+ let result = unless(x => x.startsWith('/'), x=> x.concat('/'), '/api')
17989+ expect(result).toBe('/api')
17990+ })
1817117991```
1817217992
1817317993</details>
@@ -19554,6 +19374,12 @@ test('when second list is longer', () => {
1955419374
1955519375## ❯ CHANGELOG
1955619376
19377+ 11.1.0
19378+
19379+ - Improve `R.mapToObject` types - [Issue #96](https://github.com/selfrefactor/rambdax/issues/96)
19380+
19381+ - Sync with `Rambda` version `9.2.0`
19382+
195571938311.0.0
1955819384
1955919385- Sync with `Rambda` version `9.1.0`
0 commit comments