@oscarpalmer/atoms 0.149.0 → 0.150.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 +172 -142
- package/dist/index.js +9 -3
- package/dist/promise/delay.js +28 -0
- package/dist/promise/helpers.js +51 -0
- package/dist/promise/index.js +73 -0
- package/dist/promise/misc.js +36 -0
- package/dist/promise/models.js +37 -0
- package/dist/promise/timed.js +33 -0
- package/dist/result/index.js +4 -27
- package/dist/result/misc.js +40 -0
- package/package.json +3 -3
- package/src/index.ts +1 -1
- package/src/promise/delay.ts +63 -0
- package/src/promise/helpers.ts +91 -0
- package/src/promise/index.ts +230 -0
- package/src/promise/misc.ts +89 -0
- package/src/promise/models.ts +131 -0
- package/src/promise/timed.ts +90 -0
- package/src/result/index.ts +4 -66
- package/src/result/misc.ts +115 -0
- package/types/index.d.ts +1 -1
- package/types/promise/delay.d.ts +13 -0
- package/types/promise/helpers.d.ts +17 -0
- package/types/promise/index.d.ts +53 -0
- package/types/promise/misc.d.ts +22 -0
- package/types/promise/models.d.ts +81 -0
- package/types/promise/timed.d.ts +17 -0
- package/types/result/index.d.ts +3 -34
- package/types/result/misc.d.ts +51 -0
- package/dist/promise.js +0 -221
- package/src/promise.ts +0 -538
- package/types/promise.d.ts +0 -139
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { PROMISE_ABORT_OPTIONS, PROMISE_EVENT_NAME, PROMISE_MESSAGE_EXPECTATION_TIMED, PromiseTimeoutError } from "./models.js";
|
|
2
|
+
import { getPromiseOptions } from "./helpers.js";
|
|
3
|
+
import { settlePromise } from "./misc.js";
|
|
4
|
+
async function getTimedPromise(promise, time, signal) {
|
|
5
|
+
function abort() {
|
|
6
|
+
cancelAnimationFrame(frame);
|
|
7
|
+
rejector(signal.reason);
|
|
8
|
+
}
|
|
9
|
+
function run(now) {
|
|
10
|
+
start ??= now;
|
|
11
|
+
if (time === 0 || now - start >= time - 5) settlePromise(abort, rejector, new PromiseTimeoutError(), signal);
|
|
12
|
+
else frame = requestAnimationFrame(run);
|
|
13
|
+
}
|
|
14
|
+
signal?.addEventListener(PROMISE_EVENT_NAME, abort, PROMISE_ABORT_OPTIONS);
|
|
15
|
+
let frame;
|
|
16
|
+
let rejector;
|
|
17
|
+
let start;
|
|
18
|
+
return Promise.race([promise, new Promise((_, reject) => {
|
|
19
|
+
rejector = reject;
|
|
20
|
+
frame = requestAnimationFrame(run);
|
|
21
|
+
})]).then((value) => {
|
|
22
|
+
cancelAnimationFrame(frame);
|
|
23
|
+
signal?.removeEventListener(PROMISE_EVENT_NAME, abort);
|
|
24
|
+
return value;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function timed(promise, options) {
|
|
28
|
+
if (!(promise instanceof Promise)) return Promise.reject(new TypeError(PROMISE_MESSAGE_EXPECTATION_TIMED));
|
|
29
|
+
const { signal, time } = getPromiseOptions(options);
|
|
30
|
+
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
31
|
+
return time > 0 ? getTimedPromise(promise, time, signal) : promise;
|
|
32
|
+
}
|
|
33
|
+
export { getTimedPromise, timed };
|
package/dist/result/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { isError, isOk, isResult } from "../internal/result.js";
|
|
2
|
-
import {
|
|
2
|
+
import { error, getError, ok, toPromise, unwrap } from "./misc.js";
|
|
3
|
+
import { toResult } from "../promise/misc.js";
|
|
4
|
+
import { attemptPromise } from "../promise/index.js";
|
|
3
5
|
import { matchResult } from "./match.js";
|
|
4
6
|
import { attemptFlow } from "./work/flow.js";
|
|
5
7
|
import { attemptPipe } from "./work/pipe.js";
|
|
@@ -24,29 +26,4 @@ attempt.flow = attemptFlow;
|
|
|
24
26
|
attempt.match = matchResult;
|
|
25
27
|
attempt.pipe = attemptPipe;
|
|
26
28
|
attempt.promise = attemptPromise;
|
|
27
|
-
|
|
28
|
-
return getError(value, original);
|
|
29
|
-
}
|
|
30
|
-
function getError(value, original) {
|
|
31
|
-
const errorResult = {
|
|
32
|
-
error: value,
|
|
33
|
-
ok: false
|
|
34
|
-
};
|
|
35
|
-
if (original instanceof Error) errorResult.original = original;
|
|
36
|
-
return errorResult;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Creates an ok result
|
|
40
|
-
* @param value Value
|
|
41
|
-
* @returns Ok result
|
|
42
|
-
*/
|
|
43
|
-
function ok(value) {
|
|
44
|
-
return {
|
|
45
|
-
ok: true,
|
|
46
|
-
value
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function unwrap(value, defaultValue) {
|
|
50
|
-
return isOk(value) ? value.value : defaultValue;
|
|
51
|
-
}
|
|
52
|
-
export { attempt, error, isError, isOk, isResult, ok, unwrap };
|
|
29
|
+
export { attempt, error, toResult as fromPromise, isError, isOk, isResult, ok, toPromise, unwrap };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isOk, isResult } from "../internal/result.js";
|
|
2
|
+
function error(value, original) {
|
|
3
|
+
return getError(value, original);
|
|
4
|
+
}
|
|
5
|
+
function getError(value, original) {
|
|
6
|
+
const errorResult = {
|
|
7
|
+
error: value,
|
|
8
|
+
ok: false
|
|
9
|
+
};
|
|
10
|
+
if (original instanceof Error) errorResult.original = original;
|
|
11
|
+
return errorResult;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Creates an ok result
|
|
15
|
+
* @param value Value
|
|
16
|
+
* @returns Ok result
|
|
17
|
+
*/
|
|
18
|
+
function ok(value) {
|
|
19
|
+
return {
|
|
20
|
+
ok: true,
|
|
21
|
+
value
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Converts a result to a promise
|
|
26
|
+
*
|
|
27
|
+
* Resolves if ok, rejects for error
|
|
28
|
+
* @param result Result to convert
|
|
29
|
+
* @returns Promised result
|
|
30
|
+
*/
|
|
31
|
+
async function toPromise(result) {
|
|
32
|
+
const actual = typeof result === "function" ? result() : result;
|
|
33
|
+
if (!isResult(actual)) return Promise.reject(new Error(MESSAGE_PROMISE_RESULT));
|
|
34
|
+
return isOk(actual) ? Promise.resolve(actual.value) : Promise.reject(actual.error);
|
|
35
|
+
}
|
|
36
|
+
function unwrap(value, defaultValue) {
|
|
37
|
+
return isOk(value) ? value.value : defaultValue;
|
|
38
|
+
}
|
|
39
|
+
var MESSAGE_PROMISE_RESULT = "toPromise expected to receive a Result";
|
|
40
|
+
export { error, getError, ok, toPromise, unwrap };
|
package/package.json
CHANGED
|
@@ -94,8 +94,8 @@
|
|
|
94
94
|
"default": "./dist/number.js"
|
|
95
95
|
},
|
|
96
96
|
"./promise": {
|
|
97
|
-
"types": "./types/promise.d.ts",
|
|
98
|
-
"default": "./dist/promise.js"
|
|
97
|
+
"types": "./types/promise/index.d.ts",
|
|
98
|
+
"default": "./dist/promise/index.js"
|
|
99
99
|
},
|
|
100
100
|
"./query": {
|
|
101
101
|
"types": "./types/query.d.ts",
|
|
@@ -192,5 +192,5 @@
|
|
|
192
192
|
},
|
|
193
193
|
"type": "module",
|
|
194
194
|
"types": "./types/index.d.ts",
|
|
195
|
-
"version": "0.
|
|
195
|
+
"version": "0.150.0"
|
|
196
196
|
}
|
package/src/index.ts
CHANGED
|
@@ -38,7 +38,7 @@ export * from './logger';
|
|
|
38
38
|
export * from './math';
|
|
39
39
|
export * from './models';
|
|
40
40
|
export * from './number';
|
|
41
|
-
export * from './promise';
|
|
41
|
+
export * from './promise/index';
|
|
42
42
|
export * from './query';
|
|
43
43
|
export * from './queue';
|
|
44
44
|
export * from './random';
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {getPromiseOptions} from './helpers';
|
|
2
|
+
import {settlePromise} from './misc';
|
|
3
|
+
import {PROMISE_ABORT_OPTIONS, type PromiseOptions} from './models';
|
|
4
|
+
|
|
5
|
+
// #region Functions
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create a delayed promise that resolves after a certain amount of time, or rejects if aborted
|
|
9
|
+
* @param options Options for the delay
|
|
10
|
+
* @returns Delayed promise
|
|
11
|
+
*/
|
|
12
|
+
export function delay(options?: PromiseOptions): Promise<void>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create a delayed promise that resolves after a certain amount of time
|
|
16
|
+
* @param time How long to wait for _(in milliseconds; defaults to `0`)_
|
|
17
|
+
* @returns Delayed promise
|
|
18
|
+
*/
|
|
19
|
+
export function delay(time?: number): Promise<void>;
|
|
20
|
+
|
|
21
|
+
export function delay(options?: unknown): Promise<void> {
|
|
22
|
+
const {signal, time} = getPromiseOptions(options);
|
|
23
|
+
|
|
24
|
+
if (signal?.aborted ?? false) {
|
|
25
|
+
return Promise.reject(signal!.reason);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function abort(): void {
|
|
29
|
+
cancelAnimationFrame(frame);
|
|
30
|
+
|
|
31
|
+
rejector(signal!.reason);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function run(now: DOMHighResTimeStamp): void {
|
|
35
|
+
start ??= now;
|
|
36
|
+
|
|
37
|
+
if (now - start >= time - 5) {
|
|
38
|
+
settlePromise(abort, resolver, undefined, signal);
|
|
39
|
+
} else {
|
|
40
|
+
frame = requestAnimationFrame(run);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
signal?.addEventListener('abort', abort, PROMISE_ABORT_OPTIONS);
|
|
45
|
+
|
|
46
|
+
let frame: DOMHighResTimeStamp;
|
|
47
|
+
let rejector: (reason: unknown) => void;
|
|
48
|
+
let resolver: () => void;
|
|
49
|
+
let start: DOMHighResTimeStamp;
|
|
50
|
+
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
rejector = reject;
|
|
53
|
+
resolver = resolve;
|
|
54
|
+
|
|
55
|
+
if (time === 0) {
|
|
56
|
+
settlePromise(abort, resolve, undefined, signal);
|
|
57
|
+
} else {
|
|
58
|
+
frame = requestAnimationFrame(run);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// #endregion
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type {RequiredKeys} from '../models';
|
|
2
|
+
import {
|
|
3
|
+
PROMISE_STRATEGY_DEFAULT,
|
|
4
|
+
PROMISE_STRATEGY_ALL,
|
|
5
|
+
PROMISE_TYPE_FULFILLED,
|
|
6
|
+
PROMISE_TYPE_REJECTED,
|
|
7
|
+
type FulfilledPromise,
|
|
8
|
+
type PromiseOptions,
|
|
9
|
+
type PromisesOptions,
|
|
10
|
+
type PromisesResultItem,
|
|
11
|
+
type PromiseStrategy,
|
|
12
|
+
type RejectedPromise,
|
|
13
|
+
} from './models';
|
|
14
|
+
|
|
15
|
+
// #region Functions
|
|
16
|
+
|
|
17
|
+
function getNumberOrDefault(value: unknown): number {
|
|
18
|
+
return typeof value === 'number' && value > 0 ? value : 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getPromiseOptions(input: unknown): RequiredKeys<PromiseOptions, 'time'> {
|
|
22
|
+
if (typeof input === 'number') {
|
|
23
|
+
return {
|
|
24
|
+
time: getNumberOrDefault(input),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (input instanceof AbortSignal) {
|
|
29
|
+
return {signal: input, time: 0};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const options = typeof input === 'object' && input !== null ? (input as PromiseOptions) : {};
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
signal: options.signal instanceof AbortSignal ? options.signal : undefined,
|
|
36
|
+
time: getNumberOrDefault(options.time),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getPromisesOptions(input: unknown): RequiredKeys<PromisesOptions, 'strategy'> {
|
|
41
|
+
if (typeof input === 'string') {
|
|
42
|
+
return {
|
|
43
|
+
strategy: getStrategyOrDefault(input),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (input instanceof AbortSignal) {
|
|
48
|
+
return {signal: input, strategy: PROMISE_STRATEGY_DEFAULT};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const options = typeof input === 'object' && input !== null ? (input as PromisesOptions) : {};
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
signal: options.signal instanceof AbortSignal ? options.signal : undefined,
|
|
55
|
+
strategy: getStrategyOrDefault(options.strategy),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function getStrategyOrDefault(value: unknown): PromiseStrategy {
|
|
60
|
+
return PROMISE_STRATEGY_ALL.has(value as PromiseStrategy)
|
|
61
|
+
? (value as PromiseStrategy)
|
|
62
|
+
: PROMISE_STRATEGY_DEFAULT;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Is the value a fulfilled promise result?
|
|
67
|
+
* @param value Value to check
|
|
68
|
+
* @returns `true` if the value is a fulfilled promise result, `false` otherwise
|
|
69
|
+
*/
|
|
70
|
+
export function isFulfilled<Value>(value: unknown): value is FulfilledPromise<Value> {
|
|
71
|
+
return isType(value, PROMISE_TYPE_FULFILLED);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Is the value a rejected promise result?
|
|
76
|
+
* @param value Value to check
|
|
77
|
+
* @returns `true` if the value is a rejected promise result, `false` otherwise
|
|
78
|
+
*/
|
|
79
|
+
export function isRejected(value: unknown): value is RejectedPromise {
|
|
80
|
+
return isType(value, PROMISE_TYPE_REJECTED);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isType(value: unknown, type: string): boolean {
|
|
84
|
+
return (
|
|
85
|
+
typeof value === 'object' &&
|
|
86
|
+
value !== null &&
|
|
87
|
+
(value as PromisesResultItem<unknown>).status === type
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// #endregion
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import {getPromiseOptions, getPromisesOptions} from './helpers';
|
|
2
|
+
import {handleResult, settlePromise} from './misc';
|
|
3
|
+
import {
|
|
4
|
+
PROMISE_ABORT_OPTIONS,
|
|
5
|
+
PROMISE_EVENT_NAME,
|
|
6
|
+
PROMISE_MESSAGE_EXPECTATION_ATTEMPT,
|
|
7
|
+
PROMISE_MESSAGE_EXPECTATION_PROMISES,
|
|
8
|
+
PROMISE_STRATEGY_DEFAULT,
|
|
9
|
+
PROMISE_TYPE_FULFILLED,
|
|
10
|
+
PROMISE_TYPE_REJECTED,
|
|
11
|
+
type PromiseData,
|
|
12
|
+
type PromiseHandlers,
|
|
13
|
+
type PromiseOptions,
|
|
14
|
+
type Promises,
|
|
15
|
+
type PromisesOptions,
|
|
16
|
+
type PromisesResult,
|
|
17
|
+
} from './models';
|
|
18
|
+
import {getTimedPromise} from './timed';
|
|
19
|
+
|
|
20
|
+
// #region Functions
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Wrap a promise with safety handlers, with optional abort capabilities and timeout
|
|
24
|
+
* @param promise Promise to wrap
|
|
25
|
+
* @param options Options for the promise
|
|
26
|
+
* @returns Wrapped promise
|
|
27
|
+
*/
|
|
28
|
+
export async function attemptPromise<Value>(
|
|
29
|
+
promise: Promise<Value>,
|
|
30
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
31
|
+
): Promise<Value>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Wrap a promise-returning callback with safety handlers, with optional abort capabilities and timeout
|
|
35
|
+
* @param callback Callback to wrap
|
|
36
|
+
* @param options Options for the promise
|
|
37
|
+
* @returns Promise-wrapped callback
|
|
38
|
+
*/
|
|
39
|
+
export async function attemptPromise<Value>(
|
|
40
|
+
callback: () => Promise<Value>,
|
|
41
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
42
|
+
): Promise<Value>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Wrap a callback with a promise and safety handlers, with optional abort capabilities and timeout
|
|
46
|
+
* @param callback Callback to wrap
|
|
47
|
+
* @param options Options for the promise
|
|
48
|
+
* @returns Promise-wrapped callback
|
|
49
|
+
*/
|
|
50
|
+
export async function attemptPromise<Value>(
|
|
51
|
+
callback: () => Value,
|
|
52
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
53
|
+
): Promise<Value>;
|
|
54
|
+
|
|
55
|
+
export async function attemptPromise<Value>(
|
|
56
|
+
value: (() => Value) | Promise<Value>,
|
|
57
|
+
options?: PromiseOptions | AbortSignal | number,
|
|
58
|
+
): Promise<Value> {
|
|
59
|
+
const isFunction = typeof value === 'function';
|
|
60
|
+
|
|
61
|
+
if (!isFunction && !(value instanceof Promise)) {
|
|
62
|
+
return Promise.reject(new TypeError(PROMISE_MESSAGE_EXPECTATION_ATTEMPT));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const {signal, time} = getPromiseOptions(options);
|
|
66
|
+
|
|
67
|
+
if (signal?.aborted ?? false) {
|
|
68
|
+
return Promise.reject(signal!.reason);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function abort(): void {
|
|
72
|
+
rejector(signal!.reason);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function handler(
|
|
76
|
+
resolve: (value: Value) => void,
|
|
77
|
+
reject: (reason: unknown) => void,
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
try {
|
|
80
|
+
let result = isFunction ? value() : await value;
|
|
81
|
+
|
|
82
|
+
if (result instanceof Promise) {
|
|
83
|
+
result = await result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
settlePromise(abort, resolve, result, signal);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
settlePromise(abort, reject, error, signal);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let rejector: (reason: unknown) => void;
|
|
93
|
+
|
|
94
|
+
signal?.addEventListener(PROMISE_EVENT_NAME, abort, PROMISE_ABORT_OPTIONS);
|
|
95
|
+
|
|
96
|
+
const promise = new Promise<Value>((resolve, reject) => {
|
|
97
|
+
rejector = reject;
|
|
98
|
+
|
|
99
|
+
handler(resolve, reject);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return time > 0 ? getTimedPromise(promise, time, signal) : promise;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Handle a list of promises, returning their results in an ordered array.
|
|
107
|
+
*
|
|
108
|
+
* Depending on the strategy, the function will either reject on the first error encountered or return an array of rejected and resolved results
|
|
109
|
+
* @param items List of promises
|
|
110
|
+
* @param options Options for handling the promises
|
|
111
|
+
* @returns List of results
|
|
112
|
+
*/
|
|
113
|
+
export async function promises<Items extends unknown[], Options extends PromisesOptions>(
|
|
114
|
+
items: Promises<Items>,
|
|
115
|
+
options?: Options,
|
|
116
|
+
): Promise<Options['strategy'] extends 'first' ? Items : PromisesResult<Items>>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Handle a list of promises, returning their results in an ordered array.
|
|
120
|
+
*
|
|
121
|
+
* If any promise in the list is rejected, the whole function will reject
|
|
122
|
+
* @param items List of promises
|
|
123
|
+
* @param strategy Strategy for handling the promises; rejects on the first error encountered
|
|
124
|
+
* @returns List of results
|
|
125
|
+
*/
|
|
126
|
+
export async function promises<Items extends unknown[]>(
|
|
127
|
+
items: Promises<Items>,
|
|
128
|
+
strategy: 'first',
|
|
129
|
+
): Promise<Items>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Handle a list of promises, returning their results in an ordered array of rejected and resolved results
|
|
133
|
+
* @param items List of promises
|
|
134
|
+
* @param signal AbortSignal for aborting the operation _(when aborted, the promise will reject with the reason of the signal)_
|
|
135
|
+
* @returns List of results
|
|
136
|
+
*/
|
|
137
|
+
export async function promises<Items extends unknown[]>(
|
|
138
|
+
items: Promises<Items>,
|
|
139
|
+
signal?: AbortSignal,
|
|
140
|
+
): Promise<PromisesResult<Items>>;
|
|
141
|
+
|
|
142
|
+
export async function promises<Items extends unknown[]>(
|
|
143
|
+
items: Promises<Items>,
|
|
144
|
+
options?: unknown,
|
|
145
|
+
): Promise<Items | PromisesResult<Items>> {
|
|
146
|
+
const {signal, strategy} = getPromisesOptions(options);
|
|
147
|
+
|
|
148
|
+
if (signal?.aborted ?? false) {
|
|
149
|
+
return Promise.reject(signal!.reason);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!Array.isArray(items)) {
|
|
153
|
+
return Promise.reject(new TypeError(PROMISE_MESSAGE_EXPECTATION_PROMISES));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const actual = items.filter(item => item instanceof Promise);
|
|
157
|
+
const {length} = actual;
|
|
158
|
+
|
|
159
|
+
if (length === 0) {
|
|
160
|
+
return actual as unknown as Items | PromisesResult<Items>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const complete = strategy === PROMISE_STRATEGY_DEFAULT;
|
|
164
|
+
|
|
165
|
+
function abort(): void {
|
|
166
|
+
handlers.reject(signal!.reason);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
signal?.addEventListener('abort', abort, PROMISE_ABORT_OPTIONS);
|
|
170
|
+
|
|
171
|
+
const data: PromiseData<Items> = {
|
|
172
|
+
last: length - 1,
|
|
173
|
+
result: [] as unknown as Items | PromisesResult<Items>,
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
let handlers: PromiseHandlers<Items>;
|
|
177
|
+
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
handlers = {reject, resolve};
|
|
180
|
+
|
|
181
|
+
for (let index = 0; index < length; index += 1) {
|
|
182
|
+
void actual[index]
|
|
183
|
+
.then(value =>
|
|
184
|
+
handleResult(PROMISE_TYPE_FULFILLED, {
|
|
185
|
+
abort,
|
|
186
|
+
complete,
|
|
187
|
+
data,
|
|
188
|
+
handlers,
|
|
189
|
+
index,
|
|
190
|
+
signal,
|
|
191
|
+
value,
|
|
192
|
+
}),
|
|
193
|
+
)
|
|
194
|
+
.catch(reason =>
|
|
195
|
+
handleResult(PROMISE_TYPE_REJECTED, {
|
|
196
|
+
abort,
|
|
197
|
+
complete,
|
|
198
|
+
data,
|
|
199
|
+
handlers,
|
|
200
|
+
index,
|
|
201
|
+
signal,
|
|
202
|
+
value: reason,
|
|
203
|
+
}),
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// #endregion
|
|
210
|
+
|
|
211
|
+
// #region Exports
|
|
212
|
+
|
|
213
|
+
export {toPromise as fromResult} from '../result/misc';
|
|
214
|
+
export {delay} from './delay';
|
|
215
|
+
export {isFulfilled, isRejected} from './helpers';
|
|
216
|
+
export {cancelable, toResult} from './misc';
|
|
217
|
+
export {
|
|
218
|
+
CancelablePromise,
|
|
219
|
+
PromiseTimeoutError,
|
|
220
|
+
type FulfilledPromise,
|
|
221
|
+
type RejectedPromise,
|
|
222
|
+
type PromiseOptions,
|
|
223
|
+
type PromiseStrategy,
|
|
224
|
+
type PromisesOptions,
|
|
225
|
+
type PromisesResult,
|
|
226
|
+
type PromisesResultItem,
|
|
227
|
+
} from './models';
|
|
228
|
+
export {timed} from './timed';
|
|
229
|
+
|
|
230
|
+
// #endregion
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {error, ok} from '../result/misc';
|
|
2
|
+
import type {Result} from '../result/models';
|
|
3
|
+
import {
|
|
4
|
+
CancelablePromise,
|
|
5
|
+
PROMISE_EVENT_NAME,
|
|
6
|
+
PROMISE_MESSAGE_EXPECTATION_RESULT,
|
|
7
|
+
PROMISE_TYPE_FULFILLED,
|
|
8
|
+
PROMISE_TYPE_REJECTED,
|
|
9
|
+
type PromiseParameters,
|
|
10
|
+
} from './models';
|
|
11
|
+
|
|
12
|
+
// #region Functions
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create a cancelable promise
|
|
16
|
+
* @param executor Executor function for the promise
|
|
17
|
+
* @returns Cancelable promise
|
|
18
|
+
*/
|
|
19
|
+
export function cancelable<Value>(
|
|
20
|
+
executor: (resolve: (value: Value) => void, reject: (reason: unknown) => void) => void,
|
|
21
|
+
): CancelablePromise<Value> {
|
|
22
|
+
return new CancelablePromise(executor);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function handleResult<Items extends unknown[]>(
|
|
26
|
+
status: string,
|
|
27
|
+
parameters: PromiseParameters<Items>,
|
|
28
|
+
): void {
|
|
29
|
+
const {abort, complete, data, handlers, index, signal, value} = parameters;
|
|
30
|
+
|
|
31
|
+
if (signal?.aborted ?? false) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!complete && status === PROMISE_TYPE_REJECTED) {
|
|
36
|
+
settlePromise(abort, handlers.reject, value, signal);
|
|
37
|
+
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
(data.result as unknown[])[index] = !complete
|
|
42
|
+
? value
|
|
43
|
+
: status === PROMISE_TYPE_FULFILLED
|
|
44
|
+
? {status, value}
|
|
45
|
+
: {status, reason: value};
|
|
46
|
+
|
|
47
|
+
if (index === data.last) {
|
|
48
|
+
settlePromise(abort, handlers.resolve, data.result, signal);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function settlePromise(
|
|
53
|
+
aborter: () => void,
|
|
54
|
+
settler: (value: any) => void,
|
|
55
|
+
value: unknown,
|
|
56
|
+
signal?: AbortSignal,
|
|
57
|
+
): void {
|
|
58
|
+
signal?.removeEventListener(PROMISE_EVENT_NAME, aborter);
|
|
59
|
+
|
|
60
|
+
settler(value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Converts a promise to a promised result
|
|
65
|
+
* @param callback Promise callback
|
|
66
|
+
* @returns Promised result
|
|
67
|
+
*/
|
|
68
|
+
export async function toResult<Value>(callback: () => Promise<Value>): Promise<Result<Value>>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Converts a promise to a promised result
|
|
72
|
+
* @param promise Promise to convert
|
|
73
|
+
* @returns Promised result
|
|
74
|
+
*/
|
|
75
|
+
export async function toResult<Value>(promise: Promise<Value>): Promise<Result<Value>>;
|
|
76
|
+
|
|
77
|
+
export async function toResult<Value>(
|
|
78
|
+
value: Promise<Value> | (() => Promise<Value>),
|
|
79
|
+
): Promise<Result<Value>> {
|
|
80
|
+
const actual = typeof value === 'function' ? value() : value;
|
|
81
|
+
|
|
82
|
+
if (!(actual instanceof Promise)) {
|
|
83
|
+
return Promise.reject(new TypeError(PROMISE_MESSAGE_EXPECTATION_RESULT));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return actual.then(result => ok(result)).catch(reason => error(reason));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// #endregion
|