From a6dd0ae1e69e9926f218430d32ca9d386254de14 Mon Sep 17 00:00:00 2001 From: RobsonTrasel Date: Sat, 1 Mar 2025 22:00:07 -0300 Subject: [PATCH 1/5] feat(String): add includesSome function - Creates the static includesSome method in String - Checks if at least one of the given terms is included in the base string --- src/helpers/String.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/helpers/String.ts b/src/helpers/String.ts index ccff41d..225e94b 100644 --- a/src/helpers/String.ts +++ b/src/helpers/String.ts @@ -252,4 +252,24 @@ 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)) + } + + } From 642d9310f6dac700eaf40aa5e7475fd61c102bdd Mon Sep 17 00:00:00 2001 From: RobsonTrasel Date: Sat, 1 Mar 2025 22:03:34 -0300 Subject: [PATCH 2/5] feat(String): add includesEvery function - Creates the static includesEvery method in String - Checks if all of the given terms are included in the base string --- src/helpers/String.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/helpers/String.ts b/src/helpers/String.ts index 225e94b..0da3b9b 100644 --- a/src/helpers/String.ts +++ b/src/helpers/String.ts @@ -271,5 +271,22 @@ export class String extends Macroable { 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)) + } } From ca8b83ddc2ca573212ea907c5fbb88574c8a3607 Mon Sep 17 00:00:00 2001 From: RobsonTrasel Date: Sat, 1 Mar 2025 22:18:18 -0300 Subject: [PATCH 3/5] test(String): add test coverage for includesSome and includesEvery - Adds tests for includesSome with multiple params and with an array: * shouldReturnTrueIfAtLeastOneTermMatchesUsingMultipleParams * shouldReturnTrueIfAtLeastOneTermMatchesUsingAnArray * shouldReturnFalseForIncludesSomeWithEmptyTerms - Adds tests for includesEvery with multiple params and with an array: * shouldReturnTrueOnlyIfAllTermsMatchUsingMultipleParams * shouldReturnTrueOnlyIfAllTermsMatchUsingAnArray * shouldReturnTrueForIncludesEveryWithEmptyTerms Ensures maximum coverage and verifies behavior under various conditions (e.g., no matches, partial matches, empty arrays). --- tests/unit/helpers/StringTest.ts | 46 ++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/unit/helpers/StringTest.ts b/tests/unit/helpers/StringTest.ts index 7545097..65d2fd6 100644 --- a/tests/unit/helpers/StringTest.ts +++ b/tests/unit/helpers/StringTest.ts @@ -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', [])) + } } From 0fb33af1f5568be9dd2afb79f51f48e589e4f669 Mon Sep 17 00:00:00 2001 From: RobsonTrasel Date: Wed, 11 Feb 2026 19:16:36 -0300 Subject: [PATCH 4/5] feat(globals): add String.athenna for includesSome and includesEvery --- src/globals/String.ts | 58 ++++++++++++++++++++++++++++++ src/index.ts | 1 + tests/unit/globals/StringTest.ts | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 src/globals/String.ts create mode 100644 tests/unit/globals/StringTest.ts diff --git a/src/globals/String.ts b/src/globals/String.ts new file mode 100644 index 0000000..8027331 --- /dev/null +++ b/src/globals/String.ts @@ -0,0 +1,58 @@ +/** + * @athenna/common + * + * (c) Robson Trasel + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { String } 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 String.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 String.includesEvery(this.value, ...searches) + } +} + +declare global { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions + 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) + } + }) +} diff --git a/src/index.ts b/src/index.ts index 31e72c9..85e50b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ export * from '#src/constants/alphabet' 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' diff --git a/tests/unit/globals/StringTest.ts b/tests/unit/globals/StringTest.ts new file mode 100644 index 0000000..8e9c7bc --- /dev/null +++ b/tests/unit/globals/StringTest.ts @@ -0,0 +1,62 @@ +/** + * @athenna/common + * + * (c) Robson Trasel + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Test, type Context } from '@athenna/test' + +export default class GlobalStringTest { + @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([])) + } +} From 1e26f5dd150961b2395eca75b715913d35283e6d Mon Sep 17 00:00:00 2001 From: RobsonTrasel Date: Wed, 11 Feb 2026 19:36:50 -0300 Subject: [PATCH 5/5] fix: use StringHelper alias to avoid shadowing native String --- src/globals/String.ts | 7 +++---- src/index.ts | 5 +++++ tests/unit/globals/StringTest.ts | 9 +++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/globals/String.ts b/src/globals/String.ts index 8027331..84ff3be 100644 --- a/src/globals/String.ts +++ b/src/globals/String.ts @@ -7,7 +7,7 @@ * file that was distributed with this source code. */ -import { String } from '#src/helpers/String' +import { String as StringHelper } from '#src/helpers/String' export class AthennaString { public constructor(private value: string) {} @@ -23,7 +23,7 @@ export class AthennaString { * ``` */ public includesSome(...searches: (string | string[])[]): boolean { - return String.includesSome(this.value, ...searches) + return StringHelper.includesSome(this.value, ...searches) } /** @@ -37,12 +37,11 @@ export class AthennaString { * ``` */ public includesEvery(...searches: (string | string[])[]): boolean { - return String.includesEvery(this.value, ...searches) + return StringHelper.includesEvery(this.value, ...searches) } } declare global { - // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface String { athenna: AthennaString } diff --git a/src/index.ts b/src/index.ts index 85e50b8..5dcdd8e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,11 @@ 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' diff --git a/tests/unit/globals/StringTest.ts b/tests/unit/globals/StringTest.ts index 8e9c7bc..e1967c2 100644 --- a/tests/unit/globals/StringTest.ts +++ b/tests/unit/globals/StringTest.ts @@ -7,9 +7,18 @@ * 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'