@ezez/utils 1.0.0 → 1.1.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +15 -8
  2. package/README.md +2 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/isEmpty.js +1 -1
  8. package/dist/isEmpty.js.map +1 -1
  9. package/dist/isNumericString.d.ts +10 -0
  10. package/dist/isNumericString.d.ts.map +1 -0
  11. package/dist/isNumericString.js +61 -0
  12. package/dist/isNumericString.js.map +1 -0
  13. package/dist/occurrences.d.ts +7 -0
  14. package/dist/occurrences.d.ts.map +1 -0
  15. package/dist/occurrences.js +27 -0
  16. package/dist/occurrences.js.map +1 -0
  17. package/docs/assets/search.js +1 -1
  18. package/docs/functions/cap.html +9 -5
  19. package/docs/functions/capitalize.html +9 -5
  20. package/docs/functions/coalesce.html +9 -5
  21. package/docs/functions/ensureArray.html +9 -5
  22. package/docs/functions/ensureError.html +9 -5
  23. package/docs/functions/get.html +9 -5
  24. package/docs/functions/getMultiple.html +9 -5
  25. package/docs/functions/insertSeparator.html +9 -5
  26. package/docs/functions/isEmpty.html +9 -5
  27. package/docs/functions/isNumericString.html +117 -0
  28. package/docs/functions/isPlainObject.html +9 -5
  29. package/docs/functions/last.html +9 -5
  30. package/docs/functions/mapAsync.html +9 -5
  31. package/docs/functions/mapValues.html +9 -5
  32. package/docs/functions/match.html +9 -5
  33. package/docs/functions/merge.html +17 -13
  34. package/docs/functions/mostFrequent.html +9 -5
  35. package/docs/functions/noop.html +9 -5
  36. package/docs/functions/occurrences.html +129 -0
  37. package/docs/functions/omit.html +9 -5
  38. package/docs/functions/pick.html +9 -5
  39. package/docs/functions/pull.html +9 -5
  40. package/docs/functions/remove.html +9 -5
  41. package/docs/functions/rethrow.html +9 -5
  42. package/docs/functions/scale.html +9 -5
  43. package/docs/functions/seq.html +9 -5
  44. package/docs/functions/seqEarlyBreak.html +9 -5
  45. package/docs/functions/set.html +9 -5
  46. package/docs/functions/setImmutable.html +9 -5
  47. package/docs/functions/sortBy.html +9 -5
  48. package/docs/functions/throttle.html +9 -5
  49. package/docs/functions/truthy.html +9 -5
  50. package/docs/functions/wait.html +9 -5
  51. package/docs/functions/waitFor.html +9 -5
  52. package/docs/functions/waitSync.html +9 -5
  53. package/docs/index.html +10 -4
  54. package/docs/interfaces/GetMultipleSource.html +9 -5
  55. package/docs/interfaces/GetSource.html +9 -5
  56. package/docs/interfaces/IsNumericStringOptions.html +90 -0
  57. package/docs/interfaces/OccurencesOptions.html +71 -0
  58. package/docs/interfaces/SetImmutableSource.html +9 -5
  59. package/docs/interfaces/SetSource.html +9 -5
  60. package/docs/interfaces/ThrottleOptions.html +7 -7
  61. package/docs/interfaces/ThrottledFunctionExtras.html +7 -7
  62. package/docs/modules.html +12 -4
  63. package/docs/pages/Introduction.html +8 -4
  64. package/docs/types/MapValuesFn.html +9 -5
  65. package/docs/types/MatchCallback.html +9 -5
  66. package/docs/types/SeqEarlyBreaker.html +9 -5
  67. package/docs/types/SeqFn.html +9 -5
  68. package/docs/types/SeqFunctions.html +9 -5
  69. package/docs/types/SetImmutablePath.html +9 -5
  70. package/docs/types/ThrottledFunction.html +9 -5
  71. package/docs/variables/mapValuesUNSET.html +9 -5
  72. package/docs/variables/mergeUNSET.html +9 -5
  73. package/esm/index.d.ts +2 -0
  74. package/esm/index.d.ts.map +1 -1
  75. package/esm/index.js +2 -0
  76. package/esm/index.js.map +1 -1
  77. package/esm/isEmpty.js +1 -1
  78. package/esm/isEmpty.js.map +1 -1
  79. package/esm/isNumericString.d.ts +10 -0
  80. package/esm/isNumericString.d.ts.map +1 -0
  81. package/esm/isNumericString.js +58 -0
  82. package/esm/isNumericString.js.map +1 -0
  83. package/esm/occurrences.d.ts +7 -0
  84. package/esm/occurrences.d.ts.map +1 -0
  85. package/esm/occurrences.js +24 -0
  86. package/esm/occurrences.js.map +1 -0
  87. package/package.json +1 -1
  88. package/src/index.ts +2 -0
  89. package/src/isEmpty.ts +1 -1
  90. package/src/isNumericString.spec.ts +100 -0
  91. package/src/isNumericString.ts +94 -0
  92. package/src/occurrences.spec.ts +20 -0
  93. package/src/occurrences.ts +53 -0
