Skip to content

Commit

Permalink
v1.0.0 - Rework handling of spaced strings 🧬
Browse files Browse the repository at this point in the history
  • Loading branch information
mesqueeb committed Jan 27, 2020
1 parent 937d46e commit ef7564e
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 192 deletions.
121 changes: 50 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,45 +24,35 @@ I wanted to try my hand at the smallest iteration possible.

## Usage

case-anything supports tree-shaking.
case-anything supports tree-shaking and is side-effect free!

```js
import { camelCase, pascalCase, kebabCase, snakeCase, constantCase } from 'case-anything'

const testString = 'PonytaVaporeon_poliwrath-BUTTERFREE'
// or any variant on this

camelCase(testString)
=== 'ponytaVaporeonPoliwrathButterfree'
camelCase(testString) === 'ponytaVaporeonPoliwrathButterfree'

pascalCase(testString)
=== 'PonytaVaporeonPoliwrathButterfree'
pascalCase(testString) === 'PonytaVaporeonPoliwrathButterfree'

kebabCase(testString)
=== 'ponyta-vaporeon-poliwrath-butterfree'
kebabCase(testString) === 'ponyta-vaporeon-poliwrath-butterfree'

snakeCase(testString)
=== 'ponyta_vaporeon_poliwrath_butterfree'
snakeCase(testString) === 'ponyta_vaporeon_poliwrath_butterfree'

constantCase(testString)
=== 'PONYTA_VAPOREON_POLIWRATH_BUTTERFREE'

pathCase(testString)
=== 'Ponyta/Vaporeon/Poliwrath/BUTTERFREE'
constantCase(testString) === 'PONYTA_VAPOREON_POLIWRATH_BUTTERFREE'
```

There is also `spaceCase` and `pathCase`, which does not convert the casing:
There is also `spaceCase` and `pathCase`, which does **not convert the casing**:

```js
import { spaceCase, pathCase } from 'case-anything'

const testString = 'PonytaVaporeon_poliwrath-BUTTERFREE'

spaceCase(testString)
=== 'Ponyta Vaporeon poliwrath BUTTERFREE'
spaceCase(testString) === 'Ponyta Vaporeon poliwrath BUTTERFREE'

pathCase(testString)
=== 'Ponyta/Vaporeon/poliwrath/BUTTERFREE'
pathCase(testString) === 'Ponyta/Vaporeon/poliwrath/BUTTERFREE'
```

There is also upper, lower and capital case. These will all convert the casing & also add spaces in between:
Expand All @@ -72,77 +62,66 @@ import { upperCase, lowerCase, capitalCase } from 'case-anything'

const testString = 'PonytaVaporeon_poliwrath-BUTTERFREE'

upperCase(testString)
=== 'PONYTA VAPOREON POLIWRATH BUTTERFREE'
lowerCase(testString)
=== 'ponyta vaporeon poliwrath butterfree'
capitalCase(testString)
=== 'Ponyta Vaporeon Poliwrath Butterfree'
upperCase(testString) === 'PONYTA VAPOREON POLIWRATH BUTTERFREE'
lowerCase(testString) === 'ponyta vaporeon poliwrath butterfree'
capitalCase(testString) === 'Ponyta Vaporeon Poliwrath Butterfree'
```

### Custom split function

The split function used in case-anything will remove any special characters (besides numbers) as well. If however, you require a different split function, you can provide one yourself as second parameter.
### When spaces are involved

This is possible for the `capitalCase`, `pascalCase` or `camelCase`.
As soon as there is a space in the target string, it will regard the input as a "sentence" and only split each part at the spaces.

One use case example is when working with sentences. Eg. you want the capital case of this sentence: `listen I'm O.K.!`. Let's see how this can be done:
See this example to understand each case:

