@salespark/toolkit 2.1.1 → 2.1.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/README.md CHANGED
@@ -311,48 +311,72 @@ sanitize("<script>alert('hack')</script>Hello World!", 20);
311
311
 
312
312
  ### 🔢 Number Utilities
313
313
 
314
- **`clamp(n: number, min: number, max: number): number`** — Restricts a number within min and max bounds.
314
+ **`clamp(n: number, min: number, max: number): number`** — Restricts a number to be within the min and max bounds.
315
315
 
316
316
  ```javascript
317
- clamp(15, 0, 10);
318
- // Result: 10
317
+ clamp(10, 0, 5); // 5
318
+ clamp(-5, 0, 10); // 0
319
319
  ```
320
320
 
321
- **`round(n: number, decimals?: number): number`** — Rounds a number to fixed decimal places.
321
+ **`round(n: number, decimals?: number): number`** — Rounds a number to a fixed number of decimals without floating point surprises.
322
322
 
323
323
  ```javascript
324
- round(3.14159, 2);
325
- // Result: 3.14
324
+ round(1.2345, 2); // 1.23
325
+ round(1.235, 2); // 1.24
326
326
  ```
327
327
 
328
- **`toInteger(value: unknown, defaultValue?: number): number`** — Safely converts a value to an integer.
328
+ **`safeParseInt(value: unknown, defaultValue?: number): number`** — Safely converts a value to an integer with fallback.
329
329
 
330
330
  ```javascript
331
- toInteger("42.7");
332
- // Result: 42
331
+ safeParseInt("42"); // 42
332
+ safeParseInt("abc", 10); // 10
333
+ safeParseInt(3.9); // 3
333
334
  ```
334
335
 
335
- **`safeParseInt(value: unknown, defaultValue?: number): number`** — Alias for safe integer conversion.
336
+ **`safeParseFloat(value: unknown, decimals?: number): number`** — Safely parses a value into a number with decimal precision and comma/dot normalization.
336
337
 
337
338
  ```javascript
338
- safeParseInt("abc", 0);
339
- // Result: 0
339
+ safeParseFloat("123.45"); // 123.45
340
+ safeParseFloat("123,45"); // 123.45
341
+ safeParseFloat("1,234.56"); // 1234.56
342
+ safeParseFloat("abc"); // 0
340
343
  ```
341
344
 
342
- **`toNumber(value: unknown, decimals?: number): number`** — Safely parses a value into a number with optional decimal precision.
345
+ **`randomDigits(length?: number, options?: { charset?: string; noLeadingZero?: boolean }): string`** — Generates a random string of digits with secure randomness when available.
343
346
 
344
347
  ```javascript
345
- toNumber("123,45", 2);
346
- // Result: 123.45
348
+ randomDigits(6);
349
+ // Result: "482751" (random)
347
350
  ```
348
351
 
349
352
  **`randomDigits(length?: number, options?: { charset?: string; noLeadingZero?: boolean }): string`** — Generates a random string of digits with secure randomness when available.
350
353
 
351
354
  ```javascript
352
- randomDigits(6);
353
- // Result: "482751" (random)
355
+ randomDigits(6); // "847293"
356
+ randomDigits(4, { noLeadingZero: true }); // "3847" (no leading zero)
357
+ randomDigits(6, { charset: "ABCDEF0123456789" }); // "3F2A9D" (hex)
358
+ ```
359
+
360
+ **`formatDecimalNumber(value: number | string | null | undefined, decimals?: number): string`** — Formats a number with specified decimal places, intelligently handling European (`1.234,56`) and US (`1,234.56`) number formats.
361
+
362
+ **`formatDecimalNumber(value: number | string | null | undefined, decimals?: number): string`** — Formats a number with specified decimal places, intelligently handling European (`1.234,56`) and US (`1,234.56`) number formats.
363
+
364
+ ```javascript
365
+ formatDecimalNumber(1234.5678); // "1234.57"
366
+ formatDecimalNumber("1.234,56", 2); // "1234.56" (European format)
367
+ formatDecimalNumber("1,234.56", 2); // "1234.56" (US format)
368
+ formatDecimalNumber("1234,56", 3); // "1234.560"
369
+ formatDecimalNumber(null, 2); // "0.00"
370
+ formatDecimalNumber("invalid", 2); // "0.00"
354
371
  ```
