From 028270637026ec699ce88eda71b2599e6c0f2dd8 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Wed, 3 Jul 2024 23:09:25 +0000 Subject: [PATCH 1/9] rotate service and test cases; then updated index file --- src/pages/list/index.ts | 1 + src/pages/list/rotate/index.tsx | 11 ++ src/pages/list/rotate/meta.ts | 13 +++ src/pages/list/rotate/rotate.service.test.ts | 110 +++++++++++++++++++ src/pages/list/rotate/service.ts | 48 ++++++++ 5 files changed, 183 insertions(+) create mode 100644 src/pages/list/rotate/index.tsx create mode 100644 src/pages/list/rotate/meta.ts create mode 100644 src/pages/list/rotate/rotate.service.test.ts create mode 100644 src/pages/list/rotate/service.ts diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index c3e441d..c359bb0 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listRotate } from './rotate/meta'; import { tool as listTruncate } from './truncate/meta'; import { tool as listShuffle } from './shuffle/meta'; import { tool as listSort } from './sort/meta'; diff --git a/src/pages/list/rotate/index.tsx b/src/pages/list/rotate/index.tsx new file mode 100644 index 0000000..ea7d7d5 --- /dev/null +++ b/src/pages/list/rotate/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 Rotate() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/list/rotate/meta.ts b/src/pages/list/rotate/meta.ts new file mode 100644 index 0000000..506b51e --- /dev/null +++ b/src/pages/list/rotate/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: 'Rotate', + path: 'rotate', + // image, + description: '', + shortDescription: '', + keywords: ['rotate'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/rotate/rotate.service.test.ts b/src/pages/list/rotate/rotate.service.test.ts new file mode 100644 index 0000000..9b68933 --- /dev/null +++ b/src/pages/list/rotate/rotate.service.test.ts @@ -0,0 +1,110 @@ +import { expect, describe, it } from 'vitest'; +import { + SplitOperatorType, + rotateList +} from './service'; + +describe('rotate function', () => { + it('should rotate right side if right is set to true', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ' '; + const step = 1; + const right = true; + + const result = rotateList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + right, + + step); + + expect(result).toBe('mango apple pineaple lemon orange'); + + }); + + it('should rotate left side if right is set to true', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ' '; + const step = 1; + const right = false; + + const result = rotateList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + right, + + step); + + expect(result).toBe('pineaple lemon orange mango apple'); + + }); + + it('should rotate left side with 2 step if right is set to true', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ' '; + const step = 2; + const right = false; + + const result = rotateList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + right, + + step); + + expect(result).toBe('lemon orange mango apple pineaple'); + + }); + + it('should raise an error if step is negative', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ' '; + const step = -2; + const right = false; + + expect(() => { + rotateList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + right, + step); + }).toThrowError('Rotation step must be greater than zero.'); + + }); + + it('should raise an error if step is undefined', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ' '; + const right = false; + + expect(() => { + rotateList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + right); + }).toThrowError('Rotation step contains non-digits.'); + + }); + + +}) \ No newline at end of file diff --git a/src/pages/list/rotate/service.ts b/src/pages/list/rotate/service.ts new file mode 100644 index 0000000..9a27957 --- /dev/null +++ b/src/pages/list/rotate/service.ts @@ -0,0 +1,48 @@ +import { isNumber } from 'utils/string'; +export type SplitOperatorType = 'symbol' | 'regex'; + +function rotateArray( + array: string[], + step: number, + right: boolean): string[] { + const length = array.length; + + // Normalize the step to be within the bounds of the array length + const normalizedPositions = ((step % length) + length) % length; + + if (right) { + // Rotate right + return array.slice(-normalizedPositions).concat(array.slice(0, -normalizedPositions)); + } else { + // Rotate left + return array.slice(normalizedPositions).concat(array.slice(0, normalizedPositions)); + } +} + +export function rotateList( + splitOperatorType: SplitOperatorType, + input: string, + splitSeparator: string, + joinSeparator: string, + right: boolean, + step?: number, +): string { + let array: string[]; + let rotatedArray: string[]; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)); + break; + } + if (step !== undefined) { + if (step <= 0) { + throw new Error("Rotation step must be greater than zero."); + } + rotatedArray = rotateArray(array, step, right); + return rotatedArray.join(joinSeparator); + } + throw new Error("Rotation step contains non-digits.") +} \ No newline at end of file From 37c520d9ca1da9dc33e46619b298cf33094216be Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Thu, 4 Jul 2024 09:17:52 +0000 Subject: [PATCH 2/9] wrap tool and testCases, then updated index file --- src/pages/list/index.ts | 1 + src/pages/list/wrap/index.tsx | 11 ++++ src/pages/list/wrap/meta.ts | 13 ++++ src/pages/list/wrap/service.ts | 27 ++++++++ src/pages/list/wrap/wrap.service.test.ts | 84 ++++++++++++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 src/pages/list/wrap/index.tsx create mode 100644 src/pages/list/wrap/meta.ts create mode 100644 src/pages/list/wrap/service.ts create mode 100644 src/pages/list/wrap/wrap.service.test.ts diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index c359bb0..a98cbb6 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listWrap } from './wrap/meta'; import { tool as listRotate } from './rotate/meta'; import { tool as listTruncate } from './truncate/meta'; import { tool as listShuffle } from './shuffle/meta'; diff --git a/src/pages/list/wrap/index.tsx b/src/pages/list/wrap/index.tsx new file mode 100644 index 0000000..ff4c040 --- /dev/null +++ b/src/pages/list/wrap/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 Wrap() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/list/wrap/meta.ts b/src/pages/list/wrap/meta.ts new file mode 100644 index 0000000..5a394d0 --- /dev/null +++ b/src/pages/list/wrap/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: 'Wrap', + path: 'wrap', + // image, + description: '', + shortDescription: '', + keywords: ['wrap'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/wrap/service.ts b/src/pages/list/wrap/service.ts new file mode 100644 index 0000000..d7bd8d5 --- /dev/null +++ b/src/pages/list/wrap/service.ts @@ -0,0 +1,27 @@ +export type SplitOperatorType = 'symbol' | 'regex'; + +function wrap(array: string[], left: string, right: string): string[] { + return array.map((element) => left + element + right); +} + +export function wrapList( + splitOperatorType: SplitOperatorType, + input: string, + splitSeparator: string, + joinSeparator: string, + left: string = '', + right: string = '' +): string { + let array: string[]; + let wrappedArray: string[]; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)); + break; + } + wrappedArray = wrap(array, left, right); + return wrappedArray.join(joinSeparator); +} diff --git a/src/pages/list/wrap/wrap.service.test.ts b/src/pages/list/wrap/wrap.service.test.ts new file mode 100644 index 0000000..cd20a8e --- /dev/null +++ b/src/pages/list/wrap/wrap.service.test.ts @@ -0,0 +1,84 @@ +import { expect, describe, it } from 'vitest'; +import { + SplitOperatorType, + wrapList +} from './service'; + +describe('wrap function', () => { + it('should return the same input if no left and right are blanked', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ', '; + + + const result = wrapList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + ); + + expect(result).toBe('apple, pineaple, lemon, orange, mango'); + + }); + + it('should append to left if defined', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ', '; + const left = 'the '; + + const result = wrapList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + left); + + expect(result).toBe('the apple, the pineaple, the lemon, the orange, the mango'); + + }); + + it('should append to right if defined', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ', '; + const left = ''; + const right = 'z'; + + const result = wrapList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + left, + right); + + expect(result).toBe('applez, pineaplez, lemonz, orangez, mangoz'); + }); + + it('should append to both side if both defined', () => { + const input: string = 'apple, pineaple, lemon, orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ', '; + const left = 'K'; + const right = 'z'; + + const result = wrapList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + left, + right); + + expect(result).toBe('Kapplez, Kpineaplez, Klemonz, Korangez, Kmangoz'); + + }); + + +}) \ No newline at end of file From cc16fa5bb083537c8bbc06bfeb129ac0b109e5f8 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Thu, 4 Jul 2024 10:54:30 +0000 Subject: [PATCH 3/9] uodate wrap to handle empty items deletion and adding testcases for that feature --- src/pages/list/wrap/service.ts | 7 +++- src/pages/list/wrap/wrap.service.test.ts | 53 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/pages/list/wrap/service.ts b/src/pages/list/wrap/service.ts index d7bd8d5..c92bd09 100644 --- a/src/pages/list/wrap/service.ts +++ b/src/pages/list/wrap/service.ts @@ -9,8 +9,10 @@ export function wrapList( input: string, splitSeparator: string, joinSeparator: string, + deleteEmptyItems: boolean, left: string = '', - right: string = '' + right: string = '', + ): string { let array: string[]; let wrappedArray: string[]; @@ -22,6 +24,9 @@ export function wrapList( array = input.split(new RegExp(splitSeparator)); break; } + if (deleteEmptyItems) { + array = array.filter(Boolean); + } wrappedArray = wrap(array, left, right); return wrappedArray.join(joinSeparator); } diff --git a/src/pages/list/wrap/wrap.service.test.ts b/src/pages/list/wrap/wrap.service.test.ts index cd20a8e..19c8e1d 100644 --- a/src/pages/list/wrap/wrap.service.test.ts +++ b/src/pages/list/wrap/wrap.service.test.ts @@ -10,6 +10,7 @@ describe('wrap function', () => { const splitOperatorType: SplitOperatorType = 'symbol'; const splitSeparator = ', '; const joinSeparator = ', '; + const deleteEmptyItems = false; const result = wrapList( @@ -17,6 +18,7 @@ describe('wrap function', () => { input, splitSeparator, joinSeparator, + deleteEmptyItems ); expect(result).toBe('apple, pineaple, lemon, orange, mango'); @@ -29,12 +31,14 @@ describe('wrap function', () => { const splitSeparator = ', '; const joinSeparator = ', '; const left = 'the '; + const deleteEmptyItems = false; const result = wrapList( splitOperatorType, input, splitSeparator, joinSeparator, + deleteEmptyItems, left); expect(result).toBe('the apple, the pineaple, the lemon, the orange, the mango'); @@ -48,12 +52,14 @@ describe('wrap function', () => { const joinSeparator = ', '; const left = ''; const right = 'z'; + const deleteEmptyItems = false; const result = wrapList( splitOperatorType, input, splitSeparator, joinSeparator, + deleteEmptyItems, left, right); @@ -65,6 +71,7 @@ describe('wrap function', () => { const splitOperatorType: SplitOperatorType = 'symbol'; const splitSeparator = ', '; const joinSeparator = ', '; + const deleteEmptyItems = false; const left = 'K'; const right = 'z'; @@ -73,6 +80,52 @@ describe('wrap function', () => { input, splitSeparator, joinSeparator, + deleteEmptyItems, + left, + right); + + expect(result).toBe('Kapplez, Kpineaplez, Klemonz, Korangez, Kmangoz'); + + }); + + it('should append to both side if both defined and not delete empty items', () => { + const input: string = 'apple, pineaple, lemon, orange, mango, '; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ', '; + const deleteEmptyItems = false; + const left = 'K'; + const right = 'z'; + + const result = wrapList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + deleteEmptyItems, + left, + right); + + expect(result).toBe('Kapplez, Kpineaplez, Klemonz, Korangez, Kmangoz, Kz'); + + }); + + + it('should append to both side if both defined and delete empty items', () => { + const input: string = 'apple, pineaple, lemon, , orange, mango'; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ', '; + const joinSeparator = ', '; + const deleteEmptyItems = true; + const left = 'K'; + const right = 'z'; + + const result = wrapList( + splitOperatorType, + input, + splitSeparator, + joinSeparator, + deleteEmptyItems, left, right); From ef0069202df81f73f12f854707697e1dc9391c7f Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Fri, 5 Jul 2024 18:24:16 +0000 Subject: [PATCH 4/9] group tool service, testCases then updated index file --- src/pages/list/group/group.service.test.ts | 99 ++++++++++++++++++++++ src/pages/list/group/index.tsx | 11 +++ src/pages/list/group/meta.ts | 13 +++ src/pages/list/group/service.ts | 92 ++++++++++++++++++++ src/pages/list/index.ts | 1 + 5 files changed, 216 insertions(+) create mode 100644 src/pages/list/group/group.service.test.ts create mode 100644 src/pages/list/group/index.tsx create mode 100644 src/pages/list/group/meta.ts create mode 100644 src/pages/list/group/service.ts diff --git a/src/pages/list/group/group.service.test.ts b/src/pages/list/group/group.service.test.ts new file mode 100644 index 0000000..18b0604 --- /dev/null +++ b/src/pages/list/group/group.service.test.ts @@ -0,0 +1,99 @@ +import { expect, describe, it } from 'vitest'; + +import { groupList, SplitOperatorType } from './service'; + +describe('groupList', () => { + it('splits by symbol, groups, pads, and formats correctly', () => { + const input = "a,b,c,d,e,f,g,h,i,j"; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ','; + const groupNumber = 3; + const itemSeparator = '-'; + const leftWrap = '['; + const rightWrap = ']'; + const groupSeparator = ' | '; + const deleteEmptyItems = false; + const padNonFullGroup = true; + const paddingChar = 'x'; + + const expectedOutput = "[a-b-c] | [d-e-f] | [g-h-i] | [j-x-x]"; + + const result = groupList( + splitOperatorType, + splitSeparator, + input, + groupNumber, + itemSeparator, + leftWrap, + rightWrap, + groupSeparator, + deleteEmptyItems, + padNonFullGroup, + paddingChar + ); + + expect(result).toBe(expectedOutput); + }); + + it('handles regex split, no padding, and formats correctly', () => { + const input = "a1b2c3d4e5f6g7h8i9j"; + const splitOperatorType: SplitOperatorType = 'regex'; + const splitSeparator = '\\d'; + const groupNumber = 4; + const itemSeparator = ','; + const leftWrap = '('; + const rightWrap = ')'; + const groupSeparator = ' / '; + const deleteEmptyItems = true; + const padNonFullGroup = false; + + const expectedOutput = "(a,b,c,d) / (e,f,g,h) / (i,j)"; + + const result = groupList( + splitOperatorType, + splitSeparator, + input, + groupNumber, + itemSeparator, + leftWrap, + rightWrap, + groupSeparator, + deleteEmptyItems, + padNonFullGroup + ); + + expect(result).toBe(expectedOutput); + }); + + it('handles empty items removal and padd the last group with a z', () => { + const input = "a,,b,,c,,d,,e,,"; + const splitOperatorType: SplitOperatorType = 'symbol'; + const splitSeparator = ','; + const groupNumber = 2; + const itemSeparator = ':'; + const leftWrap = '<'; + const rightWrap = '>'; + const groupSeparator = ' & '; + const deleteEmptyItems = true; + const padNonFullGroup = true; + const paddingChar = 'z'; + + const expectedOutput = " & & "; + + const result = groupList( + splitOperatorType, + splitSeparator, + input, + groupNumber, + itemSeparator, + leftWrap, + rightWrap, + groupSeparator, + deleteEmptyItems, + padNonFullGroup, + paddingChar + ); + + expect(result).toBe(expectedOutput); + }); +}); \ No newline at end of file diff --git a/src/pages/list/group/index.tsx b/src/pages/list/group/index.tsx new file mode 100644 index 0000000..3134478 --- /dev/null +++ b/src/pages/list/group/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 Group() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/list/group/meta.ts b/src/pages/list/group/meta.ts new file mode 100644 index 0000000..70d482e --- /dev/null +++ b/src/pages/list/group/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: 'Group', + path: 'group', + // image, + description: '', + shortDescription: '', + keywords: ['group'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/group/service.ts b/src/pages/list/group/service.ts new file mode 100644 index 0000000..245a564 --- /dev/null +++ b/src/pages/list/group/service.ts @@ -0,0 +1,92 @@ +export type SplitOperatorType = 'symbol' | 'regex'; + + +// function that split the array into an array of subarray of desired length +function groupMaker( + array: string[], + groupNumber: number, +): string[][] { + const result: string[][] = []; + for (let i = 0; i < array.length; i += groupNumber) { + result.push(array.slice(i, i + groupNumber)); + } + return result; +} + +// function use to handle the case paddingNonFullGroup is enable +function groupFiller( + array: string[][], + groupNumber: number, + padNonFullGroup: boolean, + paddingChar: string = '', +): string[][] { + if (padNonFullGroup) { + const lastSubArray: string[] = array[array.length - 1]; + if (lastSubArray.length < groupNumber) { + for (let i = lastSubArray.length; i < groupNumber; i++) { + lastSubArray.push(paddingChar); + } + } + array[array.length - 1] = lastSubArray; + } + return array; + +} + +// function that join with the item separator and wrap with left and right each subArray of the Array +function groupJoinerAndWrapper( + array: string[][], + itemSeparator: string = '', + leftWrap: string = '', + rightWrap: string = '', +): string[] { + return array.map(subArray => { + return leftWrap + subArray.join(itemSeparator) + rightWrap; + }); +} + + +export function groupList( + splitOperatorType: SplitOperatorType, + splitSeparator: string, + input: string, + groupNumber: number, + itemSeparator: string = '', + leftWrap: string = '', + rightWrap: string = '', + groupSeparator: string, + deleteEmptyItems: boolean, + padNonFullGroup: boolean, + paddingChar: string = '', + +): string { + let array: string[]; + let splitedArray: string[][]; + let fullSplitedArray: string[][]; + let result: string[]; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)); + break; + } + // delete empty items after intial split + if (deleteEmptyItems) { + array = array.filter(item => item !== ''); + } + + // split the input into an array of subArray with the desired length + splitedArray = groupMaker(array, groupNumber); + + // fill the last subArray is PadNonFullGroup is enabled + fullSplitedArray = groupFiller(splitedArray, groupNumber, padNonFullGroup, paddingChar); + + // get the list of formated subArray with the item separator and left and right wrapper + result = groupJoinerAndWrapper(fullSplitedArray, itemSeparator, leftWrap, rightWrap); + + // finnaly join the group separator before returning + return result.join(groupSeparator); +} + diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index a98cbb6..d265dd7 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listGroup } from './group/meta'; import { tool as listWrap } from './wrap/meta'; import { tool as listRotate } from './rotate/meta'; import { tool as listTruncate } from './truncate/meta'; From 375a10b366cbe9630679adf5dafd0c119fee0e40 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 7 Jul 2024 01:24:32 +0000 Subject: [PATCH 5/9] find-most-popular tool and updated index file --- .../find-most-popular.service.test.ts | 65 +++++++++++ src/pages/list/find-most-popular/index.tsx | 11 ++ src/pages/list/find-most-popular/meta.ts | 13 +++ src/pages/list/find-most-popular/service.ts | 107 ++++++++++++++++++ src/pages/list/index.ts | 1 + 5 files changed, 197 insertions(+) create mode 100644 src/pages/list/find-most-popular/find-most-popular.service.test.ts create mode 100644 src/pages/list/find-most-popular/index.tsx create mode 100644 src/pages/list/find-most-popular/meta.ts create mode 100644 src/pages/list/find-most-popular/service.ts diff --git a/src/pages/list/find-most-popular/find-most-popular.service.test.ts b/src/pages/list/find-most-popular/find-most-popular.service.test.ts new file mode 100644 index 0000000..665de8e --- /dev/null +++ b/src/pages/list/find-most-popular/find-most-popular.service.test.ts @@ -0,0 +1,65 @@ +import { expect, describe, it } from 'vitest'; +import { TopItemsList, SplitOperatorType, SortingMethod, DisplayFormat } from './service'; + +describe('TopItemsList function', () => { + it('should handle sorting alphabetically ignoring case', () => { + const input = 'Apple,banana,apple,Orange,Banana,apple'; + const result = TopItemsList('symbol', 'alphabetic', 'count', ',', input, false, true, false); + expect(result).toEqual( + 'apple: 3\n' + + 'banana: 2\n' + + 'orange: 1' + ); + }); + + it('should handle sorting by count and not ignoring case', () => { + const input = 'apple,banana,apple,orange,banana,apple,Banana'; + const result = TopItemsList('symbol', 'count', 'count', ',', input, false, false, false); + expect(result).toEqual( + 'apple: 3\n' + + 'banana: 2\n' + + 'orange: 1\n' + + 'Banana: 1' + ); + }); + + it('should handle regex split operator', () => { + const input = 'apple123banana456apple789orange012banana345apple678'; + const result = TopItemsList('regex', 'count', 'count', '\\d+', input, false, false, false); + expect(result).toEqual( + 'apple: 3\n' + + 'banana: 2\n' + + 'orange: 1' + ); + }); + + it('should handle percentage display format', () => { + const input = 'apple,banana,apple,orange,banana,apple'; + const result = TopItemsList('symbol', 'count', 'percentage', ',', input, false, false, false); + expect(result).toEqual( + 'apple: 3 (50.00%)\n' + + 'banana: 2 (33.33%)\n' + + 'orange: 1 (16.67%)' + ); + }); + + it('should handle total display format', () => { + const input = 'apple,banana,apple,orange,banana,apple'; + const result = TopItemsList('symbol', 'count', 'total', ',', input, false, false, false); + expect(result).toEqual( + 'apple: 3 (3 / 6)\n' + + 'banana: 2 (2 / 6)\n' + + 'orange: 1 (1 / 6)' + ); + }); + + it('should handle trimming and ignoring empty items', () => { + const input = ' apple , banana , apple , orange , banana , apple '; + const result = TopItemsList('symbol', 'count', 'count', ',', input, true, false, true); + expect(result).toEqual( + 'apple: 3\n' + + 'banana: 2\n' + + 'orange: 1' + ); + }); +}); \ No newline at end of file diff --git a/src/pages/list/find-most-popular/index.tsx b/src/pages/list/find-most-popular/index.tsx new file mode 100644 index 0000000..40566cf --- /dev/null +++ b/src/pages/list/find-most-popular/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 FindMostPopular() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/list/find-most-popular/meta.ts b/src/pages/list/find-most-popular/meta.ts new file mode 100644 index 0000000..309b33c --- /dev/null +++ b/src/pages/list/find-most-popular/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: 'Find most popular', + path: 'find-most-popular', + // image, + description: '', + shortDescription: '', + keywords: ['find', 'most', 'popular'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/find-most-popular/service.ts b/src/pages/list/find-most-popular/service.ts new file mode 100644 index 0000000..6850755 --- /dev/null +++ b/src/pages/list/find-most-popular/service.ts @@ -0,0 +1,107 @@ +export type SplitOperatorType = 'symbol' | 'regex'; +export type DisplayFormat = 'count' | 'percentage' | 'total'; +export type SortingMethod = 'count' | 'alphabetic'; + +// Function that analyzes the array and returns a dict of element occurrences and handle the ignoreItemCase +function dictMaker(array: string[], + ignoreItemCase: boolean +): { [key: string]: number } { + const dict: { [key: string]: number } = {}; + for (const item of array) { + const key = ignoreItemCase ? item.toLowerCase() : item; + dict[key] = (dict[key] || 0) + 1; + } + return dict; +} + +// Function that sorts the dict created with dictMaker based on the chosen sorting method +function dictSorter( + dict: { [key: string]: number }, + sortingMethod: SortingMethod, +): { [key: string]: number } { + let sortedArray: [string, number][]; + switch (sortingMethod) { + case 'count': + sortedArray = Object.entries(dict).sort(([, countA], [, countB]) => countB - countA); + break; + case 'alphabetic': + sortedArray = Object.entries(dict).sort(([keyA], [keyB]) => { + return keyA.localeCompare(keyB) + }); + break; + default: + sortedArray = Object.entries(dict); + break; + } + return Object.fromEntries(sortedArray); +} + +// Function that prepares the output of dictSorter based on the chosen display format +function displayFormater( + dict: { [key: string]: number }, + displayFormat: DisplayFormat +): string[] { + let formattedOutput: string[] = []; + const total = Object.values(dict).reduce((acc, val) => acc + val, 0); + + switch (displayFormat) { + case 'percentage': + Object.entries(dict).forEach(([key, value]) => { + formattedOutput.push(`${key}: ${value} (${((value / total) * 100).toFixed(2)}%)`); + }); + break; + case "total": + Object.entries(dict).forEach(([key, value]) => { + formattedOutput.push(`${key}: ${value} (${value} / ${total})`); + }); + break; + case "count": + Object.entries(dict).forEach(([key, value]) => { + formattedOutput.push(`${key}: ${value}`); + }); + break; + } + return formattedOutput; +} + +export function TopItemsList( + splitOperatorType: SplitOperatorType, + sortingMethod: SortingMethod, + displayFormat: DisplayFormat, + splitSeparator: string, + input: string, + deleteEmptyItems: boolean, + ignoreItemCase: boolean, + trimItems: boolean +): string { + let array: string[]; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)).filter(item => item !== ''); + break; + } + + // Trim items if required + if (trimItems) { + array = array.map(item => item.trim()); + } + + // Delete empty items after initial split + if (deleteEmptyItems) { + array = array.filter(item => item !== ''); + } + + // Transform the array into dict + const unsortedDict = dictMaker(array, ignoreItemCase); + + // Sort the list if required + const sortedDict = dictSorter(unsortedDict, sortingMethod); + + // Format the output with desired format + const formattedOutput = displayFormater(sortedDict, displayFormat); + + return formattedOutput.join('\n'); +} diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index d265dd7..eb8c9f6 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listFindMostPopular } from './find-most-popular/meta'; import { tool as listGroup } from './group/meta'; import { tool as listWrap } from './wrap/meta'; import { tool as listRotate } from './rotate/meta'; From b81de605a1bb185301c78ab9e14a5ae58187744f Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 7 Jul 2024 20:48:04 +0000 Subject: [PATCH 6/9] find-unique tool and testcases the updated index file --- .../find-unique/find-unique.service.test.ts | 47 +++++++++++++++ src/pages/list/find-unique/index.tsx | 11 ++++ src/pages/list/find-unique/meta.ts | 13 +++++ src/pages/list/find-unique/service.ts | 58 +++++++++++++++++++ src/pages/list/index.ts | 1 + 5 files changed, 130 insertions(+) create mode 100644 src/pages/list/find-unique/find-unique.service.test.ts create mode 100644 src/pages/list/find-unique/index.tsx create mode 100644 src/pages/list/find-unique/meta.ts create mode 100644 src/pages/list/find-unique/service.ts diff --git a/src/pages/list/find-unique/find-unique.service.test.ts b/src/pages/list/find-unique/find-unique.service.test.ts new file mode 100644 index 0000000..af1c2f5 --- /dev/null +++ b/src/pages/list/find-unique/find-unique.service.test.ts @@ -0,0 +1,47 @@ +import { expect, describe, it } from 'vitest'; + +import { TopItemsList } from './service'; + +describe('TopItemsList Function', () => { + test('should return unique items ignoring case sensitivity', () => { + const input = 'apple,banana,Apple,orange,Banana,apple'; + const result = TopItemsList('symbol', ',', '\n', input, true, true, false, true); + expect(result).toBe('orange'); + }); + + test('should return unique items considering case sensitivity', () => { + const input = 'apple,banana,Apple,orange,Banana,apple'; + const result = TopItemsList('symbol', ',', '\n', input, true, true, true, true); + expect(result).toBe('banana\nApple\norange\nBanana'); + }); + + test('should return all unique items ignoring case sensitivity', () => { + const input = 'apple,banana,Apple,orange,Banana,apple'; + const result = TopItemsList('symbol', ',', '\n', input, true, true, false, false); + expect(result).toBe('apple\nbanana\norange'); + }); + + test('should return all unique items considering case sensitivity', () => { + const input = 'apple,banana,Apple,orange,Banana,apple'; + const result = TopItemsList('symbol', ',', '\n', input, true, true, true, false); + expect(result).toBe('apple\nbanana\nApple\norange\nBanana'); + }); + + test('should handle empty items deletion', () => { + const input = 'apple,,banana, ,orange'; + const result = TopItemsList('symbol', ',', '\n', input, true, true, false, false); + expect(result).toBe('apple\nbanana\norange'); + }); + + test('should handle trimming items', () => { + const input = ' apple , banana , orange '; + const result = TopItemsList('symbol', ',', '\n', input, false, false, false, false); + expect(result).toBe(' apple \n banana \n orange '); + }); + + test('should handle regex split', () => { + const input = 'apple banana orange'; + const result = TopItemsList('regex', '\\s+', '\n', input, false, false, false, false); + expect(result).toBe('apple\nbanana\norange'); + }); +}); diff --git a/src/pages/list/find-unique/index.tsx b/src/pages/list/find-unique/index.tsx new file mode 100644 index 0000000..63b7b2f --- /dev/null +++ b/src/pages/list/find-unique/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 FindUnique() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/list/find-unique/meta.ts b/src/pages/list/find-unique/meta.ts new file mode 100644 index 0000000..149ec0b --- /dev/null +++ b/src/pages/list/find-unique/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: 'Find unique', + path: 'find-unique', + // image, + description: '', + shortDescription: '', + keywords: ['find', 'unique'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/find-unique/service.ts b/src/pages/list/find-unique/service.ts new file mode 100644 index 0000000..bf35509 --- /dev/null +++ b/src/pages/list/find-unique/service.ts @@ -0,0 +1,58 @@ +export type SplitOperatorType = 'symbol' | 'regex'; + +// Function that builds the unique items array handling caseSensitive and absolutelyUnique options +function uniqueListBuilder( + array: string[], + caseSensitive: boolean, + absolutelyUnique: boolean +): string[] { + const dict: { [key: string]: number } = {}; + for (const item of array) { + const key = caseSensitive ? item : item.toLowerCase(); + dict[key] = (dict[key] || 0) + 1; + } + if (absolutelyUnique) { + for (const [key, value] of Object.entries(dict)) { + if (value > 1) { + delete dict[key]; + } + } + } + return Object.keys(dict); +} + +export function TopItemsList( + splitOperatorType: SplitOperatorType, + splitSeparator: string, + joinSeparator: string = '\n', + input: string, + deleteEmptyItems: boolean, + trimItems: boolean, + caseSensitive: boolean, + absolutelyUnique: boolean +): string { + let array: string[]; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)).filter(item => item !== ''); + break; + } + + // Trim items if required + if (trimItems) { + array = array.map(item => item.trim()); + } + + // Delete empty items after initial split + if (deleteEmptyItems) { + array = array.filter(item => item !== ''); + } + + // Format the output with desired format + const uniqueListItems = uniqueListBuilder(array, caseSensitive, absolutelyUnique); + + return uniqueListItems.join(joinSeparator); +} diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index eb8c9f6..9f37390 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listFindUnique } from './find-unique/meta'; import { tool as listFindMostPopular } from './find-most-popular/meta'; import { tool as listGroup } from './group/meta'; import { tool as listWrap } from './wrap/meta'; From b11540b0163e3ca484cef7f9b688208a451f0a6c Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 7 Jul 2024 20:49:09 +0000 Subject: [PATCH 7/9] comment improvement --- src/pages/list/find-most-popular/service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/list/find-most-popular/service.ts b/src/pages/list/find-most-popular/service.ts index 6850755..3c812b9 100644 --- a/src/pages/list/find-most-popular/service.ts +++ b/src/pages/list/find-most-popular/service.ts @@ -2,7 +2,7 @@ export type SplitOperatorType = 'symbol' | 'regex'; export type DisplayFormat = 'count' | 'percentage' | 'total'; export type SortingMethod = 'count' | 'alphabetic'; -// Function that analyzes the array and returns a dict of element occurrences and handle the ignoreItemCase +// Function that takes the array as arg and returns a dict of element occurrences and handle the ignoreItemCase function dictMaker(array: string[], ignoreItemCase: boolean ): { [key: string]: number } { From 67749431968402d7a70b730e04e6475e23e6a625 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Sun, 7 Jul 2024 22:14:17 +0000 Subject: [PATCH 8/9] reverse tool (easiest) and testCases then updated index file --- src/pages/list/index.ts | 1 + src/pages/list/reverse/index.tsx | 11 ++++++++ src/pages/list/reverse/meta.ts | 13 +++++++++ .../list/reverse/reverse.service.test.ts | 28 +++++++++++++++++++ src/pages/list/reverse/service.ts | 21 ++++++++++++++ 5 files changed, 74 insertions(+) create mode 100644 src/pages/list/reverse/index.tsx create mode 100644 src/pages/list/reverse/meta.ts create mode 100644 src/pages/list/reverse/reverse.service.test.ts create mode 100644 src/pages/list/reverse/service.ts diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index 9f37390..17134e5 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listReverse } from './reverse/meta'; import { tool as listFindUnique } from './find-unique/meta'; import { tool as listFindMostPopular } from './find-most-popular/meta'; import { tool as listGroup } from './group/meta'; diff --git a/src/pages/list/reverse/index.tsx b/src/pages/list/reverse/index.tsx new file mode 100644 index 0000000..e017afe --- /dev/null +++ b/src/pages/list/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/list/reverse/meta.ts b/src/pages/list/reverse/meta.ts new file mode 100644 index 0000000..1ce2ba6 --- /dev/null +++ b/src/pages/list/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('list', { + name: 'Reverse', + path: 'reverse', + // image, + description: '', + shortDescription: '', + keywords: ['reverse'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/reverse/reverse.service.test.ts b/src/pages/list/reverse/reverse.service.test.ts new file mode 100644 index 0000000..b2a468d --- /dev/null +++ b/src/pages/list/reverse/reverse.service.test.ts @@ -0,0 +1,28 @@ +import { expect, describe, it } from 'vitest'; +import { reverseList } from './service'; + +describe('reverseList Function', () => { + test('should reverse items split by symbol', () => { + const input = 'apple,banana,orange'; + const result = reverseList('symbol', ',', '\n', input); + expect(result).toBe('orange\nbanana\napple'); + }); + + test('should reverse items split by regex', () => { + const input = 'apple banana orange'; + const result = reverseList('regex', '\\s+', '\n', input); + expect(result).toBe('orange\nbanana\napple'); + }); + + test('should handle empty input', () => { + const input = ''; + const result = reverseList('symbol', ',', '\n', input); + expect(result).toBe(''); + }); + + test('should handle join separator', () => { + const input = 'apple,banana,orange'; + const result = reverseList('symbol', ',', ', ', input); + expect(result).toBe('orange, banana, apple'); + }); + }); \ No newline at end of file diff --git a/src/pages/list/reverse/service.ts b/src/pages/list/reverse/service.ts new file mode 100644 index 0000000..a172f53 --- /dev/null +++ b/src/pages/list/reverse/service.ts @@ -0,0 +1,21 @@ +type SplitOperatorType = 'symbol' | 'regex'; + +export function reverseList( + splitOperatorType: SplitOperatorType, + splitSeparator: string, + joinSeparator: string = '\n', + input: string, +): string { + let array: string[] = []; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)).filter(item => item !== ''); + break; + } + + const reversedList = array.reverse(); + return reversedList.join(joinSeparator); +} From 6ef2bd13566ca42acfeab1501db869f0a7d001e7 Mon Sep 17 00:00:00 2001 From: Chesterkxng Date: Mon, 8 Jul 2024 13:12:13 +0000 Subject: [PATCH 9/9] unwrap tool and testCases then updated index file --- src/pages/list/index.ts | 1 + src/pages/list/unwrap/index.tsx | 11 +++ src/pages/list/unwrap/meta.ts | 13 ++++ src/pages/list/unwrap/service.ts | 69 +++++++++++++++++++ src/pages/list/unwrap/unwrap.service.test.ts | 70 ++++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 src/pages/list/unwrap/index.tsx create mode 100644 src/pages/list/unwrap/meta.ts create mode 100644 src/pages/list/unwrap/service.ts create mode 100644 src/pages/list/unwrap/unwrap.service.test.ts diff --git a/src/pages/list/index.ts b/src/pages/list/index.ts index 17134e5..388e39c 100644 --- a/src/pages/list/index.ts +++ b/src/pages/list/index.ts @@ -1,3 +1,4 @@ +import { tool as listUnwrap } from './unwrap/meta'; import { tool as listReverse } from './reverse/meta'; import { tool as listFindUnique } from './find-unique/meta'; import { tool as listFindMostPopular } from './find-most-popular/meta'; diff --git a/src/pages/list/unwrap/index.tsx b/src/pages/list/unwrap/index.tsx new file mode 100644 index 0000000..43db753 --- /dev/null +++ b/src/pages/list/unwrap/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 Unwrap() { + return Lorem ipsum; +} \ No newline at end of file diff --git a/src/pages/list/unwrap/meta.ts b/src/pages/list/unwrap/meta.ts new file mode 100644 index 0000000..a65c5b5 --- /dev/null +++ b/src/pages/list/unwrap/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: 'Unwrap', + path: 'unwrap', + // image, + description: '', + shortDescription: '', + keywords: ['unwrap'], + component: lazy(() => import('./index')) +}); \ No newline at end of file diff --git a/src/pages/list/unwrap/service.ts b/src/pages/list/unwrap/service.ts new file mode 100644 index 0000000..d66a107 --- /dev/null +++ b/src/pages/list/unwrap/service.ts @@ -0,0 +1,69 @@ +export type SplitOperatorType = 'symbol' | 'regex'; + +function leftUnwrap( + row: string, + left: string = '', + multiLevel: boolean +): string { + if (left === '') return row; // Prevent infinite loop if left is an empty string + while (row.startsWith(left)) { + row = row.slice(left.length); + if (!multiLevel) { + break; + } + } + return row; +} + +function rightUnwrap( + row: string, + right: string = '', + multiLevel: boolean +): string { + if (right === '') return row; // Prevent infinite loop if right is an empty string + while (row.endsWith(right)) { + row = row.slice(0, row.length - right.length); + if (!multiLevel) { + break; + } + } + return row; +} + +export function unwrapList( + splitOperatorType: SplitOperatorType, + input: string, + splitSeparator: string, + joinSeparator: string, + deleteEmptyItems: boolean, + multiLevel: boolean, + trimItems: boolean, + left: string = '', + right: string = '' +): string { + let array: string[]; + let unwrappedArray: string[] = []; + switch (splitOperatorType) { + case 'symbol': + array = input.split(splitSeparator); + break; + case 'regex': + array = input.split(new RegExp(splitSeparator)); + break; + } + if (deleteEmptyItems) { + array = array.filter(Boolean); + } + + // for each element of array unwrap left side then right side and push the result to a final array + for (let row of array) { + row = leftUnwrap(row, left, multiLevel); + row = rightUnwrap(row, right, multiLevel); + unwrappedArray.push(row); + } + // trim items if needed + if (trimItems) { + unwrappedArray = unwrappedArray.map(item => item.trim()); + } + return unwrappedArray.join(joinSeparator); +} diff --git a/src/pages/list/unwrap/unwrap.service.test.ts b/src/pages/list/unwrap/unwrap.service.test.ts new file mode 100644 index 0000000..29e12c3 --- /dev/null +++ b/src/pages/list/unwrap/unwrap.service.test.ts @@ -0,0 +1,70 @@ +import { expect, describe, it } from 'vitest'; +import { unwrapList } from './service'; + +describe('unwrapList function', () => { + it('should unwrap elements correctly with symbol split', () => { + const input = "##Hello##\n##World##"; + const result = unwrapList('symbol', input, '\n', ' ', true, true, true, '#', '#'); + expect(result).toBe("Hello World"); + }); + + it('should unwrap elements correctly with regex split', () => { + const input = "##Hello##||##World##"; + const result = unwrapList('regex', input, '\\|\\|', ' ', true, true, true, '#', '#'); + expect(result).toBe("Hello World"); + }); + + it('should handle multiple levels of unwrapping', () => { + const input = "###Hello###"; + const result = unwrapList('symbol', input, '\n', ' ', true, true, true, '#', '#'); + expect(result).toBe("Hello"); + }); + + it('should handle single level of unwrapping', () => { + const input = "###Hello###"; + const result = unwrapList('symbol', input, '\n', ' ', true, false, true, '#', '#'); + expect(result).toBe("##Hello##"); + }); + + it('should delete empty items', () => { + const input = "##Hello##\n\n##World##"; + const result = unwrapList('symbol', input, '\n', ' ', true, true, true, '#', '#'); + expect(result).toBe("Hello World"); + }); + + it('should keep empty items if deleteEmptyItems is false', () => { + const input = "##Hello##\n\n##World##"; + const result = unwrapList('symbol', input, '\n', ' ', false, true, true, '#', '#'); + expect(result).toBe("Hello World"); + }); + + it('should trim items', () => { + const input = "## Hello ##\n## World ##"; + const result = unwrapList('symbol', input, '\n', ' ', true, true, true, '#', '#'); + expect(result).toBe("Hello World"); + }); + + it('should handle no left or right unwrapping', () => { + const input = "Hello\nWorld"; + const result = unwrapList('symbol', input, '\n', ' ', true, true, true); + expect(result).toBe("Hello World"); + }); + + it('should handle mixed levels of unwrapping', () => { + const input = "###Hello##\n#World###"; + const result = unwrapList('symbol', input, '\n', ' ', true, true, true, '#', '#'); + expect(result).toBe("Hello World"); + }); + + it('should handle complex regex split', () => { + const input = "##Hello##||###World###||####Test####"; + const result = unwrapList('regex', input, '\\|\\|', ' ', true, true, true, '#', '#'); + expect(result).toBe("Hello World Test"); + }); + + it('should handle different joinSeparator', () => { + const input = "##Hello##\n##World##"; + const result = unwrapList('symbol', input, '\n', '-', true, true, true, '#', '#'); + expect(result).toBe("Hello-World"); + }); +}); \ No newline at end of file