From ee27342795b2122ef35f8a761492e49a9d08d85b Mon Sep 17 00:00:00 2001
From: Andrei Dumitrescu <5057797+andreidmt@users.noreply.github.com>
Date: Mon, 12 Oct 2020 15:40:08 +0200
Subject: [PATCH] refactor: Add curried versions to multiple functions
---
src/all/all.js | 25 ++--------
src/all/all.test.js | 37 +++++++++------
src/any/any.js | 25 ++--------
src/any/any.test.js | 43 ++++++-----------
src/append/append.js | 21 +++------
src/append/append.test.js | 8 +---
src/bottom/bottom.js | 37 ++++-----------
src/bottom/bottom.test.js | 3 +-
src/cases/cases.js | 4 +-
src/cases/cases.test.js | 3 +-
src/clone/clone.test.js | 1 +
src/contains/contains.js | 26 ++++++-----
src/contains/contains.test.js | 15 ++++--
src/converge/converge.test.js | 5 +-
src/curry/curry.js | 4 +-
src/curry/curry.test.js | 3 +-
src/debounce/debounce.js | 7 ++-
src/debounce/debounce.test.js | 3 +-
src/dec/dec.js | 4 +-
src/dec/dec.test.js | 3 +-
src/deep-equal/deep-equal.js | 2 +
src/deep-equal/deep-equal.test.js | 3 +-
src/distinct/distinct.test.js | 5 +-
src/drop-last/drop-last.js | 34 +++++---------
src/drop-last/drop-last.test.js | 3 +-
src/elapsed-time/elapsed-time.js | 8 ++--
src/elapsed-time/elapsed-time.test.js | 6 ++-
src/ends-with/ends-with.js | 36 ++++++++-------
src/ends-with/ends-with.test.js | 11 ++++-
src/escape/escape.js | 4 +-
src/escapeHTML/escapeHTML.js | 4 +-
src/escapeHTML/escapeHTML.test.js | 3 +-
src/escapeRegExp/escapeRegExp.js | 4 +-
src/escapeRegExp/escapeRegExp.test.js | 3 +-
src/filter/filter.js | 35 ++++++++------
src/filter/filter.test.js | 40 ++++++++++++----
src/find-index/find-index.js | 27 +++--------
src/find-index/find-index.test.js | 14 +++++-
src/find/find.js | 3 +-
src/find/find.test.js | 14 +++++-
src/first/first.js | 4 +-
src/first/first.test.js | 3 +-
src/flatten/flatten.test.js | 3 +-
src/for-each/for-each.js | 14 +-----
src/for-each/for-each.test.js | 12 +----
src/group-by/group-by.js | 36 ++++++++-------
src/group-by/group-by.test.js | 28 +++++++-----
src/gt/gt.js | 23 +++++-----
src/gt/gt.test.js | 4 +-
src/has-key/has-key.js | 11 +----
src/has-key/has-key.test.js | 14 ++++--
src/i/i.js | 4 +-
src/i/i.test.js | 5 +-
src/inc/inc.js | 4 +-
src/inc/inc.test.js | 3 +-
src/index-by/index-by.js | 34 +++++++-------
src/index-by/index-by.test.js | 3 +-
src/index.js | 10 +++-
src/intersect/intersect.js | 5 +-
src/intersect/intersect.test.js | 31 ++++++++-----
src/is-between/is-between.test.js | 3 +-
src/is-empty/is-empty.js | 6 +--
src/is-empty/is-empty.test.js | 5 +-
src/is-equal/is-equal.js | 18 +++++---
src/is-equal/is-equal.test.js | 3 +-
src/is-match/is-match.js | 32 +++++++------
src/is-match/is-match.test.js | 21 ++++++++-
src/is/is.js | 4 +-
src/is/is.test.js | 5 +-
src/join/join.js | 14 ++----
src/join/join.test.js | 15 ++----
src/keys/keys.js | 4 +-
src/keys/keys.test.js | 3 +-
src/last/last.test.js | 5 +-
src/lt/lt.js | 5 +-
src/lt/lt.test.js | 5 +-
src/map-matrix/map-matrix.js | 11 +----
src/map-matrix/map-matrix.test.js | 3 +-
src/map/map.js | 11 +----
src/map/map.test.js | 3 +-
src/max/max.js | 66 +++++++++++----------------
src/max/max.test.js | 15 ++++--
src/merge/merge.test.js | 3 +-
src/min/min.js | 58 +++++++++--------------
src/min/min.test.js | 16 +++++--
src/partition/partition.js | 27 +++--------
src/partition/partition.test.js | 9 +++-
src/pick/pick.js | 34 +++++++-------
src/pick/pick.test.js | 3 +-
src/pluck/pluck.js | 24 +++++-----
src/pluck/pluck.test.js | 5 +-
src/prepend/prepend.js | 16 ++-----
src/prepend/prepend.test.js | 1 +
src/read/read.js | 53 +++++++++++----------
src/read/read.test.js | 3 +-
src/reduce/reduce.test.js | 3 +-
src/remove/remove.js | 23 ++--------
src/remove/remove.test.js | 19 +++++---
src/repeat/repeat.js | 4 +-
src/repeat/repeat.test.js | 3 +-
src/same/same.js | 4 +-
src/same/same.test.js | 3 +-
src/sequence/sequence.test.js | 3 +-
src/starts-with/starts-with.test.js | 3 +-
src/trim/trim.js | 28 ++++++++----
src/trim/trim.test.js | 9 ++--
106 files changed, 697 insertions(+), 701 deletions(-)
diff --git a/src/all/all.js b/src/all/all.js
index f7b246a..70b68f1 100644
--- a/src/all/all.js
+++ b/src/all/all.js
@@ -1,4 +1,5 @@
import { pipe } from "../pipe/pipe"
+import { curry } from "../curry/curry"
import { isMatch } from "../is-match/is-match"
const _all = (_fn, _source) => {
@@ -14,6 +15,8 @@ const _all = (_fn, _source) => {
return true
}
+const _allWith = (subset, source) => _all(isMatch(subset), source)
+
/**
* Test if all elements of array satisfy a function
*
@@ -24,7 +27,6 @@ const _all = (_fn, _source) => {
*
* @name all
* @tag Array
- * @signature (fn: Function|Function[]) => (source: Array): Boolean
* @signature (fn: Function|Function[], source: Array): Boolean
*
* @see {@link allWith}
@@ -38,15 +40,7 @@ const _all = (_fn, _source) => {
* all(is, [1, "asd", null])
* // => false
*/
-export const all = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _all(params[0], source)
- }
-
- // @signature (fn, source)
- return _all(...params)
-}
+export const all = curry(_all)
/**
* Test if all elements in array match object
@@ -58,7 +52,6 @@ export const all = (...params) => {
*
* @name allWith
* @tag Array
- * @signature (subset: Object) => (source: Array): Boolean
* @signature (subset: Object, source: Array): Boolean
*
* @see {@link all}
@@ -73,12 +66,4 @@ export const all = (...params) => {
* allWith(is, [1, "asd", null])
* // => false
*/
-export const allWith = (...params) => {
- // @signature (subset) => (source)
- if (params.length <= 1) {
- return source => _all(isMatch(params[0]), source)
- }
-
- // @signature (subset, source)
- return _all(isMatch(params[0]), params[1])
-}
+export const allWith = curry(_allWith)
diff --git a/src/all/all.test.js b/src/all/all.test.js
index 416b3df..2b39a25 100644
--- a/src/all/all.test.js
+++ b/src/all/all.test.js
@@ -1,37 +1,48 @@
import test from "tape"
-import { all, allWith, is, get } from ".."
+import { all, allWith } from "./all"
+
+import { is } from "../is/is"
+import { read } from "../read/read"
const isEven = source => source % 2 === 0
test("all(With)", t => {
- t.equal(all(isEven)([2, 6, 4]), true, "Check all number are even (curried)")
-
- t.equal(all(isEven, [2, 6, 4]), true, "Check all number are even (uncurried)")
+ t.equal(all(isEven, [2, 6, 4]), true, "Check all number are even")
t.equal(
- all(item => is(item.id))([{}, { id: 2 }, {}]),
+ all(item => is(item.id), [{}, { id: 2 }, {}]),
false,
'Check all elements have "id" property'
)
t.equal(
- all([get("id"), is], [{}, { id: 2 }, {}]),
+ all([read("id"), is], [{}, { id: 2 }, {}]),
false,
- 'Check all elements have "id" property'
+ 'Check all elements have "id" property using pipe functions'
)
+ t.end()
+})
+
+test("allWith", t => {
t.equal(
- allWith({
- id: value => is(value),
- })([{}, { id: 2 }, {}]),
+ allWith(
+ {
+ id: value => is(value),
+ },
+ [{}, { id: 2 }, {}]
+ ),
false,
'Not all elements have "id" property via match subset'
)
t.equal(
- allWith({
- id: value => is(value),
- })([{ id: 1 }, { id: 2 }, { id: 3, name: "test" }]),
+ allWith(
+ {
+ id: value => is(value),
+ },
+ [{ id: 1 }, { id: 2 }, { id: 3, name: "test" }]
+ ),
true,
'All elements have "id" property via match subset'
)
diff --git a/src/any/any.js b/src/any/any.js
index 7d551d4..27e076f 100644
--- a/src/any/any.js
+++ b/src/any/any.js
@@ -1,4 +1,5 @@
import { pipe } from "../pipe/pipe"
+import { curry } from "../curry/curry"
import { isMatch } from "../is-match/is-match"
const _any = (_fn, _source) => {
@@ -15,6 +16,8 @@ const _any = (_fn, _source) => {
return false
}
+const _anyWith = (subset, source) => _any(isMatch(subset), source)
+
/**
* Test if at least one element in array matches predicate
*
@@ -26,7 +29,6 @@ const _any = (_fn, _source) => {
* @name any
* @alias has
* @tag Array
- * @signature (fn: Function|Function[]) => (source: Array): Boolean
* @signature (fn: Function|Function[], source: Array): Boolean
*
* @see {@link anyWith}
@@ -40,15 +42,7 @@ const _any = (_fn, _source) => {
* any([get("id"), is], [{title: ""}, {}])
* // => false
*/
-export const any = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _any(params[0], source)
- }
-
- // @signature (fn, source)
- return _any(...params)
-}
+export const any = curry(_any)
/**
* Test if at least one element in array matches object
@@ -61,7 +55,6 @@ export const any = (...params) => {
* @name anyWith
* @alias hasWith
* @tag Array
- * @signature (subset: Object) => (source: Array): Boolean
* @signature (subset: Object, source: Array): Boolean
*
* @see {@link any}
@@ -76,12 +69,4 @@ export const any = (...params) => {
* anyWith({ tags: is })([{id: 1}, {id: 2, comments: []}])
* // => false
*/
-export const anyWith = (...params) => {
- // @signature (subset) => (source)
- if (params.length <= 1) {
- return source => _any(isMatch(params[0]), source)
- }
-
- // @signature (subset, source)
- return _any(isMatch(params[0]), params[1])
-}
+export const anyWith = curry(_anyWith)
diff --git a/src/any/any.test.js b/src/any/any.test.js
index 77a1de9..b741674 100644
--- a/src/any/any.test.js
+++ b/src/any/any.test.js
@@ -1,53 +1,40 @@
import test from "tape"
-import { get, any, anyWith } from ".."
+
+import { any, anyWith } from "./any"
+import { read } from "../read/read"
const isNumber = source => Number.isFinite(source)
-test("any(With)", t => {
+test("any", t => {
t.equal(
any(1, [1, "string", NaN]),
true,
"Check any element is equal to primitive"
)
- t.equal(
- any(isNumber)([1, "string", NaN]),
- true,
- "Check any element is number (curried)"
- )
-
t.equal(
any(isNumber, [1, "string", NaN]),
true,
- "Check any element is number (uncurried)"
+ "Check any element is number"
)
t.equal(
any(
- [get("boolFlag"), item => item === true],
+ [read("boolFlag"), item => item === true],
[null, "2", { boolFlag: true }]
),
true,
- "Check any element has a field (uncurried, multiple functions)"
+ "Check any element has a field using piped functions"
)
- t.equal(any(isNumber)([null, "2", {}]), false, "Check any element is number")
+ t.equal(any(isNumber, [null, "2", {}]), false, "Check any element is number")
- t.equal(any(isNumber)(2), true, "Check non array input")
+ t.equal(any(isNumber, 2), true, "Check non array input")
- t.equal(
- anyWith({
- id: isNumber,
- name: "lorem",
- })([
- { id: "uuid", name: "lorem" },
- { id: 2, name: "foo" },
- { id: 3, name: "lorem", foo: "bar" },
- ]),
- true,
- "Array should contain object that satisfies conditions"
- )
+ t.end()
+})
+test("anyWith", t => {
t.equal(
anyWith(
{
@@ -57,11 +44,11 @@ test("any(With)", t => {
[
{ id: "uuid", name: "lorem" },
{ id: 2, name: "foo" },
- { id: "3", name: "lorem", foo: "bar" },
+ { id: 3, name: "lorem", foo: "bar" },
]
),
- false,
- "Array should not contain object that satisfies conditions"
+ true,
+ "Array should contain object that satisfies conditions"
)
t.end()
diff --git a/src/append/append.js b/src/append/append.js
index 81324a8..accb574 100644
--- a/src/append/append.js
+++ b/src/append/append.js
@@ -1,8 +1,6 @@
-const _append = (subset, source) => {
- if (subset === undefined) {
- return source
- }
+import { curry } from "../curry/curry"
+const _append = (subset, source) => {
if (Array.isArray(source)) {
return source.concat(subset)
}
@@ -18,22 +16,15 @@ const _append = (subset, source) => {
*
* @returns {Array}
*
+ * @name append
* @tag Array
- * @signature (subset: String) => (source: String) => String
* @signature (subset: String, source: String) => String
- * @signature (subset: mixed|Array) => (source: Array) => Array
* @signature (subset: mixed|Array, source: Array) => Array
*
+ * @see {@link prepend}
+ *
* @example
* append([1])([4, 5])
* // => [1, 4, 5]
*/
-export const append = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _append(params[0], source)
- }
-
- // @signature (fn, source)
- return _append(...params)
-}
+export const append = curry(_append)
diff --git a/src/append/append.test.js b/src/append/append.test.js
index ea71896..9d781c5 100644
--- a/src/append/append.test.js
+++ b/src/append/append.test.js
@@ -23,13 +23,7 @@ test("append", t => {
t.deepEquals(append(" ipsum", "lorem"), "lorem ipsum", "Append 2 strings")
- t.deepEquals(append([])([]), [], "Append 2 empty arrays")
-
- t.deepEquals(
- append()([1]),
- [1],
- "Append undefined should not change source array"
- )
+ t.deepEquals(append([], []), [], "Append 2 empty arrays")
t.end()
})
diff --git a/src/bottom/bottom.js b/src/bottom/bottom.js
index 89cf084..121570d 100644
--- a/src/bottom/bottom.js
+++ b/src/bottom/bottom.js
@@ -1,6 +1,6 @@
-import { is } from ".."
+import { is } from "../is/is"
-const bottomX = (limit, source) => {
+const _bottom = (limit, source) => {
if (
(!Array.isArray(source) && typeof source !== "string") ||
source.length <= 1
@@ -23,7 +23,6 @@ const bottomX = (limit, source) => {
*
* @tag Array
* @signature (limit: integer, source: Array): Array
- * @signature (limit: integer) => (source: Array): Array
* @signature (source: Array): Array
*
* @example
@@ -39,35 +38,17 @@ const bottomX = (limit, source) => {
* bottom(2)([1, 2, 3])
* // => [2, 3]
*/
-const bottom = (...params) => {
- /*
- * @signature (limit: integer) => (source: Array): Array
- *
- * bottom(2)([1, 2, 3, 4]) => [3, 4]
- */
+export const bottom = (...params) => {
+ // @signature (limit: Integer) => (source: Array): Array
if (params.length === 1 && typeof params[0] === "number") {
- const [limit] = params
-
- return source => bottomX(limit, source)
+ return source => _bottom(params[0], source)
}
- /*
- * @signature (source: Array): Array
- *
- * bottom([1, 2, 3, 4]) => [2, 3, 4]
- */
+ // @signature (source: Array): Array
if (params.length === 1 && typeof params[0] !== "number") {
- const [source] = params
-
- return bottomX(null, source)
+ return _bottom(null, params[0])
}
- /*
- * @signature (limit: integer, source: Array): Array
- *
- * bottom(2, [1, 2, 3, 4]) => [3, 4]
- */
- return bottomX(params[0], params[1])
+ // @signature (limit: integer, source: Array): Array
+ return _bottom(...params)
}
-
-export { bottom }
diff --git a/src/bottom/bottom.test.js b/src/bottom/bottom.test.js
index 9cc0e2d..8b8f842 100644
--- a/src/bottom/bottom.test.js
+++ b/src/bottom/bottom.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { bottom } from ".."
+
+import { bottom } from "./bottom"
test("bottom", t => {
t.deepEquals(
diff --git a/src/cases/cases.js b/src/cases/cases.js
index d483fff..0630314 100644
--- a/src/cases/cases.js
+++ b/src/cases/cases.js
@@ -25,11 +25,9 @@ import { i } from "../i/i"
* ], x => x + 1)(2)
* // => 3
*/
-const cases = ([[conditionFn, thenFn], ...rest], otherwise = i) =>
+export const cases = ([[conditionFn, thenFn], ...rest], otherwise = i) =>
when(
conditionFn,
thenFn,
rest.length === 0 ? otherwise : cases(rest, otherwise)
)
-
-export { cases }
diff --git a/src/cases/cases.test.js b/src/cases/cases.test.js
index dea1ee6..27e86f1 100644
--- a/src/cases/cases.test.js
+++ b/src/cases/cases.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { cases } from ".."
+
+import { cases } from "./cases"
test("cases", t => {
t.equal(
diff --git a/src/clone/clone.test.js b/src/clone/clone.test.js
index b2190ee..f2ab661 100644
--- a/src/clone/clone.test.js
+++ b/src/clone/clone.test.js
@@ -1,4 +1,5 @@
import test from "tape"
+
import { clone } from "./clone"
test("clone", t => {
diff --git a/src/contains/contains.js b/src/contains/contains.js
index cbfd772..972e801 100644
--- a/src/contains/contains.js
+++ b/src/contains/contains.js
@@ -1,24 +1,26 @@
+import { curry } from "../curry/curry"
+
+const _contains = (search, source) => {
+ if (search.length > source.length) {
+ return false
+ }
+
+ return source.indexOf(search) !== -1
+}
+
/**
* Test if string contains substring
*
- * @param {string} search Search string
- * @param {string} source Source string
+ * @param {string} search Search string
+ * @param {string} source Source string
*
* @return {boolean}
*
* @tag String
- * @signature (search: string) => (source: string): boolean
+ * @signature (search: string, source: string): boolean
*
* @example
* contains("ipsum")("lorem ipsum")
* // => true
*/
-const contains = search => source => {
- if (search.length > source.length) {
- return false
- }
-
- return source.indexOf(search) !== -1
-}
-
-export { contains }
+export const contains = curry(_contains)
diff --git a/src/contains/contains.test.js b/src/contains/contains.test.js
index e334c4b..b3e85a3 100644
--- a/src/contains/contains.test.js
+++ b/src/contains/contains.test.js
@@ -1,21 +1,28 @@
import test from "tape"
-import { contains } from ".."
+
+import { contains } from "./contains"
test("contains", t => {
t.equals(
contains("lorem")("lorem ipsum"),
true,
- "Search string exists in source string"
+ "Search string exists in source string - curried"
+ )
+
+ t.equals(
+ contains("lorem", "lorem ipsum"),
+ true,
+ "Search string exists in source string - uncurried"
)
t.equals(
- contains("loremx")("lorem ipsum"),
+ contains("loremx", "lorem ipsum"),
false,
"Search string does not exist in source string"
)
t.equals(
- contains("lorem ipsum very long dolor")("lorem ipsum"),
+ contains("lorem ipsum very long dolor", "lorem ipsum"),
false,
"Search string longer than source string"
)
diff --git a/src/converge/converge.test.js b/src/converge/converge.test.js
index 847ec86..98d1a64 100644
--- a/src/converge/converge.test.js
+++ b/src/converge/converge.test.js
@@ -1,5 +1,8 @@
import test from "tape"
-import { converge, reduce, read } from ".."
+
+import { converge } from "./converge"
+import { reduce } from "../reduce/reduce"
+import { read } from "../read/read"
test("converge", t => {
const source = [{ a: 1, b: 2 }]
diff --git a/src/curry/curry.js b/src/curry/curry.js
index 68a65c8..b03433e 100644
--- a/src/curry/curry.js
+++ b/src/curry/curry.js
@@ -16,9 +16,7 @@
*
* curry(sum)(1)(2) = 3
*/
-const curry = fn => (...args) =>
+export const curry = fn => (...args) =>
args.length >= fn.length
? fn(...args)
: (...rest) => curry(fn)(...args, ...rest)
-
-export { curry }
diff --git a/src/curry/curry.test.js b/src/curry/curry.test.js
index af4a339..2c38d8a 100644
--- a/src/curry/curry.test.js
+++ b/src/curry/curry.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { curry } from ".."
+
+import { curry } from "./curry"
test("curry", t => {
const sum = (a, b) => a + b
diff --git a/src/debounce/debounce.js b/src/debounce/debounce.js
index c5bfd34..a001fc2 100644
--- a/src/debounce/debounce.js
+++ b/src/debounce/debounce.js
@@ -1,5 +1,5 @@
/**
- * Call function after `wait` milliseconds have elapsed
+ * Run function after `wait` milliseconds have elapsed since last call
*
* @name debounce
* @tag Core
@@ -15,14 +15,13 @@
* passed without calling
*
* @example
- * // constructor
- * this.debouncedAutocomplete = debounce(autocompleteFromAPI, {
+ * const debouncedAutocomplete = debounce(autocompleteFromAPI, {
* wait: 100,
* bind: this
* })
*
* // render
- *
+ *
*/
const debounce = (fn, { wait = 50, bind = null } = {}) => {
let finalRunTimer
diff --git a/src/debounce/debounce.test.js b/src/debounce/debounce.test.js
index 35c2c56..237795a 100644
--- a/src/debounce/debounce.test.js
+++ b/src/debounce/debounce.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { debounce } from ".."
+
+import { debounce } from "./debounce"
test("core::debounce", t => {
/**
diff --git a/src/dec/dec.js b/src/dec/dec.js
index 4710911..3b80e86 100644
--- a/src/dec/dec.js
+++ b/src/dec/dec.js
@@ -12,6 +12,4 @@
* dec(2)
* // => 1
*/
-const dec = source => source - 1
-
-export { dec }
+export const dec = source => source - 1
diff --git a/src/dec/dec.test.js b/src/dec/dec.test.js
index baf939a..80557c8 100644
--- a/src/dec/dec.test.js
+++ b/src/dec/dec.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { dec } from ".."
+
+import { dec } from "./dec"
test("dec", t => {
t.equal(dec(2), 1, "Decrement number")
diff --git a/src/deep-equal/deep-equal.js b/src/deep-equal/deep-equal.js
index ac19cd5..2114e76 100644
--- a/src/deep-equal/deep-equal.js
+++ b/src/deep-equal/deep-equal.js
@@ -100,9 +100,11 @@ const _isDeepEqual = (a, b) => {
* // => false
*/
export const isDeepEqual = (...params) => {
+ // @signature (a) => (b)
if (params.length <= 1) {
return b => _isDeepEqual(params[0], b)
}
+ // @signature (a, b)
return _isDeepEqual(...params)
}
diff --git a/src/deep-equal/deep-equal.test.js b/src/deep-equal/deep-equal.test.js
index fd43b41..4185b9a 100644
--- a/src/deep-equal/deep-equal.test.js
+++ b/src/deep-equal/deep-equal.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { isDeepEqual } from ".."
+
+import { isDeepEqual } from "./deep-equal"
test("isDeepEqual", t => {
t.equal(isDeepEqual(1, 1), true, "Primitives: 1 === 1")
diff --git a/src/distinct/distinct.test.js b/src/distinct/distinct.test.js
index caeb334..b57550f 100644
--- a/src/distinct/distinct.test.js
+++ b/src/distinct/distinct.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { distinct } from ".."
+
+import { distinct } from "./distinct"
test("array::distinct", t => {
t.deepEqual(
@@ -20,5 +21,7 @@ test("array::distinct", t => {
"Recursive: ([1, {a: 2}, {a: 2}]) // => [1, {a: 2}]"
)
+ t.deepEqual(distinct([]), [], "Empty array should return empty array")
+
t.end()
})
diff --git a/src/drop-last/drop-last.js b/src/drop-last/drop-last.js
index 03c8592..79ce095 100644
--- a/src/drop-last/drop-last.js
+++ b/src/drop-last/drop-last.js
@@ -1,37 +1,25 @@
-/**
- * { lambda_description }
- *
- * @param {number} count The count
- *
- * @return {Array} { description_of_the_return_value }
- */
-const drop = count => source => {
- const result = []
+import { curry } from "../curry/curry"
- for (let i = 0, length = source.length - count; i < length; i++) {
- result.push(source[i])
- }
-
- return result
-}
+const _dropLast = curry((count, source) =>
+ count > source.length ? [] : source.slice(0, source.length - count)
+)
/**
* Remove elements from end of array
*
- * @param {number|Array} count Number of element to remove
- * @param {Array} source Source array
+ * @param {number} count Number of element to remove (default 1)
+ * @param {Array} source Source array
*
* @return {Array}
*
* @tag Array
- * @signature (count: number|Array) => (source: Array): Array
+ * @signature (count: number, source: Array): Array
+ * @signature (source: Array): Array
*/
-const dropLast = count => {
+export const dropLast = count => {
if (Array.isArray(count)) {
- return drop(1)(count)
+ return _dropLast(1, count)
}
- return drop(count)
+ return _dropLast(count)
}
-
-export { dropLast }
diff --git a/src/drop-last/drop-last.test.js b/src/drop-last/drop-last.test.js
index 4deb214..58eea6b 100644
--- a/src/drop-last/drop-last.test.js
+++ b/src/drop-last/drop-last.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { dropLast } from ".."
+
+import { dropLast } from "./drop-last"
test("dropLast", t => {
t.deepEqual(
diff --git a/src/elapsed-time/elapsed-time.js b/src/elapsed-time/elapsed-time.js
index ee60f8f..31ba195 100644
--- a/src/elapsed-time/elapsed-time.js
+++ b/src/elapsed-time/elapsed-time.js
@@ -1,3 +1,5 @@
+import { curry } from "../curry/curry"
+
const oneDay = 60 * 60 * 24
const oneHour = 60 * 60
const oneMinute = 60
@@ -22,7 +24,7 @@ const oneSecond = 1000
* )
* // => { days: 0, hours: 3, minutes: 24, seconds: 0 }
*/
-const elapsedTime = startDate => endDate => {
+export const elapsedTime = curry((startDate, endDate) => {
const timePassedInSec = Math.abs(startDate - endDate) / oneSecond
// Number of days
@@ -47,6 +49,4 @@ const elapsedTime = startDate => endDate => {
minutes,
seconds,
}
-}
-
-export { elapsedTime }
+})
diff --git a/src/elapsed-time/elapsed-time.test.js b/src/elapsed-time/elapsed-time.test.js
index bc78a74..d056dff 100644
--- a/src/elapsed-time/elapsed-time.test.js
+++ b/src/elapsed-time/elapsed-time.test.js
@@ -1,9 +1,11 @@
import test from "tape"
-import { elapsedTime } from ".."
+
+import { elapsedTime } from "./elapsed-time"
test("elapsedTime", t => {
t.deepEqual(
- elapsedTime(new Date("June 1, 2018 00:00:00"))(
+ elapsedTime(
+ new Date("June 1, 2018 00:00:00"),
new Date("June 2, 2018 03:24:00")
),
{ days: 1, hours: 3, minutes: 24, seconds: 0 },
diff --git a/src/ends-with/ends-with.js b/src/ends-with/ends-with.js
index 4490b27..604bf07 100644
--- a/src/ends-with/ends-with.js
+++ b/src/ends-with/ends-with.js
@@ -1,19 +1,6 @@
-/**
- * Test if string ends with substring
- *
- * @param {string} search Search string
- * @param {string} source Source string
- *
- * @return {boolean}
- *
- * @tag String
- * @signature (search: string) => (source: string): boolean
- *
- * @example
- * endWith("ipsum")("lorem ipsum")
- * // => true
- */
-const endsWith = search => source => {
+import { curry } from "../curry/curry"
+
+const _endsWith = (search, source) => {
if (search.length > source.length) {
return false
}
@@ -27,4 +14,19 @@ const endsWith = search => source => {
return searchPosition === source.length - search.length
}
-export { endsWith }
+/**
+ * Test if string ends with substring
+ *
+ * @param {string} search Search string
+ * @param {string} source Source string
+ *
+ * @return {boolean}
+ *
+ * @tag String
+ * @signature (search: String, source: String): Boolean
+ *
+ * @example
+ * endWith("ipsum")("lorem ipsum")
+ * // => true
+ */
+export const endsWith = curry(_endsWith)
diff --git a/src/ends-with/ends-with.test.js b/src/ends-with/ends-with.test.js
index 5582213..2092006 100644
--- a/src/ends-with/ends-with.test.js
+++ b/src/ends-with/ends-with.test.js
@@ -1,11 +1,18 @@
import test from "tape"
-import { endsWith } from ".."
+
+import { endsWith } from "./ends-with"
test("string::endsWith", t => {
t.equals(
endsWith("ipsum")("lorem ipsum"),
true,
- "Source string ends with search string"
+ "Source string ends with search string - curried"
+ )
+
+ t.equals(
+ endsWith("ipsum", "lorem ipsum"),
+ true,
+ "Source string ends with search string - uncurried"
)
t.equals(
diff --git a/src/escape/escape.js b/src/escape/escape.js
index 79f7b43..5688320 100644
--- a/src/escape/escape.js
+++ b/src/escape/escape.js
@@ -1,3 +1,3 @@
-const escape = match => source => source.replace(match, "\\$&")
+import { curry } from "../curry/curry"
-export { escape }
+export const escape = curry((match, source) => source.replace(match, "\\$&"))
diff --git a/src/escapeHTML/escapeHTML.js b/src/escapeHTML/escapeHTML.js
index 0975634..85f1a8f 100644
--- a/src/escapeHTML/escapeHTML.js
+++ b/src/escapeHTML/escapeHTML.js
@@ -1,4 +1,4 @@
-const escapeHTML = source =>
+export const escapeHTML = source =>
source.replace(
/["&'/<>]/g,
char =>
@@ -11,5 +11,3 @@ const escapeHTML = source =>
">": ">",
}[char])
)
-
-export { escapeHTML }
diff --git a/src/escapeHTML/escapeHTML.test.js b/src/escapeHTML/escapeHTML.test.js
index 18f3941..a6b3839 100644
--- a/src/escapeHTML/escapeHTML.test.js
+++ b/src/escapeHTML/escapeHTML.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { escapeHTML } from ".."
+
+import { escapeHTML } from "./escapeHTML"
test("escapeHTML", t => {
const actual = escapeHTML(
diff --git a/src/escapeRegExp/escapeRegExp.js b/src/escapeRegExp/escapeRegExp.js
index 96b4d8d..b301648 100644
--- a/src/escapeRegExp/escapeRegExp.js
+++ b/src/escapeRegExp/escapeRegExp.js
@@ -15,6 +15,4 @@ import { escape } from "../escape/escape"
* escapeRegExp( "lorem. ipsum [dolor]" )
* // => "lorem \\. ipsum \\[dolor\\]"
*/
-const escapeRegExp = escape(/[$()*+.<>?[\\\]^{|}]/g)
-
-export { escapeRegExp }
+export const escapeRegExp = escape(/[$()*+.<>?[\\\]^{|}]/g)
diff --git a/src/escapeRegExp/escapeRegExp.test.js b/src/escapeRegExp/escapeRegExp.test.js
index 7babe02..027e3f6 100644
--- a/src/escapeRegExp/escapeRegExp.test.js
+++ b/src/escapeRegExp/escapeRegExp.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { escapeRegExp } from ".."
+
+import { escapeRegExp } from "./escapeRegExp"
test("escapeRegExp", t => {
const actualT1 = escapeRegExp("lorem. ipsum [dolor] (sit amet)?")
diff --git a/src/filter/filter.js b/src/filter/filter.js
index 1058d38..ca2f222 100644
--- a/src/filter/filter.js
+++ b/src/filter/filter.js
@@ -1,5 +1,21 @@
+import { pipe } from "../pipe/pipe"
+import { curry } from "../curry/curry"
import { isMatch } from "../is-match/is-match"
+const _filter = (_fn, _source) => {
+ const fn = Array.isArray(_fn) ? pipe(..._fn) : _fn
+ const source = Array.isArray(_source) ? _source : [_source]
+ const result = []
+
+ for (let i = 0, length = source.length; i < length; i++) {
+ if (fn.call(null, source[i]) === true) {
+ result.push(source[i])
+ }
+ }
+
+ return result
+}
+
/**
* Filter elements matching a predicate
*
@@ -12,18 +28,7 @@ import { isMatch } from "../is-match/is-match"
* @signature (fn: Function) => (source: Array): Array
* @signature (fn: Function, source: Array): Array
*/
-const filter = fn => source => {
- const result = []
- const sourceArray = Array.isArray(source) ? source : [source]
-
- for (let i = 0, length = sourceArray.length; i < length; i++) {
- if (fn.call(null, sourceArray[i]) === true) {
- result.push(sourceArray[i])
- }
- }
-
- return result
-}
+export const filter = curry(_filter)
/**
* Filter elements matching an object
@@ -37,6 +42,6 @@ const filter = fn => source => {
* @signature (subset: Object) => (source: Array): Array
* @signature (subset: Object, source: Array): Array
*/
-const filterWith = subset => filter(isMatch(subset))
-
-export { filter, filterWith }
+export const filterWith = curry((subset, source) =>
+ _filter(isMatch(subset), source)
+)
diff --git a/src/filter/filter.test.js b/src/filter/filter.test.js
index e049b5a..9e33a28 100644
--- a/src/filter/filter.test.js
+++ b/src/filter/filter.test.js
@@ -1,17 +1,20 @@
import test from "tape"
-import { filter, filterWith } from ".."
-test("array::filter", t => {
+import { isEqual } from "../is-equal/is-equal"
+import { read } from "../read/read"
+import { filter, filterWith } from "./filter"
+
+test("filter", t => {
t.deepEqual(
filter(filterElm => filterElm <= 3)([1, 2, 3, 4, 5, 6]),
[1, 2, 3],
- "Keep items lower or equal than 3"
+ "Keep items lower or equal than 3 - curried"
)
t.deepEqual(
- filter(filterElm => filterElm <= 3)("asd"),
+ filter(filterElm => filterElm <= 3, "asd"),
[],
- "Run filter for non-array input, treat as array of one (input does not match function)"
+ "Run filter for non-array input, treat as array of one (input does not match function) - uncurried"
)
t.deepEqual(
@@ -20,6 +23,20 @@ test("array::filter", t => {
"Run filter for non-array input, treat as array of one (input matches function)"
)
+ t.deepEqual(
+ filter([read("items"), isEqual(1)])([
+ { id: 2, items: 2 },
+ { id: 3, items: 1 },
+ { id: 4, items: 2 },
+ ]),
+ [{ id: 3, items: 1 }],
+ "Keep items in array that have properties that equal - curried"
+ )
+
+ t.end()
+})
+
+test("filterWith", t => {
t.deepEqual(
filterWith({
items: 2,
@@ -32,15 +49,18 @@ test("array::filter", t => {
{ id: 2, items: 2 },
{ id: 4, items: 2 },
],
- "Keep items in array that have properties that equal"
+ "Keep items in array that have properties that equal - curried"
)
t.deepEqual(
- filterWith({
- "!id": 2,
- })([{ lorem: 2 }, { lorem: 3 }, { id: 2 }]),
+ filterWith(
+ {
+ "!id": 2,
+ },
+ [{ lorem: 2 }, { lorem: 3 }, { id: 2 }]
+ ),
[{ lorem: 2 }, { lorem: 3 }],
- "Keep items in array that have properties that dont equal"
+ "Keep items in array that have properties that dont equal - uncurried"
)
t.end()
diff --git a/src/find-index/find-index.js b/src/find-index/find-index.js
index 276ea8d..9ed5d0e 100644
--- a/src/find-index/find-index.js
+++ b/src/find-index/find-index.js
@@ -1,8 +1,10 @@
import { pipe } from "../pipe/pipe"
+import { curry } from "../curry/curry"
import { isMatch } from "../is-match/is-match"
-const _findIndex = (_fn, source) => {
+const _findIndex = (_fn, _source) => {
const fn = Array.isArray(_fn) ? pipe(..._fn) : _fn
+ const source = Array.isArray(_source) ? _source : [_source]
for (let i = 0, length = source.length; i < length; i++) {
const found = fn(source[i], i, source)
@@ -25,7 +27,6 @@ const _findIndex = (_fn, source) => {
*
* @name findIndex
* @tag Array
- * @signature (fn: Function) => (source: Object[]): Number
* @signature (fn: Function, source: Object[]): Number
*
* @example
@@ -37,22 +38,8 @@ const _findIndex = (_fn, source) => {
* findIndex([get("body"), equals("dolor")], null, comments)
* // => 1
*/
-export const findIndex = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _findIndex(params[0], source)
- }
-
- // @signature (fn, source)
- return _findIndex(...params)
-}
+export const findIndex = curry(_findIndex)
-export const findIndexWith = (...params) => {
- // @signature (subset) => (source)
- if (params.length <= 1) {
- return source => _findIndex(isMatch(params[0]), source)
- }
-
- // @signature (subset, source)
- return _findIndex(isMatch(params[0]), params[1], params[2])
-}
+export const findIndexWith = curry((subset, source) =>
+ _findIndex(isMatch(subset), source)
+)
diff --git a/src/find-index/find-index.test.js b/src/find-index/find-index.test.js
index 3e2b875..022d829 100644
--- a/src/find-index/find-index.test.js
+++ b/src/find-index/find-index.test.js
@@ -1,7 +1,8 @@
import test from "tape"
-import { findIndex, findIndexWith } from ".."
-test("findIndex(With)", t => {
+import { findIndex, findIndexWith } from "./find-index"
+
+test("findIndex", t => {
const comments = [
{ id: 1, body: "" },
{ id: 2, body: "dolor" },
@@ -25,6 +26,15 @@ test("findIndex(With)", t => {
"index with id:3 should be -1 (not found)"
)
+ t.end()
+})
+
+test("findIndexWith", t => {
+ const comments = [
+ { id: 1, body: "" },
+ { id: 2, body: "dolor" },
+ ]
+
t.equals(
findIndexWith({ id: 2 })([]),
-1,
diff --git a/src/find/find.js b/src/find/find.js
index f2e9380..69f923d 100644
--- a/src/find/find.js
+++ b/src/find/find.js
@@ -1,8 +1,9 @@
import { pipe } from "../pipe/pipe"
import { isMatch } from "../is-match/is-match"
-const _find = (_fn, notFoundDefault, source) => {
+const _find = (_fn, notFoundDefault, _source) => {
const fn = Array.isArray(_fn) ? pipe(..._fn) : _fn
+ const source = Array.isArray(_source) ? _source : [_source]
for (let i = 0, length = source.length; i < length; i++) {
const isFound = fn(source[i], i, source)
diff --git a/src/find/find.test.js b/src/find/find.test.js
index b114dbb..4e5e045 100644
--- a/src/find/find.test.js
+++ b/src/find/find.test.js
@@ -1,7 +1,8 @@
import test from "tape"
-import { find, findWith } from ".."
-test("array::find", t => {
+import { find, findWith } from "./find"
+
+test("find", t => {
const comments = [
{ id: 1, body: "" },
{ id: 2, body: "dolor" },
@@ -31,6 +32,15 @@ test("array::find", t => {
"find with id:3 should return default not found value"
)
+ t.end()
+})
+
+test("findWith", t => {
+ const comments = [
+ { id: 1, body: "" },
+ { id: 2, body: "dolor" },
+ ]
+
t.deepEqual(
findWith({ id: 2 })([]),
undefined,
diff --git a/src/first/first.js b/src/first/first.js
index 55da0e1..5a562e5 100644
--- a/src/first/first.js
+++ b/src/first/first.js
@@ -15,9 +15,7 @@
* first([])
* // => undefined
*/
-const first = source =>
+export const first = source =>
(Array.isArray(source) || typeof source === "string") && source.length !== 0
? source[0]
: undefined
-
-export { first }
diff --git a/src/first/first.test.js b/src/first/first.test.js
index da65360..7db1253 100644
--- a/src/first/first.test.js
+++ b/src/first/first.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { first } from ".."
+
+import { first } from "./first"
test("first", t => {
t.equal(first("xyz"), "x", "From string should return first char")
diff --git a/src/flatten/flatten.test.js b/src/flatten/flatten.test.js
index f98ef77..b204e49 100644
--- a/src/flatten/flatten.test.js
+++ b/src/flatten/flatten.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { flatten } from ".."
+
+import { flatten } from "./flatten"
test("flatten", t => {
t.equals(flatten(3), 3, "Flatten primitive returns same value")
diff --git a/src/for-each/for-each.js b/src/for-each/for-each.js
index 68437f4..525fd7f 100644
--- a/src/for-each/for-each.js
+++ b/src/for-each/for-each.js
@@ -1,3 +1,4 @@
+import { curry } from "../curry/curry"
import { pipe } from "../pipe/pipe"
const _forEach = (_fn, _source) => {
@@ -18,17 +19,6 @@ const _forEach = (_fn, _source) => {
* @return {undefined}
*
* @tag Array
- * @signature (fn: Function|Function[]) => (source: Array): undefined
* @signature (fn: Function|Function[], source: Array): undefined
*/
-const forEach = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _forEach(params[0], source)
- }
-
- // @signature (fn, source)
- return _forEach(...params)
-}
-
-export { forEach }
+export const forEach = curry(_forEach)
diff --git a/src/for-each/for-each.test.js b/src/for-each/for-each.test.js
index 27313bd..93b15e1 100644
--- a/src/for-each/for-each.test.js
+++ b/src/for-each/for-each.test.js
@@ -8,21 +8,13 @@ test("forEach", t => {
forEach(item => tmp.push(item))([1, 2, 3])
- t.deepEqual(
- tmp,
- [1, 2, 3],
- "Run function over each element of array - curried"
- )
+ t.deepEqual(tmp, [1, 2, 3], "Run function over each element of array")
const tmp2 = []
forEach([inc, item => tmp2.push(item)], [1, 2, 3])
- t.deepEqual(
- tmp2,
- [2, 3, 4],
- "Run piped functions over each element of array - uncurried"
- )
+ t.deepEqual(tmp2, [2, 3, 4], "Run piped functions over each element of array")
t.end()
})
diff --git a/src/group-by/group-by.js b/src/group-by/group-by.js
index c02d6d7..a3a8e06 100644
--- a/src/group-by/group-by.js
+++ b/src/group-by/group-by.js
@@ -1,3 +1,21 @@
+import { curry } from "../curry/curry"
+
+const _groupBy = (field, source) => {
+ const result = {}
+
+ for (let i = 0, length = source.length; i < length; i++) {
+ const groupKey = String(source[i][field])
+
+ if (result[groupKey]) {
+ result[groupKey].push(source[i])
+ } else {
+ result[groupKey] = [source[i]]
+ }
+ }
+
+ return Object.values(result)
+}
+
/**
* Group an array of objects by field.
*
@@ -20,20 +38,4 @@
* // [{id: 4, user_id: null}],
* // ]
*/
-const groupBy = field => input => {
- const result = {}
-
- for (let i = 0, length = input.length; i < length; i++) {
- const groupKey = String(input[i][field])
-
- if (result[groupKey]) {
- result[groupKey].push(input[i])
- } else {
- result[groupKey] = [input[i]]
- }
- }
-
- return Object.values(result)
-}
-
-export { groupBy }
+export const groupBy = curry(_groupBy)
diff --git a/src/group-by/group-by.test.js b/src/group-by/group-by.test.js
index 2f3fdd9..301dccd 100644
--- a/src/group-by/group-by.test.js
+++ b/src/group-by/group-by.test.js
@@ -1,32 +1,36 @@
import test from "tape"
-import { groupBy } from ".."
+
+import { groupBy } from "./group-by"
test("groupBy", t => {
const comments = [
{ id: 1, user_id: 2 },
{ id: 2, user_id: 3 },
- { id: 3, user_id: 2 },
+ { id: 3 },
{ id: 4, user_id: null },
+ { id: 5, user_id: undefined },
]
- const commentsByUserId = groupBy("user_id")(comments)
t.deepEqual(
- commentsByUserId,
+ groupBy("user_id")(comments),
[
- [
- { id: 1, user_id: 2 },
- { id: 3, user_id: 2 },
- ],
+ [{ id: 1, user_id: 2 }],
[{ id: 2, user_id: 3 }],
+ [{ id: 3 }, { id: 5, user_id: undefined }],
[{ id: 4, user_id: null }],
],
"Grouping array of objects by field returns array of arrays"
)
- t.equal(
- commentsByUserId[1][0],
- comments[1],
- "Items arent cloned after grouping"
+ t.deepEqual(
+ groupBy("user_id", comments),
+ [
+ [{ id: 1, user_id: 2 }],
+ [{ id: 2, user_id: 3 }],
+ [{ id: 3 }, { id: 5, user_id: undefined }],
+ [{ id: 4, user_id: null }],
+ ],
+ "Grouping array of objects by field returns array of arrays"
)
t.end()
diff --git a/src/gt/gt.js b/src/gt/gt.js
index d3354da..5aeda45 100644
--- a/src/gt/gt.js
+++ b/src/gt/gt.js
@@ -1,23 +1,24 @@
+import { curry } from "../curry/curry"
+
+const _gt = (a, b) => a < b
+
/**
* Grater compare.
*
- * Since this will mostly be used in pipe, the first param in the curry chain
- * is the second operand.
- *
- * @param {number} second Second number
- * @param {number} first First number
+ * @param {Number} a First number
+ * @param {Number} b Second number
*
- * @return {boolean}
+ * @return {Boolean}
*
* @tag Core
- * @signarute (second: number) => (first: number): boolean
+ * @signature (a: Number) => (b: Number): Boolean
+ * @signature (a: Number, b: Number): Boolean
*
* @example
* gt(10)(4)
* // => false
- * gt(10)(14)
+ *
+ * gt(10, 14)
* // => true
*/
-const gt = second => first => first > second
-
-export { gt }
+export const gt = curry(_gt)
diff --git a/src/gt/gt.test.js b/src/gt/gt.test.js
index 265fe92..73f9c88 100644
--- a/src/gt/gt.test.js
+++ b/src/gt/gt.test.js
@@ -1,10 +1,12 @@
import test from "tape"
-import { gt } from ".."
+
+import { gt } from "./gt"
test("gt", t => {
t.equals(gt(10)(4), false, "4 is not grater than 10")
t.equals(gt(10)(10), false, "10 is not grater than 10")
t.equals(gt(10)(14), true, "14 is grater than 10")
+ t.equals(gt(10, 10), false, "10 is mpt grater than 10")
t.end()
})
diff --git a/src/has-key/has-key.js b/src/has-key/has-key.js
index 3a2091c..0c6d66e 100644
--- a/src/has-key/has-key.js
+++ b/src/has-key/has-key.js
@@ -1,14 +1,7 @@
+import { curry } from "../curry/curry"
import { is } from "../is/is"
const _hasKey = (key, source) =>
is(source) && Object.prototype.hasOwnProperty.call(source, key)
-export const hasKey = (...params) => {
- // @signature (key) => (source)
- if (params.length <= 1) {
- return source => _hasKey(params[0], source)
- }
-
- // @signature (key, source)
- return _hasKey(...params)
-}
+export const hasKey = curry(_hasKey)
diff --git a/src/has-key/has-key.test.js b/src/has-key/has-key.test.js
index 2b30c14..2f56bea 100644
--- a/src/has-key/has-key.test.js
+++ b/src/has-key/has-key.test.js
@@ -1,9 +1,17 @@
import test from "tape"
-import { hasKey } from ".."
+
+import { hasKey } from "./has-key"
test("hasKey", t => {
- t.equals(hasKey("test")({}), false, "Primitive exists in array")
- t.equals(hasKey("test", { test: "1" }), true, "Primitive exists in array")
+ t.equals(hasKey("test")({}), false, "Key does not exist")
+
+ t.equals(hasKey("test", { test: "1" }), true, "Key exists")
+
+ t.equals(
+ hasKey("test", { test: undefined }),
+ true,
+ "Key exists even if undefined"
+ )
t.end()
})
diff --git a/src/i/i.js b/src/i/i.js
index 5c902df..4f56478 100644
--- a/src/i/i.js
+++ b/src/i/i.js
@@ -5,6 +5,4 @@
*
* @return {mixed}
*/
-const i = source => source
-
-export { i }
+export const i = source => source
diff --git a/src/i/i.test.js b/src/i/i.test.js
index 336620c..c31c353 100644
--- a/src/i/i.test.js
+++ b/src/i/i.test.js
@@ -1,7 +1,8 @@
import test from "tape"
-import { i } from ".."
-test("core::i", t => {
+import { i } from "./i"
+
+test("i", t => {
t.equals(i(true), true, "Identity boolean")
t.equals(i(3), 3, "Identity string")
t.equals(i("asd"), "asd", "Identity string")
diff --git a/src/inc/inc.js b/src/inc/inc.js
index 69651c5..8a67e4f 100644
--- a/src/inc/inc.js
+++ b/src/inc/inc.js
@@ -12,6 +12,4 @@
* inc(2)
* // => 3
*/
-const inc = source => source + 1
-
-export { inc }
+export const inc = source => source + 1
diff --git a/src/inc/inc.test.js b/src/inc/inc.test.js
index 6edc43f..4e949b6 100644
--- a/src/inc/inc.test.js
+++ b/src/inc/inc.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { inc } from ".."
+
+import { inc } from "./inc"
test("inc", t => {
t.equal(inc(2), 3, "Increment number")
diff --git a/src/index-by/index-by.js b/src/index-by/index-by.js
index 478987e..dbd0034 100644
--- a/src/index-by/index-by.js
+++ b/src/index-by/index-by.js
@@ -1,3 +1,19 @@
+import { curry } from "../curry/curry"
+
+const _indexBy = field => source => {
+ const result = {}
+
+ for (let i = 0, length = source.length; i < length; i++) {
+ if (source[i][field]) {
+ const indexKey = String(source[i][field])
+
+ result[indexKey] = source[i]
+ }
+ }
+
+ return result
+}
+
/**
* Index an array of objects by field. Only truthy fields will be indexed.
*
@@ -7,7 +23,7 @@
* @return {Object}
*
* @tag Array
- * @signature (field: string) => (source: Object[]): Object
+ * @signature (field: string, source: Object[]): Object
*
* @example
* indexBy("id")([
@@ -19,18 +35,4 @@
* // 2: {id: 2, user_id: 3},
* // }
*/
-const indexBy = field => source => {
- const result = {}
-
- for (let i = 0, length = source.length; i < length; i++) {
- if (source[i][field]) {
- const indexKey = String(source[i][field])
-
- result[indexKey] = source[i]
- }
- }
-
- return result
-}
-
-export { indexBy }
+export const indexBy = curry(_indexBy)
diff --git a/src/index-by/index-by.test.js b/src/index-by/index-by.test.js
index 31fa54b..5560a4c 100644
--- a/src/index-by/index-by.test.js
+++ b/src/index-by/index-by.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { indexBy } from ".."
+
+import { indexBy } from "./index-by"
test("indexBy", t => {
t.deepEqual(
diff --git a/src/index.js b/src/index.js
index c8e1aef..05c755e 100644
--- a/src/index.js
+++ b/src/index.js
@@ -31,7 +31,7 @@ export { curry } from "./curry/curry"
// Boolean
export { is, isNothing, not, isTrue, isFalse, isObject } from "./is/is"
export { isEmpty, isNotEmpty } from "./is-empty/is-empty"
-export { isEqual, isEqual as equals } from "./is-equal/is-equal"
+export { isEqual, isEqual as equals, isEqual as eq } from "./is-equal/is-equal"
export { isBetween, isBetween as between } from "./is-between/is-between"
export { any, any as has, anyWith, anyWith as hasWith } from "./any/any"
export { all, allWith } from "./all/all"
@@ -63,7 +63,13 @@ export { append, append as concat } from "./append/append"
export { prepend } from "./prepend/prepend"
export { toggle } from "./toggle/toggle"
export { partition, partitionWith } from "./partition/partition"
-export { count, countWith, size, size as length } from "./count/count"
+export {
+ count,
+ count as length,
+ count as size,
+ countBy,
+ countWith,
+} from "./count/count"
export { replace, replaceWith } from "./replace/replace"
export { sort, sortWith } from "./sort/sort"
export { remove, removeWith } from "./remove/remove"
diff --git a/src/intersect/intersect.js b/src/intersect/intersect.js
index fa2e9a5..3563bf3 100644
--- a/src/intersect/intersect.js
+++ b/src/intersect/intersect.js
@@ -1,6 +1,7 @@
import { findIndex } from "../find-index/find-index"
+import { curry } from "../curry/curry"
-export const intersect = (predicateFn, unionFn) => (aList, bList) => {
+const _intersect = (predicateFn, unionFn, aList, bList) => {
if (aList.length === 0) {
return bList
}
@@ -24,3 +25,5 @@ export const intersect = (predicateFn, unionFn) => (aList, bList) => {
return result
}
+
+export const intersect = curry(_intersect)
diff --git a/src/intersect/intersect.test.js b/src/intersect/intersect.test.js
index 2efbbbd..75246d8 100644
--- a/src/intersect/intersect.test.js
+++ b/src/intersect/intersect.test.js
@@ -1,13 +1,15 @@
import test from "tape"
-import { intersect } from ".."
+import { intersect } from "./intersect"
-test("array::intersect", t => {
+test("intersect", t => {
t.deepEqual(
intersect(
(a, b) => a === b,
- a => a
- )([], [1, 2, 3]),
+ a => a,
+ [],
+ [1, 2, 3]
+ ),
[1, 2, 3],
"First array empty"
)
@@ -15,8 +17,10 @@ test("array::intersect", t => {
t.deepEqual(
intersect(
(a, b) => a === b,
- a => a
- )([1, 2, 3], []),
+ a => a,
+ [1, 2, 3],
+ []
+ ),
[1, 2, 3],
"Second array empty"
)
@@ -24,8 +28,10 @@ test("array::intersect", t => {
t.deepEqual(
intersect(
(a, b) => a === b,
- a => a
- )([1, 2, 3], [3, 4, 5]),
+ a => a,
+ [1, 2, 3],
+ [3, 4, 5]
+ ),
[1, 2, 3, 4, 5],
"Join with common"
)
@@ -33,8 +39,10 @@ test("array::intersect", t => {
t.deepEqual(
intersect(
(a, b) => a === b,
- a => a
- )([1, 2], [3, 4, 5]),
+ a => a,
+ [1, 2],
+ [3, 4, 5]
+ ),
[1, 2, 3, 4, 5],
"Join without common"
)
@@ -42,8 +50,7 @@ test("array::intersect", t => {
t.deepEqual(
intersect(
(a, b) => a.id === b.id,
- (a, b) => ({ ...a, ...b })
- )(
+ (a, b) => ({ ...a, ...b }),
[{ id: 1, overwrite: 1 }, { id: 2 }],
[{ id: 1, overwrite: 2 }, { id: 3 }]
),
diff --git a/src/is-between/is-between.test.js b/src/is-between/is-between.test.js
index 1e321bd..9fd78b3 100644
--- a/src/is-between/is-between.test.js
+++ b/src/is-between/is-between.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { isBetween } from ".."
+
+import { isBetween } from "./is-between"
test("isBetween", t => {
t.equals(isBetween(2, 5)(3), true, "Number isBetween default open interval")
diff --git a/src/is-empty/is-empty.js b/src/is-empty/is-empty.js
index 1efbf8d..d377756 100644
--- a/src/is-empty/is-empty.js
+++ b/src/is-empty/is-empty.js
@@ -24,7 +24,7 @@ import { type } from "../type/type"
* isEmpty(() => {}) // false
* isEmpty(Promise.resolve() // false
*/
-const isEmpty = source => {
+export const isEmpty = source => {
const sourceType = type(source)
const byType = {
Null: () => true,
@@ -38,6 +38,4 @@ const isEmpty = source => {
return byType[sourceType] ? byType[sourceType]() : false
}
-const isNotEmpty = source => !isEmpty(source)
-
-export { isEmpty, isNotEmpty }
+export const isNotEmpty = source => !isEmpty(source)
diff --git a/src/is-empty/is-empty.test.js b/src/is-empty/is-empty.test.js
index 344ab17..1a37341 100644
--- a/src/is-empty/is-empty.test.js
+++ b/src/is-empty/is-empty.test.js
@@ -1,7 +1,8 @@
import test from "tape"
-import { isEmpty, isNotEmpty } from ".."
-test("core::isEmpty", t => {
+import { isEmpty, isNotEmpty } from "./is-empty"
+
+test("isEmpty", t => {
t.equal(isEmpty({}), true, "{} should equal true")
t.equal(isEmpty({ a: 2 }), false, "{a:2} should equal false")
t.equal(isEmpty([]), true, "[] should equal true")
diff --git a/src/is-equal/is-equal.js b/src/is-equal/is-equal.js
index eaf264a..838395e 100644
--- a/src/is-equal/is-equal.js
+++ b/src/is-equal/is-equal.js
@@ -1,13 +1,18 @@
+import { curry } from "../curry/curry"
+
+const _isEqual = (a, b) => (Number.isNaN(a) && Number.isNaN(b) ? true : a === b)
+
/**
- * Check if a is equal to b (strict equality)
+ * Check if a tripple-equals b (accounts for null, undefined and NaN)
*
- * @param {mixed} one First value
- * @param {mixed} two Second value
+ * @param {Mixed} a First value
+ * @param {Mixed} b Second value
*
- * @return {boolean}
+ * @return {Boolean}
*
* @tag Core
- * @signature (a: mixed) => (b: mixed): boolean
+ * @signature (a: Mixed) => (b: Mixed): Boolean
+ * @signature (a: Mixed, b: Mixed): Boolean
*
* @example
* equal(2)(2)
@@ -22,5 +27,4 @@
* equal([1])([1])
* // => false
*/
-export const isEqual = one => two =>
- Number.isNaN(one) && Number.isNaN(two) ? true : one === two
+export const isEqual = curry(_isEqual)
diff --git a/src/is-equal/is-equal.test.js b/src/is-equal/is-equal.test.js
index 373c2cc..3e0c77f 100644
--- a/src/is-equal/is-equal.test.js
+++ b/src/is-equal/is-equal.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { isEqual } from ".."
+
+import { isEqual } from "./is-equal"
test("isEqual", t => {
t.equals(isEqual(2)(2), true, "Compare two equal primitives")
diff --git a/src/is-match/is-match.js b/src/is-match/is-match.js
index da2d523..92e92b4 100644
--- a/src/is-match/is-match.js
+++ b/src/is-match/is-match.js
@@ -1,14 +1,28 @@
+import { pipe } from "../pipe/pipe"
+import { curry } from "../curry/curry"
import { all } from "../all/all"
-const byValue = ({ shouldBe, value, not }) =>
+const byValue = (shouldBe, value, not) =>
not ? shouldBe !== value : shouldBe === value
-const byFn = ({ shouldBe, value, not }) => {
+const byFn = (shouldBe, value, not) => {
const result = shouldBe(value) === true
return not ? !result : result
}
+const _isMatch = (subset, source) =>
+ all(([key, _shouldBe]) => {
+ const shouldBe = Array.isArray(_shouldBe) ? pipe(..._shouldBe) : _shouldBe
+ const shouldTestNegation = key[0] === "!"
+ const sourceKey = key.replace("!", "")
+ const value = source[sourceKey]
+
+ return typeof shouldBe === "function"
+ ? byFn(shouldBe, value, shouldTestNegation)
+ : byValue(shouldBe, value, shouldTestNegation)
+ })(Object.entries(subset))
+
/**
* Determines if one object's properties are equal to another
*
@@ -44,16 +58,4 @@ const byFn = ({ shouldBe, value, not }) => {
* })
* // false
*/
-const isMatch = subset => source =>
- all(([key, shouldBe]) => {
- const shouldTestNegation = key[0] === "!"
-
- const sourceKey = key.replace("!", "")
- const value = source[sourceKey]
-
- return typeof shouldBe === "function"
- ? byFn({ shouldBe, value, not: shouldTestNegation })
- : byValue({ shouldBe, value, not: shouldTestNegation })
- })(Object.entries(subset))
-
-export { isMatch }
+export const isMatch = curry(_isMatch)
diff --git a/src/is-match/is-match.test.js b/src/is-match/is-match.test.js
index 2a8f928..fe95521 100644
--- a/src/is-match/is-match.test.js
+++ b/src/is-match/is-match.test.js
@@ -1,7 +1,10 @@
import test from "tape"
-import { isMatch } from ".."
-test("core::isMatch", t => {
+import { isEqual } from "../is-equal/is-equal"
+import { read } from "../read/read"
+import { isMatch } from "./is-match"
+
+test("isMatch", t => {
t.deepEqual(
isMatch({
id: 2,
@@ -15,6 +18,20 @@ test("core::isMatch", t => {
"Properties are present and have equal values"
)
+ t.deepEqual(
+ isMatch(
+ {
+ tag: [read("userId"), isEqual(2)],
+ },
+ {
+ id: 2,
+ tag: { id: 1, userId: 2 },
+ }
+ ),
+ true,
+ "Match using piped functions"
+ )
+
t.deepEqual(
isMatch({
name: "John",
diff --git a/src/is/is.js b/src/is/is.js
index b4de3f5..4a5ea63 100644
--- a/src/is/is.js
+++ b/src/is/is.js
@@ -1,3 +1,5 @@
+import { curry } from "../curry/curry"
+
/**
* Test if something is not `null` or `undefined`
*
@@ -30,6 +32,6 @@ const isTrue = source => source === true
const isFalse = source => source === false
-const not = fn => source => !fn(source)
+const not = curry((fn, source) => !fn(source))
export { is, not, isNothing, isTrue, isFalse, isObject }
diff --git a/src/is/is.test.js b/src/is/is.test.js
index ec68fd8..d374273 100644
--- a/src/is/is.test.js
+++ b/src/is/is.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { is, isNothing, isTrue, not, isFalse, isObject } from ".."
+
+import { is, isNothing, isTrue, not, isFalse, isObject } from "./is"
/**
* Test if something is not `null` or `undefined`
@@ -20,7 +21,7 @@ import { is, isNothing, isTrue, not, isFalse, isObject } from ".."
* is(false) // => true
* is(NaN) // => false
*/
-test("core::is", t => {
+test("is", t => {
t.equal(is(false), true, 'Is "false" something')
t.equal(is(0), true, `Is "0" something`)
t.equal(is(""), true, "Is empty-string something")
diff --git a/src/join/join.js b/src/join/join.js
index 4791ef5..973643f 100644
--- a/src/join/join.js
+++ b/src/join/join.js
@@ -1,3 +1,7 @@
+import { curry } from "../curry/curry"
+
+const _join = (separator, source) => [].join.call(source, separator)
+
/**
* Join all elements of an array into a string
*
@@ -14,12 +18,4 @@
* join(",")(["lorem", "ipsum"])
* // => "lorem,ipsum"
*/
-const join = (separator, ...rest) => {
- if (rest.length === 0) {
- return source => [].join.call(source, separator)
- }
-
- return [].join.call(rest[0], separator)
-}
-
-export { join }
+export const join = curry(_join)
diff --git a/src/join/join.test.js b/src/join/join.test.js
index d1abbb5..963cfb4 100644
--- a/src/join/join.test.js
+++ b/src/join/join.test.js
@@ -1,20 +1,11 @@
import test from "tape"
-import { join } from ".."
+
+import { join } from "./join"
test("join", t => {
const source = ["lorem", "ipsum"]
- t.equals(
- join(",")(source),
- "lorem,ipsum",
- "Join array with 2 string into 1 (curried)"
- )
-
- t.equals(
- join(",", source),
- "lorem,ipsum",
- "Join array with 2 string into 1 (uncurried)"
- )
+ t.equals(join(",", source), "lorem,ipsum", "Join array with 2 string into 1")
t.end()
})
diff --git a/src/keys/keys.js b/src/keys/keys.js
index 62345f2..40eea8d 100644
--- a/src/keys/keys.js
+++ b/src/keys/keys.js
@@ -18,7 +18,7 @@
* keys("foo"), keys(12), keys(null), etc
* // => []
*/
-const keys = source => {
+export const keys = source => {
const type = Array.isArray(source)
? "array"
: source !== null && typeof source === "object"
@@ -41,5 +41,3 @@ const keys = source => {
return []
}
}
-
-export { keys }
diff --git a/src/keys/keys.test.js b/src/keys/keys.test.js
index f22e1b0..ae2fcfa 100644
--- a/src/keys/keys.test.js
+++ b/src/keys/keys.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { keys } from ".."
+
+import { keys } from "./keys"
test("keys", t => {
t.deepEquals(
diff --git a/src/last/last.test.js b/src/last/last.test.js
index 1bcf887..5b99b78 100644
--- a/src/last/last.test.js
+++ b/src/last/last.test.js
@@ -1,11 +1,14 @@
import test from "tape"
-import { last } from ".."
+
+import { last } from "./last"
test("last", t => {
t.equals(last([1, 2, 3]), 3, "Get last element from n array")
+
t.equals(last([1]), 1, "Get last element of an 1 array")
t.equals(last("xyz"), "z", "From string should return last char")
+
t.equals(last([]), undefined, "Get last element of empty array")
t.equals(last({}), undefined, "Get last element of empty object")
diff --git a/src/lt/lt.js b/src/lt/lt.js
index cd17916..ecb51d6 100644
--- a/src/lt/lt.js
+++ b/src/lt/lt.js
@@ -1,3 +1,4 @@
+import { curry } from "../curry/curry"
/**
* Less compare.
*
@@ -18,6 +19,4 @@
* lt(10)(14)
* // => false
*/
-const lt = second => first => first < second
-
-export { lt }
+export const lt = curry((second, first) => first < second)
diff --git a/src/lt/lt.test.js b/src/lt/lt.test.js
index 54e7850..37182dd 100644
--- a/src/lt/lt.test.js
+++ b/src/lt/lt.test.js
@@ -1,9 +1,12 @@
import test from "tape"
-import { lt } from ".."
+
+import { lt } from "./lt"
test("lt", t => {
t.equals(lt(10)(14), false, "14 is not less than 10")
+
t.equals(lt(10)(10), false, "10 is not less than 10")
+
t.equals(lt(10)(4), true, "4 is less than 10")
t.end()
diff --git a/src/map-matrix/map-matrix.js b/src/map-matrix/map-matrix.js
index 902009e..357374a 100644
--- a/src/map-matrix/map-matrix.js
+++ b/src/map-matrix/map-matrix.js
@@ -1,3 +1,4 @@
+import { curry } from "../curry/curry"
import { pipe } from "../pipe/pipe"
const _mapMatrix = (_fn, source) => {
@@ -43,12 +44,4 @@ const _mapMatrix = (_fn, source) => {
* mapMatrix([inc, inc], [[1, 2], [3, 4]])
* // => [[3, 4], [5, 6]]
*/
-export const mapMatrix = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _mapMatrix(params[0], source)
- }
-
- // @signature (fn, source)
- return _mapMatrix(...params)
-}
+export const mapMatrix = curry(_mapMatrix)
diff --git a/src/map-matrix/map-matrix.test.js b/src/map-matrix/map-matrix.test.js
index bce4c01..06b86a9 100644
--- a/src/map-matrix/map-matrix.test.js
+++ b/src/map-matrix/map-matrix.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { mapMatrix } from ".."
+
+import { mapMatrix } from "./map-matrix"
test("mapMatrix", t => {
const square = value => value * value
diff --git a/src/map/map.js b/src/map/map.js
index 41f8ce9..6647315 100644
--- a/src/map/map.js
+++ b/src/map/map.js
@@ -1,4 +1,5 @@
import { pipe } from "../pipe/pipe"
+import { curry } from "../curry/curry"
const _map = (_fn, _source) => {
const result = []
@@ -37,12 +38,4 @@ const _map = (_fn, _source) => {
* map([inc, inc], [1, 2])
* // => [3, 4]
*/
-export const map = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _map(params[0], source)
- }
-
- // @signature (fn, source)
- return _map(...params)
-}
+export const map = curry(_map)
diff --git a/src/map/map.test.js b/src/map/map.test.js
index 7fa52fc..75a5e65 100644
--- a/src/map/map.test.js
+++ b/src/map/map.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { map } from ".."
+
+import { map } from "./map"
test("map", t => {
const square = value => value * value
diff --git a/src/max/max.js b/src/max/max.js
index 16fd16d..5a410d5 100644
--- a/src/max/max.js
+++ b/src/max/max.js
@@ -1,35 +1,9 @@
-/**
- * Find max value using language operator
- *
- * @param {Array} source Source input
- *
- * @return {mixed}
- */
-const maxByValue = source => {
- if (source.length === 0) {
- return undefined
- }
-
- let [maxValue] = source
+import { curry } from "../curry/curry"
+import { pipe } from "../pipe/pipe"
- for (let i = 0, length = source.length; i < length; i++) {
- if (maxValue < source[i]) {
- maxValue = source[i]
- }
- }
+const _maxBy = (_fn, source) => {
+ const fn = Array.isArray(_fn) ? pipe(..._fn) : _fn
- return maxValue
-}
-
-/**
- * Find max value using function to transform element into numeric
- *
- * @param {Function} fn Transform function
- * @param {Array} source Source input
- *
- * @return {mixed}
- */
-const maxByFunction = fn => source => {
if (source.length === 0) {
return undefined
}
@@ -52,30 +26,42 @@ const maxByFunction = fn => source => {
/**
* Find the maximum value in a source array
*
- * @param {Array|Function} arg1 Custom transform function or source array
- * @param {number[]} source Array of numbers
+ * @param {Number[]} source Array of numbers
*
- * @return {number}
+ * @return {Number}
*
* @name max
* @tag Array
- * @signature ( source: Number[] ): Number
- * @signature ( fn: Function ) => ( source: Number[] ): Number
+ * @signature (source: Number[]): Number
+ * @signature (fn: Function, source: Number[]): Number
*
* @example
* max([-1, 1, 10, 3])
* // => 10
*
- * const fn = element => ( new Date( element.time ) )
+ * const fn = element => (new Date(element.time))
* const source = [
* { time: "2018-05-15T11:20:07.754110Z" },
* { time: "2018-06-11T09:01:54.337344Z" },
* { time: "2018-06-08T08:26:12.711071Z" },
* ]
- * max(fn)(source)
+ * max(fn, source)
* // => {time: "2018-06-11T09:01:54.337344Z"}
*/
-const max = arg1 =>
- Array.isArray(arg1) ? maxByValue(arg1) : maxByFunction(arg1)
+export const max = source => {
+ if (source.length === 0) {
+ return undefined
+ }
+
+ let [maxValue] = source
+
+ for (let i = 0, length = source.length; i < length; i++) {
+ if (maxValue < source[i]) {
+ maxValue = source[i]
+ }
+ }
+
+ return maxValue
+}
-export { max }
+export const maxBy = curry(_maxBy)
diff --git a/src/max/max.test.js b/src/max/max.test.js
index 52376d9..491a05a 100644
--- a/src/max/max.test.js
+++ b/src/max/max.test.js
@@ -1,13 +1,22 @@
import test from "tape"
-import { i, max } from ".."
+
+import { i } from "../i/i"
+import { max, maxBy } from "./max"
test("max", t => {
t.equals(max([-1, 1, 10, 3]), 10, "Find max in numeric array")
t.equals(max([]), undefined, "Find max in empty array (=> undefined)")
t.equals(max([-1, -10, -3]), -1, "Find max in all negative numeric array")
t.equals(max([1, 10, 3]), 10, "Find max in all positive numeric array")
+
+ t.end()
+})
+
+test("maxBy", t => {
+ t.equals(maxBy(i, [1, 10, 3]), 10, "Find max in all positive numeric array")
+
t.equals(
- max(i)([]),
+ maxBy(i, []),
undefined,
"Find max in empty array using transform function (=> undefined)"
)
@@ -20,7 +29,7 @@ test("max", t => {
]
t.deepEquals(
- max(fn)(source),
+ maxBy(fn, source),
{ time: "2018-06-11T09:01:54.337344Z" },
"Custom transform function"
)
diff --git a/src/merge/merge.test.js b/src/merge/merge.test.js
index f247062..3a7ba97 100644
--- a/src/merge/merge.test.js
+++ b/src/merge/merge.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { merge, mergeAll, mergeBy } from ".."
+
+import { merge, mergeAll, mergeBy } from "./merge"
test("merge, mergeAll", t => {
const obj1 = { a: undefined }
diff --git a/src/min/min.js b/src/min/min.js
index af7163c..4f42932 100644
--- a/src/min/min.js
+++ b/src/min/min.js
@@ -1,35 +1,9 @@
-/**
- * Find min value using language operator
- *
- * @param {Array} source Source input
- *
- * @return {mixed}
- */
-const minByValue = source => {
- if (source.length === 0) {
- return undefined
- }
-
- let [result] = source
+import { pipe } from "../pipe/pipe"
+import { curry } from "../curry/curry"
- for (let i = 0, length = source.length; i < length; i++) {
- if (result > source[i]) {
- result = source[i]
- }
- }
+const _minBy = (_fn, source) => {
+ const fn = Array.isArray(_fn) ? pipe(..._fn) : _fn
- return result
-}
-
-/**
- * Find min value using function to transform element into numeric
- *
- * @param {Function} fn Transform function
- * @param {Array} source Source input
- *
- * @return {mixed}
- */
-const minByFunction = fn => source => {
if (source.length === 0) {
return undefined
}
@@ -52,10 +26,9 @@ const minByFunction = fn => source => {
/**
* Find the minimum value in a source array
*
- * @param {Array|Function} arg1 Custom transform function or source array
- * @param {number[]} source Array of numbers
+ * @param {Number[]} source Array of numbers
*
- * @return {number}
+ * @return {Number}
*
* @name min
* @tag Array
@@ -75,7 +48,20 @@ const minByFunction = fn => source => {
* min(fn)(source)
* // => {time: "2018-05-15T11:20:07.754110Z"}
*/
-const min = arg1 =>
- Array.isArray(arg1) ? minByValue(arg1) : minByFunction(arg1)
+export const min = source => {
+ if (source.length === 0) {
+ return undefined
+ }
+
+ let [result] = source
+
+ for (let i = 0, length = source.length; i < length; i++) {
+ if (result > source[i]) {
+ result = source[i]
+ }
+ }
+
+ return result
+}
-export { min }
+export const minBy = curry(_minBy)
diff --git a/src/min/min.test.js b/src/min/min.test.js
index f3f4210..adedc2f 100644
--- a/src/min/min.test.js
+++ b/src/min/min.test.js
@@ -1,13 +1,23 @@
import test from "tape"
-import { i, min } from ".."
+
+import { i } from "../i/i"
+import { min, minBy } from "./min"
test("min", t => {
t.equals(min([-1, 1, 10, 3]), -1, "Find min in numeric array")
+
t.equals(min([]), undefined, "Find min in empty array (=> undefined)")
+
t.equals(min([1, 10, 3]), 1, "Find min in all positive numeric array")
+
t.equals(min([-1, -10, -3]), -10, "Find min in all negative numeric array")
+
+ t.end()
+})
+
+test("minBy", t => {
t.equals(
- min(i)([]),
+ minBy(i, []),
undefined,
"Find min in empty array using transform function (=> undefined)"
)
@@ -20,7 +30,7 @@ test("min", t => {
]
t.deepEquals(
- min(fn)(source),
+ minBy(fn, source),
{ time: "2018-05-15T11:20:07.754110Z" },
"Custom transform function"
)
diff --git a/src/partition/partition.js b/src/partition/partition.js
index ec200f5..11557ae 100644
--- a/src/partition/partition.js
+++ b/src/partition/partition.js
@@ -1,8 +1,9 @@
/* eslint-disable no-unused-vars*/
-import { isMatch } from "../is-match/is-match"
import { pipe } from "../pipe/pipe"
import { reduce } from "../reduce/reduce"
+import { curry } from "../curry/curry"
+import { isMatch } from "../is-match/is-match"
const _partition = (_fn, source) => {
const fn = Array.isArray(_fn) ? pipe(..._fn) : _fn
@@ -33,22 +34,13 @@ const _partition = (_fn, source) => {
*
* @name partition
* @tag Array
- * @signature (fn: Function|Funciton[]) => (source: Array) => [[], []]
* @signature (fn: Function|Funciton[], source: Array) => [[], []]
*
* @example
* partition(x => x % 2 === 0)([1, 2, 3, 4, 5])
* // => [[2, 4], [1, 3, 5]]
*/
-export const partition = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _partition(params[0], source)
- }
-
- // @signature (fn, source)
- return _partition(...params)
-}
+export const partition = curry(_partition)
/**
* Split a list based on object matching
@@ -63,19 +55,12 @@ export const partition = (...params) => {
*
* @name partitionWith
* @tag Array
- * @signature (subset: Object) => (source: Array) => [[], []]
* @signature (subset: Object, source: Array) => [[], []]
*
* @example
* partitionWith({comments: is}, [{id: 1}, {id: 2, comments: []}])
* // => [[{id: 1}], [{id: 2, comments: []}]]
*/
-export const partitionWith = (...params) => {
- // @signature (subset) => (source)
- if (params.length <= 1) {
- return source => _partition(isMatch(params[0]), source)
- }
-
- // @signature (subset, source)
- return _partition(isMatch(params[0]), params[1])
-}
+export const partitionWith = curry((subset, source) =>
+ _partition(isMatch(subset), source)
+)
diff --git a/src/partition/partition.test.js b/src/partition/partition.test.js
index 9af191c..8b03317 100644
--- a/src/partition/partition.test.js
+++ b/src/partition/partition.test.js
@@ -1,9 +1,10 @@
import test from "tape"
+
import { is } from "../is/is"
import { read } from "../read/read"
-import { partition, partitionWith } from ".."
+import { partition, partitionWith } from "./partition"
-test("array::partition", t => {
+test("partition", t => {
const equalsTwo = x => x === 2
t.deepEqual(
@@ -36,6 +37,10 @@ test("array::partition", t => {
"(equalsTwo)([1]) // => [[], [1]]"
)
+ t.end()
+})
+
+test("partitionWith", t => {
t.deepEqual(
partitionWith({
parentId: is,
diff --git a/src/pick/pick.js b/src/pick/pick.js
index d81ac05..746fc64 100644
--- a/src/pick/pick.js
+++ b/src/pick/pick.js
@@ -1,3 +1,20 @@
+import { curry } from "../curry/curry"
+
+const _pick = (keys, source) => {
+ const result = {}
+
+ for (let i = 0, length = keys.length; i < length; i++) {
+ const key = keys[i]
+ const value = source[key]
+
+ if (Object.hasOwnProperty.call(source, key)) {
+ result[key] = value
+ }
+ }
+
+ return result
+}
+
/**
* Returns a partial copy of an object containing only the keys specified.
* If the key does not exist, the property is ignored.
@@ -14,19 +31,4 @@
* pick(["id", "name"])({id: 2, name: "lorem", description: "lorem ipsum"})
* // => {id: 2, name: lorem}
*/
-const pick = keys => source => {
- const result = {}
-
- for (let i = 0, length = keys.length; i < length; i++) {
- const key = keys[i]
- const value = source[key]
-
- if (Object.hasOwnProperty.call(source, key)) {
- result[key] = value
- }
- }
-
- return result
-}
-
-export { pick }
+export const pick = curry(_pick)
diff --git a/src/pick/pick.test.js b/src/pick/pick.test.js
index e453eed..1c95b06 100644
--- a/src/pick/pick.test.js
+++ b/src/pick/pick.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { pick } from ".."
+
+import { pick } from "./pick"
test("pick", t => {
const source = {
diff --git a/src/pluck/pluck.js b/src/pluck/pluck.js
index 957b612..60ad9ce 100644
--- a/src/pluck/pluck.js
+++ b/src/pluck/pluck.js
@@ -1,3 +1,15 @@
+import { curry } from "../curry/curry"
+
+const _pluck = (field, source) => {
+ const result = []
+
+ for (let i = 0, length = source.length; i < length; i++) {
+ result.push(source[i][field])
+ }
+
+ return result
+}
+
/**
* Returns a new list by extracting the same named property off all objects in
* the source list
@@ -14,14 +26,4 @@
* pluck("position")([{id: 1, position: 3}, {id:2, position: -1}])
* // => [3, -1]
*/
-const pluck = field => source => {
- const result = []
-
- for (let i = 0, length = source.length; i < length; i++) {
- result.push(source[i][field])
- }
-
- return result
-}
-
-export { pluck }
+export const pluck = curry(_pluck)
diff --git a/src/pluck/pluck.test.js b/src/pluck/pluck.test.js
index d522995..301308e 100644
--- a/src/pluck/pluck.test.js
+++ b/src/pluck/pluck.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { pluck } from ".."
+
+import { pluck } from "./pluck"
test("pluck", t => {
const source = [
@@ -17,7 +18,7 @@ test("pluck", t => {
t.deepEqual(pluck("position")(source), [3, -1], "Array with extracted field")
t.deepEqual(
- pluck("onlyHere")(source),
+ pluck("onlyHere", source),
[1, undefined],
"Array with extracted field not available in all source elements"
)
diff --git a/src/prepend/prepend.js b/src/prepend/prepend.js
index 7b0d759..5ea038a 100644
--- a/src/prepend/prepend.js
+++ b/src/prepend/prepend.js
@@ -1,3 +1,5 @@
+import { curry } from "../curry/curry"
+
const _prepend = (subset, source) => {
if (Array.isArray(source)) {
return Array.isArray(subset)
@@ -17,21 +19,11 @@ const _prepend = (subset, source) => {
* @returns {Array}
*
* @tag Array
- * @signature (subset: String) => (source: String) => String
* @signature (subset: String, source: String) => String
- * @signature (subset: mixed|Array) => (source: Array) => Array
* @signature (subset: mixed|Array, source: Array) => Array
*
* @example
- * concat([1])([4, 5])
+ * prepend([1])([4, 5])
* // => [1, 4, 5]
*/
-export const prepend = (...params) => {
- // @signature (subset) => (source)
- if (params.length <= 1) {
- return source => _prepend(params[0], source)
- }
-
- // @signature (subset, source)
- return _prepend(...params)
-}
+export const prepend = curry(_prepend)
diff --git a/src/prepend/prepend.test.js b/src/prepend/prepend.test.js
index 0a4df1f..ef40961 100644
--- a/src/prepend/prepend.test.js
+++ b/src/prepend/prepend.test.js
@@ -1,4 +1,5 @@
import test from "tape"
+
import { prepend } from "./prepend"
test("prepend", t => {
diff --git a/src/read/read.js b/src/read/read.js
index c645e81..ebd5ec3 100644
--- a/src/read/read.js
+++ b/src/read/read.js
@@ -2,18 +2,39 @@ import { reduce } from "../reduce/reduce"
import { is, isNothing } from "../is/is"
import { pipe } from "../pipe/pipe"
+const _read = (path, defaultValue, source) => {
+ let result = undefined
+
+ if (is(source) && typeof source === "object") {
+ result = pipe(
+ reduce(
+ (acc, item) =>
+ is(acc) && typeof acc === "object" ? acc[item] : undefined,
+ source
+ ),
+
+ // only return default value if it's explicitly set.
+ // this way values of "null", "NaN" are not masked
+ value => (isNothing(value) && is(defaultValue) ? defaultValue : value)
+ )(Array.isArray(path) ? path : [path])
+ }
+
+ return isNothing(result) && is(defaultValue) ? defaultValue : result
+}
+
/**
* Get value from obj property
*
- * @param {string|string[]} path Property name or dot path of props
- * @param {mixed} defaultValue Value to return if not found
- * @param {object} source Source object
+ * @param {String|String[]} path Property name or dot path of props
+ * @param {Any} defaultValue Value to return if not found
+ * @param {Object} source Source object
*
- * @return {mixed}
+ * @return {Any}
*
* @name read
* @tag Object
- * @signature (path: string|string[]) => (source: Object|Array): mixed
+ * @signature (path: String|String[], source: Object|Array): mixed
+ * @signature (path: String|String[], defaultValue: Any, source: Object|Array): mixed
*
* @example
* read("lorem")({ lorem: "ipsum" })
@@ -31,24 +52,10 @@ import { pipe } from "../pipe/pipe"
* read(["a", "test"])({ a: { b: "c" } })
* // => undefined
*/
-const read = (path, defaultValue) => source => {
- let result = undefined
-
- if (is(source) && typeof source === "object") {
- result = pipe(
- reduce(
- (acc, item) =>
- is(acc) && typeof acc === "object" ? acc[item] : undefined,
- source
- ),
-
- // only return default value if it's explicitly set.
- // this way values of "null", "NaN" are not masked
- value => (isNothing(value) && is(defaultValue) ? defaultValue : value)
- )(Array.isArray(path) ? path : [path])
+export const read = (...params) => {
+ if (params.length <= 2) {
+ return source => _read(params[0], params[1], source)
}
- return isNothing(result) && is(defaultValue) ? defaultValue : result
+ return _read(...params)
}
-
-export { read }
diff --git a/src/read/read.test.js b/src/read/read.test.js
index 97c41e6..7c1a0e2 100644
--- a/src/read/read.test.js
+++ b/src/read/read.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { read } from ".."
+
+import { read } from "./read"
test("read", t => {
t.equal(
diff --git a/src/reduce/reduce.test.js b/src/reduce/reduce.test.js
index e99dc99..94d599b 100644
--- a/src/reduce/reduce.test.js
+++ b/src/reduce/reduce.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { reduce } from ".."
+
+import { reduce } from "./reduce"
test("reduce", t => {
t.equals(
diff --git a/src/remove/remove.js b/src/remove/remove.js
index 797edf6..8074e63 100644
--- a/src/remove/remove.js
+++ b/src/remove/remove.js
@@ -1,3 +1,4 @@
+import { curry } from "../curry/curry"
import { pipe } from "../pipe/pipe"
import { isMatch } from "../is-match/is-match"
@@ -37,15 +38,7 @@ const _remove = (_fn, source) => {
* remove(_ => _ === 3)([1, 2, 3])
* // => [1, 2]
*/
-export const remove = (...params) => {
- // @signature (fn) => (source)
- if (params.length <= 1) {
- return source => _remove(params[0], source)
- }
-
- // @signature (fn, source)
- return _remove(...params)
-}
+export const remove = curry(_remove)
/**
* Remove element(s) by matching object
@@ -67,12 +60,6 @@ export const remove = (...params) => {
* remove(_ => _ === 3)([1, 2, 3])
* // => [1, 2]
*/
-export const removeWith = (...params) => {
- // @signature (subset) => (source)
- if (params.length <= 1) {
- return source => _remove(isMatch(params[0]), source)
- }
-
- // @signature (subset, source)
- return _remove(isMatch(params[0]), params[1])
-}
+export const removeWith = curry((subset, source) =>
+ _remove(isMatch(subset), source)
+)
diff --git a/src/remove/remove.test.js b/src/remove/remove.test.js
index c44fa0f..434c869 100644
--- a/src/remove/remove.test.js
+++ b/src/remove/remove.test.js
@@ -1,9 +1,16 @@
import test from "tape"
+
import { isEmpty } from "../is-empty/is-empty"
import { read } from "../read/read"
-import { remove, removeWith } from ".."
+import { remove, removeWith } from "./remove"
+
+test("remove", t => {
+ t.deepEqual(
+ remove(isEmpty, []),
+ [],
+ "Remove elements from empty array should return empty array"
+ )
-test("remove(With)", t => {
t.deepEqual(
remove(_ => _ === 3)([1, 2, 3]),
[1, 2],
@@ -25,6 +32,10 @@ test("remove(With)", t => {
"Remove existing element from array of objects using predicate pipeline"
)
+ t.end()
+})
+
+test("removeWith", t => {
t.deepEqual(
removeWith({ author: null })([
{ id: 1, author: null },
@@ -45,9 +56,5 @@ test("remove(With)", t => {
"Remove multiple elements from array by matching a subset (uncurried)"
)
- const source = [1, 2, 3]
-
- t.notEqual(remove(3)(source), source, "Imutable")
-
t.end()
})
diff --git a/src/repeat/repeat.js b/src/repeat/repeat.js
index 1874992..9b99fa7 100644
--- a/src/repeat/repeat.js
+++ b/src/repeat/repeat.js
@@ -6,7 +6,7 @@ const _repeat = (_fn, count = 0) => {
const isFunction = typeof fn === "function"
for (let i = 0; i < count; i++) {
- result.push(isFunction ? fn(i) : fn)
+ result.push(isFunction ? fn(i, result) : fn)
}
return result
@@ -22,7 +22,7 @@ const _repeat = (_fn, count = 0) => {
*
* @name repeat
* @tag Array
- * @signature (fn: Function|mixed) => (count: Number): Array
+ * @signature (fn: Function|Mixed) => (count: Number): Array
*
* @example
* repeat(2)(3)
diff --git a/src/repeat/repeat.test.js b/src/repeat/repeat.test.js
index 8263f8d..9d76d87 100644
--- a/src/repeat/repeat.test.js
+++ b/src/repeat/repeat.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { repeat } from ".."
+
+import { repeat } from "./repeat"
test("repeat", t => {
const inc = x => x + 1
diff --git a/src/same/same.js b/src/same/same.js
index 165d73d..a5ec7c5 100644
--- a/src/same/same.js
+++ b/src/same/same.js
@@ -5,6 +5,4 @@
*
* @returns {any}
*/
-const same = source => () => source
-
-export { same }
+export const same = source => () => source
diff --git a/src/same/same.test.js b/src/same/same.test.js
index 1a49172..103cc86 100644
--- a/src/same/same.test.js
+++ b/src/same/same.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { same } from ".."
+
+import { same } from "./same"
test("same", t => {
const obj = {}
diff --git a/src/sequence/sequence.test.js b/src/sequence/sequence.test.js
index eefb314..c47dc02 100644
--- a/src/sequence/sequence.test.js
+++ b/src/sequence/sequence.test.js
@@ -1,6 +1,7 @@
import test from "tape"
+
import { isTrue } from "../is/is"
-import { sequence, sequenceWhile } from ".."
+import { sequence, sequenceWhile } from "./sequence"
const delay = (ms, val) =>
new Promise(resolve => setTimeout(() => resolve(val), ms))
diff --git a/src/starts-with/starts-with.test.js b/src/starts-with/starts-with.test.js
index 3c8703d..4c1094d 100644
--- a/src/starts-with/starts-with.test.js
+++ b/src/starts-with/starts-with.test.js
@@ -1,5 +1,6 @@
import test from "tape"
-import { startsWith } from ".."
+
+import { startsWith } from "./starts-with"
test("startsWith", t => {
t.equals(
diff --git a/src/trim/trim.js b/src/trim/trim.js
index 72db443..83cc3c7 100644
--- a/src/trim/trim.js
+++ b/src/trim/trim.js
@@ -1,26 +1,38 @@
import { escapeRegExp } from "../escapeRegExp/escapeRegExp"
+const _trim = (char = " ", source) => {
+ const safeChar = escapeRegExp(char)
+
+ return source.replace(new RegExp(`^[${safeChar}]+|[${safeChar}]+$`, "g"), "")
+}
+
/**
* Remove char from beginning and end of string
*
- * @param {string} char Character to be removed
- * @param {string} source Source string
+ * @param {String} char Character to be removed
+ * @param {String} source Source string
*
- * @return {string}
+ * @return {String}
*
* @tag String
- * @signature (char: string) => (source: string): string
+ * @signature (char: String) => (source: String): String
+ * @signature (char: String, source: String): String
*
* @example
* trim()(" lorem ")
* // => "lorem"
- * trim("-")("-- lorem --")
+ *
+ * trim("-", "-- lorem -")
* // => " lorem "
*/
-const trim = (char = " ") => source => {
- const safeChar = escapeRegExp(char)
+const trim = (...params) => {
+ // @signature (char) => (source)
+ if (params.length <= 1) {
+ return source => _trim(params[0], source)
+ }
- return source.replace(new RegExp(`^[${safeChar}]+|[${safeChar}]+$`, "g"), "")
+ // @signature (char, source)
+ return _trim(...params)
}
export { trim }
diff --git a/src/trim/trim.test.js b/src/trim/trim.test.js
index e626f7c..f413f90 100644
--- a/src/trim/trim.test.js
+++ b/src/trim/trim.test.js
@@ -1,12 +1,13 @@
import test from "tape"
-import { trim } from ".."
+
+import { trim } from "./trim"
test("trim", t => {
- t.equals(trim()(" lorem "), "lorem", "Remove default white space")
+ t.equals(trim()(" lorem "), "lorem", "Remove white space - curried")
- t.equals(trim("-")("-- lorem --"), " lorem ", "Remove custom char")
+ t.equals(trim(" ", " lorem "), "lorem", "Remove white space - uncurried")
- t.equals(trim()(trim()(" lorem ")), "lorem", "Idempotent")
+ t.equals(trim("-")("-- lorem -"), " lorem ", "Remove custom char")
t.end()
})