From 2597adb23cc8f4d25fc939b9ee376241bfefcd78 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Fri, 1 Oct 2021 10:30:14 +0800 Subject: [PATCH] Move to ESM (#33) Co-authored-by: Sindre Sorhus --- .github/workflows/main.yml | 4 +-- index.d.ts | 61 +++++++++++++++++------------------ index.js | 26 ++++++--------- index.test-d.ts | 4 +-- package.json | 11 ++++--- readme.md | 10 +++--- test.js | 66 +++++++++++++++++++------------------- 7 files changed, 88 insertions(+), 94 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1870cf..3b8aa86 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,12 +10,12 @@ jobs: fail-fast: false matrix: node-version: + - 16 - 14 - 12 - - 10 steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/index.d.ts b/index.d.ts index 4d10913..91f10dd 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,41 +1,39 @@ -declare namespace decamelize { - interface Options { - /** - Character or string inserted to separate words in `string`. +export interface Options { + /** + Character or string inserted to separate words in `string`. - @default '_' + @default '_' - @example - ``` - import decamelize = require('decamelize'); + @example + ``` + import decamelize from 'decamelize'; - decamelize('unicornRainbow'); - //=> 'unicorn_rainbow' + decamelize('unicornRainbow'); + //=> 'unicorn_rainbow' - decamelize('unicornRainbow', {separator: '-'}); - //=> 'unicorn-rainbow' - ``` - */ - readonly separator?: string; + decamelize('unicornRainbow', {separator: '-'}); + //=> 'unicorn-rainbow' + ``` + */ + readonly separator?: string; - /** - Preserve sequences of uppercase characters. + /** + Preserve sequences of uppercase characters. - @default false + @default false - @example - ``` - import decamelize = require('decamelize'); + @example + ``` + import decamelize from 'decamelize'; - decamelize('testGUILabel'); - //=> 'test_gui_label' + decamelize('testGUILabel'); + //=> 'test_gui_label' - decamelize('testGUILabel', {preserveConsecutiveUppercase: true}); - //=> 'test_GUI_label' - ``` - */ - readonly preserveConsecutiveUppercase?: boolean; - } + decamelize('testGUILabel', {preserveConsecutiveUppercase: true}); + //=> 'test_GUI_label' + ``` + */ + readonly preserveConsecutiveUppercase?: boolean; } /** @@ -45,7 +43,7 @@ Convert a camelized string into a lowercased one with a custom separator: `unico @example ``` -import decamelize = require('decamelize'); +import decamelize from 'decamelize'; decamelize('unicornRainbow'); //=> 'unicorn_rainbow' @@ -54,6 +52,5 @@ decamelize('unicornRainbow', {separator: '-'}); //=> 'unicorn-rainbow' ``` */ -declare function decamelize(string: string, options?: decamelize.Options): string; +export default function decamelize(string: string, options?: Options): string; -export = decamelize; diff --git a/index.js b/index.js index 0f8406e..1219e28 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,3 @@ -'use strict'; - const handlePreserveConsecutiveUppercase = (decamelized, separator) => { // Lowercase all single uppercase characters. As we // want to preserve uppercase sequences, we cannot @@ -7,31 +5,27 @@ const handlePreserveConsecutiveUppercase = (decamelized, separator) => { // `data_For_USACounties` → `data_for_USACounties` decamelized = decamelized.replace( /((? { - return $0.toLowerCase(); - } + $0 => $0.toLowerCase(), ); // Remaining uppercase sequences will be separated from lowercase sequences. // `data_For_USACounties` → `data_for_USA_counties` return decamelized.replace( /(\p{Uppercase_Letter}+)(\p{Uppercase_Letter}\p{Lowercase_Letter}+)/gu, - (_, $1, $2) => { - return $1 + separator + $2.toLowerCase(); - } + (_, $1, $2) => $1 + separator + $2.toLowerCase(), ); }; -module.exports = ( +export default function decamelize( text, { separator = '_', - preserveConsecutiveUppercase = false - } = {} -) => { + preserveConsecutiveUppercase = false, + } = {}, +) { if (!(typeof text === 'string' && typeof separator === 'string')) { throw new TypeError( - 'The `text` and `separator` arguments should be of type `string`' + 'The `text` and `separator` arguments should be of type `string`', ); } @@ -47,7 +41,7 @@ module.exports = ( // `myURLstring → `my_URLstring` const decamelized = text.replace( /([\p{Lowercase_Letter}\d])(\p{Uppercase_Letter})/gu, - replacement + replacement, ); if (preserveConsecutiveUppercase) { @@ -59,7 +53,7 @@ module.exports = ( return decamelized .replace( /(\p{Uppercase_Letter})(\p{Uppercase_Letter}\p{Lowercase_Letter}+)/gu, - replacement + replacement, ) .toLowerCase(); -}; +} diff --git a/index.test-d.ts b/index.test-d.ts index 420e909..14a8ccf 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,9 +1,9 @@ import {expectType} from 'tsd'; -import decamelize = require('.'); +import decamelize from './index.js'; expectType(decamelize('unicornRainbow')); expectType(decamelize('unicornRainbow', {separator: '-'})); expectType(decamelize('unicornRainbow', { separator: '-', - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, })); diff --git a/package.json b/package.json index 0ffb1a9..1a28f81 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "scripts": { "test": "xo && ava && tsd" @@ -33,8 +35,9 @@ "convert" ], "devDependencies": { - "ava": "^2.4.0", - "tsd": "^0.11.0", - "xo": "^0.24.0" + "ava": "^3.15.0", + "tsd": "^0.17.0", + "typescript": "^4.4.3", + "xo": "^0.44.0" } } diff --git a/readme.md b/readme.md index 487957c..949dcd3 100644 --- a/readme.md +++ b/readme.md @@ -7,14 +7,14 @@ If you use this on untrusted user input, don't forget to limit the length to som ## Install -``` -$ npm install decamelize +```sh +npm install decamelize ``` ## Usage ```js -const decamelize = require('decamelize'); +import decamelize from 'decamelize'; decamelize('unicornRainbow'); //=> 'unicorn_rainbow' @@ -49,7 +49,7 @@ Default: `'_'` Character or string inserted to separate words in `string`. ```js -cosnt decamelize = require('decamelize'); +import decamelize from 'decamelize'; decamelize('unicornRainbow'); //=> 'unicorn_rainbow' @@ -66,7 +66,7 @@ Default: `false` Preserve sequences of uppercase characters. ```js -const decamelize = require('decamelize'); +import decamelize from 'decamelize'; decamelize('testGUILabel'); //=> 'test_gui_label' diff --git a/test.js b/test.js index 30a54a3..d4098b9 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,5 @@ import test from 'ava'; -import decamelize from '.'; +import decamelize from './index.js'; test('decamelize', t => { t.is(decamelize(''), ''); @@ -19,7 +19,7 @@ test('decamelize', t => { t.is(decamelize('unicornRainbow', {separator: '-'}), 'unicorn-rainbow'); t.is( decamelize('thisHasSpecialCharactersLikeČandŠ', {separator: ' '}), - 'this has special characters like čand š' + 'this has special characters like čand š', ); }); @@ -39,66 +39,66 @@ test('separator and options passed', t => { t.is( decamelize('testGUILabel', { separator: '!', - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'test!GUI!label' + 'test!GUI!label', ); }); test('keeping blocks of consecutive uppercase characters but split the last if lowercase characters follow', t => { t.is( decamelize('A', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'A' + 'A', ); t.is( decamelize('myURLString', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'my_URL_string' + 'my_URL_string', ); t.is( decamelize('URLString', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'URL_string' + 'URL_string', ); t.is( decamelize('oxygenO2Level', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'oxygen_O2_level' + 'oxygen_O2_level', ); t.is( decamelize('StringURL', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'string_URL' + 'string_URL', ); t.is( decamelize('STringURL', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'S_tring_URL' + 'S_tring_URL', ); t.is( decamelize('numberOfDataForUSA', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'number_of_data_for_USA' + 'number_of_data_for_USA', ); t.is( decamelize('testGUILabel', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'test_GUI_label' + 'test_GUI_label', ); t.is( decamelize('CAPLOCKED1', { - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - 'CAPLOCKED1' + 'CAPLOCKED1', ); }); @@ -106,34 +106,34 @@ test('long strings', t => { // Factor to increase the test string const times = 100; const longString = 'Lb8SvAARMshcNvfxjgGCgfot3AZAzysuxRpG9XfpLCz89TeWqAd3TUo64K45VH2MfjLYhztt4LQYzrEbTpx7gGcG4T8ueKPm6VraXKtULJdncFQhEQfCRwWGNscdFe6UTEAvN7Nze4Qy4hvZuKLX5YiohGpvNZUtLGen3WP2jot8VeprzyXQmiKdxdxrEResSRgSWENCzXZPSerYuEfApVbjuDJZ9kGMRXFRZQVyBDDGfY9ERqtxHQxPw65TtEo3dgwhcuhvC3dMyRJ6jWaonKB3Pqtv27vRv5MgYb5mgvCE55oCTBG9yASPaw2KqYVz3amBge9HggEzXJGhwSXjkL7jUYk3WjQUbwVnZNHkH3P9MpvM98DtTnGAYfK5TjD8Y5oXPRJmdCHzhByboaW2oRJ2Ft7dxGKXLs2s7qsQs8FsJHVcYrmVHRa6th5CizHSXK7vr5D3KYsfsnr92AmtR4LERam7CV9emBBuykQJMejLGFsvgTrBKmmUqijxSgY'.repeat( - 100 + 100, ); t.is( decamelize(longString), - new Array(times) + Array.from({length: times}) .fill( - 'lb8_sv_aar_mshc_nvfxjg_g_cgfot3_az_azysux_rp_g9_xfp_l_cz89_te_wq_ad3_t_uo64_k45_vh2_mfj_l_yhztt4_lq_yzr_eb_tpx7g_gc_g4_t8ue_k_pm6_vra_x_kt_ul_jdnc_f_qh_e_qf_c_rw_wg_nscd_fe6_ute_av_n7_nze4_qy4hv_zu_klx5_yioh_gpv_nz_ut_l_gen3_wp2jot8_veprzy_x_qmi_kdxdxr_e_res_s_rg_swen_cz_xzp_ser_yu_ef_ap_vbju_djz9k_gmrxfrzq_vy_bdd_gf_y9_e_rqtx_h_qx_pw65_tt_eo3dgwhcuhv_c3d_my_rj6j_waon_kb3_pqtv27v_rv5_mg_yb5mgv_ce55o_ctbg9y_as_paw2_kq_y_vz3am_bge9_hgg_ez_xj_ghw_s_xjk_l7j_u_yk3_wj_q_ubw_vn_zn_hk_h3_p9_mpv_m98_dt_tn_ga_yf_k5_tj_d8_y5o_xpr_jmd_c_hzh_byboa_w2o_rj2_ft7dx_gkx_ls2s7qs_qs8_fs_jh_vc_yrm_vh_ra6th5_ciz_hsxk7vr5_d3_k_ysfsnr92_amt_r4_le_ram7_cv9em_b_buyk_qj_mej_lg_fsvg_tr_b_kmm_uqijx_sg_y' + 'lb8_sv_aar_mshc_nvfxjg_g_cgfot3_az_azysux_rp_g9_xfp_l_cz89_te_wq_ad3_t_uo64_k45_vh2_mfj_l_yhztt4_lq_yzr_eb_tpx7g_gc_g4_t8ue_k_pm6_vra_x_kt_ul_jdnc_f_qh_e_qf_c_rw_wg_nscd_fe6_ute_av_n7_nze4_qy4hv_zu_klx5_yioh_gpv_nz_ut_l_gen3_wp2jot8_veprzy_x_qmi_kdxdxr_e_res_s_rg_swen_cz_xzp_ser_yu_ef_ap_vbju_djz9k_gmrxfrzq_vy_bdd_gf_y9_e_rqtx_h_qx_pw65_tt_eo3dgwhcuhv_c3d_my_rj6j_waon_kb3_pqtv27v_rv5_mg_yb5mgv_ce55o_ctbg9y_as_paw2_kq_y_vz3am_bge9_hgg_ez_xj_ghw_s_xjk_l7j_u_yk3_wj_q_ubw_vn_zn_hk_h3_p9_mpv_m98_dt_tn_ga_yf_k5_tj_d8_y5o_xpr_jmd_c_hzh_byboa_w2o_rj2_ft7dx_gkx_ls2s7qs_qs8_fs_jh_vc_yrm_vh_ra6th5_ciz_hsxk7vr5_d3_k_ysfsnr92_amt_r4_le_ram7_cv9em_b_buyk_qj_mej_lg_fsvg_tr_b_kmm_uqijx_sg_y', ) - .join('_') + .join('_'), ); t.is( decamelize(longString, {separator: '!'}), - new Array(times) + Array.from({length: times}) .fill( - 'lb8!sv!aar!mshc!nvfxjg!g!cgfot3!az!azysux!rp!g9!xfp!l!cz89!te!wq!ad3!t!uo64!k45!vh2!mfj!l!yhztt4!lq!yzr!eb!tpx7g!gc!g4!t8ue!k!pm6!vra!x!kt!ul!jdnc!f!qh!e!qf!c!rw!wg!nscd!fe6!ute!av!n7!nze4!qy4hv!zu!klx5!yioh!gpv!nz!ut!l!gen3!wp2jot8!veprzy!x!qmi!kdxdxr!e!res!s!rg!swen!cz!xzp!ser!yu!ef!ap!vbju!djz9k!gmrxfrzq!vy!bdd!gf!y9!e!rqtx!h!qx!pw65!tt!eo3dgwhcuhv!c3d!my!rj6j!waon!kb3!pqtv27v!rv5!mg!yb5mgv!ce55o!ctbg9y!as!paw2!kq!y!vz3am!bge9!hgg!ez!xj!ghw!s!xjk!l7j!u!yk3!wj!q!ubw!vn!zn!hk!h3!p9!mpv!m98!dt!tn!ga!yf!k5!tj!d8!y5o!xpr!jmd!c!hzh!byboa!w2o!rj2!ft7dx!gkx!ls2s7qs!qs8!fs!jh!vc!yrm!vh!ra6th5!ciz!hsxk7vr5!d3!k!ysfsnr92!amt!r4!le!ram7!cv9em!b!buyk!qj!mej!lg!fsvg!tr!b!kmm!uqijx!sg!y' + 'lb8!sv!aar!mshc!nvfxjg!g!cgfot3!az!azysux!rp!g9!xfp!l!cz89!te!wq!ad3!t!uo64!k45!vh2!mfj!l!yhztt4!lq!yzr!eb!tpx7g!gc!g4!t8ue!k!pm6!vra!x!kt!ul!jdnc!f!qh!e!qf!c!rw!wg!nscd!fe6!ute!av!n7!nze4!qy4hv!zu!klx5!yioh!gpv!nz!ut!l!gen3!wp2jot8!veprzy!x!qmi!kdxdxr!e!res!s!rg!swen!cz!xzp!ser!yu!ef!ap!vbju!djz9k!gmrxfrzq!vy!bdd!gf!y9!e!rqtx!h!qx!pw65!tt!eo3dgwhcuhv!c3d!my!rj6j!waon!kb3!pqtv27v!rv5!mg!yb5mgv!ce55o!ctbg9y!as!paw2!kq!y!vz3am!bge9!hgg!ez!xj!ghw!s!xjk!l7j!u!yk3!wj!q!ubw!vn!zn!hk!h3!p9!mpv!m98!dt!tn!ga!yf!k5!tj!d8!y5o!xpr!jmd!c!hzh!byboa!w2o!rj2!ft7dx!gkx!ls2s7qs!qs8!fs!jh!vc!yrm!vh!ra6th5!ciz!hsxk7vr5!d3!k!ysfsnr92!amt!r4!le!ram7!cv9em!b!buyk!qj!mej!lg!fsvg!tr!b!kmm!uqijx!sg!y', ) - .join('!') + .join('!'), ); t.is( decamelize(longString, { separator: '!', - preserveConsecutiveUppercase: true + preserveConsecutiveUppercase: true, }), - new Array(times) + Array.from({length: times}) .fill( - 'lb8!sv!AAR!mshc!nvfxjg!G!cgfot3!AZ!azysux!rp!G9!xfp!L!cz89!te!wq!ad3!T!uo64!K45!VH2!mfj!L!yhztt4!LQ!yzr!eb!tpx7g!gc!G4!T8ue!K!pm6!vra!X!kt!UL!jdnc!F!qh!E!qf!C!rw!WG!nscd!fe6!UTE!av!N7!nze4!qy4hv!zu!KLX5!yioh!gpv!NZ!ut!L!gen3!WP2jot8!veprzy!X!qmi!kdxdxr!E!res!S!rg!SWEN!cz!XZP!ser!yu!ef!ap!vbju!DJZ9k!GMRXFRZQ!vy!BDD!gf!Y9!E!rqtx!H!qx!pw65!tt!eo3dgwhcuhv!C3d!my!RJ6j!waon!KB3!pqtv27v!rv5!mg!yb5mgv!CE55o!CTBG9y!AS!paw2!kq!Y!vz3am!bge9!hgg!ez!XJ!ghw!S!xjk!L7j!U!yk3!wj!Q!ubw!vn!ZN!hk!H3!P9!mpv!M98!dt!tn!GA!yf!K5!tj!D8!Y5o!XPR!jmd!C!hzh!byboa!W2o!RJ2!ft7dx!GKX!ls2s7qs!qs8!fs!JH!vc!yrm!VH!ra6th5!ciz!HSXK7vr5!D3!K!ysfsnr92!amt!R4!LE!ram7!CV9em!B!buyk!QJ!mej!LG!fsvg!tr!B!kmm!uqijx!sg!' + 'lb8!sv!AAR!mshc!nvfxjg!G!cgfot3!AZ!azysux!rp!G9!xfp!L!cz89!te!wq!ad3!T!uo64!K45!VH2!mfj!L!yhztt4!LQ!yzr!eb!tpx7g!gc!G4!T8ue!K!pm6!vra!X!kt!UL!jdnc!F!qh!E!qf!C!rw!WG!nscd!fe6!UTE!av!N7!nze4!qy4hv!zu!KLX5!yioh!gpv!NZ!ut!L!gen3!WP2jot8!veprzy!X!qmi!kdxdxr!E!res!S!rg!SWEN!cz!XZP!ser!yu!ef!ap!vbju!DJZ9k!GMRXFRZQ!vy!BDD!gf!Y9!E!rqtx!H!qx!pw65!tt!eo3dgwhcuhv!C3d!my!RJ6j!waon!KB3!pqtv27v!rv5!mg!yb5mgv!CE55o!CTBG9y!AS!paw2!kq!Y!vz3am!bge9!hgg!ez!XJ!ghw!S!xjk!L7j!U!yk3!wj!Q!ubw!vn!ZN!hk!H3!P9!mpv!M98!dt!tn!GA!yf!K5!tj!D8!Y5o!XPR!jmd!C!hzh!byboa!W2o!RJ2!ft7dx!GKX!ls2s7qs!qs8!fs!JH!vc!yrm!VH!ra6th5!ciz!HSXK7vr5!D3!K!ysfsnr92!amt!R4!LE!ram7!CV9em!B!buyk!QJ!mej!LG!fsvg!tr!B!kmm!uqijx!sg!', ) - .join('Y!') + 'y' + .join('Y!') + 'y', ); });