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

Move to ESM #33

Merged
merged 6 commits into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
61 changes: 29 additions & 32 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}

/**
Expand All @@ -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'
Expand All @@ -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;
26 changes: 10 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
'use strict';

const handlePreserveConsecutiveUppercase = (decamelized, separator) => {
// Lowercase all single uppercase characters. As we
// want to preserve uppercase sequences, we cannot
// simply lowercase the separated string at the end.
// `data_For_USACounties` → `data_for_USACounties`
decamelized = decamelized.replace(
/((?<![\p{Uppercase_Letter}\d])[\p{Uppercase_Letter}\d](?![\p{Uppercase_Letter}\d]))/gu,
$0 => {
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`',
);
}

Expand All @@ -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) {
Expand All @@ -59,7 +53,7 @@ module.exports = (
return decamelized
.replace(
/(\p{Uppercase_Letter}+)(\p{Uppercase_Letter}\p{Lowercase_Letter}+)/gu,
replacement
replacement,
)
.toLowerCase();
};
}
4 changes: 2 additions & 2 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {expectType} from 'tsd';
import decamelize = require('.');
import decamelize from './index.js';

expectType<string>(decamelize('unicornRainbow'));
expectType<string>(decamelize('unicornRainbow', {separator: '-'}));
expectType<string>(decamelize('unicornRainbow', {
separator: '-',
preserveConsecutiveUppercase: true
preserveConsecutiveUppercase: true,
}));
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
"email": "[email protected]",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=10"
"node": ">=12.17"
LitoMore marked this conversation as resolved.
Show resolved Hide resolved
},
"scripts": {
"test": "xo && ava && tsd"
Expand All @@ -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"
}
}
8 changes: 4 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
## Install

```
LitoMore marked this conversation as resolved.
Show resolved Hide resolved
$ npm install decamelize
npm install decamelize
```

## Usage

```js
const decamelize = require('decamelize');
import decamelize from 'decamelize';

decamelize('unicornRainbow');
//=> 'unicorn_rainbow'
Expand Down Expand Up @@ -47,7 +47,7 @@ Default: `'_'`
Character or string inserted to separate words in `string`.

```js
cosnt decamelize = require('decamelize');
import decamelize from 'decamelize';

decamelize('unicornRainbow');
//=> 'unicorn_rainbow'
Expand All @@ -64,7 +64,7 @@ Default: `false`
Preserve sequences of uppercase characters.

```js
const decamelize = require('decamelize');
import decamelize from 'decamelize';

decamelize('testGUILabel');
//=> 'test_gui_label'
Expand Down
66 changes: 33 additions & 33 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import test from 'ava';
import decamelize from '.';
import decamelize from './index.js';

test('decamelize', t => {
t.is(decamelize(''), '');
Expand All @@ -18,7 +18,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 š',
);
});

Expand All @@ -38,101 +38,101 @@ 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',
);
});

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',
);
});