Skip to content

Commit

Permalink
fix(toggle): use -1 as index for toKey() with toggled item (#167)
Browse files Browse the repository at this point in the history
Co-authored-by: Alec Larson <[email protected]>
  • Loading branch information
Minhir and aleclarson authored Aug 14, 2024
1 parent e6588da commit 10ee12d
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 12 deletions.
4 changes: 2 additions & 2 deletions docs/array/toggle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ _.toggle(gods, 'ra') // => ['zeus', 'loki']
_.toggle(gods, 'vishnu') // => ['ra', 'zeus', 'loki', 'vishnu']
```

### toggle(list, item, identity)
### toggle(list, item, toKey)

You can pass an optional `toKey` function to determine the identity of non-primitive values. Helpful when working with more complex data types.

Expand All @@ -34,7 +34,7 @@ _.toggle(gods, ra, g => g.name) // => [zeus, loki]
_.toggle(gods, vishnu, g => g.name) // => [ra, zeus, loki, vishnu]
```

### toggle(list, item, identity, options)
### toggle(list, item, toKey, options)

By default, toggle will append the item if it does not exist. If you need to prepend the item instead you can override the `strategy` in the options argument.

Expand Down
35 changes: 25 additions & 10 deletions src/array/toggle.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
/**
* If the item matching the condition already exists in the list it
* will be removed. If it does not it will be added.
* Either adds or removes an item from an array, based on whether it
* already exists in the array. If multiple items match the given
* `item`, all matching items will be removed.
*
* Note that the given `array` is *not mutated*. A copy of the array
* is returned with the given item either added or removed.
*
* - **"toKey" parameter**
* - You may define a `toKey` callback, which is a function that
* converts an item into a value that can be checked for equality.
* When called with the given `item`, an index of -1 will be passed.
*
* - **"strategy" option**
* - You may define a `strategy` option, which determines where the
* item should be added in the array.
*
* @see https://radashi-org.github.io/reference/array/toggle
* @example
Expand All @@ -23,11 +36,7 @@
export function toggle<T>(
array: 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),
toKey?: ((item: T, idx: number) => number | string | symbol) | null,
options?: {
strategy?: 'prepend' | 'append'
},
Expand All @@ -39,9 +48,15 @@ export function toggle<T>(
return [...array]
}

const matcher = toKey
? (x: T, idx: number) => toKey(x, idx) === toKey(item, idx)
: (x: T) => x === item
let matcher: (item: T, idx: number) => boolean

if (toKey) {
const key = toKey(item, -1)

matcher = (x: T, idx: number) => toKey(x, idx) === key
} else {
matcher = (x: T) => x === item
}

const existing = array.find(matcher)

Expand Down
9 changes: 9 additions & 0 deletions tests/array/toggle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,13 @@ describe('toggle', () => {

expect(_.toggle([1, 2], null)).toEqual([1, 2, null])
})
test('should use idx=-1 for item', () => {
const toKey = vi.fn(v => v)

expect(_.toggle(['a', 'b'], 'c', toKey)).toEqual(['a', 'b', 'c'])

expect(toKey).toBeCalledWith('c', -1)
expect(toKey).toBeCalledWith('a', 0)
expect(toKey).toBeCalledWith('b', 1)
})
})

0 comments on commit 10ee12d

Please sign in to comment.