@flex-development/when 2.0.0 → 3.0.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 +32 -0
- package/README.md +657 -69
- package/dist/index.d.mts +407 -23
- package/dist/lib/index.mjs +4 -1
- package/dist/lib/is-catchable.mjs +24 -0
- package/dist/lib/is-finalizable.mjs +24 -0
- package/dist/lib/is-promise-like.mjs +24 -0
- package/dist/lib/is-promise.mjs +12 -6
- package/dist/lib/is-thenable.mjs +30 -8
- package/dist/lib/when.mjs +76 -12
- package/dist/testing/index.d.mts +149 -0
- package/dist/testing/index.mjs +5 -0
- package/dist/testing/lib/create-thenable.mjs +350 -0
- package/dist/testing/lib/index.mjs +5 -0
- package/package.json +15 -7
package/dist/lib/is-thenable.mjs
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
* @file isThenable
|
|
3
3
|
* @module when/lib/isThenable
|
|
4
4
|
*/
|
|
5
|
+
import hasThen from '#lib/is-promise-like';
|
|
6
|
+
export default isThenable;
|
|
5
7
|
/**
|
|
6
|
-
* Check if `value` looks like a
|
|
7
|
-
*
|
|
8
|
+
* Check if `value` looks like a {@linkcode Thenable}.
|
|
9
|
+
*
|
|
10
|
+
* @see {@linkcode Thenable}
|
|
8
11
|
*
|
|
9
12
|
* @template {any} T
|
|
10
13
|
* The resolved value
|
|
@@ -13,15 +16,34 @@
|
|
|
13
16
|
*
|
|
14
17
|
* @param {unknown} value
|
|
15
18
|
* The thing to check
|
|
16
|
-
* @return {value is
|
|
19
|
+
* @return {value is Thenable<T>}
|
|
17
20
|
* `true` if `value` is an object or function with a `then` method,
|
|
18
|
-
* `false` otherwise
|
|
21
|
+
* and maybe-callable methods `catch` and/or `finally`, `false` otherwise
|
|
19
22
|
*/
|
|
20
23
|
function isThenable(value) {
|
|
21
|
-
if (!value)
|
|
24
|
+
if (!hasThen(value))
|
|
25
|
+
return false; // no `then` method, cannot be a thenable.
|
|
26
|
+
// a thenable without a `catch` or `finally` method.
|
|
27
|
+
if (!('catch' in value) && !('finally' in value))
|
|
28
|
+
return true;
|
|
29
|
+
// cannot be a thenable, invalid `catch` property.
|
|
30
|
+
if (!maybeCallable(value['catch']))
|
|
22
31
|
return false;
|
|
23
|
-
|
|
32
|
+
// cannot be a thenable, invalid `finally` property.
|
|
33
|
+
if (!maybeCallable(value['finally']))
|
|
24
34
|
return false;
|
|
25
|
-
return
|
|
35
|
+
return true; // thenable.
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @internal
|
|
39
|
+
*
|
|
40
|
+
* @this {void}
|
|
41
|
+
*
|
|
42
|
+
* @param {unknown} value
|
|
43
|
+
* The thing to check
|
|
44
|
+
* @return {((...args: any[]) => any) | null | undefined}
|
|
45
|
+
* `true` if `value` is a function, `null`, or `undefined`, `false` otherwise
|
|
46
|
+
*/
|
|
47
|
+
function maybeCallable(value) {
|
|
48
|
+
return value == null || typeof value === 'function';
|
|
26
49
|
}
|
|
27
|
-
export default isThenable;
|
package/dist/lib/when.mjs
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @file when
|
|
3
3
|
* @module when/lib/when
|
|
4
4
|
*/
|
|
5
|
-
import
|
|
5
|
+
import isCatchable from '#lib/is-catchable';
|
|
6
|
+
import isFinalizable from '#lib/is-finalizable';
|
|
6
7
|
import isThenable from '#lib/is-thenable';
|
|
7
8
|
export default when;
|
|
8
9
|
/**
|
|
@@ -29,40 +30,90 @@ export default when;
|
|
|
29
30
|
* The next awaitable
|
|
30
31
|
*/
|
|
31
32
|
function when(value, chain, fail, context, ...args) {
|
|
33
|
+
/**
|
|
34
|
+
* The post-processing hook.
|
|
35
|
+
*
|
|
36
|
+
* @var {Finish | null | undefined}
|
|
37
|
+
*/
|
|
38
|
+
let finish;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the post-processing hook ran.
|
|
41
|
+
*
|
|
42
|
+
* @var {boolean}
|
|
43
|
+
*/
|
|
44
|
+
let finished = false;
|
|
32
45
|
if (typeof chain === 'object') {
|
|
33
46
|
fail = chain.fail;
|
|
47
|
+
finish = chain.finish;
|
|
34
48
|
context = chain.context;
|
|
35
49
|
args = chain.args ?? [];
|
|
36
50
|
chain = chain.chain;
|
|
37
51
|
}
|
|
38
|
-
// no
|
|
52
|
+
// no thenable, call chain function immediately.
|
|
39
53
|
if (!isThenable(value)) {
|
|
40
54
|
try {
|
|
41
|
-
// try attaching "global" rejection handler with `catch
|
|
42
|
-
|
|
55
|
+
// try attaching "global" rejection handler with `catch`,
|
|
56
|
+
// then try running `finish`, or attaching it with `finally`.
|
|
57
|
+
return finalize(katch(chain.call(context, ...args, value)));
|
|
43
58
|
}
|
|
44
59
|
catch (e) {
|
|
45
|
-
return failure(e);
|
|
60
|
+
return finalize(katch(failure(e)));
|
|
46
61
|
}
|
|
47
62
|
}
|
|
48
|
-
// already have a
|
|
63
|
+
// already have a thenable, chain the chain callback.
|
|
49
64
|
value = value.then(res => chain.call(context, ...args, res), failure);
|
|
50
|
-
// try attaching "global" rejection handler with `catch
|
|
51
|
-
|
|
65
|
+
// try attaching "global" rejection handler with `catch`,
|
|
66
|
+
// then try running `finish`, or attaching it with `finally`.
|
|
67
|
+
return finalize(katch(value));
|
|
52
68
|
/**
|
|
53
69
|
* @this {void}
|
|
54
70
|
*
|
|
55
71
|
* @param {unknown} e
|
|
56
72
|
* The error to handle
|
|
57
73
|
* @return {unknown}
|
|
58
|
-
* The rejection result
|
|
59
|
-
* @throws {unknown}
|
|
74
|
+
* The rejection result or never, may throw `e`
|
|
60
75
|
*/
|
|
61
76
|
function failure(e) {
|
|
62
77
|
if (typeof fail !== 'function')
|
|
63
|
-
|
|
78
|
+
return thrower(e);
|
|
64
79
|
return fail.call(context, e);
|
|
65
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* @this {void}
|
|
83
|
+
*
|
|
84
|
+
* @return {undefined}
|
|
85
|
+
*/
|
|
86
|
+
function fin() {
|
|
87
|
+
return void (finished || (finished = true, finish?.call(context)));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* @this {void}
|
|
91
|
+
*
|
|
92
|
+
* @param {unknown} value
|
|
93
|
+
* The awaitable
|
|
94
|
+
* @return {unknown}
|
|
95
|
+
* The `value`
|
|
96
|
+
*/
|
|
97
|
+
function finalize(value) {
|
|
98
|
+
if (typeof finish === 'function') {
|
|
99
|
+
if (isFinalizable(value))
|
|
100
|
+
return value.finally(fin);
|
|
101
|
+
if (isThenable(value))
|
|
102
|
+
return value.then(identity, thrower);
|
|
103
|
+
}
|
|
104
|
+
return identity(value);
|
|
105
|
+
/**
|
|
106
|
+
* @this {void}
|
|
107
|
+
*
|
|
108
|
+
* @param {unknown} value
|
|
109
|
+
* The resolved value
|
|
110
|
+
* @return {unknown}
|
|
111
|
+
* The `value`
|
|
112
|
+
*/
|
|
113
|
+
function identity(value) {
|
|
114
|
+
return fin(), value;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
66
117
|
/**
|
|
67
118
|
* Try attaching a rejection handler with `catch`.
|
|
68
119
|
*
|
|
@@ -74,8 +125,21 @@ function when(value, chain, fail, context, ...args) {
|
|
|
74
125
|
* The `value`
|
|
75
126
|
*/
|
|
76
127
|
function katch(value) {
|
|
77
|
-
if (
|
|
128
|
+
if (isCatchable(value))
|
|
78
129
|
value = value.catch(failure);
|
|
79
130
|
return value;
|
|
80
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* @this {void}
|
|
134
|
+
*
|
|
135
|
+
* @param {unknown} e
|
|
136
|
+
* The error to throw
|
|
137
|
+
* @return {never}
|
|
138
|
+
* Never; throws `e`
|
|
139
|
+
* @throws {unknown}
|
|
140
|
+
*/
|
|
141
|
+
function thrower(e) {
|
|
142
|
+
void fin();
|
|
143
|
+
throw e;
|
|
144
|
+
}
|
|
81
145
|
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Thenable, Awaitable } from '@flex-development/when';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Interfaces - CreateThenableOptions
|
|
5
|
+
* @module when/testing/interfaces/CreateThenableOptions
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Options for creating a thenable.
|
|
9
|
+
*/
|
|
10
|
+
interface CreateThenableOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Control whether returned thenables implement a `catch` method.
|
|
13
|
+
*
|
|
14
|
+
* When an options object is omitted, `null`, or `undefined`,
|
|
15
|
+
* the method will be implemented.
|
|
16
|
+
*
|
|
17
|
+
* When an options object is provided, `catch` is only implemented
|
|
18
|
+
* if `options.catch` is `true`.
|
|
19
|
+
*
|
|
20
|
+
* If `options.catch` is `null` or `undefined`, the thenable's `catch`
|
|
21
|
+
* property will have the same value.\
|
|
22
|
+
* Pass `false` to disable the method implementation.
|
|
23
|
+
*/
|
|
24
|
+
catch?: boolean | null | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Control whether returned thenables implement a `finally` method.
|
|
27
|
+
*
|
|
28
|
+
* When an options object is omitted, `null`, or `undefined`,
|
|
29
|
+
* the method will be implemented.
|
|
30
|
+
*
|
|
31
|
+
* When an options object is provided, `finally` is only implemented
|
|
32
|
+
* if `options.finally` is `true`.
|
|
33
|
+
*
|
|
34
|
+
* If `options.finally` is `null` or `undefined`, the thenable's `finally`
|
|
35
|
+
* property will have the same value.\
|
|
36
|
+
* Pass `false` to disable the method implementation.
|
|
37
|
+
*/
|
|
38
|
+
finally?: boolean | null | undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @file createThenable
|
|
43
|
+
* @module when/testing/lib/createThenable
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create a thenable.
|
|
48
|
+
*
|
|
49
|
+
* The returned object conforms to {@linkcode Thenable} and ensures `then`
|
|
50
|
+
* always returns another {@linkcode Thenable}, even when adopting a foreign
|
|
51
|
+
* thenable.
|
|
52
|
+
*
|
|
53
|
+
* When `options` is omitted, `null`, or `undefined`, the returned thenable is
|
|
54
|
+
* *modern* (a thenable with `then`, `catch`, and `finally` methods).
|
|
55
|
+
* Pass an options object (e.g. `{}`) to start from a *bare* (`then` method
|
|
56
|
+
* only) thenable and selectively enable methods.
|
|
57
|
+
*
|
|
58
|
+
* @see {@linkcode CreateThenableOptions}
|
|
59
|
+
* @see {@linkcode Executor}
|
|
60
|
+
* @see {@linkcode Thenable}
|
|
61
|
+
*
|
|
62
|
+
* @template {any} T
|
|
63
|
+
* The resolved value
|
|
64
|
+
* @template {any} [Reason=Error]
|
|
65
|
+
* The reason for a rejection
|
|
66
|
+
* @template {Thenable<T>} [Result=Thenable<T>]
|
|
67
|
+
* The thenable
|
|
68
|
+
*
|
|
69
|
+
* @this {void}
|
|
70
|
+
*
|
|
71
|
+
* @param {Executor<T, Reason>} executor
|
|
72
|
+
* The initialization callback
|
|
73
|
+
* @param {CreateThenableOptions | null | undefined} [options]
|
|
74
|
+
* Options for creating a thenable
|
|
75
|
+
* @return {Result}
|
|
76
|
+
* The thenable
|
|
77
|
+
*/
|
|
78
|
+
declare function createThenable<T, Reason = Error, Result extends Thenable<T> = Thenable<T>>(this: void, executor: Executor<T, Reason>, options?: CreateThenableOptions | null | undefined): Result;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @file Type Aliases - Executor
|
|
82
|
+
* @module when/testing/types/Executor
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The callback used to initialize a thenable.
|
|
87
|
+
*
|
|
88
|
+
* @see {@linkcode Awaitable}
|
|
89
|
+
* @see {@linkcode Resolve}
|
|
90
|
+
* @see {@linkcode Reject}
|
|
91
|
+
*
|
|
92
|
+
* @template {any} [T=any]
|
|
93
|
+
* The resolved value
|
|
94
|
+
* @template {any} [Reason=Error]
|
|
95
|
+
* The reason for a rejection
|
|
96
|
+
*
|
|
97
|
+
* @this {void}
|
|
98
|
+
*
|
|
99
|
+
* @param {Resolve<T>} resolve
|
|
100
|
+
* The callback used to resolve the thenable with a value
|
|
101
|
+
* or the result of another awaitable
|
|
102
|
+
* @param {Reject<Reason>} reject
|
|
103
|
+
* The callback used to reject the thenable with a provided reason or error
|
|
104
|
+
* @return {undefined | void}
|
|
105
|
+
*/
|
|
106
|
+
type Executor<T = any, Reason = Error> = (this: void, resolve: Resolve<T>, reject: Reject<Reason>) => undefined | void;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @file Type Aliases - Reject
|
|
110
|
+
* @module when/testing/types/Reject
|
|
111
|
+
*/
|
|
112
|
+
/**
|
|
113
|
+
* The callback used to reject a thenable with a provided reason or error.
|
|
114
|
+
*
|
|
115
|
+
* @template {any} [Reason=Error]
|
|
116
|
+
* The reason for the rejection
|
|
117
|
+
*
|
|
118
|
+
* @this {void}
|
|
119
|
+
*
|
|
120
|
+
* @param {Reason} reason
|
|
121
|
+
* The reason for the rejection
|
|
122
|
+
* @return {undefined}
|
|
123
|
+
*/
|
|
124
|
+
type Reject<Reason = Error> = (this: void, reason: Reason) => undefined;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @file Type Aliases - Resolve
|
|
128
|
+
* @module when/testing/types/Resolve
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The callback used to resolve a thenable with a value
|
|
133
|
+
* or the result of another awaitable.
|
|
134
|
+
*
|
|
135
|
+
* @see {@linkcode Awaitable}
|
|
136
|
+
*
|
|
137
|
+
* @template {any} [T=any]
|
|
138
|
+
* The resolved value
|
|
139
|
+
*
|
|
140
|
+
* @this {void}
|
|
141
|
+
*
|
|
142
|
+
* @param {Awaitable<T>} value
|
|
143
|
+
* The awaitable
|
|
144
|
+
* @return {undefined}
|
|
145
|
+
*/
|
|
146
|
+
type Resolve<T = any> = (this: void, value: Awaitable<T>) => undefined;
|
|
147
|
+
|
|
148
|
+
export { createThenable };
|
|
149
|
+
export type { CreateThenableOptions, Executor, Reject, Resolve };
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file createThenable
|
|
3
|
+
* @module when/testing/lib/createThenable
|
|
4
|
+
*/
|
|
5
|
+
import isThenable from '#lib/is-thenable';
|
|
6
|
+
export default createThenable;
|
|
7
|
+
/**
|
|
8
|
+
* Create a thenable.
|
|
9
|
+
*
|
|
10
|
+
* The returned object conforms to {@linkcode Thenable} and ensures `then`
|
|
11
|
+
* always returns another {@linkcode Thenable}, even when adopting a foreign
|
|
12
|
+
* thenable.
|
|
13
|
+
*
|
|
14
|
+
* When `options` is omitted, `null`, or `undefined`, the returned thenable is
|
|
15
|
+
* *modern* (a thenable with `then`, `catch`, and `finally` methods).
|
|
16
|
+
* Pass an options object (e.g. `{}`) to start from a *bare* (`then` method
|
|
17
|
+
* only) thenable and selectively enable methods.
|
|
18
|
+
*
|
|
19
|
+
* @see {@linkcode CreateThenableOptions}
|
|
20
|
+
* @see {@linkcode Executor}
|
|
21
|
+
* @see {@linkcode Thenable}
|
|
22
|
+
*
|
|
23
|
+
* @template {any} T
|
|
24
|
+
* The resolved value
|
|
25
|
+
* @template {any} [Reason=Error]
|
|
26
|
+
* The reason for a rejection
|
|
27
|
+
* @template {Thenable<T>} [Result=Thenable<T>]
|
|
28
|
+
* The thenable
|
|
29
|
+
*
|
|
30
|
+
* @this {void}
|
|
31
|
+
*
|
|
32
|
+
* @param {Executor<T, Reason>} executor
|
|
33
|
+
* The initialization callback
|
|
34
|
+
* @param {CreateThenableOptions | null | undefined} [options]
|
|
35
|
+
* Options for creating a thenable
|
|
36
|
+
* @return {Result}
|
|
37
|
+
* The thenable
|
|
38
|
+
*/
|
|
39
|
+
function createThenable(executor, options) {
|
|
40
|
+
/**
|
|
41
|
+
* Whether the thenable has been settled.
|
|
42
|
+
*
|
|
43
|
+
* @var {boolean} settled
|
|
44
|
+
*/
|
|
45
|
+
let settled = false;
|
|
46
|
+
/**
|
|
47
|
+
* The settled state.
|
|
48
|
+
*
|
|
49
|
+
* @var {State<T, Reason> | undefined} state
|
|
50
|
+
*/
|
|
51
|
+
let state;
|
|
52
|
+
try {
|
|
53
|
+
executor(ok, nok);
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
nok(e);
|
|
57
|
+
}
|
|
58
|
+
// executor neither resolved nor rejected, treat as `ok(undefined)`.
|
|
59
|
+
if (!state)
|
|
60
|
+
ok(undefined);
|
|
61
|
+
return wrapState(state);
|
|
62
|
+
/**
|
|
63
|
+
* Adopt an awaitable into a {@linkcode Thenable}.
|
|
64
|
+
*
|
|
65
|
+
* If `x` is a thenable, the returned thenable follows its settlement.
|
|
66
|
+
* Otherwise, the returned thenable is immediately resolved with `x`.
|
|
67
|
+
*
|
|
68
|
+
* @template {any} X
|
|
69
|
+
* The resolved value
|
|
70
|
+
*
|
|
71
|
+
* @this {void}
|
|
72
|
+
*
|
|
73
|
+
* @param {Awaitable<X>} x
|
|
74
|
+
* The awaitable to adopt
|
|
75
|
+
* @return {Thenable<X>}
|
|
76
|
+
* A thenable representing the adopted awaitable
|
|
77
|
+
*/
|
|
78
|
+
function adopt(x) {
|
|
79
|
+
if (isThenable(x)) {
|
|
80
|
+
// wrap foreign thenable so `then` still returns a thenable.
|
|
81
|
+
return addMethods({
|
|
82
|
+
/**
|
|
83
|
+
* @template {any} [Next=X]
|
|
84
|
+
* The next resolved value on success
|
|
85
|
+
* @template {any} [Failure=never]
|
|
86
|
+
* The next resolved value on failure
|
|
87
|
+
*
|
|
88
|
+
* @this {void}
|
|
89
|
+
*
|
|
90
|
+
* @param {OnFulfilled<X, Next> | null | undefined} [onfulfilled]
|
|
91
|
+
* The callback to execute when the thenable is resolved
|
|
92
|
+
* @param {OnRejected<Failure, Reason> | null | undefined} [onrejected]
|
|
93
|
+
* The callback to execute when the thenable is rejected
|
|
94
|
+
* @return {Thenable<Failure | Next>}
|
|
95
|
+
* The next thenable
|
|
96
|
+
*/
|
|
97
|
+
then(onfulfilled, onrejected) {
|
|
98
|
+
return adopt(x.then(
|
|
99
|
+
/**
|
|
100
|
+
* @this {void}
|
|
101
|
+
*
|
|
102
|
+
* @param {X} value
|
|
103
|
+
* The resolved value
|
|
104
|
+
* @return {Awaitable<Next>}
|
|
105
|
+
* The next awaitable
|
|
106
|
+
*/
|
|
107
|
+
function succ(value) {
|
|
108
|
+
return resolve(value, onfulfilled);
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* @this {void}
|
|
112
|
+
*
|
|
113
|
+
* @param {unknown} e
|
|
114
|
+
* The reason for the rejection
|
|
115
|
+
* @return {Awaitable<Failure>}
|
|
116
|
+
* The next awaitable
|
|
117
|
+
*/
|
|
118
|
+
function fail(e) {
|
|
119
|
+
return reject(e, onrejected);
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return wrapState({ ok: true, value: x });
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Add requested methods to a `thenable`.
|
|
128
|
+
*
|
|
129
|
+
* @template {any} U
|
|
130
|
+
* The resolved value
|
|
131
|
+
*
|
|
132
|
+
* @this {void}
|
|
133
|
+
*
|
|
134
|
+
* @param {Thenable<U>} thenable
|
|
135
|
+
* The current thenable
|
|
136
|
+
* @return {Thenable<U>}
|
|
137
|
+
* The `thenable`
|
|
138
|
+
*/
|
|
139
|
+
function addMethods(thenable) {
|
|
140
|
+
if (!options) {
|
|
141
|
+
thenable.catch = katch;
|
|
142
|
+
thenable.finally = finalize;
|
|
143
|
+
return thenable;
|
|
144
|
+
}
|
|
145
|
+
if (options.catch) {
|
|
146
|
+
thenable.catch = katch;
|
|
147
|
+
}
|
|
148
|
+
else if ('catch' in options && options.catch !== false) {
|
|
149
|
+
thenable.catch = options.catch;
|
|
150
|
+
}
|
|
151
|
+
if (options.finally) {
|
|
152
|
+
thenable.finally = finalize;
|
|
153
|
+
}
|
|
154
|
+
else if ('finally' in options && options.finally !== false) {
|
|
155
|
+
thenable.finally = options.finally;
|
|
156
|
+
}
|
|
157
|
+
return thenable;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Attach a callback that is invoked only when `this` thenable is settled.
|
|
161
|
+
*
|
|
162
|
+
* @template {any} U
|
|
163
|
+
* The resolved value
|
|
164
|
+
*
|
|
165
|
+
* @this {Thenable<U>}
|
|
166
|
+
*
|
|
167
|
+
* @param {OnFinally | null | undefined} [onfinally]
|
|
168
|
+
* The callback to execute when the thenable is settled
|
|
169
|
+
* @return {Thenable<U>}
|
|
170
|
+
* The next thenable
|
|
171
|
+
*/
|
|
172
|
+
function finalize(onfinally) {
|
|
173
|
+
return typeof onfinally === 'function' ? this.then(succ, fail) : this;
|
|
174
|
+
/**
|
|
175
|
+
* @this {void}
|
|
176
|
+
*
|
|
177
|
+
* @param {unknown} reason
|
|
178
|
+
* The reason for the rejection
|
|
179
|
+
* @return {never}
|
|
180
|
+
* Never; throws `reason`
|
|
181
|
+
* @throws {unknown}
|
|
182
|
+
*/
|
|
183
|
+
function fail(reason) {
|
|
184
|
+
void onfinally();
|
|
185
|
+
throw reason;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* @this {void}
|
|
189
|
+
*
|
|
190
|
+
* @param {U} value
|
|
191
|
+
* The resolved value
|
|
192
|
+
* @return {U}
|
|
193
|
+
* The resolved `value`
|
|
194
|
+
*/
|
|
195
|
+
function succ(value) {
|
|
196
|
+
return void onfinally(), value;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Attach a callback only for the rejection of `this` thenable.
|
|
201
|
+
*
|
|
202
|
+
* @template {any} U
|
|
203
|
+
* The resolved value
|
|
204
|
+
* @template {any} [Failure=never]
|
|
205
|
+
* The resolved value on failure
|
|
206
|
+
*
|
|
207
|
+
* @this {Thenable<U>}
|
|
208
|
+
*
|
|
209
|
+
* @param {OnRejected<Failure, Reason> | null | undefined} [onrejected]
|
|
210
|
+
* The callback to execute when the thenable is rejected
|
|
211
|
+
* @return {Thenable<Failure | U>}
|
|
212
|
+
* The next thenable
|
|
213
|
+
*/
|
|
214
|
+
function katch(onrejected) {
|
|
215
|
+
return this.then(null, onrejected);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Reject the thenable.
|
|
219
|
+
*
|
|
220
|
+
* @this {void}
|
|
221
|
+
*
|
|
222
|
+
* @param {Reason} reason
|
|
223
|
+
* The reason for the rejection
|
|
224
|
+
* @return {undefined}
|
|
225
|
+
*/
|
|
226
|
+
function nok(reason) {
|
|
227
|
+
return void (settled || (settled = true, state = { ok: false, reason }));
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Resolve the thenable.
|
|
231
|
+
*
|
|
232
|
+
* @this {void}
|
|
233
|
+
*
|
|
234
|
+
* @param {Awaitable<T>} value
|
|
235
|
+
* The awaitable
|
|
236
|
+
* @return {undefined}
|
|
237
|
+
*/
|
|
238
|
+
function ok(value) {
|
|
239
|
+
return void (settled || (settled = true, state = { ok: true, value }));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Handle a rejection.
|
|
243
|
+
*
|
|
244
|
+
* @template {any} T
|
|
245
|
+
* The next resolved value
|
|
246
|
+
*
|
|
247
|
+
* @this {void}
|
|
248
|
+
*
|
|
249
|
+
* @param {unknown} reason
|
|
250
|
+
* The reason for the rejection
|
|
251
|
+
* @param {OnRejected<T, Reason> | null | undefined} [onrejected]
|
|
252
|
+
* The callback to execute when the thenable is rejected
|
|
253
|
+
* @return {Awaitable<T>}
|
|
254
|
+
* The next awaitable
|
|
255
|
+
*/
|
|
256
|
+
function reject(reason, onrejected) {
|
|
257
|
+
if (typeof onrejected === 'function')
|
|
258
|
+
return onrejected(reason);
|
|
259
|
+
return wrapState({ ok: false, reason: reason });
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Handle a resolved `value`.
|
|
263
|
+
*
|
|
264
|
+
* @template {any} T
|
|
265
|
+
* The resolved value
|
|
266
|
+
* @template {any} Next
|
|
267
|
+
* The next resolved value
|
|
268
|
+
* @this {void}
|
|
269
|
+
*
|
|
270
|
+
* @param {T} value
|
|
271
|
+
* The resolved value
|
|
272
|
+
* @return {Awaitable<Next>}
|
|
273
|
+
* The next awaitable
|
|
274
|
+
*/
|
|
275
|
+
function resolve(value, onfulfilled) {
|
|
276
|
+
if (typeof onfulfilled === 'function')
|
|
277
|
+
return onfulfilled(value);
|
|
278
|
+
return value;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Wrap a settled state into a {@linkcode Thenable}.
|
|
282
|
+
*
|
|
283
|
+
* @template {any} S
|
|
284
|
+
* The resolved value
|
|
285
|
+
*
|
|
286
|
+
* @this {void}
|
|
287
|
+
*
|
|
288
|
+
* @param {State} s
|
|
289
|
+
* The settled state
|
|
290
|
+
* @return {Thenable<S>}
|
|
291
|
+
* A thenable representing the settled state
|
|
292
|
+
*/
|
|
293
|
+
function wrapState(s) {
|
|
294
|
+
return addMethods({
|
|
295
|
+
/**
|
|
296
|
+
* @template {any} [Next=S]
|
|
297
|
+
* The next resolved value on success
|
|
298
|
+
* @template {any} [Failure=never]
|
|
299
|
+
* The next resolved value on failure
|
|
300
|
+
*
|
|
301
|
+
* @this {void}
|
|
302
|
+
*
|
|
303
|
+
* @param {OnFulfilled<S, Next> | null | undefined} [onfulfilled]
|
|
304
|
+
* The callback to execute when the thenable is resolved
|
|
305
|
+
* @param {OnRejected<Failure, Reason> | null | undefined} [onrejected]
|
|
306
|
+
* The callback to execute when the thenable is rejected
|
|
307
|
+
* @return {Thenable<Failure | Next>}
|
|
308
|
+
* The next thenable
|
|
309
|
+
*/
|
|
310
|
+
then(onfulfilled, onrejected) {
|
|
311
|
+
try {
|
|
312
|
+
if (s.ok) {
|
|
313
|
+
if (isThenable(s.value))
|
|
314
|
+
return adopt(s.value).then(succ, fail);
|
|
315
|
+
return adopt(succ(s.value));
|
|
316
|
+
/**
|
|
317
|
+
* @this {void}
|
|
318
|
+
*
|
|
319
|
+
* @param {S} value
|
|
320
|
+
* The resolved value
|
|
321
|
+
* @return {Awaitable<Next>}
|
|
322
|
+
* The next awaitable
|
|
323
|
+
*/
|
|
324
|
+
function succ(value) {
|
|
325
|
+
return resolve(value, onfulfilled);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// rejected.
|
|
329
|
+
if (typeof onrejected === 'function')
|
|
330
|
+
return adopt(fail(s.reason));
|
|
331
|
+
return wrapState({ ok: false, reason: s.reason });
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
return wrapState({ ok: false, reason: e });
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* @this {void}
|
|
338
|
+
*
|
|
339
|
+
* @param {unknown} e
|
|
340
|
+
* The reason for the rejection
|
|
341
|
+
* @return {Awaitable<Failure>}
|
|
342
|
+
* The next awaitable
|
|
343
|
+
*/
|
|
344
|
+
function fail(e) {
|
|
345
|
+
return reject(e, onrejected);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|