From e36ffddd99386bb273a95f44ff67ee286adfec38 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 09:03:52 +0200 Subject: [PATCH 01/66] test: add test for 'isConsiderableCharSequence' method --- test/main.spec.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/main.spec.ts b/test/main.spec.ts index a0d517c..7b169bb 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -28,3 +28,19 @@ for (const key of replaceAtExpectedReturns.keys()) { ); }); } + +const isConsiderableCharSequenceExpectedReturns = new Map([ + [' t', false], + ['of', true], + [' of', true], + ['of ', true], + ['f ', false], +]); +for (const [ + input, + output, +] of isConsiderableCharSequenceExpectedReturns.entries()) { + test(`Should return '${output}' for '${input}'`, () => { + expect(StringUtils.isConsiderableCharSequence(input)).toBe(output); + }); +} From 246853133824a5c6893928388bcb2b21d59f2649 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 09:05:17 +0200 Subject: [PATCH 02/66] feat: implement 'isConsiderableCharSequence' logic --- src/main.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main.ts b/src/main.ts index e100ef8..ead5345 100644 --- a/src/main.ts +++ b/src/main.ts @@ -34,4 +34,22 @@ export class StringUtils { return strArray.join(''); } + + /** + * Returns a boolean indicating if given string is atleast 2 lengthed string + * + * @param {string} str + * @example + * str: ' t' + * returns: false + * @example + * str: 'test' + * returns: true + * @example + * str: 'of ' + * returns: true + */ + public static isConsiderableCharSequence(str: string): boolean { + return str.trim().replaceAll(' ', '').length >= 2; + } } From f3174d10e91140d7484f99fccd03e3bb57669717 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 09:12:13 +0200 Subject: [PATCH 03/66] refactor: use 'isConsiderableCharSequence' method invokation instead of rewrite the same code in different methdos --- src/case.ts | 3 ++- src/main.ts | 35 +++++++++++++++++------------------ src/word-ending-utils.ts | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/case.ts b/src/case.ts index a7ef80a..f48a472 100644 --- a/src/case.ts +++ b/src/case.ts @@ -1,3 +1,4 @@ +import { StringUtils } from './main'; import StringUtilsWord from './word-ending-utils'; /** @@ -106,7 +107,7 @@ export default class StringUtilsCase { * returns: this_is_a_test */ public static convertToCase(str: string, caseToConvert: Case): string { - if (str.trim().replaceAll(' ', '').length < 2) return str; + if (!StringUtils.isConsiderableCharSequence(str)) return str; const splittedByCaseString = this.splitByCase(str); if (splittedByCaseString.length == 1) return str; // Case was unsucessfully determinated diff --git a/src/main.ts b/src/main.ts index ead5345..b1907b4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,23 @@ export class StringUtils { public static isBlank(str: string): boolean { return str.trim().replaceAll(' ', '').length == 0; } + /** + * Returns a boolean indicating if given string is atleast 2 lengthed string + * + * @param {string} str + * @example + * str: ' t' + * returns: false + * @example + * str: 'test' + * returns: true + * @example + * str: 'of ' + * returns: true + */ + public static isConsiderableCharSequence(str: string): boolean { + return str.trim().replaceAll(' ', '').length >= 2; + } /** * Replace a subsequent string at a given position by another string in a given string @@ -34,22 +51,4 @@ export class StringUtils { return strArray.join(''); } - - /** - * Returns a boolean indicating if given string is atleast 2 lengthed string - * - * @param {string} str - * @example - * str: ' t' - * returns: false - * @example - * str: 'test' - * returns: true - * @example - * str: 'of ' - * returns: true - */ - public static isConsiderableCharSequence(str: string): boolean { - return str.trim().replaceAll(' ', '').length >= 2; - } } diff --git a/src/word-ending-utils.ts b/src/word-ending-utils.ts index 9abcfb3..a3629c7 100644 --- a/src/word-ending-utils.ts +++ b/src/word-ending-utils.ts @@ -130,7 +130,7 @@ export default class StringUtilsWord { * returns: Passes */ public static pluralize(word: string): string { - if (word.trim().replaceAll(' ', '').length < 2 || this.isPlural(word)) + if (!StringUtils.isConsiderableCharSequence(word) || this.isPlural(word)) return word; const wordEnding = this.getCorrespondingEnding(word); @@ -150,7 +150,7 @@ export default class StringUtilsWord { * returns: Pass */ public static singularize(word: string): string { - if (word.trim().replaceAll(' ', '').length < 2 || this.isSingular(word)) + if (!StringUtils.isConsiderableCharSequence(word) || this.isSingular(word)) return word; const wordEnding = this.getCorrespondingEnding(word); From f58ed54542d54ed033bb42d6f71de0393ce08d19 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 09:15:07 +0200 Subject: [PATCH 04/66] chore(files): rename 'words-ending-utils.ts' -> 'word.ts' --- src/case.ts | 2 +- src/index.ts | 2 +- src/{word-ending-utils.ts => word.ts} | 0 test/words.spec.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename src/{word-ending-utils.ts => word.ts} (100%) diff --git a/src/case.ts b/src/case.ts index f48a472..4e14962 100644 --- a/src/case.ts +++ b/src/case.ts @@ -1,5 +1,5 @@ import { StringUtils } from './main'; -import StringUtilsWord from './word-ending-utils'; +import StringUtilsWord from './word'; /** * This interface provide a structure for literal objects diff --git a/src/index.ts b/src/index.ts index 5f95ffc..d334e91 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ export * from './main'; export * from './case'; -export * from './word-ending-utils'; +export * from './word'; diff --git a/src/word-ending-utils.ts b/src/word.ts similarity index 100% rename from src/word-ending-utils.ts rename to src/word.ts diff --git a/test/words.spec.ts b/test/words.spec.ts index 20ee1f0..fc2466d 100644 --- a/test/words.spec.ts +++ b/test/words.spec.ts @@ -1,4 +1,4 @@ -import StringUtilsWord, { IWordEnding } from '../src/word-ending-utils'; +import StringUtilsWord, { IWordEnding } from '../src/word'; describe('Get word ending', () => { const getWordEndingReturns = new Map([ From 2273aa5f79d71b4dbc6ef87eb82ec074fc7290ff Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 09:44:27 +0200 Subject: [PATCH 05/66] test: add tests for 'removeBlankChars' method --- test/main.spec.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/main.spec.ts b/test/main.spec.ts index 7b169bb..6ea080e 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -44,3 +44,15 @@ for (const [ expect(StringUtils.isConsiderableCharSequence(input)).toBe(output); }); } + +const removeBlankCharsExpectedReturns = new Map([ + ['This is a test', 'Thisisatest'], + ['Thisisatest', 'Thisisatest'], + [' ', ''], + ['', ''], +]); +for (const [input, output] of removeBlankCharsExpectedReturns.entries()) { + test(`Should return '${output}' for '${input}'`, () => { + expect(StringUtils.removeBlankChars(input)).toBe(output); + }); +} From 8fba6582bf8b3452d78f48dab927ad936f0fb630 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 09:45:58 +0200 Subject: [PATCH 06/66] feat: implement 'removeBlankChars' logic --- src/main.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main.ts b/src/main.ts index b1907b4..1da2c51 100644 --- a/src/main.ts +++ b/src/main.ts @@ -51,4 +51,17 @@ export class StringUtils { return strArray.join(''); } + + /** + * Return a string removed from all blank chars + * + * @param {string} str - The string of which remove blank spaces + * + * @example + * str: This is my example + * returns: Thisismyexample + */ + public static removeBlankChars(str: string): string { + return str.replaceAll(' ', ''); + } } From f4f43718b2ce870eb4599fc61c7f50e99e43b525 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 09:51:05 +0200 Subject: [PATCH 07/66] test: add tests for 'toCamelCase' method --- test/case.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/case.spec.ts b/test/case.spec.ts index 59b11da..1cb2037 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -52,4 +52,22 @@ describe('Casing operation', () => { expect(StringUtilsCase.convertToCase(...key)).toBe(value); }); } + + const toCamelCaseExpectedReturns = new Map([ + ['thisIsMyTest', 'thisIsMyTest'], + ['ThisIsMyTest', 'thisIsMyTest'], + ['', ''], + ['th', 'tH'], + [' th', 'tH'], + ['thisIsM y Tes t', 'thisIsMyTest'], + ['this_is_my_test', 'thisIsMyTest'], + ['this is my test', 'thisIsMyTest'], + ['ThisIsMyTest', 'thisIsMyTest'], + ['This Is My Test', 'thisIsMyTest'], + ]); + for (const [input, output] of toCamelCaseExpectedReturns.entries()) { + test(`Should return '${output}' for '${input}'`, () => { + expect(StringUtilsCase.toCamelCase(input)).toBe(output); + }); + } }); From d4d00306783233dba4a9746629b58daf6d9f6f41 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 11:00:49 +0200 Subject: [PATCH 08/66] test: add tests for 'blendIrrelevantStringsInRelevantOnes' method --- test/main.spec.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/main.spec.ts b/test/main.spec.ts index 6ea080e..e860128 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -56,3 +56,17 @@ for (const [input, output] of removeBlankCharsExpectedReturns.entries()) { expect(StringUtils.removeBlankChars(input)).toBe(output); }); } + +const blendIrrelevantStringsInRelevantOnes = new Map([ + ['This is my ex a m p l e', ['This', 'is', 'my', 'example']], + ['T h i s m y e x a m p l e', ['Thisismyexample']], + ['This is my ex a m pl e ', ['This', 'is', 'my', 'exam', 'ple']], +]); + +for (const [input, output] of blendIrrelevantStringsInRelevantOnes.entries()) { + test(`Should return '${output}' for '${input}'`, () => { + expect(StringUtils.blendIrrelevantStringsInRelevantOnes(input)).toEqual( + output, + ); + }); +} From 4cae8e2dbb5325bd1a7a986bfbc5e0f2cc76103e Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 11:57:28 +0200 Subject: [PATCH 09/66] fix: add 'this' to input to pass test --- test/main.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/main.spec.ts b/test/main.spec.ts index e860128..59c51de 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -59,7 +59,7 @@ for (const [input, output] of removeBlankCharsExpectedReturns.entries()) { const blendIrrelevantStringsInRelevantOnes = new Map([ ['This is my ex a m p l e', ['This', 'is', 'my', 'example']], - ['T h i s m y e x a m p l e', ['Thisismyexample']], + ['T h i s i s m y e x a m p l e', ['Thisismyexample']], ['This is my ex a m pl e ', ['This', 'is', 'my', 'exam', 'ple']], ]); From 25a656ab01ecf9562a25dd8b9f73e5a0fbdbaad0 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 11:57:52 +0200 Subject: [PATCH 10/66] feat: add 'blendIrrelevantStringsInRelevantOnes' logic --- src/main.ts | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/main.ts b/src/main.ts index 1da2c51..3b48e35 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,5 @@ +import StringUtilsWord from './word'; + export class StringUtils { /** * Check if a given string is blank or not @@ -64,4 +66,50 @@ export class StringUtils { public static removeBlankChars(str: string): string { return str.replaceAll(' ', ''); } + + /** + * Returns a table of string where each element is at least 2 length char + * + * @param {string} str - Should be a string containing spaces and at least 2 letters + * + * @remarks + * This method works only if str starts with a relevant / considerable sub string sequence, it should be rework later to manage following relevant sequences + * + * @example + * str: 'This is my ex a m p l e' + * returns: ['This', 'is', 'my', 'example'] + * @example + * str: 'T h i s m y e x a m p l e' + * returns: ['Thisismyexample'] + * @example + * str: 'Thi s is my exa mple' + * returns: ['This is my exa mple'] + * + */ + public static blendIrrelevantStringsInRelevantOnes(str: string): string[] { + const splittedStr = + StringUtilsWord.normalizeSpacesBetweenWords(str).split(' '); + if ( + splittedStr.find((subSequence) => + this.isConsiderableCharSequence(subSequence), + ) == undefined + ) + return [this.removeBlankChars(str)]; + + const revelantSubSequences: string[] = []; + + /* If the current subsequence is relevant, push it to revelants table + * Otherwise append the current one to the last relevant subsequence + */ + + splittedStr.forEach((subSequence) => { + if (this.isConsiderableCharSequence(subSequence)) + revelantSubSequences.push(subSequence); + else + revelantSubSequences[revelantSubSequences.length - 1] += + `${subSequence}`; + }); + + return revelantSubSequences; + } } From 06f46764c65b02161ea0caf77890a1c869a128e1 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 12:08:35 +0200 Subject: [PATCH 11/66] test: add tests for 'containsConsiderableCharSequence' method --- test/main.spec.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/main.spec.ts b/test/main.spec.ts index 59c51de..f73b744 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -70,3 +70,16 @@ for (const [input, output] of blendIrrelevantStringsInRelevantOnes.entries()) { ); }); } + +const containsConsiderableCharSequence = new Map([ + [['This', 'is', 'my', 'test'], true], + [[' ', ' t ', ' h '], false], + [['t', 'h', 'i'], false], + [[' ', ' '], false], +]); + +for (const [input, output] of containsConsiderableCharSequence.entries()) { + test(`Should return '${output}' for '${input}'`, () => { + expect(StringUtils.containsConsiderableCharSequence(input)).toBe(output); + }); +} From 56751260fb7de81b1891cdffc066dccfd624959d Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 12:12:48 +0200 Subject: [PATCH 12/66] test: add test --- test/main.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/main.spec.ts b/test/main.spec.ts index f73b744..7cb2912 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -76,6 +76,7 @@ const containsConsiderableCharSequence = new Map([ [[' ', ' t ', ' h '], false], [['t', 'h', 'i'], false], [[' ', ' '], false], + [['T', 'h', 'is'], true], ]); for (const [input, output] of containsConsiderableCharSequence.entries()) { From 99a6c3060c8f8b5cf2ca442ac669547d658c8a71 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 12:13:33 +0200 Subject: [PATCH 13/66] feat: implement 'containsConsiderableCharSequence' logic --- src/main.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main.ts b/src/main.ts index 3b48e35..70887df 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,6 +10,7 @@ export class StringUtils { public static isBlank(str: string): boolean { return str.trim().replaceAll(' ', '').length == 0; } + /** * Returns a boolean indicating if given string is atleast 2 lengthed string * @@ -28,6 +29,32 @@ export class StringUtils { return str.trim().replaceAll(' ', '').length >= 2; } + /** + * Returns a boolean indicating if a given string table contains atleast one considerable subsequence + * + * @param {string[]} stringTable - Should be a table of string + * + * @example + * stringTable: ['This', 'is', 'my', 'test'] + * retunrs: true + * @example + * stringTable: [' ', ' ', ' '] + * retunrs: false + * @example + * stringTable: ['t', 'h', 'i'] + * retruns: false + */ + public static containsConsiderableCharSequence( + stringTable: string[], + ): boolean { + if (this.isBlank(stringTable.join(''))) return false; + return ( + stringTable.find((subsequence) => + this.isConsiderableCharSequence(subsequence), + ) != undefined + ); + } + /** * Replace a subsequent string at a given position by another string in a given string * From 173747c8801ea4a77f33ddad138a160308b5c2cd Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 12:15:26 +0200 Subject: [PATCH 14/66] refactor: use 'containsConsiderableCharSequence' in 'blendIrrelevant..' method --- src/main.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main.ts b/src/main.ts index 70887df..59ff763 100644 --- a/src/main.ts +++ b/src/main.ts @@ -116,11 +116,7 @@ export class StringUtils { public static blendIrrelevantStringsInRelevantOnes(str: string): string[] { const splittedStr = StringUtilsWord.normalizeSpacesBetweenWords(str).split(' '); - if ( - splittedStr.find((subSequence) => - this.isConsiderableCharSequence(subSequence), - ) == undefined - ) + if (!this.containsConsiderableCharSequence(splittedStr)) return [this.removeBlankChars(str)]; const revelantSubSequences: string[] = []; From 5f1e81ca556725f6a445dbddf8a4b6647a25052e Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 13:08:28 +0200 Subject: [PATCH 15/66] feat: implement 'toCamelCase' logic --- src/case.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/case.ts b/src/case.ts index 4e14962..3939ada 100644 --- a/src/case.ts +++ b/src/case.ts @@ -133,4 +133,46 @@ export default class StringUtilsCase { return splittedByCaseString.join('_').toLowerCase(); } } + + /** + * Returns a given string converted to camelCase + * + * @param {string} str - The string to convert + * + * @example + * str: ThisIsMyExample + * returns: thisIsMyExample + * @example + * str: thisIsMyExample + * returns: thisIsMyExample + */ + public static toCamelCase(str: string): string { + if (!StringUtils.isConsiderableCharSequence(str)) return str; + + if (str.includes(' ')) { + const removedBlankChars = StringUtils.removeBlankChars(str); + if (this.determineCase(removedBlankChars).name == 'camelCase') { + return removedBlankChars; + } + const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); + + return ( + blended.length < 2 ? this.splitByCase(removedBlankChars) : blended + ) + .map((subSequence, index) => + index == 0 + ? subSequence.toLowerCase() + : StringUtilsWord.formatWord(subSequence), + ) + .join(''); + } + + return this.splitByCase(str) + .map((subSequence, index) => + index == 0 + ? subSequence.toLowerCase() + : StringUtilsWord.formatWord(subSequence), + ) + .join(''); + } } From faff18f5a3751926e6b1d4da1bca29c2c36b62ba Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 13:14:39 +0200 Subject: [PATCH 16/66] refactor: rework condition in 'toCamelCase' method --- src/case.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/case.ts b/src/case.ts index 3939ada..26948e6 100644 --- a/src/case.ts +++ b/src/case.ts @@ -149,25 +149,23 @@ export default class StringUtilsCase { public static toCamelCase(str: string): string { if (!StringUtils.isConsiderableCharSequence(str)) return str; - if (str.includes(' ')) { - const removedBlankChars = StringUtils.removeBlankChars(str); - if (this.determineCase(removedBlankChars).name == 'camelCase') { - return removedBlankChars; - } - const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); - - return ( - blended.length < 2 ? this.splitByCase(removedBlankChars) : blended - ) + if (!str.includes(' ')) + return this.splitByCase(str) .map((subSequence, index) => index == 0 ? subSequence.toLowerCase() : StringUtilsWord.formatWord(subSequence), ) .join(''); + + const removedBlankChars = StringUtils.removeBlankChars(str); + if (this.determineCase(removedBlankChars).name == 'camelCase') { + return removedBlankChars; } - return this.splitByCase(str) + const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); + + return (blended.length < 2 ? this.splitByCase(removedBlankChars) : blended) .map((subSequence, index) => index == 0 ? subSequence.toLowerCase() From a976a975baf44548b10388e65ba40cf85e5a1b74 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 14:10:41 +0200 Subject: [PATCH 17/66] test: add test for 'toPascalCase' methdo --- test/case.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/case.spec.ts b/test/case.spec.ts index 1cb2037..84fadff 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -70,4 +70,22 @@ describe('Casing operation', () => { expect(StringUtilsCase.toCamelCase(input)).toBe(output); }); } + + const toPascalCaseExpectedReturns = new Map([ + ['thisIsMyTest', 'ThisIsMyTest'], + ['ThisIsMyTest', 'ThisIsMyTest'], + ['', ''], + ['th', 'Th'], + [' th', 'tH'], + ['thisIsM y Tes t', 'ThisIsMyTest'], + ['this_is_my_test', 'ThisIsMyTest'], + ['this is my test', 'ThisIsMyTest'], + ['ThisIsMyTest', 'ThisIsMyTest'], + ['This Is My Test', 'ThisIsMyTest'], + ]); + for (const [input, output] of toPascalCaseExpectedReturns.entries()) { + test(`Should return '${output}' for '${input}'`, () => { + expect(StringUtilsCase.toPascalCase(input)).toBe(output); + }); + } }); From 25c2bdacbbca9a46df433f762a23be14decae0e7 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 14:35:46 +0200 Subject: [PATCH 18/66] fix: change output to pass test --- test/case.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/case.spec.ts b/test/case.spec.ts index 84fadff..e7e31f6 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -76,7 +76,7 @@ describe('Casing operation', () => { ['ThisIsMyTest', 'ThisIsMyTest'], ['', ''], ['th', 'Th'], - [' th', 'tH'], + [' th', 'Th'], ['thisIsM y Tes t', 'ThisIsMyTest'], ['this_is_my_test', 'ThisIsMyTest'], ['this is my test', 'ThisIsMyTest'], From 04945e6e4ba74a940ac766a6bb114ec819501838 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 14:36:20 +0200 Subject: [PATCH 19/66] feat: implement 'toPascalCase' logic --- src/case.ts | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/case.ts b/src/case.ts index 26948e6..fbcc5cb 100644 --- a/src/case.ts +++ b/src/case.ts @@ -173,4 +173,44 @@ export default class StringUtilsCase { ) .join(''); } + + /** + * Returns a given string converted to PamelCase + * + * @param {string} str - The string to convert + * + * @example + * str: ThisIsMyExample + * returns: ThisIsMyExample + * @example + * str: thisIsMyExample + * returns: ThisIsMyExample + */ + + public static toPascalCase(str: string): string { + if (!StringUtils.isConsiderableCharSequence(str)) return str; + + if (!str.includes(' ')) { + const splittedByCase = this.splitByCase(str); + + return StringUtils.removeBlankChars( + !StringUtils.containsConsiderableCharSequence(splittedByCase) + ? StringUtilsWord.formatWord(str) + : StringUtilsWord.formatWords(splittedByCase), + ); + } + + const removedBlankChars = StringUtils.removeBlankChars(str); + if (this.determineCase(removedBlankChars).name == 'pascalCase') { + return removedBlankChars; + } + + const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); + + return StringUtils.removeBlankChars( + blended.length < 2 + ? StringUtilsWord.formatWord(str) + : StringUtilsWord.formatWords(blended), + ); + } } From 47795ed55956cc8b5aeda6806c2253bc92c893a9 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 14:58:55 +0200 Subject: [PATCH 20/66] test: add test for 'toSnakeCase' method --- test/case.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/case.spec.ts b/test/case.spec.ts index e7e31f6..69a77ea 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -88,4 +88,22 @@ describe('Casing operation', () => { expect(StringUtilsCase.toPascalCase(input)).toBe(output); }); } + + const toSnakeCaseExpectedReturns = new Map([ + ['thisIsMyTest', 'this_is_my_test'], + ['ThisIsMyTest', 'this_is_my_test'], + ['', ''], + ['th', 't_h'], + [' th', 't_h'], + ['thisIsM y Tes t', 'this_is_my_test'], + ['this_is_my_test', 'this_is_my_test'], + ['this is my test', 'this_is_my_test'], + ['ThisIsMyTest', 'this_is_my_test'], + ['This Is My Test', 'this_is_my_test'], + ]); + for (const [input, output] of toPascalCaseExpectedReturns.entries()) { + test(`Should return '${output}' for '${input}'`, () => { + expect(StringUtilsCase.toPascalCase(input)).toBe(output); + }); + } }); From 531bd7e0b0ba9b1e5ec5f33a6db18ec7c0d27881 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 15:00:05 +0200 Subject: [PATCH 21/66] feat: implement 'toSnakeCase' logic --- src/case.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/case.ts b/src/case.ts index fbcc5cb..1d22baf 100644 --- a/src/case.ts +++ b/src/case.ts @@ -213,4 +213,37 @@ export default class StringUtilsCase { : StringUtilsWord.formatWords(blended), ); } + + /** + * Returns a given string converted to snakeCase + * + * @param {string} str - The string to convert + * + * @example + * str: ThisIsMyExample + * returns: this_is_my_example + * @example + * str: thisIsMyExample + * returns: this_is_my_example + */ + public static toSnakeCase(str: string): string { + if (!StringUtils.isConsiderableCharSequence(str)) return str; + + if (!str.includes(' ')) { + const splittedByCase = this.splitByCase(str); + + return splittedByCase.join('_').toLowerCase(); + } + + const removedBlankChars = StringUtils.removeBlankChars(str); + if (this.determineCase(removedBlankChars).name == 'snakeCase') { + return removedBlankChars; + } + + const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); + + return (blended.length < 2 ? this.splitByCase(str) : blended) + .join('_') + .toLowerCase(); + } } From e02940b63446a905f948902494362b9741fe8925 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 15:13:39 +0200 Subject: [PATCH 22/66] fix: add case determination check --- src/case.ts | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/case.ts b/src/case.ts index 1d22baf..3047575 100644 --- a/src/case.ts +++ b/src/case.ts @@ -107,30 +107,17 @@ export default class StringUtilsCase { * returns: this_is_a_test */ public static convertToCase(str: string, caseToConvert: Case): string { - if (!StringUtils.isConsiderableCharSequence(str)) return str; - - const splittedByCaseString = this.splitByCase(str); - if (splittedByCaseString.length == 1) return str; // Case was unsucessfully determinated - switch (caseToConvert) { case 'lowerCase': - return splittedByCaseString.join('').toLowerCase(); + return str.toLowerCase(); case 'upperCase': - return splittedByCaseString.join('').toUpperCase(); + return str.toUpperCase(); case 'camelCase': - return splittedByCaseString - .map((subSequence, index) => - index == 0 - ? subSequence.toLowerCase() - : StringUtilsWord.formatWord(subSequence), - ) - .join(''); + return this.toCamelCase(str); case 'pascalCase': - return splittedByCaseString - .map((subSequence) => StringUtilsWord.formatWord(subSequence)) - .join(''); + return this.toPascalCase(str); case 'snakeCase': - return splittedByCaseString.join('_').toLowerCase(); + return this.toSnakeCase(str); } } @@ -149,14 +136,18 @@ export default class StringUtilsCase { public static toCamelCase(str: string): string { if (!StringUtils.isConsiderableCharSequence(str)) return str; - if (!str.includes(' ')) - return this.splitByCase(str) + if (!str.includes(' ')) { + if (!this.determineCase(str)) return str; + const splittedByCase = this.splitByCase(str); + + return splittedByCase .map((subSequence, index) => index == 0 ? subSequence.toLowerCase() : StringUtilsWord.formatWord(subSequence), ) .join(''); + } const removedBlankChars = StringUtils.removeBlankChars(str); if (this.determineCase(removedBlankChars).name == 'camelCase') { @@ -191,6 +182,7 @@ export default class StringUtilsCase { if (!StringUtils.isConsiderableCharSequence(str)) return str; if (!str.includes(' ')) { + if (!this.determineCase(str)) return str; const splittedByCase = this.splitByCase(str); return StringUtils.removeBlankChars( @@ -230,6 +222,7 @@ export default class StringUtilsCase { if (!StringUtils.isConsiderableCharSequence(str)) return str; if (!str.includes(' ')) { + if (!this.determineCase(str)) return str; const splittedByCase = this.splitByCase(str); return splittedByCase.join('_').toLowerCase(); From d1225e2c479b50f4c0ba07dc15f0adecbd60c27d Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 15:14:38 +0200 Subject: [PATCH 23/66] fix: fix testing for snake case methdo --- test/case.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/case.spec.ts b/test/case.spec.ts index 69a77ea..cc2474b 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -101,9 +101,9 @@ describe('Casing operation', () => { ['ThisIsMyTest', 'this_is_my_test'], ['This Is My Test', 'this_is_my_test'], ]); - for (const [input, output] of toPascalCaseExpectedReturns.entries()) { + for (const [input, output] of toSnakeCaseExpectedReturns.entries()) { test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtilsCase.toPascalCase(input)).toBe(output); + expect(StringUtilsCase.toSnakeCase(input)).toBe(output); }); } }); From 9c36b8403d35d3155cb15e37669d2a83c6c18643 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 15:55:51 +0200 Subject: [PATCH 24/66] fix: rework 'toSnakeCase' behavior to pass tests --- src/case.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/case.ts b/src/case.ts index 3047575..961b68f 100644 --- a/src/case.ts +++ b/src/case.ts @@ -223,7 +223,9 @@ export default class StringUtilsCase { if (!str.includes(' ')) { if (!this.determineCase(str)) return str; - const splittedByCase = this.splitByCase(str); + const splittedByCase = this.splitByCase( + StringUtils.removeBlankChars(str), + ); return splittedByCase.join('_').toLowerCase(); } @@ -235,8 +237,10 @@ export default class StringUtilsCase { const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); - return (blended.length < 2 ? this.splitByCase(str) : blended) - .join('_') - .toLowerCase(); + return blended.length <= 2 && this.determineCase(blended.join('')) + ? this.splitByCase(blended.join('')).join('_').toLowerCase() + : StringUtilsWord.normalizeSpacesBetweenWords( + blended.join('_'), + ).toLowerCase(); } } From a8c59fa1b8ad03dfd06be1d7af20098093f07969 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 16:34:23 +0200 Subject: [PATCH 25/66] test(coverage): add new tests to get 100% branch coverage --- test/case.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/case.spec.ts b/test/case.spec.ts index cc2474b..a68eb57 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -64,6 +64,7 @@ describe('Casing operation', () => { ['this is my test', 'thisIsMyTest'], ['ThisIsMyTest', 'thisIsMyTest'], ['This Is My Test', 'thisIsMyTest'], + ['thisISMYTEST', 'thisISMYTEST'], ]); for (const [input, output] of toCamelCaseExpectedReturns.entries()) { test(`Should return '${output}' for '${input}'`, () => { @@ -82,6 +83,7 @@ describe('Casing operation', () => { ['this is my test', 'ThisIsMyTest'], ['ThisIsMyTest', 'ThisIsMyTest'], ['This Is My Test', 'ThisIsMyTest'], + ['thisISMYTEST', 'thisISMYTEST'], ]); for (const [input, output] of toPascalCaseExpectedReturns.entries()) { test(`Should return '${output}' for '${input}'`, () => { @@ -100,6 +102,8 @@ describe('Casing operation', () => { ['this is my test', 'this_is_my_test'], ['ThisIsMyTest', 'this_is_my_test'], ['This Is My Test', 'this_is_my_test'], + ['thisISMYTEST', 'thisISMYTEST'], + ['this _ is _ my _ test', 'this_is_my_test'], ]); for (const [input, output] of toSnakeCaseExpectedReturns.entries()) { test(`Should return '${output}' for '${input}'`, () => { From 4e4712cb1d0c55b22045ef574b6d15339e166141 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 16:34:45 +0200 Subject: [PATCH 26/66] fix: add 'toLowerCase 'for snakeCase to pass new tests --- src/case.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/case.ts b/src/case.ts index 961b68f..382ac46 100644 --- a/src/case.ts +++ b/src/case.ts @@ -230,7 +230,7 @@ export default class StringUtilsCase { return splittedByCase.join('_').toLowerCase(); } - const removedBlankChars = StringUtils.removeBlankChars(str); + const removedBlankChars = StringUtils.removeBlankChars(str.toLowerCase()); if (this.determineCase(removedBlankChars).name == 'snakeCase') { return removedBlankChars; } From 5cafb8a04902933c04277d32acdd91b45a90d521 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 16:58:30 +0200 Subject: [PATCH 27/66] refactor: remove 'toLowerCase' --- src/case.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/case.ts b/src/case.ts index 382ac46..961b68f 100644 --- a/src/case.ts +++ b/src/case.ts @@ -230,7 +230,7 @@ export default class StringUtilsCase { return splittedByCase.join('_').toLowerCase(); } - const removedBlankChars = StringUtils.removeBlankChars(str.toLowerCase()); + const removedBlankChars = StringUtils.removeBlankChars(str); if (this.determineCase(removedBlankChars).name == 'snakeCase') { return removedBlankChars; } From e1545eb846f960c1627713d1514eebddf350c4fa Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 17:02:02 +0200 Subject: [PATCH 28/66] refactor: remove useless condition check --- src/case.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/case.ts b/src/case.ts index 961b68f..7a49e4a 100644 --- a/src/case.ts +++ b/src/case.ts @@ -237,7 +237,7 @@ export default class StringUtilsCase { const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); - return blended.length <= 2 && this.determineCase(blended.join('')) + return blended.length <= 2 ? this.splitByCase(blended.join('')).join('_').toLowerCase() : StringUtilsWord.normalizeSpacesBetweenWords( blended.join('_'), From 2495e07db4446ec64b3204dceddfc77257735e82 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:09:59 +0200 Subject: [PATCH 29/66] refactor: use a wrapped method to avoid code rewriting --- src/case.ts | 178 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 71 deletions(-) diff --git a/src/case.ts b/src/case.ts index 7a49e4a..8d44824 100644 --- a/src/case.ts +++ b/src/case.ts @@ -15,6 +15,8 @@ interface ICase { name: Case; matcher: RegExp; splitter: RegExp | string; + noBlendReturn: Function; + blendedReturn: Function; } /** @@ -38,26 +40,104 @@ const knownCases: ICase[] = [ name: 'snakeCase', matcher: /(\w+)_(\w+)/, splitter: '_', + blendedReturn: ( + splittedByCase: string[], + blended: string[], + str: string, + ) => { + return blended.length <= 2 + ? StringUtilsCase.splitByCase(blended.join('')).join('_').toLowerCase() + : StringUtilsWord.normalizeSpacesBetweenWords( + blended.join('_'), + ).toLowerCase(); + }, + noBlendReturn: (splittedByCase: string[], str: string) => { + return splittedByCase.join('_').toLowerCase(); + }, }, { name: 'pascalCase', matcher: /^[A-Z][a-z]+(?:[A-Z][a-z]+)*$/, splitter: /([A-Z]+[a-z]*)/, + blendedReturn: ( + splittedByCase: string[], + blended: string[], + str: string, + ) => { + return StringUtils.removeBlankChars( + blended.length < 2 + ? StringUtilsWord.formatWord(str) + : StringUtilsWord.formatWords(blended), + ); + }, + noBlendReturn: (splittedByCase: string[], str: string) => { + return StringUtils.removeBlankChars( + !StringUtils.containsConsiderableCharSequence(splittedByCase) + ? StringUtilsWord.formatWord(str) + : StringUtilsWord.formatWords(splittedByCase), + ); + }, }, { name: 'lowerCase', matcher: /^[a-z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]*$/, splitter: '', + blendedReturn: ( + splittedByCase: string[], + blended: string[], + str: string, + ) => { + return str.toLowerCase(); + }, + noBlendReturn: (splittedByCase: string[], str: string) => { + return str.toLowerCase(); + }, }, { name: 'upperCase', matcher: /^[A-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]*$/, splitter: '', + blendedReturn: ( + splittedByCase: string[], + blended: string[], + str: string, + ) => { + return str.toUpperCase(); + }, + noBlendReturn: (splittedByCase: string[], str: string) => { + return str.toUpperCase(); + }, }, { name: 'camelCase', matcher: /^[a-z]+(?:[A-Z][a-z]+)*$/, splitter: /([A-Z]+[a-z]*)/, + blendedReturn: ( + splittedByCase: string[], + blended: string[], + str: string, + ) => { + return ( + blended.length < 2 + ? StringUtilsCase.splitByCase(StringUtils.removeBlankChars(str)) + : blended + ) + .map((subSequence, index) => + index == 0 + ? subSequence.toLowerCase() + : StringUtilsWord.formatWord(subSequence), + ) + .join(''); + }, + noBlendReturn: (splittedByCase, str) => { + return splittedByCase + .map((subSequence, index) => + index == 0 + ? subSequence.toLowerCase() + : StringUtilsWord.formatWord(subSequence), + ) + .join(''); + }, }, ]; @@ -109,15 +189,15 @@ export default class StringUtilsCase { public static convertToCase(str: string, caseToConvert: Case): string { switch (caseToConvert) { case 'lowerCase': - return str.toLowerCase(); + return this.convertToCaseLogic('lowerCase', str); case 'upperCase': - return str.toUpperCase(); + return this.convertToCaseLogic('upperCase', str); case 'camelCase': - return this.toCamelCase(str); + return this.convertToCaseLogic('camelCase', str); case 'pascalCase': - return this.toPascalCase(str); + return this.convertToCaseLogic('pascalCase', str); case 'snakeCase': - return this.toSnakeCase(str); + return this.convertToCaseLogic('snakeCase', str); } } @@ -134,35 +214,7 @@ export default class StringUtilsCase { * returns: thisIsMyExample */ public static toCamelCase(str: string): string { - if (!StringUtils.isConsiderableCharSequence(str)) return str; - - if (!str.includes(' ')) { - if (!this.determineCase(str)) return str; - const splittedByCase = this.splitByCase(str); - - return splittedByCase - .map((subSequence, index) => - index == 0 - ? subSequence.toLowerCase() - : StringUtilsWord.formatWord(subSequence), - ) - .join(''); - } - - const removedBlankChars = StringUtils.removeBlankChars(str); - if (this.determineCase(removedBlankChars).name == 'camelCase') { - return removedBlankChars; - } - - const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); - - return (blended.length < 2 ? this.splitByCase(removedBlankChars) : blended) - .map((subSequence, index) => - index == 0 - ? subSequence.toLowerCase() - : StringUtilsWord.formatWord(subSequence), - ) - .join(''); + return this.convertToCaseLogic('camelCase', str); } /** @@ -179,31 +231,7 @@ export default class StringUtilsCase { */ public static toPascalCase(str: string): string { - if (!StringUtils.isConsiderableCharSequence(str)) return str; - - if (!str.includes(' ')) { - if (!this.determineCase(str)) return str; - const splittedByCase = this.splitByCase(str); - - return StringUtils.removeBlankChars( - !StringUtils.containsConsiderableCharSequence(splittedByCase) - ? StringUtilsWord.formatWord(str) - : StringUtilsWord.formatWords(splittedByCase), - ); - } - - const removedBlankChars = StringUtils.removeBlankChars(str); - if (this.determineCase(removedBlankChars).name == 'pascalCase') { - return removedBlankChars; - } - - const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); - - return StringUtils.removeBlankChars( - blended.length < 2 - ? StringUtilsWord.formatWord(str) - : StringUtilsWord.formatWords(blended), - ); + return this.convertToCaseLogic('pascalCase', str); } /** @@ -219,28 +247,36 @@ export default class StringUtilsCase { * returns: this_is_my_example */ public static toSnakeCase(str: string): string { + return this.convertToCaseLogic('snakeCase', str); + } + + private static convertToCaseLogic(toCase: Case, str: string): string { + const correspondantKnowCase = knownCases.find( + (caseObject) => caseObject.name == toCase, + ); + + const [noBlendReturnFn, blendedReturnFn] = [ + correspondantKnowCase.noBlendReturn, + correspondantKnowCase.blendedReturn, + ]; + if (!StringUtils.isConsiderableCharSequence(str)) return str; if (!str.includes(' ')) { if (!this.determineCase(str)) return str; - const splittedByCase = this.splitByCase( - StringUtils.removeBlankChars(str), - ); - return splittedByCase.join('_').toLowerCase(); + return noBlendReturnFn(this.splitByCase(str), str); } const removedBlankChars = StringUtils.removeBlankChars(str); - if (this.determineCase(removedBlankChars).name == 'snakeCase') { + if (this.determineCase(removedBlankChars).name == toCase) { return removedBlankChars; } - const blended = StringUtils.blendIrrelevantStringsInRelevantOnes(str); - - return blended.length <= 2 - ? this.splitByCase(blended.join('')).join('_').toLowerCase() - : StringUtilsWord.normalizeSpacesBetweenWords( - blended.join('_'), - ).toLowerCase(); + return blendedReturnFn( + this.splitByCase(str), + StringUtils.blendIrrelevantStringsInRelevantOnes(str), + str, + ); } } From 79a99c096f8dc7a33627d83ea51ef4f63c6324e7 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:31:39 +0200 Subject: [PATCH 30/66] feat: implement 'Case' abstract class --- src/case/Case.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/case/Case.ts diff --git a/src/case/Case.ts b/src/case/Case.ts new file mode 100644 index 0000000..4f535e8 --- /dev/null +++ b/src/case/Case.ts @@ -0,0 +1,20 @@ +export default abstract class Case { + private _name: string; + private _matcher: RegExp; + private _splitter: RegExp | string; + + public abstract basicConversionReturnFn(): string; + public abstract blendedConversionReturnFn(): string; + + public get name(): string { + return this._name; + } + + public get matcher(): RegExp { + return this._matcher; + } + + public get splitter(): RegExp | string { + return this._splitter; + } +} From 8e44b8647ea3d727748998e9247e055007587e39 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:36:55 +0200 Subject: [PATCH 31/66] refactor: do not use '_name' field anymore in 'Case' abstract class --- src/case/Case.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/case/Case.ts b/src/case/Case.ts index 4f535e8..16bbb68 100644 --- a/src/case/Case.ts +++ b/src/case/Case.ts @@ -1,5 +1,4 @@ export default abstract class Case { - private _name: string; private _matcher: RegExp; private _splitter: RegExp | string; @@ -7,7 +6,7 @@ export default abstract class Case { public abstract blendedConversionReturnFn(): string; public get name(): string { - return this._name; + return this.constructor.name; } public get matcher(): RegExp { From e7e5bf11a08ed521951e5bfff4bc63bec320194a Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:42:09 +0200 Subject: [PATCH 32/66] fix: add parameters to 'Case' method signatures --- src/case/Case.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/case/Case.ts b/src/case/Case.ts index 16bbb68..f6c08ee 100644 --- a/src/case/Case.ts +++ b/src/case/Case.ts @@ -2,8 +2,15 @@ export default abstract class Case { private _matcher: RegExp; private _splitter: RegExp | string; - public abstract basicConversionReturnFn(): string; - public abstract blendedConversionReturnFn(): string; + public abstract basicConversionReturnFn( + splittedByCase: string[], + str: string, + ): string; + public abstract blendedConversionReturnFn( + splittedByCase: string[], + blended: string[], + str: string, + ): string; public get name(): string { return this.constructor.name; From 4cb0fe94dc59af782d0cc79ff8ccf1b033e38903 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:43:49 +0200 Subject: [PATCH 33/66] feat: implement 'CamelCase' class --- src/case/camel-case.ts | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/case/camel-case.ts diff --git a/src/case/camel-case.ts b/src/case/camel-case.ts new file mode 100644 index 0000000..28d86c6 --- /dev/null +++ b/src/case/camel-case.ts @@ -0,0 +1,37 @@ +import Case from './Case'; +import StringUtilsCase from '../case'; +import StringUtilsWord from '../word'; +import { StringUtils } from '../main'; + +export default class CamelCase extends Case { + public basicConversionReturnFn( + splittedByCase: string[], + str: string, + ): string { + return splittedByCase + .map((subSequence, index) => + index == 0 + ? subSequence.toLowerCase() + : StringUtilsWord.formatWord(subSequence), + ) + .join(''); + } + + public blendedConversionReturnFn( + splittedByCase: string[], + blended: string[], + str: string, + ): string { + return ( + blended.length < 2 + ? StringUtilsCase.splitByCase(StringUtils.removeBlankChars(str)) + : blended + ) + .map((subSequence, index) => + index == 0 + ? subSequence.toLowerCase() + : StringUtilsWord.formatWord(subSequence), + ) + .join(''); + } +} From a8648fafca7713a07702fc60c45262df33a61acb Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:51:39 +0200 Subject: [PATCH 34/66] feat: redefine scope of attributes --- src/case/Case.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/case/Case.ts b/src/case/Case.ts index f6c08ee..7b8aa87 100644 --- a/src/case/Case.ts +++ b/src/case/Case.ts @@ -1,6 +1,6 @@ export default abstract class Case { - private _matcher: RegExp; - private _splitter: RegExp | string; + protected abstract _matcher: RegExp; + protected abstract _splitter: RegExp | string; public abstract basicConversionReturnFn( splittedByCase: string[], From 7c0c2962e4c68456b79d9d0d843c53be3be33475 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:53:40 +0200 Subject: [PATCH 35/66] fix: implement '_matcher' & '_splitter' for CamelCase class --- src/case/camel-case.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/case/camel-case.ts b/src/case/camel-case.ts index 28d86c6..b4c305b 100644 --- a/src/case/camel-case.ts +++ b/src/case/camel-case.ts @@ -4,6 +4,9 @@ import StringUtilsWord from '../word'; import { StringUtils } from '../main'; export default class CamelCase extends Case { + protected _matcher = /^[a-z]+(?:[A-Z][a-z]+)*$/; + protected _splitter = /([A-Z]+[a-z]*)/; + public basicConversionReturnFn( splittedByCase: string[], str: string, From 1c2feae69c2212292e76518e96f7e47c7edbd85e Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 18:57:10 +0200 Subject: [PATCH 36/66] feat: implement 'PascalCase' class --- src/case/pascal-case.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/case/pascal-case.ts diff --git a/src/case/pascal-case.ts b/src/case/pascal-case.ts new file mode 100644 index 0000000..505b830 --- /dev/null +++ b/src/case/pascal-case.ts @@ -0,0 +1,31 @@ +import Case from './Case'; +import StringUtilsWord from '../word'; +import { StringUtils } from '../main'; + +export default class PascalCase extends Case { + protected _matcher = /^[A-Z][a-z]+(?:[A-Z][a-z]+)*$/; + protected _splitter = /([A-Z]+[a-z]*)/; + + public basicConversionReturnFn( + splittedByCase: string[], + str: string, + ): string { + return StringUtils.removeBlankChars( + !StringUtils.containsConsiderableCharSequence(splittedByCase) + ? StringUtilsWord.formatWord(str) + : StringUtilsWord.formatWords(splittedByCase), + ); + } + + public blendedConversionReturnFn( + splittedByCase: string[], + blended: string[], + str: string, + ): string { + return StringUtils.removeBlankChars( + blended.length < 2 + ? StringUtilsWord.formatWord(str) + : StringUtilsWord.formatWords(blended), + ); + } +} From 94908d6fb5dced9d9af6717335a6d23cda8d4307 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 19:00:24 +0200 Subject: [PATCH 37/66] feat: implement 'SnakeCase' class --- src/case/snake-case.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/case/snake-case.ts diff --git a/src/case/snake-case.ts b/src/case/snake-case.ts new file mode 100644 index 0000000..d869412 --- /dev/null +++ b/src/case/snake-case.ts @@ -0,0 +1,27 @@ +import Case from './Case'; +import StringUtilsCase from '../case'; +import StringUtilsWord from '../word'; + +export default class SnakeCase extends Case { + protected _matcher = /(\w+)_(\w+)/; + protected _splitter = '_'; + + public basicConversionReturnFn( + splittedByCase: string[], + str: string, + ): string { + return splittedByCase.join('_').toLowerCase(); + } + + public blendedConversionReturnFn( + splittedByCase: string[], + blended: string[], + str: string, + ): string { + return blended.length <= 2 + ? StringUtilsCase.splitByCase(blended.join('')).join('_').toLowerCase() + : StringUtilsWord.normalizeSpacesBetweenWords( + blended.join('_'), + ).toLowerCase(); + } +} From 615a3d3e740155eb17d3188a36885734ef70911d Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 19:02:08 +0200 Subject: [PATCH 38/66] feat: implement 'LowerCase' class --- src/case/lower-case.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/case/lower-case.ts diff --git a/src/case/lower-case.ts b/src/case/lower-case.ts new file mode 100644 index 0000000..094edea --- /dev/null +++ b/src/case/lower-case.ts @@ -0,0 +1,21 @@ +import Case from './Case'; + +export default class LowerCase extends Case { + protected _matcher = /^[a-z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]*$/; + protected _splitter = ''; + + public basicConversionReturnFn( + splittedByCase: string[], + str: string, + ): string { + return str.toLowerCase(); + } + + public blendedConversionReturnFn( + splittedByCase: string[], + blended: string[], + str: string, + ): string { + return str.toLowerCase(); + } +} From 4f6c8134f45b15464729950c366495d99f1cba84 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 19:05:54 +0200 Subject: [PATCH 39/66] feat: implement 'PascalCase' class --- src/case/upper-case.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/case/upper-case.ts diff --git a/src/case/upper-case.ts b/src/case/upper-case.ts new file mode 100644 index 0000000..3b41f32 --- /dev/null +++ b/src/case/upper-case.ts @@ -0,0 +1,21 @@ +import Case from './Case'; + +export default class UpperCase extends Case { + protected _matcher = /^[A-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]*$/; + protected _splitter = ''; + + public basicConversionReturnFn( + splittedByCase: string[], + str: string, + ): string { + return str.toUpperCase(); + } + + public blendedConversionReturnFn( + splittedByCase: string[], + blended: string[], + str: string, + ): string { + return str.toUpperCase(); + } +} From 354de872e2a8f0136fa6166a62df6f0076945524 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 19:30:27 +0200 Subject: [PATCH 40/66] refactor: refactor 'StringUtilsCase' class to pass tests with new case objects --- src/case.ts | 186 +++++++++------------------------------------- test/case.spec.ts | 32 ++++---- 2 files changed, 53 insertions(+), 165 deletions(-) diff --git a/src/case.ts b/src/case.ts index 8d44824..5ced726 100644 --- a/src/case.ts +++ b/src/case.ts @@ -1,144 +1,32 @@ +import CamelCase from './case/camel-case'; +import Case from './case/Case'; +import LowerCase from './case/lower-case'; +import PascalCase from './case/pascal-case'; +import SnakeCase from './case/snake-case'; +import UpperCase from './case/upper-case'; import { StringUtils } from './main'; -import StringUtilsWord from './word'; - -/** - * This interface provide a structure for literal objects - * It brings reliable way to add unmanaged cases without any other code writing - * - * @interface ICase - * @field {string} name is used to represent a matcher & splitter for case - * @field {RegExp} matcher is used with Regex operations to check if a given string match - * @field {RegExp | string} splitter is used to split given string who match `matcher` - * - */ -interface ICase { - name: Case; - matcher: RegExp; - splitter: RegExp | string; - noBlendReturn: Function; - blendedReturn: Function; -} /** * This type is used to ensure case selection is reliable */ - -export type Case = - | 'snakeCase' - | 'pascalCase' - | 'lowerCase' - | 'upperCase' - | 'camelCase'; +export type CaseName = + | 'SnakeCase' + | 'PascalCase' + | 'LowerCase' + | 'UpperCase' + | 'CamelCase'; /** * This table store few basics cases. * * @method StringUtilsCase.determineCase <- Use it */ -const knownCases: ICase[] = [ - { - name: 'snakeCase', - matcher: /(\w+)_(\w+)/, - splitter: '_', - blendedReturn: ( - splittedByCase: string[], - blended: string[], - str: string, - ) => { - return blended.length <= 2 - ? StringUtilsCase.splitByCase(blended.join('')).join('_').toLowerCase() - : StringUtilsWord.normalizeSpacesBetweenWords( - blended.join('_'), - ).toLowerCase(); - }, - noBlendReturn: (splittedByCase: string[], str: string) => { - return splittedByCase.join('_').toLowerCase(); - }, - }, - { - name: 'pascalCase', - matcher: /^[A-Z][a-z]+(?:[A-Z][a-z]+)*$/, - splitter: /([A-Z]+[a-z]*)/, - blendedReturn: ( - splittedByCase: string[], - blended: string[], - str: string, - ) => { - return StringUtils.removeBlankChars( - blended.length < 2 - ? StringUtilsWord.formatWord(str) - : StringUtilsWord.formatWords(blended), - ); - }, - noBlendReturn: (splittedByCase: string[], str: string) => { - return StringUtils.removeBlankChars( - !StringUtils.containsConsiderableCharSequence(splittedByCase) - ? StringUtilsWord.formatWord(str) - : StringUtilsWord.formatWords(splittedByCase), - ); - }, - }, - { - name: 'lowerCase', - matcher: /^[a-z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]*$/, - splitter: '', - blendedReturn: ( - splittedByCase: string[], - blended: string[], - str: string, - ) => { - return str.toLowerCase(); - }, - noBlendReturn: (splittedByCase: string[], str: string) => { - return str.toLowerCase(); - }, - }, - { - name: 'upperCase', - matcher: /^[A-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\s]*$/, - splitter: '', - blendedReturn: ( - splittedByCase: string[], - blended: string[], - str: string, - ) => { - return str.toUpperCase(); - }, - noBlendReturn: (splittedByCase: string[], str: string) => { - return str.toUpperCase(); - }, - }, - { - name: 'camelCase', - matcher: /^[a-z]+(?:[A-Z][a-z]+)*$/, - splitter: /([A-Z]+[a-z]*)/, - blendedReturn: ( - splittedByCase: string[], - blended: string[], - str: string, - ) => { - return ( - blended.length < 2 - ? StringUtilsCase.splitByCase(StringUtils.removeBlankChars(str)) - : blended - ) - .map((subSequence, index) => - index == 0 - ? subSequence.toLowerCase() - : StringUtilsWord.formatWord(subSequence), - ) - .join(''); - }, - noBlendReturn: (splittedByCase, str) => { - return splittedByCase - .map((subSequence, index) => - index == 0 - ? subSequence.toLowerCase() - : StringUtilsWord.formatWord(subSequence), - ) - .join(''); - }, - }, +const knownCases: Case[] = [ + new SnakeCase(), + new PascalCase(), + new LowerCase(), + new UpperCase(), + new CamelCase(), ]; export default class StringUtilsCase { @@ -149,7 +37,7 @@ export default class StringUtilsCase { * * @returns {ICase} - The case of given string */ - public static determineCase(str: string): ICase | undefined { + public static determineCase(str: string): Case | undefined { return knownCases.find((caseObject) => caseObject.matcher.test(str)); } @@ -186,18 +74,18 @@ export default class StringUtilsCase { * case: snakeCase * returns: this_is_a_test */ - public static convertToCase(str: string, caseToConvert: Case): string { + public static convertToCase(str: string, caseToConvert: CaseName): string { switch (caseToConvert) { - case 'lowerCase': - return this.convertToCaseLogic('lowerCase', str); - case 'upperCase': - return this.convertToCaseLogic('upperCase', str); - case 'camelCase': - return this.convertToCaseLogic('camelCase', str); - case 'pascalCase': - return this.convertToCaseLogic('pascalCase', str); - case 'snakeCase': - return this.convertToCaseLogic('snakeCase', str); + case 'LowerCase': + return this.convertToCaseLogic('LowerCase', str); + case 'UpperCase': + return this.convertToCaseLogic('UpperCase', str); + case 'CamelCase': + return this.convertToCaseLogic('CamelCase', str); + case 'PascalCase': + return this.convertToCaseLogic('PascalCase', str); + case 'SnakeCase': + return this.convertToCaseLogic('SnakeCase', str); } } @@ -214,7 +102,7 @@ export default class StringUtilsCase { * returns: thisIsMyExample */ public static toCamelCase(str: string): string { - return this.convertToCaseLogic('camelCase', str); + return this.convertToCaseLogic('CamelCase', str); } /** @@ -231,7 +119,7 @@ export default class StringUtilsCase { */ public static toPascalCase(str: string): string { - return this.convertToCaseLogic('pascalCase', str); + return this.convertToCaseLogic('PascalCase', str); } /** @@ -247,17 +135,17 @@ export default class StringUtilsCase { * returns: this_is_my_example */ public static toSnakeCase(str: string): string { - return this.convertToCaseLogic('snakeCase', str); + return this.convertToCaseLogic('SnakeCase', str); } - private static convertToCaseLogic(toCase: Case, str: string): string { + private static convertToCaseLogic(toCase: CaseName, str: string): string { const correspondantKnowCase = knownCases.find( - (caseObject) => caseObject.name == toCase, + (caseInstance: Case) => caseInstance.name == toCase, ); const [noBlendReturnFn, blendedReturnFn] = [ - correspondantKnowCase.noBlendReturn, - correspondantKnowCase.blendedReturn, + correspondantKnowCase.basicConversionReturnFn, + correspondantKnowCase.blendedConversionReturnFn, ]; if (!StringUtils.isConsiderableCharSequence(str)) return str; diff --git a/test/case.spec.ts b/test/case.spec.ts index a68eb57..a48620b 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -1,12 +1,12 @@ -import StringUtilsCase, { Case } from '../src/case'; +import StringUtilsCase, { CaseName } from '../src/case'; describe('Casing operation', () => { const samples = new Map([ - ['camelCase', 'thisIsMyTest'], - ['pascalCase', 'ThisIsMyTest'], - ['snakeCase', 'this_is_my_test'], - ['upperCase', 'THISISMY23 TEST'], - ['lowerCase', 'thisis02my test'], + ['CamelCase', 'thisIsMyTest'], + ['PascalCase', 'ThisIsMyTest'], + ['SnakeCase', 'this_is_my_test'], + ['UpperCase', 'THISISMY23 TEST'], + ['LowerCase', 'thisis02my test'], [undefined, 'thisisATEST'], ]); @@ -35,16 +35,16 @@ describe('Casing operation', () => { }); } - const convertToCaseExpectedReturns = new Map<[string, Case], string>([ - [['thisIsMyTest', 'snakeCase'], 'this_is_my_test'], - [['thisIsMyTest', 'camelCase'], 'thisIsMyTest'], - [['thisIsMyTest', 'pascalCase'], 'ThisIsMyTest'], - [['thisIsMyTest', 'lowerCase'], 'thisismytest'], - [['thisIsMyTest', 'upperCase'], 'THISISMYTEST'], - [['a', 'camelCase'], 'a'], - [['this', 'camelCase'], 'tHIS'], - [['th', 'camelCase'], 'tH'], - [['thisISMYTEST', 'camelCase'], 'thisISMYTEST'], + const convertToCaseExpectedReturns = new Map<[string, CaseName], string>([ + [['thisIsMyTest', 'SnakeCase'], 'this_is_my_test'], + [['thisIsMyTest', 'CamelCase'], 'thisIsMyTest'], + [['thisIsMyTest', 'PascalCase'], 'ThisIsMyTest'], + [['thisIsMyTest', 'LowerCase'], 'thisismytest'], + [['thisIsMyTest', 'UpperCase'], 'THISISMYTEST'], + [['a', 'CamelCase'], 'a'], + [['this', 'CamelCase'], 'tHIS'], + [['th', 'CamelCase'], 'tH'], + [['thisISMYTEST', 'CamelCase'], 'thisISMYTEST'], ]); for (const [key, value] of convertToCaseExpectedReturns.entries()) { From a250d5482890312a531b76461adf1ce07b639199 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 20:32:33 +0200 Subject: [PATCH 41/66] docs: TSDOC add docs comments for 'Case' abstract methods --- src/case/Case.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/case/Case.ts b/src/case/Case.ts index 7b8aa87..c409544 100644 --- a/src/case/Case.ts +++ b/src/case/Case.ts @@ -2,24 +2,40 @@ export default abstract class Case { protected abstract _matcher: RegExp; protected abstract _splitter: RegExp | string; + /** + * This method is a wrapper for conversion to targeted case (when `str` is already cased in managed one) + */ public abstract basicConversionReturnFn( splittedByCase: string[], str: string, ): string; + + /** + * This method is a wrapper for conversion to targeted case (when `str` contains spaces) + */ public abstract blendedConversionReturnFn( splittedByCase: string[], blended: string[], str: string, ): string; + /** + * Returns the name of class + */ public get name(): string { return this.constructor.name; } + /** + * Returns the matcher for Regex linked to targeted case class + */ public get matcher(): RegExp { return this._matcher; } + /** + * Returns the splitter for Regex or string linked to targeted case class + */ public get splitter(): RegExp | string { return this._splitter; } From 03393cef52ae6511b68c384dc6733d23a735e687 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 20:36:11 +0200 Subject: [PATCH 42/66] refactor: do not use destucturation to get prototype of methods before use them --- src/case.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/case.ts b/src/case.ts index 5ced726..7815e23 100644 --- a/src/case.ts +++ b/src/case.ts @@ -143,17 +143,15 @@ export default class StringUtilsCase { (caseInstance: Case) => caseInstance.name == toCase, ); - const [noBlendReturnFn, blendedReturnFn] = [ - correspondantKnowCase.basicConversionReturnFn, - correspondantKnowCase.blendedConversionReturnFn, - ]; - if (!StringUtils.isConsiderableCharSequence(str)) return str; if (!str.includes(' ')) { if (!this.determineCase(str)) return str; - return noBlendReturnFn(this.splitByCase(str), str); + return correspondantKnowCase.basicConversionReturnFn( + this.splitByCase(str), + str, + ); } const removedBlankChars = StringUtils.removeBlankChars(str); @@ -161,7 +159,7 @@ export default class StringUtilsCase { return removedBlankChars; } - return blendedReturnFn( + return correspondantKnowCase.blendedConversionReturnFn( this.splitByCase(str), StringUtils.blendIrrelevantStringsInRelevantOnes(str), str, From acbe72852bf3fac30f20b29d163561d063d58da9 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 20:40:23 +0200 Subject: [PATCH 43/66] docs: add comments to 'convertToCaseLogic' --- src/case.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/case.ts b/src/case.ts index 7815e23..13ec7b0 100644 --- a/src/case.ts +++ b/src/case.ts @@ -143,19 +143,24 @@ export default class StringUtilsCase { (caseInstance: Case) => caseInstance.name == toCase, ); + // do not apply any process overload for nothing if (!StringUtils.isConsiderableCharSequence(str)) return str; if (!str.includes(' ')) { + // str do not need blending operation if (!this.determineCase(str)) return str; return correspondantKnowCase.basicConversionReturnFn( this.splitByCase(str), str, - ); + ); //Apply stored behavior of correspondantKnownCase and return the processed value } + // str need blending operation + const removedBlankChars = StringUtils.removeBlankChars(str); if (this.determineCase(removedBlankChars).name == toCase) { + //str is per any chance alraedy cased as wanted but needed to be cleanedFrom any blank chars return removedBlankChars; } @@ -163,6 +168,6 @@ export default class StringUtilsCase { this.splitByCase(str), StringUtils.blendIrrelevantStringsInRelevantOnes(str), str, - ); + ); //Apply stored behavior of correspondantKnownCase and return the processed value } } From 71e4c03dbfc20b083b9df7217654dc5d296e6494 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 20:41:25 +0200 Subject: [PATCH 44/66] fix typo in var name --- src/case.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/case.ts b/src/case.ts index 13ec7b0..447e77e 100644 --- a/src/case.ts +++ b/src/case.ts @@ -139,7 +139,7 @@ export default class StringUtilsCase { } private static convertToCaseLogic(toCase: CaseName, str: string): string { - const correspondantKnowCase = knownCases.find( + const correspondantKnownCase = knownCases.find( (caseInstance: Case) => caseInstance.name == toCase, ); @@ -150,7 +150,7 @@ export default class StringUtilsCase { // str do not need blending operation if (!this.determineCase(str)) return str; - return correspondantKnowCase.basicConversionReturnFn( + return correspondantKnownCase.basicConversionReturnFn( this.splitByCase(str), str, ); //Apply stored behavior of correspondantKnownCase and return the processed value @@ -164,7 +164,7 @@ export default class StringUtilsCase { return removedBlankChars; } - return correspondantKnowCase.blendedConversionReturnFn( + return correspondantKnownCase.blendedConversionReturnFn( this.splitByCase(str), StringUtils.blendIrrelevantStringsInRelevantOnes(str), str, From 99a88c961aa2a3c150211fe6e1446201c890a683 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 23:21:56 +0200 Subject: [PATCH 45/66] docs: add comments for camelCase class --- src/case.ts | 1 - src/case/camel-case.ts | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/case.ts b/src/case.ts index 447e77e..83fc751 100644 --- a/src/case.ts +++ b/src/case.ts @@ -117,7 +117,6 @@ export default class StringUtilsCase { * str: thisIsMyExample * returns: ThisIsMyExample */ - public static toPascalCase(str: string): string { return this.convertToCaseLogic('PascalCase', str); } diff --git a/src/case/camel-case.ts b/src/case/camel-case.ts index b4c305b..715127f 100644 --- a/src/case/camel-case.ts +++ b/src/case/camel-case.ts @@ -7,6 +7,13 @@ export default class CamelCase extends Case { protected _matcher = /^[a-z]+(?:[A-Z][a-z]+)*$/; protected _splitter = /([A-Z]+[a-z]*)/; + /* + * `str` do not need blending operation (there's no spaces into it) + * from `splittedByCase`, for each subsequence + * (at this step, it should be atleast a subSequence of length >= 2: because of check if it's a considerable str) + * if current subSequence index is index 0, then lower it + * otherwise format the current subSequence as a word (c.f: with first char uppered and the rest lowered) + */ public basicConversionReturnFn( splittedByCase: string[], str: string, @@ -20,6 +27,13 @@ export default class CamelCase extends Case { .join(''); } + /* + * `str` was blent (see StringUtils.blendIrrelevantStringsInRelevantOnes) and stored in `blended` + * if blended length < 2 (c.f: blend operation didn't produce more than 1 relevant string) then + * the table to work with in previous statement will be the result of splitted removed from blank chars + * version of `str` (which is never modified). + * Otherwise use the result of blend operation as table to work with (blended) + */ public blendedConversionReturnFn( splittedByCase: string[], blended: string[], From 8cf4456c17979f3c907305f48a704913c5439762 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 23:43:30 +0200 Subject: [PATCH 46/66] test: add test for 'containsOnlyConsiderableCharSequence' method --- test/main.spec.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/main.spec.ts b/test/main.spec.ts index 7cb2912..f1c3725 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -84,3 +84,23 @@ for (const [input, output] of containsConsiderableCharSequence.entries()) { expect(StringUtils.containsConsiderableCharSequence(input)).toBe(output); }); } + +const containsOnlyConsiderableCharSequenceExpectedReturns = new Map< + string[], + boolean +>([ + ['this is my example'.split(' '), true], + ['this i s my example'.split(' '), false], + [' '.split(' '), false], +]); + +for (const [ + input, + output, +] of containsOnlyConsiderableCharSequenceExpectedReturns.entries()) { + test(`SHould return '${output}' for '${input}'`, () => { + expect(StringUtils.containsOnlyConsiderableCharSequence(input)).toBe( + output, + ); + }); +} From be0be11a7622b16dbeb40fb137e35a632c900218 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 23:43:58 +0200 Subject: [PATCH 47/66] feat: implement 'containsOnlyConsiderableCharSequence' logic --- src/main.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main.ts b/src/main.ts index 59ff763..ce3def8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -55,6 +55,29 @@ export class StringUtils { ); } + /** + * Returns a boolean indicating if a given string table contains only considerable subsequence + * + * @param {string[]} stringTable - Should be a table of string + * + * @example + * stringTable: ['This', 'is', 'my', 'example'] + * returns: true + * @example + * stringTable: ['This', 'i', 's', 'my', 'example'] + * returns: false + */ + public static containsOnlyConsiderableCharSequence( + stringTable: string[], + ): boolean { + if (this.isBlank(stringTable.join(''))) return false; + return ( + stringTable.find( + (subsequence) => !this.isConsiderableCharSequence(subsequence), + ) == undefined + ); + } + /** * Replace a subsequent string at a given position by another string in a given string * From 444f240683c7d8958f885652d666e41d4f43a7c4 Mon Sep 17 00:00:00 2001 From: benjGam Date: Tue, 24 Sep 2024 23:48:59 +0200 Subject: [PATCH 48/66] refactor: use 'containsOnlyConsiderableCharSequences' to avoid process when all sub char sequence are relevant --- src/main.ts | 6 +++++- test/main.spec.ts | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main.ts b/src/main.ts index ce3def8..a82ea74 100644 --- a/src/main.ts +++ b/src/main.ts @@ -67,7 +67,7 @@ export class StringUtils { * stringTable: ['This', 'i', 's', 'my', 'example'] * returns: false */ - public static containsOnlyConsiderableCharSequence( + public static containsOnlyConsiderableCharSequences( stringTable: string[], ): boolean { if (this.isBlank(stringTable.join(''))) return false; @@ -139,9 +139,13 @@ export class StringUtils { public static blendIrrelevantStringsInRelevantOnes(str: string): string[] { const splittedStr = StringUtilsWord.normalizeSpacesBetweenWords(str).split(' '); + if (!this.containsConsiderableCharSequence(splittedStr)) return [this.removeBlankChars(str)]; + if (this.containsOnlyConsiderableCharSequences(splittedStr)) + return splittedStr; + const revelantSubSequences: string[] = []; /* If the current subsequence is relevant, push it to revelants table diff --git a/test/main.spec.ts b/test/main.spec.ts index f1c3725..d03b8b4 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -85,7 +85,7 @@ for (const [input, output] of containsConsiderableCharSequence.entries()) { }); } -const containsOnlyConsiderableCharSequenceExpectedReturns = new Map< +const containsOnlyConsiderableCharSequencesExpectedReturns = new Map< string[], boolean >([ @@ -97,9 +97,9 @@ const containsOnlyConsiderableCharSequenceExpectedReturns = new Map< for (const [ input, output, -] of containsOnlyConsiderableCharSequenceExpectedReturns.entries()) { +] of containsOnlyConsiderableCharSequencesExpectedReturns.entries()) { test(`SHould return '${output}' for '${input}'`, () => { - expect(StringUtils.containsOnlyConsiderableCharSequence(input)).toBe( + expect(StringUtils.containsOnlyConsiderableCharSequences(input)).toBe( output, ); }); From 08b7124a17dd10027f734bf0305ab25bff08dc8e Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 00:08:49 +0200 Subject: [PATCH 49/66] feat: implement 'JestUtils' class --- test/test.utils.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test/test.utils.ts diff --git a/test/test.utils.ts b/test/test.utils.ts new file mode 100644 index 0000000..91930c5 --- /dev/null +++ b/test/test.utils.ts @@ -0,0 +1,12 @@ +export default class JestUtils { + public static runBasicTests( + expectedReturns: Map, + functionToTest: Function, + ): void { + for (const [input, output] of expectedReturns.entries()) { + test(`[${functionToTest.name}] Should return '${expectedReturns}'`, () => { + expect(input)[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' + }); + } + } +} From e4b16168fb873547881441b1e900314e34ee409a Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 00:10:43 +0200 Subject: [PATCH 50/66] fix: use function to test invokation --- test/test.utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test.utils.ts b/test/test.utils.ts index 91930c5..c82159e 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -5,7 +5,9 @@ export default class JestUtils { ): void { for (const [input, output] of expectedReturns.entries()) { test(`[${functionToTest.name}] Should return '${expectedReturns}'`, () => { - expect(input)[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' + expect(functionToTest(input))[ + typeof output === 'object' ? 'toEqual' : 'toBe' + ](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); } } From 15a892b11693f6add2314f460b38e56d795ed2ee Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 00:52:01 +0200 Subject: [PATCH 51/66] fix: rework class to be usable in that context --- test/test.utils.ts | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/test/test.utils.ts b/test/test.utils.ts index c82159e..f1fcab0 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -1,14 +1,31 @@ -export default class JestUtils { - public static runBasicTests( - expectedReturns: Map, - functionToTest: Function, - ): void { +interface Type extends Function { + new (...args: any[]): T; +} + +export default class JestRunner { + private _classToInvoke: Type; + + constructor(classToInvoke: Type) { + this._classToInvoke = classToInvoke; + } + + public runBasicTests(expectedReturns: Map, fn: Function): void { + this.checkInvokation(fn); + for (const [input, output] of expectedReturns.entries()) { - test(`[${functionToTest.name}] Should return '${expectedReturns}'`, () => { - expect(functionToTest(input))[ + test(`[${fn.name}] Should return '${output}'`, () => { + expect(this._classToInvoke[fn.name](input))[ typeof output === 'object' ? 'toEqual' : 'toBe' ](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); } } + + private checkInvokation(fn: Function) { + // Throw error if _classToInvoke doesn't describe functionToTest or if prototype of functionToTest & function identified with name in _classToInvoke + if (!this._classToInvoke[fn.name] || fn !== this._classToInvoke[fn.name]) + throw new Error( + `${this._classToInvoke.name}.${fn.name} is not the expected tested one`, + ); + } } From 3af17e2baca33fca16272db6b56273563326d4b4 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 01:36:51 +0200 Subject: [PATCH 52/66] fix: add way to split params when needed SHOULD BE REWORK LATER --- test/main.spec.ts | 161 ++++++++++++++++++--------------------------- test/test.utils.ts | 18 ++++- 2 files changed, 79 insertions(+), 100 deletions(-) diff --git a/test/main.spec.ts b/test/main.spec.ts index d03b8b4..deedf38 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -1,106 +1,73 @@ import { StringUtils } from '../src/main'; +import JestRunner from './test.utils'; -const isBlankExpectedReturns = new Map([ - ['hey', false], - [' hey ', false], - [' ', true], - ['', true], -]); +const runner = new JestRunner(StringUtils); -for (const strKey of isBlankExpectedReturns.keys()) { - test(`Should return '${isBlankExpectedReturns.get(strKey)!}' for str = '${strKey}'`, () => { - expect(StringUtils.isBlank(strKey)).toBe( - isBlankExpectedReturns.get(strKey)!, - ); - }); -} +runner.runBasicTests( + new Map([ + ['hey', false], + [' hey ', false], + [' ', true], + ['', true], + ]), + StringUtils.isBlank, +); -const replaceAtExpectedReturns = new Map([ - [['This', 2, 'hello'], 'Thhellos'], - [['Hello', 18, 'hi'], 'Hello'], - [['Hi', -2, 'hello'], 'Hi'], -]); +runner.runBasicTests( + new Map([ + [['This', 2, 'hello'], 'Thhellos'], + [['Hello', 18, 'hi'], 'Hello'], + [['Hi', -2, 'hello'], 'Hi'], + ]), + StringUtils.replaceAt, +); -for (const key of replaceAtExpectedReturns.keys()) { - test(`Should return ${replaceAtExpectedReturns.get(key)!} for '${key}'`, () => { - expect(StringUtils.replaceAt(key[0], key[1], key[2])).toBe( - replaceAtExpectedReturns.get(key)!, - ); - }); -} +runner.runBasicTests( + new Map([ + [' t', false], + ['of', true], + [' of', true], + ['of ', true], + ['f ', false], + ]), + StringUtils.isConsiderableCharSequence, +); -const isConsiderableCharSequenceExpectedReturns = new Map([ - [' t', false], - ['of', true], - [' of', true], - ['of ', true], - ['f ', false], -]); -for (const [ - input, - output, -] of isConsiderableCharSequenceExpectedReturns.entries()) { - test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtils.isConsiderableCharSequence(input)).toBe(output); - }); -} +runner.runBasicTests( + new Map([ + ['This is a test', 'Thisisatest'], + ['Thisisatest', 'Thisisatest'], + [' ', ''], + ['', ''], + ]), + StringUtils.removeBlankChars, +); -const removeBlankCharsExpectedReturns = new Map([ - ['This is a test', 'Thisisatest'], - ['Thisisatest', 'Thisisatest'], - [' ', ''], - ['', ''], -]); -for (const [input, output] of removeBlankCharsExpectedReturns.entries()) { - test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtils.removeBlankChars(input)).toBe(output); - }); -} +runner.runBasicTests( + new Map([ + ['This is my ex a m p l e', ['This', 'is', 'my', 'example']], + ['T h i s i s m y e x a m p l e', ['Thisismyexample']], + ['This is my ex a m pl e ', ['This', 'is', 'my', 'exam', 'ple']], + ]), + StringUtils.blendIrrelevantStringsInRelevantOnes, +); -const blendIrrelevantStringsInRelevantOnes = new Map([ - ['This is my ex a m p l e', ['This', 'is', 'my', 'example']], - ['T h i s i s m y e x a m p l e', ['Thisismyexample']], - ['This is my ex a m pl e ', ['This', 'is', 'my', 'exam', 'ple']], -]); +runner.runBasicTests( + new Map([ + [['This', 'is', 'my', 'test'], true], + [[' ', ' t ', ' h '], false], + [['t', 'h', 'i'], false], + [[' ', ' '], false], + [['T', 'h', 'is'], true], + ]), + StringUtils.containsConsiderableCharSequence, +); -for (const [input, output] of blendIrrelevantStringsInRelevantOnes.entries()) { - test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtils.blendIrrelevantStringsInRelevantOnes(input)).toEqual( - output, - ); - }); -} - -const containsConsiderableCharSequence = new Map([ - [['This', 'is', 'my', 'test'], true], - [[' ', ' t ', ' h '], false], - [['t', 'h', 'i'], false], - [[' ', ' '], false], - [['T', 'h', 'is'], true], -]); - -for (const [input, output] of containsConsiderableCharSequence.entries()) { - test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtils.containsConsiderableCharSequence(input)).toBe(output); - }); -} - -const containsOnlyConsiderableCharSequencesExpectedReturns = new Map< - string[], - boolean ->([ - ['this is my example'.split(' '), true], - ['this i s my example'.split(' '), false], - [' '.split(' '), false], -]); - -for (const [ - input, - output, -] of containsOnlyConsiderableCharSequencesExpectedReturns.entries()) { - test(`SHould return '${output}' for '${input}'`, () => { - expect(StringUtils.containsOnlyConsiderableCharSequences(input)).toBe( - output, - ); - }); -} +runner.runBasicTests( + new Map([ + ['this is my example'.split(' '), true], + ['this i s my example'.split(' '), false], + [' '.split(' '), false], + ]), + StringUtils.containsOnlyConsiderableCharSequences, +); diff --git a/test/test.utils.ts b/test/test.utils.ts index f1fcab0..a9bd2bf 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -14,13 +14,25 @@ export default class JestRunner { for (const [input, output] of expectedReturns.entries()) { test(`[${fn.name}] Should return '${output}'`, () => { - expect(this._classToInvoke[fn.name](input))[ - typeof output === 'object' ? 'toEqual' : 'toBe' - ](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' + if (this.checkTypesLengthInInput(input)) { + expect(fn.call(this._classToInvoke, ...input))[ + typeof output === 'object' ? 'toEqual' : 'toBe' + ](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' + } else + expect(fn.call(this._classToInvoke, input))[ + typeof output === 'object' ? 'toEqual' : 'toBe' + ](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); } } + private checkTypesLengthInInput(input: any) { + return ( + Array.isArray(input) && + Array.from(new Set(input.map((type) => typeof type)).values()).length > 1 + ); + } + private checkInvokation(fn: Function) { // Throw error if _classToInvoke doesn't describe functionToTest or if prototype of functionToTest & function identified with name in _classToInvoke if (!this._classToInvoke[fn.name] || fn !== this._classToInvoke[fn.name]) From 1501065077ed3214015f46df950dd2e617e4e874 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 02:00:01 +0200 Subject: [PATCH 53/66] feat: add expected output in test message --- test/test.utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.utils.ts b/test/test.utils.ts index a9bd2bf..6d65166 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -13,7 +13,7 @@ export default class JestRunner { this.checkInvokation(fn); for (const [input, output] of expectedReturns.entries()) { - test(`[${fn.name}] Should return '${output}'`, () => { + test(`[${fn.name}] Should return '${output} for '${input}''`, () => { if (this.checkTypesLengthInInput(input)) { expect(fn.call(this._classToInvoke, ...input))[ typeof output === 'object' ? 'toEqual' : 'toBe' From 58ba8a81b87d092086a8cd296e3d0253216b53c2 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 02:07:45 +0200 Subject: [PATCH 54/66] refactor: do not rewrite same code --- test/test.utils.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/test.utils.ts b/test/test.utils.ts index 6d65166..8fa76dc 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -14,14 +14,11 @@ export default class JestRunner { for (const [input, output] of expectedReturns.entries()) { test(`[${fn.name}] Should return '${output} for '${input}''`, () => { - if (this.checkTypesLengthInInput(input)) { - expect(fn.call(this._classToInvoke, ...input))[ - typeof output === 'object' ? 'toEqual' : 'toBe' - ](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' - } else - expect(fn.call(this._classToInvoke, input))[ - typeof output === 'object' ? 'toEqual' : 'toBe' - ](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' + expect( + this._classToInvoke[fn.name]( + ...(this.checkTypesLengthInInput(input) ? input : [input]), + ), + )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); } } From 82e8dee4e80ca6e185ebbbd3cf4014041e59ed3a Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 02:19:42 +0200 Subject: [PATCH 55/66] try a fix for now --- test/main.spec.ts | 8 ++++---- test/test.utils.ts | 11 ++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/test/main.spec.ts b/test/main.spec.ts index deedf38..a281f79 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -14,10 +14,10 @@ runner.runBasicTests( ); runner.runBasicTests( - new Map([ - [['This', 2, 'hello'], 'Thhellos'], - [['Hello', 18, 'hi'], 'Hello'], - [['Hi', -2, 'hello'], 'Hi'], + new Map([ + [[['This', 2, 'hello']], 'Thhellos'], + [[['Hello', 18, 'hi']], 'Hello'], + [[['Hi', -2, 'hello']], 'Hi'], ]), StringUtils.replaceAt, ); diff --git a/test/test.utils.ts b/test/test.utils.ts index 8fa76dc..0eeb40f 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -12,11 +12,15 @@ export default class JestRunner { public runBasicTests(expectedReturns: Map, fn: Function): void { this.checkInvokation(fn); + const isMultiArgs = this.checkTypesLengthInInput( + Array.from(expectedReturns.keys())[0], + ); + for (const [input, output] of expectedReturns.entries()) { test(`[${fn.name}] Should return '${output} for '${input}''`, () => { expect( this._classToInvoke[fn.name]( - ...(this.checkTypesLengthInInput(input) ? input : [input]), + ...(isMultiArgs ? input.flat() : [input]), ), )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); @@ -24,10 +28,7 @@ export default class JestRunner { } private checkTypesLengthInInput(input: any) { - return ( - Array.isArray(input) && - Array.from(new Set(input.map((type) => typeof type)).values()).length > 1 - ); + return Array.isArray(input[0]); } private checkInvokation(fn: Function) { From 563b3643a2202c8df8fb466b94c71b42305c64b2 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 02:39:05 +0200 Subject: [PATCH 56/66] fix: use function to determine when it's a multi args or other stuffs --- test/main.spec.ts | 8 ++++---- test/test.utils.ts | 10 +--------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/test/main.spec.ts b/test/main.spec.ts index a281f79..138bb44 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -14,10 +14,10 @@ runner.runBasicTests( ); runner.runBasicTests( - new Map([ - [[['This', 2, 'hello']], 'Thhellos'], - [[['Hello', 18, 'hi']], 'Hello'], - [[['Hi', -2, 'hello']], 'Hi'], + new Map([ + [() => ['This', 2, 'hello'], 'Thhellos'], + [() => ['Hello', 18, 'hi'], 'Hello'], + [() => ['Hi', -2, 'hello'], 'Hi'], ]), StringUtils.replaceAt, ); diff --git a/test/test.utils.ts b/test/test.utils.ts index 0eeb40f..84c3e18 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -12,25 +12,17 @@ export default class JestRunner { public runBasicTests(expectedReturns: Map, fn: Function): void { this.checkInvokation(fn); - const isMultiArgs = this.checkTypesLengthInInput( - Array.from(expectedReturns.keys())[0], - ); - for (const [input, output] of expectedReturns.entries()) { test(`[${fn.name}] Should return '${output} for '${input}''`, () => { expect( this._classToInvoke[fn.name]( - ...(isMultiArgs ? input.flat() : [input]), + ...(typeof input == 'function' ? input() : [input]), ), )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); } } - private checkTypesLengthInInput(input: any) { - return Array.isArray(input[0]); - } - private checkInvokation(fn: Function) { // Throw error if _classToInvoke doesn't describe functionToTest or if prototype of functionToTest & function identified with name in _classToInvoke if (!this._classToInvoke[fn.name] || fn !== this._classToInvoke[fn.name]) From 8c1ed2bcf60f306feebf358988bc7e19410df546 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 11:52:46 +0200 Subject: [PATCH 57/66] chore: move param & args position for runner.runBasicTest --- test/main.spec.ts | 14 +++++++------- test/test.utils.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/main.spec.ts b/test/main.spec.ts index 138bb44..5570b47 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -4,25 +4,26 @@ import JestRunner from './test.utils'; const runner = new JestRunner(StringUtils); runner.runBasicTests( + StringUtils.isBlank, new Map([ ['hey', false], [' hey ', false], [' ', true], ['', true], ]), - StringUtils.isBlank, ); runner.runBasicTests( + StringUtils.replaceAt, new Map([ [() => ['This', 2, 'hello'], 'Thhellos'], [() => ['Hello', 18, 'hi'], 'Hello'], [() => ['Hi', -2, 'hello'], 'Hi'], ]), - StringUtils.replaceAt, ); runner.runBasicTests( + StringUtils.isConsiderableCharSequence, new Map([ [' t', false], ['of', true], @@ -30,29 +31,29 @@ runner.runBasicTests( ['of ', true], ['f ', false], ]), - StringUtils.isConsiderableCharSequence, ); runner.runBasicTests( + StringUtils.removeBlankChars, new Map([ ['This is a test', 'Thisisatest'], ['Thisisatest', 'Thisisatest'], [' ', ''], ['', ''], ]), - StringUtils.removeBlankChars, ); runner.runBasicTests( + StringUtils.blendIrrelevantStringsInRelevantOnes, new Map([ ['This is my ex a m p l e', ['This', 'is', 'my', 'example']], ['T h i s i s m y e x a m p l e', ['Thisismyexample']], ['This is my ex a m pl e ', ['This', 'is', 'my', 'exam', 'ple']], ]), - StringUtils.blendIrrelevantStringsInRelevantOnes, ); runner.runBasicTests( + StringUtils.containsConsiderableCharSequence, new Map([ [['This', 'is', 'my', 'test'], true], [[' ', ' t ', ' h '], false], @@ -60,14 +61,13 @@ runner.runBasicTests( [[' ', ' '], false], [['T', 'h', 'is'], true], ]), - StringUtils.containsConsiderableCharSequence, ); runner.runBasicTests( + StringUtils.containsOnlyConsiderableCharSequences, new Map([ ['this is my example'.split(' '), true], ['this i s my example'.split(' '), false], [' '.split(' '), false], ]), - StringUtils.containsOnlyConsiderableCharSequences, ); diff --git a/test/test.utils.ts b/test/test.utils.ts index 84c3e18..523a62f 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -9,7 +9,7 @@ export default class JestRunner { this._classToInvoke = classToInvoke; } - public runBasicTests(expectedReturns: Map, fn: Function): void { + public runBasicTests(fn: Function, expectedReturns: Map): void { this.checkInvokation(fn); for (const [input, output] of expectedReturns.entries()) { From 2b4e23dd1aba61601dbf0f4829bef735ed279c1b Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 12:13:08 +0200 Subject: [PATCH 58/66] feat: add way to test a specific field in a object --- test/test.utils.ts | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/test/test.utils.ts b/test/test.utils.ts index 523a62f..e021a58 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -9,16 +9,36 @@ export default class JestRunner { this._classToInvoke = classToInvoke; } - public runBasicTests(fn: Function, expectedReturns: Map): void { + public runBasicTests( + fn: Function, + expectedReturns: Map, + inputPropertiesToTestName: string = null, + ): void { this.checkInvokation(fn); for (const [input, output] of expectedReturns.entries()) { test(`[${fn.name}] Should return '${output} for '${input}''`, () => { - expect( - this._classToInvoke[fn.name]( - ...(typeof input == 'function' ? input() : [input]), - ), - )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' + if (inputPropertiesToTestName) + if (output) { + expect( + this._classToInvoke[fn.name]( + ...(typeof input == 'function' ? input() : [input]), + )[inputPropertiesToTestName], + )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); + } else { + expect( + this._classToInvoke[fn.name]( + ...(typeof input == 'function' ? input() : [input]), + ), + )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); + } + // if output is a complexe object use 'toEqual' otherwise 'toBe' + else + expect( + this._classToInvoke[fn.name]( + ...(typeof input == 'function' ? input() : [input]), + ), + )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); } } From f00c72904dbaae86e38cb9d053cbad396470e619 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 12:20:43 +0200 Subject: [PATCH 59/66] refactor: use runner for 'case' test --- test/case.spec.ts | 195 ++++++++++++++++++++++------------------------ 1 file changed, 91 insertions(+), 104 deletions(-) diff --git a/test/case.spec.ts b/test/case.spec.ts index a48620b..b4dbdcd 100644 --- a/test/case.spec.ts +++ b/test/case.spec.ts @@ -1,113 +1,100 @@ import StringUtilsCase, { CaseName } from '../src/case'; +import JestRunner from './test.utils'; -describe('Casing operation', () => { - const samples = new Map([ - ['CamelCase', 'thisIsMyTest'], - ['PascalCase', 'ThisIsMyTest'], - ['SnakeCase', 'this_is_my_test'], - ['UpperCase', 'THISISMY23 TEST'], - ['LowerCase', 'thisis02my test'], - [undefined, 'thisisATEST'], - ]); - - for (const key of samples.keys()) { - test(`Should return '${key}'`, () => { - expect(StringUtilsCase.determineCase(samples.get(key)!)?.name).toBe(key); - }); - } +const runner = new JestRunner(StringUtilsCase); - const splittedByCase = new Map([ - ['thisIsMyTest', ['this', 'Is', 'My', 'Test']], - ['ThisIsMyTest', ['This', 'Is', 'My', 'Test']], - ['this_is_my_test', ['this', 'is', 'my', 'test']], - ['This is my test', ['This is my test']], - ['THIS', ['T', 'H', 'I', 'S']], - ['this', ['t', 'h', 'i', 's']], - ['this is a test', 'this is a test'.split('')], - ['THIS IS A TEST', 'THIS IS A TEST'.split('')], - ]); - - for (const key of splittedByCase.keys()) { - test(`Should return '[${splittedByCase.get(key)!.toString()}]'`, () => { - expect(StringUtilsCase.splitByCase(key)).toEqual( - splittedByCase.get(key)!, - ); - }); - } +describe('Casing operation', () => { + runner.runBasicTests( + StringUtilsCase.determineCase, + new Map([ + ['thisIsMyTest', 'CamelCase'], + ['ThisIsMyTest', 'PascalCase'], + ['this_is_my_test', 'SnakeCase'], + ['THISISMY23 TEST', 'UpperCase'], + ['thisis02my test', 'LowerCase'], + ['thisisATEST', undefined], + ]), + 'name', + ); - const convertToCaseExpectedReturns = new Map<[string, CaseName], string>([ - [['thisIsMyTest', 'SnakeCase'], 'this_is_my_test'], - [['thisIsMyTest', 'CamelCase'], 'thisIsMyTest'], - [['thisIsMyTest', 'PascalCase'], 'ThisIsMyTest'], - [['thisIsMyTest', 'LowerCase'], 'thisismytest'], - [['thisIsMyTest', 'UpperCase'], 'THISISMYTEST'], - [['a', 'CamelCase'], 'a'], - [['this', 'CamelCase'], 'tHIS'], - [['th', 'CamelCase'], 'tH'], - [['thisISMYTEST', 'CamelCase'], 'thisISMYTEST'], - ]); + runner.runBasicTests( + StringUtilsCase.splitByCase, + new Map([ + ['thisIsMyTest', ['this', 'Is', 'My', 'Test']], + ['ThisIsMyTest', ['This', 'Is', 'My', 'Test']], + ['this_is_my_test', ['this', 'is', 'my', 'test']], + ['This is my test', ['This is my test']], + ['THIS', ['T', 'H', 'I', 'S']], + ['this', ['t', 'h', 'i', 's']], + ['this is a test', 'this is a test'.split('')], + ['THIS IS A TEST', 'THIS IS A TEST'.split('')], + ]), + ); - for (const [key, value] of convertToCaseExpectedReturns.entries()) { - test(`Should return '${value}' for '${key}'`, () => { - expect(StringUtilsCase.convertToCase(...key)).toBe(value); - }); - } + runner.runBasicTests( + StringUtilsCase.convertToCase, + new Map([ + [() => ['thisIsMyTest', 'SnakeCase'], 'this_is_my_test'], + [() => ['thisIsMyTest', 'CamelCase'], 'thisIsMyTest'], + [() => ['thisIsMyTest', 'PascalCase'], 'ThisIsMyTest'], + [() => ['thisIsMyTest', 'LowerCase'], 'thisismytest'], + [() => ['thisIsMyTest', 'UpperCase'], 'THISISMYTEST'], + [() => ['a', 'CamelCase'], 'a'], + [() => ['this', 'CamelCase'], 'tHIS'], + [() => ['th', 'CamelCase'], 'tH'], + [() => ['thisISMYTEST', 'CamelCase'], 'thisISMYTEST'], + ]), + ); - const toCamelCaseExpectedReturns = new Map([ - ['thisIsMyTest', 'thisIsMyTest'], - ['ThisIsMyTest', 'thisIsMyTest'], - ['', ''], - ['th', 'tH'], - [' th', 'tH'], - ['thisIsM y Tes t', 'thisIsMyTest'], - ['this_is_my_test', 'thisIsMyTest'], - ['this is my test', 'thisIsMyTest'], - ['ThisIsMyTest', 'thisIsMyTest'], - ['This Is My Test', 'thisIsMyTest'], - ['thisISMYTEST', 'thisISMYTEST'], - ]); - for (const [input, output] of toCamelCaseExpectedReturns.entries()) { - test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtilsCase.toCamelCase(input)).toBe(output); - }); - } + runner.runBasicTests( + StringUtilsCase.toCamelCase, + new Map([ + ['thisIsMyTest', 'thisIsMyTest'], + ['ThisIsMyTest', 'thisIsMyTest'], + ['', ''], + ['th', 'tH'], + [' th', 'tH'], + ['thisIsM y Tes t', 'thisIsMyTest'], + ['this_is_my_test', 'thisIsMyTest'], + ['this is my test', 'thisIsMyTest'], + ['ThisIsMyTest', 'thisIsMyTest'], + ['This Is My Test', 'thisIsMyTest'], + ['thisISMYTEST', 'thisISMYTEST'], + ]), + ); - const toPascalCaseExpectedReturns = new Map([ - ['thisIsMyTest', 'ThisIsMyTest'], - ['ThisIsMyTest', 'ThisIsMyTest'], - ['', ''], - ['th', 'Th'], - [' th', 'Th'], - ['thisIsM y Tes t', 'ThisIsMyTest'], - ['this_is_my_test', 'ThisIsMyTest'], - ['this is my test', 'ThisIsMyTest'], - ['ThisIsMyTest', 'ThisIsMyTest'], - ['This Is My Test', 'ThisIsMyTest'], - ['thisISMYTEST', 'thisISMYTEST'], - ]); - for (const [input, output] of toPascalCaseExpectedReturns.entries()) { - test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtilsCase.toPascalCase(input)).toBe(output); - }); - } + runner.runBasicTests( + StringUtilsCase.toPascalCase, + new Map([ + ['thisIsMyTest', 'ThisIsMyTest'], + ['ThisIsMyTest', 'ThisIsMyTest'], + ['', ''], + ['th', 'Th'], + [' th', 'Th'], + ['thisIsM y Tes t', 'ThisIsMyTest'], + ['this_is_my_test', 'ThisIsMyTest'], + ['this is my test', 'ThisIsMyTest'], + ['ThisIsMyTest', 'ThisIsMyTest'], + ['This Is My Test', 'ThisIsMyTest'], + ['thisISMYTEST', 'thisISMYTEST'], + ]), + ); - const toSnakeCaseExpectedReturns = new Map([ - ['thisIsMyTest', 'this_is_my_test'], - ['ThisIsMyTest', 'this_is_my_test'], - ['', ''], - ['th', 't_h'], - [' th', 't_h'], - ['thisIsM y Tes t', 'this_is_my_test'], - ['this_is_my_test', 'this_is_my_test'], - ['this is my test', 'this_is_my_test'], - ['ThisIsMyTest', 'this_is_my_test'], - ['This Is My Test', 'this_is_my_test'], - ['thisISMYTEST', 'thisISMYTEST'], - ['this _ is _ my _ test', 'this_is_my_test'], - ]); - for (const [input, output] of toSnakeCaseExpectedReturns.entries()) { - test(`Should return '${output}' for '${input}'`, () => { - expect(StringUtilsCase.toSnakeCase(input)).toBe(output); - }); - } + runner.runBasicTests( + StringUtilsCase.toSnakeCase, + new Map([ + ['thisIsMyTest', 'this_is_my_test'], + ['ThisIsMyTest', 'this_is_my_test'], + ['', ''], + ['th', 't_h'], + [' th', 't_h'], + ['thisIsM y Tes t', 'this_is_my_test'], + ['this_is_my_test', 'this_is_my_test'], + ['this is my test', 'this_is_my_test'], + ['ThisIsMyTest', 'this_is_my_test'], + ['This Is My Test', 'this_is_my_test'], + ['thisISMYTEST', 'thisISMYTEST'], + ['this _ is _ my _ test', 'this_is_my_test'], + ]), + ); }); From 123d1c93fb3d61410b361baa430814020a0e089e Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 13:03:04 +0200 Subject: [PATCH 60/66] refactor: use runner for 'words' --- test/words.spec.ts | 319 ++++++++++++++++++++------------------------- 1 file changed, 142 insertions(+), 177 deletions(-) diff --git a/test/words.spec.ts b/test/words.spec.ts index fc2466d..2f1fbaa 100644 --- a/test/words.spec.ts +++ b/test/words.spec.ts @@ -1,95 +1,88 @@ import StringUtilsWord, { IWordEnding } from '../src/word'; +import JestRunner from './test.utils'; -describe('Get word ending', () => { - const getWordEndingReturns = new Map([ - ['Pass', 'ss'], - ['Passes', 'sses'], - ['Category', 'y'], - ['Categories', 'ies'], - ['Bees', 'es'], - ['Bee', 'e'], - ['Cars', 's'], - ['Bet', ''], - ]); +const runner = new JestRunner(StringUtilsWord); - for (const key of getWordEndingReturns.keys()) { - test(`Should return '${getWordEndingReturns.get(key)!}' for word = '${key}'`, () => { - expect(StringUtilsWord.getWordEnding(key)).toEqual( - getWordEndingReturns.get(key)!, - ); - }); - } - - const getCorrespondingEndingReturns = new Map([ - [ - 'Passes', - { - pluralForm: 'sses', - singularForm: 'ss', - }, - ], - [ - 'Pass', - { - pluralForm: 'sses', - singularForm: 'ss', - }, - ], - [ - 'Categories', - { - pluralForm: 'ies', - singularForm: 'y', - }, - ], - [ - 'Category', - { - pluralForm: 'ies', - singularForm: 'y', - }, - ], - [ - 'Bees', - { - pluralForm: 'es', - singularForm: 'e', - }, - ], - [ - 'Bee', - { - pluralForm: 'es', - singularForm: 'e', - }, - ], - [ - 'Cars', - { - pluralForm: 's', - singularForm: '', - }, - ], - [ - 'Car', - { - pluralForm: 's', - singularForm: '', - }, - ], - ]); +describe('Get word ending', () => { + runner.runBasicTests( + StringUtilsWord.getWordEnding, + new Map([ + ['Pass', 'ss'], + ['Passes', 'sses'], + ['Category', 'y'], + ['Categories', 'ies'], + ['Bees', 'es'], + ['Bee', 'e'], + ['Cars', 's'], + ['Bet', ''], + ]), + ); - for (const key of getCorrespondingEndingReturns.keys()) { - test(`Should return correct IWordEnding object for word = '${key}'`, () => { - expect(StringUtilsWord.getCorrespondingEnding(key)).toEqual( - getCorrespondingEndingReturns.get(key)!, - ); - }); - } + runner.runBasicTests( + StringUtilsWord.getCorrespondingEnding, + new Map([ + [ + 'Passes', + { + pluralForm: 'sses', + singularForm: 'ss', + }, + ], + [ + 'Pass', + { + pluralForm: 'sses', + singularForm: 'ss', + }, + ], + [ + 'Categories', + { + pluralForm: 'ies', + singularForm: 'y', + }, + ], + [ + 'Category', + { + pluralForm: 'ies', + singularForm: 'y', + }, + ], + [ + 'Bees', + { + pluralForm: 'es', + singularForm: 'e', + }, + ], + [ + 'Bee', + { + pluralForm: 'es', + singularForm: 'e', + }, + ], + [ + 'Cars', + { + pluralForm: 's', + singularForm: '', + }, + ], + [ + 'Car', + { + pluralForm: 's', + singularForm: '', + }, + ], + ]), + ); }); describe('Is singular or plural', () => { - const isPluralReturns = new Map([ + const isPluralExpectedReturns = new Map([ ['Pass', false], ['Passes', true], ['Category', false], @@ -100,109 +93,81 @@ describe('Is singular or plural', () => { ['Bet', false], ]); - for (const key of isPluralReturns.keys()) { - test(`Should return '${isPluralReturns.get(key)!}' for word = '${key}'`, () => { - expect(StringUtilsWord.isPlural(key)).toBe(isPluralReturns.get(key)!); - }); - } - - const isSingularReturns = new Map( - Array.from(isPluralReturns.keys()).map((key) => [ + const isSingularExpectedReturns = new Map( + Array.from(isPluralExpectedReturns.keys()).map((key) => [ key, - !isPluralReturns.get(key), + !isPluralExpectedReturns.get(key), ]), ); - for (const key of isSingularReturns.keys()) { - test(`Should return '${isSingularReturns.get(key)!}' for word = '${key}'`, () => { - expect(StringUtilsWord.isSingular(key)).toBe(isSingularReturns.get(key)!); - }); - } + runner.runBasicTests(StringUtilsWord.isPlural, isPluralExpectedReturns); + runner.runBasicTests(StringUtilsWord.isSingular, isSingularExpectedReturns); }); describe('Move from singular to plural and vice-versa', () => { - const pluralizeWords = new Map([ - ['Pass', 'Passes'], - ['Category', 'Categories'], - ['Car', 'Cars'], - ['Bee', 'Bees'], - ['', ''], - ['List', 'Lists'], - ['Lists', 'Lists'], - ['C', 'C'], - ['Of', 'Ofs'], - [' ', ' '], - ]); - - for (const key of pluralizeWords.keys()) { - test(`Should return '${pluralizeWords.get(key)!}' for word = '${key}'`, () => { - expect(StringUtilsWord.pluralize(key)).toBe(pluralizeWords.get(key)!); - }); - } - - const singularizeWords = new Map([ - ['Passes', 'Pass'], - ['Categories', 'Category'], - ['Cars', 'Car'], - ['Bees', 'Bee'], - ['', ''], - ['Lists', 'List'], - ['List', 'List'], - ['C', 'C'], - ['Ofs', 'Of'], - [' ', ' '], - ]); + runner.runBasicTests( + StringUtilsWord.pluralize, + new Map([ + ['Pass', 'Passes'], + ['Category', 'Categories'], + ['Car', 'Cars'], + ['Bee', 'Bees'], + ['', ''], + ['List', 'Lists'], + ['Lists', 'Lists'], + ['C', 'C'], + ['Of', 'Ofs'], + [' ', ' '], + ]), + ); - for (const key of singularizeWords.keys()) { - test(`Should return '${singularizeWords.get(key)!}' for word = '${key}'`, () => { - expect(StringUtilsWord.singularize(key)).toBe(singularizeWords.get(key)!); - }); - } + runner.runBasicTests( + StringUtilsWord.singularize, + new Map([ + ['Passes', 'Pass'], + ['Categories', 'Category'], + ['Cars', 'Car'], + ['Bees', 'Bee'], + ['', ''], + ['Lists', 'List'], + ['List', 'List'], + ['C', 'C'], + ['Ofs', 'Of'], + [' ', ' '], + ]), + ); }); describe('Normalization of stuffs', () => { - const formatWordExpectedReturns = new Map([ - ['this', 'This'], - [' this', ' This'], - ['', ''], - [' ', ' '], - ['This', 'This'], - ['this Is a test', 'This Is a test'], - ]); - - for (const key of formatWordExpectedReturns.keys()) { - test(`Should return '${formatWordExpectedReturns.get(key)}' for str = '${key}'`, () => { - expect(StringUtilsWord.formatWord(key)).toBe( - formatWordExpectedReturns.get(key)!, - ); - }); - } - - const normalizeSpacesBetweenWordsExpectedReturns = new Map([ - ['This is a test', 'This is a test'], - ['Hello ', 'Hello'], - [' Hello', 'Hello'], - ]); - - for (const key of normalizeSpacesBetweenWordsExpectedReturns.keys()) { - test(`Should return '${normalizeSpacesBetweenWordsExpectedReturns.get(key)!}' for str = '${key}'`, () => { - expect(StringUtilsWord.normalizeSpacesBetweenWords(key)).toBe( - normalizeSpacesBetweenWordsExpectedReturns.get(key)!, - ); - }); - } + runner.runBasicTests( + StringUtilsWord.formatWord, + new Map([ + ['this', 'This'], + [' this', ' This'], + ['', ''], + [' ', ' '], + ['This', 'This'], + ['this Is a test', 'This Is a test'], + ]), + ); - const formatWordsExpectedReturns = new Map([ - ['This is my test', 'This Is My Test'], - [['This', 'is', 'my', 'test'], 'This Is My Test'], - [[' ', ''], ' '], - [' ', ' '], - [['This ', 'is ', 'my ', 'test'], 'This Is My Test'], - ]); + runner.runBasicTests( + StringUtilsWord.normalizeSpacesBetweenWords, + new Map([ + ['This is a test', 'This is a test'], + ['Hello ', 'Hello'], + [' Hello', 'Hello'], + ]), + ); - for (const [key, value] of formatWordsExpectedReturns.entries()) { - test(`Should return '${value}' for '${key}'`, () => { - expect(StringUtilsWord.formatWords(key)).toEqual(value); - }); - } + runner.runBasicTests( + StringUtilsWord.formatWords, + new Map([ + ['This is my test', 'This Is My Test'], + [['This', 'is', 'my', 'test'], 'This Is My Test'], + [[' ', ''], ' '], + [' ', ' '], + [['This ', 'is ', 'my ', 'test'], 'This Is My Test'], + ]), + ); }); From 4eb57f8c6314f06d21dc9ec70139fb5842cefc0d Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 13:10:50 +0200 Subject: [PATCH 61/66] refactor: kinda refactor test utils --- test/test.utils.ts | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/test/test.utils.ts b/test/test.utils.ts index e021a58..21935cb 100644 --- a/test/test.utils.ts +++ b/test/test.utils.ts @@ -18,27 +18,17 @@ export default class JestRunner { for (const [input, output] of expectedReturns.entries()) { test(`[${fn.name}] Should return '${output} for '${input}''`, () => { - if (inputPropertiesToTestName) - if (output) { - expect( + (inputPropertiesToTestName && output + ? expect( this._classToInvoke[fn.name]( ...(typeof input == 'function' ? input() : [input]), )[inputPropertiesToTestName], - )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); - } else { - expect( + ) + : expect( this._classToInvoke[fn.name]( ...(typeof input == 'function' ? input() : [input]), ), - )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); - } - // if output is a complexe object use 'toEqual' otherwise 'toBe' - else - expect( - this._classToInvoke[fn.name]( - ...(typeof input == 'function' ? input() : [input]), - ), - )[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' + ))[typeof output === 'object' ? 'toEqual' : 'toBe'](output); // if output is a complexe object use 'toEqual' otherwise 'toBe' }); } } From 02dab102e3bb5e9b01c4cb9c73e91f9e153bc7f4 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 13:59:40 +0200 Subject: [PATCH 62/66] docs(CHANGELOG): add 'Added' case logs --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57c2d63..b730eba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +# Version 2.3.0 + +- `Added`: + - `Case` abstract class is now used to reliably create case objects. + - `CamelCase` class implement logic of previous correspondant object. + - `PascalCase` class implement logic of previous correspondant object. + - `SnakeCase` class implement logic of previous correspondant object. + - `LowerCase` class implement logic of previous correspondant object. + - `UpperCase` class implement logic of previous correspondant object. + # Version 2.2.0 - `Added`: From dd91e6e1def1f6cd37b55a8255b2e49bd4242b4c Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 14:12:23 +0200 Subject: [PATCH 63/66] docs(CHANGELOG): add 'StringUtils' class added changes --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b730eba..40c713f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ - `SnakeCase` class implement logic of previous correspondant object. - `LowerCase` class implement logic of previous correspondant object. - `UpperCase` class implement logic of previous correspondant object. + - `StringUtils (main.ts)` + - `isConsiderableCharSequence(str: string): boolean` method has been implemented and used to check if a given string contains atleast 2 chars (excepted blanks ones). + - `containsConsiderableCharSequence(stringTable: string[]): boolean` method has been implemented and used to check if a given table of string contains atleast one considerable (determined by `isConsiderableCharSequence` criterias) element. + - `containsOnlyConsiderableCharSequences(stringTable: string[]): boolean` method has been implemented and used to check if a given table of string contains only considerable (determined by `isConsiderableCharSequence` criterias) elements. + - `removeBlankChars(str): string` method has been implemented and could be use to remove blank chars from a given string. + - `blendIrrelevantStringsInRelevantOnes(str: string): string[]` method has been implemented and should be used to blend orphan chars (a char adjacent to blank chars) to the last considerable subsequence of char (determined by `isConsiderableCharSequence` criterias) in a given string. # Version 2.2.0 From 6d2a332bb8643c7adc761a8753d3a3f4e5e905f5 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 14:33:33 +0200 Subject: [PATCH 64/66] docs: add 'Enhancement', 'Removed', 'Refactor' sections --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40c713f..96159e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Version 2.3.0 +- `Enhancement`: + - `Case convertion`: Previously algorithms responsible of converting a string to another case was obviously to light, so, the range of managed uses was too poor, i reworked those algorithms and they're now better from far that was they were. The new ones got tested and passes tests, it's more than sure that i didn't test all of cases, but an enhancement of this feature is truely brang to package. - `Added`: - `Case` abstract class is now used to reliably create case objects. - `CamelCase` class implement logic of previous correspondant object. @@ -13,6 +15,16 @@ - `containsOnlyConsiderableCharSequences(stringTable: string[]): boolean` method has been implemented and used to check if a given table of string contains only considerable (determined by `isConsiderableCharSequence` criterias) elements. - `removeBlankChars(str): string` method has been implemented and could be use to remove blank chars from a given string. - `blendIrrelevantStringsInRelevantOnes(str: string): string[]` method has been implemented and should be used to blend orphan chars (a char adjacent to blank chars) to the last considerable subsequence of char (determined by `isConsiderableCharSequence` criterias) in a given string. +- `Removed`: + - `[BREAKING CHANGES]`: + - `Case` type has been renamed `CaseName` to avoid collision between new `Case` object type and previous `Case` type. + - `ICase` interface has been removed, it was useless to keep working with it. +- `Refactor`: + - `[BREAKING CHANGES]`: + - `determineCase(str: string): ICase` method signature changed to `determineCase(str: string): Case`. + - `convertToCase(str: string, caseToConvert: Case): string` method signature moved to `convertToCase(str: string, caseToConvert: CaseName): string`. + - `knownCases` table is now a `:Case[]` instead of `:ICase[]`. + - Tests has been refactored to avoid rewriting loops again and again, they now use `JestRunner` utils class. # Version 2.2.0 From 0e7a515187337052690b4d2a584b72179d64a1f5 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 14:42:18 +0200 Subject: [PATCH 65/66] chore(version): update package to v2.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 206e1da..23a283e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "string-utils-ts", - "version": "2.2.0", + "version": "2.3.0", "description": "Provide some useful functions for strings", "main": "./lib", "scripts": { From 7195a03ced09146cc9ea8deb271c4022377f3d90 Mon Sep 17 00:00:00 2001 From: benjGam Date: Wed, 25 Sep 2024 14:50:19 +0200 Subject: [PATCH 66/66] fix(CD): try to fix workflow triggering --- .github/workflows/cd.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 0e8a36b..195b2bf 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -1,10 +1,13 @@ name: Node.js CD on: - push: - branches: ['main'] + pull_request: + branches: + - main + types: [closed] jobs: + if: ${{ github.event.pull_request.merged }} publish-npm: runs-on: ubuntu-latest steps: