Skip to content

Commit

Permalink
feat: port more string functions from lodash
Browse files Browse the repository at this point in the history
Added `camelCaseName`, `kebabCaseName`, `snakeCaseName` and `upperFirst`.
  • Loading branch information
alexkvak committed Jun 4, 2021
1 parent 81763cd commit 441fe09
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -4,7 +4,7 @@
"author": "Tinkoff team",
"scripts": {
"release": "node ./releaseUtils/index.js",
"benchmark": "ts-node --skip-project runBenchmark.ts",
"benchmark": "ts-node --project tsconfig.benchmark.json runBenchmark.ts",
"prebenchmark": "npm install --no-save ts-node lodash ramda lazy.js underscore",
"docs": "node ./generate/docs/index.js",
"test": "jest --coverage",
Expand Down
14 changes: 14 additions & 0 deletions src/string/__benchmarks__/camelCaseName.ts
@@ -0,0 +1,14 @@
import camelCaseName from '../camelCaseName';

const camelCaseLodash = require('lodash/camelCase');

const testStr = 'very-log-foo-bar-string';

export default {
lodash: () => {
camelCaseLodash(testStr);
},
utils: () => {
camelCaseName(testStr);
},
};
14 changes: 14 additions & 0 deletions src/string/__benchmarks__/kebabCaseName.ts
@@ -0,0 +1,14 @@
import kebabCaseName from '../kebabCaseName';

const kebabCaseLodash = require('lodash/kebabCase');

const testStr = 'VeryLogFooBarString';

export default {
lodash: () => {
kebabCaseLodash(testStr);
},
utils: () => {
kebabCaseName(testStr);
},
};
14 changes: 14 additions & 0 deletions src/string/__benchmarks__/snakeCaseName.ts
@@ -0,0 +1,14 @@
import snakeCaseName from '../snakeCaseName';

const snakeCaseLodash = require('lodash/snakeCase');

const testStr = 'VeryLogFooBarString';

export default {
lodash: () => {
snakeCaseLodash(testStr);
},
utils: () => {
snakeCaseName(testStr);
},
};
13 changes: 13 additions & 0 deletions src/string/__benchmarks__/upperFirst.ts
@@ -0,0 +1,13 @@
const upperFirstLodash = require('lodash/upperFirst');
import upperFirst from '../upperFirst';

const testStr = 'very-log-foo-bar-string';

export default {
lodash: () => {
upperFirstLodash(testStr);
},
utils: () => {
upperFirst(testStr);
},
};
15 changes: 15 additions & 0 deletions src/string/__tests__/camelCaseName.ts
@@ -0,0 +1,15 @@
import camelCaseName from '../camelCaseName';

describe('utils/string/camelCaseName', () => {
it.each([
['', ''],
['abc', 'abc'],
['Foo Bar', 'fooBar'],
['foo-bar', 'fooBar'],
['foo_bar', 'fooBar'],
['FOO_BAR', 'fooBar'],
['Foo Bär', 'fooBR'],
])('should return camel cased string for %s: %s', (str, expected) => {
expect(camelCaseName(str)).toEqual(expected);
});
});
15 changes: 15 additions & 0 deletions src/string/__tests__/kebabCaseName.ts
@@ -0,0 +1,15 @@
import kebabCaseName from '../kebabCaseName';

describe('utils/string/kebabCaseName', () => {
it.each([
['', ''],
['abc', 'abc'],
['Foo Bar', 'foo-bar'],
['fooBar', 'foo-bar'],
['foo_Bar', 'foo-bar'],
['FOO_BAR', 'foo-bar'],
['Foo Bär', 'foo-b-r'],
])('should return kebab cased string for %s: %s', (str, expected) => {
expect(kebabCaseName(str)).toEqual(expected);
});
});
16 changes: 16 additions & 0 deletions src/string/__tests__/snakeCaseName.ts
@@ -0,0 +1,16 @@
import snakeCaseName from '../snakeCaseName';

describe('utils/string/snakeCaseName', () => {
it.each([
['', ''],
['abc', 'abc'],
['Foo Bar', 'foo_bar'],
['fooBar', 'foo_bar'],
['foo_Bar', 'foo_bar'],
['foo-Bar', 'foo_bar'],
['FOO_BAR', 'foo_bar'],
['Foo Bär', 'foo_b_r'],
])('should return snake cased string for %s: %s', (str, expected) => {
expect(snakeCaseName(str)).toEqual(expected);
});
});
12 changes: 12 additions & 0 deletions src/string/__tests__/upperFirst.ts
@@ -0,0 +1,12 @@
import upperFirst from '../upperFirst';

describe('utils/string/upperFirst', () => {
it.each([
['', ''],
['foo', 'Foo'],
['FOO', 'FOO'],
['über', 'Über'],
])('should convert the first character of string to upper case for %s: %s', (str, expected) => {
expect(upperFirst(str)).toEqual(expected);
});
});
21 changes: 21 additions & 0 deletions src/string/camelCaseName.ts
@@ -0,0 +1,21 @@
/**
* Converts string to camel case.
*
* This function convert only latin chars.
* The preferred purpose is to generate file or class names in your code generation tools.
*
* @param {String} str The string to convert.
* @return {String} The camel cased string.
* @example
*
* camelCase('Foo Bar'); //=> 'fooBar'
* camelCase('foo-bar'); //=> 'fooBar'
* camelCase('foo_bar'); //=> 'fooBar'
* camelCase('FOO_BAR'); //=> 'fooBar'
* camelCase('Foo Bär'); //=> 'fooBR' only latin chars are supported
*/
const nonLettersRegex = /[^a-zA-Z]+(.)/g;

export default function camelCaseName(str: string): string {
return str.toLowerCase().replace(nonLettersRegex, (match, chr) => chr.toUpperCase());
}
25 changes: 25 additions & 0 deletions src/string/kebabCaseName.ts
@@ -0,0 +1,25 @@
const camelCaseRegex = /(([a-z])([A-Z])|[^a-zA-Z])/g;

/**
* Converts string to kebab case.
*
* This function convert only latin chars.
* The preferred purpose is to generate file or class names in your code generation tools.
*
* @param {String} str The string to convert.
* @return {String} The kebab cased string.
* @example
*
* kebabCase('Foo Bar'); //=> 'foo-bar'
* kebabCase('fooBar'); //=> 'foo-bar'
* kebabCase('foo_bar'); //=> 'foo-bar'
* kebabCase('FOO_BAR'); //=> 'foo-bar'
* kebabCase('Foo Bär'); //=> 'foo-b-r' — only latin chars are supported
*/
export default function kebabCaseName(str: string): string {
return str
.replace(camelCaseRegex, (match, _, first?: string, second?: string) =>
first !== undefined && second !== undefined ? `${first}-${second}` : '-'
)
.toLowerCase();
}
29 changes: 29 additions & 0 deletions src/string/snakeCaseName.ts
@@ -0,0 +1,29 @@
const camelCaseRegex = /([a-z])([A-Z])/g;
const nonLettersRegex = /[^a-zA-Z]/g;

/**
* Returns the snake case version of a string.
*
* This function convert only latin chars.
* The preferred purpose is to generate file or class names in your code generation tools.
*
* @param {String} str The string to switch to snake case.
* @return {String} The snake case version of `str`.
* @example
*
* snakeCaseName('Foo Bar'); //=> 'foo_bar'
* snakeCaseName('fooBar'); //=> 'foo_bar'
* snakeCaseName('foo-bar'); //=> 'foo_bar'
* snakeCaseName('FOO-BAR'); //=> 'foo_bar'
* snakeCaseName('Foo Bär'); //=> 'foo_b_r' only latin chars are supported
*/
export default function snakeCaseName(str: string): string {
return (
str
// handle camelCase
.replace(camelCaseRegex, (match, first, second) => `${first}-${second}`)
// replace non-letters with underscore
.replace(nonLettersRegex, '_')
.toLowerCase()
);
}
16 changes: 16 additions & 0 deletions src/string/upperFirst.ts
@@ -0,0 +1,16 @@
/**
* Converts the first character of string to upper case and returns the new string.
*
* @param {String} str The string to convert.
* @return {String} The converted string.
* @example
*
* upperFirst('foo'); //=> 'Foo'
* upperFirst('über'); //=> 'Über'
* upperFirst('FOO'); //=> 'FOO'
*/
function upperFirst(str: string): string {
return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
}

export default upperFirst;
11 changes: 11 additions & 0 deletions tsconfig.benchmark.json
@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"declaration": false
},
"include": [
"src/**/*",
],
"exclude": []
}

0 comments on commit 441fe09

Please sign in to comment.