nhb-toolbox 4.13.0 β†’ 4.13.3

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,16 @@ All notable changes to the package will be documented here.
6
6
 
7
7
  ---
8
8
 
9
- ## [4.13.0] - 2025-07-21
9
+ ## [4.13.3] - 2025-07-22
10
+
11
+ - **Updated** pluralization/uncountable rules, case restoration method and fixed other bugs in `pluralizer`.
12
+ - **Updated** docs for `pluralizer`, `Pluralizer` and `formatUnitWithPlural`.
13
+
14
+ ## [4.13.1] - 2025-07-22
15
+
16
+ - **Updated** docs in [README](README.md) for `pluralizer`.
17
+
18
+ ## [4.13.0] - 2025-07-22
10
19
 
11
20
  - **Added** new `Pluralizer` class and utility `pluralizer` (shared instance of `Pluralizer` class) with multiple methods.
12
21
  - **Refactored** codes in number utilities, introduced new `normalizeNumber` utility.
package/README.md CHANGED
@@ -68,7 +68,7 @@ See [Changelog](CHANGELOG.md) for recent updates.
68
68
 
69
69
  ## Signature Utilities
70
70
 
71
- ### πŸ•°οΈ **Chronos - Time Mastery**
71
+ ### πŸ•°οΈ Chronos - Time Mastery
72
72
 
73
73
  The ultimate date/time manipulation class with 100+ methods for parsing, formatting, calculating, and comparing dates. Handles all edge cases and timezones safely.
74
74
 
@@ -82,7 +82,9 @@ chronos('2025-01-01').addDays(3).format('YYYY-MM-DD'); // "2025-01-04"
82
82
 
83
83
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/classes/Chronos)
84
84
 
85
- ### 🎨 **Color - Professional Color Manipulation**
85
+ ---
86
+
87
+ ### 🎨 Color - Professional Color Manipulation
86
88
 
87
89
  Convert between color formats, generate palettes, check accessibility contrast, and perform advanced color math with perfect type safety.
88
90
 
@@ -94,7 +96,9 @@ console.log(darkerBlue.hsl); // "hsl(240, 100%, 40%)" (was 50%)
94
96
 
95
97
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/classes/Color)
96
98
 
97
- ### πŸ” **Finder - Optimized Array Search**
99
+ ---
100
+
101
+ ### πŸ” Finder - Optimized Array Search
98
102
 
99
103
  Blazing-fast array searching with binary search, fuzzy matching, and smart caching. Perfect for large datasets.
100
104
 
