1
1
export const STOP_WORDS =
2
- 'a an and at but by for in nor of on or so the to up yet' ;
2
+ 'a an and at but by for in nor of on or the to up yet' ;
3
3
4
- export const SEPARATORS = / ( \s + | [ - ‑ – — , : ; ! ? ( ) “ ” " ] ) / ;
4
+ // Matches a colon (:) and 0+ white spaces following after
5
+ // Matches 1+ white spaces
6
+ // Matches special chars (i.e. hyphens, quotes, etc)
7
+ export const SEPARATORS = / ( : \s * | \s + | [ - ‑ – — , : ; ! ? ( ) “ ” ' ‘ " ] ) / ; // Include curly quotes as separators
5
8
6
9
export const stop = STOP_WORDS . split ( ' ' ) ;
7
10
11
+ /**
12
+ * Format a string: Capture the letter after an apostrophe at the end of a
13
+ * sentence (without requiring a space) or with a white space following the letter.
14
+ * Lowercase the captured letter & return the formatted string.
15
+ * @param input
16
+ * @returns {string }
17
+ */
18
+ export const lowercaseAfterApostrophe = ( input : string ) : string => {
19
+ // matches a char (num or letter) right after an apostrophe,
20
+ // only if the apostrophe is preceded by a char & is followed
21
+ // by a space or end of the str.
22
+ const regex = / (?< = \w ) ' ( \w ) (? = \s | $ ) / g;
23
+
24
+ return input . replace ( regex , ( match , p1 ) => {
25
+ return `'${ p1 . toLowerCase ( ) } ` ; // Replace with the apostrophe and the lowercase letter
26
+ } ) ;
27
+ } ;
28
+
8
29
/**
9
30
* Capitalize first character for string
10
31
*
@@ -30,19 +51,36 @@ export const applyApTitleCase = (value: string): string => {
30
51
if ( ! value ) {
31
52
return '' ;
32
53
}
33
- // split by separators, check if word is first or last
34
- // or not blacklisted, then capitalize
35
- return value
36
- . split ( SEPARATORS )
54
+
55
+ // Split and filter empty strings
56
+ // Boolean here acts as a callback, evaluates each word:
57
+ // If it's a non-empty string, keep the word in the array;
58
+ // If it's an empty string (or falsy), remove from array.
59
+ const allWords = value . split ( SEPARATORS ) . filter ( Boolean ) ; // Split and filter empty strings
60
+
61
+ const result = allWords
37
62
. map ( ( word , index , all ) => {
63
+ const isAfterColon = index > 0 && all [ index - 1 ] . trim ( ) === ':' ;
64
+
65
+ const isAfterQuote =
66
+ index > 0 &&
67
+ ( allWords [ index - 1 ] === "'" ||
68
+ allWords [ index - 1 ] === '"' ||
69
+ allWords [ index - 1 ] === '\u2018' || // Opening single quote ’
70
+ allWords [ index - 1 ] === '\u201C' ) ; // Opening double quote “
71
+
38
72
if (
39
- index === 0 ||
40
- index === all . length - 1 ||
41
- ! stop . includes ( word . toLowerCase ( ) )
73
+ index === 0 || // first word
74
+ index === all . length - 1 || // last word
75
+ isAfterColon || // capitalize the first word after a colon
76
+ isAfterQuote || // capitalize the first word after a quote
77
+ ! stop . includes ( word . toLowerCase ( ) ) // not a stop word
42
78
) {
43
79
return capitalize ( word ) ;
44
80
}
81
+
45
82
return word . toLowerCase ( ) ;
46
83
} )
47
- . join ( '' ) ;
84
+ . join ( '' ) ; // join without additional spaces
85
+ return lowercaseAfterApostrophe ( result ) ;
48
86
} ;
0 commit comments