Skip to content

Commit

Permalink
feat(transforms): add toCamel function to transform strings to came…
Browse files Browse the repository at this point in the history
…l case

Unlike the lodash `camelCase` function, this version will (by default anyway) retain the casing of acronyms in the output camel-case string.
  • Loading branch information
cahilfoley committed Nov 16, 2019
1 parent 2d1c7dd commit 7b3e680
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/transforms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export { default as camelToTitle } from './camelToTitle'
export { default as capitalize } from './capitalize'
export { default as getAcronym } from './getAcronym'
export { default as normalizeURL } from './normalizeURL'
export { default as toCamel } from './toCamel'
export { default as toProperList } from './toProperList'
27 changes: 27 additions & 0 deletions src/transforms/toCamel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import batchTest from '../tests/batchTest'
import toCamel from './toCamel'

const batch = (cases: any[][]) => {
batchTest(toCamel, cases, { verb: 'toContain' })
}

describe('String to Camel Case (toCamel)', () => {
test('Always lower cases the first word', () => {
batch([['To Camel', 'toCamel'], ['hello', 'hello'], ['InOut', 'inOut'], ['FOO_BAR', 'fooBar']])
})

test('Maintains acronyms if lower case letters are present', () => {
batch([['User ID', 'userID'], ['Current KPI Status', 'currentKPIStatus']])
})

test('Does not maintain acronyms if the input contains no lower case letters', () => {
batch([['USER ID', 'userId'], ['CURRENT KPI STATUS', 'currentKpiStatus']])
})

test('Does not maintain acronyms if "keepAcronyms" is false', () => {
batch([
[['User ID', { keepAcronyms: false }], 'userId'],
[['Current KPI Status', { keepAcronyms: false }], 'currentKpiStatus'],
])
})
})
66 changes: 66 additions & 0 deletions src/transforms/toCamel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @module transforms
*/

import splitCamelCase from '../internal/patterns/splitCamelCase'

/**
* A really basic pascal case implementation, only works for single words.
* @ignore
*/
function pascalCase(input: string): string {
const [firstLetter, ...rest] = input.split('')
return [firstLetter.toUpperCase(), ...rest.map(letter => letter.toLowerCase())].join('')
}

export interface ToCamelOptions {
keepAcronyms?: boolean
}

/**
*
* Transforms the provided string into camel-case.
*
* If the string contains a combination of upper and lower-case letters then the method
* will retain the capitalization of acronyms. This behaviour can be explicitly toggled
* on or off with the `keepAcronyms` option.
*
* @param input The string to be converted
* @return Returns the camel-case string
*
* @example
* ```typescript
*
* toCamel('ILoveCamels') // => 'iLoveCamels'
* toCamel('User ID') // => 'userID'
* ```
*
*/
export default function toCamel(input: string): string
export default function toCamel(input: string, options: ToCamelOptions): string
export default function toCamel(input: string, { keepAcronyms }: ToCamelOptions = {}): string {
// Split the string into the separate parts
const parts: string[] = (input + ' ').match(splitCamelCase)

// If `keepAcronyms` is not specified then default to true if there are any lower case characters
const shouldKeepAcronyms = keepAcronyms !== undefined ? keepAcronyms : /[a-z]/.test(input)

// Transform each part of the string
const newParts: string[] = parts.map((part, index) => {
// Always lower-case the first words
if (index === 0) {
return part.toLowerCase()
}

// If we are keeping acronyms and the part only contains capital letters, leave it as is
if (shouldKeepAcronyms && /^[A-Z]+$/.test(part)) {
return part
}

// Otherwise, all other parts are changed to pascal case
return pascalCase(part)
})

// Return the parts concatenated together
return newParts.join('')
}

0 comments on commit 7b3e680

Please # to comment.