@ezez/utils 4.2.0 → 4.4.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 (134) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/race.d.ts +3 -0
  7. package/dist/race.d.ts.map +1 -0
  8. package/dist/race.js +14 -0
  9. package/dist/race.js.map +1 -0
  10. package/dist/sortBy.d.ts +1 -1
  11. package/dist/sortBy.d.ts.map +1 -1
  12. package/dist/sortBy.js +2 -7
  13. package/dist/sortBy.js.map +1 -1
  14. package/dist/sortByMultiple.d.ts +3 -0
  15. package/dist/sortByMultiple.d.ts.map +1 -0
  16. package/dist/sortByMultiple.js +18 -0
  17. package/dist/sortByMultiple.js.map +1 -0
  18. package/docs/assets/navigation.js +1 -1
  19. package/docs/assets/search.js +1 -1
  20. package/docs/documents/CHANGELOG.html +57 -48
  21. package/docs/functions/index.cap.html +2 -2
  22. package/docs/functions/index.capitalize.html +2 -2
  23. package/docs/functions/index.coalesce.html +2 -2
  24. package/docs/functions/index.compareArrays.html +2 -2
  25. package/docs/functions/index.compareProps.html +2 -2
  26. package/docs/functions/index.deserialize.html +2 -2
  27. package/docs/functions/index.ensureArray.html +2 -2
  28. package/docs/functions/index.ensureDate.html +2 -2
  29. package/docs/functions/index.ensureError.html +2 -2
  30. package/docs/functions/index.ensurePrefix.html +2 -2
  31. package/docs/functions/index.ensureSuffix.html +2 -2
  32. package/docs/functions/index.ensureTimestamp.html +2 -2
  33. package/docs/functions/index.escapeRegExp.html +2 -2
  34. package/docs/functions/index.formatDate.html +2 -2
  35. package/docs/functions/index.get.html +2 -2
  36. package/docs/functions/index.getMultiple.html +2 -2
  37. package/docs/functions/index.insertSeparator.html +2 -2
  38. package/docs/functions/index.isEmpty.html +2 -2
  39. package/docs/functions/index.isNumericString.html +2 -2
  40. package/docs/functions/index.isPlainObject.html +2 -2
  41. package/docs/functions/index.last.html +2 -2
  42. package/docs/functions/index.later-1.html +2 -2
  43. package/docs/functions/index.mapAsync.html +2 -2
  44. package/docs/functions/index.mapValues.html +2 -2
  45. package/docs/functions/index.match.html +2 -2
  46. package/docs/functions/index.memoize.html +2 -2
  47. package/docs/functions/index.merge.html +2 -2
  48. package/docs/functions/index.mostFrequent.html +2 -2
  49. package/docs/functions/index.noop.html +2 -2
  50. package/docs/functions/index.occurrences.html +2 -2
  51. package/docs/functions/index.omit.html +2 -2
  52. package/docs/functions/index.pick.html +2 -2
  53. package/docs/functions/index.pull.html +2 -2
  54. package/docs/functions/index.race.html +11 -0
  55. package/docs/functions/index.remove.html +2 -2
  56. package/docs/functions/index.removeCommonProperties.html +2 -2
  57. package/docs/functions/index.replace.html +2 -2
  58. package/docs/functions/index.replaceDeep.html +2 -2
  59. package/docs/functions/index.rethrow.html +2 -2
  60. package/docs/functions/index.retry.html +2 -2
  61. package/docs/functions/index.round.html +2 -2
  62. package/docs/functions/index.safe.html +2 -2
  63. package/docs/functions/index.sample.html +2 -2
  64. package/docs/functions/index.samples.html +2 -2
  65. package/docs/functions/index.scale.html +2 -2
  66. package/docs/functions/index.seq.html +2 -2
  67. package/docs/functions/index.seqEarlyBreak.html +2 -2
  68. package/docs/functions/index.serialize.html +2 -2
  69. package/docs/functions/index.set.html +2 -2
  70. package/docs/functions/index.setImmutable.html +2 -2
  71. package/docs/functions/index.shuffle.html +2 -2
  72. package/docs/functions/index.sortBy.html +4 -4
  73. package/docs/functions/index.sortByMultiple.html +10 -0
  74. package/docs/functions/index.sortProps.html +2 -2
  75. package/docs/functions/index.stripPrefix.html +2 -2
  76. package/docs/functions/index.stripSuffix.html +2 -2
  77. package/docs/functions/index.throttle.html +2 -2
  78. package/docs/functions/index.toggle.html +2 -2
  79. package/docs/functions/index.trim.html +2 -2
  80. package/docs/functions/index.trimEnd.html +2 -2
  81. package/docs/functions/index.trimStart.html +2 -2
  82. package/docs/functions/index.truthy.html +2 -2
  83. package/docs/functions/index.unique.html +2 -2
  84. package/docs/functions/index.wait.html +2 -2
  85. package/docs/functions/index.waitFor.html +2 -2
  86. package/docs/functions/index.waitSync.html +2 -2
  87. package/docs/index.html +2 -2
  88. package/docs/interfaces/index.ComparePropsOptions.html +3 -3
  89. package/docs/interfaces/index.GetMultipleSource.html +2 -2
  90. package/docs/interfaces/index.GetSource.html +2 -2
  91. package/docs/interfaces/index.IsNumericStringOptions.html +2 -2
  92. package/docs/interfaces/index.OccurencesOptions.html +2 -2
  93. package/docs/interfaces/index.SetImmutableSource.html +2 -2
  94. package/docs/interfaces/index.SetSource.html +2 -2
  95. package/docs/interfaces/index.ThrottleOptions.html +3 -3
  96. package/docs/interfaces/index.ThrottledFunctionExtras.html +3 -3
  97. package/docs/modules/index.html +4 -2
  98. package/docs/modules.html +2 -2
  99. package/docs/types/index.CustomDeserializers.html +1 -1
  100. package/docs/types/index.CustomSerializers.html +1 -1
  101. package/docs/types/index.Later.html +2 -2
  102. package/docs/types/index.MapValuesFn.html +2 -2
  103. package/docs/types/index.MatchCallback.html +1 -1
  104. package/docs/types/index.MergeTwo.html +2 -2
  105. package/docs/types/index.SeqEarlyBreaker.html +2 -2
  106. package/docs/types/index.SeqFn.html +2 -2
  107. package/docs/types/index.SeqFunctions.html +2 -2
  108. package/docs/types/index.SetImmutablePath.html +2 -2
  109. package/docs/types/index.ThrottledFunction.html +1 -1
  110. package/docs/variables/index.mapValuesUNSET.html +2 -2
  111. package/docs/variables/index.mergeUNSET.html +2 -2
  112. package/esm/index.d.ts +2 -0
  113. package/esm/index.d.ts.map +1 -1
  114. package/esm/index.js +2 -0
  115. package/esm/index.js.map +1 -1
  116. package/esm/race.d.ts +3 -0
  117. package/esm/race.d.ts.map +1 -0
  118. package/esm/race.js +11 -0
  119. package/esm/race.js.map +1 -0
  120. package/esm/sortBy.d.ts +1 -1
  121. package/esm/sortBy.d.ts.map +1 -1
  122. package/esm/sortBy.js +2 -7
  123. package/esm/sortBy.js.map +1 -1
  124. package/esm/sortByMultiple.d.ts +3 -0
  125. package/esm/sortByMultiple.d.ts.map +1 -0
  126. package/esm/sortByMultiple.js +15 -0
  127. package/esm/sortByMultiple.js.map +1 -0
  128. package/package.json +1 -1
  129. package/src/index.ts +2 -0
  130. package/src/race.ts +30 -0
  131. package/src/sortBy.spec.ts +13 -0
  132. package/src/sortBy.ts +11 -15
  133. package/src/sortByMultiple.spec.ts +87 -0
  134. package/src/sortByMultiple.ts +57 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ezez/utils",