<!-- prettier-ignore-start -->
```js
const testString = "listen I'M O.K.!"
const testString = "listen I'm O.K.!"

// splits on spaces & removes special characters
camelCase(listenImOK) === 'listenImOk'
pascalCase(listenImOK) === 'ListenImOk'
kebabCase(listenImOK) === 'listen-im-ok'
snakeCase(listenImOK) === 'listen_im_ok'
constantCase(listenImOK) === 'LISTEN_IM_OK'

// splits on spaces & keeps special characters
spaceCase(listenImOK) === "listen I'm O.K.!"
pathCase(listenImOK) === "listen/I'm/O.K.!"
lowerCase(listenImOK) === "listen i'm o.k.!"
upperCase(listenImOK) === "LISTEN I'M O.K.!"
capitalCase(listenImOK) === "Listen I'm O.k.!"
```
<!-- prettier-ignore-end -->

// capitalCase expected behaviour:
capitalCase(testString)
=== 'Listen I M O K'
### When special alphabet is involved

// capitalCase with own split function:
capitalCase(testString, s => s.split(' '))
=== "Listen I'm O.k.!"
```
Currently what keeps the package small is the fact that I use a simple regex to find all the parts in a string:

The reason this is only possible for three functions is because the logic behind the other functions is simple enough to implement yourself. Eg.:
- `/^[a-z]+|[A-Z][a-z]+|[a-z]+|[0-9]+|[A-Z]+(?![a-z])/g`

```js
// snakeCase with own split function:
testString.split(' ').join('_').toLowerCase()
=== "listen_i'm_o.k.!"
```
That means that alphabet letters like é, ç, ü, ī and many others aren't compatible.

If there is a simple way to include these via unicode ranges in the regex, please feel free to open a PR or issue!

## Package size

We'll compare this package with [blakeembrey/change-case](https://github.com/blakeembrey/change-case), a very famous package on npm.

| | case-anything | change-case |
| --- | --- | --- |
| camelCase | 1.1K (572) | 27.2K (6K) |
| pascalCase | 1.1K (561) | 27.4K (6.1K) |
| kebabCase | 1.1K (541) | 26.8K (5.9K) |
| snakeCase | 1.1K (540) | 26.8K (5.9K) |
| constantCase | 1.1K (540) | 27.2K (6K) |
| pathCase | 1K (530) | 26.8K (5.9K) |
| | case-anything | change-case |
| ------------ | ------------- | ------------ |
| camelCase | 1.1K (572) | 27.2K (6K) |
| pascalCase | 1.1K (561) | 27.4K (6.1K) |
| kebabCase | 1.1K (541) | 26.8K (5.9K) |
| snakeCase | 1.1K (540) | 26.8K (5.9K) |
| constantCase | 1.1K (540) | 27.2K (6K) |
| pathCase | 1K (530) | 26.8K (5.9K) |

## Source code

It is literally just this code:
What keeps my package small, is that it's literally just a regex:

```js
function getParts (string) {
return string.match(/^[a-z]+|[A-Z][a-z]+|[A-Z]+|[a-z]+/g)
}

