1
- const SNAKE_CASE_SEPARATOR = '_' ;
1
+ const snakeCaseSeparator = '_' ;
2
+
3
+ const separators = new Set ( [
4
+ '' , // represents all whitespaces (trim the character before performing the membership check)
5
+ snakeCaseSeparator ,
6
+ '-' ,
7
+ '.' ,
8
+ ] ) ;
9
+
10
+ const isSeparator = ( ch : string ) => separators . has ( ch . trim ( ) ) ;
11
+
12
+ const isUpperCase = ( ch : string ) =>
13
+ ch === ch . toUpperCase ( ) && ch !== ch . toLowerCase ( ) ;
14
+
15
+ const isNotEmpty = ( arr : readonly unknown [ ] ) => arr . length > 0 ;
16
+
17
+ const isTopSnakeCaseSeparator = ( chs : readonly string [ ] ) =>
18
+ chs . at ( - 1 ) === snakeCaseSeparator ;
2
19
3
20
/**
4
21
* Converts a string to snake case.
@@ -9,32 +26,29 @@ const SNAKE_CASE_SEPARATOR = '_';
9
26
*/
10
27
export function snakeCase ( input : string ) : string {
11
28
const res : string [ ] = [ ] ;
12
- let wasPrevChUpperCase = false ;
29
+ let wasPrevUpperCase = false ;
13
30
for ( const ch of input . trimStart ( ) ) {
14
- const lowerCaseCh = ch . toLowerCase ( ) ;
15
- const isWhiteSpace = ch . trim ( ) === '' ;
16
- const isSeparator =
17
- isWhiteSpace || ch === SNAKE_CASE_SEPARATOR || ch === '-' || ch === '.' ;
18
- const isUpperCase = ch === ch . toUpperCase ( ) && ch !== lowerCaseCh ;
19
- if ( isSeparator ) {
20
- if ( res . length > 0 && res [ res . length - 1 ] !== SNAKE_CASE_SEPARATOR ) {
21
- res . push ( SNAKE_CASE_SEPARATOR ) ;
22
- }
23
- } else if ( isUpperCase ) {
31
+ const isCurUpperCase = isUpperCase ( ch ) ;
32
+ if ( isCurUpperCase ) {
24
33
if (
25
- res . length > 0 &&
26
- res [ res . length - 1 ] !== SNAKE_CASE_SEPARATOR &&
27
- ! wasPrevChUpperCase
34
+ isNotEmpty ( res ) &&
35
+ ! isTopSnakeCaseSeparator ( res ) &&
36
+ ! wasPrevUpperCase
28
37
) {
29
- res . push ( SNAKE_CASE_SEPARATOR ) ;
38
+ res . push ( snakeCaseSeparator ) ;
30
39
}
31
- res . push ( lowerCaseCh ) ;
32
- } else {
40
+ res . push ( ch . toLowerCase ( ) ) ;
41
+ } else if ( ! isSeparator ( ch ) ) {
42
+ // `ch` is a lowercase character
33
43
res . push ( ch ) ;
34
44
}
35
- wasPrevChUpperCase = isUpperCase ;
45
+ // `ch` is a separator
46
+ else if ( isNotEmpty ( res ) && ! isTopSnakeCaseSeparator ( res ) ) {
47
+ res . push ( snakeCaseSeparator ) ;
48
+ }
49
+ wasPrevUpperCase = isCurUpperCase ;
36
50
}
37
- if ( res . length > 0 && res [ res . length - 1 ] === SNAKE_CASE_SEPARATOR ) {
51
+ if ( isTopSnakeCaseSeparator ( res ) ) {
38
52
res . pop ( ) ;
39
53
}
40
54
return res . join ( '' ) ;
0 commit comments