Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/globals/String.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @athenna/common
*
* (c) Robson Trasel <robson@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { String as StringHelper } from '#src/helpers/String'

export class AthennaString {
public constructor(private value: string) {}

/**
* Check if at least one of the provided search strings
* is included in the given string value.
*
* @example
* ```ts
* 'Hello model.id'.athenna.includesSome('models.id', 'models.provider') // false
* 'Hello models.id'.athenna.includesSome(['models.id', 'provider']) // true
* ```
*/
public includesSome(...searches: (string | string[])[]): boolean {
return StringHelper.includesSome(this.value, ...searches)
}

/**
* Check if every provided search string is included
* in the given string value.
*
* @example
* ```ts
* 'Hello model.id'.athenna.includesEvery('models.id', 'models.provider') // false
* 'Hello model.id'.athenna.includesEvery(['model.id', 'Hello']) // true
* ```
*/
public includesEvery(...searches: (string | string[])[]): boolean {
return StringHelper.includesEvery(this.value, ...searches)
}
}

declare global {
interface String {
athenna: AthennaString
}
}

if (!String.prototype.athenna) {
// eslint-disable-next-line no-extend-native
Object.defineProperty(String.prototype, 'athenna', {
get: function () {
return new AthennaString(this)
}
})
}
37 changes: 37 additions & 0 deletions src/helpers/String.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,41 @@ export class String extends Macroable {
return `${value}th`
}
}

/**
* Check if at least one of the provided search strings
* is included in the given value.
*
* @example
* ```ts
* String.includesSome('Hello model.id', 'models.id', 'models.provider') // false
* String.includesSome('Hello models.id', ['models.id', 'provider']) // true (models.id is found)
* ```
*/
public static includesSome(
value: string,
...searches: (string | string[])[]
): boolean {
const terms = Array.isArray(searches[0]) ? (searches[0] as string[]) : (searches as string[])
return terms.some(term => value.includes(term))
}

/**
* Check if every provided search string is included
* in the given value.
*
* @example
* ```ts
* String.includesEvery('Hello model.id', 'models.id', 'models.provider') // false
* String.includesEvery('Hello model.id', ['model.id', 'Hello']) // true (both are found)
* ```
*/
public static includesEvery(
value: string,
...searches: (string | string[])[]
): boolean {
const terms = Array.isArray(searches[0]) ? (searches[0] as string[]) : (searches as string[])
return terms.every(term => value.includes(term))
}

}
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ export * from '#src/types'

export * from '#src/constants/alphabet'

import '#src/globals/Enum'
import '#src/globals/Error'
import '#src/globals/Array'
import '#src/globals/String'

export * from '#src/globals/Enum'
export * from '#src/globals/Error'
export * from '#src/globals/Array'
export * from '#src/globals/String'

export * from '#src/helpers/Exception'
export * from '#src/helpers/Clean'
Expand Down
71 changes: 71 additions & 0 deletions tests/unit/globals/StringTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* @athenna/common
*
* (c) Robson Trasel <robson@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { String } from '#src'
import { Test, type Context } from '@athenna/test'

export default class GlobalStringTest {
@Test()
public async shouldBeAbleToUseStaticMethodsFromStringHelper({ assert }: Context) {
const value = 'Hello model.id and some text'

assert.isTrue(String.includesSome(value, 'model.id', 'nope'))
assert.isTrue(String.includesEvery(value, 'Hello', 'model.id'))
}

@Test()
public async shouldReturnTrueIfAtLeastOneTermMatchesUsingMultipleParams({ assert }: Context) {
const value = 'Hello model.id and some other text'

assert.isTrue(value.athenna.includesSome('model.id', 'nope'))
assert.isTrue(value.athenna.includesSome('some', 'anything'))
assert.isFalse(value.athenna.includesSome('not-found', 'nope'))
}

@Test()
public async shouldReturnTrueIfAtLeastOneTermMatchesUsingAnArray({ assert }: Context) {
const value = 'Hello model.id and some other text'

assert.isTrue(value.athenna.includesSome(['model.id', 'random']))
assert.isFalse(value.athenna.includesSome(['aaa', 'bbb']))
}

@Test()
public async shouldReturnFalseForIncludesSomeWithEmptyTerms({ assert }: Context) {
const value = 'anything'

assert.isFalse(value.athenna.includesSome())
assert.isFalse(value.athenna.includesSome([]))
}

@Test()
public async shouldReturnTrueOnlyIfAllTermsMatchUsingMultipleParams({ assert }: Context) {
const value = 'Hello model.id and some text'

assert.isFalse(value.athenna.includesEvery('Hello', 'somethingElse'))
assert.isTrue(value.athenna.includesEvery('Hello', 'model.id'))
assert.isFalse(value.athenna.includesEvery('model.id', 'not-found'))
}

@Test()
public async shouldReturnTrueOnlyIfAllTermsMatchUsingAnArray({ assert }: Context) {
const value = 'Hello model.id and some text'

assert.isTrue(value.athenna.includesEvery(['Hello', 'model.id']))
assert.isFalse(value.athenna.includesEvery(['Hello', 'random']))
}

@Test()
public async shouldReturnTrueForIncludesEveryWithEmptyTerms({ assert }: Context) {
const value = 'anything'

assert.isTrue(value.athenna.includesEvery())
assert.isTrue(value.athenna.includesEvery([]))
}
}
46 changes: 46 additions & 0 deletions tests/unit/helpers/StringTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,50 @@ export default class StringTest {

assert.throws(useCase, OrdinalNanException)
}

@Test()
public async shouldReturnTrueIfAtLeastOneTermMatchesUsingMultipleParams({ assert }: Context) {
const base = 'Hello model.id and some other text'

assert.isTrue(String.includesSome(base, 'model.id', 'nope'))
assert.isTrue(String.includesSome(base, 'some', 'anything'))
assert.isFalse(String.includesSome(base, 'not-found', 'nope'))
}

@Test()
public async shouldReturnTrueIfAtLeastOneTermMatchesUsingAnArray({ assert }: Context) {
const base = 'Hello model.id and some other text'

assert.isTrue(String.includesSome(base, ['model.id', 'random']))
assert.isFalse(String.includesSome(base, ['aaa', 'bbb']))
}

@Test()
public async shouldReturnFalseForIncludesSomeWithEmptyTerms({ assert }: Context) {
assert.isFalse(String.includesSome('anything'))
assert.isFalse(String.includesSome('anything', []))
}

@Test()
public async shouldReturnTrueOnlyIfAllTermsMatchUsingMultipleParams({ assert }: Context) {
const base = 'Hello model.id and some text'

assert.isFalse(String.includesEvery(base, 'Hello', 'somethingElse'))
assert.isTrue(String.includesEvery(base, 'Hello', 'model.id'))
assert.isFalse(String.includesEvery(base, 'model.id', 'not-found'))
}

@Test()
public async shouldReturnTrueOnlyIfAllTermsMatchUsingAnArray({ assert }: Context) {
const base = 'Hello model.id and some text'

assert.isTrue(String.includesEvery(base, ['Hello', 'model.id']))
assert.isFalse(String.includesEvery(base, ['Hello', 'random']))
}

@Test()
public async shouldReturnTrueForIncludesEveryWithEmptyTerms({ assert }: Context) {
assert.isTrue(String.includesEvery('anything'))
assert.isTrue(String.includesEvery('anything', []))
}
}