nhb-toolbox 4.12.80 → 4.13.0
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 +6 -1
- package/README.md +6 -0
- package/dist/cjs/array/helpers.js +2 -5
- package/dist/cjs/index.js +12 -7
- package/dist/cjs/number/utilities.js +17 -1
- package/dist/cjs/pluralize/Pluralizer.js +228 -0
- package/dist/cjs/pluralize/rules.js +430 -0
- package/dist/cjs/pluralize/types.js +2 -0
- package/dist/dts/array/helpers.d.ts.map +1 -1
- package/dist/dts/date/Chronos.d.ts.map +1 -1
- package/dist/dts/index.d.ts +2 -1
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/number/utilities.d.ts +9 -0
- package/dist/dts/number/utilities.d.ts.map +1 -1
- package/dist/dts/pluralize/Pluralizer.d.ts +114 -0
- package/dist/dts/pluralize/Pluralizer.d.ts.map +1 -0
- package/dist/dts/pluralize/rules.d.ts +5 -0
- package/dist/dts/pluralize/rules.d.ts.map +1 -0
- package/dist/dts/pluralize/types.d.ts +23 -0
- package/dist/dts/pluralize/types.d.ts.map +1 -0
- package/dist/esm/array/helpers.js +2 -5
- package/dist/esm/index.js +3 -1
- package/dist/esm/number/utilities.js +15 -0
- package/dist/esm/pluralize/Pluralizer.js +224 -0
- package/dist/esm/pluralize/rules.js +427 -0
- package/dist/esm/pluralize/types.js +1 -0
- package/package.json +11 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,12 @@ All notable changes to the package will be documented here.
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## [4.
|
|
9
|
+
## [4.13.0] - 2025-07-21
|
|
10
|
+
|
|
11
|
+
- **Added** new `Pluralizer` class and utility `pluralizer` (shared instance of `Pluralizer` class) with multiple methods.
|
|
12
|
+
- **Refactored** codes in number utilities, introduced new `normalizeNumber` utility.
|
|
13
|
+
|
|
14
|
+
## [4.12.80-81] - 2025-07-19
|
|
10
15
|
|
|
11
16
|
- **Updated** `convertArrayToString` to accept array of any primitive values.
|
|
12
17
|
- **Fully integrated** with [nhb-scripts](https://www.npmjs.com/package/nhb-scripts/).
|
package/README.md
CHANGED
|
@@ -300,6 +300,12 @@ debounceAction(fetchResults, 300);
|
|
|
300
300
|
</a>
|
|
301
301
|
</div>
|
|
302
302
|
|
|
303
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
|
304
|
+
<a target="_blank" href="https://www.npmjs.com/package/nhb-express">
|
|
305
|
+
<img src="https://img.shields.io/badge/Express_Server_Scaffolder-nhb--express-orange" alt="nhb-express" />
|
|
306
|
+
</a>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
303
309
|
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
|
304
310
|
<a target="_blank" href="https://www.npmjs.com/package/nhb-anagram-generator">
|
|
305
311
|
<img src="https://img.shields.io/badge/Anagram_Generator-nhb--anagram--generator-teal" alt="nhb-anagram-generator" />
|
|
@@ -3,8 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports._resolveNestedKey = _resolveNestedKey;
|
|
4
4
|
exports._getNumericProp = _getNumericProp;
|
|
5
5
|
const non_primitives_1 = require("../guards/non-primitives");
|
|
6
|
-
const
|
|
7
|
-
const specials_1 = require("../guards/specials");
|
|
6
|
+
const utilities_1 = require("../number/utilities");
|
|
8
7
|
/**
|
|
9
8
|
* Safely resolves nested keys from a dot-separated string like "user.city".
|
|
10
9
|
*
|
|
@@ -36,9 +35,7 @@ function _getNumericProp(obj, path) {
|
|
|
36
35
|
return acc[key];
|
|
37
36
|
}
|
|
38
37
|
}, obj);
|
|
39
|
-
return (
|
|
40
|
-
: (0, specials_1.isNumericString)(value) ? Number(value)
|
|
41
|
-
: 0);
|
|
38
|
+
return (0, utilities_1.normalizeNumber)(value) ?? 0;
|
|
42
39
|
}
|
|
43
40
|
else {
|
|
44
41
|
return 0;
|
package/dist/cjs/index.js
CHANGED
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.
|
|
19
|
-
exports.
|
|
20
|
-
exports.
|
|
21
|
-
exports.
|
|
22
|
-
exports.
|
|
23
|
-
exports.
|
|
24
|
-
exports.isValidURL = exports.isValidEmail = exports.isUUID = exports.isURL = exports.isPhoneNumber = exports.isNumericString = exports.isNodeEnvironment = exports.isNodeENV = exports.isNode = exports.isIPAddress = exports.isExpectedNodeENV = exports.isEnvironment = exports.isEmailArray = exports.isEmail = exports.isDateString = exports.isBrowser = exports.isBase64 = exports.isValidSet = exports.isValidObject = exports.isValidMap = exports.isValidJSON = exports.isValidArray = exports.isSet = exports.isReturningPromise = exports.isRegularExpression = exports.isRegExp = exports.isPromise = exports.isObjectWithKeys = exports.isObjectEmpty = void 0;
|
|
18
|
+
exports.sumOfNumbers = exports.sumNumbers = exports.sumDigits = exports.roundToDecimal = exports.roundNumber = exports.reverseNumber = exports.getSumOfNumbers = exports.getRandomNumber = exports.getRandomInt = exports.getAverageOfNumbers = exports.getAverage = exports.convertToFixed = exports.convertToDecimal = exports.calculateLCM = exports.calculateLCD = exports.calculateHCF = exports.calculateGCD = exports.calculateAverage = exports.pluralizer = exports.Pluralizer = exports.wordCount = exports.parseNumbersFromText = exports.levenshteinDistance = exports.getLevenshteinDistance = exports.extractNumbersFromString = exports.extractNumbers = exports.countWordsInString = exports.countWords = exports.slugifyString = exports.reverseString = exports.replaceAllInString = exports.normalizeString = exports.maskString = exports.formatWithPlural = exports.formatUnitWithPlural = exports.formatNumberWithPluralUnit = exports.extractURLs = exports.extractEmails = exports.convertStringCase = exports.isSnakeCase = exports.isPascalCase = exports.isPalindrome = exports.isKebabCase = exports.isEmojiOnly = exports.isCamelCase = exports.generateAnagrams = exports.truncateString = exports.trimString = exports.generateRandomID = exports.capitalizeString = void 0;
|
|
19
|
+
exports.getRandomDecimal = exports.getOrdinalNumber = exports.getOrdinal = exports.formatCurrency = exports.convertToOrdinal = exports.convertNumberToOrdinal = exports.convertNumberToCurrency = exports.clampNumber = exports.cardinalToOrdinal = exports.isPrimeNumber = exports.isPrime = exports.getPrimeNumbers = exports.findPrimeNumbers = exports.toRomanNumeral = exports.toRoman = exports.numericToRoman = exports.numberToWordsOrdinal = exports.numberToWords = exports.numberToRoman = exports.integerToRoman = exports.convertToRomanNumerals = exports.convertNumberToWordsOrdinal = exports.convertNumberToWords = exports.cardinalWordsToOrdinal = exports.isPerfectSquare = exports.isPartOfFibonacciSeries = exports.isPartOfFibonacci = exports.isOddNumber = exports.isOdd = exports.isNumberInvalid = exports.isMultiple = exports.isInvalidNumber = exports.isFibonacci = exports.isEvenNumber = exports.isEven = exports.areNumbersInvalid = exports.areInvalidNumbers = exports.getNthFibonacci = exports.getMemoizedFibonacciSeries = exports.getMemoizedFibonacci = exports.getFibonacciSeriesMemo = exports.getFibonacciSeries = exports.getFibonacciNumbers = exports.getFibonacci = exports.generateFibonacci = exports.fibonacciGenerator = exports.calculatePercentage = exports.UnitConverter = exports.Unit = exports.Currency = void 0;
|
|
20
|
+
exports.extractHourMinute = exports.convertMinutesToUTCOffset = exports.convertMinutesToTime = exports.convertMinutesToHourMinutes = exports.chronusts = exports.chronusjs = exports.chronus = exports.chronosts = exports.chronosjs = exports.chronos = exports.INTERNALS = exports.Chronus = exports.Chronos = exports.isValidUTCOffSet = exports.isValidUTC = exports.isValidTimeString = exports.isValidTime = exports.isLeapYear = exports.isDateLike = exports.greet = exports.getGreeting = exports.generateGreeting = exports.extractSolidColorValues = exports.extractAlphaColorValues = exports.Colour = exports.Color = exports.convertRgbToRgba = exports.convertRgbToHsl = exports.convertRgbToHex = exports.convertRgbaToHsla = exports.convertRgbaToHex8 = exports.convertHslToRgb = exports.convertHslToHex = exports.convertHslaToRgba = exports.convertHslaToHex8 = exports.convertHexToRgb = exports.convertHexToHsl = exports.convertHex8ToRgba = exports.convertHex8ToHsla = exports.convertColorCode = exports.generateRandomHSLColor = exports.generateRandomColorInHexRGB = exports.getColorForInitial = exports.getNumbersInRange = exports.roundToNearestInterval = exports.roundToNearest = exports.roundNumberToNearestInterval = exports.numberToOrdinal = exports.normalizeNumber = exports.getRandomFloat = void 0;
|
|
21
|
+
exports.naturalSortForString = exports.naturalSort = exports.compareSorter = exports.compareNaturally = exports.splitArrayByProperty = exports.splitArray = exports.rotateArray = exports.removeDuplicatesFromArray = exports.removeDuplicates = exports.moveArrayElement = exports.groupArrayByProperty = exports.getMissingElements = exports.getDuplicatesFromArray = exports.getDuplicates = exports.findMissingElements = exports.extractMissingElements = exports.extractDuplicatesFromArray = exports.extractDuplicates = exports.createOptionsArray = exports.sortAnArray = exports.Finder = exports.totalDeltaByField = exports.sumFieldDifference = exports.sumByField = exports.groupAndSumByField = exports.groupAndAvgByField = exports.groupAndAverageByField = exports.avgByField = exports.averageByField = exports.shuffleArray = exports.isValidEmptyArray = exports.isInvalidOrEmptyArray = exports.getLastArrayElement = exports.flattenArray = exports.filterArrayOfObjects = exports.minutesToUTCOffset = exports.getTotalMinutesFromUTC = exports.getTotalMinutesFromTime = exports.getTotalMinutes = exports.getTimeStringFromUTC = exports.getTimeFromMinutes = exports.getMinutesFromUTC = exports.getHourMinutesFromMinutes = exports.getCurrentTime = exports.getCurrentDateTime = exports.formatUTCOffset = exports.extractTotalMinutesFromTime = exports.extractTimeStringFromUTC = exports.extractTimeFromUTC = exports.extractMinutesFromUTC = void 0;
|
|
22
|
+
exports.toggleFullScreen = exports.smoothScrollTo = exports.copyToClipboard = exports.updateQueryParam = exports.queryStringToObject = exports.parseQueryString = exports.getQueryStringAsObject = exports.getQueryParams = exports.generateQueryParams = exports.formatQueryParams = exports.createQueryParams = exports.removeObjectFields = exports.removeFields = exports.remapObjectFields = exports.remapFields = exports.pickObjectFieldsByCondition = exports.pickObjectFields = exports.pickFieldsByCondition = exports.pickFields = exports.omitObjectFields = exports.omitFields = exports.deleteObjectFields = exports.deleteFields = exports.convertObjectValues = exports.sanitizeData = exports.parseStringifiedObjectValues = exports.parseObjectValues = exports.parseJsonToObject = exports.mergeObjects = exports.mergeAndFlattenObjects = exports.flattenObjectKeyValue = exports.flattenObjectDotNotation = exports.extractUpdatedFields = exports.extractUpdatedAndNewFields = exports.extractNewFields = exports.countObjectFields = exports.cloneObject = exports.isValidFormData = exports.isOriginFileObj = exports.isFileUpload = exports.isFileOrBlob = exports.isFileList = exports.isFileArray = exports.isCustomFileArray = exports.isCustomFile = exports.serializeForm = exports.parseFormData = exports.createFormData = exports.createControlledFormData = exports.convertIntoFormData = void 0;
|
|
23
|
+
exports.isMethod = exports.isMap = exports.isJSONObject = exports.isJSON = exports.isFunction = exports.isError = exports.isEmptyObjectGuard = exports.isEmptyObject = exports.isDate = exports.isArrayWithLength = exports.isArrayOfType = exports.isArray = exports.doesReturnPromise = exports.isUndefined = exports.isTruthy = exports.isSymbol = exports.isString = exports.isPrimitive = exports.isPositiveInteger = exports.isNumber = exports.isNull = exports.isNormalPrimitive = exports.isNonEmptyString = exports.isInteger = exports.isFalsy = exports.isBoolean = exports.isBigInt = exports.Paginator = exports.throttleAction = exports.parsePrimitivesDeep = exports.parseJsonDeep = exports.parseJSON = exports.joinArrayElements = exports.isDeepEqual = exports.getStaticMethodsCount = exports.getStaticMethodNames = exports.getInstanceMethodsCount = exports.getInstanceMethodNames = exports.getClassDetails = exports.deepParsePrimitives = exports.debounceAction = exports.countStaticMethods = exports.countInstanceMethods = exports.convertArrayToString = exports.saveToSessionStorage = exports.saveToLocalStorage = exports.removeFromSessionStorage = exports.removeFromLocalStorage = exports.getFromSessionStorage = exports.getFromLocalStorage = void 0;
|
|
24
|
+
exports.isValidURL = exports.isValidEmail = exports.isUUID = exports.isURL = exports.isPhoneNumber = exports.isNumericString = exports.isNodeEnvironment = exports.isNodeENV = exports.isNode = exports.isIPAddress = exports.isExpectedNodeENV = exports.isEnvironment = exports.isEmailArray = exports.isEmail = exports.isDateString = exports.isBrowser = exports.isBase64 = exports.isValidSet = exports.isValidObject = exports.isValidMap = exports.isValidJSON = exports.isValidArray = exports.isSet = exports.isReturningPromise = exports.isRegularExpression = exports.isRegExp = exports.isPromise = exports.isObjectWithKeys = exports.isObjectEmpty = exports.isObject = exports.isNotEmptyObject = exports.isMethodDescriptor = void 0;
|
|
25
25
|
// ! String Utilities
|
|
26
26
|
var basics_1 = require("./string/basics");
|
|
27
27
|
Object.defineProperty(exports, "capitalizeString", { enumerable: true, get: function () { return basics_1.capitalizeString; } });
|
|
@@ -58,6 +58,10 @@ Object.defineProperty(exports, "getLevenshteinDistance", { enumerable: true, get
|
|
|
58
58
|
Object.defineProperty(exports, "levenshteinDistance", { enumerable: true, get: function () { return utilities_1.getLevenshteinDistance; } });
|
|
59
59
|
Object.defineProperty(exports, "parseNumbersFromText", { enumerable: true, get: function () { return utilities_1.extractNumbersFromString; } });
|
|
60
60
|
Object.defineProperty(exports, "wordCount", { enumerable: true, get: function () { return utilities_1.countWords; } });
|
|
61
|
+
// ! Pluralizer Class and Its Default Instance
|
|
62
|
+
var Pluralizer_1 = require("./pluralize/Pluralizer");
|
|
63
|
+
Object.defineProperty(exports, "Pluralizer", { enumerable: true, get: function () { return Pluralizer_1.Pluralizer; } });
|
|
64
|
+
Object.defineProperty(exports, "pluralizer", { enumerable: true, get: function () { return Pluralizer_1.pluralizer; } });
|
|
61
65
|
// ! Number Utilities
|
|
62
66
|
var basics_2 = require("./number/basics");
|
|
63
67
|
Object.defineProperty(exports, "calculateAverage", { enumerable: true, get: function () { return basics_2.getAverage; } });
|
|
@@ -137,6 +141,7 @@ Object.defineProperty(exports, "getOrdinal", { enumerable: true, get: function (
|
|
|
137
141
|
Object.defineProperty(exports, "getOrdinalNumber", { enumerable: true, get: function () { return utilities_2.getOrdinal; } });
|
|
138
142
|
Object.defineProperty(exports, "getRandomDecimal", { enumerable: true, get: function () { return utilities_2.getRandomFloat; } });
|
|
139
143
|
Object.defineProperty(exports, "getRandomFloat", { enumerable: true, get: function () { return utilities_2.getRandomFloat; } });
|
|
144
|
+
Object.defineProperty(exports, "normalizeNumber", { enumerable: true, get: function () { return utilities_2.normalizeNumber; } });
|
|
140
145
|
Object.defineProperty(exports, "numberToOrdinal", { enumerable: true, get: function () { return utilities_2.getOrdinal; } });
|
|
141
146
|
Object.defineProperty(exports, "roundNumberToNearestInterval", { enumerable: true, get: function () { return utilities_2.roundToNearest; } });
|
|
142
147
|
Object.defineProperty(exports, "roundToNearest", { enumerable: true, get: function () { return utilities_2.roundToNearest; } });
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getOrdinal = exports.getRandomFloat = exports.clampNumber = exports.formatCurrency = exports.roundToNearest = void 0;
|
|
3
|
+
exports.normalizeNumber = exports.getOrdinal = exports.getRandomFloat = exports.clampNumber = exports.formatCurrency = exports.roundToNearest = void 0;
|
|
4
|
+
const primitives_1 = require("../guards/primitives");
|
|
5
|
+
const specials_1 = require("../guards/specials");
|
|
4
6
|
const constants_1 = require("./constants");
|
|
5
7
|
/**
|
|
6
8
|
* * Rounds a number to the nearest specified interval.
|
|
@@ -85,3 +87,17 @@ const getOrdinal = (num, withNumber = true) => {
|
|
|
85
87
|
return withNumber ? String(num).concat(suffix) : suffix;
|
|
86
88
|
};
|
|
87
89
|
exports.getOrdinal = getOrdinal;
|
|
90
|
+
/**
|
|
91
|
+
* * Normalize a number or numeric string to a number.
|
|
92
|
+
* @description
|
|
93
|
+
* This function checks if the input is a number or a numeric string and converts it to a number.
|
|
94
|
+
* If the input is not a valid number or numeric string, it returns undefined.
|
|
95
|
+
* @param num - The number to normalize.
|
|
96
|
+
* @returns The normalized number or undefined if the input is not a valid number or numeric string.
|
|
97
|
+
*/
|
|
98
|
+
const normalizeNumber = (num) => {
|
|
99
|
+
return ((0, primitives_1.isNumber)(num) ? num
|
|
100
|
+
: (0, specials_1.isNumericString)(num) ? Number(num)
|
|
101
|
+
: undefined);
|
|
102
|
+
};
|
|
103
|
+
exports.normalizeNumber = normalizeNumber;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pluralizer = exports.Pluralizer = void 0;
|
|
4
|
+
const utilities_1 = require("../number/utilities");
|
|
5
|
+
const rules_1 = require("./rules");
|
|
6
|
+
/**
|
|
7
|
+
* * Handles English word pluralization and singularization with support for irregular forms and uncountable nouns.
|
|
8
|
+
*
|
|
9
|
+
* - Provides methods to convert words between singular and plural forms, check if a word is plural or singular, and manage custom pluralization rules.
|
|
10
|
+
* - Supports adding custom pluralization and singularization rules, as well as uncountable nouns.
|
|
11
|
+
* - Automatically handles common irregular forms like "child" to "children"
|
|
12
|
+
* - Automatically loads common irregular forms and uncountable nouns.
|
|
13
|
+
* - Supports options for count-based pluralization, allowing for inclusive formatting.
|
|
14
|
+
* - This class is useful for applications that need to handle natural language processing, such as chatbots, content management systems, or any text processing tasks that require accurate pluralization.
|
|
15
|
+
* @example
|
|
16
|
+
* const pluralizer = new Pluralizer();
|
|
17
|
+
* pluralizer.pluralize('child'); // "children"
|
|
18
|
+
* pluralizer.toSingular('geese'); // "goose"
|
|
19
|
+
* pluralizer.isPlural('fish'); // false (uncountable)
|
|
20
|
+
*/
|
|
21
|
+
class Pluralizer {
|
|
22
|
+
#pluralRules = [];
|
|
23
|
+
#singularRules = [];
|
|
24
|
+
#uncountables = new Set();
|
|
25
|
+
#irregularSingles = {};
|
|
26
|
+
#irregularPlurals = {};
|
|
27
|
+
/**
|
|
28
|
+
* Initializes the Pluralizer with default rules and exceptions.
|
|
29
|
+
* Automatically loads irregular rules, pluralization rules, and uncountable nouns.
|
|
30
|
+
*/
|
|
31
|
+
constructor() {
|
|
32
|
+
this.#loadRules();
|
|
33
|
+
}
|
|
34
|
+
#loadRules() {
|
|
35
|
+
// ! Load irregular rules
|
|
36
|
+
rules_1.irregularRules.forEach(([single, plural]) => {
|
|
37
|
+
this.addIrregular(single, plural);
|
|
38
|
+
});
|
|
39
|
+
// ! Load plural rules
|
|
40
|
+
rules_1.pluralRules.forEach(([rule, replacement]) => {
|
|
41
|
+
this.addPluralRule(rule, replacement);
|
|
42
|
+
});
|
|
43
|
+
// ! Load uncountables
|
|
44
|
+
rules_1.uncountables.forEach((word) => {
|
|
45
|
+
this.addUncountable(word);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
#restoreCase(word, token) {
|
|
49
|
+
if (word === word.toUpperCase())
|
|
50
|
+
return token.toUpperCase();
|
|
51
|
+
if (word[0] === word[0].toUpperCase()) {
|
|
52
|
+
return token.charAt(0).toUpperCase() + token.slice(1).toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
return token.toLowerCase();
|
|
55
|
+
}
|
|
56
|
+
#sanitizeWord(word, rules) {
|
|
57
|
+
if (!word.length || this.#isUncountable(word)) {
|
|
58
|
+
return word;
|
|
59
|
+
}
|
|
60
|
+
for (let i = rules.length - 1; i >= 0; i--) {
|
|
61
|
+
const [rule, replacement] = rules[i];
|
|
62
|
+
if (rule.test(word)) {
|
|
63
|
+
return word.replace(rule, replacement);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return word;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if a word is uncountable.
|
|
70
|
+
* Supports both string and RegExp entries.
|
|
71
|
+
*/
|
|
72
|
+
#isUncountable(word) {
|
|
73
|
+
const lower = word.toLowerCase();
|
|
74
|
+
for (const entry of this.#uncountables) {
|
|
75
|
+
if (typeof entry === 'string') {
|
|
76
|
+
if (entry === lower)
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
if (entry.test(word))
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* * Add a new pluralization rule.
|
|
88
|
+
* @param rule Pattern to match singular words.
|
|
89
|
+
* @param replacement Replacement pattern for plural form.
|
|
90
|
+
* @example
|
|
91
|
+
* pluralizer.addPluralRule(/(quiz)$/i, '$1zes');
|
|
92
|
+
*/
|
|
93
|
+
addPluralRule(rule, replacement) {
|
|
94
|
+
this.#pluralRules.push([rule, replacement]);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Add a new singularization rule.
|
|
98
|
+
* @param rule Pattern to match plural words.
|
|
99
|
+
* @param replacement Replacement pattern for singular form.
|
|
100
|
+
* @example
|
|
101
|
+
* pluralizer.addSingularRule(/(matr)ices$/i, '$1ix');
|
|
102
|
+
*/
|
|
103
|
+
addSingularRule(rule, replacement) {
|
|
104
|
+
this.#singularRules.push([rule, replacement]);
|
|
105
|
+
}
|
|
106
|
+
addUncountable(word) {
|
|
107
|
+
this.#uncountables.add(typeof word === 'string' ? word.toLowerCase() : word);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Add a word or pattern that should never change between singular and plural.
|
|
111
|
+
* @param word A word or regex pattern.
|
|
112
|
+
* @example
|
|
113
|
+
* pluralizer.addUncountable('fish');
|
|
114
|
+
* pluralizer.addUncountable(/pok[eé]mon$/i);
|
|
115
|
+
*/
|
|
116
|
+
addIrregular(single, plural) {
|
|
117
|
+
const singleLower = single.toLowerCase();
|
|
118
|
+
const pluralLower = plural.toLowerCase();
|
|
119
|
+
this.#irregularSingles[singleLower] = pluralLower;
|
|
120
|
+
this.#irregularPlurals[pluralLower] = singleLower;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get the proper singular or plural form based on count.
|
|
124
|
+
* @param word Target word to pluralize or singularize.
|
|
125
|
+
* @param options Optional count and inclusive formatting.
|
|
126
|
+
* @returns The transformed word.
|
|
127
|
+
* @example
|
|
128
|
+
* pluralizer.pluralize('category', { count: 3 }); // "categories"
|
|
129
|
+
* pluralizer.pluralize('child', { count: 1, inclusive: true }); // "1 child"
|
|
130
|
+
*/
|
|
131
|
+
pluralize(word, options = {}) {
|
|
132
|
+
const count = (0, utilities_1.normalizeNumber)(options?.count);
|
|
133
|
+
if (typeof count === 'number') {
|
|
134
|
+
const pluralized = count > 1 ? this.toPlural(word) : this.toSingular(word);
|
|
135
|
+
return options.inclusive ? `${count} ${pluralized}` : pluralized;
|
|
136
|
+
}
|
|
137
|
+
return this.toPlural(word);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Convert a word to its plural form.
|
|
141
|
+
* @param word Singular form of the word.
|
|
142
|
+
* @returns Plural form of the word.
|
|
143
|
+
* @example
|
|
144
|
+
* pluralizer.toPlural('analysis'); // "analyses"
|
|
145
|
+
*/
|
|
146
|
+
toPlural(word) {
|
|
147
|
+
if (!word)
|
|
148
|
+
return '';
|
|
149
|
+
const lower = word.toLowerCase();
|
|
150
|
+
if (this.#isUncountable(word))
|
|
151
|
+
return word;
|
|
152
|
+
if (this.#irregularSingles[lower]) {
|
|
153
|
+
return this.#restoreCase(word, this.#irregularSingles[lower]);
|
|
154
|
+
}
|
|
155
|
+
return this.#restoreCase(word, this.#sanitizeWord(lower, this.#pluralRules));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Convert a word to its singular form.
|
|
159
|
+
* @param word Plural form of the word.
|
|
160
|
+
* @returns Singular form of the word.
|
|
161
|
+
* @example
|
|
162
|
+
* pluralizer.toSingular('geese'); // "goose"
|
|
163
|
+
*/
|
|
164
|
+
toSingular(word) {
|
|
165
|
+
if (!word)
|
|
166
|
+
return '';
|
|
167
|
+
const lower = word.toLowerCase();
|
|
168
|
+
if (this.#isUncountable(word))
|
|
169
|
+
return word;
|
|
170
|
+
if (this.#irregularPlurals[lower]) {
|
|
171
|
+
return this.#restoreCase(word, this.#irregularPlurals[lower]);
|
|
172
|
+
}
|
|
173
|
+
return this.#restoreCase(word, this.#sanitizeWord(lower, this.#singularRules));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Check if a given word is plural.
|
|
177
|
+
* @param word Word to check.
|
|
178
|
+
* @returns True if the word is plural, otherwise false.
|
|
179
|
+
* @example
|
|
180
|
+
* pluralizer.isPlural('children'); // true
|
|
181
|
+
*/
|
|
182
|
+
isPlural(word) {
|
|
183
|
+
const lower = word?.toLowerCase();
|
|
184
|
+
if (this.#isUncountable(word))
|
|
185
|
+
return false;
|
|
186
|
+
if (this.#irregularPlurals?.[lower])
|
|
187
|
+
return true;
|
|
188
|
+
return this.toSingular(lower) !== lower;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Check if a given word is singular.
|
|
192
|
+
* @param word Word to check.
|
|
193
|
+
* @returns True if the word is singular, otherwise false.
|
|
194
|
+
* @example
|
|
195
|
+
* pluralizer.isSingular('child'); // true
|
|
196
|
+
*/
|
|
197
|
+
isSingular(word) {
|
|
198
|
+
const lower = word?.toLowerCase();
|
|
199
|
+
if (this.#isUncountable(word))
|
|
200
|
+
return false;
|
|
201
|
+
if (this.#irregularSingles?.[lower])
|
|
202
|
+
return true;
|
|
203
|
+
return this.toPlural(lower) !== lower;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
exports.Pluralizer = Pluralizer;
|
|
207
|
+
/**
|
|
208
|
+
* Default shared instance of {@link Pluralizer}.
|
|
209
|
+
*
|
|
210
|
+
* - _Use this when you don’t need multiple configurations._
|
|
211
|
+
* - _It comes preloaded with standard pluralization rules, irregular forms, and uncountable nouns._
|
|
212
|
+
*
|
|
213
|
+
* * Handles English word pluralization and singularization with support for irregular forms and uncountable nouns.
|
|
214
|
+
*
|
|
215
|
+
* - Provides methods to convert words between singular and plural forms, check if a word is plural or singular, and manage custom pluralization rules.
|
|
216
|
+
* - Supports adding custom pluralization and singularization rules, as well as uncountable nouns.
|
|
217
|
+
* - Automatically handles common irregular forms like "child" to "children"
|
|
218
|
+
* - Automatically loads common irregular forms and uncountable nouns.
|
|
219
|
+
* - Supports options for count-based pluralization, allowing for inclusive formatting.
|
|
220
|
+
* - This is useful for applications that need to handle natural language processing, such as chatbots, content management systems, or any text processing tasks that require accurate pluralization.
|
|
221
|
+
* @example
|
|
222
|
+
* import { pluralizer } from 'nhb-toolbox';
|
|
223
|
+
*
|
|
224
|
+
* pluralizer.pluralize('child'); // "children"
|
|
225
|
+
* pluralizer.toSingular('geese'); // "goose"
|
|
226
|
+
* pluralizer.isPlural('fish'); // false (uncountable)
|
|
227
|
+
*/
|
|
228
|
+
exports.pluralizer = new Pluralizer();
|