Skip to content

Commit

Permalink
feat(utils): [includes] allow nilable targets
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed Aug 1, 2023
1 parent 261b60d commit 373c45b
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 23 deletions.
13 changes: 7 additions & 6 deletions src/utils/__tests__/includes.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,23 @@ import cast from '../cast'
import testSubject from '../includes'

describe('unit:utils/includes', () => {
it('should return false if value does not include target', () => {
it('should return false if target does not include value', () => {
// Arrange
const cases: Parameters<typeof testSubject>[] = [
[null, '0'],
['abc', 'z'],
['abc', 'a', 1, null],
[['a', 'b', 'c'], 'z'],
[['a', 'b', 'c'], 'a', 1]
]

// Act + Expect
cases.forEach(([value, target, position, identity]) => {
expect(testSubject(value, target, position, identity)).to.be.false
cases.forEach(([target, value, position, identity]) => {
expect(testSubject(target, value, position, identity)).to.be.false
})
})

it('should return true if value includes target', () => {
it('should return true if target includes value', () => {
// Arrange
const cases: Parameters<typeof testSubject>[] = [
['foobar', 'foo'],
Expand All @@ -40,8 +41,8 @@ describe('unit:utils/includes', () => {
]

// Act + Expect
cases.forEach(([value, target, position, identity]) => {
expect(testSubject(value, target, position, identity)).to.be.true
cases.forEach(([target, value, position, identity]) => {
expect(testSubject(target, value, position, identity)).to.be.true
})
})
})
37 changes: 20 additions & 17 deletions src/utils/includes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,50 @@
* @module tutils/utils/includes
*/

import type { Fn, Nilable, PropertyKey } from '#src/types'
import type { Fn, Nilable, PropertyKey, Values } from '#src/types'
import cast from './cast'
import equal from './equal'
import isNIL from './is-nil'
import isString from './is-string'

/**
* Checks if an array or string `value` includes `target`.
* Checks if an array or string includes `value`.
*
* An array `value` includes `target` if `target` is deeply equal to at least
* one item in the array. A string `value` includes `target` if `target` is
* equal to at least one character in the string.
* An array includes `value` if `value` is deeply equal to at least one item in
* the array. A string includes `value` if `value` is equal to at least one
* character in the string.
*
* When searching an array, an `identity` function can be used to convert array
* items to unique keys. If provided, two items with the same identity key will
* be considered equal.
*
* @todo examples
*
* @template T - Value to search
* @template T - Search target type
* @template K - Identity key type
*
* @param {T} value - Value to search
* @param {unknown} target - Search target
* @param {Nilable<Fn<[T[number]], K>>} [identity] - Identity key function
* @param {T} target - Search target
* @param {unknown} value - Value to search for
* @param {Nilable<number>} [position] - Position to begin search
* @return {boolean} `true` if `value` includes `target`
* @param {Nilable<Fn<[Values<T>[number]], K>>} [identity] - Identity function
* @return {boolean} `true` if `target` includes `value`
*/
const includes = <
T extends string | readonly unknown[],
T extends Nilable<string | readonly unknown[]>,
K extends PropertyKey = PropertyKey
>(
value: T,
target: unknown,
target: T,
value: unknown,
position?: Nilable<number>,
identity?: Nilable<Fn<[T[number]], K>>
identity?: Nilable<Fn<[Values<T>[number]], K>>
): boolean => {
position ??= 0

return isString(value)
? value.includes(cast(target), position)
: value.slice(position).some(item => equal(target, item, identity))
return isNIL(target)
? false
: isString(target)
? target.includes(cast(value), position)
: target.slice(position).some(item => equal(value, item, identity))
}

export default includes

0 comments on commit 373c45b

Please sign in to comment.