From 721a7e06fc219e8cfade41cacb7b34cc44cd9d9b Mon Sep 17 00:00:00 2001 From: rocktimsaikia Date: Tue, 6 Oct 2020 22:37:57 +0530 Subject: [PATCH 1/9] add support for -preserveConsecutiveUppercase option --- index.d.ts | 18 +++++++++++++++- index.js | 30 ++++++++++++++++++++------- readme.md | 16 ++++++++++++++ test.js | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 9 deletions(-) diff --git a/index.d.ts b/index.d.ts index 51d2ba2..5f5624a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -6,6 +6,13 @@ declare namespace camelcase { @default false */ readonly pascalCase?: boolean; + + /** + Preserve the consecutive uppercase characters: `foo-BAR` → `FooBAR`. + + @default false + */ + readonly preserveConsecutiveUppercase?: boolean; } } @@ -18,7 +25,7 @@ Correctly handles Unicode strings. @example ``` -import camelCase = require('camelcase'); +const camelCase = require('camelcase'); camelCase('foo-bar'); //=> 'fooBar' @@ -38,6 +45,12 @@ camelCase('Foo-Bar', {pascalCase: true}); camelCase('--foo.bar', {pascalCase: false}); //=> 'fooBar' +camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); +//=> 'FooBAR' + +camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true})); +//=> 'FooBaR' + camelCase('foo bar'); //=> 'fooBar' @@ -51,6 +64,9 @@ camelCase(['foo', 'bar']); camelCase(['__foo__', '--bar'], {pascalCase: true}); //=> 'FooBar' + +camelCase(['foo', 'BAR'], {pascalCase: true, preserveConsecutiveUppercase: true}) +//=> 'FooBAR' ``` */ declare function camelcase( diff --git a/index.js b/index.js index dd2c490..8d36a6a 100644 --- a/index.js +++ b/index.js @@ -29,18 +29,26 @@ const preserveCamelCase = string => { return string; }; +const preserveConsecutiveUppercase = input => { + return input.replace(/^[\p{Lu}](?![\p{Lu}])/gu, m1 => m1.toLowerCase()); +}; + +const postProcess = input => { + return input.replace(/[_.\- ]+([\p{Alpha}\p{N}_]|$)/gu, (_, p1) => p1.toLocaleUpperCase()) + .replace(/\d+([\p{Alpha}\p{N}_]|$)/gu, m => m.toLocaleUpperCase()); +}; + const camelCase = (input, options) => { if (!(typeof input === 'string' || Array.isArray(input))) { throw new TypeError('Expected the input to be `string | string[]`'); } options = { - ...{pascalCase: false}, + pascalCase: false, + preserveConsecutiveUppercase: false, ...options }; - const postProcess = x => options.pascalCase ? x.charAt(0).toLocaleUpperCase() + x.slice(1) : x; - if (Array.isArray(input)) { input = input.map(x => x.trim()) .filter(x => x.length) @@ -63,11 +71,17 @@ const camelCase = (input, options) => { input = preserveCamelCase(input); } - input = input - .replace(/^[_.\- ]+/, '') - .toLocaleLowerCase() - .replace(/[_.\- ]+([\p{Alpha}\p{N}_]|$)/gu, (_, p1) => p1.toLocaleUpperCase()) - .replace(/\d+([\p{Alpha}\p{N}_]|$)/gu, m => m.toLocaleUpperCase()); + input = input.replace(/^[_.\- ]+/, ''); + + if (options.preserveConsecutiveUppercase) { + input = preserveConsecutiveUppercase(input); + } else { + input = input.toLocaleLowerCase(); + } + + if (options.pascalCase) { + input = input.charAt(0).toLocaleUpperCase() + input.slice(1); + } return postProcess(input); }; diff --git a/readme.md b/readme.md index da76012..2361c33 100644 --- a/readme.md +++ b/readme.md @@ -35,6 +35,12 @@ camelCase('Foo-Bar', {pascalCase: true}); camelCase('--foo.bar', {pascalCase: false}); //=> 'fooBar' +camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); +//=> 'FooBAR' + +camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true})); +//=> 'FooBaR' + camelCase('foo bar'); //=> 'fooBar' @@ -48,6 +54,9 @@ camelCase(['foo', 'bar']); camelCase(['__foo__', '--bar'], {pascalCase: true}); //=> 'FooBar' + +camelCase(['foo', 'BAR'], {pascalCase: true, preserveConsecutiveUppercase: true}) +//=> 'FooBAR' ``` ## API @@ -71,6 +80,13 @@ Default: `false` Uppercase the first character: `foo-bar` → `FooBar` +##### preserveConsecutiveUppercase + +Type: `boolean`\ +Default: `false` + +Preserve the consecutive uppercase characters: `foo-BAR` → `FooBAR` + ## camelcase for enterprise Available as part of the Tidelift Subscription. diff --git a/test.js b/test.js index 4dea4be..46ce711 100644 --- a/test.js +++ b/test.js @@ -130,6 +130,67 @@ test('camelCase with pascalCase option', t => { t.is(camelCase('桑德_在这里。', {pascalCase: true}), '桑德在这里。'); }); +test('camelCase with preserveConsecutiveUppercase option', t => { + t.is(camelCase('foo-BAR', {preserveConsecutiveUppercase: true}), 'fooBAR'); + t.is(camelCase('fooBAR', {preserveConsecutiveUppercase: true}), 'fooBAR'); + t.is(camelCase('fooBaR', {preserveConsecutiveUppercase: true}), 'fooBaR'); + t.is(camelCase('FOÈ-BAR', {preserveConsecutiveUppercase: true}), 'FOÈBAR'); + t.is(camelCase(['foo', 'BAR'], {preserveConsecutiveUppercase: true}), 'fooBAR'); + t.is(camelCase(['foo', '-BAR'], {preserveConsecutiveUppercase: true}), 'fooBAR'); + t.is(camelCase(['foo', '-BAR', 'baz'], {preserveConsecutiveUppercase: true}), 'fooBARBaz'); + t.is(camelCase(['', ''], {preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('--', {preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('', {preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('--__--_--_', {preserveConsecutiveUppercase: true}), ''); + t.is(camelCase(['---_', '--', '', '-_- '], {preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('foo BAR?', {preserveConsecutiveUppercase: true}), 'fooBAR?'); + t.is(camelCase('foo BAR!', {preserveConsecutiveUppercase: true}), 'fooBAR!'); + t.is(camelCase('foo BAR$', {preserveConsecutiveUppercase: true}), 'fooBAR$'); + t.is(camelCase('foo-BAR#', {preserveConsecutiveUppercase: true}), 'fooBAR#'); + t.is(camelCase('XMLHttpRequest', {preserveConsecutiveUppercase: true}), 'XMLHttpRequest'); + t.is(camelCase('AjaxXMLHttpRequest', {preserveConsecutiveUppercase: true}), 'ajaxXMLHttpRequest'); + t.is(camelCase('Ajax-XMLHttpRequest', {preserveConsecutiveUppercase: true}), 'ajaxXMLHttpRequest'); + t.is(camelCase([], {preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('mGridCOl6@md', {preserveConsecutiveUppercase: true}), 'mGridCOl6@md'); + t.is(camelCase('A::a', {preserveConsecutiveUppercase: true}), 'a::a'); + t.is(camelCase('Hello1WORLD', {preserveConsecutiveUppercase: true}), 'hello1WORLD'); + t.is(camelCase('Hello11WORLD', {preserveConsecutiveUppercase: true}), 'hello11WORLD'); + t.is(camelCase('РозовыйПушистыйFOOдинорогиf', {preserveConsecutiveUppercase: true}), 'розовыйПушистыйFOOдинорогиf'); + t.is(camelCase('桑德在这里。', {preserveConsecutiveUppercase: true}), '桑德在这里。'); + t.is(camelCase('桑德_在这里。', {preserveConsecutiveUppercase: true}), '桑德在这里。'); +}); + +test('camelCase with both -pascalCase and -preserveConsecutiveUppercase option', t => { + t.is(camelCase('foo-BAR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR'); + t.is(camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR'); + t.is(camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBaR'); + t.is(camelCase('fOÈ-BAR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FOÈBAR'); + t.is(camelCase('--foo.BAR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR'); + t.is(camelCase(['Foo', 'BAR'], {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR'); + t.is(camelCase(['foo', '-BAR'], {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR'); + t.is(camelCase(['foo', '-BAR', 'baz'], {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBARBaz'); + t.is(camelCase(['', ''], {pascalCase: true, preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('--', {pascalCase: true, preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('', {pascalCase: true, preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('--__--_--_', {pascalCase: true, preserveConsecutiveUppercase: true}), ''); + t.is(camelCase(['---_', '--', '', '-_- '], {pascalCase: true, preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('foo BAR?', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR?'); + t.is(camelCase('foo BAR!', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR!'); + t.is(camelCase('Foo BAR$', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR$'); + t.is(camelCase('foo-BAR#', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR#'); + t.is(camelCase('xMLHttpRequest', {pascalCase: true, preserveConsecutiveUppercase: true}), 'XMLHttpRequest'); + t.is(camelCase('ajaxXMLHttpRequest', {pascalCase: true, preserveConsecutiveUppercase: true}), 'AjaxXMLHttpRequest'); + t.is(camelCase('Ajax-XMLHttpRequest', {pascalCase: true, preserveConsecutiveUppercase: true}), 'AjaxXMLHttpRequest'); + t.is(camelCase([], {pascalCase: true, preserveConsecutiveUppercase: true}), ''); + t.is(camelCase('mGridCOl6@md', {pascalCase: true, preserveConsecutiveUppercase: true}), 'MGridCOl6@md'); + t.is(camelCase('A::a', {pascalCase: true, preserveConsecutiveUppercase: true}), 'A::a'); + t.is(camelCase('Hello1WORLD', {pascalCase: true, preserveConsecutiveUppercase: true}), 'Hello1WORLD'); + t.is(camelCase('Hello11WORLD', {pascalCase: true, preserveConsecutiveUppercase: true}), 'Hello11WORLD'); + t.is(camelCase('pозовыйПушистыйFOOдинорогиf', {pascalCase: true, preserveConsecutiveUppercase: true}), 'PозовыйПушистыйFOOдинорогиf'); + t.is(camelCase('桑德在这里。', {pascalCase: true, preserveConsecutiveUppercase: true}), '桑德在这里。'); + t.is(camelCase('桑德_在这里。', {pascalCase: true, preserveConsecutiveUppercase: true}), '桑德在这里。'); +}); + test('invalid input', t => { t.throws(() => { camelCase(1); From 29b62269a2dd6993648100ea5ae25b9e4f25b359 Mon Sep 17 00:00:00 2001 From: rocktimsaikia Date: Tue, 6 Oct 2020 22:41:24 +0530 Subject: [PATCH 2/9] add a new test for -preserveConsecutiveUppercase --- readme.md | 2 +- test.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2361c33..05d8135 100644 --- a/readme.md +++ b/readme.md @@ -36,7 +36,7 @@ camelCase('--foo.bar', {pascalCase: false}); //=> 'fooBar' camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); -//=> 'FooBAR' +//=> 'fooBAR' camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true})); //=> 'FooBaR' diff --git a/test.js b/test.js index 46ce711..c22cf3a 100644 --- a/test.js +++ b/test.js @@ -132,6 +132,7 @@ test('camelCase with pascalCase option', t => { test('camelCase with preserveConsecutiveUppercase option', t => { t.is(camelCase('foo-BAR', {preserveConsecutiveUppercase: true}), 'fooBAR'); + t.is(camelCase('Foo-BAR', {preserveConsecutiveUppercase: true}), 'fooBAR'); t.is(camelCase('fooBAR', {preserveConsecutiveUppercase: true}), 'fooBAR'); t.is(camelCase('fooBaR', {preserveConsecutiveUppercase: true}), 'fooBaR'); t.is(camelCase('FOÈ-BAR', {preserveConsecutiveUppercase: true}), 'FOÈBAR'); From df4ad29c02cae0cd7521454be71d90308c1d499f Mon Sep 17 00:00:00 2001 From: rocktimsaikia Date: Tue, 6 Oct 2020 22:42:47 +0530 Subject: [PATCH 3/9] fix example in declaration file --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 5f5624a..4cec03e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -46,7 +46,7 @@ camelCase('--foo.bar', {pascalCase: false}); //=> 'fooBar' camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); -//=> 'FooBAR' +//=> 'fooBAR' camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true})); //=> 'FooBaR' From 5d6cf80eee23214d022d072754f6a72f667f0645 Mon Sep 17 00:00:00 2001 From: rocktimsaikia Date: Tue, 6 Oct 2020 22:48:11 +0530 Subject: [PATCH 4/9] fix example --- index.d.ts | 6 +++--- readme.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/index.d.ts b/index.d.ts index 4cec03e..9f00795 100644 --- a/index.d.ts +++ b/index.d.ts @@ -25,7 +25,7 @@ Correctly handles Unicode strings. @example ``` -const camelCase = require('camelcase'); +import camelCase = require('camelcase'); camelCase('foo-bar'); //=> 'fooBar' @@ -48,8 +48,8 @@ camelCase('--foo.bar', {pascalCase: false}); camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); //=> 'fooBAR' -camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true})); -//=> 'FooBaR' +camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true})); +//=> 'FooBAR' camelCase('foo bar'); //=> 'fooBar' diff --git a/readme.md b/readme.md index 05d8135..f763e8f 100644 --- a/readme.md +++ b/readme.md @@ -38,8 +38,8 @@ camelCase('--foo.bar', {pascalCase: false}); camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); //=> 'fooBAR' -camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true})); -//=> 'FooBaR' +camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true})); +//=> 'FooBAR' camelCase('foo bar'); //=> 'fooBar' From ff13fd05fd3f7b9143fda801d428419e17a14874 Mon Sep 17 00:00:00 2001 From: rocktimsaikia Date: Mon, 26 Oct 2020 13:02:05 +0530 Subject: [PATCH 5/9] remove dashes from option names --- test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.js b/test.js index c22cf3a..34f75b8 100644 --- a/test.js +++ b/test.js @@ -161,7 +161,7 @@ test('camelCase with preserveConsecutiveUppercase option', t => { t.is(camelCase('桑德_在这里。', {preserveConsecutiveUppercase: true}), '桑德在这里。'); }); -test('camelCase with both -pascalCase and -preserveConsecutiveUppercase option', t => { +test('camelCase with both pascalCase and preserveConsecutiveUppercase option', t => { t.is(camelCase('foo-BAR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR'); t.is(camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBAR'); t.is(camelCase('fooBaR', {pascalCase: true, preserveConsecutiveUppercase: true}), 'FooBaR'); From f195a7f4e5e45661d3d220e6419639c9d6802830 Mon Sep 17 00:00:00 2001 From: Rocktim Saikia Date: Mon, 26 Oct 2020 13:05:40 +0530 Subject: [PATCH 6/9] Update readme.md Co-authored-by: Sindre Sorhus --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f763e8f..4b79980 100644 --- a/readme.md +++ b/readme.md @@ -85,7 +85,7 @@ Uppercase the first character: `foo-bar` → `FooBar` Type: `boolean`\ Default: `false` -Preserve the consecutive uppercase characters: `foo-BAR` → `FooBAR` +Preserve the consecutive uppercase characters: `foo-BAR` → `FooBAR`. ## camelcase for enterprise From 6a64a71a7b741c2ce9401623f7349a12afdc90a0 Mon Sep 17 00:00:00 2001 From: Rocktim Saikia Date: Tue, 27 Oct 2020 16:02:37 +0530 Subject: [PATCH 7/9] Update index.d.ts Co-authored-by: Sindre Sorhus --- index.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.d.ts b/index.d.ts index d867f50..c24d07a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -16,7 +16,9 @@ declare namespace camelcase { /** The locale parameter indicates the locale to be used to convert to upper/lower case according to any locale-specific case mappings. If multiple locales are given in an array, the best available locale is used. + Default: The host environment’s current locale. + @example ``` import camelCase = require('camelcase'); From c861b06326c830965583df92d0fdfef1a2ba69b7 Mon Sep 17 00:00:00 2001 From: rocktimsaikia Date: Tue, 27 Oct 2020 16:00:07 +0530 Subject: [PATCH 8/9] fix typos --- index.d.ts | 1 + readme.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index c24d07a..37d1a65 100644 --- a/index.d.ts +++ b/index.d.ts @@ -22,6 +22,7 @@ declare namespace camelcase { @example ``` import camelCase = require('camelcase'); + camelCase('lorem-ipsum', {locale: 'en-US'}); //=> 'loremIpsum' camelCase('lorem-ipsum', {locale: 'tr-TR'}); diff --git a/readme.md b/readme.md index 60bd224..dbfc0de 100644 --- a/readme.md +++ b/readme.md @@ -35,7 +35,7 @@ camelCase('Foo-Bar', {pascalCase: true}); camelCase('--foo.bar', {pascalCase: false}); //=> 'fooBar' -camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); +camelCase('Foo-BAR', {preserveConsecutiveUppercase: true}); //=> 'fooBAR' camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true})); From 47a299aeee295ac25202e2ee37bc2103345f37e7 Mon Sep 17 00:00:00 2001 From: rocktimsaikia Date: Wed, 28 Oct 2020 22:20:01 +0530 Subject: [PATCH 9/9] update example in index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 37d1a65..169b634 100644 --- a/index.d.ts +++ b/index.d.ts @@ -66,7 +66,7 @@ camelCase('Foo-Bar', {pascalCase: true}); camelCase('--foo.bar', {pascalCase: false}); //=> 'fooBar' -camelCase('Foo-Bar', {preserveConsecutiveUppercase: true}); +camelCase('Foo-BAR', {preserveConsecutiveUppercase: true}); //=> 'fooBAR' camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true}));