From 1d2e9e1df0a870e93724f45c75d492ca424f99d1 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 6 Jun 2022 12:02:25 +0700 Subject: [PATCH] Require Node.js 14 and move to ESM Closes #83 --- .github/workflows/main.yml | 2 - index.d.ts | 89 +++++++++++++++++++------------------- index.js | 42 +++++++----------- index.test-d.ts | 2 +- package.json | 11 +++-- readme.md | 14 +++--- test.js | 10 +++-- 7 files changed, 80 insertions(+), 90 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index af02945..d50ada6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,8 +13,6 @@ jobs: - 18 - 16 - 14 - - 12 - - 10 steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 diff --git a/index.d.ts b/index.d.ts index 9db94e5..9d519ec 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,43 +1,44 @@ -declare namespace camelcase { - interface Options { - /** - Uppercase the first character: `foo-bar` → `FooBar`. - - @default false - */ - readonly pascalCase?: boolean; - - /** - Preserve the consecutive uppercase characters: `foo-BAR` → `FooBAR`. - - @default false - */ - readonly preserveConsecutiveUppercase?: boolean; - - /** - 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. - - Setting `locale: false` ignores the platform locale and uses the [Unicode Default Case Conversion](https://unicode-org.github.io/icu/userguide/transforms/casemappings.html#simple-single-character-case-mapping) algorithm. - - Default: The host environment’s current locale. - - @example - ``` - import camelCase = require('camelcase'); - - 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' - ``` - */ - readonly locale?: false | string | readonly string[]; - } -} +export type Options = { + /** + Uppercase the first character: `foo-bar` → `FooBar`. + + @default false + */ + readonly pascalCase?: boolean; + + /** + Preserve consecutive uppercase characters: `foo-BAR` → `FooBAR`. + + @default false + */ + readonly preserveConsecutiveUppercase?: boolean; + + /** + 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. + + Setting `locale: false` ignores the platform locale and uses the [Unicode Default Case Conversion](https://unicode-org.github.io/icu/userguide/transforms/casemappings.html#simple-single-character-case-mapping) algorithm. + + Default: The host environment’s current locale. + + @example + ``` + import camelCase from 'camelcase'; + + 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' + ``` + */ + readonly locale?: false | string | readonly string[]; +}; /** Convert a dash/dot/underscore/space separated string to camelCase or PascalCase: `foo-bar` → `fooBar`. @@ -48,7 +49,7 @@ Correctly handles Unicode strings. @example ``` -import camelCase = require('camelcase'); +import camelCase from 'camelcase'; camelCase('foo-bar'); //=> 'fooBar' @@ -95,9 +96,7 @@ camelCase('lorem-ipsum', {locale: 'en-US'}); //=> 'loremIpsum' ``` */ -declare function camelcase( +export default function camelcase( input: string | readonly string[], - options?: camelcase.Options + options?: Options ): string; - -export = camelcase; diff --git a/index.js b/index.js index 7d488fe..6e350bd 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,3 @@ -'use strict'; - const UPPERCASE = /[\p{Lu}]/u; const LOWERCASE = /[\p{Ll}]/u; const LEADING_CAPITAL = /^[\p{Lu}](?![\p{Lu}])/gu; @@ -15,17 +13,17 @@ const preserveCamelCase = (string, toLowerCase, toUpperCase) => { let isLastCharUpper = false; let isLastLastCharUpper = false; - for (let i = 0; i < string.length; i++) { - const character = string[i]; + for (let index = 0; index < string.length; index++) { + const character = string[index]; if (isLastCharLower && UPPERCASE.test(character)) { - string = string.slice(0, i) + '-' + string.slice(i); + string = string.slice(0, index) + '-' + string.slice(index); isLastCharLower = false; isLastLastCharUpper = isLastCharUpper; isLastCharUpper = true; - i++; + index++; } else if (isLastCharUpper && isLastLastCharUpper && LOWERCASE.test(character)) { - string = string.slice(0, i - 1) + '-' + string.slice(i - 1); + string = string.slice(0, index - 1) + '-' + string.slice(index - 1); isLastLastCharUpper = isLastCharUpper; isLastCharUpper = false; isLastCharLower = true; @@ -53,7 +51,7 @@ const postProcess = (input, toUpperCase) => { .replace(NUMBERS_AND_IDENTIFIER, m => toUpperCase(m)); }; -const camelCase = (input, options) => { +export default function camelCase(input, options) { if (!(typeof input === 'string' || Array.isArray(input))) { throw new TypeError('Expected the input to be `string | string[]`'); } @@ -61,7 +59,7 @@ const camelCase = (input, options) => { options = { pascalCase: false, preserveConsecutiveUppercase: false, - ...options + ...options, }; if (Array.isArray(input)) { @@ -76,12 +74,13 @@ const camelCase = (input, options) => { return ''; } - const toLowerCase = options.locale === false ? - string => string.toLowerCase() : - string => string.toLocaleLowerCase(options.locale); - const toUpperCase = options.locale === false ? - string => string.toUpperCase() : - string => string.toLocaleUpperCase(options.locale); + const toLowerCase = options.locale === false + ? string => string.toLowerCase() + : string => string.toLocaleLowerCase(options.locale); + + const toUpperCase = options.locale === false + ? string => string.toUpperCase() + : string => string.toLocaleUpperCase(options.locale); if (input.length === 1) { if (SEPARATORS.test(input)) { @@ -98,20 +97,11 @@ const camelCase = (input, options) => { } input = input.replace(LEADING_SEPARATORS, ''); - - if (options.preserveConsecutiveUppercase) { - input = preserveConsecutiveUppercase(input, toLowerCase); - } else { - input = toLowerCase(input); - } + input = options.preserveConsecutiveUppercase ? preserveConsecutiveUppercase(input, toLowerCase) : toLowerCase(input); if (options.pascalCase) { input = toUpperCase(input.charAt(0)) + input.slice(1); } return postProcess(input, toUpperCase); -}; - -module.exports = camelCase; -// TODO: Remove this for the next major release -module.exports.default = camelCase; +} diff --git a/index.test-d.ts b/index.test-d.ts index e39b067..c3b6de2 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,5 +1,5 @@ import {expectType} from 'tsd'; -import camelCase = require('.'); +import camelCase from './index.js'; expectType(camelCase('foo-bar')); expectType(camelCase('розовый_пушистый_единороги')); diff --git a/package.json b/package.json index c433579..f7e9e7a 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,11 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", + "types": "./index.d.ts", "engines": { - "node": ">=10" + "node": ">=14.16" }, "scripts": { "test": "xo && ava && tsd" @@ -37,8 +40,8 @@ "pascal-case" ], "devDependencies": { - "ava": "^1.4.1", - "tsd": "^0.11.0", - "xo": "^0.28.3" + "ava": "^4.3.0", + "tsd": "^0.20.0", + "xo": "^0.49.0" } } diff --git a/readme.md b/readme.md index 0ff8f9e..ef8ef97 100644 --- a/readme.md +++ b/readme.md @@ -8,16 +8,14 @@ If you use this on untrusted user input, don't forget to limit the length to som ## Install +```sh +npm install camelcase ``` -$ npm install camelcase -``` - -*If you need to support Firefox < 78, stay on version 5 as version 6 uses regex features not available in Firefox < 78.* ## Usage ```js -const camelCase = require('camelcase'); +import camelCase from 'camelcase'; camelCase('foo-bar'); //=> 'fooBar' @@ -90,7 +88,7 @@ Uppercase the first character: `foo-bar` → `FooBar` Type: `boolean`\ Default: `false` -Preserve the consecutive uppercase characters: `foo-BAR` → `FooBAR`. +Preserve consecutive uppercase characters: `foo-BAR` → `FooBAR`. ##### locale @@ -100,7 +98,7 @@ Default: The host environment’s current locale. 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. ```js -const camelCase = require('camelcase'); +import camelCase from 'camelcase'; camelCase('lorem-ipsum', {locale: 'en-US'}); //=> 'loremIpsum' @@ -118,7 +116,7 @@ camelCase('lorem-ipsum', {locale: ['tr', 'TR', 'tr-TR']}); Setting `locale: false` ignores the platform locale and uses the [Unicode Default Case Conversion](https://unicode-org.github.io/icu/userguide/transforms/casemappings.html#simple-single-character-case-mapping) algorithm: ```js -const camelCase = require('camelcase'); +import camelCase from 'camelcase'; // On a platform with 'tr-TR' diff --git a/test.js b/test.js index 3d7cd56..d3cbc27 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,5 @@ import test from 'ava'; -import camelCase from '.'; +import camelCase from './index.js'; test('camelCase', t => { t.is(camelCase('foo'), 'foo'); @@ -228,7 +228,9 @@ test('camelCase with disabled locale', t => { test('invalid input', t => { t.throws(() => { camelCase(1); - }, /Expected the input to be/); + }, { + message: /Expected the input to be/, + }); }); /* eslint-disable no-extend-native */ @@ -242,11 +244,11 @@ const withLocaleCaseFunctionsMocked = fn => { Object.defineProperty(String.prototype, 'toLocaleUpperCase', { ...toLocaleUpperCase, - value: throwWhenBeingCalled + value: throwWhenBeingCalled, }); Object.defineProperty(String.prototype, 'toLocaleLowerCase', { ...toLocaleLowerCase, - value: throwWhenBeingCalled + value: throwWhenBeingCalled, }); try {