@danielhaim/titlecaser 1.2.54 → 1.2.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,8 +28,8 @@ Transform any text to proper title case format using popular style guides such a
28
28
  + [Basic Usage](#basic-usage)
29
29
  + [Customizing Word Replacements Method](#customizing-word-replacements-method)
30
30
  + [Customizing TitleCaser](#customizing-titlecaser)
31
- + [TitleCaser With Default Word Replacement](#titlecaser-with-default-word-replacement)
32
- + [TitleCaser With Possessive Noun and a Colon](#titlecaser-with-possessive-noun-and-a-colon)
31
+ + [TitleCaser with Default Word Replacement](#titlecaser-with-default-word-replacement)
32
+ + [TitleCaser with Possessive Noun and a Colon](#titlecaser-with-possessive-noun-and-a-colon)
33
33
  * [Build Process](#build-process)
34
34
  * [Test](#test)
35
35
  * [Resources](#resources)
@@ -130,6 +130,7 @@ function applyTitleCaseToH2Elements(options = { style: "apa" }) {
130
130
 
131
131
  applyTitleCaseToH2Elements();
132
132
  ```
133
+
133
134
  ## Options
134
135
 
135
136
  The `{options}` parameter is an object that contains the settings for the conversion process.
@@ -140,6 +141,7 @@ The `{options}` parameter is an object that contains the settings for the conver
140
141
  - `shortPrepositionsList` relates to the words that should be treated as short prepositions in title case.
141
142
  - `neverCapitalizedList` contains the words that should never be capitalized in title case.
142
143
  - `wordReplacementsList` is a map of terms that will be replaced during the title case conversion process.
144
+ - `smartQuotes` boolean value that determines whether quotes should be replaced with smart quotes.
143
145
 
144
146
  ## Methods
145
147
 
@@ -147,6 +149,7 @@ The `{options}` parameter is an object that contains the settings for the conver
147
149
  - `removeReplaceTerm(term: string)`: Removes a replaced term from the `wordReplacementsList` array in the option object of the `TitleCaser` instance. Throws an error if the term is not found in the array, otherwise removes it from the array and updates the option object.
148
150
  - `addReplaceTerm(term: string, replacement: string)`: Adds a new term to the `wordReplacementsList` array in the options object of the TitleCaser instance. The method takes two string arguments: term specifies the word to be replaced, and replacement specifies the replacement for the word. If the term already exists in the array, the method updates its replacement value. Otherwise, it adds a new object with the term and replacement to the array. The method then updates the wordReplacementsList property in the object.
149
151
  - `setStyle(style: string)`: Sets the style option in the object of the TitleCaser instance. The method takes a string argument style that specifies the style to use for the title casing. If the argument is not a string, the method throws a TypeError. Otherwise, it updates the style option in the object.
152
+ - `smartQuotes(smartQuotes: boolean)`: Specifies whether to replace straight quotes with smart quotes during title casing. Provide a boolean argument smartQuotes to enable or disable this feature.
150
153
 
151
154
  ## Examples
152
155
 
@@ -200,7 +203,7 @@ const options = {
200
203
  // Instantiate a new TitleCaser object with the options
201
204
  const titleCaser = new TitleCaser(options);
202
205
 
203
- // Set the input string to test
206
+ // Set the input string to be tested
204
207
  const input = "the basics of nodejs development with mongodb";
205
208
 
206
209
  // Set the expected output
@@ -210,7 +213,7 @@ const expectedOutput = "The Basics of Node.js Development with MongoDB";
210
213
  const actualOutput = titleCaser.toTitleCase(input);
211
214
  ```
212
215
 
213
- ### TitleCaser With Default Word Replacement
216
+ ### TitleCaser with Default Word Replacement
214
217
 
215
218
  The example below demonstrates how to use the TitleCaser class to convert a string to a title case with AP style formatting, including hyphenated words and word/brand replacement.
216
219
 
@@ -220,7 +223,7 @@ import "./path/to/@danielhaim/titlecaser";
220
223
  // Instantiate a new TitleCaser object with AP style formatting
221
224
  const titleCaser = new TitleCaser({ style: 'ap' });
222
225
 
223
- // Set the input string to test
226
+ // Set the input string to be tested
224
227
  const input = 'nodejs development on aws: an in-depth tutorial on server-side javascript deployment';
225
228
 
226
229
  // Set the expected output
@@ -230,7 +233,7 @@ const expectedOutput = 'Node.js Development on AWS: An In-depth Tutorial on Serv
230
233
  const actualOutput = titleCaser.toTitleCase(input);
231
234
  ```
232
235
 
233
- ### TitleCaser With Possessive Noun and a Colon
236
+ ### TitleCaser with Possessive Noun and a Colon
234
237
 
235
238
  The example below demonstrates how to use the TitleCaser class to convert a string to title case with AP style formatting, including a possessive noun and a colon.
236
239
 
@@ -240,7 +243,7 @@ import "./path/to/@danielhaim/titlecaser";
240
243
  // Instantiate a new TitleCaser object with AP style formatting
241
244
  const titleCaser = new TitleCaser({ style: "ap" });
242
245
 
243
- // Set the input string to test
246
+ // Set the input string to be tested
244
247
  const input = "the iphone's impact on modern communication: a sociolinguistic analysis";
245
248
 
246
249
  // Set the expected output
@@ -250,6 +253,29 @@ const expectedOutput = "The iPhone's Impact on Modern Communication: A Socioling
250
253
  const actualOutput = titleCaser.toTitleCase(input);
251
254
  ```
252
255
 
256
+ ### TitleCaser with Smart Quotes
257
+
258
+ The example below demonstrates how to use the TitleCaser with smart quotes.
259
+
260
+ ```js
261
+ import "./path/to/@danielhaim/titlecaser";
262
+
263
+ // Instantiate a new TitleCaser object with AP style formatting and smart quotes enabled
264
+ const titleCaser = new TitleCaser({
265
+ style: 'ap',
266
+ smartQuotes: true
267
+ });
268
+
269
+ // Set the input string to be tested
270
+ const input = '"Never underestimate the power O\' persistence,"';
271
+
272
+ // Set the expected output
273
+ const expectedOutput = '“Never Underestimate the Power O’ Persistence,”';
274
+
275
+ // Call the toTitleCase method and store the result in actualOutput
276
+ const actualOutput = titleCaser.toTitleCase(input);
277
+ ```
278
+
253
279
  ## Build Process
254
280
 
255
281
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielhaim/titlecaser",
3
- "version": "1.2.54",
3
+ "version": "1.2.57",
4
4
  "description": "Converts a string to title case with multiple style options, ability to ignore certain words, and handle acronyms",
5
5
  "keywords": [
6
6
  "title case",
package/src/TitleCaser.js CHANGED
@@ -9,141 +9,141 @@ import {
9
9
  import { TitleCaserUtils } from "./TitleCaserUtils.js";
10
10
 
11
11
  export class TitleCaser {
12
- constructor ( options = {} ) {
12
+ constructor(options = {}) {
13
13
  this.options = options;
14
14
  this.wordReplacementsList = wordReplacementsList;
15
15
  }
16
-
17
- toTitleCase ( str ) {
16
+
17
+ toTitleCase(str) {
18
18
  try {
19
19
  // If input is empty, throw an error.
20
- if ( str.trim ().length === 0 ) throw new TypeError ( "Invalid input: input must not be empty." );
21
-
20
+ if (str.trim().length === 0) throw new TypeError("Invalid input: input must not be empty.");
21
+
22
22
  // If input is not a string, throw an error.
23
- if ( typeof str !== 'string' ) throw new TypeError ( "Invalid input: input must be a string." );
24
-
23
+ if (typeof str !== 'string') throw new TypeError("Invalid input: input must be a string.");
24
+
25
25
  // If options is not an object, throw an error.
26
- if ( typeof this.options !== "undefined" && typeof this.options !== "object" ) throw new TypeError ( "Invalid options: options must be an object." );
27
-
26
+ if (typeof this.options !== "undefined" && typeof this.options !== "object") throw new TypeError("Invalid options: options must be an object.");
27
+
28
28
  const {
29
29
  style = "ap",
30
30
  neverCapitalize = [],
31
31
  replaceTermList = wordReplacementsList,
32
- smartQuotes = false // Set to false by default
32
+ smartQuotes = false // Set to false by default
33
33
  } = this.options;
34
34
 
35
35
 
36
- const ignoreList = [ "nl2br", ...neverCapitalize ];
36
+ const ignoreList = ["nl2br", ...neverCapitalize];
37
37
  const {
38
38
  articlesList,
39
39
  shortConjunctionsList,
40
40
  shortPrepositionsList,
41
41
  neverCapitalizedList,
42
42
  replaceTerms,
43
- smartQuotes: mergedSmartQuotes // Rename for clarity
44
- } = TitleCaserUtils.getTitleCaseOptions ( this.options, commonAbbreviationList, wordReplacementsList );
45
-
43
+ smartQuotes: mergedSmartQuotes // Rename for clarity
44
+ } = TitleCaserUtils.getTitleCaseOptions(this.options, commonAbbreviationList, wordReplacementsList);
45
+
46
46
  // Prerocess the replaceTerms array to make it easier to search for.
47
- const replaceTermsArray = replaceTermList.map ( term => Object.keys ( term )[0].toLowerCase () );
47
+ const replaceTermsArray = replaceTermList.map(term => Object.keys(term)[0].toLowerCase());
48
48
  // Create an object from the replaceTerms array to make it easier to search for.
49
- const replaceTermObj = Object.fromEntries ( replaceTermList.map (
50
- term => [ Object.keys ( term )[0].toLowerCase (), Object.values ( term )[0] ]
51
- ) );
52
-
49
+ const replaceTermObj = Object.fromEntries(replaceTermList.map(
50
+ term => [Object.keys(term)[0].toLowerCase(), Object.values(term)[0]]
51
+ ));
52
+
53
53
  const map = {
54
54
  '&': '&',
55
55
  '<': '&lt;',
56
56
  '>': '&gt;',
57
- // '\u2018': '\u2019', // Smart single quote
58
- // '\u201C': '\u201D', // Smart double quote
57
+ // '\u2018': '\u2019', // Smart single quote
58
+ // '\u201C': '\u201D', // Smart double quote
59
59
  '"': '&quot;',
60
60
  "'": '&#039;'
61
61
  };
62
-
62
+
63
63
  // Remove extra spaces and replace <br> tags with a placeholder.
64
- let inputString = str.trim ();
64
+ let inputString = str.trim();
65
65
 
66
66
  // Replace <br> and <br /> tags with a placeholder.
67
67
  inputString = inputString.replace(/<\s*br\s*\/?\s*>/gi, " nl2br ");
68
68
 
69
69
  // Remove extra spaces and replace <br> tags with a placeholder.
70
- inputString = inputString.replace ( / {2,}/g, ( match ) => match.slice ( 0, 1 ) );
70
+ inputString = inputString.replace(/ {2,}/g, (match) => match.slice(0, 1));
71
71
 
72
72
 
73
73
  // Split the string into an array of words.
74
- const words = inputString.split ( " " );
75
-
76
- const wordsInTitleCase = words.map ( ( word, i ) => {
74
+ const words = inputString.split(" ");
75
+
76
+ const wordsInTitleCase = words.map((word, i) => {
77
77
  switch (true) {
78
- case TitleCaserUtils.isWordAmpersand ( word ):
78
+ case TitleCaserUtils.isWordAmpersand(word):
79
79
  // if the word is an ampersand, return it as is.
80
80
  return word;
81
- case TitleCaserUtils.hasHtmlBreak ( word ):
81
+ case TitleCaserUtils.hasHtmlBreak(word):
82
82
  // If the word is a <br> tag, return it as is.
83
83
  return word;
84
- case TitleCaserUtils.isWordIgnored ( word, ignoreList ):
84
+ case TitleCaserUtils.isWordIgnored(word, ignoreList):
85
85
  // If the word is in the ignore list, return it as is.
86
86
  return word;
87
- case replaceTermsArray.includes ( word.toLowerCase () ):
87
+ case replaceTermsArray.includes(word.toLowerCase()):
88
88
  // If the word is in the replaceTerms array, return the replacement.
89
- return replaceTermObj[word.toLowerCase ()];
90
- case TitleCaserUtils.isWordInArray ( word, correctTitleCasingList ):
89
+ return replaceTermObj[word.toLowerCase()];
90
+ case TitleCaserUtils.isWordInArray(word, correctTitleCasingList):
91
91
  // If the word is in the correctTitleCasingList array, return the correct casing.
92
- return TitleCaserUtils.correctTerm ( word, correctTitleCasingList );
93
- case TitleCaserUtils.hasSuffix ( word, style ):
92
+ return TitleCaserUtils.correctTerm(word, correctTitleCasingList);
93
+ case TitleCaserUtils.hasSuffix(word, style):
94
94
  // If the word has a suffix, return the correct casing.
95
- return TitleCaserUtils.correctSuffix ( word, correctTitleCasingList );
96
- case TitleCaserUtils.hasHyphen ( word ):
95
+ return TitleCaserUtils.correctSuffix(word, correctTitleCasingList);
96
+ case TitleCaserUtils.hasHyphen(word):
97
97
  // If the word has a hyphen, return the correct casing.
98
- return TitleCaserUtils.correctTermHyphenated ( word, style );
99
- case TitleCaserUtils.hasUppercaseIntentional ( word ):
98
+ return TitleCaserUtils.correctTermHyphenated(word, style);
99
+ case TitleCaserUtils.hasUppercaseIntentional(word):
100
100
  // If the word has an intentional uppercase letter, return the correct casing.
101
101
  return word;
102
- case TitleCaserUtils.isShortWord ( word, style ) && i !== 0:
102
+ case TitleCaserUtils.isShortWord(word, style) && i !== 0:
103
103
  // If the word is a short word, return the correct casing.
104
- return (i > 0 && TitleCaserUtils.endsWithSymbol ( words[i - 1],
105
- [ ':', '?', '!', '.' ] )) ? word.charAt ( 0 ).toUpperCase () + word.slice ( 1 ) : word.toLowerCase ();
106
- case TitleCaserUtils.endsWithSymbol ( word ):
104
+ return (i > 0 && TitleCaserUtils.endsWithSymbol(words[i - 1],
105
+ [':', '?', '!', '.'])) ? word.charAt(0).toUpperCase() + word.slice(1) : word.toLowerCase();
106
+ case TitleCaserUtils.endsWithSymbol(word):
107
107
  // If the word ends with a symbol, return the correct casing.
108
- const splitWord = word.split ( /([.,\/#!$%\^&\*;:{}=\-_`~()])/g );
109
- const processedWords = splitWord.map ( ( splitWord, j ) => {
108
+ const splitWord = word.split(/([.,\/#!$%\^&\*;:{}=\-_`~()])/g);
109
+ const processedWords = splitWord.map((splitWord, j) => {
110
110
  // If the word is in the correctTitleCasingList array, return the correct casing.
111
- if ( TitleCaserUtils.isWordInArray ( splitWord, correctTitleCasingList ) ) return TitleCaserUtils.correctTerm ( splitWord, correctTitleCasingList );
111
+ if (TitleCaserUtils.isWordInArray(splitWord, correctTitleCasingList)) return TitleCaserUtils.correctTerm(splitWord, correctTitleCasingList);
112
112
  // Else return the word with the correct casing.
113
- else return (j > 0 && TitleCaserUtils.endsWithSymbol ( splitWord )) ? splitWord.charAt ( 0 )
114
- .toUpperCase () + splitWord.slice ( 1 ) : splitWord.charAt ( 0 )
115
- .toUpperCase () + splitWord.slice ( 1 );
116
- } );
113
+ else return (j > 0 && TitleCaserUtils.endsWithSymbol(splitWord)) ? splitWord.charAt(0)
114
+ .toUpperCase() + splitWord.slice(1) : splitWord.charAt(0)
115
+ .toUpperCase() + splitWord.slice(1);
116
+ });
117
117
  // Join the processed words and return them.
118
- return processedWords.join ( "" );
119
- case TitleCaserUtils.startsWithSymbol ( word ):
118
+ return processedWords.join("");
119
+ case TitleCaserUtils.startsWithSymbol(word):
120
120
  // If the word starts with a symbol, return the correct casing.
121
- return !TitleCaserUtils.isWordInArray ( word, correctTitleCasingList ) ? word : TitleCaserUtils.correctTerm ( word );
122
- case TitleCaserUtils.hasRomanNumeral ( word ):
121
+ return !TitleCaserUtils.isWordInArray(word, correctTitleCasingList) ? word : TitleCaserUtils.correctTerm(word);
122
+ case TitleCaserUtils.hasRomanNumeral(word):
123
123
  // If the word has a roman numeral, return the correct casing.
124
- return word.toUpperCase ();
125
- case TitleCaserUtils.hasNumbers ( word ):
124
+ return word.toUpperCase();
125
+ case TitleCaserUtils.hasNumbers(word):
126
126
  // If the word has numbers, return the correct casing.
127
127
  return word;
128
- default:
128
+ default:
129
129
  // Default to returning the word with the correct casing.
130
- return word.charAt ( 0 )
131
- .toUpperCase () + word.slice ( 1 )
132
- .toLowerCase ();
130
+ return word.charAt(0)
131
+ .toUpperCase() + word.slice(1)
132
+ .toLowerCase();
133
133
  }
134
- } );
135
-
134
+ });
135
+
136
136
  // Join the words in the array into a string.
137
- inputString = wordsInTitleCase.join ( " " );
138
-
139
- for ( const phrase of correctPhraseCasingList ) {
137
+ inputString = wordsInTitleCase.join(" ");
138
+
139
+ for (const phrase of correctPhraseCasingList) {
140
140
  // If the phrase is in the input string, replace it with the correct casing.
141
- if ( inputString.toLowerCase ()
142
- .includes ( phrase.toLowerCase () ) ) {
143
- inputString = inputString.replace ( new RegExp ( phrase, 'gi' ), phrase );
141
+ if (inputString.toLowerCase()
142
+ .includes(phrase.toLowerCase())) {
143
+ inputString = inputString.replace(new RegExp(phrase, 'gi'), phrase);
144
144
  }
145
145
  }
146
-
146
+
147
147
  // Replace the nl2br placeholder with <br> tags.
148
148
  inputString = inputString.replace(/nl2br/gi, "<br />");
149
149
 
@@ -151,86 +151,86 @@ export class TitleCaser {
151
151
  // Refer to: https://github.com/danielhaim1/TitleCaser/issues/4
152
152
  if (smartQuotes) {
153
153
  inputString = TitleCaserUtils.convertQuotesToCurly(inputString);
154
- }
155
-
154
+ }
155
+
156
156
  // Return the string.
157
157
  return inputString;
158
- } catch ( error ) {
159
- throw new Error ( error );
158
+ } catch (error) {
159
+ throw new Error(error);
160
160
  }
161
161
  }
162
-
163
- setReplaceTerms ( terms ) {
164
- if ( typeof terms !== 'object' ) {
165
- throw new TypeError ( 'Invalid argument: replace terms must be an object.' );
162
+
163
+ setReplaceTerms(terms) {
164
+ if (typeof terms !== 'object') {
165
+ throw new TypeError('Invalid argument: replace terms must be an object.');
166
166
  }
167
-
167
+
168
168
  // Add the new replace terms to the wordReplacementsList array
169
- Object.entries ( terms ).forEach ( ( [ term, replacement ] ) => {
170
- const index = wordReplacementsList.findIndex ( obj => obj[term] );
171
- if ( index !== -1 ) {
169
+ Object.entries(terms).forEach(([term, replacement]) => {
170
+ const index = wordReplacementsList.findIndex(obj => obj[term]);
171
+ if (index !== -1) {
172
172
  // If the term already exists in the array, update the replacement value
173
173
  wordReplacementsList[index][term] = replacement;
174
174
  } else {
175
175
  // If the term doesn't exist in the array, add a new object with the term and replacement
176
- wordReplacementsList.push ( { [term]: replacement } );
176
+ wordReplacementsList.push({ [term]: replacement });
177
177
  }
178
- } );
179
-
178
+ });
179
+
180
180
  // Log the updated wordReplacementsList array
181
181
  // console.log(wordReplacementsList);
182
-
182
+
183
183
  // Update the replace terms option
184
184
  this.options.wordReplacementsList = wordReplacementsList;
185
185
  }
186
-
187
- addReplaceTerm ( term, replacement ) {
188
- if ( typeof term !== 'string' || typeof replacement !== 'string' ) {
189
- throw new TypeError ( 'Invalid argument: term and replacement must be strings.' );
186
+
187
+ addReplaceTerm(term, replacement) {
188
+ if (typeof term !== 'string' || typeof replacement !== 'string') {
189
+ throw new TypeError('Invalid argument: term and replacement must be strings.');
190
190
  }
191
-
192
- const index = this.wordReplacementsList.findIndex ( obj => obj[term] );
193
-
194
- if ( index !== -1 ) {
191
+
192
+ const index = this.wordReplacementsList.findIndex(obj => obj[term]);
193
+
194
+ if (index !== -1) {
195
195
  // If the term already exists in the array, update the replacement value
196
196
  this.wordReplacementsList[index][term] = replacement;
197
197
  } else {
198
198
  // If the term doesn't exist in the array, add a new object with the term and replacement
199
- this.wordReplacementsList.push ( { [term]: replacement } );
199
+ this.wordReplacementsList.push({ [term]: replacement });
200
200
  }
201
-
201
+
202
202
  // Update the replace terms option
203
203
  this.options.wordReplacementsList = this.wordReplacementsList;
204
204
  }
205
-
206
- removeReplaceTerm ( term ) {
207
- if ( typeof term !== 'string' ) {
208
- throw new TypeError ( 'Invalid argument: term must be a string.' );
205
+
206
+ removeReplaceTerm(term) {
207
+ if (typeof term !== 'string') {
208
+ throw new TypeError('Invalid argument: term must be a string.');
209
209
  }
210
-
210
+
211
211
  // Find the index of the term in the wordReplacementsList array
212
- const index = this.wordReplacementsList.findIndex ( obj => Object.keys ( obj )[0] === term );
213
-
212
+ const index = this.wordReplacementsList.findIndex(obj => Object.keys(obj)[0] === term);
213
+
214
214
  // If the term is not found in the array, throw an error
215
- if ( index === -1 ) {
216
- throw new Error ( `Term '${ term }' not found in word replacements list.` );
215
+ if (index === -1) {
216
+ throw new Error(`Term '${term}' not found in word replacements list.`);
217
217
  }
218
-
218
+
219
219
  // Remove the term from the array
220
- this.wordReplacementsList.splice ( index, 1 );
221
-
220
+ this.wordReplacementsList.splice(index, 1);
221
+
222
222
  // Log the updated wordReplacementsList array
223
223
  // console.log(this.wordReplacementsList);
224
-
224
+
225
225
  // Update the replace terms option
226
226
  this.options.wordReplacementsList = this.wordReplacementsList;
227
227
  }
228
-
229
- setStyle ( style ) {
230
- if ( typeof style !== 'string' ) {
231
- throw new TypeError ( 'Invalid argument: style must be a string.' );
228
+
229
+ setStyle(style) {
230
+ if (typeof style !== 'string') {
231
+ throw new TypeError('Invalid argument: style must be a string.');
232
232
  }
233
-
233
+
234
234
  this.options.style = style;
235
235
  }
236
236
  }