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