nhb-toolbox 4.13.4 → 4.13.7
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/CHANGELOG.md +9 -0
- package/dist/cjs/pluralize/Pluralizer.js +43 -15
- package/dist/cjs/pluralize/rules.js +143 -125
- package/dist/dts/pluralize/Pluralizer.d.ts.map +1 -1
- package/dist/dts/pluralize/rules.d.ts +5 -5
- package/dist/dts/pluralize/rules.d.ts.map +1 -1
- package/dist/esm/pluralize/Pluralizer.js +43 -15
- package/dist/esm/pluralize/rules.js +142 -124
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ All notable changes to the package will be documented here.
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [4.13.7] - 2025-07-23
|
|
10
|
+
|
|
11
|
+
- **Updated** `isPlural` and `isSingular` methods in `Pluralizer` class to handle more cases.
|
|
12
|
+
- **Ran full test** on `pluralizer` and fixed some known issues.
|
|
13
|
+
|
|
14
|
+
## [4.13.3-6] - 2025-07-22
|
|
15
|
+
|
|
16
|
+
- **Reordered** rules for `pluralizer` and fixed other issues.
|
|
17
|
+
|
|
9
18
|
## [4.13.3] - 2025-07-22
|
|
10
19
|
|
|
11
20
|
- **Updated** pluralization/uncountable rules, case restoration method and fixed other bugs in `pluralizer`.
|
|
@@ -56,17 +56,31 @@ class Pluralizer {
|
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
#restoreCase(original, transformed) {
|
|
59
|
+
// Exact match
|
|
60
|
+
if (original === transformed)
|
|
61
|
+
return transformed;
|
|
62
|
+
// Entire original is lowercase
|
|
63
|
+
if (original === original.toLowerCase()) {
|
|
64
|
+
return transformed.toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
// Entire original is uppercase
|
|
67
|
+
if (original === original.toUpperCase()) {
|
|
68
|
+
return transformed.toUpperCase();
|
|
69
|
+
}
|
|
70
|
+
// Title case (first letter uppercase, rest lowercase)
|
|
71
|
+
if (original[0] === original[0].toUpperCase() &&
|
|
72
|
+
original.slice(1) === original.slice(1).toLowerCase()) {
|
|
73
|
+
return (transformed.charAt(0).toUpperCase() +
|
|
74
|
+
transformed.slice(1).toLowerCase());
|
|
75
|
+
}
|
|
76
|
+
// Mixed case: per-character casing
|
|
59
77
|
let result = '';
|
|
60
78
|
for (let i = 0; i < transformed.length; i++) {
|
|
61
79
|
const origChar = original[i];
|
|
62
|
-
if (origChar
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
result += transformed[i].toLowerCase();
|
|
69
|
-
}
|
|
80
|
+
if (origChar &&
|
|
81
|
+
origChar === origChar.toUpperCase() &&
|
|
82
|
+
origChar !== origChar.toLowerCase()) {
|
|
83
|
+
result += transformed[i].toUpperCase();
|
|
70
84
|
}
|
|
71
85
|
else {
|
|
72
86
|
result += transformed[i].toLowerCase();
|
|
@@ -210,11 +224,18 @@ class Pluralizer {
|
|
|
210
224
|
* pluralizer.isPlural('children'); // true
|
|
211
225
|
*/
|
|
212
226
|
isPlural(word) {
|
|
213
|
-
|
|
214
|
-
if (this.#isUncountable(word))
|
|
227
|
+
if (!(0, primitives_1.isNonEmptyString)(word))
|
|
215
228
|
return false;
|
|
216
|
-
|
|
229
|
+
const lower = word.toLowerCase();
|
|
230
|
+
// if uncountable return true
|
|
231
|
+
if (this.#isUncountable(lower))
|
|
232
|
+
return true;
|
|
233
|
+
// directly known as plural
|
|
234
|
+
if (this.#irregularPlurals[lower])
|
|
217
235
|
return true;
|
|
236
|
+
// directly known as singular
|
|
237
|
+
if (this.#irregularSingles[lower])
|
|
238
|
+
return false;
|
|
218
239
|
return this.toSingular(lower) !== lower;
|
|
219
240
|
}
|
|
220
241
|
/**
|
|
@@ -225,12 +246,19 @@ class Pluralizer {
|
|
|
225
246
|
* pluralizer.isSingular('child'); // true
|
|
226
247
|
*/
|
|
227
248
|
isSingular(word) {
|
|
228
|
-
|
|
229
|
-
if (this.#isUncountable(word))
|
|
249
|
+
if (!(0, primitives_1.isNonEmptyString)(word))
|
|
230
250
|
return false;
|
|
231
|
-
|
|
251
|
+
const lower = word.toLowerCase();
|
|
252
|
+
// if uncountable return true
|
|
253
|
+
if (this.#isUncountable(lower))
|
|
254
|
+
return true;
|
|
255
|
+
// directly known as singular
|
|
256
|
+
if (this.#irregularSingles[lower])
|
|
232
257
|
return true;
|
|
233
|
-
|
|
258
|
+
// directly known as plural
|
|
259
|
+
if (this.#irregularPlurals[lower])
|
|
260
|
+
return false;
|
|
261
|
+
return this.toSingular(lower) === lower;
|
|
234
262
|
}
|
|
235
263
|
}
|
|
236
264
|
exports.Pluralizer = Pluralizer;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
/** Irregular
|
|
3
|
+
exports.uncountables = exports.singularRules = exports.pluralRules = exports.irregularRules = void 0;
|
|
4
|
+
/** Irregular singular → plural mappings */
|
|
5
5
|
exports.irregularRules =
|
|
6
6
|
/* @__PURE__ */ Object.freeze([
|
|
7
7
|
// Pronouns
|
|
@@ -26,70 +26,79 @@ exports.irregularRules =
|
|
|
26
26
|
['his', 'their'],
|
|
27
27
|
['her', 'their'],
|
|
28
28
|
// Common irregulars
|
|
29
|
+
['analysis', 'analyses'],
|
|
30
|
+
['anathema', 'anathemata'],
|
|
31
|
+
['appendix', 'appendices'],
|
|
32
|
+
['automaton', 'automata'],
|
|
33
|
+
['basis', 'bases'],
|
|
34
|
+
['calf', 'calves'],
|
|
35
|
+
['carve', 'carves'],
|
|
29
36
|
['child', 'children'],
|
|
30
|
-
['
|
|
31
|
-
['
|
|
32
|
-
['
|
|
33
|
-
['
|
|
37
|
+
['codex', 'codices'],
|
|
38
|
+
['criterion', 'criteria'],
|
|
39
|
+
['crisis', 'crises'],
|
|
40
|
+
['datum', 'data'],
|
|
41
|
+
['diagnosis', 'diagnoses'],
|
|
42
|
+
['die', 'dice'],
|
|
43
|
+
['dogma', 'dogmata'],
|
|
44
|
+
['echo', 'echoes'],
|
|
45
|
+
['elf', 'elves'],
|
|
34
46
|
['foot', 'feet'],
|
|
35
|
-
['
|
|
47
|
+
['genus', 'genera'],
|
|
36
48
|
['goose', 'geese'],
|
|
37
|
-
['
|
|
49
|
+
['groove', 'grooves'],
|
|
50
|
+
['half', 'halves'],
|
|
51
|
+
['hedron', 'hedra'],
|
|
52
|
+
['hero', 'heroes'],
|
|
53
|
+
['hoof', 'hooves'],
|
|
54
|
+
['human', 'humans'],
|
|
55
|
+
['honey', 'honeys'],
|
|
56
|
+
['index', 'indices'],
|
|
38
57
|
['leaf', 'leaves'],
|
|
39
|
-
['
|
|
58
|
+
['lemma', 'lemmata'],
|
|
59
|
+
['loaf', 'loaves'],
|
|
60
|
+
['looey', 'looies'],
|
|
61
|
+
['man', 'men'],
|
|
62
|
+
['mango', 'mangoes'],
|
|
63
|
+
['matrix', 'matrices'],
|
|
40
64
|
['medium', 'media'],
|
|
41
|
-
['
|
|
42
|
-
['
|
|
43
|
-
['
|
|
44
|
-
['
|
|
45
|
-
['
|
|
65
|
+
['mouse', 'mice'],
|
|
66
|
+
['neurosis', 'neuroses'],
|
|
67
|
+
['noumenon', 'noumena'],
|
|
68
|
+
['organon', 'organa'],
|
|
69
|
+
['ox', 'oxen'],
|
|
70
|
+
['passerby', 'passersby'],
|
|
46
71
|
['phenomenon', 'phenomena'],
|
|
47
|
-
['
|
|
48
|
-
['
|
|
49
|
-
['
|
|
50
|
-
['vertex', 'vertices'],
|
|
51
|
-
['quiz', 'quizzes'],
|
|
52
|
-
['die', 'dice'],
|
|
53
|
-
['yes', 'yeses'],
|
|
54
|
-
['human', 'humans'],
|
|
72
|
+
['pickaxe', 'pickaxes'],
|
|
73
|
+
['potato', 'potatoes'],
|
|
74
|
+
['prolegomenon', 'prolegomena'],
|
|
55
75
|
['proof', 'proofs'],
|
|
56
|
-
['
|
|
57
|
-
['
|
|
58
|
-
['
|
|
76
|
+
['quiz', 'quizzes'],
|
|
77
|
+
['schema', 'schemata'],
|
|
78
|
+
['self', 'selves'],
|
|
79
|
+
['shelf', 'shelves'],
|
|
80
|
+
['stigma', 'stigmata'],
|
|
81
|
+
['stoma', 'stomata'],
|
|
59
82
|
['thief', 'thieves'],
|
|
60
|
-
['
|
|
61
|
-
['
|
|
62
|
-
['passerby', 'passersby'],
|
|
63
|
-
['honey', 'honeys'],
|
|
64
|
-
// Words ending in with a consonant and `o`.
|
|
65
|
-
['echo', 'echoes'],
|
|
66
|
-
['dingo', 'dingoes'],
|
|
67
|
-
['mango', 'mangoes'],
|
|
68
|
-
['volcano', 'volcanoes'],
|
|
69
|
-
['tornado', 'tornadoes'],
|
|
83
|
+
['tooth', 'teeth'],
|
|
84
|
+
['tomato', 'tomatoes'],
|
|
70
85
|
['torpedo', 'torpedoes'],
|
|
71
|
-
|
|
72
|
-
['
|
|
86
|
+
['tornado', 'tornadoes'],
|
|
87
|
+
['valve', 'valves'],
|
|
88
|
+
['vertex', 'vertices'],
|
|
89
|
+
['virus', 'viruses'],
|
|
73
90
|
['viscus', 'viscera'],
|
|
74
|
-
|
|
75
|
-
['
|
|
76
|
-
['
|
|
77
|
-
['
|
|
78
|
-
['lemma', 'lemmata'],
|
|
79
|
-
['schema', 'schemata'],
|
|
80
|
-
['anathema', 'anathemata'],
|
|
91
|
+
['volcano', 'volcanoes'],
|
|
92
|
+
['woman', 'women'],
|
|
93
|
+
['wolf', 'wolves'],
|
|
94
|
+
['yes', 'yeses'],
|
|
81
95
|
]);
|
|
82
|
-
/**
|
|
96
|
+
/** Pluralization rules with regex and replacements */
|
|
83
97
|
exports.pluralRules =
|
|
84
98
|
/* @__PURE__ */ Object.freeze([
|
|
85
|
-
[/
|
|
99
|
+
[/s?$/i, 's'],
|
|
86
100
|
[/(pe)(rson|ople)$/i, '$1ople'],
|
|
87
101
|
[/(child)(?:ren)?$/i, '$1ren'],
|
|
88
|
-
[/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i, '$1ices'],
|
|
89
|
-
[
|
|
90
|
-
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
91
|
-
'$1i',
|
|
92
|
-
],
|
|
93
102
|
[/(alumn|alg|vertebr)(?:a|ae)$/i, '$1ae'],
|
|
94
103
|
[
|
|
95
104
|
/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,
|
|
@@ -108,18 +117,94 @@ exports.pluralRules =
|
|
|
108
117
|
[/(x|ch|ss|sh|zz)$/i, '$1es'],
|
|
109
118
|
[/(her|at|gr)o$/i, '$1oes'],
|
|
110
119
|
[/sis$/i, 'ses'],
|
|
111
|
-
[
|
|
120
|
+
[/^(chief|chef|belief|roof|cliff|reef)$/i, '$1s'],
|
|
121
|
+
[/(seraph|cherub)$/i, '$1im'],
|
|
122
|
+
[/(kni|wi|li)fe$/i, '$1ves'],
|
|
123
|
+
[/(ar|l|ea|eo|oa|hoo)f$/i, '$1ves'],
|
|
112
124
|
[/([^aeiouy]|qu)y$/i, '$1ies'],
|
|
113
125
|
[/(tive)$/i, '$1s'],
|
|
114
126
|
[/(hive)$/i, '$1s'],
|
|
115
127
|
[/(quiz)$/i, '$1zes'],
|
|
116
128
|
[/m[ae]n$/i, 'men'],
|
|
117
129
|
[/eaux$/i, '$0'],
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
[
|
|
131
|
+
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
132
|
+
'$1i',
|
|
133
|
+
],
|
|
120
134
|
]);
|
|
121
|
-
/**
|
|
135
|
+
/** Singularization rules with regex and replacements */
|
|
136
|
+
exports.singularRules =
|
|
137
|
+
/* @__PURE__ */ Object.freeze([
|
|
138
|
+
[/s$/i, ''],
|
|
139
|
+
[/(\P{ASCII})$/u, '$1'],
|
|
140
|
+
[/(pe)(rson|ople)$/i, '$1rson'],
|
|
141
|
+
[/(child)ren$/i, '$1'],
|
|
142
|
+
[/(eau)x?$/i, '$1'],
|
|
143
|
+
[/men$/i, 'man'],
|
|
144
|
+
[/(matr|append)ices$/i, '$1ix'],
|
|
145
|
+
[/(cod|mur|sil|vert|ind)ices$/i, '$1ex'],
|
|
146
|
+
[/(alumn|alg|vertebr)ae$/i, '$1a'],
|
|
147
|
+
[
|
|
148
|
+
/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,
|
|
149
|
+
'$1on',
|
|
150
|
+
],
|
|
151
|
+
[
|
|
152
|
+
/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,
|
|
153
|
+
'$1um',
|
|
154
|
+
],
|
|
155
|
+
[/(test)(?:is|es)$/i, '$1is'],
|
|
156
|
+
[/(movie|twelve|abuse|e[mn]u)s$/i, '$1'],
|
|
157
|
+
[
|
|
158
|
+
/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,
|
|
159
|
+
'$1sis',
|
|
160
|
+
],
|
|
161
|
+
[
|
|
162
|
+
/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,
|
|
163
|
+
'$1',
|
|
164
|
+
],
|
|
165
|
+
[/^(chief|chef|belief|roof|cliff|reef)s$/i, '$1'],
|
|
166
|
+
[/(seraph|cherub)im$/i, '$1'],
|
|
167
|
+
[/\b((?:tit)?m|l)ice$/i, '$1ouse'],
|
|
168
|
+
[/\b(mon|smil)ies$/i, '$1ey'],
|
|
169
|
+
[
|
|
170
|
+
/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,
|
|
171
|
+
'$1ie',
|
|
172
|
+
],
|
|
173
|
+
[/ies$/i, 'y'],
|
|
174
|
+
[/(kni|wi|li)ves$/i, '$1fe'],
|
|
175
|
+
[/(ar|l|ea|eo|oa|hoo)ves$/i, '$1f'],
|
|
176
|
+
[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, '$1f'],
|
|
177
|
+
[
|
|
178
|
+
/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,
|
|
179
|
+
'$1fe',
|
|
180
|
+
],
|
|
181
|
+
[/(ss)$/i, '$1'],
|
|
182
|
+
[/(quiz)zes$/i, '$1'],
|
|
183
|
+
[/(vert|ind)ices$/i, '$1ex'],
|
|
184
|
+
[/^(ox)en$/i, '$1'],
|
|
185
|
+
[/(alias|status)es$/i, '$1'],
|
|
186
|
+
[/(octop|vir)i$/i, '$1us'],
|
|
187
|
+
[/(cris|ax|test)es$/i, '$1is'],
|
|
188
|
+
[/(shoe)s$/i, '$1'],
|
|
189
|
+
[/(her|at|gr)oes$/i, '$1o'],
|
|
190
|
+
[/oes$/i, 'o'],
|
|
191
|
+
[/(bus)es$/i, '$1'],
|
|
192
|
+
[/ices$/i, 'ex'],
|
|
193
|
+
[/(hive)s$/i, '$1'],
|
|
194
|
+
[/(tive)s$/i, '$1'],
|
|
195
|
+
[/([^f])ves$/i, '$1fe'],
|
|
196
|
+
[/([lr])ves$/i, '$1f'],
|
|
197
|
+
[/(^analy)ses$/i, '$1sis'],
|
|
198
|
+
[/([ti])a$/i, '$1um'],
|
|
199
|
+
[/(n)ews$/i, '$1ews'],
|
|
200
|
+
[
|
|
201
|
+
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
202
|
+
'$1us',
|
|
203
|
+
],
|
|
204
|
+
]);
|
|
205
|
+
/** Uncountable words */
|
|
122
206
|
exports.uncountables = Object.freeze(new Set([
|
|
207
|
+
// common
|
|
123
208
|
'aircraft',
|
|
124
209
|
'alcohol',
|
|
125
210
|
'ammo',
|
|
@@ -170,6 +255,7 @@ exports.uncountables = Object.freeze(new Set([
|
|
|
170
255
|
'weather',
|
|
171
256
|
'wildlife',
|
|
172
257
|
'you',
|
|
258
|
+
// abstract
|
|
173
259
|
'adulthood',
|
|
174
260
|
'advertising',
|
|
175
261
|
'anger',
|
|
@@ -181,9 +267,9 @@ exports.uncountables = Object.freeze(new Set([
|
|
|
181
267
|
'botany',
|
|
182
268
|
'carbon',
|
|
183
269
|
'chaos',
|
|
184
|
-
'coffee',
|
|
185
270
|
'cheese',
|
|
186
271
|
'childhood',
|
|
272
|
+
'coffee',
|
|
187
273
|
'compassion',
|
|
188
274
|
'cotton',
|
|
189
275
|
'dancing',
|
|
@@ -358,7 +444,7 @@ exports.uncountables = Object.freeze(new Set([
|
|
|
358
444
|
'youth',
|
|
359
445
|
'zinc',
|
|
360
446
|
'zoology',
|
|
361
|
-
//
|
|
447
|
+
// regex-based uncountables
|
|
362
448
|
/pok[eé]mon$/i,
|
|
363
449
|
/[^aeiou]ese$/i,
|
|
364
450
|
/deer$/i,
|
|
@@ -373,71 +459,3 @@ exports.uncountables = Object.freeze(new Set([
|
|
|
373
459
|
/trousers$/i,
|
|
374
460
|
/jeans$/i,
|
|
375
461
|
]));
|
|
376
|
-
/** Singular rules and replacements */
|
|
377
|
-
exports.singularRules =
|
|
378
|
-
/* @__PURE__ */ Object.freeze([
|
|
379
|
-
[/(\P{ASCII})$/u, '$1'],
|
|
380
|
-
[/(pe)(rson|ople)$/i, '$1rson'],
|
|
381
|
-
[/(child)ren$/i, '$1'],
|
|
382
|
-
[/(eau)x?$/i, '$1'],
|
|
383
|
-
[/men$/i, 'man'],
|
|
384
|
-
[/(matr|append)ices$/i, '$1ix'],
|
|
385
|
-
[/(cod|mur|sil|vert|ind)ices$/i, '$1ex'],
|
|
386
|
-
[/(alumn|alg|vertebr)ae$/i, '$1a'],
|
|
387
|
-
[
|
|
388
|
-
/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,
|
|
389
|
-
'$1on',
|
|
390
|
-
],
|
|
391
|
-
[
|
|
392
|
-
/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,
|
|
393
|
-
'$1um',
|
|
394
|
-
],
|
|
395
|
-
[
|
|
396
|
-
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
397
|
-
'$1us',
|
|
398
|
-
],
|
|
399
|
-
[/(test)(?:is|es)$/i, '$1is'],
|
|
400
|
-
[/(movie|twelve|abuse|e[mn]u)s$/i, '$1'],
|
|
401
|
-
[
|
|
402
|
-
/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,
|
|
403
|
-
'$1sis',
|
|
404
|
-
],
|
|
405
|
-
[
|
|
406
|
-
/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,
|
|
407
|
-
'$1',
|
|
408
|
-
],
|
|
409
|
-
[/(seraph|cherub)im$/i, '$1'],
|
|
410
|
-
[/\b((?:tit)?m|l)ice$/i, '$1ouse'],
|
|
411
|
-
[/\b(mon|smil)ies$/i, '$1ey'],
|
|
412
|
-
[
|
|
413
|
-
/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,
|
|
414
|
-
'$1ie',
|
|
415
|
-
],
|
|
416
|
-
[/ies$/i, 'y'],
|
|
417
|
-
[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, '$1f'],
|
|
418
|
-
[
|
|
419
|
-
/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,
|
|
420
|
-
'$1fe',
|
|
421
|
-
],
|
|
422
|
-
[/(ss)$/i, '$1'],
|
|
423
|
-
[/(quiz)zes$/i, '$1'],
|
|
424
|
-
[/(matr)ices$/i, '$1ix'],
|
|
425
|
-
[/(vert|ind)ices$/i, '$1ex'],
|
|
426
|
-
[/^(ox)en$/i, '$1'],
|
|
427
|
-
[/(alias|status)es$/i, '$1'],
|
|
428
|
-
[/(octop|vir)i$/i, '$1us'],
|
|
429
|
-
[/(cris|ax|test)es$/i, '$1is'],
|
|
430
|
-
[/(shoe)s$/i, '$1'],
|
|
431
|
-
[/(o)es$/i, '$1'],
|
|
432
|
-
[/(bus)es$/i, '$1'],
|
|
433
|
-
[/ices$/i, 'ex'],
|
|
434
|
-
[/(hive)s$/i, '$1'],
|
|
435
|
-
[/(tive)s$/i, '$1'],
|
|
436
|
-
[/([^f])ves$/i, '$1fe'],
|
|
437
|
-
[/([lr])ves$/i, '$1f'],
|
|
438
|
-
[/(^analy)ses$/i, '$1sis'],
|
|
439
|
-
[/([ti])a$/i, '$1um'],
|
|
440
|
-
[/(n)ews$/i, '$1ews'],
|
|
441
|
-
// <-- put generic catch-all last
|
|
442
|
-
[/s$/i, ''],
|
|
443
|
-
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Pluralizer.d.ts","sourceRoot":"","sources":["../../../src/pluralize/Pluralizer.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAgB,gBAAgB,EAAiB,MAAM,SAAS,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU;;IAOtB;;;OAGG;;
|
|
1
|
+
{"version":3,"file":"Pluralizer.d.ts","sourceRoot":"","sources":["../../../src/pluralize/Pluralizer.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAgB,gBAAgB,EAAiB,MAAM,SAAS,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU;;IAOtB;;;OAGG;;IAuGH;;;;;;OAMG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAItD;;;;;;OAMG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAIxD;;;;;;OAMG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAM3C;;;;;;OAMG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAOlD;;;;;;;;OAQG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM;IAY/D;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAiB9B;;;;;;OAMG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAiBhC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAc/B;;;;;;OAMG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAajC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,UAAU,YAAmB,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { PluralizeRule } from './types';
|
|
2
|
-
/** Irregular
|
|
2
|
+
/** Irregular singular → plural mappings */
|
|
3
3
|
export declare const irregularRules: readonly [string, string][];
|
|
4
|
-
/**
|
|
4
|
+
/** Pluralization rules with regex and replacements */
|
|
5
5
|
export declare const pluralRules: readonly PluralizeRule[];
|
|
6
|
-
/**
|
|
7
|
-
export declare const uncountables: Readonly<Set<string | RegExp>>;
|
|
8
|
-
/** Singular rules and replacements */
|
|
6
|
+
/** Singularization rules with regex and replacements */
|
|
9
7
|
export declare const singularRules: readonly PluralizeRule[];
|
|
8
|
+
/** Uncountable words */
|
|
9
|
+
export declare const uncountables: Readonly<Set<string | RegExp>>;
|
|
10
10
|
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/pluralize/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/pluralize/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,2CAA2C;AAC3C,eAAO,MAAM,cAAc,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EA2FnD,CAAC;AAEJ,sDAAsD;AACtD,eAAO,MAAM,WAAW,EAAE,SAAS,aAAa,EAqC7C,CAAC;AAEJ,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,SAAS,aAAa,EAoE/C,CAAC;AAEJ,wBAAwB;AACxB,eAAO,MAAM,YAAY,gCAmQxB,CAAC"}
|
|
@@ -53,17 +53,31 @@ export class Pluralizer {
|
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
#restoreCase(original, transformed) {
|
|
56
|
+
// Exact match
|
|
57
|
+
if (original === transformed)
|
|
58
|
+
return transformed;
|
|
59
|
+
// Entire original is lowercase
|
|
60
|
+
if (original === original.toLowerCase()) {
|
|
61
|
+
return transformed.toLowerCase();
|
|
62
|
+
}
|
|
63
|
+
// Entire original is uppercase
|
|
64
|
+
if (original === original.toUpperCase()) {
|
|
65
|
+
return transformed.toUpperCase();
|
|
66
|
+
}
|
|
67
|
+
// Title case (first letter uppercase, rest lowercase)
|
|
68
|
+
if (original[0] === original[0].toUpperCase() &&
|
|
69
|
+
original.slice(1) === original.slice(1).toLowerCase()) {
|
|
70
|
+
return (transformed.charAt(0).toUpperCase() +
|
|
71
|
+
transformed.slice(1).toLowerCase());
|
|
72
|
+
}
|
|
73
|
+
// Mixed case: per-character casing
|
|
56
74
|
let result = '';
|
|
57
75
|
for (let i = 0; i < transformed.length; i++) {
|
|
58
76
|
const origChar = original[i];
|
|
59
|
-
if (origChar
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
result += transformed[i].toLowerCase();
|
|
66
|
-
}
|
|
77
|
+
if (origChar &&
|
|
78
|
+
origChar === origChar.toUpperCase() &&
|
|
79
|
+
origChar !== origChar.toLowerCase()) {
|
|
80
|
+
result += transformed[i].toUpperCase();
|
|
67
81
|
}
|
|
68
82
|
else {
|
|
69
83
|
result += transformed[i].toLowerCase();
|
|
@@ -207,11 +221,18 @@ export class Pluralizer {
|
|
|
207
221
|
* pluralizer.isPlural('children'); // true
|
|
208
222
|
*/
|
|
209
223
|
isPlural(word) {
|
|
210
|
-
|
|
211
|
-
if (this.#isUncountable(word))
|
|
224
|
+
if (!isNonEmptyString(word))
|
|
212
225
|
return false;
|
|
213
|
-
|
|
226
|
+
const lower = word.toLowerCase();
|
|
227
|
+
// if uncountable return true
|
|
228
|
+
if (this.#isUncountable(lower))
|
|
229
|
+
return true;
|
|
230
|
+
// directly known as plural
|
|
231
|
+
if (this.#irregularPlurals[lower])
|
|
214
232
|
return true;
|
|
233
|
+
// directly known as singular
|
|
234
|
+
if (this.#irregularSingles[lower])
|
|
235
|
+
return false;
|
|
215
236
|
return this.toSingular(lower) !== lower;
|
|
216
237
|
}
|
|
217
238
|
/**
|
|
@@ -222,12 +243,19 @@ export class Pluralizer {
|
|
|
222
243
|
* pluralizer.isSingular('child'); // true
|
|
223
244
|
*/
|
|
224
245
|
isSingular(word) {
|
|
225
|
-
|
|
226
|
-
if (this.#isUncountable(word))
|
|
246
|
+
if (!isNonEmptyString(word))
|
|
227
247
|
return false;
|
|
228
|
-
|
|
248
|
+
const lower = word.toLowerCase();
|
|
249
|
+
// if uncountable return true
|
|
250
|
+
if (this.#isUncountable(lower))
|
|
251
|
+
return true;
|
|
252
|
+
// directly known as singular
|
|
253
|
+
if (this.#irregularSingles[lower])
|
|
229
254
|
return true;
|
|
230
|
-
|
|
255
|
+
// directly known as plural
|
|
256
|
+
if (this.#irregularPlurals[lower])
|
|
257
|
+
return false;
|
|
258
|
+
return this.toSingular(lower) === lower;
|
|
231
259
|
}
|
|
232
260
|
}
|
|
233
261
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Irregular
|
|
1
|
+
/** Irregular singular → plural mappings */
|
|
2
2
|
export const irregularRules =
|
|
3
3
|
/* @__PURE__ */ Object.freeze([
|
|
4
4
|
// Pronouns
|
|
@@ -23,70 +23,79 @@ export const irregularRules =
|
|
|
23
23
|
['his', 'their'],
|
|
24
24
|
['her', 'their'],
|
|
25
25
|
// Common irregulars
|
|
26
|
+
['analysis', 'analyses'],
|
|
27
|
+
['anathema', 'anathemata'],
|
|
28
|
+
['appendix', 'appendices'],
|
|
29
|
+
['automaton', 'automata'],
|
|
30
|
+
['basis', 'bases'],
|
|
31
|
+
['calf', 'calves'],
|
|
32
|
+
['carve', 'carves'],
|
|
26
33
|
['child', 'children'],
|
|
27
|
-
['
|
|
28
|
-
['
|
|
29
|
-
['
|
|
30
|
-
['
|
|
34
|
+
['codex', 'codices'],
|
|
35
|
+
['criterion', 'criteria'],
|
|
36
|
+
['crisis', 'crises'],
|
|
37
|
+
['datum', 'data'],
|
|
38
|
+
['diagnosis', 'diagnoses'],
|
|
39
|
+
['die', 'dice'],
|
|
40
|
+
['dogma', 'dogmata'],
|
|
41
|
+
['echo', 'echoes'],
|
|
42
|
+
['elf', 'elves'],
|
|
31
43
|
['foot', 'feet'],
|
|
32
|
-
['
|
|
44
|
+
['genus', 'genera'],
|
|
33
45
|
['goose', 'geese'],
|
|
34
|
-
['
|
|
46
|
+
['groove', 'grooves'],
|
|
47
|
+
['half', 'halves'],
|
|
48
|
+
['hedron', 'hedra'],
|
|
49
|
+
['hero', 'heroes'],
|
|
50
|
+
['hoof', 'hooves'],
|
|
51
|
+
['human', 'humans'],
|
|
52
|
+
['honey', 'honeys'],
|
|
53
|
+
['index', 'indices'],
|
|
35
54
|
['leaf', 'leaves'],
|
|
36
|
-
['
|
|
55
|
+
['lemma', 'lemmata'],
|
|
56
|
+
['loaf', 'loaves'],
|
|
57
|
+
['looey', 'looies'],
|
|
58
|
+
['man', 'men'],
|
|
59
|
+
['mango', 'mangoes'],
|
|
60
|
+
['matrix', 'matrices'],
|
|
37
61
|
['medium', 'media'],
|
|
38
|
-
['
|
|
39
|
-
['
|
|
40
|
-
['
|
|
41
|
-
['
|
|
42
|
-
['
|
|
62
|
+
['mouse', 'mice'],
|
|
63
|
+
['neurosis', 'neuroses'],
|
|
64
|
+
['noumenon', 'noumena'],
|
|
65
|
+
['organon', 'organa'],
|
|
66
|
+
['ox', 'oxen'],
|
|
67
|
+
['passerby', 'passersby'],
|
|
43
68
|
['phenomenon', 'phenomena'],
|
|
44
|
-
['
|
|
45
|
-
['
|
|
46
|
-
['
|
|
47
|
-
['vertex', 'vertices'],
|
|
48
|
-
['quiz', 'quizzes'],
|
|
49
|
-
['die', 'dice'],
|
|
50
|
-
['yes', 'yeses'],
|
|
51
|
-
['human', 'humans'],
|
|
69
|
+
['pickaxe', 'pickaxes'],
|
|
70
|
+
['potato', 'potatoes'],
|
|
71
|
+
['prolegomenon', 'prolegomena'],
|
|
52
72
|
['proof', 'proofs'],
|
|
53
|
-
['
|
|
54
|
-
['
|
|
55
|
-
['
|
|
73
|
+
['quiz', 'quizzes'],
|
|
74
|
+
['schema', 'schemata'],
|
|
75
|
+
['self', 'selves'],
|
|
76
|
+
['shelf', 'shelves'],
|
|
77
|
+
['stigma', 'stigmata'],
|
|
78
|
+
['stoma', 'stomata'],
|
|
56
79
|
['thief', 'thieves'],
|
|
57
|
-
['
|
|
58
|
-
['
|
|
59
|
-
['passerby', 'passersby'],
|
|
60
|
-
['honey', 'honeys'],
|
|
61
|
-
// Words ending in with a consonant and `o`.
|
|
62
|
-
['echo', 'echoes'],
|
|
63
|
-
['dingo', 'dingoes'],
|
|
64
|
-
['mango', 'mangoes'],
|
|
65
|
-
['volcano', 'volcanoes'],
|
|
66
|
-
['tornado', 'tornadoes'],
|
|
80
|
+
['tooth', 'teeth'],
|
|
81
|
+
['tomato', 'tomatoes'],
|
|
67
82
|
['torpedo', 'torpedoes'],
|
|
68
|
-
|
|
69
|
-
['
|
|
83
|
+
['tornado', 'tornadoes'],
|
|
84
|
+
['valve', 'valves'],
|
|
85
|
+
['vertex', 'vertices'],
|
|
86
|
+
['virus', 'viruses'],
|
|
70
87
|
['viscus', 'viscera'],
|
|
71
|
-
|
|
72
|
-
['
|
|
73
|
-
['
|
|
74
|
-
['
|
|
75
|
-
['lemma', 'lemmata'],
|
|
76
|
-
['schema', 'schemata'],
|
|
77
|
-
['anathema', 'anathemata'],
|
|
88
|
+
['volcano', 'volcanoes'],
|
|
89
|
+
['woman', 'women'],
|
|
90
|
+
['wolf', 'wolves'],
|
|
91
|
+
['yes', 'yeses'],
|
|
78
92
|
]);
|
|
79
|
-
/**
|
|
93
|
+
/** Pluralization rules with regex and replacements */
|
|
80
94
|
export const pluralRules =
|
|
81
95
|
/* @__PURE__ */ Object.freeze([
|
|
82
|
-
[/
|
|
96
|
+
[/s?$/i, 's'],
|
|
83
97
|
[/(pe)(rson|ople)$/i, '$1ople'],
|
|
84
98
|
[/(child)(?:ren)?$/i, '$1ren'],
|
|
85
|
-
[/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i, '$1ices'],
|
|
86
|
-
[
|
|
87
|
-
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
88
|
-
'$1i',
|
|
89
|
-
],
|
|
90
99
|
[/(alumn|alg|vertebr)(?:a|ae)$/i, '$1ae'],
|
|
91
100
|
[
|
|
92
101
|
/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,
|
|
@@ -105,18 +114,94 @@ export const pluralRules =
|
|
|
105
114
|
[/(x|ch|ss|sh|zz)$/i, '$1es'],
|
|
106
115
|
[/(her|at|gr)o$/i, '$1oes'],
|
|
107
116
|
[/sis$/i, 'ses'],
|
|
108
|
-
[
|
|
117
|
+
[/^(chief|chef|belief|roof|cliff|reef)$/i, '$1s'],
|
|
118
|
+
[/(seraph|cherub)$/i, '$1im'],
|
|
119
|
+
[/(kni|wi|li)fe$/i, '$1ves'],
|
|
120
|
+
[/(ar|l|ea|eo|oa|hoo)f$/i, '$1ves'],
|
|
109
121
|
[/([^aeiouy]|qu)y$/i, '$1ies'],
|
|
110
122
|
[/(tive)$/i, '$1s'],
|
|
111
123
|
[/(hive)$/i, '$1s'],
|
|
112
124
|
[/(quiz)$/i, '$1zes'],
|
|
113
125
|
[/m[ae]n$/i, 'men'],
|
|
114
126
|
[/eaux$/i, '$0'],
|
|
115
|
-
|
|
116
|
-
|
|
127
|
+
[
|
|
128
|
+
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
129
|
+
'$1i',
|
|
130
|
+
],
|
|
117
131
|
]);
|
|
118
|
-
/**
|
|
132
|
+
/** Singularization rules with regex and replacements */
|
|
133
|
+
export const singularRules =
|
|
134
|
+
/* @__PURE__ */ Object.freeze([
|
|
135
|
+
[/s$/i, ''],
|
|
136
|
+
[/(\P{ASCII})$/u, '$1'],
|
|
137
|
+
[/(pe)(rson|ople)$/i, '$1rson'],
|
|
138
|
+
[/(child)ren$/i, '$1'],
|
|
139
|
+
[/(eau)x?$/i, '$1'],
|
|
140
|
+
[/men$/i, 'man'],
|
|
141
|
+
[/(matr|append)ices$/i, '$1ix'],
|
|
142
|
+
[/(cod|mur|sil|vert|ind)ices$/i, '$1ex'],
|
|
143
|
+
[/(alumn|alg|vertebr)ae$/i, '$1a'],
|
|
144
|
+
[
|
|
145
|
+
/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,
|
|
146
|
+
'$1on',
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,
|
|
150
|
+
'$1um',
|
|
151
|
+
],
|
|
152
|
+
[/(test)(?:is|es)$/i, '$1is'],
|
|
153
|
+
[/(movie|twelve|abuse|e[mn]u)s$/i, '$1'],
|
|
154
|
+
[
|
|
155
|
+
/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,
|
|
156
|
+
'$1sis',
|
|
157
|
+
],
|
|
158
|
+
[
|
|
159
|
+
/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,
|
|
160
|
+
'$1',
|
|
161
|
+
],
|
|
162
|
+
[/^(chief|chef|belief|roof|cliff|reef)s$/i, '$1'],
|
|
163
|
+
[/(seraph|cherub)im$/i, '$1'],
|
|
164
|
+
[/\b((?:tit)?m|l)ice$/i, '$1ouse'],
|
|
165
|
+
[/\b(mon|smil)ies$/i, '$1ey'],
|
|
166
|
+
[
|
|
167
|
+
/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,
|
|
168
|
+
'$1ie',
|
|
169
|
+
],
|
|
170
|
+
[/ies$/i, 'y'],
|
|
171
|
+
[/(kni|wi|li)ves$/i, '$1fe'],
|
|
172
|
+
[/(ar|l|ea|eo|oa|hoo)ves$/i, '$1f'],
|
|
173
|
+
[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, '$1f'],
|
|
174
|
+
[
|
|
175
|
+
/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,
|
|
176
|
+
'$1fe',
|
|
177
|
+
],
|
|
178
|
+
[/(ss)$/i, '$1'],
|
|
179
|
+
[/(quiz)zes$/i, '$1'],
|
|
180
|
+
[/(vert|ind)ices$/i, '$1ex'],
|
|
181
|
+
[/^(ox)en$/i, '$1'],
|
|
182
|
+
[/(alias|status)es$/i, '$1'],
|
|
183
|
+
[/(octop|vir)i$/i, '$1us'],
|
|
184
|
+
[/(cris|ax|test)es$/i, '$1is'],
|
|
185
|
+
[/(shoe)s$/i, '$1'],
|
|
186
|
+
[/(her|at|gr)oes$/i, '$1o'],
|
|
187
|
+
[/oes$/i, 'o'],
|
|
188
|
+
[/(bus)es$/i, '$1'],
|
|
189
|
+
[/ices$/i, 'ex'],
|
|
190
|
+
[/(hive)s$/i, '$1'],
|
|
191
|
+
[/(tive)s$/i, '$1'],
|
|
192
|
+
[/([^f])ves$/i, '$1fe'],
|
|
193
|
+
[/([lr])ves$/i, '$1f'],
|
|
194
|
+
[/(^analy)ses$/i, '$1sis'],
|
|
195
|
+
[/([ti])a$/i, '$1um'],
|
|
196
|
+
[/(n)ews$/i, '$1ews'],
|
|
197
|
+
[
|
|
198
|
+
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
199
|
+
'$1us',
|
|
200
|
+
],
|
|
201
|
+
]);
|
|
202
|
+
/** Uncountable words */
|
|
119
203
|
export const uncountables = /* @__PURE__ */ Object.freeze(new Set([
|
|
204
|
+
// common
|
|
120
205
|
'aircraft',
|
|
121
206
|
'alcohol',
|
|
122
207
|
'ammo',
|
|
@@ -167,6 +252,7 @@ export const uncountables = /* @__PURE__ */ Object.freeze(new Set([
|
|
|
167
252
|
'weather',
|
|
168
253
|
'wildlife',
|
|
169
254
|
'you',
|
|
255
|
+
// abstract
|
|
170
256
|
'adulthood',
|
|
171
257
|
'advertising',
|
|
172
258
|
'anger',
|
|
@@ -178,9 +264,9 @@ export const uncountables = /* @__PURE__ */ Object.freeze(new Set([
|
|
|
178
264
|
'botany',
|
|
179
265
|
'carbon',
|
|
180
266
|
'chaos',
|
|
181
|
-
'coffee',
|
|
182
267
|
'cheese',
|
|
183
268
|
'childhood',
|
|
269
|
+
'coffee',
|
|
184
270
|
'compassion',
|
|
185
271
|
'cotton',
|
|
186
272
|
'dancing',
|
|
@@ -355,7 +441,7 @@ export const uncountables = /* @__PURE__ */ Object.freeze(new Set([
|
|
|
355
441
|
'youth',
|
|
356
442
|
'zinc',
|
|
357
443
|
'zoology',
|
|
358
|
-
//
|
|
444
|
+
// regex-based uncountables
|
|
359
445
|
/pok[eé]mon$/i,
|
|
360
446
|
/[^aeiou]ese$/i,
|
|
361
447
|
/deer$/i,
|
|
@@ -370,71 +456,3 @@ export const uncountables = /* @__PURE__ */ Object.freeze(new Set([
|
|
|
370
456
|
/trousers$/i,
|
|
371
457
|
/jeans$/i,
|
|
372
458
|
]));
|
|
373
|
-
/** Singular rules and replacements */
|
|
374
|
-
export const singularRules =
|
|
375
|
-
/* @__PURE__ */ Object.freeze([
|
|
376
|
-
[/(\P{ASCII})$/u, '$1'],
|
|
377
|
-
[/(pe)(rson|ople)$/i, '$1rson'],
|
|
378
|
-
[/(child)ren$/i, '$1'],
|
|
379
|
-
[/(eau)x?$/i, '$1'],
|
|
380
|
-
[/men$/i, 'man'],
|
|
381
|
-
[/(matr|append)ices$/i, '$1ix'],
|
|
382
|
-
[/(cod|mur|sil|vert|ind)ices$/i, '$1ex'],
|
|
383
|
-
[/(alumn|alg|vertebr)ae$/i, '$1a'],
|
|
384
|
-
[
|
|
385
|
-
/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i,
|
|
386
|
-
'$1on',
|
|
387
|
-
],
|
|
388
|
-
[
|
|
389
|
-
/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i,
|
|
390
|
-
'$1um',
|
|
391
|
-
],
|
|
392
|
-
[
|
|
393
|
-
/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i,
|
|
394
|
-
'$1us',
|
|
395
|
-
],
|
|
396
|
-
[/(test)(?:is|es)$/i, '$1is'],
|
|
397
|
-
[/(movie|twelve|abuse|e[mn]u)s$/i, '$1'],
|
|
398
|
-
[
|
|
399
|
-
/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i,
|
|
400
|
-
'$1sis',
|
|
401
|
-
],
|
|
402
|
-
[
|
|
403
|
-
/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i,
|
|
404
|
-
'$1',
|
|
405
|
-
],
|
|
406
|
-
[/(seraph|cherub)im$/i, '$1'],
|
|
407
|
-
[/\b((?:tit)?m|l)ice$/i, '$1ouse'],
|
|
408
|
-
[/\b(mon|smil)ies$/i, '$1ey'],
|
|
409
|
-
[
|
|
410
|
-
/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i,
|
|
411
|
-
'$1ie',
|
|
412
|
-
],
|
|
413
|
-
[/ies$/i, 'y'],
|
|
414
|
-
[/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, '$1f'],
|
|
415
|
-
[
|
|
416
|
-
/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i,
|
|
417
|
-
'$1fe',
|
|
418
|
-
],
|
|
419
|
-
[/(ss)$/i, '$1'],
|
|
420
|
-
[/(quiz)zes$/i, '$1'],
|
|
421
|
-
[/(matr)ices$/i, '$1ix'],
|
|
422
|
-
[/(vert|ind)ices$/i, '$1ex'],
|
|
423
|
-
[/^(ox)en$/i, '$1'],
|
|
424
|
-
[/(alias|status)es$/i, '$1'],
|
|
425
|
-
[/(octop|vir)i$/i, '$1us'],
|
|
426
|
-
[/(cris|ax|test)es$/i, '$1is'],
|
|
427
|
-
[/(shoe)s$/i, '$1'],
|
|
428
|
-
[/(o)es$/i, '$1'],
|
|
429
|
-
[/(bus)es$/i, '$1'],
|
|
430
|
-
[/ices$/i, 'ex'],
|
|
431
|
-
[/(hive)s$/i, '$1'],
|
|
432
|
-
[/(tive)s$/i, '$1'],
|
|
433
|
-
[/([^f])ves$/i, '$1fe'],
|
|
434
|
-
[/([lr])ves$/i, '$1f'],
|
|
435
|
-
[/(^analy)ses$/i, '$1sis'],
|
|
436
|
-
[/([ti])a$/i, '$1um'],
|
|
437
|
-
[/(n)ews$/i, '$1ews'],
|
|
438
|
-
// <-- put generic catch-all last
|
|
439
|
-
[/s$/i, ''],
|
|
440
|
-
]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nhb-toolbox",
|
|
3
|
-
"version": "4.13.
|
|
3
|
+
"version": "4.13.7",
|
|
4
4
|
"description": "A versatile collection of smart, efficient, and reusable utility functions and classes for everyday development needs.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -243,6 +243,7 @@
|
|
|
243
243
|
},
|
|
244
244
|
"scripts": {
|
|
245
245
|
"test": "jest --coverage --verbose",
|
|
246
|
+
"start": "start coverage/lcov-report/index.html",
|
|
246
247
|
"format": "nhb-format",
|
|
247
248
|
"lint": "nhb-lint",
|
|
248
249
|
"fix": "nhb-fix",
|