@fibery/pluralize 1.0.1 → 1.0.2
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/lib/src/pluralize.d.ts +19 -0
- package/{src/pluralize.ts → lib/src/pluralize.js} +224 -274
- package/package.json +4 -1
- package/.babelrc +0 -3
- package/.eslintignore +0 -2
- package/.eslintrc +0 -3
- package/CHANGELOG.md +0 -7
- package/src/pluralize.test.ts +0 -835
- package/tsconfig.build.json +0 -15
- package/tsconfig.json +0 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluralize or singularize a word based on the passed in count.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} word The word to pluralize
|
|
5
|
+
* @param {number} count How many of the word exist
|
|
6
|
+
* @param {boolean} inclusive Whether to prefix with the number (e.g. 3 ducks)
|
|
7
|
+
* @return {string}
|
|
8
|
+
*/
|
|
9
|
+
export declare function pluralize(word: string, count?: number, inclusive?: boolean): string;
|
|
10
|
+
export declare namespace pluralize {
|
|
11
|
+
var plural: (word: string) => string;
|
|
12
|
+
var isPlural: (word: string) => boolean;
|
|
13
|
+
var singular: (word: string) => string;
|
|
14
|
+
var isSingular: (word: string) => boolean;
|
|
15
|
+
var addPluralRule: (rule: string | RegExp, replacement: string) => void;
|
|
16
|
+
var addSingularRule: (rule: string | RegExp, replacement: string) => void;
|
|
17
|
+
var addUncountableRule: (word: string | RegExp) => void;
|
|
18
|
+
var addIrregularRule: (single: string, plural: string) => void;
|
|
19
|
+
}
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pluralize = pluralize;
|
|
1
4
|
/* eslint-disable max-lines */
|
|
2
5
|
// Rule storage - pluralize and singularize need to be run sequentially,
|
|
3
6
|
// while other rules can be optimized using an object for instant lookups.
|
|
4
|
-
const pluralRules
|
|
5
|
-
const singularRules
|
|
6
|
-
const uncountables
|
|
7
|
-
const irregularPlurals
|
|
8
|
-
const irregularSingles
|
|
9
|
-
|
|
7
|
+
const pluralRules = [];
|
|
8
|
+
const singularRules = [];
|
|
9
|
+
const uncountables = {};
|
|
10
|
+
const irregularPlurals = {};
|
|
11
|
+
const irregularSingles = {};
|
|
10
12
|
/**
|
|
11
13
|
* Sanitize a pluralization rule to a usable regular expression.
|
|
12
14
|
*
|
|
13
15
|
* @param {(RegExp|string)} rule
|
|
14
16
|
* @return {RegExp}
|
|
15
17
|
*/
|
|
16
|
-
function sanitizeRule(rule
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return rule;
|
|
18
|
+
function sanitizeRule(rule) {
|
|
19
|
+
if (typeof rule === "string") {
|
|
20
|
+
return new RegExp("^" + rule + "$", "i");
|
|
21
|
+
}
|
|
22
|
+
return rule;
|
|
22
23
|
}
|
|
23
|
-
|
|
24
24
|
/**
|
|
25
25
|
* Pass in a word token to produce a function that can replicate the case on
|
|
26
26
|
* another word.
|
|
@@ -29,31 +29,26 @@ function sanitizeRule(rule: string | RegExp): RegExp {
|
|
|
29
29
|
* @param {string} token
|
|
30
30
|
* @return {Function}
|
|
31
31
|
*/
|
|
32
|
-
function restoreCase(word
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
function restoreCase(word, token) {
|
|
33
|
+
// Tokens are an exact match.
|
|
34
|
+
if (word === token) {
|
|
35
|
+
return token;
|
|
36
|
+
}
|
|
37
|
+
// Lower cased words. E.g. "hello".
|
|
38
|
+
if (word === word.toLowerCase()) {
|
|
39
|
+
return token.toLowerCase();
|
|
40
|
+
}
|
|
41
|
+
// Upper cased words. E.g. "WHISKY".
|
|
42
|
+
if (word === word.toUpperCase()) {
|
|
43
|
+
return token.toUpperCase();
|
|
44
|
+
}
|
|
45
|
+
// Title cased words. E.g. "Title".
|
|
46
|
+
if (word[0] === word[0].toUpperCase()) {
|
|
47
|
+
return token.charAt(0).toUpperCase() + token.substr(1).toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
// Lower cased words. E.g. "test".
|
|
40
50
|
return token.toLowerCase();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Upper cased words. E.g. "WHISKY".
|
|
44
|
-
if (word === word.toUpperCase()) {
|
|
45
|
-
return token.toUpperCase();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Title cased words. E.g. "Title".
|
|
49
|
-
if (word[0] === word[0].toUpperCase()) {
|
|
50
|
-
return token.charAt(0).toUpperCase() + token.substr(1).toLowerCase();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Lower cased words. E.g. "test".
|
|
54
|
-
return token.toLowerCase();
|
|
55
51
|
}
|
|
56
|
-
|
|
57
52
|
/**
|
|
58
53
|
* Interpolate a regexp string.
|
|
59
54
|
*
|
|
@@ -61,12 +56,11 @@ function restoreCase(word: string, token: string): string {
|
|
|
61
56
|
* @param {Array} args
|
|
62
57
|
* @return {string}
|
|
63
58
|
*/
|
|
64
|
-
function interpolate(str
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
function interpolate(str, args) {
|
|
60
|
+
return str.replace(/\$(\d{1,2})/g, function (match, index) {
|
|
61
|
+
return args[index] || "";
|
|
62
|
+
});
|
|
68
63
|
}
|
|
69
|
-
|
|
70
64
|
/**
|
|
71
65
|
* Replace a word using a rule.
|
|
72
66
|
*
|
|
@@ -74,19 +68,16 @@ function interpolate(str: string, args: string[]): string {
|
|
|
74
68
|
* @param {Array} rule
|
|
75
69
|
* @return {string}
|
|
76
70
|
*/
|
|
77
|
-
function replace(word
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return restoreCase(match, result);
|
|
87
|
-
});
|
|
71
|
+
function replace(word, rule) {
|
|
72
|
+
return word.replace(rule[0], function (match, index) {
|
|
73
|
+
// eslint-disable-next-line prefer-rest-params
|
|
74
|
+
const result = interpolate(rule[1], arguments);
|
|
75
|
+
if (match === "") {
|
|
76
|
+
return restoreCase(word[index - 1], result);
|
|
77
|
+
}
|
|
78
|
+
return restoreCase(match, result);
|
|
79
|
+
});
|
|
88
80
|
}
|
|
89
|
-
|
|
90
81
|
/**
|
|
91
82
|
* Sanitize a word by passing in the word and sanitization rules.
|
|
92
83
|
*
|
|
@@ -95,26 +86,21 @@ function replace(word: string, rule: [RegExp, string]): string {
|
|
|
95
86
|
* @param {Array} rules
|
|
96
87
|
* @return {string}
|
|
97
88
|
*/
|
|
98
|
-
function sanitizeWord(token
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let len = rules.length;
|
|
105
|
-
|
|
106
|
-
// Iterate over the sanitization rules and use the first one to match.
|
|
107
|
-
while (len--) {
|
|
108
|
-
const rule = rules[len];
|
|
109
|
-
|
|
110
|
-
if (rule[0].test(word)) {
|
|
111
|
-
return replace(word, rule);
|
|
89
|
+
function sanitizeWord(token, word, rules) {
|
|
90
|
+
// Empty string or doesn't need fixing.
|
|
91
|
+
if (!token.length || Object.keys(uncountables).some((key) => token.includes(key))) {
|
|
92
|
+
return word;
|
|
112
93
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
94
|
+
let len = rules.length;
|
|
95
|
+
// Iterate over the sanitization rules and use the first one to match.
|
|
96
|
+
while (len--) {
|
|
97
|
+
const rule = rules[len];
|
|
98
|
+
if (rule[0].test(word)) {
|
|
99
|
+
return replace(word, rule);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return word;
|
|
116
103
|
}
|
|
117
|
-
|
|
118
104
|
/**
|
|
119
105
|
* Replace a word with the updated word.
|
|
120
106
|
*
|
|
@@ -123,52 +109,37 @@ function sanitizeWord(token: string, word: string, rules: [RegExp, string][]): s
|
|
|
123
109
|
* @param {Array} rules
|
|
124
110
|
* @return {Function}
|
|
125
111
|
*/
|
|
126
|
-
function replaceWord(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (Object.hasOwn(replaceMap, token)) {
|
|
142
|
-
return restoreCase(word, replaceMap[token]);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Run all the rules against the word.
|
|
146
|
-
return sanitizeWord(token, word, rules);
|
|
147
|
-
};
|
|
112
|
+
function replaceWord(replaceMap, keepMap, rules) {
|
|
113
|
+
return function (word) {
|
|
114
|
+
// Get the correct token and case restoration functions.
|
|
115
|
+
const token = word.toLowerCase();
|
|
116
|
+
// Check against the keep object map.
|
|
117
|
+
if (Object.hasOwn(keepMap, token)) {
|
|
118
|
+
return restoreCase(word, token);
|
|
119
|
+
}
|
|
120
|
+
// Check against the replacement map for a direct word replacement.
|
|
121
|
+
if (Object.hasOwn(replaceMap, token)) {
|
|
122
|
+
return restoreCase(word, replaceMap[token]);
|
|
123
|
+
}
|
|
124
|
+
// Run all the rules against the word.
|
|
125
|
+
return sanitizeWord(token, word, rules);
|
|
126
|
+
};
|
|
148
127
|
}
|
|
149
|
-
|
|
150
128
|
/**
|
|
151
129
|
* Check if a word is part of the map.
|
|
152
130
|
*/
|
|
153
|
-
function checkWord(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
if (Object.hasOwn(replaceMap, token)) {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return sanitizeWord(token, token, rules) === token;
|
|
169
|
-
};
|
|
131
|
+
function checkWord(replaceMap, keepMap, rules) {
|
|
132
|
+
return function (word) {
|
|
133
|
+
const token = word.toLowerCase();
|
|
134
|
+
if (Object.hasOwn(keepMap, token)) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (Object.hasOwn(replaceMap, token)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return sanitizeWord(token, token, rules) === token;
|
|
141
|
+
};
|
|
170
142
|
}
|
|
171
|
-
|
|
172
143
|
/**
|
|
173
144
|
* Pluralize or singularize a word based on the passed in count.
|
|
174
145
|
*
|
|
@@ -177,100 +148,87 @@ function checkWord(
|
|
|
177
148
|
* @param {boolean} inclusive Whether to prefix with the number (e.g. 3 ducks)
|
|
178
149
|
* @return {string}
|
|
179
150
|
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return (inclusive ? count + " " : "") + pluralized;
|
|
151
|
+
function pluralize(word, count, inclusive) {
|
|
152
|
+
if (count === undefined) {
|
|
153
|
+
return pluralize.plural(word);
|
|
154
|
+
}
|
|
155
|
+
const pluralized = count === 1 ? pluralize.singular(word) : pluralize.plural(word);
|
|
156
|
+
return (inclusive ? count + " " : "") + pluralized;
|
|
187
157
|
}
|
|
188
|
-
|
|
189
158
|
/**
|
|
190
159
|
* Pluralize a word.
|
|
191
160
|
*
|
|
192
161
|
* @type {Function}
|
|
193
162
|
*/
|
|
194
163
|
pluralize.plural = replaceWord(irregularSingles, irregularPlurals, pluralRules);
|
|
195
|
-
|
|
196
164
|
/**
|
|
197
165
|
* Check if a word is plural.
|
|
198
166
|
*
|
|
199
167
|
* @type {Function}
|
|
200
168
|
*/
|
|
201
169
|
pluralize.isPlural = checkWord(irregularSingles, irregularPlurals, pluralRules);
|
|
202
|
-
|
|
203
170
|
/**
|
|
204
171
|
* Singularize a word.
|
|
205
172
|
*
|
|
206
173
|
* @type {Function}
|
|
207
174
|
*/
|
|
208
175
|
pluralize.singular = replaceWord(irregularPlurals, irregularSingles, singularRules);
|
|
209
|
-
|
|
210
176
|
/**
|
|
211
177
|
* Check if a word is singular.
|
|
212
178
|
*
|
|
213
179
|
* @type {Function}
|
|
214
180
|
*/
|
|
215
181
|
pluralize.isSingular = checkWord(irregularPlurals, irregularSingles, singularRules);
|
|
216
|
-
|
|
217
182
|
/**
|
|
218
183
|
* Add a pluralization rule to the collection.
|
|
219
184
|
*
|
|
220
185
|
* @param {(string|RegExp)} rule
|
|
221
186
|
* @param {string} replacement
|
|
222
187
|
*/
|
|
223
|
-
pluralize.addPluralRule = function (rule
|
|
224
|
-
|
|
188
|
+
pluralize.addPluralRule = function (rule, replacement) {
|
|
189
|
+
pluralRules.push([sanitizeRule(rule), replacement]);
|
|
225
190
|
};
|
|
226
|
-
|
|
227
191
|
/**
|
|
228
192
|
* Add a singularization rule to the collection.
|
|
229
193
|
*
|
|
230
194
|
* @param {(string|RegExp)} rule
|
|
231
195
|
* @param {string} replacement
|
|
232
196
|
*/
|
|
233
|
-
pluralize.addSingularRule = function (rule
|
|
234
|
-
|
|
197
|
+
pluralize.addSingularRule = function (rule, replacement) {
|
|
198
|
+
singularRules.push([sanitizeRule(rule), replacement]);
|
|
235
199
|
};
|
|
236
|
-
|
|
237
200
|
/**
|
|
238
201
|
* Add an uncountable word rule.
|
|
239
202
|
*
|
|
240
203
|
* @param {(string|RegExp)} word
|
|
241
204
|
*/
|
|
242
|
-
pluralize.addUncountableRule = function (word
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
pluralize.addSingularRule(word, "$0");
|
|
205
|
+
pluralize.addUncountableRule = function (word) {
|
|
206
|
+
if (typeof word === "string") {
|
|
207
|
+
uncountables[word.toLowerCase()] = true;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Set singular and plural references for the word.
|
|
211
|
+
pluralize.addPluralRule(word, "$0");
|
|
212
|
+
pluralize.addSingularRule(word, "$0");
|
|
251
213
|
};
|
|
252
|
-
|
|
253
214
|
/**
|
|
254
215
|
* Add an irregular word definition.
|
|
255
216
|
*
|
|
256
217
|
* @param {string} single
|
|
257
218
|
* @param {string} plural
|
|
258
219
|
*/
|
|
259
|
-
pluralize.addIrregularRule = function (single
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
irregularPlurals[plural] = single;
|
|
220
|
+
pluralize.addIrregularRule = function (single, plural) {
|
|
221
|
+
// eslint-disable-next-line no-param-reassign
|
|
222
|
+
plural = plural.toLowerCase();
|
|
223
|
+
// eslint-disable-next-line no-param-reassign
|
|
224
|
+
single = single.toLowerCase();
|
|
225
|
+
irregularSingles[single] = plural;
|
|
226
|
+
irregularPlurals[plural] = single;
|
|
267
227
|
};
|
|
268
|
-
|
|
269
228
|
/**
|
|
270
229
|
* Irregular rules.
|
|
271
230
|
*/
|
|
272
|
-
|
|
273
|
-
[
|
|
231
|
+
[
|
|
274
232
|
// Pronouns.
|
|
275
233
|
["I", "we"],
|
|
276
234
|
["me", "us"],
|
|
@@ -328,16 +286,13 @@ pluralize.addIrregularRule = function (single: string, plural: string) {
|
|
|
328
286
|
["pickaxe", "pickaxes"],
|
|
329
287
|
["passerby", "passersby"],
|
|
330
288
|
["canvas", "canvases"],
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
return pluralize.addIrregularRule(rule[0], rule[1]);
|
|
289
|
+
].forEach(function (rule) {
|
|
290
|
+
return pluralize.addIrregularRule(rule[0], rule[1]);
|
|
334
291
|
});
|
|
335
|
-
|
|
336
292
|
/**
|
|
337
293
|
* Pluralization rules.
|
|
338
294
|
*/
|
|
339
|
-
|
|
340
|
-
[
|
|
295
|
+
[
|
|
341
296
|
[/s?$/i, "s"],
|
|
342
297
|
// eslint-disable-next-line no-control-regex
|
|
343
298
|
[/[^\u0000-\u007F]$/i, "$0"],
|
|
@@ -351,8 +306,8 @@ pluralize.addIrregularRule = function (single: string, plural: string) {
|
|
|
351
306
|
[/(seraph|cherub)(?:im)?$/i, "$1im"],
|
|
352
307
|
[/(her|at|gr)o$/i, "$1oes"],
|
|
353
308
|
[
|
|
354
|
-
|
|
355
|
-
|
|
309
|
+
/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i,
|
|
310
|
+
"$1a",
|
|
356
311
|
],
|
|
357
312
|
[/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i, "$1a"],
|
|
358
313
|
[/sis$/i, "ses"],
|
|
@@ -367,16 +322,13 @@ pluralize.addIrregularRule = function (single: string, plural: string) {
|
|
|
367
322
|
[/eaux$/i, "$0"],
|
|
368
323
|
[/m[ae]n$/i, "men"],
|
|
369
324
|
["thou", "you"],
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
return pluralize.addPluralRule(rule[0], rule[1]);
|
|
325
|
+
].forEach(function (rule) {
|
|
326
|
+
return pluralize.addPluralRule(rule[0], rule[1]);
|
|
373
327
|
});
|
|
374
|
-
|
|
375
328
|
/**
|
|
376
329
|
* Singularization rules.
|
|
377
330
|
*/
|
|
378
|
-
|
|
379
|
-
[
|
|
331
|
+
[
|
|
380
332
|
[/s$/i, ""],
|
|
381
333
|
[/(ss)$/i, "$1"],
|
|
382
334
|
[/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i, "$1fe"],
|
|
@@ -384,8 +336,8 @@ pluralize.addIrregularRule = function (single: string, plural: string) {
|
|
|
384
336
|
[/ies$/i, "y"],
|
|
385
337
|
[/(dg|ss|ois|lk|ok|wn|mb|th|ch|ec|oal|is|ck|ix|sser|ts|wb)ies$/i, "$1ie"],
|
|
386
338
|
[
|
|
387
|
-
|
|
388
|
-
|
|
339
|
+
/\b(l|(?:neck|cross|hog|aun)?t|coll|faer|food|gen|goon|group|hipp|junk|vegg|(?:pork)?p|charl|calor|cut)ies$/i,
|
|
340
|
+
"$1ie",
|
|
389
341
|
],
|
|
390
342
|
[/\b(mon|smil)ies$/i, "$1ey"],
|
|
391
343
|
[/\b((?:tit)?m|l)ice$/i, "$1ouse"],
|
|
@@ -404,116 +356,114 @@ pluralize.addIrregularRule = function (single: string, plural: string) {
|
|
|
404
356
|
[/(child)ren$/i, "$1"],
|
|
405
357
|
[/(eau)x?$/i, "$1"],
|
|
406
358
|
[/men$/i, "man"],
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
return pluralize.addSingularRule(rule[0], rule[1]);
|
|
359
|
+
].forEach(function (rule) {
|
|
360
|
+
return pluralize.addSingularRule(rule[0], rule[1]);
|
|
410
361
|
});
|
|
411
|
-
|
|
412
362
|
/**
|
|
413
363
|
* Uncountable rules.
|
|
414
364
|
*/
|
|
415
365
|
[
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
366
|
+
// Singular words with no plurals.
|
|
367
|
+
"adulthood",
|
|
368
|
+
"advice",
|
|
369
|
+
"agenda",
|
|
370
|
+
"aid",
|
|
371
|
+
"aircraft",
|
|
372
|
+
"alcohol",
|
|
373
|
+
"ammo",
|
|
374
|
+
"analytics",
|
|
375
|
+
"anime",
|
|
376
|
+
"athletics",
|
|
377
|
+
"audio",
|
|
378
|
+
"bison",
|
|
379
|
+
"blood",
|
|
380
|
+
"bream",
|
|
381
|
+
"buffalo",
|
|
382
|
+
"butter",
|
|
383
|
+
"carp",
|
|
384
|
+
"cash",
|
|
385
|
+
"chassis",
|
|
386
|
+
"chess",
|
|
387
|
+
"clothing",
|
|
388
|
+
"cod",
|
|
389
|
+
"commerce",
|
|
390
|
+
"cooperation",
|
|
391
|
+
"corps",
|
|
392
|
+
"debris",
|
|
393
|
+
"diabetes",
|
|
394
|
+
"digestion",
|
|
395
|
+
"elk",
|
|
396
|
+
"energy",
|
|
397
|
+
"equipment",
|
|
398
|
+
"excretion",
|
|
399
|
+
"expertise",
|
|
400
|
+
"firmware",
|
|
401
|
+
"flounder",
|
|
402
|
+
"fun",
|
|
403
|
+
"gallows",
|
|
404
|
+
"garbage",
|
|
405
|
+
"graffiti",
|
|
406
|
+
"hardware",
|
|
407
|
+
"headquarters",
|
|
408
|
+
"health",
|
|
409
|
+
"herpes",
|
|
410
|
+
"highjinks",
|
|
411
|
+
"homework",
|
|
412
|
+
"housework",
|
|
413
|
+
"information",
|
|
414
|
+
"jeans",
|
|
415
|
+
"justice",
|
|
416
|
+
"kudos",
|
|
417
|
+
"labour",
|
|
418
|
+
"literature",
|
|
419
|
+
"machinery",
|
|
420
|
+
"mackerel",
|
|
421
|
+
"mail",
|
|
422
|
+
"media",
|
|
423
|
+
"mews",
|
|
424
|
+
"moose",
|
|
425
|
+
"music",
|
|
426
|
+
"mud",
|
|
427
|
+
"manga",
|
|
428
|
+
"news",
|
|
429
|
+
"only",
|
|
430
|
+
"personnel",
|
|
431
|
+
"pike",
|
|
432
|
+
"plankton",
|
|
433
|
+
"pliers",
|
|
434
|
+
"police",
|
|
435
|
+
"pollution",
|
|
436
|
+
"premises",
|
|
437
|
+
"rain",
|
|
438
|
+
"research",
|
|
439
|
+
"rice",
|
|
440
|
+
"salmon",
|
|
441
|
+
"scissors",
|
|
442
|
+
"series",
|
|
443
|
+
"sewage",
|
|
444
|
+
"shambles",
|
|
445
|
+
"shrimp",
|
|
446
|
+
"software",
|
|
447
|
+
"staff",
|
|
448
|
+
"swine",
|
|
449
|
+
"tennis",
|
|
450
|
+
"traffic",
|
|
451
|
+
"transportation",
|
|
452
|
+
"trout",
|
|
453
|
+
"tuna",
|
|
454
|
+
"wealth",
|
|
455
|
+
"welfare",
|
|
456
|
+
"whiting",
|
|
457
|
+
"wildebeest",
|
|
458
|
+
"wildlife",
|
|
459
|
+
"you",
|
|
460
|
+
/pok[eé]mon$/i,
|
|
461
|
+
// Regexes.
|
|
462
|
+
/[^aeiou]ese$/i, // "chinese", "japanese"
|
|
463
|
+
/deer$/i, // "deer", "reindeer"
|
|
464
|
+
/fish$/i, // "fish", "blowfish", "angelfish"
|
|
465
|
+
/measles$/i,
|
|
466
|
+
/o[iu]s$/i, // "carnivorous"
|
|
467
|
+
/pox$/i, // "chickpox", "smallpox"
|
|
468
|
+
/sheep$/i,
|
|
519
469
|
].forEach(pluralize.addUncountableRule);
|