@@ -0,0 +1,94 @@
1
+ interface Options {
2
+ allowFloats?: boolean;
3
+ allowExponents?: boolean;
4
+ allowInfinity?: boolean;
5
+ allowNaN?: boolean;
6
+ }
7
+
8
+ const NOT_FOUND = -1;
9
+
10
+ /**
11
+ * Checks if a string is a numeric string. By default, it allows only integers. Floats and exponents can be enabled with
12
+ * options. Optionally allow NaN and Infinity.
13
+ * @param {string} string - String to check
14
+ * @param {object} [options] - Options object
15
+ * @param {boolean} [options.allowFloats=false] - Allow floats
16
+ * @param {boolean} [options.allowExponents=false] - Allow exponents
17
+ * @param {boolean} [options.allowInfinity=false] - Allow Initity and -Infinity (casing matters)
18
+ * @param {boolean} [options.allowNaN=false] - Allow NaN (casing matters)
19
+ */
20
+ const isNumericString = (string: string, options: Options = {}) => { // eslint-disable-line max-statements, max-lines-per-function, max-len
21
+ if (typeof string !== "string") {
22
+ throw new TypeError("Expected a string");
23
+ }
24
+
25
+ if (options.allowNaN && string === "NaN") {
26
+ return true;
27
+ }
28
+
29
+ if (options.allowInfinity && (string === "Infinity" || string === "-Infinity")) {
30
+ return true;
31
+ }
32
+
33
+ let normalized = string.toLowerCase();
34
+ if (normalized.startsWith("-")) {
35
+ normalized = normalized.slice(1);
36
+ }
37
+
38
+ const parts = normalized.split(".");
39
+
40
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
41
+ if (parts.length > (options.allowFloats ? 2 : 1)) {
42
+ return false;
43
+ }
44
+
45
+ const expParts = parts[parts.length - 1].split("e");
46
+
47
+ if (!options.allowExponents) {
48
+ if (expParts.length > 1) {
49
+ return false;
50
+ }
51
+ }
52
+ else {
53
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
54
+ if (expParts.length > 2) {
55
+ return false;
56
+ }
57
+ }
58
+
59
+ const hasPlusAt = normalized.indexOf("+");
60
+ if (hasPlusAt > NOT_FOUND) {
61
+ if (!options.allowExponents) {
62
+ return false;
63
+ }
64
+ if (hasPlusAt !== normalized.lastIndexOf("+")) {
65
+ return false;
66
+ }
67
+ if (hasPlusAt !== normalized.indexOf("e") + 1) {
68
+ return false;
69
+ }
70
+ }
71
+
72
+ const hasMinusAt = normalized.indexOf("-");
73
+ if (hasMinusAt > NOT_FOUND) {
74
+ if (!options.allowExponents) {
75
+ return false;
76
+ }
77
+ if (hasMinusAt !== normalized.lastIndexOf("-")) {
78
+ return false;
79
+ }
80
+ if (hasMinusAt !== normalized.indexOf("e") + 1) {
81
+ return false;
82
+ }
83
+ }
84
+
85
+ return Boolean(/^[\de.+-]+$/.exec(normalized));
86
+ };
87
+
88
+ export {
89
+ isNumericString,
90
+ };
91
+
92
+ export type {
93
+ Options as IsNumericStringOptions,
94
+ };
@@ -0,0 +1,20 @@
1
+ import { occurrences } from "./occurrences.js";
2
+
3
+ describe("occurrences", function() {
4
+ it("returns zero for empty search string", function() {
5
+ occurrences("test string", "").must.equal(0);
6
+ });
7
+
8
+ it("returns count of occurences for typical use cases", function() {
9
+ occurrences("hello beautiful world, hello bees and hello sun", "hello").must.equal(3);
10
+ occurrences("hello beautiful world, hello bees and hello sun", "o").must.equal(4);
11
+ });
12
+
13
+ it("allows counting overlaps too", function() {
14
+ occurrences("aaaa", "aa", { overlap: true }).must.equal(3);
15
+ occurrences("aaaa", "aa", { overlap: false }).must.equal(2);
16
+
17
+ occurrences("aaaaaa", "aa", { overlap: true }).must.equal(5);
18
+ occurrences("aaaaaa", "aa", { overlap: false }).must.equal(3);
19
+ });
20
+ });
@@ -0,0 +1,53 @@
1
+ interface Options {
2
+ /**
3
+ * Allow overlapping matches, ie. "aa" in "aaa" will return 2 instead of 1
4
+ */
5
+ overlap?: boolean;
6
+ }
7
+
8
+ const NOT_FOUND = -1;
9
+
10
+ /**
11
+ * Count the number of occurrences of a substring in a string
12
+ *
13
+ * @example occurrences("aaa", "a"); // 3
14
+ * @example occurrences("aaaa", "aa", { overlap: false }); // 2
15
+ * @example occurrences("aaaa", "aa", { overlap: true }); // 3
16
+ * @param {string} string - string to search in
17
+ * @param {string} search - string to search for
18
+ * @param {object} [options] - options
19
+ * @param {boolean} [options.overlap=false] - allow overlapping matches, ie "aa" in "aaa" will return 2 instead of 1
20
+ */
21
+ const occurrences = (string: string, search: string, { overlap }: Options = {}) => {
22
+ if (typeof string !== "string") {
23
+ throw new TypeError("Expected a string");
24
+ }
25
+ if (typeof search !== "string") {
26
+ throw new TypeError("Expected a string");
27
+ }
28
+ if (search.length === 0) {
29
+ return 0;
30
+ }
31
+ let n = 0,
32
+ i = 0;
33
+
34
+ // eslint-disable-next-line no-constant-condition,@typescript-eslint/no-unnecessary-condition
35
+ while (true) {
36
+ i = string.indexOf(search, i);
37
+
38
+ if (i === NOT_FOUND) {
39
+ break;
40
+ }
41
+ n++;
42
+ i += overlap ? 1 : search.length;
43
+ }
44
+ return n;
45
+ };
46
+
47
+ export {
48
+ occurrences,
49
+ };
50
+
51
+ export type {
52
+ Options as OccurencesOptions,
53
+ };