feat(string): add snakeCase, startCase, lowerCase, kebabCase in compat layer (#517)

* Add cases function

* Add benchmarks and re-export in index.ts

* Revert
This commit is contained in:
Dayong Lee 2024-09-13 16:43:07 +09:00 committed by GitHub
parent 7aad9d6b9a
commit 31769810b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 338 additions and 28 deletions

View File

@ -1,15 +1,30 @@
import { bench, describe } from 'vitest';
import { kebabCase as kebabCaseToolkit } from 'es-toolkit';
import { kebabCase as kebabCaseToolkitCompat } from 'es-toolkit/compat';
import { kebabCase as kebabCaseLodash } from 'lodash';
describe('kebabCase', () => {
bench('es-toolkit/kebabCase', () => {
const str = 'camelCase';
kebabCaseToolkit(str);
kebabCaseToolkit('hello world');
kebabCaseToolkit('--foo--bar__baz 123');
kebabCaseToolkit('123numericValues');
kebabCaseToolkit('XMLHttpRequest');
kebabCaseToolkit('hello-World_of XML_httpRequest');
});
bench('es-toolkit/comapt/kebabCase', () => {
kebabCaseToolkitCompat('hello world');
kebabCaseToolkitCompat('--foo--bar__baz 123');
kebabCaseToolkitCompat('123numericValues');
kebabCaseToolkitCompat('XMLHttpRequest');
kebabCaseToolkitCompat('hello-World_of XML_httpRequest');
});
bench('lodash/kebabCase', () => {
const str = 'camelCase';
kebabCaseLodash(str);
kebabCaseLodash('hello world');
kebabCaseLodash('--foo--bar__baz 123');
kebabCaseLodash('123numericValues');
kebabCaseLodash('XMLHttpRequest');
kebabCaseLodash('hello-World_of XML_httpRequest');
});
});

View File

@ -1,28 +1,36 @@
import { bench, describe } from 'vitest';
import { lowerCase as lowerCaseToolkit } from 'es-toolkit';
import { lowerCase as lowerCaseToolkitCompat } from 'es-toolkit/compat';
import { lowerCase as lowerCaseLodash } from 'lodash';
describe('lowerCase', () => {
describe('short string', () => {
bench('es-toolkit/lowerCase', () => {
const str = 'camelCase';
lowerCaseToolkit(str);
});
bench('lodash/lowerCase', () => {
const str = 'camelCase';
lowerCaseLodash(str);
});
describe('lowerCase - short string', () => {
bench('es-toolkit/lowerCase', () => {
const str = 'camelCase';
lowerCaseToolkit(str);
});
describe('long string', () => {
const LONG_STR = 'camelCaseLongString'.repeat(1000);
bench('es-toolkit/lowerCase', () => {
lowerCaseToolkit(LONG_STR);
});
bench('es-toolkit/compat/lowerCase', () => {
const str = 'camelCase';
lowerCaseToolkitCompat(str);
});
bench('lodash/lowerCase', () => {
lowerCaseLodash(LONG_STR);
});
bench('lodash/lowerCase', () => {
const str = 'camelCase';
lowerCaseLodash(str);
});
});
describe('lowerCase - long string', () => {
const LONG_STR = 'camelCaseLongString'.repeat(1000);
bench('es-toolkit/lowerCase', () => {
lowerCaseToolkit(LONG_STR);
});
bench('es-toolkit/compat/lowerCase', () => {
lowerCaseToolkitCompat(LONG_STR);
});
bench('lodash/lowerCase', () => {
lowerCaseLodash(LONG_STR);
});
});

View File

@ -1,15 +1,30 @@
import { bench, describe } from 'vitest';
import { snakeCase as snakeCaseToolkit } from 'es-toolkit';
import { snakeCase as snakeCaseToolkitCompat } from 'es-toolkit/compat';
import { snakeCase as snakeCaseLodash } from 'lodash';
describe('snakeCase', () => {
bench('es-toolkit/snakeCase', () => {
const str = 'camelCase';
snakeCaseToolkit(str);
snakeCaseToolkit('hello world');
snakeCaseToolkit('--foo--bar__baz 123');
snakeCaseToolkit('123numericValues');
snakeCaseToolkit('XMLHttpRequest');
snakeCaseToolkit('hello-World_of XML_httpRequest');
});
bench('es-toolkit/comapt/snakeCase', () => {
snakeCaseToolkitCompat('hello world');
snakeCaseToolkitCompat('--foo--bar__baz 123');
snakeCaseToolkitCompat('123numericValues');
snakeCaseToolkitCompat('XMLHttpRequest');
snakeCaseToolkitCompat('hello-World_of XML_httpRequest');
});
bench('lodash/snakeCase', () => {
const str = 'camelCase';
snakeCaseLodash(str);
snakeCaseLodash('hello world');
snakeCaseLodash('--foo--bar__baz 123');
snakeCaseLodash('123numericValues');
snakeCaseLodash('XMLHttpRequest');
snakeCaseLodash('hello-World_of XML_httpRequest');
});
});

View File

@ -1,4 +1,5 @@
import { startCase as startCaseToolkit } from 'es-toolkit';
import { startCase as startCaseToolkitCompat } from 'es-toolkit/compat';
import { startCase as startCaseLodash } from 'lodash';
import { bench, describe } from 'vitest';
@ -11,6 +12,14 @@ describe('startCase', () => {
startCaseToolkit('hello-World_of XML_httpRequest');
});
bench('es-toolkit/comapt/startCase', () => {
startCaseToolkitCompat('hello world');
startCaseToolkitCompat('--foo--bar__baz 123');
startCaseToolkitCompat('123numericValues');
startCaseToolkitCompat('XMLHttpRequest');
startCaseToolkitCompat('hello-World_of XML_httpRequest');
});
bench('lodash/startCase', () => {
startCaseLodash('hello world');
startCaseLodash('--foo--bar__baz 123');

View File

@ -83,6 +83,10 @@ export { conforms } from './predicate/conforms.ts';
export { conformsTo } from './predicate/conformsTo.ts';
export { camelCase } from './string/camelCase.ts';
export { kebabCase } from './string/kebabCase.ts';
export { snakeCase } from './string/snakeCase.ts';
export { startCase } from './string/startCase.ts';
export { lowerCase } from './string/lowerCase.ts';
export { startsWith } from './string/startsWith.ts';
export { endsWith } from './string/endsWith.ts';
export { padStart } from './string/padStart.ts';

View File

@ -0,0 +1,45 @@
import { describe, it, expect } from 'vitest';
import { kebabCase } from './kebabCase';
describe('kebabCase', () => {
const strings = ['foo bar', 'Foo bar', 'foo Bar', 'Foo Bar', 'FOO BAR', 'fooBar', '--foo-bar--', '__foo_bar__'];
it(`should convert \`string\``, () => {
const actual = strings.map(string => kebabCase(string));
const expected = actual.map(() => 'foo-bar');
expect(actual).toEqual(expected);
});
it(`should handle double-converting strings`, () => {
const actual = strings.map(string => kebabCase(kebabCase(string)));
const expected = actual.map(() => 'foo-bar');
expect(actual).toEqual(expected);
});
it(`should remove contraction apostrophes`, () => {
const postfixes = ['d', 'll', 'm', 're', 's', 't', 've'];
["'", '\u2019'].forEach(apos => {
const actual = postfixes.map(postfix => kebabCase(`a b${apos}${postfix} c`));
const expected = postfixes.map(postfix => `a-b${postfix}-c`);
expect(actual).toEqual(expected);
});
});
it(`should remove Latin mathematical operators`, () => {
const actual = ['\xd7', '\xf7'].map(kebabCase);
expect(actual).toEqual(['', '']);
});
it(`should coerce \`string\` to a string`, () => {
const string = 'foo bar';
expect(kebabCase(Object(string))).toBe('foo-bar');
expect(kebabCase({ toString: () => string })).toBe('foo-bar');
});
});

View File

@ -0,0 +1,20 @@
import { kebabCase as kebabCaseToolkit } from '../../string';
import { normalizeForCase } from '../_internal/normalizeForCase';
/**
* Converts a string to kebab case.
*
* Kebab case is the naming convention in which each word is written in lowercase and separated by a dash (-) character.
*
* @param {string} str - The string that is to be changed to kebab case.
* @returns {string} - The converted string to kebab case.
*
* @example
* const convertedStr1 = kebabCase('camelCase') // returns 'camel-case'
* const convertedStr2 = kebabCase('some whitespace') // returns 'some-whitespace'
* const convertedStr3 = kebabCase('hyphen-text') // returns 'hyphen-text'
* const convertedStr4 = kebabCase('HTTPRequest') // returns 'http-request'
*/
export function kebabCase(str: string | object): string {
return kebabCaseToolkit(normalizeForCase(str));
}

View File

@ -0,0 +1,45 @@
import { describe, it, expect } from 'vitest';
import { lowerCase } from './lowerCase';
describe('lowerCase', () => {
const strings = ['foo bar', 'Foo bar', 'foo Bar', 'Foo Bar', 'FOO BAR', 'fooBar', '--foo-bar--', '__foo_bar__'];
it(`should convert \`string\``, () => {
const actual = strings.map(string => lowerCase(string));
const expected = actual.map(() => 'foo bar');
expect(actual).toEqual(expected);
});
it(`should handle double-converting strings`, () => {
const actual = strings.map(string => lowerCase(lowerCase(string)));
const expected = actual.map(() => 'foo bar');
expect(actual).toEqual(expected);
});
it(`should remove contraction apostrophes`, () => {
const postfixes = ['d', 'll', 'm', 're', 's', 't', 've'];
["'", '\u2019'].forEach(apos => {
const actual = postfixes.map(postfix => lowerCase(`a b${apos}${postfix} c`));
const expected = postfixes.map(postfix => `a b${postfix} c`);
expect(actual).toEqual(expected);
});
});
it(`should remove Latin mathematical operators`, () => {
const actual = ['\xd7', '\xf7'].map(lowerCase);
expect(actual).toEqual(['', '']);
});
it(`should coerce \`string\` to a string`, () => {
const string = 'foo bar';
expect(lowerCase(Object(string))).toBe('foo bar');
expect(lowerCase({ toString: () => string })).toBe('foo bar');
});
});

View File

@ -0,0 +1,20 @@
import { lowerCase as lowerCaseToolkit } from '../../string/lowerCase';
import { normalizeForCase } from '../_internal/normalizeForCase';
/**
* Converts a string to lower case.
*
* Lower case is the naming convention in which each word is written in lowercase and separated by an space ( ) character.
*
* @param {string} str - The string that is to be changed to lower case.
* @returns {string} - The converted string to lower case.
*
* @example
* const convertedStr1 = lowerCase('camelCase') // returns 'camel case'
* const convertedStr2 = lowerCase('some whitespace') // returns 'some whitespace'
* const convertedStr3 = lowerCase('hyphen-text') // returns 'hyphen text'
* const convertedStr4 = lowerCase('HTTPRequest') // returns 'http request'
*/
export function lowerCase(str: string | object): string {
return lowerCaseToolkit(normalizeForCase(str));
}

View File

@ -0,0 +1,45 @@
import { describe, it, expect } from 'vitest';
import { snakeCase } from './snakeCase';
describe('snakeCase', () => {
const strings = ['foo bar', 'Foo bar', 'foo Bar', 'Foo Bar', 'FOO BAR', 'fooBar', '--foo-bar--', '__foo_bar__'];
it(`should convert \`string\``, () => {
const actual = strings.map(string => snakeCase(string));
const expected = actual.map(() => 'foo_bar');
expect(actual).toEqual(expected);
});
it(`should handle double-converting strings`, () => {
const actual = strings.map(string => snakeCase(snakeCase(string)));
const expected = actual.map(() => 'foo_bar');
expect(actual).toEqual(expected);
});
it(`should remove contraction apostrophes`, () => {
const postfixes = ['d', 'll', 'm', 're', 's', 't', 've'];
["'", '\u2019'].forEach(apos => {
const actual = postfixes.map(postfix => snakeCase(`a b${apos}${postfix} c`));
const expected = postfixes.map(postfix => `a_b${postfix}_c`);
expect(actual).toEqual(expected);
});
});
it(`should remove Latin mathematical operators`, () => {
const actual = ['\xd7', '\xf7'].map(snakeCase);
expect(actual).toEqual(['', '']);
});
it(`should coerce \`string\` to a string`, () => {
const string = 'foo bar';
expect(snakeCase(Object(string))).toBe('foo_bar');
expect(snakeCase({ toString: () => string })).toBe('foo_bar');
});
});

View File

@ -0,0 +1,20 @@
import { snakeCase as snakeCaseToolkit } from '../../string/snakeCase';
import { normalizeForCase } from '../_internal/normalizeForCase';
/**
* Converts a string to snake case.
*
* Snake case is the naming convention in which each word is written in lowercase and separated by an underscore (_) character.
*
* @param {string} str - The string that is to be changed to snake case.
* @returns {string} - The converted string to snake case.
*
* @example
* const convertedStr1 = snakeCase('camelCase') // returns 'camel_case'
* const convertedStr2 = snakeCase('some whitespace') // returns 'some_whitespace'
* const convertedStr3 = snakeCase('hyphen-text') // returns 'hyphen_text'
* const convertedStr4 = snakeCase('HTTPRequest') // returns 'http_request'
*/
export function snakeCase(str: string | object): string {
return snakeCaseToolkit(normalizeForCase(str));
}

View File

@ -0,0 +1,45 @@
import { describe, it, expect } from 'vitest';
import { startCase } from './startCase';
describe('case methods', () => {
const strings = ['foo bar', 'Foo bar', 'foo Bar', 'Foo Bar', 'FOO BAR', 'fooBar', '--foo-bar--', '__foo_bar__'];
it(`should convert \`string\``, () => {
const actual = strings.map(string => startCase(string));
const expected = actual.map(string => (string === 'FOO BAR' ? 'FOO BAR' : 'Foo Bar'));
expect(actual).toEqual(expected);
});
it(`should handle double-converting strings`, () => {
const actual = strings.map(string => startCase(startCase(string)));
const expected = actual.map(string => (string === 'FOO BAR' ? 'FOO BAR' : 'Foo Bar'));
expect(actual).toEqual(expected);
});
it(`should remove contraction apostrophes`, () => {
const postfixes = ['d', 'll', 'm', 're', 's', 't', 've'];
["'", '\u2019'].forEach(apos => {
const actual = postfixes.map(postfix => startCase(`a b${apos}${postfix} c`));
const expected = postfixes.map(postfix => `A B${postfix} C`);
expect(actual).toEqual(expected);
});
});
it(`should remove Latin mathematical operators`, () => {
const actual = ['\xd7', '\xf7'].map(startCase);
expect(actual).toEqual(['', '']);
});
it(`should coerce \`string\` to a string`, () => {
const string = 'foo bar';
expect(startCase(Object(string))).toBe('Foo Bar');
expect(startCase({ toString: () => string })).toBe('Foo Bar');
});
});

View File

@ -0,0 +1,19 @@
import { startCase as startCaseToolkit } from '../../string/startCase';
import { normalizeForCase } from '../_internal/normalizeForCase';
/**
* Converts the first character of each word in a string to uppercase and the remaining characters to lowercase.
*
* Start case is the naming convention in which each word is written with an initial capital letter.
* @param {string} str - The string to convert.
* @returns {string} The converted string.
*
* @example
* const result1 = startCase('hello world'); // result will be 'Hello World'
* const result2 = startCase('HELLO WORLD'); // result will be 'HELLO WORLD'
* const result3 = startCase('hello-world'); // result will be 'Hello World'
* const result4 = startCase('hello_world'); // result will be 'Hello World'
*/
export function startCase(str: string | object): string {
return startCaseToolkit(normalizeForCase(str));
}

View File

@ -9,7 +9,7 @@ import { getWords } from './_internal/getWords.ts';
*
* @example
* const result1 = startCase('hello world'); // result will be 'Hello World'
* const result2 = startCase('HELLO WORLD'); // result will be 'Hello World'
* const result2 = startCase('HELLO WORLD'); // result will be 'HELLO WORLD'
* const result3 = startCase('hello-world'); // result will be 'Hello World'
* const result4 = startCase('hello_world'); // result will be 'Hello World'
*/