From 98806d3688924e8272a81770c49fc3f132387e87 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Tue, 9 Jul 2024 16:22:59 +0000 Subject: [PATCH 1/9] duplicate tool service and testCases, then updated index file --- .../list/duplicate/duplicate.service.test.ts | 62 +++++++++++++++++ src/pages/list/duplicate/index.tsx | 11 +++ src/pages/list/duplicate/meta.ts | 13 ++++ src/pages/list/duplicate/service.ts | 69 +++++++++++++++++++ src/pages/list/index.ts | 1 + 5 files changed, 156 insertions(+) create mode 100644 src/pages/list/duplicate/duplicate.service.test.ts create mode 100644 src/pages/list/duplicate/index.tsx create mode 100644 src/pages/list/duplicate/meta.ts create mode 100644 src/pages/list/duplicate/service.ts diff --git a/src/pages/list/duplicate/duplicate.service.test.ts b/src/pages/list/duplicate/duplicate.service.test.ts new file mode 100644 index 0000000..c1554e6 --- /dev/null +++ b/src/pages/list/duplicate/duplicate.service.test.ts @@ -0,0 +1,62 @@ +import { expect, describe, it } from 'vitest'; +import { duplicateList } from './service'; + +describe('duplicateList function', () => { + it('should duplicate elements correctly with symbol split', () => { + const input = "Hello World"; + const result = duplicateList('symbol', ' ', ' ', input, true, false, 2); + expect(result).toBe("Hello World Hello World"); + }); + + it('should duplicate elements correctly with regex split', () => { + const input = "Hello||World"; + const result = duplicateList('regex', '\\|\\|', ' ', input, true, false, 2); + expect(result).toBe("Hello World Hello World"); + }); + + it('should handle fractional duplication', () => { + const input = "Hello World"; + const result = duplicateList('symbol', ' ', ' ', input, true, false, 1.5); + expect(result).toBe("Hello World Hello"); + }); + + it('should handle reverse option correctly', () => { + const input = "Hello World"; + const result = duplicateList('symbol', ' ', ' ', input, true, true, 2); + expect(result).toBe("Hello World World Hello"); + }); + + it('should handle concatenate option correctly', () => { + const input = "Hello World"; + const result = duplicateList('symbol', ' ', ' ', input, false, false, 2); + expect(result).toBe("Hello Hello World World"); + }); + + it('should handle interweaving option correctly', () => { + const input = "Hello World"; + const result = duplicateList('symbol', ' ', ' ', input, false, false, 2); + expect(result).toBe("Hello Hello World World"); + }); + + it('should throw an error for negative copies', () => { + expect(() => duplicateList('symbol', ' ', ' ', "Hello World", true, false, -1)).toThrow("Number of copies cannot be negative"); + }); + + it('should handle interweaving option correctly 2', () => { + const input = "je m'appelle king"; + const result = duplicateList('symbol', ' ', ', ', input, false, true, 2.1); + expect(result).toBe("je, king, m'appelle, m'appelle, king, je"); + }); + + it('should handle interweaving option correctly 3', () => { + const input = "je m'appelle king"; + const result = duplicateList('symbol', ' ', ', ', input, false, true, 1); + expect(result).toBe("je, m'appelle, king"); + }); + + it('should handle interweaving option correctly 3', () => { + const input = "je m'appelle king"; + const result = duplicateList('symbol', ' ', ', ', input, true, true, 2.7); + expect(result).toBe("je, m'appelle, king, king, m'appelle, je, king, m'appelle"); + }); +}); \ No newline at end of file diff --git a/src/pages/list/duplicate/index.tsx b/src/pages/list/duplicate/index.tsx new file mode 100644 index 0000000..c833d45 --- /dev/null +++ b/src/pages/list/duplicate/index.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import * as Yup from 'yup'; + +const initialValues = {}; +const validationSchema = Yup.object({ + // splitSeparator: Yup.string().required('The separator is required') +}); +export default function Duplicate() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/list/duplicate/meta.ts b/src/pages/list/duplicate/meta.ts new file mode 100644 index 0000000..89f9fe1 --- /dev/null +++ b/src/pages/list/duplicate/meta.ts @@ -0,0 +1,13 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; +// import image from '@assets/text.png'; + +export const tool = defineTool('list', { + name: 'Duplicate', + path: 'duplicate', + // image, + description: '', + shortDescription: '', + keywords: ['duplicate'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/duplicate/service.ts b/src/pages/list/duplicate/service.ts new file mode 100644 index 0000000..c1c2bbd --- /dev/null +++ b/src/pages/list/duplicate/service.ts @@ -0,0 +1,69 @@ +export type SplitOperatorType = 'symbol' | 'regex'; + +function interweave( + array1: string[], + array2: string[]) { + const result: string[] = []; + const maxLength = Math.max(array1.length, array2.length); + + for (let i = 0; i < maxLength; i++) { + if (i < array1.length) result.push(array1[i]); + if (i < array2.length) result.push(array2[i]); + } + return result; +} +function duplicate( + input: string[], + concatenate: boolean, + reverse: boolean, + copy?: number +) { + if (copy) { + if (copy > 0) { + let result: string[] = []; + let toAdd: string[] = []; + let WholePart: string[] = []; + let fractionalPart: string[] = []; + const whole = Math.floor(copy); + const fractional = copy - whole; + if (!reverse) { + WholePart = concatenate ? Array(whole).fill(input).flat() : Array(whole - 1).fill(input).flat(); + fractionalPart = input.slice(0, Math.floor(input.length * fractional)); + toAdd = WholePart.concat(fractionalPart); + result = concatenate ? WholePart.concat(fractionalPart) : interweave(input, toAdd); + } else { + WholePart = Array(whole - 1).fill(input).flat().reverse() + fractionalPart = input.slice().reverse().slice(0, Math.floor(input.length * fractional)); + toAdd = WholePart.concat(fractionalPart); + result = concatenate ? input.concat(toAdd) : interweave(input, toAdd); + } + + return result; + } + throw new Error("Number of copies cannot be negative"); + } + throw new Error("Number of copies must be a valid number"); +} + +export function duplicateList( + splitOperatorType: SplitOperatorType, + splitSeparator: string, + joinSeparator: string, + input: string, + concatenate: boolean, + reverse: boolean, + copy?: number +): string { + let array: string[]; + let result: string[]; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)).filter(item => item !== ''); + break; + } + result = duplicate(array, concatenate, reverse, copy); + return result.join(joinSeparator); +} \ No newline at end of file diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index 388e39c..79b8491 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listDuplicate } from './duplicate/meta'; import { tool as listUnwrap } from './unwrap/meta'; import { tool as listReverse } from './reverse/meta'; import { tool as listFindUnique } from './find-unique/meta'; From 2855efd8c73bbd5b75caf7404f016ac71ea3ee02 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 10 Jul 2024 00:39:26 +0000 Subject: [PATCH 2/9] palindrome tool, testCases then updated index file --- src/pages/string/index.ts | 1 + src/pages/string/palindrome/index.tsx | 11 ++++ src/pages/string/palindrome/meta.ts | 13 ++++ .../palindrome/palindrome.service.test.ts | 60 +++++++++++++++++++ src/pages/string/palindrome/service.ts | 47 +++++++++++++++ 5 files changed, 132 insertions(+) create mode 100644 src/pages/string/palindrome/index.tsx create mode 100644 src/pages/string/palindrome/meta.ts create mode 100644 src/pages/string/palindrome/palindrome.service.test.ts create mode 100644 src/pages/string/palindrome/service.ts diff --git a/src/pages/string/index.ts b/src/pages/string/index.ts index 3011347..ccc5a01 100644 --- a/src/pages/string/index.ts +++ b/src/pages/string/index.ts @@ -1,3 +1,4 @@ +import { tool as stringPalindrome } from './palindrome/meta'; import { tool as stringToMorse } from './to-morse/meta'; import { tool as stringSplit } from './split/meta'; import { tool as stringJoin } from './join/meta'; diff --git a/src/pages/string/palindrome/index.tsx b/src/pages/string/palindrome/index.tsx new file mode 100644 index 0000000..a7104cb --- /dev/null +++ b/src/pages/string/palindrome/index.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import * as Yup from 'yup'; + +const initialValues = {}; +const validationSchema = Yup.object({ + // splitSeparator: Yup.string().required('The separator is required') +}); +export default function Palindrome() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/string/palindrome/meta.ts b/src/pages/string/palindrome/meta.ts new file mode 100644 index 0000000..868cff3 --- /dev/null +++ b/src/pages/string/palindrome/meta.ts @@ -0,0 +1,13 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; +// import image from '@assets/text.png'; + +export const tool = defineTool('string', { + name: 'Palindrome', + path: 'palindrome', + // image, + description: '', + shortDescription: '', + keywords: ['palindrome'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/string/palindrome/palindrome.service.test.ts b/src/pages/string/palindrome/palindrome.service.test.ts new file mode 100644 index 0000000..10d5f2e --- /dev/null +++ b/src/pages/string/palindrome/palindrome.service.test.ts @@ -0,0 +1,60 @@ +import { expect, describe, it } from 'vitest'; +import { palindromeList } from './service'; + +describe('palindromeList', () => { + test('should return true for single character words', () => { + const input = 'a|b|c'; + const separator = '|'; + const result = palindromeList('symbol', input, separator); + expect(result).toBe('true|true|true'); + }); + + test('should return false for non-palindromes', () => { + const input = 'hello|world'; + const separator = '|'; + const result = palindromeList('symbol', input, separator); + expect(result).toBe('false|false'); + }); + + test('should split using regex', () => { + const input = 'racecar,abba,hello'; + const separator = ','; + const result = palindromeList('regex', input, separator); + expect(result).toBe('true,true,false'); + }); + + test('should return empty string for empty input', () => { + const input = ''; + const separator = '|'; + const result = palindromeList('symbol', input, separator); + expect(result).toBe(''); + }); + + test('should split using custom separator', () => { + const input = 'racecar;abba;hello'; + const separator = ';'; + const result = palindromeList('symbol', input, separator); + expect(result).toBe('true;true;false'); + }); + + test('should handle leading and trailing spaces', () => { + const input = ' racecar | abba | hello '; + const separator = '|'; + const result = palindromeList('symbol', input, separator); + expect(result).toBe('true|true|false'); + }); + + test('should handle multilines checking with trimming', () => { + const input = ' racecar \n abba \n hello '; + const separator = '\n'; + const result = palindromeList('symbol', input, separator); + expect(result).toBe('true\ntrue\nfalse'); + }); + + test('should handle empty strings in input', () => { + const input = 'racecar||hello'; + const separator = '|'; + const result = palindromeList('symbol', input, separator); + expect(result).toBe('true|true|false'); + }); +}); \ No newline at end of file diff --git a/src/pages/string/palindrome/service.ts b/src/pages/string/palindrome/service.ts new file mode 100644 index 0000000..e383fd4 --- /dev/null +++ b/src/pages/string/palindrome/service.ts @@ -0,0 +1,47 @@ +export type SplitOperatorType = 'symbol' | 'regex'; + +function isPalindrome( + word: string, + left: number, + right: number +): boolean { + if (left >= right) return true; + if (word[left] !== word[right]) return false; + + return isPalindrome(word, left + 1, right - 1); +} + +// check each word of the input and add the palindrome status in an array +function checkPalindromes(array: string[]): boolean[] { + let status: boolean[] = []; + for (const word of array) { + const palindromeStatus = isPalindrome(word, 0, word.length - 1); + status.push(palindromeStatus); + } + return status; +} + +export function palindromeList( + splitOperatorType: SplitOperatorType, + input: string, + separator: string, // the splitting separator will be the joining separator for visual satisfaction +): string { + if (!input) return ''; + let array: string[]; + switch (splitOperatorType) { + case 'symbol': + array = input.split(separator); + break; + case 'regex': + array = input.split(new RegExp(separator)); + break; + } + // trim all items to focus on the word and not biasing the result due to spaces (leading and trailing) + array = array.map((item) => item.trim()); + + const statusArray = checkPalindromes(array); + + return statusArray.map(status => status.toString()).join(separator); + +} + From 7a7bf06b28bde727be7fefff39a021697871f1cc Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 10 Jul 2024 14:33:20 +0000 Subject: [PATCH 3/9] adding string reverser code to string in utils --- src/utils/string.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/string.ts b/src/utils/string.ts index db558eb..f918364 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -16,3 +16,7 @@ export const replaceSpecialCharacters = (str: string) => { .replace(/\\f/g, '\f') .replace(/\\v/g, '\v'); }; + +export function reverseString(input: string): string { + return input.split('').reverse().join(''); +} From b309921d892fabef063ecb34ee2891913b229d01 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 10 Jul 2024 14:34:17 +0000 Subject: [PATCH 4/9] create palindrome tool, testCases and undated index file --- .../create-palindrome.service.test.ts | 66 +++++++++++++++++++ src/pages/string/create-palindrome/index.tsx | 11 ++++ src/pages/string/create-palindrome/meta.ts | 13 ++++ src/pages/string/create-palindrome/service.ts | 35 ++++++++++ src/pages/string/index.ts | 1 + 5 files changed, 126 insertions(+) create mode 100644 src/pages/string/create-palindrome/create-palindrome.service.test.ts create mode 100644 src/pages/string/create-palindrome/index.tsx create mode 100644 src/pages/string/create-palindrome/meta.ts create mode 100644 src/pages/string/create-palindrome/service.ts diff --git a/src/pages/string/create-palindrome/create-palindrome.service.test.ts b/src/pages/string/create-palindrome/create-palindrome.service.test.ts new file mode 100644 index 0000000..ddd712b --- /dev/null +++ b/src/pages/string/create-palindrome/create-palindrome.service.test.ts @@ -0,0 +1,66 @@ +import { expect, describe, it } from 'vitest'; + import { createPalindromeList, createPalindrome } from './service'; + +describe('createPalindrome', () => { + test('should create palindrome by reversing the entire string', () => { + const input = 'hello'; + const result = createPalindrome(input, true); + expect(result).toBe('helloolleh'); + }); + + test('should create palindrome by reversing the string excluding the last character', () => { + const input = 'hello'; + const result = createPalindrome(input, false); + expect(result).toBe('hellolleh'); + }); + + test('should return an empty string if input is empty', () => { + const input = ''; + const result = createPalindrome(input, true); + expect(result).toBe(''); + }); +}); + +describe('createPalindromeList', () => { + test('should create palindrome for single-line input', () => { + const input = 'hello'; + const result = createPalindromeList(input, true, false); + expect(result).toBe('helloolleh'); + }); + + test('should create palindrome for single-line input considering trailing spaces', () => { + const input = 'hello '; + const result = createPalindromeList(input, true, false); + expect(result).toBe('hello olleh'); + }); + + test('should create palindrome for single-line input ignoring trailing spaces if lastChar is set to false', () => { + const input = 'hello '; + const result = createPalindromeList(input, true, false); + expect(result).toBe('hello olleh'); + }); + + test('should create palindrome for multi-line input', () => { + const input = 'hello\nworld'; + const result = createPalindromeList(input, true, true); + expect(result).toBe('helloolleh\nworlddlrow'); + }); + + test('should create palindrome for no multi-line input', () => { + const input = 'hello\nworld\n'; + const result = createPalindromeList(input, true, false); + expect(result).toBe('hello\nworld\n\ndlrow\nolleh'); + }); + + test('should handle multi-line input with lastChar set to false', () => { + const input = 'hello\nworld'; + const result = createPalindromeList(input, false, true); + expect(result).toBe('hellolleh\nworldlrow'); + }); + + test('should return an empty string if input is empty', () => { + const input = ''; + const result = createPalindromeList(input, true, false); + expect(result).toBe(''); + }); +}); \ No newline at end of file diff --git a/src/pages/string/create-palindrome/index.tsx b/src/pages/string/create-palindrome/index.tsx new file mode 100644 index 0000000..da75227 --- /dev/null +++ b/src/pages/string/create-palindrome/index.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import * as Yup from 'yup'; + +const initialValues = {}; +const validationSchema = Yup.object({ + // splitSeparator: Yup.string().required('The separator is required') +}); +export default function CreatePalindrome() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/string/create-palindrome/meta.ts b/src/pages/string/create-palindrome/meta.ts new file mode 100644 index 0000000..5b21620 --- /dev/null +++ b/src/pages/string/create-palindrome/meta.ts @@ -0,0 +1,13 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; +// import image from '@assets/text.png'; + +export const tool = defineTool('string', { + name: 'Create palindrome', + path: 'create-palindrome', + // image, + description: '', + shortDescription: '', + keywords: ['create', 'palindrome'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/string/create-palindrome/service.ts b/src/pages/string/create-palindrome/service.ts new file mode 100644 index 0000000..1f87c6d --- /dev/null +++ b/src/pages/string/create-palindrome/service.ts @@ -0,0 +1,35 @@ +import { reverseString } from 'utils/string' + +export function createPalindrome( + input: string, + lastChar: boolean // only checkbox is need here to handle it [instead of two combo boxes] +) { + if (!input) return ''; + let result: string; + let reversedString: string; + + // reverse the whole input if lastChar enabled + reversedString = lastChar ? reverseString(input) : reverseString(input.slice(0, -1)); + result = input.concat(reversedString); + return result; +} + +export function createPalindromeList( + input: string, + lastChar: boolean, + multiLine: boolean +): string { + if (!input) return ''; + let array: string[]; + let result: string[] = []; + + if (!multiLine) return createPalindrome(input, lastChar); + else { + array = input.split('\n'); + for (const word of array) { + result.push(createPalindrome(word, lastChar)); + } + } + return result.join('\n'); + +} \ No newline at end of file diff --git a/src/pages/string/index.ts b/src/pages/string/index.ts index ccc5a01..b588dee 100644 --- a/src/pages/string/index.ts +++ b/src/pages/string/index.ts @@ -1,3 +1,4 @@ +import { tool as stringCreatePalindrome } from './create-palindrome/meta'; import { tool as stringPalindrome } from './palindrome/meta'; import { tool as stringToMorse } from './to-morse/meta'; import { tool as stringSplit } from './split/meta'; From eda771f38c79c6b673b26fc30d67c4f6e58265c4 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 10 Jul 2024 16:17:56 +0000 Subject: [PATCH 5/9] extract substring tool, testCases then updated index file --- .../extract-substring.service.test.ts | 57 +++++++++++++++++++ src/pages/string/extract-substring/index.tsx | 11 ++++ src/pages/string/extract-substring/meta.ts | 13 +++++ src/pages/string/extract-substring/service.ts | 36 ++++++++++++ src/pages/string/index.ts | 1 + 5 files changed, 118 insertions(+) create mode 100644 src/pages/string/extract-substring/extract-substring.service.test.ts create mode 100644 src/pages/string/extract-substring/index.tsx create mode 100644 src/pages/string/extract-substring/meta.ts create mode 100644 src/pages/string/extract-substring/service.ts diff --git a/src/pages/string/extract-substring/extract-substring.service.test.ts b/src/pages/string/extract-substring/extract-substring.service.test.ts new file mode 100644 index 0000000..ecacc55 --- /dev/null +++ b/src/pages/string/extract-substring/extract-substring.service.test.ts @@ -0,0 +1,57 @@ +import { expect, describe, it } from 'vitest'; +import { extractSubstring } from './service'; + +describe('extractSubstring', () => { + it('should extract a substring from single-line input', () => { + const input = 'hello world'; + const result = extractSubstring(input, 1, 4, false, false); + expect(result).toBe('hell'); + }); + + it('should extract and reverse a substring from single-line input', () => { + const input = 'hello world'; + const result = extractSubstring(input, 1, 5, false, true); + expect(result).toBe('olleh'); + }); + + it('should extract substrings from multi-line input', () => { + const input = 'hello\nworld'; + const result = extractSubstring(input, 1, 5, true, false); + expect(result).toBe('hello\nworld'); + }); + + it('should extract and reverse substrings from multi-line input', () => { + const input = 'hello\nworld'; + const result = extractSubstring(input, 1, 4, true, true); + expect(result).toBe('lleh\nlrow'); + }); + + it('should handle empty input', () => { + const input = ''; + const result = extractSubstring(input, 1, 5, false, false); + expect(result).toBe(''); + }); + + it('should handle start and length out of bounds', () => { + const input = 'hello'; + const result = extractSubstring(input, 10, 5, false, false); + expect(result).toBe(''); + }); + + it('should handle negative start and length', () => { + expect(() => extractSubstring('hello', -1, 5, false, false)).toThrow("Start index must be greater than zero."); + expect(() => extractSubstring('hello', 1, -5, false, false)).toThrow("Length value must be greater than or equal to zero."); + }); + + it('should handle zero length', () => { + const input = 'hello'; + const result = extractSubstring(input, 1, 0, false, false); + expect(result).toBe(''); + }); + + it('should work', () => { + const input = 'je me nomme king\n22 est mon chiffre'; + const result = extractSubstring(input, 12, 7, true, false); + expect(result).toBe(' king\nchiffre'); + }); +}); \ No newline at end of file diff --git a/src/pages/string/extract-substring/index.tsx b/src/pages/string/extract-substring/index.tsx new file mode 100644 index 0000000..be249e8 --- /dev/null +++ b/src/pages/string/extract-substring/index.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import * as Yup from 'yup'; + +const initialValues = {}; +const validationSchema = Yup.object({ + // splitSeparator: Yup.string().required('The separator is required') +}); +export default function ExtractSubstring() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/string/extract-substring/meta.ts b/src/pages/string/extract-substring/meta.ts new file mode 100644 index 0000000..30e8f74 --- /dev/null +++ b/src/pages/string/extract-substring/meta.ts @@ -0,0 +1,13 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; +// import image from '@assets/text.png'; + +export const tool = defineTool('string', { + name: 'Extract substring', + path: 'extract-substring', + // image, + description: '', + shortDescription: '', + keywords: ['extract', 'substring'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/string/extract-substring/service.ts b/src/pages/string/extract-substring/service.ts new file mode 100644 index 0000000..c06a10f --- /dev/null +++ b/src/pages/string/extract-substring/service.ts @@ -0,0 +1,36 @@ +import { reverseString } from 'utils/string' + +export function extractSubstring( + input: string, + start: number, + length: number, + multiLine: boolean, + reverse: boolean +): string { + if (!input) return ''; + // edge Cases + if (start <= 0) throw new Error("Start index must be greater than zero."); + if (length < 0) throw new Error("Length value must be greater than or equal to zero."); + if (length === 0) return ''; + + let array: string[]; + let result: string[] = []; + + const extract = (str: string, start: number, length: number): string => { + const end = start - 1 + length; + if (start - 1 >= str.length) return ''; + return str.substring(start - 1, Math.min(end, str.length)); + }; + + if (!multiLine) { + result.push(extract(input, start, length)); + } + else { + array = input.split('\n'); + for (const word of array) { + result.push(extract(word, start, length)); + } + } + result = reverse ? result.map(word => reverseString(word)) : result; + return result.join('\n'); +} \ No newline at end of file diff --git a/src/pages/string/index.ts b/src/pages/string/index.ts index b588dee..1ea0627 100644 --- a/src/pages/string/index.ts +++ b/src/pages/string/index.ts @@ -1,3 +1,4 @@ +import { tool as stringExtractSubstring } from './extract-substring/meta'; import { tool as stringCreatePalindrome } from './create-palindrome/meta'; import { tool as stringPalindrome } from './palindrome/meta'; import { tool as stringToMorse } from './to-morse/meta'; From ad46b91b3bca605ccd1559aeb2668b543750519e Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 10 Jul 2024 16:49:55 +0000 Subject: [PATCH 6/9] toUppercase tool, testCases and updated index file --- src/pages/string/index.ts | 1 + src/pages/string/uppercase/index.tsx | 11 ++++++ src/pages/string/uppercase/meta.ts | 13 +++++++ src/pages/string/uppercase/service.ts | 3 ++ .../uppercase/uppercase.service.test.ts | 34 +++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 src/pages/string/uppercase/index.tsx create mode 100644 src/pages/string/uppercase/meta.ts create mode 100644 src/pages/string/uppercase/service.ts create mode 100644 src/pages/string/uppercase/uppercase.service.test.ts diff --git a/src/pages/string/index.ts b/src/pages/string/index.ts index 1ea0627..bc988ea 100644 --- a/src/pages/string/index.ts +++ b/src/pages/string/index.ts @@ -1,3 +1,4 @@ +import { tool as stringUppercase } from './uppercase/meta'; import { tool as stringExtractSubstring } from './extract-substring/meta'; import { tool as stringCreatePalindrome } from './create-palindrome/meta'; import { tool as stringPalindrome } from './palindrome/meta'; diff --git a/src/pages/string/uppercase/index.tsx b/src/pages/string/uppercase/index.tsx new file mode 100644 index 0000000..727cc03 --- /dev/null +++ b/src/pages/string/uppercase/index.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import * as Yup from 'yup'; + +const initialValues = {}; +const validationSchema = Yup.object({ + // splitSeparator: Yup.string().required('The separator is required') +}); +export default function Uppercase() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/string/uppercase/meta.ts b/src/pages/string/uppercase/meta.ts new file mode 100644 index 0000000..014f2cd --- /dev/null +++ b/src/pages/string/uppercase/meta.ts @@ -0,0 +1,13 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; +// import image from '@assets/text.png'; + +export const tool = defineTool('string', { + name: 'Uppercase', + path: 'uppercase', + // image, + description: '', + shortDescription: '', + keywords: ['uppercase'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/string/uppercase/service.ts b/src/pages/string/uppercase/service.ts new file mode 100644 index 0000000..3bfecff --- /dev/null +++ b/src/pages/string/uppercase/service.ts @@ -0,0 +1,3 @@ +export function toUppercase(input: string): string { + return input.toUpperCase(); +} \ No newline at end of file diff --git a/src/pages/string/uppercase/uppercase.service.test.ts b/src/pages/string/uppercase/uppercase.service.test.ts new file mode 100644 index 0000000..4392ca6 --- /dev/null +++ b/src/pages/string/uppercase/uppercase.service.test.ts @@ -0,0 +1,34 @@ +import { expect, describe, it } from 'vitest'; +import { toUppercase } from './service'; + +describe('toUppercase', () => { + test('should convert a lowercase string to uppercase', () => { + const input = 'hello'; + const result = toUppercase(input); + expect(result).toBe('HELLO'); + }); + + test('should convert a mixed case string to uppercase', () => { + const input = 'HeLLo WoRLd'; + const result = toUppercase(input); + expect(result).toBe('HELLO WORLD'); + }); + + test('should convert an already uppercase string to uppercase', () => { + const input = 'HELLO'; + const result = toUppercase(input); + expect(result).toBe('HELLO'); + }); + + test('should handle an empty string', () => { + const input = ''; + const result = toUppercase(input); + expect(result).toBe(''); + }); + + test('should handle a string with numbers and symbols', () => { + const input = '123 hello! @world'; + const result = toUppercase(input); + expect(result).toBe('123 HELLO! @WORLD'); + }); +}); \ No newline at end of file From 2bb8158aa3e512cc45f8d354fdb0f04d42c7e31f Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 10 Jul 2024 16:59:47 +0000 Subject: [PATCH 7/9] renaming the function for clarity --- src/pages/string/uppercase/service.ts | 2 +- .../uppercase/uppercase.service.test.ts | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/pages/string/uppercase/service.ts b/src/pages/string/uppercase/service.ts index 3bfecff..1ffc0fa 100644 --- a/src/pages/string/uppercase/service.ts +++ b/src/pages/string/uppercase/service.ts @@ -1,3 +1,3 @@ -export function toUppercase(input: string): string { +export function UppercaseInput(input: string): string { return input.toUpperCase(); } \ No newline at end of file diff --git a/src/pages/string/uppercase/uppercase.service.test.ts b/src/pages/string/uppercase/uppercase.service.test.ts index 4392ca6..6bb3f11 100644 --- a/src/pages/string/uppercase/uppercase.service.test.ts +++ b/src/pages/string/uppercase/uppercase.service.test.ts @@ -1,34 +1,34 @@ import { expect, describe, it } from 'vitest'; -import { toUppercase } from './service'; +import { UppercaseInput } from './service'; -describe('toUppercase', () => { - test('should convert a lowercase string to uppercase', () => { +describe('UppercaseInput', () => { + it('should convert a lowercase string to uppercase', () => { const input = 'hello'; - const result = toUppercase(input); + const result = UppercaseInput(input); expect(result).toBe('HELLO'); }); - test('should convert a mixed case string to uppercase', () => { + it('should convert a mixed case string to uppercase', () => { const input = 'HeLLo WoRLd'; - const result = toUppercase(input); + const result = UppercaseInput(input); expect(result).toBe('HELLO WORLD'); }); - test('should convert an already uppercase string to uppercase', () => { + it('should convert an already uppercase string to uppercase', () => { const input = 'HELLO'; - const result = toUppercase(input); + const result = UppercaseInput(input); expect(result).toBe('HELLO'); }); - test('should handle an empty string', () => { + it('should handle an empty string', () => { const input = ''; - const result = toUppercase(input); + const result = UppercaseInput(input); expect(result).toBe(''); }); - test('should handle a string with numbers and symbols', () => { + it('should handle a string with numbers and symbols', () => { const input = '123 hello! @world'; - const result = toUppercase(input); + const result = UppercaseInput(input); expect(result).toBe('123 HELLO! @WORLD'); }); }); \ No newline at end of file From c48b2853b65275548ef8c1a662484f386846f908 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 10 Jul 2024 17:56:56 +0000 Subject: [PATCH 8/9] randomize case tool, testCases and updated index file --- src/pages/string/index.ts | 1 + src/pages/string/randomize-case/index.tsx | 11 +++++ src/pages/string/randomize-case/meta.ts | 13 +++++ .../randomize-case.service.test.ts | 48 +++++++++++++++++++ src/pages/string/randomize-case/service.ts | 6 +++ 5 files changed, 79 insertions(+) create mode 100644 src/pages/string/randomize-case/index.tsx create mode 100644 src/pages/string/randomize-case/meta.ts create mode 100644 src/pages/string/randomize-case/randomize-case.service.test.ts create mode 100644 src/pages/string/randomize-case/service.ts diff --git a/src/pages/string/index.ts b/src/pages/string/index.ts index bc988ea..ea2d978 100644 --- a/src/pages/string/index.ts +++ b/src/pages/string/index.ts @@ -1,3 +1,4 @@ +import { tool as stringRandomizeCase } from './randomize-case/meta'; import { tool as stringUppercase } from './uppercase/meta'; import { tool as stringExtractSubstring } from './extract-substring/meta'; import { tool as stringCreatePalindrome } from './create-palindrome/meta'; diff --git a/src/pages/string/randomize-case/index.tsx b/src/pages/string/randomize-case/index.tsx new file mode 100644 index 0000000..fbb7733 --- /dev/null +++ b/src/pages/string/randomize-case/index.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import * as Yup from 'yup'; + +const initialValues = {}; +const validationSchema = Yup.object({ + // splitSeparator: Yup.string().required('The separator is required') +}); +export default function RandomizeCase() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/string/randomize-case/meta.ts b/src/pages/string/randomize-case/meta.ts new file mode 100644 index 0000000..be2da07 --- /dev/null +++ b/src/pages/string/randomize-case/meta.ts @@ -0,0 +1,13 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; +// import image from '@assets/text.png'; + +export const tool = defineTool('string', { + name: 'Randomize case', + path: 'randomize-case', + // image, + description: '', + shortDescription: '', + keywords: ['randomize', 'case'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/string/randomize-case/randomize-case.service.test.ts b/src/pages/string/randomize-case/randomize-case.service.test.ts new file mode 100644 index 0000000..7e44a7a --- /dev/null +++ b/src/pages/string/randomize-case/randomize-case.service.test.ts @@ -0,0 +1,48 @@ +import { expect, describe, it } from 'vitest'; +import { randomizeCase } from './service'; + +describe('randomizeCase', () => { + it('should randomize the case of each character in the string', () => { + const input = 'hello world'; + const result = randomizeCase(input); + + // Ensure the output length is the same + expect(result).toHaveLength(input.length); + + // Ensure each character in the input string appears in the result + for (let i = 0; i < input.length; i++) { + const inputChar = input[i]; + const resultChar = result[i]; + + if (/[a-zA-Z]/.test(inputChar)) { + expect([inputChar.toLowerCase(), inputChar.toUpperCase()]).toContain(resultChar); + } else { + expect(inputChar).toBe(resultChar); + } + } + }); + + it('should handle an empty string', () => { + const input = ''; + const result = randomizeCase(input); + expect(result).toBe(''); + }); + + it('should handle a string with numbers and symbols', () => { + const input = '123 hello! @world'; + const result = randomizeCase(input); + + // Ensure the output length is the same + expect(result).toHaveLength(input.length); + + // Ensure numbers and symbols remain unchanged + for (let i = 0; i < input.length; i++) { + const inputChar = input[i]; + const resultChar = result[i]; + + if (!/[a-zA-Z]/.test(inputChar)) { + expect(inputChar).toBe(resultChar); + } + } + }); +}); \ No newline at end of file diff --git a/src/pages/string/randomize-case/service.ts b/src/pages/string/randomize-case/service.ts new file mode 100644 index 0000000..a6f6860 --- /dev/null +++ b/src/pages/string/randomize-case/service.ts @@ -0,0 +1,6 @@ +export function randomizeCase(input: string): string { + return input + .split('') + .map(char => (Math.random() < 0.5 ? char.toLowerCase() : char.toUpperCase())) + .join(''); +} \ No newline at end of file From 0064476c51dcd39d84cfe301d2aa00b0ccda09c1 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Thu, 11 Jul 2024 00:01:59 +0000 Subject: [PATCH 9/9] reverse tool, testCases then updated index file --- src/pages/string/index.ts | 1 + src/pages/string/reverse/index.tsx | 11 ++++ src/pages/string/reverse/meta.ts | 13 +++++ .../string/reverse/reverse.service.test.ts | 52 +++++++++++++++++++ src/pages/string/reverse/service.ts | 31 +++++++++++ 5 files changed, 108 insertions(+) create mode 100644 src/pages/string/reverse/index.tsx create mode 100644 src/pages/string/reverse/meta.ts create mode 100644 src/pages/string/reverse/reverse.service.test.ts create mode 100644 src/pages/string/reverse/service.ts diff --git a/src/pages/string/index.ts b/src/pages/string/index.ts index ea2d978..f7eed37 100644 --- a/src/pages/string/index.ts +++ b/src/pages/string/index.ts @@ -1,3 +1,4 @@ +import { tool as stringReverse } from './reverse/meta'; import { tool as stringRandomizeCase } from './randomize-case/meta'; import { tool as stringUppercase } from './uppercase/meta'; import { tool as stringExtractSubstring } from './extract-substring/meta'; diff --git a/src/pages/string/reverse/index.tsx b/src/pages/string/reverse/index.tsx new file mode 100644 index 0000000..e017afe --- /dev/null +++ b/src/pages/string/reverse/index.tsx @@ -0,0 +1,11 @@ +import { Box } from '@mui/material'; +import React from 'react'; +import * as Yup from 'yup'; + +const initialValues = {}; +const validationSchema = Yup.object({ + // splitSeparator: Yup.string().required('The separator is required') +}); +export default function Reverse() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/string/reverse/meta.ts b/src/pages/string/reverse/meta.ts new file mode 100644 index 0000000..886b604 --- /dev/null +++ b/src/pages/string/reverse/meta.ts @@ -0,0 +1,13 @@ +import { defineTool } from '@tools/defineTool'; +import { lazy } from 'react'; +// import image from '@assets/text.png'; + +export const tool = defineTool('string', { + name: 'Reverse', + path: 'reverse', + // image, + description: '', + shortDescription: '', + keywords: ['reverse'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/string/reverse/reverse.service.test.ts b/src/pages/string/reverse/reverse.service.test.ts new file mode 100644 index 0000000..0e6ed45 --- /dev/null +++ b/src/pages/string/reverse/reverse.service.test.ts @@ -0,0 +1,52 @@ +import { expect, describe, it } from 'vitest'; +import { stringReverser } from './service'; + +describe('stringReverser', () => { + it('should reverse a single-line string', () => { + const input = 'hello world'; + const result = stringReverser(input, false, false, false); + expect(result).toBe('dlrow olleh'); + }); + + it('should reverse each line in a multi-line string', () => { + const input = 'hello\nworld'; + const result = stringReverser(input, true, false, false); + expect(result).toBe('olleh\ndlrow'); + }); + + it('should remove empty items if emptyItems is true', () => { + const input = 'hello\n\nworld'; + const result = stringReverser(input, true, true, false); + expect(result).toBe('olleh\ndlrow'); + }); + + it('should trim each line if trim is true', () => { + const input = ' hello \n world '; + const result = stringReverser(input, true, false, true); + expect(result).toBe('olleh\ndlrow'); + }); + + it('should handle empty input', () => { + const input = ''; + const result = stringReverser(input, false, false, false); + expect(result).toBe(''); + }); + + it('should handle a single line with emptyItems and trim', () => { + const input = ' hello world '; + const result = stringReverser(input, false, true, true); + expect(result).toBe('dlrow olleh'); + }); + + it('should handle a single line with emptyItems and non trim', () => { + const input = ' hello world '; + const result = stringReverser(input, false, true, false); + expect(result).toBe(' dlrow olleh '); + }); + + it('should handle a multi line with emptyItems and non trim', () => { + const input = ' hello\n\n\n\nworld '; + const result = stringReverser(input, true, true, false); + expect(result).toBe('olleh \n dlrow'); + }); +}); \ No newline at end of file diff --git a/src/pages/string/reverse/service.ts b/src/pages/string/reverse/service.ts new file mode 100644 index 0000000..c8c68a6 --- /dev/null +++ b/src/pages/string/reverse/service.ts @@ -0,0 +1,31 @@ +import { reverseString } from 'utils/string'; + +export function stringReverser( + input: string, + multiLine: boolean, + emptyItems: boolean, + trim: boolean +) { + let array: string[] = []; + let result: string[] = []; + + // split the input in multiLine mode + if (multiLine) { + array = input.split('\n'); + } + else { + array.push(input); + } + + // handle empty items + if (emptyItems){ + array = array.filter(Boolean); + } + // Handle trim + if (trim) { + array = array.map(line => line.trim()); + } + + result = array.map(element => reverseString(element)); + return result.join('\n'); +} \ No newline at end of file