@ezez/utils 4.3.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 (130) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/race.d.ts.map +1 -1
  7. package/dist/race.js.map +1 -1
  8. package/dist/sortBy.d.ts +1 -1
  9. package/dist/sortBy.d.ts.map +1 -1
  10. package/dist/sortBy.js +2 -7
  11. package/dist/sortBy.js.map +1 -1
  12. package/dist/sortByMultiple.d.ts +3 -0
  13. package/dist/sortByMultiple.d.ts.map +1 -0
  14. package/dist/sortByMultiple.js +18 -0
  15. package/dist/sortByMultiple.js.map +1 -0
  16. package/docs/assets/navigation.js +1 -1
  17. package/docs/assets/search.js +1 -1
  18. package/docs/documents/CHANGELOG.html +55 -49
  19. package/docs/functions/index.cap.html +2 -2
  20. package/docs/functions/index.capitalize.html +2 -2
  21. package/docs/functions/index.coalesce.html +2 -2
  22. package/docs/functions/index.compareArrays.html +2 -2
  23. package/docs/functions/index.compareProps.html +2 -2
  24. package/docs/functions/index.deserialize.html +2 -2
  25. package/docs/functions/index.ensureArray.html +2 -2
  26. package/docs/functions/index.ensureDate.html +2 -2
  27. package/docs/functions/index.ensureError.html +2 -2
  28. package/docs/functions/index.ensurePrefix.html +2 -2
  29. package/docs/functions/index.ensureSuffix.html +2 -2
  30. package/docs/functions/index.ensureTimestamp.html +2 -2
  31. package/docs/functions/index.escapeRegExp.html +2 -2
  32. package/docs/functions/index.formatDate.html +2 -2
  33. package/docs/functions/index.get.html +2 -2
  34. package/docs/functions/index.getMultiple.html +2 -2
  35. package/docs/functions/index.insertSeparator.html +2 -2
  36. package/docs/functions/index.isEmpty.html +2 -2
  37. package/docs/functions/index.isNumericString.html +2 -2
  38. package/docs/functions/index.isPlainObject.html +2 -2
  39. package/docs/functions/index.last.html +2 -2
  40. package/docs/functions/index.later-1.html +2 -2
  41. package/docs/functions/index.mapAsync.html +2 -2
  42. package/docs/functions/index.mapValues.html +2 -2
  43. package/docs/functions/index.match.html +2 -2
  44. package/docs/functions/index.memoize.html +2 -2
  45. package/docs/functions/index.merge.html +2 -2
  46. package/docs/functions/index.mostFrequent.html +2 -2
  47. package/docs/functions/index.noop.html +2 -2
  48. package/docs/functions/index.occurrences.html +2 -2
  49. package/docs/functions/index.omit.html +2 -2
  50. package/docs/functions/index.pick.html +2 -2
  51. package/docs/functions/index.pull.html +2 -2
  52. package/docs/functions/index.race.html +6 -3
  53. package/docs/functions/index.remove.html +2 -2
  54. package/docs/functions/index.removeCommonProperties.html +2 -2
  55. package/docs/functions/index.replace.html +2 -2
  56. package/docs/functions/index.replaceDeep.html +2 -2
  57. package/docs/functions/index.rethrow.html +2 -2
  58. package/docs/functions/index.retry.html +2 -2
  59. package/docs/functions/index.round.html +2 -2
  60. package/docs/functions/index.safe.html +2 -2
  61. package/docs/functions/index.sample.html +2 -2
  62. package/docs/functions/index.samples.html +2 -2
  63. package/docs/functions/index.scale.html +2 -2
  64. package/docs/functions/index.seq.html +2 -2
  65. package/docs/functions/index.seqEarlyBreak.html +2 -2
  66. package/docs/functions/index.serialize.html +2 -2
  67. package/docs/functions/index.set.html +2 -2
  68. package/docs/functions/index.setImmutable.html +2 -2
  69. package/docs/functions/index.shuffle.html +2 -2
  70. package/docs/functions/index.sortBy.html +4 -4
  71. package/docs/functions/index.sortByMultiple.html +10 -0
  72. package/docs/functions/index.sortProps.html +2 -2
  73. package/docs/functions/index.stripPrefix.html +2 -2
  74. package/docs/functions/index.stripSuffix.html +2 -2
  75. package/docs/functions/index.throttle.html +2 -2
  76. package/docs/functions/index.toggle.html +2 -2
  77. package/docs/functions/index.trim.html +2 -2
  78. package/docs/functions/index.trimEnd.html +2 -2
  79. package/docs/functions/index.trimStart.html +2 -2
  80. package/docs/functions/index.truthy.html +2 -2
  81. package/docs/functions/index.unique.html +2 -2
  82. package/docs/functions/index.wait.html +2 -2
  83. package/docs/functions/index.waitFor.html +2 -2
  84. package/docs/functions/index.waitSync.html +2 -2
  85. package/docs/index.html +2 -2
  86. package/docs/interfaces/index.ComparePropsOptions.html +3 -3
  87. package/docs/interfaces/index.GetMultipleSource.html +2 -2
  88. package/docs/interfaces/index.GetSource.html +2 -2
  89. package/docs/interfaces/index.IsNumericStringOptions.html +2 -2
  90. package/docs/interfaces/index.OccurencesOptions.html +2 -2
  91. package/docs/interfaces/index.SetImmutableSource.html +2 -2
  92. package/docs/interfaces/index.SetSource.html +2 -2
  93. package/docs/interfaces/index.ThrottleOptions.html +3 -3
  94. package/docs/interfaces/index.ThrottledFunctionExtras.html +3 -3
  95. package/docs/modules/index.html +3 -2
  96. package/docs/modules.html +2 -2
  97. package/docs/types/index.CustomDeserializers.html +1 -1
  98. package/docs/types/index.CustomSerializers.html +1 -1
  99. package/docs/types/index.Later.html +2 -2
  100. package/docs/types/index.MapValuesFn.html +2 -2
  101. package/docs/types/index.MatchCallback.html +1 -1
  102. package/docs/types/index.MergeTwo.html +2 -2
  103. package/docs/types/index.SeqEarlyBreaker.html +2 -2
  104. package/docs/types/index.SeqFn.html +2 -2
  105. package/docs/types/index.SeqFunctions.html +2 -2
  106. package/docs/types/index.SetImmutablePath.html +2 -2
  107. package/docs/types/index.ThrottledFunction.html +1 -1
  108. package/docs/variables/index.mapValuesUNSET.html +2 -2
  109. package/docs/variables/index.mergeUNSET.html +2 -2
  110. package/esm/index.d.ts +1 -0
  111. package/esm/index.d.ts.map +1 -1
  112. package/esm/index.js +1 -0
  113. package/esm/index.js.map +1 -1
  114. package/esm/race.d.ts.map +1 -1
  115. package/esm/race.js.map +1 -1
  116. package/esm/sortBy.d.ts +1 -1
  117. package/esm/sortBy.d.ts.map +1 -1
  118. package/esm/sortBy.js +2 -7
  119. package/esm/sortBy.js.map +1 -1
  120. package/esm/sortByMultiple.d.ts +3 -0
  121. package/esm/sortByMultiple.d.ts.map +1 -0
  122. package/esm/sortByMultiple.js +15 -0
  123. package/esm/sortByMultiple.js.map +1 -0
  124. package/package.json +1 -1
  125. package/src/index.ts +1 -0
  126. package/src/race.ts +1 -0
  127. package/src/sortBy.spec.ts +13 -0
  128. package/src/sortBy.ts +11 -15
  129. package/src/sortByMultiple.spec.ts +87 -0
  130. package/src/sortByMultiple.ts +57 -0
@@ -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
+ };