3
- "version": "4.2.0",
3
+ "version": "4.4.0",
4
4
  "repository": "https://github.com/dzek69/bottom-line.git",
5
5
  "author": "Jacek Nowacki @dzek69 <git-public@dzek.eu>",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -32,6 +32,7 @@ export * from "./occurrences.js";
32
32
  export * from "./omit.js";
33
33
  export * from "./pick.js";
34
34
  export * from "./pull.js";
35
+ export * from "./race.js";
35
36
  export * from "./remove.js";
36
37
  export * from "./removeCommonProperties.js";
37
38
  export * from "./replace.js";
@@ -49,6 +50,7 @@ export * from "./set.js";
49
50
  export * from "./setImmutable.js";
50
51
  export * from "./shuffle.js";
51
52
  export * from "./sortBy.js";
53
+ export * from "./sortByMultiple.js";
52
54
  export * from "./sortProps.js";
53
55
  export * from "./stripPrefix.js";
54
56
  export * from "./stripSuffix.js";
package/src/race.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * This function helps you timeout your promises while keeping the TS types right.
3
+ *
4
+ * @example await race(yourPromise, 1000); // resolves (or rejects) with the value of yourPromise or rejects with "Race: Timeout" message in a second
5
+ * @example
6
+ * ```
7
+ * type Data = { a: number };
8
+ * const myPromise = new Promise<Data>((resolve) => setTimeout(() => resolve({ a: 1 }), 2000));
9
+ * const { a } = await race(myPromise, 1000); // You're allowed to destructure the result with TS
10
+ * ```
11
+ *
12
+ * @param promise - Your promise
13
+ * @param timeout - Time in milliseconds to wait for the promise to resolve
14
+ * @param message - Error message to use when the timeout is reached
15
+ */
16
+ const race = <T>(promise: Promise<T>, timeout: number, message = "Race: Timeout"): Promise<T> => {
17
+ return Promise.race([
18
+ promise, new Promise<T>((_, reject) => {
19
+ setTimeout(() => {
20
+ reject(new Error(message));
21
+ }, timeout);
22
+ }),
23
+ ]);
24
+ };
25
+
26
+ export {
27
+ race,
28
+ };
29
+
30
+ // TODO unit tests
@@ -53,4 +53,17 @@ describe("sortBy", () => {
53
53
  { size: 90 },
54
54
  ]);
