@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.
- package/CHANGELOG.md +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/race.d.ts +3 -0
- package/dist/race.d.ts.map +1 -0
- package/dist/race.js +14 -0
- package/dist/race.js.map +1 -0
- package/dist/sortBy.d.ts +1 -1
- package/dist/sortBy.d.ts.map +1 -1
- package/dist/sortBy.js +2 -7
- package/dist/sortBy.js.map +1 -1
- package/dist/sortByMultiple.d.ts +3 -0
- package/dist/sortByMultiple.d.ts.map +1 -0
- package/dist/sortByMultiple.js +18 -0
- package/dist/sortByMultiple.js.map +1 -0
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/documents/CHANGELOG.html +57 -48
- package/docs/functions/index.cap.html +2 -2
- package/docs/functions/index.capitalize.html +2 -2
- package/docs/functions/index.coalesce.html +2 -2
- package/docs/functions/index.compareArrays.html +2 -2
- package/docs/functions/index.compareProps.html +2 -2
- package/docs/functions/index.deserialize.html +2 -2
- package/docs/functions/index.ensureArray.html +2 -2
- package/docs/functions/index.ensureDate.html +2 -2
- package/docs/functions/index.ensureError.html +2 -2
- package/docs/functions/index.ensurePrefix.html +2 -2
- package/docs/functions/index.ensureSuffix.html +2 -2
- package/docs/functions/index.ensureTimestamp.html +2 -2
- package/docs/functions/index.escapeRegExp.html +2 -2
- package/docs/functions/index.formatDate.html +2 -2
- package/docs/functions/index.get.html +2 -2
- package/docs/functions/index.getMultiple.html +2 -2
- package/docs/functions/index.insertSeparator.html +2 -2
- package/docs/functions/index.isEmpty.html +2 -2
- package/docs/functions/index.isNumericString.html +2 -2
- package/docs/functions/index.isPlainObject.html +2 -2
- package/docs/functions/index.last.html +2 -2
- package/docs/functions/index.later-1.html +2 -2
- package/docs/functions/index.mapAsync.html +2 -2
- package/docs/functions/index.mapValues.html +2 -2
- package/docs/functions/index.match.html +2 -2
- package/docs/functions/index.memoize.html +2 -2
- package/docs/functions/index.merge.html +2 -2
- package/docs/functions/index.mostFrequent.html +2 -2
- package/docs/functions/index.noop.html +2 -2
- package/docs/functions/index.occurrences.html +2 -2
- package/docs/functions/index.omit.html +2 -2
- package/docs/functions/index.pick.html +2 -2
- package/docs/functions/index.pull.html +2 -2
- package/docs/functions/index.race.html +11 -0
- package/docs/functions/index.remove.html +2 -2
- package/docs/functions/index.removeCommonProperties.html +2 -2
- package/docs/functions/index.replace.html +2 -2
- package/docs/functions/index.replaceDeep.html +2 -2
- package/docs/functions/index.rethrow.html +2 -2
- package/docs/functions/index.retry.html +2 -2
- package/docs/functions/index.round.html +2 -2
- package/docs/functions/index.safe.html +2 -2
- package/docs/functions/index.sample.html +2 -2
- package/docs/functions/index.samples.html +2 -2
- package/docs/functions/index.scale.html +2 -2
- package/docs/functions/index.seq.html +2 -2
- package/docs/functions/index.seqEarlyBreak.html +2 -2
- package/docs/functions/index.serialize.html +2 -2
- package/docs/functions/index.set.html +2 -2
- package/docs/functions/index.setImmutable.html +2 -2
- package/docs/functions/index.shuffle.html +2 -2
- package/docs/functions/index.sortBy.html +4 -4
- package/docs/functions/index.sortByMultiple.html +10 -0
- package/docs/functions/index.sortProps.html +2 -2
- package/docs/functions/index.stripPrefix.html +2 -2
- package/docs/functions/index.stripSuffix.html +2 -2
- package/docs/functions/index.throttle.html +2 -2
- package/docs/functions/index.toggle.html +2 -2
- package/docs/functions/index.trim.html +2 -2
- package/docs/functions/index.trimEnd.html +2 -2
- package/docs/functions/index.trimStart.html +2 -2
- package/docs/functions/index.truthy.html +2 -2
- package/docs/functions/index.unique.html +2 -2
- package/docs/functions/index.wait.html +2 -2
- package/docs/functions/index.waitFor.html +2 -2
- package/docs/functions/index.waitSync.html +2 -2
- package/docs/index.html +2 -2
- package/docs/interfaces/index.ComparePropsOptions.html +3 -3
- package/docs/interfaces/index.GetMultipleSource.html +2 -2
- package/docs/interfaces/index.GetSource.html +2 -2
- package/docs/interfaces/index.IsNumericStringOptions.html +2 -2
- package/docs/interfaces/index.OccurencesOptions.html +2 -2
- package/docs/interfaces/index.SetImmutableSource.html +2 -2
- package/docs/interfaces/index.SetSource.html +2 -2
- package/docs/interfaces/index.ThrottleOptions.html +3 -3
- package/docs/interfaces/index.ThrottledFunctionExtras.html +3 -3
- package/docs/modules/index.html +4 -2
- package/docs/modules.html +2 -2
- package/docs/types/index.CustomDeserializers.html +1 -1
- package/docs/types/index.CustomSerializers.html +1 -1
- package/docs/types/index.Later.html +2 -2
- package/docs/types/index.MapValuesFn.html +2 -2
- package/docs/types/index.MatchCallback.html +1 -1
- package/docs/types/index.MergeTwo.html +2 -2
- package/docs/types/index.SeqEarlyBreaker.html +2 -2
- package/docs/types/index.SeqFn.html +2 -2
- package/docs/types/index.SeqFunctions.html +2 -2
- package/docs/types/index.SetImmutablePath.html +2 -2
- package/docs/types/index.ThrottledFunction.html +1 -1
- package/docs/variables/index.mapValuesUNSET.html +2 -2
- package/docs/variables/index.mergeUNSET.html +2 -2
- package/esm/index.d.ts +2 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +2 -0
- package/esm/index.js.map +1 -1
- package/esm/race.d.ts +3 -0
- package/esm/race.d.ts.map +1 -0
- package/esm/race.js +11 -0
- package/esm/race.js.map +1 -0
- package/esm/sortBy.d.ts +1 -1
- package/esm/sortBy.d.ts.map +1 -1
- package/esm/sortBy.js +2 -7
- package/esm/sortBy.js.map +1 -1
- package/esm/sortByMultiple.d.ts +3 -0
- package/esm/sortByMultiple.d.ts.map +1 -0
- package/esm/sortByMultiple.js +15 -0
- package/esm/sortByMultiple.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/race.ts +30 -0
- package/src/sortBy.spec.ts +13 -0
- package/src/sortBy.ts +11 -15
- package/src/sortByMultiple.spec.ts +87 -0
- package/src/sortByMultiple.ts +57 -0
package/package.json
CHANGED
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
|
package/src/sortBy.spec.ts
CHANGED
|
@@ -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
|
-
*
|
|
5
|
-
* @param
|
|
6
|
-
* @param
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
+
};
|