355
372
 
373
+ #### 🗑️ Deprecated (Number Utilities)
374
+
375
+ - **`toInteger`** → Use `safeParseInt` instead
376
+ - **`toNumber`** → Use `safeParseFloat` instead
377
+ - **`parseToNumber`** → Use `safeParseFloat` instead
378
+ - **`otp`** → Use `randomDigits` instead
379
+
356
380
  ### ✅ Boolean Utilities
357
381
 
358
382
  **`toBool(value: unknown, def?: boolean): boolean`** — Converts a value to boolean, supporting common string/number representations.
@@ -425,14 +449,20 @@ isNilText("undefined");
425
449
  // Result: true
426
450
  ```
427
451
 
428
- **`isNilOrEmpty(value: unknown): boolean`** — Checks if value is null/undefined or an empty string.
452
+ **`isNilOrEmpty(value: unknown): boolean`** — Checks if value is null/undefined or an empty string (trimmed).
429
453
 
430
454
  ```javascript
431
455
  isNilOrEmpty("");
432
456
  // Result: true
433
457
 
458
+ isNilOrEmpty(" ");
459
+ // Result: true
460
+
434
461
  isNilOrEmpty(null);
435
462
  // Result: true
463
+
464
+ isNilOrEmpty(undefined);
465
+ // Result: true
436
466
  ```
437
467
 
438
468
  **`hasNilOrEmpty(array: unknown): boolean`** — Checks if any element in array is nil or empty.
@@ -596,15 +626,17 @@ checkMarkdownSecurity("# Hello World\n\nThis is **bold** text.");
596
626
 
597
627
  // Dangerous content with script
598
628
  checkMarkdownSecurity('<script>alert("xss")</script>');
599
- // Result: {
600
- // isValid: false,
601
- // text: "",
602
- // risks: [{ type: "scriptTags", severity: "critical", description: "..." }],
603
- // sanitized: true
629
+ // Result: {
630
+ // isValid: false,
631
+ // text: "",
632
+ // risks: [{ type: "scriptTags", severity: "critical", description: "..." }],
633
+ // sanitized: true
604
634
  // }
605
635
 
606
636
  // Content with multiple threats
607
- checkMarkdownSecurity('<iframe src="evil.com"></iframe><div onclick="bad()">test</div>');
637
+ checkMarkdownSecurity(
638
+ '<iframe src="evil.com"></iframe><div onclick="bad()">test</div>'
639
+ );
608
640
  // Result: Multiple risks detected, sorted by severity
609
641
  ```
610
642
 
