diff --git a/packages/change-case/README.md b/packages/change-case/README.md index 3172a3ba..e75c2bea 100644 --- a/packages/change-case/README.md +++ b/packages/change-case/README.md @@ -37,9 +37,11 @@ All methods accept an `options` object as the second argument: - `delimiter?: string` The character to use between words. Default depends on method, e.g. `_` in snake case. - `locale?: string[] | string | false` Lower/upper according to specified locale, defaults to host environment. Set to `false` to disable. -- `separateNumbers?: boolean` Splits `foo123` into `foo 123` instead of keeping them together. Defaults to `true`. +- `separateNumbers?: boolean` Splits `foo123` into `foo 123` instead of keeping them together. Defaults to `false`. - `prefixCharacters?: string` Retain at the beginning of the string. Defaults to `""`. Example: use `"_"` to keep the underscores in `__typename`. +By default, `pascalCase` and `snakeCase` separate ambiguous characters with `_`. For example, `V1.2` would become `V1_2` instead of `V12`. If you prefer them merged you can set `mergeAmbiguousCharacters` to `true`. + ### Split **Change case** exports a `split` utility which can be used to build other case functions. It accepts a string and returns each "word" as an array. For example: diff --git a/packages/change-case/src/index.spec.ts b/packages/change-case/src/index.spec.ts index 3bf9fe83..f8bfbfd2 100644 --- a/packages/change-case/src/index.spec.ts +++ b/packages/change-case/src/index.spec.ts @@ -350,4 +350,17 @@ describe("change case", () => { expect(snakeCase(input, options)).toEqual(result.snakeCase); }); } + + describe("pascal case merge option", () => { + it("should merge numbers", () => { + const input = "version 1.2.10"; + + expect(camelCase(input, { mergeAmbiguousCharacters: true })).toEqual( + "version1210", + ); + expect(pascalCase(input, { mergeAmbiguousCharacters: true })).toEqual( + "Version1210", + ); + }); + }); }); diff --git a/packages/change-case/src/index.ts b/packages/change-case/src/index.ts index 5c4b3005..cb10f9f7 100644 --- a/packages/change-case/src/index.ts +++ b/packages/change-case/src/index.ts @@ -19,12 +19,25 @@ const DEFAULT_PREFIX_CHARACTERS = ""; */ export type Locale = string[] | string | false | undefined; +/** + * Options used for converting strings to pascal/camel case. + */ +export interface PascalCaseOptions extends Options { + mergeAmbiguousCharacters?: boolean; +} + +/** + * Options used for converting strings to any case. + */ export interface Options extends SplitOptions { locale?: Locale; delimiter?: string; prefixCharacters?: string; } +/** + * Options used for splitting strings into word segments. + */ export interface SplitOptions { separateNumbers?: boolean; } @@ -32,15 +45,14 @@ export interface SplitOptions { /** * Split any cased input strings into an array of words. */ -export function split(input: string, options: SplitOptions = {}) { - const { separateNumbers } = options; +export function split(input: string, options?: SplitOptions) { let result = input.trim(); result = result .replace(SPLIT_LOWER_UPPER_RE, SPLIT_REPLACE_VALUE) .replace(SPLIT_UPPER_UPPER_RE, SPLIT_REPLACE_VALUE); - if (separateNumbers) { + if (options?.separateNumbers) { result = result .replace(SPLIT_NUMBER_LOWER_RE, SPLIT_REPLACE_VALUE) .replace(SPLIT_LETTER_NUMBER_RE, SPLIT_REPLACE_VALUE); @@ -75,11 +87,13 @@ export function noCase(input: string, options?: Options) { /** * Convert a string to camel case (`fooBar`). */ -export function camelCase(input: string, options?: Options) { +export function camelCase(input: string, options?: PascalCaseOptions) { const prefix = getPrefix(input, options?.prefixCharacters); const lower = lowerFactory(options?.locale); const upper = upperFactory(options?.locale); - const transform = pascalCaseTransformFactory(lower, upper); + const transform = options?.mergeAmbiguousCharacters + ? capitalCaseTransformFactory(lower, upper) + : pascalCaseTransformFactory(lower, upper); return ( prefix + split(input, options) @@ -94,14 +108,17 @@ export function camelCase(input: string, options?: Options) { /** * Convert a string to pascal case (`FooBar`). */ -export function pascalCase(input: string, options?: Options) { +export function pascalCase(input: string, options?: PascalCaseOptions) { const prefix = getPrefix(input, options?.prefixCharacters); const lower = lowerFactory(options?.locale); const upper = upperFactory(options?.locale); + const transform = options?.mergeAmbiguousCharacters + ? capitalCaseTransformFactory(lower, upper) + : pascalCaseTransformFactory(lower, upper); return ( prefix + split(input, options) - .map(pascalCaseTransformFactory(lower, upper)) + .map(transform) .join(options?.delimiter ?? "") ); }