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 CHANGED
@@ -6,7 +6,12 @@ All notable changes to the package will be documented here.
6
6
 
7
7
  ---
8
8
 
9
- ## [4.12.80] - 2025-07-19
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 primitives_1 = require("../guards/primitives");
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 ((0, primitives_1.isNumber)(value) ? value
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.Unit = exports.Currency = 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.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.numberToOrdinal = exports.getRandomFloat = 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 = void 0;
20
- exports.extractTimeStringFromUTC = exports.extractTimeFromUTC = exports.extractMinutesFromUTC = 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 = void 0;
21
- exports.createFormData = exports.createControlledFormData = exports.convertIntoFormData = 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 = void 0;
22
- exports.removeFromLocalStorage = exports.getFromSessionStorage = exports.getFromLocalStorage = 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 = void 0;
23
- exports.isObject = exports.isNotEmptyObject = exports.isMethodDescriptor = 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 = 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 = 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();