export function camelCase (string) {
return getParts(string)
.reduce((result, match, index) => {
return (index === 0)
? match.toLowerCase()
: result + match[0].toUpperCase() + match.slice(1).toLowerCase()
}, '')
export function splitOnSpecialChars (string: string): any[] {
return string.match(/^[a-z]+|[A-Z][a-z]+|[a-z]+|[0-9]+|[A-Z]+(?![a-z])/g)
}

export function kebabCase (string) {
return getParts(string)
.join('-').toLowerCase()
}

// etc...
```
66 changes: 36 additions & 30 deletions dist/index.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@ Object.defineProperty(exports, '__esModule', { value: true });
* @param {string} string
* @returns {string[]}
*/
function getParts(string) {
function splitOnSpecialChars(string) {
return string.match(/^[a-z]+|[A-Z][a-z]+|[a-z]+|[0-9]+|[A-Z]+(?![a-z])/g);
}
/**
* A string.match function that will return an array of "string parts"
*
* @param {string} string
* @returns {string[]}
*/
function getParts(string, noSpecialChars) {
if (noSpecialChars === void 0) { noSpecialChars = false; }
var target = string.trim();
var parts = target.includes(' ') ? target.split(' ') : splitOnSpecialChars(target);
return noSpecialChars ? parts.map(function (part) { return part.replace(/[^a-zA-Z0-9]/g, ''); }) : parts;
}
/**
* Capitalises a single word
*
Expand All @@ -22,35 +34,28 @@ function capitaliseWord(string) {
return string[0].toUpperCase() + string.slice(1).toLowerCase();
}

var noSpecialChars = true;
/**
* converts strings to camelCase
*
* @export
* @param {string} string
* @param {function} [splitFn=getParts] the function to split the string. Defaults to `getParts`
* @returns {string} in camelCase
*/
function camelCase(string, splitFn) {
if (splitFn === void 0) { splitFn = getParts; }
return splitFn(string)
.reduce(function (result, match, index) {
return (index === 0)
? match.toLowerCase()
: result + capitaliseWord(match);
function camelCase(string) {
return getParts(string, noSpecialChars).reduce(function (result, match, index) {
return index === 0 ? match.toLowerCase() : result + capitaliseWord(match);
}, '');
}
/**
* converts strings to PascalCase
*
* @export
* @param {string} string
* @param {function} [splitFn=getParts] the function to split the string. Defaults to `getParts`
* @returns {string} in PascalCase
*/
function pascalCase(string, splitFn) {
if (splitFn === void 0) { splitFn = getParts; }
return splitFn(string)
.reduce(function (result, match) {
function pascalCase(string) {
return getParts(string, noSpecialChars).reduce(function (result, match) {
return result + capitaliseWord(match);
}, '');
}
Expand All @@ -62,8 +67,9 @@ function pascalCase(string, splitFn) {
* @returns {string} in kebab-case
*/
function kebabCase(string) {
return getParts(string)
.join('-').toLowerCase();
return getParts(string, noSpecialChars)
.join('-')
.toLowerCase();
}
/**
* converts strings to snake_case
Expand All @@ -73,8 +79,9 @@ function kebabCase(string) {
* @returns {string} in snake_case
*/
function snakeCase(string) {
return getParts(string)
.join('_').toLowerCase();
return getParts(string, noSpecialChars)
.join('_')
.toLowerCase();
}
/**
* converts strings to CONSTANT_CASE
Expand All @@ -84,8 +91,9 @@ function snakeCase(string) {
* @returns {string} in CONSTANT_CASE
*/
function constantCase(string) {
return getParts(string)
.join('_').toUpperCase();
return getParts(string, noSpecialChars)
.join('_')
.toUpperCase();
}
/**
* converts strings to path/case
Expand All @@ -95,8 +103,7 @@ function constantCase(string) {
* @returns {string} in path/case
*/
function pathCase(string) {
return getParts(string)
.join('/');
return getParts(string).join('/');
}
/**
* converts strings to space case (will add spaces but not change casing)
Expand All @@ -106,20 +113,17 @@ function pathCase(string) {
* @returns {string} in path case
*/
function spaceCase(string) {
return getParts(string)
.join(' ');
return getParts(string).join(' ');
}
/**
* converts strings to Capital Case (with spaces)
*
* @export
* @param {string} string
* @param {function} [splitFn=getParts] the function to split the string. Defaults to `getParts`
* @returns {string} in Capital Case (with spaces)
*/
function capitalCase(string, splitFn) {
if (splitFn === void 0) { splitFn = getParts; }
return splitFn(string)
function capitalCase(string) {
return getParts(string)
.reduce(function (result, match) {
return result + " " + capitaliseWord(match);
}, '')
Expand All @@ -134,7 +138,8 @@ function capitalCase(string, splitFn) {
*/
function lowerCase(string) {
return getParts(string)
.join(' ').toLowerCase();
.join(' ')
.toLowerCase();
}
/**
* converts strings to UPPER CASE (with spaces)
Expand All @@ -145,7 +150,8 @@ function lowerCase(string) {
*/
function upperCase(string) {
return getParts(string)
.join(' ').toUpperCase();
.join(' ')
.toUpperCase();
}

exports.camelCase = camelCase;
Expand Down
Loading

0 comments on commit ef7564e

Please sign in to comment.