@@ -109,9 +113,11 @@ const laptop = productFinder.findOne('laptop', 'category', {
109
113
 
110
114
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/classes/Finder)
111
115
 
112
- ### πŸ†” **Random ID Generation**
116
+ ---
113
117
 
114
- **`generateRandomID`** - Enterprise-grade unique ID generation with prefixes, timestamps, and formatting
118
+ ### πŸ†” Random ID Generation
119
+
120
+ **`generateRandomID`** - Enterprise-grade unique ID generation with prefixes, timestamps, and formatting.
115
121
 
116
122
  ```typescript
117
123
  generateRandomID({
@@ -124,7 +130,32 @@ generateRandomID({
124
130
 
125
131
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/string/generateRandomID)
126
132
 
127
- ### 🎨 **Color System Utilities**
133
+ ---
134
+
135
+ ### πŸ”’ Pluralize Strings and More
136
+
137
+ **`pluralizer`** - Handles English word pluralization and singularization with support for irregular forms and uncountable nouns.
138
+
139
+ ```ts
140
+ import { pluralizer } from 'nhb-toolbox';
141
+
142
+ pluralizer.pluralize('child'); // "children"
143
+ pluralizer.pluralize('category', { count: 3 }); // "categories"
144
+ pluralizer.pluralize('child', { count: 1, inclusive: true }); // "1 child"
145
+
146
+ pluralizer.toSingular('geese'); // "goose"
147
+ pluralizer.toSingular('children'); // "child"
148
+
149
+ pluralizer.isPlural('children'); // true
150
+ pluralizer.isSingular('child'); // true
151
+ pluralizer.isPlural('fish'); // false (uncountable)
152
+ ```
153
+
154
+ [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/string/pluralizer)
155
+
156
+ ---
157
+
158
+ ### 🎨 Color System Utilities
128
159
 
129
160
  **`getColorForInitial`** - Deterministic color mapping system for consistent UI theming
130
161
 
@@ -138,6 +169,8 @@ getColorForInitial('Banana', 50); // '#00376E80' (50% opacity)
138
169
 
139
170
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/color/getColorForInitial)
140
171
 
172
+ ---
173
+
141
174
  ### FormData Preparation
142
175
 
143
176
  Convert JavaScript objects into `FormData` with extensive configuration options for handling nested structures, files, and data transformations.
@@ -169,7 +202,9 @@ const formData = createFormData({
169
202
 
170
203
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/form/createFormData)
171
204
 
172
- ### πŸ›‘οΈ **Sanitize Data**
205
+ ---
206
+
207
+ ### πŸ›‘οΈ Data Sanitization
173
208
 
174
209
  Clean and normalize strings/objects by trimming whitespace, removing empty values, and applying customizable filters.
175
210
 
@@ -192,7 +227,9 @@ sanitizeData(user, { ignoreNullish: true }, 'partial');
192
227
 
193
228
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/object/sanitizeData)
194
229
 
195
- ### πŸ”„ **JSON Hydration**
230
+ ---
231
+
232
+ ### πŸ”„ JSON Hydration
196
233
 
197
234
  **`parseJSON`** - Bulletproof JSON parsing with primitive conversion
198
235
 
@@ -202,19 +239,9 @@ parseJSON('{"value":"42"}'); // { value: 42 } (auto-converts numbers)
202
239
 
203
240
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/misc/parseJSON)
204
241
 
205
- ### πŸ’° **Format Currency**
206
-
207
- Intelligent currency formatting with automatic locale detection and 150+ supported currencies.
208
-
209
- ```typescript
210
- console.log(formatCurrency(99.99, 'EUR')); // "99,99 €"
211
- console.log(formatCurrency('5000', 'JPY')); // "οΏ₯5,000" (ja-JP locale)
212
- console.log(formatCurrency('5000', 'BDT')); // "৫,০০০.০০৳" (bn-BD locale)
213
- ```
214
-
215
- [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/number/formatCurrency)
242
+ ---
216
243
 
217
- ### πŸ”’ **Number to Words**
244
+ ### πŸ”’ Number to Words
218
245
 
219
246
  Convert numbers to human-readable words (supports up to 100 quintillion).
220
247
 
@@ -224,7 +251,9 @@ numberToWords(125); // "one hundred twenty-five"
224
251
 
225
252
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/number/numberToWords)
226
253
 
227
- ### πŸ”’ **Advanced Number Operations**
254
+ ---
255
+
256
+ ### πŸ”’ Advanced Number Operations
228
257
 
229
258
  **`getNumbersInRange`** - Generate intelligent number sequences with prime, even/odd, and custom filtering capabilities
230
259
 
@@ -249,7 +278,9 @@ calculatePercentage({
249
278
 
250
279
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/number/calculatePercentage)
251
280
 
252
- ### πŸ”„ **Extract Updated Fields**
281
+ ---
282
+
283
+ ### πŸ”„ Extract Updated Fields
253
284
 
254
285
  Detect exactly what changed between two objects (including deep nested changes).
255
286
 
@@ -262,7 +293,9 @@ extractUpdatedFields(dbRecord, update);
262
293
 
263
294
  [Documentation β†’](https://nhb-toolbox.vercel.app/docs/utilities/object/extractUpdatedFields)
264
295
 
265
- ### ⚑ **Performance Optimizers**
296
+ ---
297
+
298
+ ### ⚑ Performance Optimizers
266
299
 
267
300
  **`throttleAction`** - Precision control for high-frequency events
268
301
 
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pluralizer = exports.Pluralizer = void 0;
4
+ const primitives_1 = require("../guards/primitives");
4
5
  const utilities_1 = require("../number/utilities");
5
6
  const rules_1 = require("./rules");
6
7
  /**
@@ -12,6 +13,11 @@ const rules_1 = require("./rules");
12
13
  * - Automatically loads common irregular forms and uncountable nouns.
13
14
  * - Supports options for count-based pluralization, allowing for inclusive formatting.
14
15
  * - 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.
16
+ *
17
+ * @remarks For simpler pluralization (plural with only 's'), please refer to {@link https://nhb-toolbox.vercel.app/docs/utilities/string/formatUnitWithPlural formatUnitWithPlural} instead.
18
+ *
19
+ * @remarks For ready to use instance, please refer to {@link https://nhb-toolbox.vercel.app/docs/utilities/string/pluralizer pluralizer} instead.
20
+ *
15
21
  * @example
16
22
  * const pluralizer = new Pluralizer();
17
23
  * pluralizer.pluralize('child'); // "children"
@@ -26,7 +32,7 @@ class Pluralizer {
26
32
  #irregularPlurals = {};
27
33
  /**
28
34
  * Initializes the Pluralizer with default rules and exceptions.
29
- * Automatically loads irregular rules, pluralization rules, and uncountable nouns.
35
+ * Automatically loads irregular, pluralization and singular rules along with pre-defined uncountable nouns.
30
36
  */
31
37
  constructor() {
32
38
  this.#loadRules();
@@ -40,21 +46,38 @@ class Pluralizer {
40
46
  rules_1.pluralRules.forEach(([rule, replacement]) => {
41
47
  this.addPluralRule(rule, replacement);
42
48
  });
49
+ // ! Load singular rules
50
+ rules_1.singularRules.forEach(([rule, replacement]) => {
51
+ this.addSingularRule(rule, replacement);
52
+ });
43
53
  // ! Load uncountables
44
54
  rules_1.uncountables.forEach((word) => {
45
55
  this.addUncountable(word);
46
56
  });
47
57
  }
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();
58
+ #restoreCase(original, transformed) {
59
+ let result = '';
60
+ for (let i = 0; i < transformed.length; i++) {
61
+ const origChar = original[i];
62
+ if (origChar) {
63
+ if (origChar.toUpperCase() === origChar &&
64
+ origChar.toLowerCase() !== origChar) {
65
+ result += transformed[i].toUpperCase();
66
+ }
67
+ else {
68
+ result += transformed[i].toLowerCase();
69
+ }
70
+ }
71
+ else {
72
+ result += transformed[i].toLowerCase();
73
+ }
53
74
  }
54
- return token.toLowerCase();
75
+ return result;
55
76
  }
56
77
  #sanitizeWord(word, rules) {
57
- if (!word.length || this.#isUncountable(word)) {
78
+ if (!(0, primitives_1.isNonEmptyString)(word))
79
+ return '';
80
+ if (this.#isUncountable(word)) {
58
81
  return word;
59
82
  }
60
83
  for (let i = rules.length - 1; i >= 0; i--) {
@@ -70,7 +93,7 @@ class Pluralizer {
70
93
  * Supports both string and RegExp entries.
71
94
  */
72
95
  #isUncountable(word) {
73
- const lower = word.toLowerCase();
96
+ const lower = word?.toLowerCase();
74
97
  for (const entry of this.#uncountables) {
75
98
  if (typeof entry === 'string') {
76
99
  if (entry === lower)
@@ -94,7 +117,7 @@ class Pluralizer {
94
117
  this.#pluralRules.push([rule, replacement]);
95
118
  }
96
119
  /**
97
- * Add a new singularization rule.
120
+ * * Add a new singularization rule.
98
121
  * @param rule Pattern to match plural words.
99
122
  * @param replacement Replacement pattern for singular form.
100
123
  * @example
@@ -104,23 +127,23 @@ class Pluralizer {
104
127
  this.#singularRules.push([rule, replacement]);
105
128
  }
106
129
  addUncountable(word) {
107
- this.#uncountables.add(typeof word === 'string' ? word.toLowerCase() : word);
130
+ this.#uncountables.add(typeof word === 'string' ? word?.toLowerCase() : word);
108
131
  }
109
132
  /**
110
- * Add a word or pattern that should never change between singular and plural.
133
+ * * Add a word or pattern that should never change between singular and plural.
111
134
  * @param word A word or regex pattern.
112
135
  * @example
113
136
  * pluralizer.addUncountable('fish');
114
137
  * pluralizer.addUncountable(/pok[eΓ©]mon$/i);
115
138
  */
116
139
  addIrregular(single, plural) {
117
- const singleLower = single.toLowerCase();
118
- const pluralLower = plural.toLowerCase();
140
+ const singleLower = single?.toLowerCase();
141
+ const pluralLower = plural?.toLowerCase();
119
142
  this.#irregularSingles[singleLower] = pluralLower;
120
143
  this.#irregularPlurals[pluralLower] = singleLower;
121
144
  }
122
145
  /**
123
- * Get the proper singular or plural form based on count.
146
+ * * Get the proper singular or plural form based on optional count.
124
147
  * @param word Target word to pluralize or singularize.
125
148
  * @param options Optional count and inclusive formatting.
126
149
  * @returns The transformed word.
@@ -137,14 +160,14 @@ class Pluralizer {
137
160
  return this.toPlural(word);
138
161
  }
139
162
  /**
140
- * Convert a word to its plural form.
163
+ * * Convert a word to its plural form.
141
164
  * @param word Singular form of the word.
142
165
  * @returns Plural form of the word.
143
166
  * @example
144
167
  * pluralizer.toPlural('analysis'); // "analyses"
145
168
  */
146
169
  toPlural(word) {
147
- if (!word)
170
+ if (!(0, primitives_1.isNonEmptyString)(word))
148
171
  return '';
149
172
  const lower = word.toLowerCase();
150
173
  if (this.#isUncountable(word))
@@ -155,14 +178,14 @@ class Pluralizer {
155
178
  return this.#restoreCase(word, this.#sanitizeWord(lower, this.#pluralRules));
156
179
  }
157
180
  /**
158
- * Convert a word to its singular form.
181
+ * * Convert a word to its singular form.
159
182
  * @param word Plural form of the word.
160
183
  * @returns Singular form of the word.
161
184
  * @example
162
185
  * pluralizer.toSingular('geese'); // "goose"
163
186
  */
164
187
  toSingular(word) {
165
- if (!word)
188
+ if (!(0, primitives_1.isNonEmptyString)(word))
166
189
  return '';
167
190
  const lower = word.toLowerCase();
168
191
  if (this.#isUncountable(word))
@@ -173,7 +196,7 @@ class Pluralizer {
173
196
  return this.#restoreCase(word, this.#sanitizeWord(lower, this.#singularRules));
174
197
  }
175
198
  /**
176
- * Check if a given word is plural.
199
+ * * Check if a given word is plural.
177
200
  * @param word Word to check.
178
201
  * @returns True if the word is plural, otherwise false.
179
202
  * @example
@@ -188,7 +211,7 @@ class Pluralizer {
188
211
  return this.toSingular(lower) !== lower;
189
212
  }
190
213
  /**
191
- * Check if a given word is singular.
214
+ * * Check if a given word is singular.
192
215
  * @param word Word to check.
193
216
  * @returns True if the word is singular, otherwise false.
194
217
  * @example
@@ -205,11 +228,13 @@ class Pluralizer {
205
228
  }
206
229
  exports.Pluralizer = Pluralizer;
207
230
  /**
208
- * Default shared instance of {@link Pluralizer}.
231
+ * Default shared instance of {@link https://nhb-toolbox.vercel.app/docs/classes/Pluralizer Pluralizer}.
209
232
  *
210
233
  * - _Use this when you don’t need multiple configurations._
211
234
  * - _It comes preloaded with standard pluralization rules, irregular forms, and uncountable nouns._
212
235
  *
236
+ * @remarks For simpler pluralization (plural with only 's'), please refer to {@link https://nhb-toolbox.vercel.app/docs/utilities/string/formatUnitWithPlural formatUnitWithPlural} instead.
237
+ *
213
238
  * * Handles English word pluralization and singularization with support for irregular forms and uncountable nouns.
214
239
  *
215
240
  * - Provides methods to convert words between singular and plural forms, check if a word is plural or singular, and manage custom pluralization rules.