@salespark/toolkit 2.1.6 → 2.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,7 +27,7 @@ npm i @salespark/toolkit
27
27
  - **Array utilities**: chunk, uniqBy, deep equality, flatten, groupBy, etc.
28
28
  - **Object utilities**: pick, omit, clean objects, deep merge, etc.
29
29
  - **String utilities**: slugify, template fill, deburr, sanitize, etc.
30
- - **Number utilities**: clamp, round, safe parse (locale-aware), random digits, etc.
30
+ - **Number utilities**: clamp, round, safe arithmetic/comparisons, safe parse (locale-aware), random digits, etc.
31
31
  - **Function utilities**: debounce, throttle, formatCurrency, parseName, currency conversions, etc.
32
32
  - **Boolean utilities**: safe boolean conversion with common representations
33
33
  - **Validation utilities**: IBAN validator (ISO 13616), Portuguese tax ID validator
@@ -325,6 +325,42 @@ round(1.2345, 2); // 1.23
325
325
  round(1.235, 2); // 1.24
326
326
  ```
327
327
 
328
+ **`safeAdd(a: number, b: number, decimals?: number): number`** — Adds two numbers with rounding and guards against invalid operands and precision errors.
329
+
330
+ ```javascript
331
+ safeAdd(0.1, 0.2, 2); // 0.3
332
+ safeAdd(Number.NaN, 5); // 0 (invalid operand)
333
+ ```
334
+
335
+ **`safeMultiply(a: number, b: number, decimals?: number): number`** — Multiplies two numbers safely with rounding and operand validation.
336
+
337
+ ```javascript
338
+ safeMultiply(0.1, 0.2, 4); // 0.02
339
+ safeMultiply(Infinity, 2); // 0 (invalid operand)
340
+ ```
341
+
342
+ **`safeSubtract(a: number, b: number, decimals?: number): number`** — Subtracts numbers safely, clamping decimal precision when needed.
343
+
344
+ ```javascript
345
+ safeSubtract(10, 3.3333, 2); // 6.67
346
+ safeSubtract(5, Number.NaN); // 0 (invalid operand)
347
+ ```
348
+
349
+ **`safeDivide(a: number, b: number, decimals?: number): number`** — Divides numbers with division-by-zero protection and precision normalization.
350
+
351
+ ```javascript
352
+ safeDivide(1, 3, 3); // 0.333
353
+ safeDivide(10, 0); // 0 (division by zero)
354
+ ```
355
+
356
+ **`numbersEqual(a: number, b: number, decimals?: number): boolean`** — Safely compares two numbers using fixed decimal precision and invalid operand guards.
357
+
358
+ ```javascript
359
+ numbersEqual(0.1 + 0.2, 0.3); // true
360
+ numbersEqual(1.2345, 1.2344, 4); // false
361
+ numbersEqual(NaN, 1); // false
362
+ ```
363
+
328
364
  **`safeParseInt(value: unknown, defaultValue?: number): number`** — Safely converts a value to an integer with fallback.
329
365
 
330
366
  ```javascript
@@ -820,5 +856,5 @@ MIT © [SalesPark](https://salespark.io)
820
856
 
821
857
  ---
822
858
 
823
- _Document version: 8_
824
- _Last update: 10-12-2025_
859
+ _Document version: 9_
860
+ _Last update: 01-12-2025_
package/dist/index.cjs CHANGED
@@ -261,6 +261,61 @@ function safeParseInt(value, defaultValue = 0) {
261
261
  return defaultValue;
262
262
  }
263
263
  }
264
+ function normalizeDecimals(decimals) {
265
+ if (!Number.isFinite(decimals)) return 0;
266
+ const int = Math.floor(decimals);
267
+ if (int < 0) return 0;
268
+ if (int > 100) return 100;
269
+ return int;
270
+ }
271
+ function sanitizeOperands(...values) {
272
+ return values.every((value) => Number.isFinite(value));
273
+ }
274
+ function safeAdd(a, b, decimals = 2) {
275
+ try {
276
+ if (!sanitizeOperands(a, b)) return 0;
277
+ const precision = normalizeDecimals(decimals);
278
+ return Number((a + b).toFixed(precision));
279
+ } catch {
280
+ return 0;
281
+ }
282
+ }
283
+ function safeMultiply(a, b, decimals = 2) {
284
+ try {
285
+ if (!sanitizeOperands(a, b)) return 0;
286
+ const precision = normalizeDecimals(decimals);
287
+ return Number((a * b).toFixed(precision));
288
+ } catch {
289
+ return 0;
290
+ }
291
+ }
292
+ function safeSubtract(a, b, decimals = 2) {
293
+ try {
294
+ if (!sanitizeOperands(a, b)) return 0;
295
+ const precision = normalizeDecimals(decimals);
296
+ return Number((a - b).toFixed(precision));
297
+ } catch {
298
+ return 0;
299
+ }
300
+ }
301
+ function safeDivide(a, b, decimals = 2) {
302
+ try {
303
+ if (!sanitizeOperands(a, b) || b === 0) return 0;
304
+ const precision = normalizeDecimals(decimals);
305
+ return Number((a / b).toFixed(precision));
306
+ } catch {
307
+ return 0;
308
+ }
309
+ }
310
+ function numbersEqual(a, b, decimals = 2) {
311
+ try {
312
+ if (!sanitizeOperands(a, b)) return false;
313
+ const precision = normalizeDecimals(decimals);
314
+ return a.toFixed(precision) === b.toFixed(precision);
315
+ } catch {
316
+ return false;
317
+ }
318
+ }
264
319
  var toInteger = safeParseInt;
265
320
  function safeParseFloat(value, decimals = 6) {
266
321
  try {
@@ -292,7 +347,8 @@ function safeParseFloat(value, decimals = 6) {
292
347
  }
293
348
  const num = parseFloat(normalized);
294
349
  if (!isFinite(num)) return 0;
295
- return Number(num.toFixed(decimals));
350
+ const precision = normalizeDecimals(decimals);
351
+ return Number(num.toFixed(precision));
296
352
  } catch {
297
353
  return 0;
298
354
  }
@@ -1692,6 +1748,7 @@ exports.isNullUndefinedOrZero = isNullUndefinedOrZero;
1692
1748
  exports.isPTTaxId = isPTTaxId;
1693
1749
  exports.isValidIBAN = isValidIBAN;
1694
1750
  exports.isValidPTTaxId = isValidPTTaxId;
1751
+ exports.numbersEqual = numbersEqual;
1695
1752
  exports.objectToString = objectToString;
1696
1753
  exports.omit = omit;
1697
1754
  exports.otp = otp;
@@ -1704,8 +1761,12 @@ exports.pushAll = pushAll;
1704
1761
  exports.randomDigits = randomDigits;
1705
1762
  exports.removeDiacritics = removeDiacritics;
1706
1763
  exports.round = round;
1764
+ exports.safeAdd = safeAdd;
1765
+ exports.safeDivide = safeDivide;
1766
+ exports.safeMultiply = safeMultiply;
1707
1767
  exports.safeParseFloat = safeParseFloat;
1708
1768
  exports.safeParseInt = safeParseInt;
1769
+ exports.safeSubtract = safeSubtract;
1709
1770
  exports.sanitize = sanitize;
1710
1771
  exports.sanitizeMarkdown = sanitizeMarkdown;
1711
1772
  exports.shuffle = shuffle;