Skip to content

Commit

Permalink
Add toggle function to array module (#144)
Browse files Browse the repository at this point in the history
* add toggle function to array module

* build for cdn files

* move strategy to optional config argument

* remove unneeded null check

* rename newItem -> item + rename toValue -> toKey + comment
  • Loading branch information
sodiray authored Nov 11, 2022
1 parent 9e3bf44 commit b8b9ff2
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 4 deletions.
2 changes: 1 addition & 1 deletion cdn/.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9.0.2
9.1.0
18 changes: 17 additions & 1 deletion cdn/radash.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,22 @@ const replaceOrAppend = (list2, newItem, match) => {
}
return [...list2, newItem];
};
const toggle = (list2, item, toKey, options) => {
if (!list2 && !item)
return [];
if (!list2)
return [item];
if (!item)
return [...list2];
const matcher = toKey ? (x, idx) => toKey(x, idx) === toKey(item, idx) : (x) => x === item;
const existing = list2.find(matcher);
if (existing)
return list2.filter((x, idx) => !matcher(x, idx));
const strategy = options?.strategy ?? "append";
if (strategy === "append")
return [...list2, item];
return [item, ...list2];
};
const sift = (list2) => {
return list2?.filter((x) => !!x) ?? [];
};
Expand Down Expand Up @@ -738,4 +754,4 @@ const template = (str, data, regex = /\{\{(.+?)\}\}/g) => {
}, str);
};

export { alphabetical, boil, camel as camal, camel, capitalize, chain, clone, cluster, compose, counting, dash, debounce, defer, diff, draw, first, flat, fork, get, group, intersects, invert, isArray, isDate, isEmpty, isEqual, isFloat, isFunction, isInt, isNumber, isObject, isString, isSymbol, iterate, last, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, max, memo, merge, min, objectify, omit, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, select, series, shake, shift, shuffle, sift, sleep, snake, sort, sum, template, throttle, toFloat, toInt, tryit as try, tryit, uid, unique, upperize, zip };
export { alphabetical, boil, camel as camal, camel, capitalize, chain, clone, cluster, compose, counting, dash, debounce, defer, diff, draw, first, flat, fork, get, group, intersects, invert, isArray, isDate, isEmpty, isEqual, isFloat, isFunction, isInt, isNumber, isObject, isString, isSymbol, iterate, last, list, listify, lowerize, map, mapEntries, mapKeys, mapValues, max, memo, merge, min, objectify, omit, parallel, partial, partob, pascal, pick, proxied, random, range, reduce, replace, replaceOrAppend, retry, select, series, shake, shift, shuffle, sift, sleep, snake, sort, sum, template, throttle, toFloat, toInt, toggle, tryit as try, tryit, uid, unique, upperize, zip };
17 changes: 17 additions & 0 deletions cdn/radash.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,22 @@ var radash = (function (exports) {
}
return [...list2, newItem];
};
const toggle = (list2, item, toKey, options) => {
if (!list2 && !item)
return [];
if (!list2)
return [item];
if (!item)
return [...list2];
const matcher = toKey ? (x, idx) => toKey(x, idx) === toKey(item, idx) : (x) => x === item;
const existing = list2.find(matcher);
if (existing)
return list2.filter((x, idx) => !matcher(x, idx));
const strategy = options?.strategy ?? "append";
if (strategy === "append")
return [...list2, item];
return [item, ...list2];
};
const sift = (list2) => {
return list2?.filter((x) => !!x) ?? [];
};
Expand Down Expand Up @@ -815,6 +831,7 @@ var radash = (function (exports) {
exports.throttle = throttle;
exports.toFloat = toFloat;
exports.toInt = toInt;
exports.toggle = toggle;
exports.try = tryit;
exports.tryit = tryit;
exports.uid = uid;
Expand Down
2 changes: 1 addition & 1 deletion cdn/radash.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "radash",
"version": "9.0.2",
"version": "9.1.0",
"description": "Functional utility library - modern, simple, typed, powerful",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
Expand Down
30 changes: 30 additions & 0 deletions src/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,36 @@ export const replaceOrAppend = <T>(
return [...list, newItem]
}

/**
* If the item matching the condition already exists
* in the list it will be removed. If it does not it
* will be added.
*/
export const toggle = <T>(
list: readonly T[],
item: T,
/**
* Converts an item of type T item into a value that
* can be checked for equality
*/
toKey?: null | ((item: T, idx: number) => number | string | symbol),
options?: {
strategy?: 'prepend' | 'append'
}
) => {
if (!list && !item) return []
if (!list) return [item]
if (!item) return [...list]
const matcher = toKey
? (x: T, idx: number) => toKey(x, idx) === toKey(item, idx)
: (x: T) => x === item
const existing = list.find(matcher)
if (existing) return list.filter((x, idx) => !matcher(x, idx))
const strategy = options?.strategy ?? 'append'
if (strategy === 'append') return [...list, item]
return [item, ...list]
}

/**
* Given a list returns a new list with
* only truthy values
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export {
sift,
sort,
sum,
toggle,
unique
} from './array'
export {
Expand Down
39 changes: 39 additions & 0 deletions src/tests/array.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,4 +635,43 @@ describe('array module', () => {
assert.deepEqual(results, [])
})
})

describe('toggle function', () => {
test('should handle null input list', () => {
const result = _.toggle(null as unknown as any[], 'a')
assert.deepEqual(result, ['a'])
})
test('should handle null input list and null item', () => {
const result = _.toggle(null as unknown as any[], null)
assert.deepEqual(result, [])
})
test('should handle null item', () => {
const result = _.toggle(['a'], null)
assert.deepEqual(result, ['a'])
})
test('should add item when it does not exist using default matcher', () => {
const result = _.toggle(['a'], 'b')
assert.deepEqual(result, ['a', 'b'])
})
test('should remove item when it does exist using default matcher', () => {
const result = _.toggle(['a', 'b'], 'b')
assert.deepEqual(result, ['a'])
})
test('should remove item when it does exist using custom matcher', () => {
const result = _.toggle(
[{ value: 'a' }, { value: 'b' }],
{ value: 'b' },
v => v.value
)
assert.deepEqual(result, [{ value: 'a' }])
})
test('should add item when it does not exist using custom matcher', () => {
const result = _.toggle([{ value: 'a' }], { value: 'b' }, v => v.value)
assert.deepEqual(result, [{ value: 'a' }, { value: 'b' }])
})
test('should prepend item when strategy is set', () => {
const result = _.toggle(['a'], 'b', null, { strategy: 'prepend' })
assert.deepEqual(result, ['b', 'a'])
})
})
})

0 comments on commit b8b9ff2

Please sign in to comment.