55
55
  });
56
+
57
+ it("supports using default value", () => {
58
+ const sizes = [
59
+ { size: 30 },
60
+ { size: 90 },
61
+ {},
62
+ ];
63
+ sizes.sort(sortBy("size", true, 55)).must.eql([
64
+ { size: 30 },
65
+ {}, // size assumed to be 55
66
+ { size: 90 },
67
+ ]);
68
+ });
56
69
  });
package/src/sortBy.ts CHANGED
@@ -1,22 +1,18 @@
1
+ import { sortByMultiple } from "./sortByMultiple.js";
2
+
1
3
  /**
2
4
  * Returns a function that can be used as a callback to `.sort()` method. Returned function will sort array by given
3
5
  * property.
4
- * @param {string} propertyName - name of the property to sort by
5
- * @param {boolean} [asc=true] - should sort be ascending?
6
- * @param {*} defaultValue - value to use when property is not defined in one of the objects
6
+ *
7
+ * @param propertyName - name of the property to sort by
8
+ * @param asc - should sort be ascending?
9
+ * @param defaultValue - value to use when property is not defined in one of the objects
7
10
  */
8
- const sortBy = <T>(propertyName: keyof T, asc = true, defaultValue: unknown = null) => (a: T, b: T) => {
9
- if (a[propertyName] === b[propertyName]) {
10
- return 0;
11
- }
12
- // @ts-expect-error We don't care about types here, it's for runtime pure JS too
13
-
14
- if ((a[propertyName] ?? defaultValue) > (b[propertyName] ?? defaultValue)) {
15
- // eslint-disable-next-line @typescript-eslint/no-magic-numbers
16
- return asc ? 1 : -1;
17
- }
18
- // eslint-disable-next-line @typescript-eslint/no-magic-numbers
19
- return asc ? -1 : 1;
11
+ const sortBy = <T extends Record<string | number | symbol, any>>( // eslint-disable-line @typescript-eslint/no-explicit-any
12
+ propertyName: keyof T, asc = true, defaultValue: unknown = null,
13
+ ) => (a: T, b: T) => {
14
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
15
+ return sortByMultiple([propertyName], asc, { [propertyName]: defaultValue } as Partial<Record<keyof T, any>>)(a, b);
20
16
  };
21
17
 
22
18
  export {
@@ -0,0 +1,87 @@
1
+ import { sortByMultiple } from "./sortByMultiple.js";
2
+
3
+ describe("sortByMultiple", () => {
4
+ const items = [
5
+ { height: 480, bitrate: 300 },
6
+ { height: 720, bitrate: 100 },
7
+ { height: 720, bitrate: 200 },
8
+ { height: 720, bitrate: 50 },
9
+ ];
10
+
11
+ it("must sort asc", () => {
12
+ items.sort(sortByMultiple(["height", "bitrate"])).must.eql([
13
+ { height: 480, bitrate: 300 },
14
+ { height: 720, bitrate: 50 },
15
+ { height: 720, bitrate: 100 },
16
+ { height: 720, bitrate: 200 },
17
+ ]);
18
+ });
19
+
20
+ it("must sort desc", () => {
21
+ items.sort(sortByMultiple(["height", "bitrate"], false)).must.eql([
22
+ { height: 720, bitrate: 200 },
23
+ { height: 720, bitrate: 100 },
24
+ { height: 720, bitrate: 50 },
25
+ { height: 480, bitrate: 300 },
26
+ ]);
27
+ });
28
+
29
+ it("must sort with default value (example 1)", () => {
30
+ const itemsMissing = [
31
+ { height: 480, bitrate: 300 },
32
+ { height: 720, bitrate: 100 },
33
+ { height: 720 },
34
+ { height: 720, bitrate: 200 },
35
+ ];
36
+
37
+ itemsMissing.sort(sortByMultiple(["height", "bitrate"], false, { bitrate: 999 })).must.eql([
38
+ { height: 720 }, // bitrate assumed to be 999
39
+ { height: 720, bitrate: 200 },
40
+ { height: 720, bitrate: 100 },
41
+ { height: 480, bitrate: 300 },
42
+ ]);
43
+ });
44
+
45
+ it("must sort with default value (example 2)", () => {
46
+ const itemsMissing = [
47
+ { height: 480, bitrate: 300 },
48
+ { height: 720, bitrate: 100 },
49
+ { height: 720 },
50
+ { height: 720, bitrate: 200 },
51
+ ];
52
+
53
+ itemsMissing.sort(sortByMultiple(["height", "bitrate"], true, { bitrate: 1 })).must.eql([
54
+ { height: 480, bitrate: 300 },
55
+ { height: 720 }, // bitrate assumed to be 1
56
+ { height: 720, bitrate: 100 },
57
+ { height: 720, bitrate: 200 },
58
+ ]);
59
+ });
60
+
61
+ it("must sort each prop order separately", () => {
62
+ items.sort(sortByMultiple(["height", "bitrate"], { height: true, bitrate: false })).must.eql([
63
+ { height: 480, bitrate: 300 },
64
+ { height: 720, bitrate: 200 },
65
+ { height: 720, bitrate: 100 },
66
+ { height: 720, bitrate: 50 },
67
+ ]);
68
+ });
69
+
70
+ it("must sort each prop order separately (with missing)", () => {
71
+ const itemsMissing = [
72
+ { height: 480, bitrate: 300 },
73
+ { height: 720, bitrate: 100 },
74
+ { height: 720 },
75
+ { height: 720, bitrate: 200 },
76
+ ];
77
+
78
+ itemsMissing.sort(
79
+ sortByMultiple(["height", "bitrate"], { height: true, bitrate: false }, { bitrate: 150 }),
80
+ ).must.eql([
81
+ { height: 480, bitrate: 300 },
82
+ { height: 720, bitrate: 200 },
83
+ { height: 720 }, // bitrate assumed to be 150
84
+ { height: 720, bitrate: 100 },
85
+ ]);
86
+ });
87
+ });
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Returns a function that can be used as a callback to `.sort()` method. Returned function will sort array by given
3
+ * properties.
4
+ *
5
+ * @param propertyNames - name of the properties to sort by, in order of priority
6
+ * @param ascending - should sort be ascending? Pass boolean or object with boolean values for each property
7
+ * @param defaultValues - values to use when properties are not defined in one of the objects
8
+ *
9
+ * @example:
10
+ * ```
11
+ * const videos = [
12
+ * { height: 480, bitrate: 300 },
13
+ * { height: 720, bitrate: 100 },
14
+ * { height: 720 },
15
+ * { height: 720, bitrate: 200 },
16
+ * ];
17
+ * // Sort by height ascending, then by bitrate descending, and set default bitrate to 150
18
+ * itemsMissing.sort(sortByMultiple(["height", "bitrate"], { height: true, bitrate: false }, { bitrate: 150 }));
19
+ * // Result:
20
+ * [
21
+ * { height: 480, bitrate: 300 },
22
+ * { height: 720, bitrate: 200 },
23
+ * { height: 720 }, // bitrate assumed to be 150
24
+ * { height: 720, bitrate: 100 },
25
+ * ]
26
+ * ```
27
+ */
28
+ const sortByMultiple = <
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ T extends Record<string | number | symbol, any>,
31
+ K extends (keyof T)[],
32
+ >(
33
+ propertyNames: K,
34
+ ascending: boolean | Record<K[number], boolean> = true,
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ defaultValues?: Partial<Record<K[number], any>>, // Force defaultValues to use only keys from K
37
+ ): ((a: T, b: T) => number) => (a: T, b: T) => {
38
+ for (const propertyName of propertyNames) {
39
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
40
+ const asc = typeof ascending === "boolean" ? ascending : (ascending[propertyName] ?? true);
41
+ const aBiggerValue = asc ? 1 : -1; // eslint-disable-line @typescript-eslint/no-magic-numbers
42
+ const bBiggerValue = asc ? -1 : 1; // eslint-disable-line @typescript-eslint/no-magic-numbers
43
+
44
+ const aValue = a[propertyName] ?? defaultValues?.[propertyName];
45
+ const bValue = b[propertyName] ?? defaultValues?.[propertyName];
46
+
47
+ if (aValue !== bValue) {
48
+ // @ts-expect-error Too dynamic for TS
49
+ return (aValue > bValue ? aBiggerValue : bBiggerValue);
50
+ }
51
+ }
52
+ return 0;
53
+ };
54
+
55
+ export {
56
+ sortByMultiple,
57
+ };