@danielhaim/titlecaser 1.2.23
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/LICENSE +21 -0
- package/README.md +292 -0
- package/package.json +60 -0
- package/src/TitleCaseConsts.js +214 -0
- package/src/TitleCaser.js +220 -0
- package/src/index.js +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Daniel Haim
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# TitleCaser
|
|
2
|
+
|
|
3
|
+
Transform any text to proper title case format using popular style guides such as APA, AP, Chicago, NYT, Wikipedia, and British. Customize options to achieve greater flexibility and consistency.
|
|
4
|
+
|
|
5
|
+
## Demo
|
|
6
|
+
|
|
7
|
+
<a target="_blank" href="https://danielhaim1.github.io/titlecaser/"><img src="dist/demo.png" width="100%" height="auto"></a>
|
|
8
|
+
|
|
9
|
+
[](https://badge.fury.io/js/titlecaser)
|
|
10
|
+
[](https://www.npmjs.com/package/titlecaser)
|
|
11
|
+
[](https://opensource.org/licenses/MIT)
|
|
12
|
+
|
|
13
|
+
The Language Conventions and Style Module is a comprehensive library designed to help web content developers adhere to the latest style guides and English language conventions. It offers a wide range of features, including support for various style guides such as AP, APA, Chicago, NY Times, Wikipedia, and British styles, and customizable preferences to suit your specific needs.
|
|
14
|
+
|
|
15
|
+
To streamline workflow, the Language Conventions and Style Module is available in both browser and node environment versions and includes a command-line interface for building, testing, and minimizing the module. Additionally, it features a filter ability that allows users to ignore certain phrases containing short words, preventing the module from mistakenly flagging instances where short words are used as part of a larger term or phrase.
|
|
16
|
+
|
|
17
|
+
The module has been designed to handle various capitalization scenarios, including hyphenated words, prefixes, suffixes, reserved words, Roman numerals, proper nouns that contain lowercase letters, and words that require capitalization in specific contexts. This ensures that your content meets the appropriate style and formatting guidelines, regardless of the context. It also offers word replacement capabilities, as well as ignored phrases to create consistency in cases where certain terms may be capitalized differently depending on the context, such as converting variations of gOogle to Google, front-end to Frontend.
|
|
18
|
+
|
|
19
|
+
So whether you're developing web content for a major news organization or simply looking to improve your writing skills, the Language Conventions and Style Module is an essential tool that can help ensure your work is accurate, consistent, and conforms to the latest style guidelines.
|
|
20
|
+
|
|
21
|
+
## Key Features:
|
|
22
|
+
|
|
23
|
+
- Support for popular style guides and customizable preferences
|
|
24
|
+
- Advanced capitalization handling for suffixes, prefixes, hyphenated words, and reserved words
|
|
25
|
+
- Support for proper capitalization of Roman numerals and exclusion of specific words and phrases from title capitalization
|
|
26
|
+
- Word replacement capabilities for consistency in capitalization
|
|
27
|
+
Command-line interface for building, testing, and minimizing the module
|
|
28
|
+
- Pre-defined word lists for articles, conjunctions, prepositions, and uncapitalized words in titles
|
|
29
|
+
- Exclusion of common phrases from title capitalization
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
You can install this module via npm:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm i @danielhaim/titlecaser
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
The package can be imported and used in both Node.js and browser environments using the following syntax:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
// CommonJS
|
|
44
|
+
const { TitleCaser } = require('./path/to/titlecaser');
|
|
45
|
+
const TitleCaser = require('./path/to/titlecaser');
|
|
46
|
+
|
|
47
|
+
// ECMAScript
|
|
48
|
+
import { TitleCaser } from './TitleCaser';
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Here's an example of how to use the modulate function:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const options = {
|
|
55
|
+
style: 'chicago'
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const titleCaser = new TitleCaser(options);
|
|
59
|
+
|
|
60
|
+
const input = 'the book of life';
|
|
61
|
+
const output = titleCaser.toTitleCase(input);
|
|
62
|
+
|
|
63
|
+
console.log(output); // 'The Book of Life'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Usage in the Browser
|
|
67
|
+
|
|
68
|
+
The function can also be used in a browser environment by including the `titlecase.browser.js` script in your HTML file:
|
|
69
|
+
|
|
70
|
+
Here's an example of how to use the modulate function:
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<script src="./path/to/titlecase.browser.js"></script>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
After that, the `toTitleCase()` function can be accessed in your JavaScript code like this:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
const options = {
|
|
80
|
+
style: 'apa'
|
|
81
|
+
};
|
|
82
|
+
const input = 'the future of devops: the next era';
|
|
83
|
+
const output = input.toTitleCase(options);
|
|
84
|
+
|
|
85
|
+
console.log(output); // The Future of DevOps: The Next Era
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Options
|
|
89
|
+
|
|
90
|
+
The `{options}` parameter is an object that contains the settings for the conversion process.
|
|
91
|
+
|
|
92
|
+
- `style`: determines the specific title case style to be applied. Permissible values include: `['ap', 'apa', 'british', 'chicago', 'nyt', 'wikipedia']`
|
|
93
|
+
- `articlesList` refers to the words that should be treated as articles in title case.
|
|
94
|
+
- `shortConjunctionsList` pertains to the words that should be treated as short conjunctions in title case.
|
|
95
|
+
- `shortPrepositionsList` relates to the words that should be treated as short prepositions in title case.
|
|
96
|
+
- `neverCapitalizedList` contains the words that should never be capitalized in title case.
|
|
97
|
+
- `wordReplacementsList` is a map of terms that will be replaced during the title case conversion process.
|
|
98
|
+
|
|
99
|
+
## Methods
|
|
100
|
+
|
|
101
|
+
- `setReplaceTerms(terms: object)`: Sets word replacement terms to be used during title casing. Multiple calls can be made to add or update multiple word replacements.
|
|
102
|
+
- `removeReplaceTerm(term: string)`: Removes a replace term from the `wordReplacementsList` array in the options 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 options object.
|
|
103
|
+
- `addReplaceTerm(term: string, replacement: string)`: Adds a new replace 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 options object.
|
|
104
|
+
- `setStyle(style: string)`: Sets the style option in the options 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 options object.
|
|
105
|
+
|
|
106
|
+
## Examples
|
|
107
|
+
|
|
108
|
+
The example below demonstrates how to use the TitleCaser class to convert a string to title case with custom options.
|
|
109
|
+
|
|
110
|
+
### Basic Usage
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
// Instantiate a new TitleCaser object with the options
|
|
114
|
+
const titleCaser = new TitleCaser();
|
|
115
|
+
|
|
116
|
+
const input = 'the Book of lIfe';
|
|
117
|
+
const output = titleCaser.toTitleCase(input);
|
|
118
|
+
|
|
119
|
+
console.log(output); // The Book of Life
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Customizing Word Replacements Method
|
|
123
|
+
|
|
124
|
+
In the example below, we create a new instance of the `TitleCaser` class with the `APA` style option. We then set multiple replacement terms using two separate calls to the `setReplaceTerms()` method. Descriptive variable names are used for the input string and expected output. We call `toTitleCase()` to convert the input string to title case.
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
// CommonJS
|
|
128
|
+
const titleCaser = new TitleCaser({
|
|
129
|
+
style: 'apa'
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Set multiple replacement terms using two separate calls to setReplaceTerms()
|
|
133
|
+
titleCaser.setReplaceTerms({
|
|
134
|
+
'hello world': 'Hello World',
|
|
135
|
+
'replace me': 'Replace Me'
|
|
136
|
+
});
|
|
137
|
+
titleCaser.setReplaceTerms({
|
|
138
|
+
'apa': 'APA'
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Use descriptive variable names for the input and expected output
|
|
142
|
+
const inputString = "hello world, replace me!";
|
|
143
|
+
const expectedOutput = "Hello World, Replace Me!";
|
|
144
|
+
|
|
145
|
+
// Call toTitleCase() to convert the input string to title case
|
|
146
|
+
const outputString = titleCaser.toTitleCase(inputString);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Customizing TitleCaser
|
|
150
|
+
|
|
151
|
+
The example below demonstrates how to use the TitleCaser class to convert a string to title case with specific settings.
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
// Set the options object
|
|
155
|
+
const options = {
|
|
156
|
+
style: "nyt",
|
|
157
|
+
wordReplacementsList: {
|
|
158
|
+
"nodejs": "Node.js",
|
|
159
|
+
"javascript": "JavaScript",
|
|
160
|
+
"mongodb": "MongoDB"
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Instantiate a new TitleCaser object with the options
|
|
165
|
+
const titleCaser = new TitleCaser(options);
|
|
166
|
+
|
|
167
|
+
// Set the input string to test
|
|
168
|
+
const input = "the basics of nodejs development with mongodb";
|
|
169
|
+
|
|
170
|
+
// Set the expected output
|
|
171
|
+
const expectedOutput = "The Basics of Node.js Development with MongoDB";
|
|
172
|
+
|
|
173
|
+
// Call the toTitleCase method and store the result in actualOutput
|
|
174
|
+
const actualOutput = titleCaser.toTitleCase(input);
|
|
175
|
+
|
|
176
|
+
// Log the actual output
|
|
177
|
+
console.log(actualOutput);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### TitleCaser With Default Word Replacement
|
|
181
|
+
|
|
182
|
+
The example below demonstrates how to use the TitleCaser class to convert a string to title case with AP style formatting, including hyphenated words and word/brand replacement.
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
// Instantiate a new TitleCaser object with AP style formatting
|
|
186
|
+
const titleCaser = new TitleCaser({ style: 'ap' });
|
|
187
|
+
|
|
188
|
+
// Set the input string to test
|
|
189
|
+
const input = 'nodejs development on aws: an in-depth tutorial on server-side javascript deployment';
|
|
190
|
+
|
|
191
|
+
// Set the expected output
|
|
192
|
+
const expectedOutput = 'Node.js Development on AWS: An In-depth Tutorial on Server-side JavaScript Deployment';
|
|
193
|
+
|
|
194
|
+
// Call the toTitleCase method and store the result in actualOutput
|
|
195
|
+
const actualOutput = titleCaser.toTitleCase(input);
|
|
196
|
+
|
|
197
|
+
// Log the actual output
|
|
198
|
+
console.log(actualOutput);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### TitleCaser With Possessive Noun and a Colon
|
|
202
|
+
|
|
203
|
+
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.
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
// Instantiate a new TitleCaser object with AP style formatting
|
|
207
|
+
const titleCaser = new TitleCaser({ style: "ap" });
|
|
208
|
+
|
|
209
|
+
// Set the input string to test
|
|
210
|
+
const input = "the iphone's impact on modern communication: a sociolinguistic analysis";
|
|
211
|
+
|
|
212
|
+
// Set the expected output
|
|
213
|
+
const expectedOutput = "The iPhone's Impact on Modern Communication: A Sociolinguistic Analysis";
|
|
214
|
+
|
|
215
|
+
// Call the toTitleCase method and store the result in actualOutput
|
|
216
|
+
const actualOutput = titleCaser.toTitleCase(input);
|
|
217
|
+
|
|
218
|
+
// Log the actual output
|
|
219
|
+
console.log(actualOutput);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Build Process
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
$ npm run build-package
|
|
226
|
+
$ npm run build-docs
|
|
227
|
+
$ npm run copy-package-to-docs
|
|
228
|
+
$ npm run test
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Test
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
$ npm run test
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
Test Basic Options
|
|
239
|
+
✓ Default title case conversion
|
|
240
|
+
✓ Customized title case conversion
|
|
241
|
+
✓ AP-style title case conversion with replacements
|
|
242
|
+
✓ AP-style title case conversion with replacements
|
|
243
|
+
✓ Capitalize suffix word in sentence
|
|
244
|
+
|
|
245
|
+
Test Methods
|
|
246
|
+
✓ removeReplaceTerm
|
|
247
|
+
✓ setReplaceTerms
|
|
248
|
+
|
|
249
|
+
Test Variation Stability
|
|
250
|
+
✓ Hyphenated, colon, and short word replacements
|
|
251
|
+
✓ Capitalization and word replacements
|
|
252
|
+
✓ AP-style title case with possessive and colon
|
|
253
|
+
✓ AP-style title case with lowercase back/front-end terms
|
|
254
|
+
✓ Chicago style title case with comparison and colon
|
|
255
|
+
✓ APA style title case with colon
|
|
256
|
+
✓ Wikipedia style title case with acronym and hyphen
|
|
257
|
+
✓ APA style title case with colon and apostrophe
|
|
258
|
+
✓ Chicago style title case with custom term replacements
|
|
259
|
+
✓ AP-style capitalization test with special terms and colon
|
|
260
|
+
✓ NYT-style capitalization test with special terms and colon
|
|
261
|
+
✓ APA style capitalization test with short conjunction terms and colon
|
|
262
|
+
✓ Correct phrase casing list testing
|
|
263
|
+
✓ Wikipedia style capitalization test with special term and colon
|
|
264
|
+
|
|
265
|
+
Test Reserved Words
|
|
266
|
+
✓ Reserved word
|
|
267
|
+
✓ Reserved word with colon
|
|
268
|
+
✓ Reserved word, posessive
|
|
269
|
+
✓ Hyphenated reserved word
|
|
270
|
+
✓ Hyphenated reserved word, possessive
|
|
271
|
+
✓ HTML line break nl2br, <br /> tag
|
|
272
|
+
✓ Untrimmed white spaces
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Resources
|
|
276
|
+
|
|
277
|
+
Useful materials for improving your knowledge of writing and language style guides. These resources include various books and manuals, such as the Publication Manual of the American Psychological Association, the Chicago Manual of Style, and the AP Stylebook, which are widely recognized as authoritative sources on grammar, punctuation, and capitalization rules.
|
|
278
|
+
|
|
279
|
+
- [AP Stylebook, 56th Edition](https://store.stylebooks.com/ap-stylebook-56th-edition-print.html)
|
|
280
|
+
- [Publication Manual of the American Psychological Association, Seventh Edition (2020)](https://apastyle.apa.org/products/publication-manual-7th-edition)
|
|
281
|
+
- [Chicago Manual of Style: Capitalization](https://chat.openai.com/chat/643828ec-d4b5-4f21-b035-62946dd2cec3#:~:text=Chicago%20Manual%20of%20Style%3A%20Capitalization)
|
|
282
|
+
- [The Bluebook: A Uniform System of Citation. 21st ed. Cambridge: Harvard Law Review Association, 2020](https://open.mitchellhamline.edu/cgi/viewcontent.cgi?article=2782&context=wmlr)
|
|
283
|
+
- [The Chicago Manual of Style, 17th Edition](https://press.uchicago.edu/ucp/books/book/chicago/C/bo25956703.html)
|
|
284
|
+
- [The New York Times Manual of Style and Usage](https://www.worldcat.org/title/946964415)
|
|
285
|
+
- [Wikipedia: Letter case](https://chat.openai.com/chat/643828ec-d4b5-4f21-b035-62946dd2cec3#:~:text=Wikipedia%3A%20Letter%20case)
|
|
286
|
+
- [Wikipedia:Manual of Style/Titles of works](https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Titles_of_works#Capital_letters)
|
|
287
|
+
|
|
288
|
+
## Report Bugs
|
|
289
|
+
|
|
290
|
+
If you encounter any bugs or issues while using the library or the demo page, please report them by opening a new issue in the repository's issue tracker.
|
|
291
|
+
|
|
292
|
+
When reporting a bug, please provide as much detail as possible, including the steps to reproduce the issue and any error messages that you see. I appreciate any contribution to improve this library.
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@danielhaim/titlecaser",
|
|
3
|
+
"version": "1.2.23",
|
|
4
|
+
"description": "Converts a string to title case with multiple style options, ability to ignore certain words, and handle acronyms",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"titlecase",
|
|
7
|
+
"text transformation",
|
|
8
|
+
"capitalization",
|
|
9
|
+
"formatting"
|
|
10
|
+
],
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/danielhaim1/titlecaser.git"
|
|
14
|
+
},
|
|
15
|
+
"main": "src/TitleCaser.js",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"build-docs": "cd docs && bundle install && bundle exec jekyll build",
|
|
19
|
+
"build-package": "webpack --mode production && terser dist/titlecaser.js -o dist/titlecaser.min.js",
|
|
20
|
+
"copy-package-to-docs": "cp -R dist/ docs/assets/js",
|
|
21
|
+
"tree": "tree -I 'node_modules'",
|
|
22
|
+
"release": "npm version patch && npm run build-package && npm run copy-package-to-docs && git add package.json package-lock.json dist/ docs/assets/js && git commit -m 'Bump version and build package for release' && git push"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"README.md",
|
|
27
|
+
"package.json",
|
|
28
|
+
"src/index.js",
|
|
29
|
+
"src/TitleCaseConsts.js",
|
|
30
|
+
"src/TitleCaser.js",
|
|
31
|
+
"src/index.js"
|
|
32
|
+
],
|
|
33
|
+
"author": {
|
|
34
|
+
"name": "Daniel Haim",
|
|
35
|
+
"url": "https://github.com/danielhaim1"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@babel/cli": "^7.21.0",
|
|
40
|
+
"@babel/core": "^7.21.0",
|
|
41
|
+
"@babel/plugin-transform-modules-commonjs": "^7.21.2",
|
|
42
|
+
"@babel/preset-env": "^7.20.2",
|
|
43
|
+
"@babel/runtime-corejs3": "^7.21.0",
|
|
44
|
+
"babel-loader": "^9.1.2",
|
|
45
|
+
"esbuild-jest": "^0.5.0",
|
|
46
|
+
"exports-loader": "^4.0.0",
|
|
47
|
+
"terser-webpack-plugin": "^5.3.7",
|
|
48
|
+
"webpack": "^5.76.3",
|
|
49
|
+
"webpack-cli": "^5.0.1",
|
|
50
|
+
"webpack-node-externals": "^3.0.0",
|
|
51
|
+
"@jest/expect": "^29.5.0",
|
|
52
|
+
"babel-jest": "^29.5.0",
|
|
53
|
+
"jest": "^29.5.0",
|
|
54
|
+
"jest-environment-jsdom": "^29.5.0",
|
|
55
|
+
"jest-environment-puppeteer": "^8.0.5",
|
|
56
|
+
"jest-puppeteer": "^8.0.5",
|
|
57
|
+
"puppeteer": "^19.8.2",
|
|
58
|
+
"puppeteer-core": "^19.8.0"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
export const commonAbbreviationList = [
|
|
2
|
+
'a', 'an', 'the', 'as', 'at', 'by', 'for', 'in', 'of', 'on',
|
|
3
|
+
'to', 'up', 'yet', 'so', 'but', 'nor', 'or', 'and',
|
|
4
|
+
];
|
|
5
|
+
|
|
6
|
+
export const correctTitleCasingList = [
|
|
7
|
+
// Web Technologies
|
|
8
|
+
'AJAX', 'CSS', 'DOM', 'ES6', 'HTML', 'JavaScript', 'jQuery',
|
|
9
|
+
'MobX', 'SCSS', 'TypeScript', 'Vue.js', '.NET', 'ASP', 'ASPX',
|
|
10
|
+
'MySQL', 'PHP', 'PostgreSQL', 'Python', 'SQL', 'GraphQL',
|
|
11
|
+
'HTML5',
|
|
12
|
+
|
|
13
|
+
// Acronyms/Abbreviations
|
|
14
|
+
'API', 'APIs', 'ASCII', 'CI', 'CircleCI', 'CLI', 'DLL', 'DNS',
|
|
15
|
+
'EC2', 'FTP', 'HTTP', 'HTTPs', 'ICMP', 'IDE', 'IP', 'ISP',
|
|
16
|
+
'JSON', 'JSP', 'LPWAN', 'M2M', 'MQTT', 'OOP', 'REST', 'SSH',
|
|
17
|
+
'SSL', 'TCP', 'UDP', 'URL', 'WLAN', 'WYSIWYG', 'XML', 'YAML',
|
|
18
|
+
'YML', 'IMAP', 'RSS', 'IaaS', 'PaaS', 'SaaS', 'CaaS', 'FaaS',
|
|
19
|
+
'XaaS', 'RaaS', 'IoE', 'IoT', 'LoRa', 'NB-IoT', 'RFID', 'RF',
|
|
20
|
+
'RFI', 'RFQ', 'ECMAScript', 'IO', 'I/O', 'DevOps', 'SecOps',
|
|
21
|
+
'DDoS', 'VoIP', 'AI', 'AR', 'ML', 'VR',
|
|
22
|
+
|
|
23
|
+
// Misc.
|
|
24
|
+
'w/', 'w/o',
|
|
25
|
+
|
|
26
|
+
// 'eTerms'
|
|
27
|
+
'e-Book', 'e-Books', 'eBook', 'eBooks', 'eCommerce',
|
|
28
|
+
'eMarket', 'eMarketplace', 'eMarketplaces', 'eMarkets',
|
|
29
|
+
'eReader', 'eShop', 'eShops', 'eStore', 'eStores',
|
|
30
|
+
'E-commerce',
|
|
31
|
+
|
|
32
|
+
// Accounting terms
|
|
33
|
+
'AP', 'COGS', 'EBIT', 'EPS', 'FIFO', 'GAAP', 'LIFO',
|
|
34
|
+
'P&L', 'ROI', 'SOX', 'TCO', 'VAT',
|
|
35
|
+
|
|
36
|
+
// Investment terms
|
|
37
|
+
'CAGR', 'DCF', 'ETF', 'IPO', 'IRR', 'M&A', 'NAV', 'PE', 'PEG',
|
|
38
|
+
'PPE', 'ROE', 'S&P', 'TVM', 'VC',
|
|
39
|
+
|
|
40
|
+
// Marketing terms
|
|
41
|
+
'B2B', 'B2C', 'CMO', 'CPA', 'CPC', 'CPL', 'CPM', 'CRM', 'CTA',
|
|
42
|
+
'CTR', 'SEO', 'SEM', 'SMM', 'USP', 'A/B', 'CTA', 'CTOR',
|
|
43
|
+
'CTR', 'KPI', 'PWA', 'SEM', 'SERP', 'SERPs', 'SMM', 'SMO',
|
|
44
|
+
'FAQ', 'FAQA', 'FAQS', 'UI', 'UI/UX', 'UX', 'T&C', 'TOS',
|
|
45
|
+
'PP', 'CRM', 'PoE', 'PoW', 'PoC', 'A11Y', 'PR',
|
|
46
|
+
|
|
47
|
+
// Sales terms
|
|
48
|
+
'BANT', 'GAP', 'KPI', 'MQL', 'NPS', 'POS', 'SPIN', 'SQL',
|
|
49
|
+
'SWOT',
|
|
50
|
+
|
|
51
|
+
// Legal terms
|
|
52
|
+
'AFA', 'ADR', 'CCPA', 'CFAA', 'CISG', 'DMCA', 'EULA', 'GDPR',
|
|
53
|
+
'HIPAA', 'NDA', 'SOW', 'TOS',
|
|
54
|
+
|
|
55
|
+
// Roles and titles
|
|
56
|
+
'CEO', 'CEOs', 'CFO', 'CFOs', 'CIO', 'CIOs', 'CMO', 'CMOs',
|
|
57
|
+
'COO', 'COOs', 'CPO', 'CPOs', 'CRO', 'CROs', 'CSO', 'CSOs',
|
|
58
|
+
'CTO', 'CTOs', 'EVP', 'EVPs', 'HR', 'HRs', 'SVP', 'SVPs',
|
|
59
|
+
'VP', 'VPs',
|
|
60
|
+
|
|
61
|
+
// Non-profit organizations
|
|
62
|
+
'NGO', 'NPO', 'NGOs', 'NPOs', 'UN', 'UNESCO', 'UNICEF',
|
|
63
|
+
'UNHCR', 'UNODC', 'UNDP', 'UNFPA', 'UNEP',
|
|
64
|
+
|
|
65
|
+
'Adobe', 'Airbnb', 'Alibaba', 'Allstate', 'American Express', 'Apple',
|
|
66
|
+
'AT&T', 'BMW', 'Boeing', 'Cisco', 'Citigroup', 'Coca', 'Deloitte', 'Disney',
|
|
67
|
+
'Dropbox', 'ExxonMobil', 'Ford', 'GE', 'General', 'Goldman Sachs', 'Google',
|
|
68
|
+
'Hilton', 'HP', 'IBM', 'Intel', 'JPMorgan', 'Johnson & Johnson', 'LinkedIn',
|
|
69
|
+
"McDonald's", 'Mercedes-Benz', 'Microsoft', 'Nestle', 'Nike', 'Nissan',
|
|
70
|
+
'Oracle', 'PepsiCo', 'Pfizer', 'Salesforce', 'Samsung', 'Shell', 'Sony',
|
|
71
|
+
'Tesla', 'Toyota', 'Uber', 'Verizon', 'Visa', 'Walmart', 'Wells Fargo',
|
|
72
|
+
'Yahoo', 'Zara', 'IKEA', 'Facebook', 'YouTube', 'Instagram', 'Twitter',
|
|
73
|
+
'TensorFlow', 'Amazon', 'Netflix', 'eBay', 'iPhone', 'iPad', 'iPod',
|
|
74
|
+
'PlayStation', 'PayPal', 'GitHub', 'GitLab', 'CodeIgniter', 'WordPress',
|
|
75
|
+
'WooCommerce', 'MongoDB', 'JIRA', 'HubSpot', 'AirDrop', 'AirPlay', 'AirPods',
|
|
76
|
+
'AirTags', 'FinalCut', 'GarageBand', 'iBooks', 'iCloud', 'iLife', 'iMac',
|
|
77
|
+
'iMessage', 'iMovie', 'iPhoto', 'iWatch', 'iWork', 'LogicPro', 'macOS',
|
|
78
|
+
'ProTools', 'QuickTime', 'AdWords', 'AdSense', 'TikTok', 'Slack', 'Trello',
|
|
79
|
+
'Zoom', 'Twitch', 'Snapchat', 'WhatsApp', 'Telegram', 'Discord', 'Reddit',
|
|
80
|
+
'Quora', 'StackOverflow', 'StackExchange', 'Coca-Cola',
|
|
81
|
+
'AWS', 'GCP', 'VMware', 'CVS',
|
|
82
|
+
|
|
83
|
+
// Sports
|
|
84
|
+
'NBA', 'NCAA', 'NFL', 'WWE', 'WWF', 'FIFA',
|
|
85
|
+
|
|
86
|
+
// Time-related, numbers, and measurements: Includes abbreviations for
|
|
87
|
+
// time-related terms, numbers, and measurements.
|
|
88
|
+
'a.m.', 'p.m.', 'ca.', 'cc.', 'fig.', 'pl.', 'pt.', 'rev.',
|
|
89
|
+
'sr.', 'v.', 'vol.', 'et al.', 'pp.', 'p.',
|
|
90
|
+
|
|
91
|
+
// Professional abbreviations, degrees, and titles: Includes abbreviations
|
|
92
|
+
// for professional titles, degrees, and certifications.
|
|
93
|
+
'ph.d.', 'm.d.', 'd.d.s.', 'd.m.d.', 'd.o.', 'd.c.', 'd.v.m.',
|
|
94
|
+
'd.n.p.', 'd.p.m.', 'd.s.w.', 'd.s.n.', 'd.n.sc.', 'd.n.a.',
|
|
95
|
+
'd.n.t.', 'd.n.p.t.', 'd.n.o.', 'd.n.m.', 'd.n.e.', 'd.n.s.',
|
|
96
|
+
'd.n.p.s.',
|
|
97
|
+
|
|
98
|
+
// Academic & literary abbreviations: Includes abbreviations for academic
|
|
99
|
+
// and literary terms, such as 'ed.' for 'edition' and 'vol.' for 'volume'.
|
|
100
|
+
'adj.', 'adv.', 'cf.', 'cm.', 'co.', 'corp.', 'dept.',
|
|
101
|
+
'dist.', 'ed.', 'edn.', 'esp.', 'etc.', 'ex.', 'i.e.', 'e.g.',
|
|
102
|
+
'op. cit.', 'vs.',
|
|
103
|
+
|
|
104
|
+
// Commercial
|
|
105
|
+
'Ltd.', 'Co.', 'Inc.', 'St.', 'Ave.', 'Bldg.', 'No.',
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
export const wordReplacementsList = [
|
|
109
|
+
{ 'a.k.a': 'AKA' },
|
|
110
|
+
{ 'a.s.a.p': 'ASAP' },
|
|
111
|
+
{ 'angularjs': 'Angular.js' },
|
|
112
|
+
{ 'back-end': 'Backend' },
|
|
113
|
+
{ 'd.i.y': 'DIY' },
|
|
114
|
+
{ 'e-book': 'eBook' },
|
|
115
|
+
{ 'e-books': 'eBooks' },
|
|
116
|
+
{ 'e-commerce': 'eCommerce' },
|
|
117
|
+
{ 'ecom': 'eCommerce' },
|
|
118
|
+
{ 'ecommerce': 'eCommerce' },
|
|
119
|
+
{ 'f.a.q': 'FAQ' },
|
|
120
|
+
{ 'f.a.q.a': 'FAQs' },
|
|
121
|
+
{ 'f.a.q.s': 'FAQs' },
|
|
122
|
+
{ 'f.y.i': 'FYI' },
|
|
123
|
+
{ 'front-end': 'Frontend' },
|
|
124
|
+
{ 'full-stack': 'Fullstack' },
|
|
125
|
+
{ 'nextjs': 'Next.js' },
|
|
126
|
+
{ 'nodejs': 'Node.js' },
|
|
127
|
+
{ 'nuxtjs': 'Nuxt.js' },
|
|
128
|
+
{ 'reactjs': 'React.js' },
|
|
129
|
+
{ 't.b.d': 'TBD' },
|
|
130
|
+
{ 'vuejs': 'Vue.js' },
|
|
131
|
+
{ 'phd': 'ph.d.' },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
// ! TODO
|
|
135
|
+
// const wordReplacementsList = [
|
|
136
|
+
// { word: 'a.k.a', replacement: 'AKA' },
|
|
137
|
+
// { word: 'a.s.a.p', replacement: 'ASAP' },
|
|
138
|
+
// { word: 'angularjs', replacement: 'Angular.js' },
|
|
139
|
+
// { word: 'back-end', replacement: 'Backend' },
|
|
140
|
+
// { word: 'd.i.y', replacement: 'DIY' },
|
|
141
|
+
// { word: 'e-book', replacement: 'eBook' },
|
|
142
|
+
// { word: 'e-books', replacement: 'eBooks' },
|
|
143
|
+
// { word: 'e-commerce', replacement: 'eCommerce' },
|
|
144
|
+
// { word: 'ecom', replacement: 'eCommerce' },
|
|
145
|
+
// { word: 'ecommerce', replacement: 'eCommerce' },
|
|
146
|
+
// { word: 'f.a.q', replacement: 'FAQ' },
|
|
147
|
+
// { word: 'f.a.q.a', replacement: 'FAQs' },
|
|
148
|
+
// { word: 'f.a.q.s', replacement: 'FAQs' },
|
|
149
|
+
// { word: 'f.y.i', replacement: 'FYI' },
|
|
150
|
+
// { word: 'front-end', replacement: 'Frontend' },
|
|
151
|
+
// { word: 'full-stack', replacement: 'Fullstack' },
|
|
152
|
+
// { word: 'nextjs', replacement: 'Next.js' },
|
|
153
|
+
// { word: 'nodejs', replacement: 'Node.js' },
|
|
154
|
+
// { word: 'nuxtjs', replacement: 'Nuxt.js' },
|
|
155
|
+
// { word: 'reactjs', replacement: 'React.js' },
|
|
156
|
+
// { word: 't.b.d', replacement: 'TBD' },
|
|
157
|
+
// { word: 'vuejs', replacement: 'Vue.js' },
|
|
158
|
+
// { word: 'phd', replacement: 'ph.d.' },
|
|
159
|
+
// ];
|
|
160
|
+
|
|
161
|
+
export const titleCaseStylesList = Object.freeze({
|
|
162
|
+
AP: 'ap',
|
|
163
|
+
APA: 'apa',
|
|
164
|
+
BRITISH: 'british',
|
|
165
|
+
CHICAGO: 'chicago',
|
|
166
|
+
NYT: 'nyt',
|
|
167
|
+
WIKIPEDIA: 'wikipedia'
|
|
168
|
+
});
|
|
169
|
+
export const allowedTitleCaseStylesList = Object.values(titleCaseStylesList);
|
|
170
|
+
export const titleCaseDefaultOptionsList = Object.freeze({
|
|
171
|
+
ap: {
|
|
172
|
+
shortConjunctionsList: ['and', 'but', 'or', 'for', 'nor', 'yet', 'so'],
|
|
173
|
+
articlesList: ['a', 'an', 'the'],
|
|
174
|
+
shortPrepositionsList: ['as', 'at', 'by', 'in', 'of', 'on', 'to', 'up', 'via'],
|
|
175
|
+
neverCapitalizedList: []
|
|
176
|
+
},
|
|
177
|
+
apa: {
|
|
178
|
+
shortConjunctionsList: ['and', 'as', 'but', 'by', 'for', 'in', 'nor', 'of', 'on', 'or', 'so', 'to', 'yet'],
|
|
179
|
+
articlesList: ['a', 'an', 'the'],
|
|
180
|
+
shortPrepositionsList: ['as', 'at', 'by', 'for', 'in', 'of', 'on', 'to', 'up', 'via'],
|
|
181
|
+
neverCapitalizedList: []
|
|
182
|
+
},
|
|
183
|
+
british: {
|
|
184
|
+
shortConjunctionsList: ['and', 'but', 'or', 'for', 'nor', 'yet', 'so'],
|
|
185
|
+
articlesList: ['a', 'an', 'the'],
|
|
186
|
+
shortPrepositionsList: ['as', 'at', 'by', 'in', 'of', 'on', 'to', 'up', 'via'],
|
|
187
|
+
neverCapitalizedList: []
|
|
188
|
+
},
|
|
189
|
+
chicago: {
|
|
190
|
+
shortConjunctionsList: ['and', 'but', 'or', 'for', 'nor', 'yet', 'so'],
|
|
191
|
+
articlesList: ['a', 'an', 'the'],
|
|
192
|
+
shortPrepositionsList: ['as', 'at', 'by', 'for', 'in', 'of', 'on', 'to', 'up', 'with', 'via'],
|
|
193
|
+
neverCapitalizedList: ['etc.']
|
|
194
|
+
},
|
|
195
|
+
nyt: {
|
|
196
|
+
shortConjunctionsList: ['and', 'but', 'or', 'for', 'nor', 'yet', 'so'],
|
|
197
|
+
articlesList: ['a', 'an', 'the'],
|
|
198
|
+
shortPrepositionsList: ['as', 'at', 'by', 'in', 'of', 'on', 'to', 'up', 'via'],
|
|
199
|
+
neverCapitalizedList: []
|
|
200
|
+
},
|
|
201
|
+
wikipedia: {
|
|
202
|
+
shortConjunctionsList: ['and', 'as', 'but', 'for', 'if', 'nor', 'or', 'so', 'yet'],
|
|
203
|
+
articlesList: ['a', 'an', 'the'],
|
|
204
|
+
shortPrepositionsList: ['as', 'at', 'by', 'in', 'of', 'on', 'to', 'up', 'via'],
|
|
205
|
+
neverCapitalizedList: []
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
export const ignoredWordsList = [];
|
|
210
|
+
export const correctPhraseCasingList = [
|
|
211
|
+
'The Cybersmile Foundation',
|
|
212
|
+
'CO. by Colgate',
|
|
213
|
+
"The Simpsons",
|
|
214
|
+
];
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import {
|
|
2
|
+
commonAbbreviationList,
|
|
3
|
+
correctTitleCasingList,
|
|
4
|
+
correctPhraseCasingList,
|
|
5
|
+
wordReplacementsList,
|
|
6
|
+
}
|
|
7
|
+
from "./TitleCaseConsts.js";
|
|
8
|
+
|
|
9
|
+
import TitleCaseHelper from "./TitleCaseHelper.js";
|
|
10
|
+
|
|
11
|
+
export class TitleCaser {
|
|
12
|
+
constructor (options = {}) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
this.wordReplacementsList = wordReplacementsList;
|
|
15
|
+
}
|
|
16
|
+
toTitleCase(str) {
|
|
17
|
+
try {
|
|
18
|
+
// If input is empty, throw an error.
|
|
19
|
+
if (str.trim().length === 0) throw new TypeError("Invalid input: input must not be empty.");
|
|
20
|
+
|
|
21
|
+
// If input is not a string, throw an error.
|
|
22
|
+
if (typeof str !== 'string') throw new TypeError("Invalid input: input must be a string.");
|
|
23
|
+
|
|
24
|
+
// If options is not an object, throw an error.
|
|
25
|
+
if (typeof this.options !== "undefined" && typeof this.options !== "object") throw new TypeError("Invalid options: options must be an object.");
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
style = "ap",
|
|
29
|
+
neverCapitalize = [],
|
|
30
|
+
replaceTermsList = wordReplacementsList
|
|
31
|
+
} = this.options;
|
|
32
|
+
const ignoreList = ["nl2br", ...neverCapitalize];
|
|
33
|
+
const {
|
|
34
|
+
articlesList,
|
|
35
|
+
shortConjunctionsList,
|
|
36
|
+
shortPrepositionsList,
|
|
37
|
+
neverCapitalizedList,
|
|
38
|
+
replaceTerms
|
|
39
|
+
} = TitleCaseHelper.getTitleCaseOptions(this.options, commonAbbreviationList, wordReplacementsList);
|
|
40
|
+
|
|
41
|
+
// Prerocess the replaceTerms array to make it easier to search for.
|
|
42
|
+
const replaceTermsArray = replaceTermsList.map(term => Object.keys(term)[0].toLowerCase());
|
|
43
|
+
// Create an object from the replaceTerms array to make it easier to search for.
|
|
44
|
+
const replaceTermsObj = Object.fromEntries(replaceTermsList.map(
|
|
45
|
+
term => [Object.keys(term)[0].toLowerCase(), Object.values(term)[0]]
|
|
46
|
+
));
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// Remove extra spaces and replace <br> tags with a placeholder.
|
|
50
|
+
let inputString = str.trim();
|
|
51
|
+
|
|
52
|
+
// Remove extra spaces and replace <br> tags with a placeholder.
|
|
53
|
+
inputString = inputString.replace(/ {2,}/g, (match) => match.slice(0, 1));
|
|
54
|
+
|
|
55
|
+
// Replace <br> tags with a placeholder.
|
|
56
|
+
inputString = inputString.replace(/<br\s*[\/]?>/gi, "nl2br ");
|
|
57
|
+
|
|
58
|
+
// Split the string into an array of words.
|
|
59
|
+
const words = inputString.split(" ");
|
|
60
|
+
|
|
61
|
+
const wordsInTitleCase = words.map((word, i) => {
|
|
62
|
+
switch (true) {
|
|
63
|
+
case TitleCaseHelper.hasHtmlBreak(word):
|
|
64
|
+
// If the word is a <br> tag, return it as is.
|
|
65
|
+
return word;
|
|
66
|
+
case TitleCaseHelper.isWordIgnored(word, ignoreList):
|
|
67
|
+
// If the word is in the ignore list, return it as is.
|
|
68
|
+
return word;
|
|
69
|
+
case replaceTermsArray.includes(word.toLowerCase()):
|
|
70
|
+
// If the word is in the replaceTerms array, return the replacement.
|
|
71
|
+
return replaceTermsObj[word.toLowerCase()];
|
|
72
|
+
case TitleCaseHelper.isWordInArray(word, correctTitleCasingList):
|
|
73
|
+
// If the word is in the correctTitleCasingList array, return the correct casing.
|
|
74
|
+
return TitleCaseHelper.correctTerm(word, correctTitleCasingList);
|
|
75
|
+
case TitleCaseHelper.hasSuffix(word, style):
|
|
76
|
+
// If the word has a suffix, return the correct casing.
|
|
77
|
+
return TitleCaseHelper.correctSuffix(word, correctTitleCasingList);
|
|
78
|
+
case TitleCaseHelper.hasHyphen(word):
|
|
79
|
+
// If the word has a hyphen, return the correct casing.
|
|
80
|
+
return TitleCaseHelper.correctTermHyphenated(word, style);
|
|
81
|
+
case TitleCaseHelper.hasUppercaseIntentional(word):
|
|
82
|
+
// If the word has an intentional uppercase letter, return the correct casing.
|
|
83
|
+
return word;
|
|
84
|
+
case TitleCaseHelper.isShortWord(word, style) && i !== 0:
|
|
85
|
+
// If the word is a short word, return the correct casing.
|
|
86
|
+
return (i > 0 && TitleCaseHelper.endsWithSymbol(words[i - 1],
|
|
87
|
+
[':', '?', '!', '.'])) ? word.charAt(0).toUpperCase() + word.slice(1) : word.toLowerCase();
|
|
88
|
+
case TitleCaseHelper.endsWithSymbol(word):
|
|
89
|
+
// If the word ends with a symbol, return the correct casing.
|
|
90
|
+
const splitWord = word.split(/([.,\/#!$%\^&\*;:{}=\-_`~()])/g);
|
|
91
|
+
const processedWords = splitWord.map((splitWord, j) => {
|
|
92
|
+
// If the word is in the correctTitleCasingList array, return the correct casing.
|
|
93
|
+
if (TitleCaseHelper.isWordInArray(splitWord, correctTitleCasingList)) return TitleCaseHelper.correctTerm(splitWord, correctTitleCasingList);
|
|
94
|
+
// Else return the word with the correct casing.
|
|
95
|
+
else return (j > 0 && TitleCaseHelper.endsWithSymbol(splitWord)) ? splitWord.charAt(0)
|
|
96
|
+
.toUpperCase() + splitWord.slice(1) : splitWord.charAt(0)
|
|
97
|
+
.toUpperCase() + splitWord.slice(1);
|
|
98
|
+
});
|
|
99
|
+
// Join the processed words and return them.
|
|
100
|
+
return processedWords.join("");
|
|
101
|
+
case TitleCaseHelper.startsWithSymbol(word):
|
|
102
|
+
// If the word starts with a symbol, return the correct casing.
|
|
103
|
+
return !TitleCaseHelper.isWordInArray(word, correctTitleCasingList) ? word : TitleCaseHelper.correctTerm(word);
|
|
104
|
+
case TitleCaseHelper.hasRomanNumeral(word):
|
|
105
|
+
// If the word has a roman numeral, return the correct casing.
|
|
106
|
+
return word.toUpperCase();
|
|
107
|
+
case TitleCaseHelper.hasNumbers(word):
|
|
108
|
+
// If the word has numbers, return the correct casing.
|
|
109
|
+
return word;
|
|
110
|
+
default:
|
|
111
|
+
// Default to returning the word with the correct casing.
|
|
112
|
+
return word.charAt(0)
|
|
113
|
+
.toUpperCase() + word.slice(1)
|
|
114
|
+
.toLowerCase();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Join the words in the array into a string.
|
|
119
|
+
inputString = wordsInTitleCase.join(" ");
|
|
120
|
+
|
|
121
|
+
for (const phrase of correctPhraseCasingList) {
|
|
122
|
+
// If the phrase is in the input string, replace it with the correct casing.
|
|
123
|
+
if (inputString.toLowerCase()
|
|
124
|
+
.includes(phrase.toLowerCase())) {
|
|
125
|
+
inputString = inputString.replace(new RegExp(phrase, 'gi'), phrase);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Replace the nl2br placeholder with <br> tags.
|
|
130
|
+
inputString = inputString.replace(/nl2br /gi, "<br />");
|
|
131
|
+
|
|
132
|
+
// Return the string.
|
|
133
|
+
return inputString;
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
throw new Error(error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
setReplaceTerms(terms) {
|
|
141
|
+
if (typeof terms !== 'object') {
|
|
142
|
+
throw new TypeError('Invalid argument: replace terms must be an object.');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Add the new replace terms to the wordReplacementsList array
|
|
146
|
+
Object.entries(terms).forEach(([term, replacement]) => {
|
|
147
|
+
const index = wordReplacementsList.findIndex(obj => obj[term]);
|
|
148
|
+
if (index !== -1) {
|
|
149
|
+
// If the term already exists in the array, update the replacement value
|
|
150
|
+
wordReplacementsList[index][term] = replacement;
|
|
151
|
+
} else {
|
|
152
|
+
// If the term doesn't exist in the array, add a new object with the term and replacement
|
|
153
|
+
wordReplacementsList.push({ [term]: replacement });
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Log the updated wordReplacementsList array
|
|
158
|
+
// console.log(wordReplacementsList);
|
|
159
|
+
|
|
160
|
+
// Update the replace terms option
|
|
161
|
+
this.options.wordReplacementsList = wordReplacementsList;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
addReplaceTerm(term, replacement) {
|
|
165
|
+
if (typeof term !== 'string' || typeof replacement !== 'string') {
|
|
166
|
+
throw new TypeError('Invalid argument: term and replacement must be strings.');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const index = this.wordReplacementsList.findIndex(obj => obj[term]);
|
|
170
|
+
|
|
171
|
+
if (index !== -1) {
|
|
172
|
+
// If the term already exists in the array, update the replacement value
|
|
173
|
+
this.wordReplacementsList[index][term] = replacement;
|
|
174
|
+
} else {
|
|
175
|
+
// If the term doesn't exist in the array, add a new object with the term and replacement
|
|
176
|
+
this.wordReplacementsList.push({ [term]: replacement });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Update the replace terms option
|
|
180
|
+
this.options.wordReplacementsList = this.wordReplacementsList;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
removeReplaceTerm(term) {
|
|
184
|
+
if (typeof term !== 'string') {
|
|
185
|
+
throw new TypeError('Invalid argument: term must be a string.');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Find the index of the term in the wordReplacementsList array
|
|
189
|
+
const index = this.wordReplacementsList.findIndex(obj => Object.keys(obj)[0] === term);
|
|
190
|
+
|
|
191
|
+
// If the term is not found in the array, throw an error
|
|
192
|
+
if (index === -1) {
|
|
193
|
+
throw new Error(`Term '${term}' not found in word replacements list.`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Remove the term from the array
|
|
197
|
+
this.wordReplacementsList.splice(index, 1);
|
|
198
|
+
|
|
199
|
+
// Log the updated wordReplacementsList array
|
|
200
|
+
// console.log(this.wordReplacementsList);
|
|
201
|
+
|
|
202
|
+
// Update the replace terms option
|
|
203
|
+
this.options.wordReplacementsList = this.wordReplacementsList;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
setStyle(style) {
|
|
207
|
+
if (typeof style !== 'string') {
|
|
208
|
+
throw new TypeError('Invalid argument: style must be a string.');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.options.style = style;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// If the module is being used in a Node environment, export the module.
|
|
216
|
+
if (typeof module === 'object' && module.exports) {
|
|
217
|
+
module.exports = { TitleCaser };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
package/src/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TitleCaser } from './TitleCaser.js';
|
|
2
|
+
|
|
3
|
+
if (typeof String.prototype.toTitleCase !== 'function') {
|
|
4
|
+
String.prototype.toTitleCase = function (options) {
|
|
5
|
+
const titleCaser = new TitleCaser(options);
|
|
6
|
+
return titleCaser.toTitleCase(this);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { TitleCaser };
|
|
11
|
+
|
|
12
|
+
if (typeof window === 'object') {
|
|
13
|
+
window.TitleCaser = TitleCaser;
|
|
14
|
+
}
|