Skip to content

Commit

Permalink
feat: add split by separator + order by numeric + no sort
Browse files Browse the repository at this point in the history
  • Loading branch information
sharevb committed Sep 22, 2024
1 parent 327ff11 commit cde70bc
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 72 deletions.
2 changes: 2 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ declare module '@vue/runtime-core' {
NCode: typeof import('naive-ui')['NCode']
NCollapseTransition: typeof import('naive-ui')['NCollapseTransition']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDivider: typeof import('naive-ui')['NDivider']
NEllipsis: typeof import('naive-ui')['NEllipsis']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
Expand All @@ -144,6 +145,7 @@ declare module '@vue/runtime-core' {
NMenu: typeof import('naive-ui')['NMenu']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSlider: typeof import('naive-ui')['NSlider']
NSpace: typeof import('naive-ui')['NSpace']
NSwitch: typeof import('naive-ui')['NSwitch']
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']
Expand Down
88 changes: 47 additions & 41 deletions src/tools/list-converter/list-converter.models.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,11 @@ describe('list-converter', () => {
describe('convert', () => {
it('should convert a given list', () => {
const options: ConvertOptions = {
separator: ', ',
itemsSeparator: ', ',
trimItems: true,
removeDuplicates: true,
itemPrefix: '"',
itemSuffix: '"',
removeItemPrefix: '',
removeItemSuffix: '',
listPrefix: '',
listSuffix: '',
reverseList: false,
sortList: null,
lowerCase: false,
keepLineBreaks: false,
};
const input = `
1
Expand All @@ -33,38 +25,21 @@ describe('list-converter', () => {

it('should return an empty value for an empty input', () => {
const options: ConvertOptions = {
separator: ', ',
itemsSeparator: ', ',
trimItems: true,
removeDuplicates: true,
itemPrefix: '',
itemSuffix: '',
removeItemPrefix: '',
removeItemSuffix: '',
listPrefix: '',
listSuffix: '',
reverseList: false,
sortList: null,
lowerCase: false,
keepLineBreaks: false,
};
expect(convert('', options)).toEqual('');
});

it('should keep line breaks', () => {
const options: ConvertOptions = {
separator: '',
trimItems: true,
itemPrefix: '<li>',
itemSuffix: '</li>',
removeItemPrefix: '',
removeItemSuffix: '',
listPrefix: '<ul>',
listSuffix: '</ul>',
keepLineBreaks: true,
lowerCase: false,
removeDuplicates: false,
reverseList: false,
sortList: null,
};
const input = `
1
Expand All @@ -81,30 +56,61 @@ describe('list-converter', () => {

it('should remove prefix and suffix', () => {
const options: ConvertOptions = {
separator: '',
trimItems: true,
itemPrefix: '',
itemSuffix: '',
removeItemPrefix: '\<li\>',
removeItemSuffix: '\</li\>',
listPrefix: '',
listSuffix: '',
removeItemPrefix: '<li>',
removeItemSuffix: '</li>',
keepLineBreaks: true,
lowerCase: false,
removeDuplicates: false,
reverseList: false,
sortList: null,
};
const input = `
<li>1</li>
<li>2</li>
<li>3</li>
`;
const expected = `
1
const expected = `1
2
3`;
expect(convert(input, options)).toEqual(expected);
});

it('should split by separator', () => {
const options: ConvertOptions = {
trimItems: true,
keepLineBreaks: true,
splitBySeparator: ',',
};
const input = '1,2,3';
const expected = `1
2
3`;
expect(convert(input, options)).toEqual(expected);
});

it('should sort by asc-num', () => {
const options: ConvertOptions = {
trimItems: true,
keepLineBreaks: true,
sortList: 'asc-num',
};
const input = `3
20
1`;
const expected = `1
3
`;
20`;
expect(convert(input, options)).toEqual(expected);
});
it('should sort by desc', () => {
const options: ConvertOptions = {
trimItems: true,
keepLineBreaks: true,
sortList: 'desc',
};
const input = `1
20
3`;
const expected = `3
20
1`;
expect(convert(input, options)).toEqual(expected);
});
});
Expand Down
12 changes: 6 additions & 6 deletions src/tools/list-converter/list-converter.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { byOrder } from '@/utils/array';

export { convert };

function whenever<T, R>(condition: boolean, fn: (value: T) => R) {
function whenever<T, R>(condition: boolean | undefined, fn: (value: T) => R) {
return (value: T) =>
condition ? fn(value) : value;
}
Expand All @@ -14,16 +14,16 @@ function convert(list: string, options: ConvertOptions): string {

return _.chain(list)
.thru(whenever(options.lowerCase, text => text.toLowerCase()))
.split('\n')
.split(new RegExp(`[${options.splitBySeparator || ''}\n]`, 'g'))
.thru(whenever(options.removeDuplicates, _.uniq))
.thru(whenever(options.reverseList, _.reverse))
.thru(whenever(!_.isNull(options.sortList), parts => parts.sort(byOrder({ order: options.sortList }))))
.map(whenever(options.trimItems, _.trim))
.thru(whenever(!!options.sortList, parts => parts.sort(byOrder({ order: options.sortList }))))
.without('')
.map(p => options.removeItemPrefix ? p.replace(new RegExp(`^${options.removeItemPrefix}`, 'g'), '') : p)
.map(p => options.removeItemSuffix ? p.replace(new RegExp(`${options.removeItemSuffix}$`, 'g'), '') : p)
.map(p => options.itemPrefix + p + options.itemSuffix)
.join(options.separator + lineBreak)
.thru(text => [options.listPrefix, text, options.listSuffix].join(lineBreak))
.map(p => (options.itemPrefix || '') + p + (options.itemSuffix || ''))
.join((options.itemsSeparator || '') + lineBreak)
.thru(text => [options.listPrefix, text, options.listSuffix].filter(l => l).join(lineBreak))
.value();
}
29 changes: 15 additions & 14 deletions src/tools/list-converter/list-converter.types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
export type SortOrder = 'asc' | 'desc' | null;
export type SortOrder = null | 'asc' | 'desc' | 'asc-num' | 'desc-num' | 'asc-bin' | 'desc-bin' | 'asc-upper' | 'desc-upper';

export interface ConvertOptions {
lowerCase: boolean
trimItems: boolean
itemPrefix: string
itemSuffix: string
removeItemPrefix: string
removeItemSuffix: string
listPrefix: string
listSuffix: string
reverseList: boolean
sortList: SortOrder
removeDuplicates: boolean
separator: string
keepLineBreaks: boolean
lowerCase?: boolean
trimItems?: boolean
itemPrefix?: string
itemSuffix?: string
removeItemPrefix?: string
removeItemSuffix?: string
listPrefix?: string
listSuffix?: string
reverseList?: boolean
sortList?: SortOrder
removeDuplicates?: boolean
itemsSeparator?: string
splitBySeparator?: string
keepLineBreaks?: boolean
}
55 changes: 46 additions & 9 deletions src/tools/list-converter/list-converter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,41 @@ import { convert } from './list-converter.models';
import type { ConvertOptions } from './list-converter.types';
const sortOrderOptions = [
{
label: 'No Sort',
value: null,
},
{
label: 'Sort ascending',
value: 'asc',
disabled: false,
},
{
label: 'Sort descending',
value: 'desc',
disabled: false,
},
{
label: 'Sort asc (Numeric)',
value: 'asc-num',
},
{
label: 'Sort desc (Numeric)',
value: 'desc-num',
},
{
label: 'Sort asc (Upper)',
value: 'asc-upper',
},
{
label: 'Sort desc (Upper)',
value: 'desc-upper',
},
{
label: 'Sort asc (Binary)',
value: 'asc-bin',
},
{
label: 'Sort desc (Binary)',
value: 'desc-bin',
},
];
Expand All @@ -29,7 +55,8 @@ const conversionConfig = useStorage<ConvertOptions>('list-converter:conversionCo
listSuffix: '',
reverseList: false,
sortList: null,
separator: ', ',
itemsSeparator: ', ',
splitBySeparator: '',
});
function transformer(value: string) {
Expand All @@ -41,7 +68,7 @@ function transformer(value: string) {
<div style="flex: 0 0 100%">
<div style="margin: 0 auto; max-width: 600px">
<c-card>
<div flex>
<n-space>
<div>
<n-form-item label="Trim list items" label-placement="left" label-width="150" :show-feedback="false" mb-2>
<n-switch v-model:value="conversionConfig.trimItems" />
Expand All @@ -62,7 +89,7 @@ function transformer(value: string) {
<n-switch v-model:value="conversionConfig.keepLineBreaks" />
</n-form-item>
</div>
<div flex-1>
<div>
<c-select
v-model:value="conversionConfig.sortList"
label="Sort list"
Expand All @@ -78,13 +105,23 @@ function transformer(value: string) {
/>

<c-input-text
v-model:value="conversionConfig.separator"
label="Separator"
v-model:value="conversionConfig.itemsSeparator"
label="Items Separator"
label-position="left"
label-width="120px"
label-align="right"
mb-2
placeholder="Items separator"
/>

<c-input-text
v-model:value="conversionConfig.splitBySeparator"
label="Split Separator"
label-position="left"
label-width="120px"
label-align="right"
mb-2
placeholder=","
placeholder="Separator for splitting"
/>

<n-form-item label="Unwrap item" label-placement="left" label-width="120" :show-feedback="false" mb-2>
Expand Down Expand Up @@ -125,7 +162,7 @@ function transformer(value: string) {
/>
</n-form-item>
</div>
</div>
</n-space>
</c-card>
</div>
</div>
Expand Down
25 changes: 25 additions & 0 deletions src/utils/array.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { describe, expect, it } from 'vitest';
import { type SortOrder, byOrder } from './array';

describe('array utils', () => {
describe('byOrder', () => {
it('should sort correctly', () => {
const sortBy = (array: string[], order: SortOrder) => {
return array.sort(byOrder({ order }));
};

const strings = ['a', 'A', 'b', 'B', 'á', '1', '2', '10', '一', '阿'];

expect(sortBy(strings, null)).to.eql(strings);
expect(sortBy(strings, undefined)).to.eql(strings);
expect(sortBy(strings, 'asc')).to.eql(['1', '10', '2', 'a', 'A', 'á', 'b', 'B', '一', '阿']);
expect(sortBy(strings, 'asc-num')).to.eql(['1', '2', '10', 'a', 'A', 'á', 'b', 'B', '一', '阿']);
expect(sortBy(strings, 'asc-bin')).to.eql(['1', '10', '2', 'A', 'B', 'a', 'b', 'á', '一', '阿']);
expect(sortBy(strings, 'asc-upper')).to.eql(['1', '10', '2', 'A', 'a', 'á', 'B', 'b', '一', '阿']);
expect(sortBy(strings, 'desc')).to.eql(['阿', '一', 'B', 'b', 'á', 'A', 'a', '2', '10', '1']);
expect(sortBy(strings, 'desc-num')).to.eql(['阿', '一', 'B', 'b', 'á', 'A', 'a', '10', '2', '1']);
expect(sortBy(strings, 'desc-bin')).to.eql(['阿', '一', 'á', 'b', 'a', 'B', 'A', '2', '10', '1']);
expect(sortBy(strings, 'desc-upper')).to.eql(['阿', '一', 'b', 'B', 'á', 'a', 'A', '2', '10', '1']);
});
});
});
27 changes: 25 additions & 2 deletions src/utils/array.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
export { byOrder };
export type SortOrder = 'asc' | 'desc' | 'asc-num' | 'desc-num' | 'asc-bin' | 'desc-bin' | 'asc-upper' | 'desc-upper' | null | undefined;

export function byOrder({ order }: { order: SortOrder }) {
if (order === 'asc-bin' || order === 'desc-bin') {
return (a: string, b: string) => {
const compare = a > b ? 1 : a < b ? -1 : 0;
return order === 'asc-bin' ? compare : -compare;
};
}
if (order === 'asc-num' || order === 'desc-num') {
return (a: string, b: string) => {
const compare = a.localeCompare(b, undefined, {
numeric: true,
});
return order === 'asc-num' ? compare : -compare;
};
}
if (order === 'asc-upper' || order === 'desc-upper') {
return (a: string, b: string) => {
const compare = a.localeCompare(b, undefined, {
caseFirst: 'upper',
});
return order === 'asc-upper' ? compare : -compare;
};
}

function byOrder({ order }: { order: 'asc' | 'desc' | null | undefined }) {
return (a: string, b: string) => {
return order === 'asc' ? a.localeCompare(b) : b.localeCompare(a);
};
Expand Down

0 comments on commit cde70bc

Please sign in to comment.