@oscarpalmer/atoms 0.141.2 → 0.142.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/dist/atoms.full.js +81 -36
- package/dist/index.js +2 -2
- package/dist/promise.js +81 -36
- package/package.json +5 -5
- package/src/promise.ts +209 -54
- package/src/value/get-set.ts +1 -1
- package/src/value/merge.ts +1 -1
- package/types/promise.d.ts +50 -8
package/dist/atoms.full.js
CHANGED
|
@@ -2764,25 +2764,25 @@ function delay(options) {
|
|
|
2764
2764
|
clearTimeout(timeout);
|
|
2765
2765
|
rejector(signal.reason);
|
|
2766
2766
|
}
|
|
2767
|
-
signal?.addEventListener("abort", abort,
|
|
2767
|
+
signal?.addEventListener("abort", abort, ABORT_OPTIONS);
|
|
2768
2768
|
let rejector;
|
|
2769
2769
|
let timeout;
|
|
2770
2770
|
return new Promise((resolve, reject) => {
|
|
2771
2771
|
rejector = reject;
|
|
2772
2772
|
timeout = setTimeout(() => {
|
|
2773
|
-
|
|
2774
|
-
resolve();
|
|
2773
|
+
settlePromise(abort, resolve, void 0, signal);
|
|
2775
2774
|
}, time);
|
|
2776
2775
|
});
|
|
2777
2776
|
}
|
|
2778
|
-
function getBooleanOrDefault$1(value, defaultValue) {
|
|
2779
|
-
return typeof value === "boolean" ? value : defaultValue;
|
|
2780
|
-
}
|
|
2781
2777
|
function getNumberOrDefault$1(value) {
|
|
2782
2778
|
return typeof value === "number" && value > 0 ? value : 0;
|
|
2783
2779
|
}
|
|
2784
2780
|
function getPromiseOptions(input) {
|
|
2785
2781
|
if (typeof input === "number") return { time: getNumberOrDefault$1(input) };
|
|
2782
|
+
if (input instanceof AbortSignal) return {
|
|
2783
|
+
signal: input,
|
|
2784
|
+
time: 0
|
|
2785
|
+
};
|
|
2786
2786
|
const options = typeof input === "object" && input !== null ? input : {};
|
|
2787
2787
|
return {
|
|
2788
2788
|
signal: options.signal instanceof AbortSignal ? options.signal : void 0,
|
|
@@ -2790,32 +2790,54 @@ function getPromiseOptions(input) {
|
|
|
2790
2790
|
};
|
|
2791
2791
|
}
|
|
2792
2792
|
function getPromisesOptions(input) {
|
|
2793
|
-
if (typeof input === "
|
|
2793
|
+
if (typeof input === "string") return { strategy: getStrategyOrDefault(input) };
|
|
2794
2794
|
if (input instanceof AbortSignal) return {
|
|
2795
|
-
|
|
2796
|
-
|
|
2795
|
+
signal: input,
|
|
2796
|
+
strategy: DEFAULT_STRATEGY
|
|
2797
2797
|
};
|
|
2798
2798
|
const options = typeof input === "object" && input !== null ? input : {};
|
|
2799
2799
|
return {
|
|
2800
|
-
|
|
2801
|
-
|
|
2800
|
+
signal: options.signal instanceof AbortSignal ? options.signal : void 0,
|
|
2801
|
+
strategy: getStrategyOrDefault(options.strategy)
|
|
2802
2802
|
};
|
|
2803
2803
|
}
|
|
2804
|
+
function getStrategyOrDefault(value) {
|
|
2805
|
+
return strategies.has(value) ? value : DEFAULT_STRATEGY;
|
|
2806
|
+
}
|
|
2807
|
+
async function getTimed(promise, time, signal) {
|
|
2808
|
+
function abort() {
|
|
2809
|
+
clearTimeout(timeout);
|
|
2810
|
+
rejector(signal.reason);
|
|
2811
|
+
}
|
|
2812
|
+
signal?.addEventListener(EVENT_NAME$1, abort, ABORT_OPTIONS);
|
|
2813
|
+
let rejector;
|
|
2814
|
+
let timeout;
|
|
2815
|
+
return Promise.race([promise, new Promise((_, reject) => {
|
|
2816
|
+
rejector = reject;
|
|
2817
|
+
timeout = setTimeout(() => {
|
|
2818
|
+
settlePromise(abort, reject, new PromiseTimeoutError(), signal);
|
|
2819
|
+
}, time);
|
|
2820
|
+
})]).then((value) => {
|
|
2821
|
+
clearTimeout(timeout);
|
|
2822
|
+
signal?.removeEventListener(EVENT_NAME$1, abort);
|
|
2823
|
+
return value;
|
|
2824
|
+
});
|
|
2825
|
+
}
|
|
2804
2826
|
function handleResult(status, parameters) {
|
|
2805
|
-
const {
|
|
2827
|
+
const { abort, complete, data, handlers, index, signal, value } = parameters;
|
|
2806
2828
|
if (signal?.aborted ?? false) return;
|
|
2807
|
-
if (
|
|
2808
|
-
handlers.reject
|
|
2829
|
+
if (!complete && status === TYPE_REJECTED) {
|
|
2830
|
+
settlePromise(abort, handlers.reject, value, signal);
|
|
2809
2831
|
return;
|
|
2810
2832
|
}
|
|
2811
|
-
data.result[index] =
|
|
2833
|
+
data.result[index] = !complete ? value : status === TYPE_FULFILLED ? {
|
|
2812
2834
|
status,
|
|
2813
2835
|
value
|
|
2814
2836
|
} : {
|
|
2815
2837
|
status,
|
|
2816
2838
|
reason: value
|
|
2817
2839
|
};
|
|
2818
|
-
if (index === data.last) handlers.resolve
|
|
2840
|
+
if (index === data.last) settlePromise(abort, handlers.resolve, data.result, signal);
|
|
2819
2841
|
}
|
|
2820
2842
|
/**
|
|
2821
2843
|
* Is the value a fulfilled promise result?
|
|
@@ -2837,15 +2859,17 @@ function isType(value, type) {
|
|
|
2837
2859
|
return typeof value === "object" && value !== null && value.status === type;
|
|
2838
2860
|
}
|
|
2839
2861
|
async function promises(items, options) {
|
|
2862
|
+
const { signal, strategy } = getPromisesOptions(options);
|
|
2863
|
+
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
2864
|
+
if (!Array.isArray(items)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_PROMISES));
|
|
2840
2865
|
const actual = items.filter((item) => item instanceof Promise);
|
|
2841
2866
|
const { length } = actual;
|
|
2842
|
-
const { eager, signal } = getPromisesOptions(options);
|
|
2843
|
-
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
2844
2867
|
if (length === 0) return actual;
|
|
2868
|
+
const complete = strategy === DEFAULT_STRATEGY;
|
|
2845
2869
|
function abort() {
|
|
2846
2870
|
handlers.reject(signal.reason);
|
|
2847
2871
|
}
|
|
2848
|
-
signal?.addEventListener("abort", abort,
|
|
2872
|
+
signal?.addEventListener("abort", abort, ABORT_OPTIONS);
|
|
2849
2873
|
const data = {
|
|
2850
2874
|
last: length - 1,
|
|
2851
2875
|
result: []
|
|
@@ -2857,15 +2881,17 @@ async function promises(items, options) {
|
|
|
2857
2881
|
resolve
|
|
2858
2882
|
};
|
|
2859
2883
|
for (let index = 0; index < length; index += 1) actual[index].then((value) => handleResult(TYPE_FULFILLED, {
|
|
2884
|
+
abort,
|
|
2885
|
+
complete,
|
|
2860
2886
|
data,
|
|
2861
|
-
eager,
|
|
2862
2887
|
handlers,
|
|
2863
2888
|
index,
|
|
2864
2889
|
signal,
|
|
2865
2890
|
value
|
|
2866
2891
|
})).catch((reason) => handleResult(TYPE_REJECTED, {
|
|
2892
|
+
abort,
|
|
2893
|
+
complete,
|
|
2867
2894
|
data,
|
|
2868
|
-
eager,
|
|
2869
2895
|
handlers,
|
|
2870
2896
|
index,
|
|
2871
2897
|
signal,
|
|
@@ -2873,31 +2899,50 @@ async function promises(items, options) {
|
|
|
2873
2899
|
}));
|
|
2874
2900
|
});
|
|
2875
2901
|
}
|
|
2876
|
-
function
|
|
2877
|
-
|
|
2902
|
+
function settlePromise(aborter, settler, value, signal) {
|
|
2903
|
+
signal?.removeEventListener(EVENT_NAME$1, aborter);
|
|
2904
|
+
settler(value);
|
|
2905
|
+
}
|
|
2906
|
+
async function timed(promise, options) {
|
|
2907
|
+
if (!(promise instanceof Promise)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_TIMED));
|
|
2908
|
+
const { signal, time } = getPromiseOptions(options);
|
|
2909
|
+
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
2910
|
+
return time > 0 ? getTimed(promise, time, signal) : promise;
|
|
2911
|
+
}
|
|
2912
|
+
async function tryPromise(value, options) {
|
|
2913
|
+
const isFunction = typeof value === "function";
|
|
2914
|
+
if (!isFunction && !(value instanceof Promise)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_TRY));
|
|
2878
2915
|
const { signal, time } = getPromiseOptions(options);
|
|
2879
2916
|
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
2880
|
-
if (time <= 0) return promise;
|
|
2881
2917
|
function abort() {
|
|
2882
|
-
clearTimeout(timeout);
|
|
2883
2918
|
rejector(signal.reason);
|
|
2884
2919
|
}
|
|
2885
|
-
|
|
2920
|
+
async function handler(resolve, reject) {
|
|
2921
|
+
try {
|
|
2922
|
+
let result = isFunction ? value() : await value;
|
|
2923
|
+
if (result instanceof Promise) result = await result;
|
|
2924
|
+
settlePromise(abort, resolve, result, signal);
|
|
2925
|
+
} catch (error) {
|
|
2926
|
+
settlePromise(abort, reject, error, signal);
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2886
2929
|
let rejector;
|
|
2887
|
-
|
|
2888
|
-
|
|
2930
|
+
signal?.addEventListener(EVENT_NAME$1, abort, ABORT_OPTIONS);
|
|
2931
|
+
const promise = new Promise((resolve, reject) => {
|
|
2889
2932
|
rejector = reject;
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
}, time);
|
|
2894
|
-
})]);
|
|
2933
|
+
handler(resolve, reject);
|
|
2934
|
+
});
|
|
2935
|
+
return time > 0 ? getTimed(promise, time, signal) : promise;
|
|
2895
2936
|
}
|
|
2896
|
-
const
|
|
2937
|
+
const ABORT_OPTIONS = { once: true };
|
|
2938
|
+
const DEFAULT_STRATEGY = "complete";
|
|
2897
2939
|
const ERROR_NAME$1 = "PromiseTimeoutError";
|
|
2898
2940
|
const EVENT_NAME$1 = "abort";
|
|
2899
|
-
const
|
|
2941
|
+
const MESSAGE_EXPECTATION_PROMISES = "Promises expected an array of promises";
|
|
2942
|
+
const MESSAGE_EXPECTATION_TIMED = "Timed function expected a Promise";
|
|
2943
|
+
const MESSAGE_EXPECTATION_TRY = "TryPromise expected a function or a promise";
|
|
2900
2944
|
const MESSAGE_TIMEOUT = "Promise timed out";
|
|
2945
|
+
const strategies = new Set(["complete", "first"]);
|
|
2901
2946
|
const TYPE_FULFILLED = "fulfilled";
|
|
2902
2947
|
const TYPE_REJECTED = "rejected";
|
|
2903
2948
|
/**
|
|
@@ -3342,4 +3387,4 @@ var SizedSet = class extends Set {
|
|
|
3342
3387
|
}
|
|
3343
3388
|
}
|
|
3344
3389
|
};
|
|
3345
|
-
export { frame_rate_default as FRAME_RATE_MS, PromiseTimeoutError, QueueError, SizedMap, SizedSet, average, beacon, between, camelCase, capitalize, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, fromQuery, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isKey, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, memoize, merge, min, noop, ok, parse, partial, pascalCase, promises, push, queue, result, rgbToHex, rgbToHsl, rgbToHsla, round, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, titleCase, toMap, toQuery, toRecord, toSet, trim, truncate, tryDecode, tryEncode, unique, unsmush, unwrap, upperCase, words };
|
|
3390
|
+
export { frame_rate_default as FRAME_RATE_MS, PromiseTimeoutError, QueueError, SizedMap, SizedSet, average, beacon, between, camelCase, capitalize, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, fromQuery, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isKey, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, memoize, merge, min, noop, ok, parse, partial, pascalCase, promises, push, queue, result, rgbToHex, rgbToHsl, rgbToHsla, round, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, titleCase, toMap, toQuery, toRecord, toSet, trim, truncate, tryDecode, tryEncode, tryPromise, unique, unsmush, unwrap, upperCase, words };
|
package/dist/index.js
CHANGED
|
@@ -51,10 +51,10 @@ import { unsmush } from "./value/unsmush.js";
|
|
|
51
51
|
import { isEmpty, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumerical, isObject, isPrimitive } from "./is.js";
|
|
52
52
|
import { logger } from "./logger.js";
|
|
53
53
|
import { average, count, min, round, sum } from "./math.js";
|
|
54
|
-
import { PromiseTimeoutError, delay, isFulfilled, isRejected, promises, timed } from "./promise.js";
|
|
54
|
+
import { PromiseTimeoutError, delay, isFulfilled, isRejected, promises, timed, tryPromise } from "./promise.js";
|
|
55
55
|
import { fromQuery, toQuery } from "./query.js";
|
|
56
56
|
import { QueueError, queue } from "./queue.js";
|
|
57
57
|
import { getRandomBoolean, getRandomCharacters, getRandomColor, getRandomHex, getRandomItem, getRandomItems } from "./random.js";
|
|
58
58
|
import { error, isError, isOk, isResult, ok, result, unwrap } from "./result.js";
|
|
59
59
|
import { SizedSet } from "./sized/set.js";
|
|
60
|
-
export { frame_rate_default as FRAME_RATE_MS, PromiseTimeoutError, QueueError, SizedMap, SizedSet, average, beacon, between, camelCase, capitalize, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, fromQuery, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isKey, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, memoize, merge, min, noop, ok, parse, partial, pascalCase, promises, push, queue, result, rgbToHex, rgbToHsl, rgbToHsla, round, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, titleCase, toMap, toQuery, toRecord, toSet, trim, truncate, tryDecode, tryEncode, unique, unsmush, unwrap, upperCase, words };
|
|
60
|
+
export { frame_rate_default as FRAME_RATE_MS, PromiseTimeoutError, QueueError, SizedMap, SizedSet, average, beacon, between, camelCase, capitalize, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, endsWith, equal, error, exists, filter, find, flatten, fromQuery, getArray, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, indexOf, insert, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isKey, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, memoize, merge, min, noop, ok, parse, partial, pascalCase, promises, push, queue, result, rgbToHex, rgbToHsl, rgbToHsla, round, setValue, shuffle, smush, snakeCase, sort, splice, startsWith, sum, template, throttle, timed, titleCase, toMap, toQuery, toRecord, toSet, trim, truncate, tryDecode, tryEncode, tryPromise, unique, unsmush, unwrap, upperCase, words };
|
package/dist/promise.js
CHANGED
|
@@ -11,25 +11,25 @@ function delay(options) {
|
|
|
11
11
|
clearTimeout(timeout);
|
|
12
12
|
rejector(signal.reason);
|
|
13
13
|
}
|
|
14
|
-
signal?.addEventListener("abort", abort,
|
|
14
|
+
signal?.addEventListener("abort", abort, ABORT_OPTIONS);
|
|
15
15
|
let rejector;
|
|
16
16
|
let timeout;
|
|
17
17
|
return new Promise((resolve, reject) => {
|
|
18
18
|
rejector = reject;
|
|
19
19
|
timeout = setTimeout(() => {
|
|
20
|
-
|
|
21
|
-
resolve();
|
|
20
|
+
settlePromise(abort, resolve, void 0, signal);
|
|
22
21
|
}, time);
|
|
23
22
|
});
|
|
24
23
|
}
|
|
25
|
-
function getBooleanOrDefault(value, defaultValue) {
|
|
26
|
-
return typeof value === "boolean" ? value : defaultValue;
|
|
27
|
-
}
|
|
28
24
|
function getNumberOrDefault(value) {
|
|
29
25
|
return typeof value === "number" && value > 0 ? value : 0;
|
|
30
26
|
}
|
|
31
27
|
function getPromiseOptions(input) {
|
|
32
28
|
if (typeof input === "number") return { time: getNumberOrDefault(input) };
|
|
29
|
+
if (input instanceof AbortSignal) return {
|
|
30
|
+
signal: input,
|
|
31
|
+
time: 0
|
|
32
|
+
};
|
|
33
33
|
const options = typeof input === "object" && input !== null ? input : {};
|
|
34
34
|
return {
|
|
35
35
|
signal: options.signal instanceof AbortSignal ? options.signal : void 0,
|
|
@@ -37,32 +37,54 @@ function getPromiseOptions(input) {
|
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
function getPromisesOptions(input) {
|
|
40
|
-
if (typeof input === "
|
|
40
|
+
if (typeof input === "string") return { strategy: getStrategyOrDefault(input) };
|
|
41
41
|
if (input instanceof AbortSignal) return {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
signal: input,
|
|
43
|
+
strategy: DEFAULT_STRATEGY
|
|
44
44
|
};
|
|
45
45
|
const options = typeof input === "object" && input !== null ? input : {};
|
|
46
46
|
return {
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
signal: options.signal instanceof AbortSignal ? options.signal : void 0,
|
|
48
|
+
strategy: getStrategyOrDefault(options.strategy)
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
+
function getStrategyOrDefault(value) {
|
|
52
|
+
return strategies.has(value) ? value : DEFAULT_STRATEGY;
|
|
53
|
+
}
|
|
54
|
+
async function getTimed(promise, time, signal) {
|
|
55
|
+
function abort() {
|
|
56
|
+
clearTimeout(timeout);
|
|
57
|
+
rejector(signal.reason);
|
|
58
|
+
}
|
|
59
|
+
signal?.addEventListener(EVENT_NAME, abort, ABORT_OPTIONS);
|
|
60
|
+
let rejector;
|
|
61
|
+
let timeout;
|
|
62
|
+
return Promise.race([promise, new Promise((_, reject) => {
|
|
63
|
+
rejector = reject;
|
|
64
|
+
timeout = setTimeout(() => {
|
|
65
|
+
settlePromise(abort, reject, new PromiseTimeoutError(), signal);
|
|
66
|
+
}, time);
|
|
67
|
+
})]).then((value) => {
|
|
68
|
+
clearTimeout(timeout);
|
|
69
|
+
signal?.removeEventListener(EVENT_NAME, abort);
|
|
70
|
+
return value;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
51
73
|
function handleResult(status, parameters) {
|
|
52
|
-
const {
|
|
74
|
+
const { abort, complete, data, handlers, index, signal, value } = parameters;
|
|
53
75
|
if (signal?.aborted ?? false) return;
|
|
54
|
-
if (
|
|
55
|
-
handlers.reject
|
|
76
|
+
if (!complete && status === TYPE_REJECTED) {
|
|
77
|
+
settlePromise(abort, handlers.reject, value, signal);
|
|
56
78
|
return;
|
|
57
79
|
}
|
|
58
|
-
data.result[index] =
|
|
80
|
+
data.result[index] = !complete ? value : status === TYPE_FULFILLED ? {
|
|
59
81
|
status,
|
|
60
82
|
value
|
|
61
83
|
} : {
|
|
62
84
|
status,
|
|
63
85
|
reason: value
|
|
64
86
|
};
|
|
65
|
-
if (index === data.last) handlers.resolve
|
|
87
|
+
if (index === data.last) settlePromise(abort, handlers.resolve, data.result, signal);
|
|
66
88
|
}
|
|
67
89
|
/**
|
|
68
90
|
* Is the value a fulfilled promise result?
|
|
@@ -84,15 +106,17 @@ function isType(value, type) {
|
|
|
84
106
|
return typeof value === "object" && value !== null && value.status === type;
|
|
85
107
|
}
|
|
86
108
|
async function promises(items, options) {
|
|
109
|
+
const { signal, strategy } = getPromisesOptions(options);
|
|
110
|
+
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
111
|
+
if (!Array.isArray(items)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_PROMISES));
|
|
87
112
|
const actual = items.filter((item) => item instanceof Promise);
|
|
88
113
|
const { length } = actual;
|
|
89
|
-
const { eager, signal } = getPromisesOptions(options);
|
|
90
|
-
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
91
114
|
if (length === 0) return actual;
|
|
115
|
+
const complete = strategy === DEFAULT_STRATEGY;
|
|
92
116
|
function abort() {
|
|
93
117
|
handlers.reject(signal.reason);
|
|
94
118
|
}
|
|
95
|
-
signal?.addEventListener("abort", abort,
|
|
119
|
+
signal?.addEventListener("abort", abort, ABORT_OPTIONS);
|
|
96
120
|
const data = {
|
|
97
121
|
last: length - 1,
|
|
98
122
|
result: []
|
|
@@ -104,15 +128,17 @@ async function promises(items, options) {
|
|
|
104
128
|
resolve
|
|
105
129
|
};
|
|
106
130
|
for (let index = 0; index < length; index += 1) actual[index].then((value) => handleResult(TYPE_FULFILLED, {
|
|
131
|
+
abort,
|
|
132
|
+
complete,
|
|
107
133
|
data,
|
|
108
|
-
eager,
|
|
109
134
|
handlers,
|
|
110
135
|
index,
|
|
111
136
|
signal,
|
|
112
137
|
value
|
|
113
138
|
})).catch((reason) => handleResult(TYPE_REJECTED, {
|
|
139
|
+
abort,
|
|
140
|
+
complete,
|
|
114
141
|
data,
|
|
115
|
-
eager,
|
|
116
142
|
handlers,
|
|
117
143
|
index,
|
|
118
144
|
signal,
|
|
@@ -120,31 +146,50 @@ async function promises(items, options) {
|
|
|
120
146
|
}));
|
|
121
147
|
});
|
|
122
148
|
}
|
|
123
|
-
function
|
|
124
|
-
|
|
149
|
+
function settlePromise(aborter, settler, value, signal) {
|
|
150
|
+
signal?.removeEventListener(EVENT_NAME, aborter);
|
|
151
|
+
settler(value);
|
|
152
|
+
}
|
|
153
|
+
async function timed(promise, options) {
|
|
154
|
+
if (!(promise instanceof Promise)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_TIMED));
|
|
155
|
+
const { signal, time } = getPromiseOptions(options);
|
|
156
|
+
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
157
|
+
return time > 0 ? getTimed(promise, time, signal) : promise;
|
|
158
|
+
}
|
|
159
|
+
async function tryPromise(value, options) {
|
|
160
|
+
const isFunction = typeof value === "function";
|
|
161
|
+
if (!isFunction && !(value instanceof Promise)) return Promise.reject(new TypeError(MESSAGE_EXPECTATION_TRY));
|
|
125
162
|
const { signal, time } = getPromiseOptions(options);
|
|
126
163
|
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
127
|
-
if (time <= 0) return promise;
|
|
128
164
|
function abort() {
|
|
129
|
-
clearTimeout(timeout);
|
|
130
165
|
rejector(signal.reason);
|
|
131
166
|
}
|
|
132
|
-
|
|
167
|
+
async function handler(resolve, reject) {
|
|
168
|
+
try {
|
|
169
|
+
let result = isFunction ? value() : await value;
|
|
170
|
+
if (result instanceof Promise) result = await result;
|
|
171
|
+
settlePromise(abort, resolve, result, signal);
|
|
172
|
+
} catch (error) {
|
|
173
|
+
settlePromise(abort, reject, error, signal);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
133
176
|
let rejector;
|
|
134
|
-
|
|
135
|
-
|
|
177
|
+
signal?.addEventListener(EVENT_NAME, abort, ABORT_OPTIONS);
|
|
178
|
+
const promise = new Promise((resolve, reject) => {
|
|
136
179
|
rejector = reject;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}, time);
|
|
141
|
-
})]);
|
|
180
|
+
handler(resolve, reject);
|
|
181
|
+
});
|
|
182
|
+
return time > 0 ? getTimed(promise, time, signal) : promise;
|
|
142
183
|
}
|
|
143
|
-
var
|
|
184
|
+
var ABORT_OPTIONS = { once: true };
|
|
185
|
+
var DEFAULT_STRATEGY = "complete";
|
|
144
186
|
var ERROR_NAME = "PromiseTimeoutError";
|
|
145
187
|
var EVENT_NAME = "abort";
|
|
146
|
-
var
|
|
188
|
+
var MESSAGE_EXPECTATION_PROMISES = "Promises expected an array of promises";
|
|
189
|
+
var MESSAGE_EXPECTATION_TIMED = "Timed function expected a Promise";
|
|
190
|
+
var MESSAGE_EXPECTATION_TRY = "TryPromise expected a function or a promise";
|
|
147
191
|
var MESSAGE_TIMEOUT = "Promise timed out";
|
|
192
|
+
var strategies = new Set(["complete", "first"]);
|
|
148
193
|
var TYPE_FULFILLED = "fulfilled";
|
|
149
194
|
var TYPE_REJECTED = "rejected";
|
|
150
|
-
export { PromiseTimeoutError, delay, isFulfilled, isRejected, promises, timed };
|
|
195
|
+
export { PromiseTimeoutError, delay, isFulfilled, isRejected, promises, timed, tryPromise };
|
package/package.json
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"@types/node": "^25.3",
|
|
9
9
|
"@vitest/coverage-istanbul": "^4",
|
|
10
10
|
"jsdom": "^28.1",
|
|
11
|
-
"oxfmt": "^0.
|
|
12
|
-
"oxlint": "^1.
|
|
13
|
-
"rolldown": "1.0.0-rc.
|
|
11
|
+
"oxfmt": "^0.35",
|
|
12
|
+
"oxlint": "^1.50",
|
|
13
|
+
"rolldown": "1.0.0-rc.6",
|
|
14
14
|
"tslib": "^2.8",
|
|
15
15
|
"typescript": "^5.9",
|
|
16
|
-
"vite": "8.0.0-beta.
|
|
16
|
+
"vite": "8.0.0-beta.16",
|
|
17
17
|
"vitest": "^4"
|
|
18
18
|
},
|
|
19
19
|
"exports": {
|
|
@@ -236,5 +236,5 @@
|
|
|
236
236
|
},
|
|
237
237
|
"type": "module",
|
|
238
238
|
"types": "./types/index.d.ts",
|
|
239
|
-
"version": "0.
|
|
239
|
+
"version": "0.142.0"
|
|
240
240
|
}
|
package/src/promise.ts
CHANGED
|
@@ -18,8 +18,9 @@ type Handlers<Items extends unknown[]> = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
type Parameters<Items extends unknown[]> = {
|
|
21
|
+
abort: () => void;
|
|
22
|
+
complete: boolean;
|
|
21
23
|
data: Data<Items>;
|
|
22
|
-
eager: boolean;
|
|
23
24
|
handlers: Handlers<Items>;
|
|
24
25
|
index: number;
|
|
25
26
|
signal?: AbortSignal;
|
|
@@ -37,6 +38,11 @@ type PromiseOptions = {
|
|
|
37
38
|
time?: number;
|
|
38
39
|
};
|
|
39
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Promise handling strategy
|
|
43
|
+
*/
|
|
44
|
+
export type PromiseStrategy = 'complete' | 'first';
|
|
45
|
+
|
|
40
46
|
export class PromiseTimeoutError extends Error {
|
|
41
47
|
constructor() {
|
|
42
48
|
super(MESSAGE_TIMEOUT);
|
|
@@ -50,8 +56,8 @@ type Promises<Items extends unknown[]> = {
|
|
|
50
56
|
};
|
|
51
57
|
|
|
52
58
|
type PromisesOptions = {
|
|
53
|
-
eager?: boolean;
|
|
54
59
|
signal?: AbortSignal;
|
|
60
|
+
strategy?: PromiseStrategy;
|
|
55
61
|
};
|
|
56
62
|
|
|
57
63
|
type PromisesResult<Items extends unknown[]> = {
|
|
@@ -96,7 +102,7 @@ export function delay(options?: unknown): Promise<void> {
|
|
|
96
102
|
rejector(signal!.reason);
|
|
97
103
|
}
|
|
98
104
|
|
|
99
|
-
signal?.addEventListener('abort', abort,
|
|
105
|
+
signal?.addEventListener('abort', abort, ABORT_OPTIONS);
|
|
100
106
|
|
|
101
107
|
let rejector: (reason: unknown) => void;
|
|
102
108
|
let timeout: ReturnType<typeof setTimeout>;
|
|
@@ -105,17 +111,11 @@ export function delay(options?: unknown): Promise<void> {
|
|
|
105
111
|
rejector = reject;
|
|
106
112
|
|
|
107
113
|
timeout = setTimeout(() => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
resolve();
|
|
114
|
+
settlePromise(abort, resolve, undefined, signal);
|
|
111
115
|
}, time);
|
|
112
116
|
});
|
|
113
117
|
}
|
|
114
118
|
|
|
115
|
-
function getBooleanOrDefault(value: unknown, defaultValue: boolean): boolean {
|
|
116
|
-
return typeof value === 'boolean' ? value : defaultValue;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
119
|
function getNumberOrDefault(value: unknown): number {
|
|
120
120
|
return typeof value === 'number' && value > 0 ? value : 0;
|
|
121
121
|
}
|
|
@@ -127,6 +127,10 @@ function getPromiseOptions(input: unknown): RequiredKeys<PromiseOptions, 'time'>
|
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
if (input instanceof AbortSignal) {
|
|
131
|
+
return {signal: input, time: 0};
|
|
132
|
+
}
|
|
133
|
+
|
|
130
134
|
const options = typeof input === 'object' && input !== null ? (input as PromiseOptions) : {};
|
|
131
135
|
|
|
132
136
|
return {
|
|
@@ -135,47 +139,87 @@ function getPromiseOptions(input: unknown): RequiredKeys<PromiseOptions, 'time'>
|
|
|
135
139
|
};
|
|
136
140
|
}
|
|
137
141
|
|
|
138
|
-
function getPromisesOptions(input: unknown): RequiredKeys<PromisesOptions, '
|
|
139
|
-
if (typeof input === '
|
|
140
|
-
return {
|
|
142
|
+
function getPromisesOptions(input: unknown): RequiredKeys<PromisesOptions, 'strategy'> {
|
|
143
|
+
if (typeof input === 'string') {
|
|
144
|
+
return {
|
|
145
|
+
strategy: getStrategyOrDefault(input),
|
|
146
|
+
};
|
|
141
147
|
}
|
|
142
148
|
|
|
143
149
|
if (input instanceof AbortSignal) {
|
|
144
|
-
return {
|
|
150
|
+
return {signal: input, strategy: DEFAULT_STRATEGY};
|
|
145
151
|
}
|
|
146
152
|
|
|
147
153
|
const options = typeof input === 'object' && input !== null ? (input as PromisesOptions) : {};
|
|
148
154
|
|
|
149
155
|
return {
|
|
150
|
-
eager: getBooleanOrDefault(options.eager, false),
|
|
151
156
|
signal: options.signal instanceof AbortSignal ? options.signal : undefined,
|
|
157
|
+
strategy: getStrategyOrDefault(options.strategy),
|
|
152
158
|
};
|
|
153
159
|
}
|
|
154
160
|
|
|
161
|
+
function getStrategyOrDefault(value: unknown): PromiseStrategy {
|
|
162
|
+
return strategies.has(value as PromiseStrategy) ? (value as PromiseStrategy) : DEFAULT_STRATEGY;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function getTimed<Value>(
|
|
166
|
+
promise: Promise<Value>,
|
|
167
|
+
time: number,
|
|
168
|
+
signal?: AbortSignal,
|
|
169
|
+
): Promise<Value> {
|
|
170
|
+
function abort(): void {
|
|
171
|
+
clearTimeout(timeout);
|
|
172
|
+
|
|
173
|
+
rejector(signal!.reason);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
signal?.addEventListener(EVENT_NAME, abort, ABORT_OPTIONS);
|
|
177
|
+
|
|
178
|
+
let rejector: (reason: unknown) => void;
|
|
179
|
+
let timeout: ReturnType<typeof setTimeout>;
|
|
180
|
+
|
|
181
|
+
return Promise.race<Value>([
|
|
182
|
+
promise,
|
|
183
|
+
new Promise((_, reject) => {
|
|
184
|
+
rejector = reject;
|
|
185
|
+
|
|
186
|
+
timeout = setTimeout(() => {
|
|
187
|
+
settlePromise(abort, reject, new PromiseTimeoutError(), signal);
|
|
188
|
+
}, time);
|
|
189
|
+
}),
|
|
190
|
+
]).then(value => {
|
|
191
|
+
clearTimeout(timeout);
|
|
192
|
+
|
|
193
|
+
signal?.removeEventListener(EVENT_NAME, abort);
|
|
194
|
+
|
|
195
|
+
return value;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
155
199
|
function handleResult<Items extends unknown[]>(
|
|
156
200
|
status: string,
|
|
157
201
|
parameters: Parameters<Items>,
|
|
158
202
|
): void {
|
|
159
|
-
const {
|
|
203
|
+
const {abort, complete, data, handlers, index, signal, value} = parameters;
|
|
160
204
|
|
|
161
205
|
if (signal?.aborted ?? false) {
|
|
162
206
|
return;
|
|
163
207
|
}
|
|
164
208
|
|
|
165
|
-
if (
|
|
166
|
-
handlers.reject
|
|
209
|
+
if (!complete && status === TYPE_REJECTED) {
|
|
210
|
+
settlePromise(abort, handlers.reject, value, signal);
|
|
167
211
|
|
|
168
212
|
return;
|
|
169
213
|
}
|
|
170
214
|
|
|
171
|
-
(data.result as unknown[])[index] =
|
|
215
|
+
(data.result as unknown[])[index] = !complete
|
|
172
216
|
? value
|
|
173
217
|
: status === TYPE_FULFILLED
|
|
174
218
|
? {status, value}
|
|
175
219
|
: {status, reason: value};
|
|
176
220
|
|
|
177
221
|
if (index === data.last) {
|
|
178
|
-
handlers.resolve
|
|
222
|
+
settlePromise(abort, handlers.resolve, data.result, signal);
|
|
179
223
|
}
|
|
180
224
|
}
|
|
181
225
|
|
|
@@ -206,7 +250,9 @@ function isType(value: unknown, type: string): boolean {
|
|
|
206
250
|
}
|
|
207
251
|
|
|
208
252
|
/**
|
|
209
|
-
*
|
|
253
|
+
* Handle a list of promises, returning their results in an ordered array.
|
|
254
|
+
*
|
|
255
|
+
* Depending on the strategy, the function will either reject on the first error encountered or return an array of rejected and resolved results
|
|
210
256
|
* @param items List of promises
|
|
211
257
|
* @param options Options for handling the promises
|
|
212
258
|
* @return List of results
|
|
@@ -214,17 +260,19 @@ function isType(value: unknown, type: string): boolean {
|
|
|
214
260
|
export async function promises<Items extends unknown[], Options extends PromisesOptions>(
|
|
215
261
|
items: Promises<Items>,
|
|
216
262
|
options?: Options,
|
|
217
|
-
): Promise<Options['
|
|
263
|
+
): Promise<Options['strategy'] extends 'first' ? Items : PromisesResult<Items>>;
|
|
218
264
|
|
|
219
265
|
/**
|
|
220
|
-
* Handle a list of promises, returning their results in an ordered array.
|
|
266
|
+
* Handle a list of promises, returning their results in an ordered array.
|
|
267
|
+
*
|
|
268
|
+
* If any promise in the list is rejected, the whole function will reject
|
|
221
269
|
* @param items List of promises
|
|
222
|
-
* @param
|
|
270
|
+
* @param strategy Strategy for handling the promises; rejects on the first error encountered
|
|
223
271
|
* @return List of results
|
|
224
272
|
*/
|
|
225
273
|
export async function promises<Items extends unknown[]>(
|
|
226
274
|
items: Promises<Items>,
|
|
227
|
-
|
|
275
|
+
strategy: 'first',
|
|
228
276
|
): Promise<Items>;
|
|
229
277
|
|
|
230
278
|
/**
|
|
@@ -242,24 +290,30 @@ export async function promises<Items extends unknown[]>(
|
|
|
242
290
|
items: Promises<Items>,
|
|
243
291
|
options?: unknown,
|
|
244
292
|
): Promise<Items | PromisesResult<Items>> {
|
|
245
|
-
const
|
|
246
|
-
const {length} = actual;
|
|
247
|
-
|
|
248
|
-
const {eager, signal} = getPromisesOptions(options);
|
|
293
|
+
const {signal, strategy} = getPromisesOptions(options);
|
|
249
294
|
|
|
250
295
|
if (signal?.aborted ?? false) {
|
|
251
296
|
return Promise.reject(signal!.reason);
|
|
252
297
|
}
|
|
253
298
|
|
|
299
|
+
if (!Array.isArray(items)) {
|
|
300
|
+
return Promise.reject(new TypeError(MESSAGE_EXPECTATION_PROMISES));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const actual = items.filter(item => item instanceof Promise);
|
|
304
|
+
const {length} = actual;
|
|
305
|
+
|
|
254
306
|
if (length === 0) {
|
|
255
307
|
return actual as unknown as Items | PromisesResult<Items>;
|
|
256
308
|
}
|
|
257
309
|
|
|
310
|
+
const complete = strategy === DEFAULT_STRATEGY;
|
|
311
|
+
|
|
258
312
|
function abort(): void {
|
|
259
313
|
handlers.reject(signal!.reason);
|
|
260
314
|
}
|
|
261
315
|
|
|
262
|
-
signal?.addEventListener('abort', abort,
|
|
316
|
+
signal?.addEventListener('abort', abort, ABORT_OPTIONS);
|
|
263
317
|
|
|
264
318
|
const data: Data<Items> = {
|
|
265
319
|
last: length - 1,
|
|
@@ -273,21 +327,57 @@ export async function promises<Items extends unknown[]>(
|
|
|
273
327
|
|
|
274
328
|
for (let index = 0; index < length; index += 1) {
|
|
275
329
|
void actual[index]
|
|
276
|
-
.then(value =>
|
|
330
|
+
.then(value =>
|
|
331
|
+
handleResult(TYPE_FULFILLED, {abort, complete, data, handlers, index, signal, value}),
|
|
332
|
+
)
|
|
277
333
|
.catch(reason =>
|
|
278
|
-
handleResult(TYPE_REJECTED, {
|
|
334
|
+
handleResult(TYPE_REJECTED, {
|
|
335
|
+
abort,
|
|
336
|
+
complete,
|
|
337
|
+
data,
|
|
338
|
+
handlers,
|
|
339
|
+
index,
|
|
340
|
+
signal,
|
|
341
|
+
value: reason,
|
|
342
|
+
}),
|
|
279
343
|
);
|
|
280
344
|
}
|
|
281
345
|
});
|
|
282
346
|
}
|
|
283
347
|
|
|
284
|
-
|
|
348
|
+
function settlePromise(
|
|
349
|
+
aborter: () => void,
|
|
350
|
+
settler: (value: any) => void,
|
|
351
|
+
value: unknown,
|
|
352
|
+
signal?: AbortSignal,
|
|
353
|
+
): void {
|
|
354
|
+
signal?.removeEventListener(EVENT_NAME, aborter);
|
|
355
|
+
|
|
356
|
+
settler(value);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Create a promise that should be settled within a certain amount of time
|
|
361
|
+
* @param promise Promise to settle
|
|
362
|
+
* @param options Timed options
|
|
363
|
+
* @returns A timed promise
|
|
364
|
+
*/
|
|
365
|
+
export async function timed<Value>(
|
|
366
|
+
promise: Promise<Value>,
|
|
367
|
+
options: RequiredKeys<PromiseOptions, 'time'>,
|
|
368
|
+
): Promise<Value>;
|
|
285
369
|
|
|
286
|
-
|
|
370
|
+
/**
|
|
371
|
+
* Create a promise that should be settled within a certain amount of time
|
|
372
|
+
* @param promise Promise to settle
|
|
373
|
+
* @param time How long to wait for _(in milliseconds; defaults to `0`)_
|
|
374
|
+
* @returns A timed promise
|
|
375
|
+
*/
|
|
376
|
+
export async function timed<Value>(promise: Promise<Value>, time: number): Promise<Value>;
|
|
287
377
|
|
|
288
|
-
export function timed(promise: Promise<
|
|
378
|
+
export async function timed<Value>(promise: Promise<Value>, options: unknown): Promise<Value> {
|
|
289
379
|
if (!(promise instanceof Promise)) {
|
|
290
|
-
|
|
380
|
+
return Promise.reject(new TypeError(MESSAGE_EXPECTATION_TIMED));
|
|
291
381
|
}
|
|
292
382
|
|
|
293
383
|
const {signal, time} = getPromiseOptions(options);
|
|
@@ -296,49 +386,114 @@ export function timed(promise: Promise<unknown>, options: unknown): Promise<unkn
|
|
|
296
386
|
return Promise.reject(signal!.reason);
|
|
297
387
|
}
|
|
298
388
|
|
|
299
|
-
|
|
300
|
-
|
|
389
|
+
return time > 0 ? getTimed(promise, time, signal) : promise;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Wrap a promise with safety handlers, with optional abort capabilities and timeout
|
|
394
|
+
* @param promise Promise to wrap
|
|
395
|
+
* @param options Options for the promise
|
|
396
|
+
* @returns A wrapped promise
|
|
397
|
+
*/
|
|
398
|
+
export async function tryPromise<Value>(
|
|
399
|
+
promise: Promise<Value>,
|
|
400
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
401
|
+
): Promise<Value>;
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Wrap a promise-returning callback with safety handlers, with optional abort capabilities and timeout
|
|
405
|
+
* @param callback Callback to wrap
|
|
406
|
+
* @param options Options for the promise
|
|
407
|
+
* @returns A promise-wrapped callback
|
|
408
|
+
*/
|
|
409
|
+
export async function tryPromise<Value>(
|
|
410
|
+
callback: () => Promise<Value>,
|
|
411
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
412
|
+
): Promise<Value>;
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Wrap a callback with a promise and safety handlers, with optional abort capabilities and timeout
|
|
416
|
+
* @param callback Callback to wrap
|
|
417
|
+
* @param options Options for the promise
|
|
418
|
+
* @returns A promise-wrapped callback
|
|
419
|
+
*/
|
|
420
|
+
export async function tryPromise<Value>(
|
|
421
|
+
callback: () => Value,
|
|
422
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
423
|
+
): Promise<Value>;
|
|
424
|
+
|
|
425
|
+
export async function tryPromise<Value>(
|
|
426
|
+
value: (() => Value) | Promise<Value>,
|
|
427
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
428
|
+
): Promise<Value> {
|
|
429
|
+
const isFunction = typeof value === 'function';
|
|
430
|
+
|
|
431
|
+
if (!isFunction && !(value instanceof Promise)) {
|
|
432
|
+
return Promise.reject(new TypeError(MESSAGE_EXPECTATION_TRY));
|
|
301
433
|
}
|
|
302
434
|
|
|
303
|
-
|
|
304
|
-
clearTimeout(timeout);
|
|
435
|
+
const {signal, time} = getPromiseOptions(options);
|
|
305
436
|
|
|
437
|
+
if (signal?.aborted ?? false) {
|
|
438
|
+
return Promise.reject(signal!.reason);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function abort(): void {
|
|
306
442
|
rejector(signal!.reason);
|
|
307
443
|
}
|
|
308
444
|
|
|
309
|
-
|
|
445
|
+
async function handler(
|
|
446
|
+
resolve: (value: Value) => void,
|
|
447
|
+
reject: (reason: unknown) => void,
|
|
448
|
+
): Promise<void> {
|
|
449
|
+
try {
|
|
450
|
+
let result = isFunction ? value() : await value;
|
|
451
|
+
|
|
452
|
+
if (result instanceof Promise) {
|
|
453
|
+
result = await result;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
settlePromise(abort, resolve, result, signal);
|
|
457
|
+
} catch (error) {
|
|
458
|
+
settlePromise(abort, reject, error, signal);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
310
461
|
|
|
311
462
|
let rejector: (reason: unknown) => void;
|
|
312
|
-
let timeout: ReturnType<typeof setTimeout>;
|
|
313
463
|
|
|
314
|
-
|
|
315
|
-
promise,
|
|
316
|
-
new Promise((_, reject) => {
|
|
317
|
-
rejector = reject;
|
|
464
|
+
signal?.addEventListener(EVENT_NAME, abort, ABORT_OPTIONS);
|
|
318
465
|
|
|
319
|
-
|
|
320
|
-
|
|
466
|
+
const promise = new Promise<Value>((resolve, reject) => {
|
|
467
|
+
rejector = reject;
|
|
321
468
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
469
|
+
handler(resolve, reject);
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
return time > 0 ? getTimed(promise, time, signal) : promise;
|
|
326
473
|
}
|
|
327
474
|
|
|
328
475
|
// #endregion
|
|
329
476
|
|
|
330
477
|
// #region Variables
|
|
331
478
|
|
|
332
|
-
const
|
|
479
|
+
const ABORT_OPTIONS = {once: true};
|
|
480
|
+
|
|
481
|
+
const DEFAULT_STRATEGY: PromiseStrategy = 'complete';
|
|
333
482
|
|
|
334
483
|
const ERROR_NAME = 'PromiseTimeoutError';
|
|
335
484
|
|
|
336
485
|
const EVENT_NAME = 'abort';
|
|
337
486
|
|
|
338
|
-
const
|
|
487
|
+
const MESSAGE_EXPECTATION_PROMISES = 'Promises expected an array of promises';
|
|
488
|
+
|
|
489
|
+
const MESSAGE_EXPECTATION_TIMED = 'Timed function expected a Promise';
|
|
490
|
+
|
|
491
|
+
const MESSAGE_EXPECTATION_TRY = 'TryPromise expected a function or a promise';
|
|
339
492
|
|
|
340
493
|
const MESSAGE_TIMEOUT = 'Promise timed out';
|
|
341
494
|
|
|
495
|
+
const strategies = new Set<PromiseStrategy>(['complete', 'first']);
|
|
496
|
+
|
|
342
497
|
const TYPE_FULFILLED = 'fulfilled';
|
|
343
498
|
|
|
344
499
|
const TYPE_REJECTED = 'rejected';
|
package/src/value/get-set.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export {getValue} from '../internal/value/get';
|
|
2
|
-
export {setValue} from '../internal/value/set';
|
|
2
|
+
export {setValue} from '../internal/value/set';
|
package/src/value/merge.ts
CHANGED
|
@@ -101,7 +101,7 @@ function initializeMerger(options?: Partial<MergeOptions>): Merger {
|
|
|
101
101
|
|
|
102
102
|
return <Model extends ArrayOrPlainObject>(values: NestedPartial<Model>[]): Model =>
|
|
103
103
|
handleMerge(values, actual) as Model;
|
|
104
|
-
}
|
|
104
|
+
}
|
|
105
105
|
|
|
106
106
|
function mergeObjects(
|
|
107
107
|
values: ArrayOrPlainObject[],
|
package/types/promise.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RequiredKeys } from './models';
|
|
1
2
|
type FulfilledPromiseResult<Value> = {
|
|
2
3
|
status: typeof TYPE_FULFILLED;
|
|
3
4
|
value: Value;
|
|
@@ -12,6 +13,10 @@ type PromiseOptions = {
|
|
|
12
13
|
*/
|
|
13
14
|
time?: number;
|
|
14
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Promise handling strategy
|
|
18
|
+
*/
|
|
19
|
+
export type PromiseStrategy = 'complete' | 'first';
|
|
15
20
|
export declare class PromiseTimeoutError extends Error {
|
|
16
21
|
constructor();
|
|
17
22
|
}
|
|
@@ -19,8 +24,8 @@ type Promises<Items extends unknown[]> = {
|
|
|
19
24
|
[K in keyof Items]: Promise<Items[K]>;
|
|
20
25
|
};
|
|
21
26
|
type PromisesOptions = {
|
|
22
|
-
eager?: boolean;
|
|
23
27
|
signal?: AbortSignal;
|
|
28
|
+
strategy?: PromiseStrategy;
|
|
24
29
|
};
|
|
25
30
|
type PromisesResult<Items extends unknown[]> = {
|
|
26
31
|
[K in keyof Items]: PromisesResultItem<Items[K]>;
|
|
@@ -55,19 +60,23 @@ export declare function isFulfilled<Value>(value: unknown): value is FulfilledPr
|
|
|
55
60
|
*/
|
|
56
61
|
export declare function isRejected(value: unknown): value is RejectedPromiseResult;
|
|
57
62
|
/**
|
|
58
|
-
*
|
|
63
|
+
* Handle a list of promises, returning their results in an ordered array.
|
|
64
|
+
*
|
|
65
|
+
* Depending on the strategy, the function will either reject on the first error encountered or return an array of rejected and resolved results
|
|
59
66
|
* @param items List of promises
|
|
60
67
|
* @param options Options for handling the promises
|
|
61
68
|
* @return List of results
|
|
62
69
|
*/
|
|
63
|
-
export declare function promises<Items extends unknown[], Options extends PromisesOptions>(items: Promises<Items>, options?: Options): Promise<Options['
|
|
70
|
+
export declare function promises<Items extends unknown[], Options extends PromisesOptions>(items: Promises<Items>, options?: Options): Promise<Options['strategy'] extends 'first' ? Items : PromisesResult<Items>>;
|
|
64
71
|
/**
|
|
65
|
-
* Handle a list of promises, returning their results in an ordered array.
|
|
72
|
+
* Handle a list of promises, returning their results in an ordered array.
|
|
73
|
+
*
|
|
74
|
+
* If any promise in the list is rejected, the whole function will reject
|
|
66
75
|
* @param items List of promises
|
|
67
|
-
* @param
|
|
76
|
+
* @param strategy Strategy for handling the promises; rejects on the first error encountered
|
|
68
77
|
* @return List of results
|
|
69
78
|
*/
|
|
70
|
-
export declare function promises<Items extends unknown[]>(items: Promises<Items>,
|
|
79
|
+
export declare function promises<Items extends unknown[]>(items: Promises<Items>, strategy: 'first'): Promise<Items>;
|
|
71
80
|
/**
|
|
72
81
|
* Handle a list of promises, returning their results in an ordered array of rejected and resolved results
|
|
73
82
|
* @param items List of promises
|
|
@@ -75,8 +84,41 @@ export declare function promises<Items extends unknown[]>(items: Promises<Items>
|
|
|
75
84
|
* @return List of results
|
|
76
85
|
*/
|
|
77
86
|
export declare function promises<Items extends unknown[]>(items: Promises<Items>, signal?: AbortSignal): Promise<PromisesResult<Items>>;
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Create a promise that should be settled within a certain amount of time
|
|
89
|
+
* @param promise Promise to settle
|
|
90
|
+
* @param options Timed options
|
|
91
|
+
* @returns A timed promise
|
|
92
|
+
*/
|
|
93
|
+
export declare function timed<Value>(promise: Promise<Value>, options: RequiredKeys<PromiseOptions, 'time'>): Promise<Value>;
|
|
94
|
+
/**
|
|
95
|
+
* Create a promise that should be settled within a certain amount of time
|
|
96
|
+
* @param promise Promise to settle
|
|
97
|
+
* @param time How long to wait for _(in milliseconds; defaults to `0`)_
|
|
98
|
+
* @returns A timed promise
|
|
99
|
+
*/
|
|
100
|
+
export declare function timed<Value>(promise: Promise<Value>, time: number): Promise<Value>;
|
|
101
|
+
/**
|
|
102
|
+
* Wrap a promise with safety handlers, with optional abort capabilities and timeout
|
|
103
|
+
* @param promise Promise to wrap
|
|
104
|
+
* @param options Options for the promise
|
|
105
|
+
* @returns A wrapped promise
|
|
106
|
+
*/
|
|
107
|
+
export declare function tryPromise<Value>(promise: Promise<Value>, options?: PromiseOptions | AbortSignal | number): Promise<Value>;
|
|
108
|
+
/**
|
|
109
|
+
* Wrap a promise-returning callback with safety handlers, with optional abort capabilities and timeout
|
|
110
|
+
* @param callback Callback to wrap
|
|
111
|
+
* @param options Options for the promise
|
|
112
|
+
* @returns A promise-wrapped callback
|
|
113
|
+
*/
|
|
114
|
+
export declare function tryPromise<Value>(callback: () => Promise<Value>, options?: PromiseOptions | AbortSignal | number): Promise<Value>;
|
|
115
|
+
/**
|
|
116
|
+
* Wrap a callback with a promise and safety handlers, with optional abort capabilities and timeout
|
|
117
|
+
* @param callback Callback to wrap
|
|
118
|
+
* @param options Options for the promise
|
|
119
|
+
* @returns A promise-wrapped callback
|
|
120
|
+
*/
|
|
121
|
+
export declare function tryPromise<Value>(callback: () => Value, options?: PromiseOptions | AbortSignal | number): Promise<Value>;
|
|
80
122
|
declare const TYPE_FULFILLED = "fulfilled";
|
|
81
123
|
declare const TYPE_REJECTED = "rejected";
|
|
82
124
|
export {};
|