Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add locale option #75

Merged
merged 16 commits into from Oct 10, 2020
10 changes: 10 additions & 0 deletions index.d.ts
Expand Up @@ -6,6 +6,13 @@ declare namespace camelcase {
@default false
*/
readonly pascalCase?: boolean;

/**
From `String.prototype.toLocaleUpperCase()`: 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. The default locale is the host environment’s current locale.
sindresorhus marked this conversation as resolved.
Show resolved Hide resolved

@default The host environment’s current locale
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect syntax. @default only works with a JS value.

Copy link
Contributor Author

@rasgele rasgele Sep 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I'll remove @default and append following to the description of locale parameter:
"If not provided, host environment's current locale is used".

Do you have other suggestion for such a case?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just write Default: The host environment’s current locale.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

*/
readonly locale?: string | readonly string[];
}
}

Expand Down Expand Up @@ -51,6 +58,9 @@ camelCase(['foo', 'bar']);

camelCase(['__foo__', '--bar'], {pascalCase: true});
//=> 'FooBar'

camelCase('lorem-ipsum', {locale: 'en-US'});
//=> 'loremIpsum'
rasgele marked this conversation as resolved.
Show resolved Hide resolved
```
*/
declare function camelcase(
Expand Down
20 changes: 10 additions & 10 deletions index.js
@@ -1,6 +1,6 @@
'use strict';

const preserveCamelCase = string => {
const preserveCamelCase = (string, locale) => {
let isLastCharLower = false;
let isLastCharUpper = false;
let isLastLastCharUpper = false;
Expand All @@ -20,9 +20,9 @@ const preserveCamelCase = string => {
isLastCharUpper = false;
isLastCharLower = true;
} else {
isLastCharLower = character.toLocaleLowerCase() === character && character.toLocaleUpperCase() !== character;
isLastCharLower = character.toLocaleLowerCase(locale) === character && character.toLocaleUpperCase(locale) !== character;
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = character.toLocaleUpperCase() === character && character.toLocaleLowerCase() !== character;
isLastCharUpper = character.toLocaleUpperCase(locale) === character && character.toLocaleLowerCase(locale) !== character;
}
}

Expand All @@ -39,7 +39,7 @@ const camelCase = (input, options) => {
...options
};

const postProcess = x => options.pascalCase ? x.charAt(0).toLocaleUpperCase() + x.slice(1) : x;
const postProcess = x => options.pascalCase ? x.charAt(0).toLocaleUpperCase(options.locale) + x.slice(1) : x;

if (Array.isArray(input)) {
input = input.map(x => x.trim())
Expand All @@ -54,20 +54,20 @@ const camelCase = (input, options) => {
}

if (input.length === 1) {
return options.pascalCase ? input.toLocaleUpperCase() : input.toLocaleLowerCase();
return options.pascalCase ? input.toLocaleUpperCase(options.locale) : input.toLocaleLowerCase(options.locale);
}

const hasUpperCase = input !== input.toLocaleLowerCase();
const hasUpperCase = input !== input.toLocaleLowerCase(options.locale);

if (hasUpperCase) {
input = preserveCamelCase(input);
input = preserveCamelCase(input, options.locale);
}

input = input
.replace(/^[_.\- ]+/, '')
.toLocaleLowerCase()
.replace(/[_.\- ]+([\p{Alpha}\p{N}_]|$)/gu, (_, p1) => p1.toLocaleUpperCase())
.replace(/\d+([\p{Alpha}\p{N}_]|$)/gu, m => m.toLocaleUpperCase());
.toLocaleLowerCase(options.locale)
.replace(/[_.\- ]+([\p{Alpha}\p{N}_]|$)/gu, (_, p1) => p1.toLocaleUpperCase(options.locale))
.replace(/\d+([\p{Alpha}\p{N}_]|$)/gu, m => m.toLocaleUpperCase(options.locale));

return postProcess(input);
};
Expand Down
4 changes: 4 additions & 0 deletions index.test-d.ts
Expand Up @@ -3,6 +3,10 @@ import camelCase = require('.');

expectType<string>(camelCase('foo-bar'));
expectType<string>(camelCase('розовый_пушистый_единороги'));
expectType<string>(camelCase('Foo-Bar', {locale: ['tr']}));
expectType<string>(camelCase('Foo-Bar', {locale: ['tr', 'TR', 'tr-TR']}));
expectType<string>(camelCase('Foo-Bar', {pascalCase: true, locale: ['tr']}));
expectType<string>(camelCase('Foo-Bar', {pascalCase: true, locale: ['tr', 'TR', 'tr-TR']}));
expectType<string>(camelCase('Foo-Bar', {pascalCase: true}));
expectType<string>(camelCase(['foo', 'bar']));
expectType<string>(camelCase(['__foo__', '--bar'], {pascalCase: true}));
24 changes: 24 additions & 0 deletions readme.md
Expand Up @@ -48,6 +48,9 @@ camelCase(['foo', 'bar']);

camelCase(['__foo__', '--bar'], {pascalCase: true});
//=> 'FooBar'

camelCase('lorem-ipsum', {locale: 'en-US'});
//=> 'loremIpsum'
```

## API
Expand All @@ -71,6 +74,27 @@ Default: `false`

Uppercase the first character: `foo-bar` → `FooBar`

##### locale

Type: `string | string[]`\
Default: The host environment’s current locale

*From `String.prototype.toLocaleUpperCase()`*: 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. The default locale is the host environment’s current locale.

```js
camelCase('lorem-ipsum', {locale: 'en-US'});
//=> 'loremIpsum'

camelCase('lorem-ipsum', {locale: 'tr-TR'});
//=> 'loremİpsum'

camelCase('lorem-ipsum', {locale: ['en-US', 'en-GB']});
//=> 'loremIpsum'

camelCase('lorem-ipsum', {locale: ['tr', 'TR', 'tr-TR']});
//=> 'loremİpsum'
```
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The readme and index.d.ts should be fully in sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readme contains 4 examples and index.d.ts contains one example due to your previous comment: #75 (comment)
Do you means smth else?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, ok. thanks. Done.


## camelcase for enterprise

Available as part of the Tidelift Subscription.
Expand Down
11 changes: 11 additions & 0 deletions test.js
Expand Up @@ -130,6 +130,17 @@ test('camelCase with pascalCase option', t => {
t.is(camelCase('桑德_在这里。', {pascalCase: true}), '桑德在这里。');
});

test('camelCase with locale option', t => {
t.is(camelCase('lorem-ipsum', {locale: 'tr-TR'}), 'loremİpsum');
t.is(camelCase('lorem-ipsum', {locale: 'en-EN'}), 'loremIpsum');
t.is(camelCase('lorem-ipsum', {locale: ['tr', 'TR', 'tr-TR']}), 'loremİpsum');
t.is(camelCase('lorem-ipsum', {locale: ['en-EN', 'en-GB']}), 'loremIpsum');
t.is(camelCase('ipsum-dolor', {pascalCase: true, locale: 'tr-TR'}), 'İpsumDolor');
t.is(camelCase('ipsum-dolor', {pascalCase: true, locale: 'en-EN'}), 'IpsumDolor');
t.is(camelCase('ipsum-dolor', {pascalCase: true, locale: ['tr', 'TR', 'tr-TR']}), 'İpsumDolor');
t.is(camelCase('ipsum-dolor', {pascalCase: true, locale: ['en-EN', 'en-GB']}), 'IpsumDolor');
});

test('invalid input', t => {
t.throws(() => {
camelCase(1);
Expand Down