@@ -613,13 +645,13 @@ checkMarkdownSecurity('<iframe src="evil.com"></iframe><div onclick="bad()">test
613
645
  ```typescript
614
646
  import { sanitizeMarkdown } from "@salespark/toolkit";
615
647
 
616
- sanitizeMarkdown('<p>Hello <strong>World</strong></p>');
648
+ sanitizeMarkdown("<p>Hello <strong>World</strong></p>");
617
649
  // Result: "Hello World"
618
650
 
619
651
  sanitizeMarkdown('javascript:alert("xss")');
620
652
  // Result: "alert(\"xss\")"
621
653
 
622
- sanitizeMarkdown('<script>alert(1)</script>Safe text');
654
+ sanitizeMarkdown("<script>alert(1)</script>Safe text");
623
655
  // Result: "Safe text"
624
656
  ```
625
657
 
@@ -629,7 +661,11 @@ sanitizeMarkdown('<script>alert(1)</script>Safe text');
629
661
  import { assessSecurityRisks } from "@salespark/toolkit";
630
662
 
631
663
  const risks = [
632
- { type: "scriptTags", severity: "critical", description: "Script injection detected" }
664
+ {
665
+ type: "scriptTags",
666
+ severity: "critical",
667
+ description: "Script injection detected",
668
+ },
633
669
  ];
634
670
 
635
671
  assessSecurityRisks(risks);
@@ -655,10 +691,10 @@ assessSecurityRisks([]);
655
691
  ```typescript
656
692
  import { isPTTaxId } from "@salespark/toolkit";
657
693
 
658
- isPTTaxId("123456789"); // false (invalid check digit)
659
- isPTTaxId("123 456 789"); // false (spaces stripped automatically)
660
- isPTTaxId("513183504"); // true (valid NIF)
661
- isPTTaxId("423456789"); // false (invalid prefix - 4 not allowed)
694
+ isPTTaxId("123456789"); // false (invalid check digit)
695
+ isPTTaxId("123 456 789"); // false (spaces stripped automatically)
696
+ isPTTaxId("513183504"); // true (valid NIF)
697
+ isPTTaxId("423456789"); // false (invalid prefix - 4 not allowed)
662
698
 
663
699
  // Deprecated alias (use isPTTaxId instead)
664
700
  // isValidPTTaxId("513183504"); // true
@@ -669,12 +705,12 @@ isPTTaxId("423456789"); // false (invalid prefix - 4 not allowed)
669
705
  ```typescript
670
706
  import { isValidIBAN } from "@salespark/toolkit";
671
707
 
672
- isValidIBAN("NL91ABNA0417164300"); // true (valid Dutch IBAN)
708
+ isValidIBAN("NL91ABNA0417164300"); // true (valid Dutch IBAN)
673
709
  isValidIBAN("NL91 ABNA 0417 1643 00"); // true (spaces stripped automatically)
674
710
  isValidIBAN("GB29NWBK60161331926819"); // true (valid UK IBAN)
675
- isValidIBAN("DE89370400440532013000"); // true (valid German IBAN)
676
- isValidIBAN("NL91ABNA0417164301"); // false (invalid checksum)
677
- isValidIBAN("XX1234567890"); // false (invalid country code)
711
+ isValidIBAN("DE89370400440532013000"); // true (valid German IBAN)
712
+ isValidIBAN("NL91ABNA0417164301"); // false (invalid checksum)
713
+ isValidIBAN("XX1234567890"); // false (invalid country code)
678
714
  ```
679
715
 
680
716
  ### 🌐 Environment Detection
@@ -710,7 +746,7 @@ The following functions are deprecated but maintained for backward compatibility
710
746
  ### ⚡ Function Utilities (Deprecated)
711
747
 
712
748
  - `isNullOrUndefined` — Use `isNil` instead.
713
- - `isNullOrUndefinedTextInc` — Use `isNilText` instead.
749
+ - `isNullOrUndefinedTextInc` — Use `isNilText` instead.
714
750
  - `isNullUndefinedOrEmpty` — Use `isNilOrEmpty` instead.
715
751
  - `isNullOrUndefinedInArray` — Use `hasNilOrEmpty` instead.
716
752
  - `isNullOrUndefinedEmptyOrZero` — Use `isNilEmptyOrZeroLen` instead.
@@ -779,5 +815,5 @@ MIT © [SalesPark](https://salespark.io)
779
815
 
780
816
  ---
781
817
 
782
- _Document version: 5_
783
- _Last update: 25-09-2025_
818
+ _Document version: 6_
819
+ _Last update: 29-10-2025_
package/dist/index.cjs CHANGED
@@ -253,7 +253,7 @@ function round(n, decimals = 0) {
253
253
  const f = Math.pow(10, decimals);
254
254
  return Math.round((n + Number.EPSILON) * f) / f;
255
255
  }
256
- function toInteger(value, defaultValue = 0) {
256
+ function safeParseInt(value, defaultValue = 0) {
257
257
  try {
258
258
  const safeValue = parseInt(String(value), 10);
259
259
  return isNaN(safeValue) ? defaultValue : safeValue;
@@ -261,8 +261,8 @@ function toInteger(value, defaultValue = 0) {
261
261
  return defaultValue;
262
262
  }
263
263
  }
264
- var safeParseInt = toInteger;
265
- function toNumber(value, decimals = 6) {
264
+ var toInteger = safeParseInt;
265
+ function safeParseFloat(value, decimals = 6) {
266
266
  try {
267
267
  if (value === void 0 || value === null || value === "") return 0;
268
268
  let str = String(value);
@@ -278,7 +278,8 @@ function toNumber(value, decimals = 6) {
278
278
  return 0;
279
279
  }
280
280
  }
281
- var parseToNumber = toNumber;
281
+ var toNumber = safeParseFloat;
282
+ var parseToNumber = safeParseFloat;
282
283
  function secureRandomIndex(max) {
283
284
  if (max <= 0) return 0;
284
285
  const g = globalThis;
@@ -310,6 +311,30 @@ function randomDigits(length = 6, options) {
310
311
  return out;
311
312
  }
312
313
  var otp = randomDigits;
314
+ var formatDecimalNumber = (value, decimals = 2) => {
315
+ try {
316
+ let processedValue = value ?? 0;
317
+ if (typeof processedValue === "string") {
318
+ const trimmed = processedValue.trim();
319
+ if (trimmed.includes(",") && trimmed.includes(".")) {
320
+ const lastComma = trimmed.lastIndexOf(",");
321
+ const lastDot = trimmed.lastIndexOf(".");
322
+ processedValue = lastComma > lastDot ? trimmed.replace(/\./g, "").replace(",", ".") : trimmed.replace(/,/g, "");
323
+ } else if (trimmed.includes(",")) {
324
+ processedValue = trimmed.replace(/,/g, ".");
325
+ } else {
326
+ processedValue = trimmed;
327
+ }
328
+ }
329
+ const numValue = parseFloat(String(processedValue));
330
+ if (isNaN(numValue)) {
331
+ return 0 .toFixed(Math.max(0, Math.floor(decimals)));
332
+ }
333
+ return numValue.toFixed(Math.max(0, Math.floor(decimals)));
334
+ } catch (error) {
335
+ return 0 .toFixed(Math.max(0, Math.floor(decimals)));
336
+ }
337
+ };
313
338
 
314
339
  // src/utils/func.ts
315
340
  function debounce(fn, wait = 250) {
@@ -348,7 +373,7 @@ var isNilText = (value) => {
348
373
  };
349
374
  var isNilOrEmpty = (value) => {
350
375
  try {
351
- return isNil(value) || value === "";
376
+ return isNil(value) || typeof value === "string" && value?.trim() === "";
352
377
  } catch {
353
378
  return true;
354
379
  }
@@ -1615,6 +1640,7 @@ exports.flattenDepthBase = flattenDepthBase;
1615
1640
  exports.flattenOnce = flattenOnce;
1616
1641
  exports.formatBytes = formatBytes;
1617
1642
  exports.formatCurrency = formatCurrency;
1643
+ exports.formatDecimalNumber = formatDecimalNumber;
1618
1644
  exports.getStringSimilarity = getStringSimilarity;
1619
1645
  exports.groupBy = groupBy;
1620
1646
  exports.hasNilOrEmpty = hasNilOrEmpty;
@@ -1653,6 +1679,7 @@ exports.pushAll = pushAll;
1653
1679
  exports.randomDigits = randomDigits;
1654
1680
  exports.removeDiacritics = removeDiacritics;
1655
1681
  exports.round = round;
1682
+ exports.safeParseFloat = safeParseFloat;
1656
1683
  exports.safeParseInt = safeParseInt;
1657
1684
  exports.sanitize = sanitize;
1658
1685
  exports.sanitizeMarkdown = sanitizeMarkdown;