@flex-development/when 1.0.0 → 2.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 +17 -0
- package/README.md +221 -97
- package/dist/index.d.mts +135 -44
- package/dist/lib/index.mjs +1 -0
- package/dist/lib/is-promise.mjs +31 -0
- package/dist/lib/is-thenable.mjs +9 -7
- package/dist/lib/when.mjs +35 -16
- package/package.json +13 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## [2.0.0](https://github.com/flex-development/when/compare/1.0.0...2.0.0) (2026-02-19)
|
|
2
|
+
|
|
3
|
+
### ⚠ BREAKING CHANGES
|
|
4
|
+
|
|
5
|
+
- `catch` support
|
|
6
|
+
|
|
7
|
+
### :package: Build
|
|
8
|
+
|
|
9
|
+
- [[`dd93b19`](https://github.com/flex-development/when/commit/dd93b19904b21760b5ae86a48fe7b7127adbcf95)] **deps-dev:** Bump @commitlint/cli from 20.4.1 to 20.4.2 in the commitlint group ([#9](https://github.com/flex-development/when/issues/9))
|
|
10
|
+
- [[`9229069`](https://github.com/flex-development/when/commit/9229069b28f05bf3394c29d85ec3261c6246959b)] **deps-dev:** Bump happy-dom from 20.6.2 to 20.6.3 ([#10](https://github.com/flex-development/when/issues/10))
|
|
11
|
+
|
|
12
|
+
### :sparkles: Features
|
|
13
|
+
|
|
14
|
+
- [[`8d8f17f`](https://github.com/flex-development/when/commit/8d8f17f847ac90d5633d87c554229bbd42d9a1cf)] `catch` support
|
|
15
|
+
- [[`003be0f`](https://github.com/flex-development/when/commit/003be0f34d1e626b0ee6ea940d73f0babd12df78)] **lib:** `isPromise`
|
|
16
|
+
|
|
1
17
|
## 1.0.0 (2026-02-18)
|
|
2
18
|
|
|
3
19
|
### :package: Build
|
|
@@ -71,3 +87,4 @@
|
|
|
71
87
|
|
|
72
88
|
|
|
73
89
|
|
|
90
|
+
|
package/README.md
CHANGED
|
@@ -17,44 +17,72 @@ like `.then`, but for synchronous values *and* thenables.
|
|
|
17
17
|
## Contents
|
|
18
18
|
|
|
19
19
|
- [What is this?](#what-is-this)
|
|
20
|
+
- [When should I use this?](#when-should-i-use-this)
|
|
20
21
|
- [Why not `Promise.resolve`?](#why-not-promiseresolve)
|
|
22
|
+
- [Design guarantees](#design-guarantees)
|
|
21
23
|
- [Install](#install)
|
|
22
24
|
- [Use](#use)
|
|
23
25
|
- [Chain a synchronous value](#chain-a-synchronous-value)
|
|
24
26
|
- [Chain a *thenable*](#chain-a-thenable)
|
|
25
27
|
- [Pass arguments to the chain callback](#pass-arguments-to-the-chain-callback)
|
|
26
|
-
- [Handle
|
|
28
|
+
- [Handle failures](#handle-failures)
|
|
27
29
|
- [Bind `this` context](#bind-this-context)
|
|
28
30
|
- [Use an options object](#use-an-options-object)
|
|
29
31
|
- [API](#api)
|
|
32
|
+
- [`isPromise<T>(value)`][ispromise]
|
|
30
33
|
- [`isThenable<T>(value)`][isthenable]
|
|
31
|
-
- [`when<
|
|
34
|
+
- [`when<T[, Next][, Failure][, Args][, Error][, This]>(value, chain[, reject][, context][, ...args])`][when]
|
|
32
35
|
- [Types](#types)
|
|
33
36
|
- [`Awaitable<T>`][awaitable]
|
|
34
|
-
- [`Chain<[T][, Next][, Args][,
|
|
35
|
-
- [`
|
|
36
|
-
- [`
|
|
37
|
+
- [`Chain<[T][, Next][, Args][, This]>`][chain]
|
|
38
|
+
- [`Fail<[Next][, Error][, This]>`][fail]
|
|
39
|
+
- [`Options<[T][, Next][, Failure][, Args][, Error][, This]>`][options]
|
|
37
40
|
- [Glossary](#glossary)
|
|
38
41
|
- [Project](#project)
|
|
39
42
|
- [Version](#version)
|
|
40
43
|
- [Contribute](#contribute)
|
|
44
|
+
- [Sponsor](#sponsor)
|
|
41
45
|
|
|
42
46
|
## What is this?
|
|
43
47
|
|
|
44
|
-
`when` is a
|
|
45
|
-
onto
|
|
48
|
+
`when` is a tiny primitive for chaining callbacks
|
|
49
|
+
onto [awaitables][awaitable] (synchronous or [*thenable*][thenable] values).
|
|
46
50
|
|
|
47
|
-
For thenable values,
|
|
48
|
-
|
|
49
|
-
This makes it easy to write one code path that supports both synchronous and asynchronous values.
|
|
51
|
+
For thenable values, `then` is used to invoke the callback after resolution. Otherwise, the callback fires immediately.
|
|
52
|
+
This makes it easy to write one code path that supports both synchronous values and promises.
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
loaders, or resolvers that may or may not return promises.
|
|
54
|
+
## When should I use this?
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
`when` is especially useful in libraries implementing awaitable APIs.
|
|
55
57
|
|
|
56
|
-
`
|
|
57
|
-
|
|
58
|
+
It provides [`Promise.then`][promise-then] semantics without forcing [`Promise.resolve`][promise-resolve],
|
|
59
|
+
preserving synchronous execution whenever possible.
|
|
60
|
+
|
|
61
|
+
Typical use cases include plugin systems, hook pipelines, module resolvers, data loaders, and file system adapters where
|
|
62
|
+
users may return both synchronous or asynchronous values.
|
|
63
|
+
|
|
64
|
+
If you're only dealing with promises and thenables, consider using native `async/await` or `Promise` chaining instead.
|
|
65
|
+
|
|
66
|
+
### Why not [`Promise.resolve`][promise-resolve]?
|
|
67
|
+
|
|
68
|
+
`when` preserves synchronous operations whenever possible,
|
|
69
|
+
avoiding unnecessary promise allocation and microtask scheduling.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
Promise.resolve(value).then(fn) // always a promise
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
when(value, fn) // only a promise if `value` is a thenable, or `fn` returns one
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Design guarantees
|
|
80
|
+
|
|
81
|
+
- Synchronous values remain synchronous
|
|
82
|
+
- [*Thenable*s][thenable] are chained without wrapping in [`Promise.resolve`][promise-resolve]
|
|
83
|
+
- No additional microtasks are scheduled for non-thenables
|
|
84
|
+
- Failures propagate unless a `fail` handler is provided
|
|
85
|
+
- Returned thenables are preserved without additional wrapping
|
|
58
86
|
|
|
59
87
|
## Install
|
|
60
88
|
|
|
@@ -125,7 +153,7 @@ console.dir(await result) // 3
|
|
|
125
153
|
|
|
126
154
|
### Pass arguments to the chain callback
|
|
127
155
|
|
|
128
|
-
|
|
156
|
+
When arguments are provided, they are passed to the `chain` callback first, followed by the resolved value.
|
|
129
157
|
|
|
130
158
|
When the `value` passed to `when` is not [*thenable*][thenable], the resolved value is the same `value`.
|
|
131
159
|
|
|
@@ -137,12 +165,23 @@ import when, { type Awaitable } from '@flex-development/when'
|
|
|
137
165
|
*
|
|
138
166
|
* @const {Awaitable<number>} result
|
|
139
167
|
*/
|
|
140
|
-
const result: Awaitable<number> = when(
|
|
168
|
+
const result: Awaitable<number> = when(
|
|
169
|
+
1, // last argument passed to `Math.min`
|
|
170
|
+
Math.min, // `chain`
|
|
171
|
+
null, // `fail`
|
|
172
|
+
undefined, // `context`
|
|
173
|
+
2, // first argument passed to `Math.min`
|
|
174
|
+
3, // second argument passed to `Math.min`
|
|
175
|
+
4 // third argument passed to `Math.min`
|
|
176
|
+
)
|
|
141
177
|
|
|
142
178
|
console.dir(result) // 1
|
|
143
179
|
```
|
|
144
180
|
|
|
145
|
-
### Handle
|
|
181
|
+
### Handle failures
|
|
182
|
+
|
|
183
|
+
For [*thenable*s][thenable], the `fail` callback is passed to `then` as the `onrejected` parameter,
|
|
184
|
+
and if implemented, to `catch` as well to prevent unhandled rejections.
|
|
146
185
|
|
|
147
186
|
```ts
|
|
148
187
|
import when, { type Awaitable } from '@flex-development/when'
|
|
@@ -161,7 +200,7 @@ const value: PromiseLike<never> = new Promise((resolve, reject) => {
|
|
|
161
200
|
*
|
|
162
201
|
* @const {Awaitable<boolean>} result
|
|
163
202
|
*/
|
|
164
|
-
const result: Awaitable<boolean> = when(value, chain,
|
|
203
|
+
const result: Awaitable<boolean> = when(value, chain, fail)
|
|
165
204
|
|
|
166
205
|
console.dir(await result) // false
|
|
167
206
|
|
|
@@ -183,7 +222,7 @@ function chain(this: void): true {
|
|
|
183
222
|
* @return {false}
|
|
184
223
|
* The failure result
|
|
185
224
|
*/
|
|
186
|
-
function
|
|
225
|
+
function fail(this: void, e: Error): false {
|
|
187
226
|
return console.dir(e), false
|
|
188
227
|
}
|
|
189
228
|
```
|
|
@@ -246,7 +285,7 @@ const result: Awaitable<number | undefined> = when(value, {
|
|
|
246
285
|
args: [39],
|
|
247
286
|
chain: divide,
|
|
248
287
|
context: { errors: [] },
|
|
249
|
-
|
|
288
|
+
fail
|
|
250
289
|
})
|
|
251
290
|
|
|
252
291
|
console.dir(await result) // 13
|
|
@@ -272,7 +311,7 @@ function divide(this: void, dividend: number, divisor: number): number {
|
|
|
272
311
|
* The error to handle
|
|
273
312
|
* @return {undefined}
|
|
274
313
|
*/
|
|
275
|
-
function
|
|
314
|
+
function fail(this: Context, e: Error): undefined {
|
|
276
315
|
return void this.errors.push(e)
|
|
277
316
|
}
|
|
278
317
|
```
|
|
@@ -283,9 +322,31 @@ function reject(this: Context, e: Error): undefined {
|
|
|
283
322
|
|
|
284
323
|
The default export is [`when`][when].
|
|
285
324
|
|
|
325
|
+
### `isPromise<T>(value)`
|
|
326
|
+
|
|
327
|
+
Check if `value` looks like a `Promise`.
|
|
328
|
+
|
|
329
|
+
> 👉 **Note**: This function intentionally performs a structural check instead of a brand check.
|
|
330
|
+
> It does not rely on `instanceof Promise` or constructors, making it compatible with cross-realm promises
|
|
331
|
+
> and custom thenables.
|
|
332
|
+
|
|
333
|
+
#### Type Parameters
|
|
334
|
+
|
|
335
|
+
- `T` (`any`)
|
|
336
|
+
— the resolved value
|
|
337
|
+
|
|
338
|
+
#### Parameters
|
|
339
|
+
|
|
340
|
+
- `value` (`unknown`)
|
|
341
|
+
— the thing to check
|
|
342
|
+
|
|
343
|
+
#### Returns
|
|
344
|
+
|
|
345
|
+
(`value is Promise<T>`) `true` if `value` is a [*thenable*][thenable] with a `catch` method, `false` otherwise
|
|
346
|
+
|
|
286
347
|
### `isThenable<T>(value)`
|
|
287
348
|
|
|
288
|
-
Check if `value` looks like a [*thenable*][thenable].
|
|
349
|
+
Check if `value` looks like a [*thenable*][thenable], i.e. a `PromiseLike` object.
|
|
289
350
|
|
|
290
351
|
> 👉 **Note**: Also exported as `isPromiseLike`.
|
|
291
352
|
|
|
@@ -301,15 +362,16 @@ Check if `value` looks like a [*thenable*][thenable].
|
|
|
301
362
|
|
|
302
363
|
#### Returns
|
|
303
364
|
|
|
304
|
-
(`value is PromiseLike<T>`) `true` if `value` is a
|
|
365
|
+
(`value is PromiseLike<T>`) `true` if `value` is an object or function with a `then` method, `false` otherwise
|
|
305
366
|
|
|
306
367
|
<!--lint disable-->
|
|
307
368
|
|
|
308
|
-
### `when<
|
|
369
|
+
### `when<T[, Next][, Failure][, Args][, Error][, This]>(value, chain[, fail][, context][, ...args])`
|
|
309
370
|
|
|
310
371
|
<!--lint enable-->
|
|
311
372
|
|
|
312
|
-
Chain a callback, calling the function after `value` is resolved,
|
|
373
|
+
Chain a callback, calling the function after `value` is resolved,
|
|
374
|
+
or immediately if `value` is not a [*thenable*][thenable].
|
|
313
375
|
|
|
314
376
|
#### Overloads
|
|
315
377
|
|
|
@@ -318,13 +380,13 @@ function when<
|
|
|
318
380
|
T,
|
|
319
381
|
Next = any,
|
|
320
382
|
Args extends any[] = any[],
|
|
321
|
-
|
|
383
|
+
This = unknown
|
|
322
384
|
>(
|
|
323
385
|
this: void,
|
|
324
386
|
value: Awaitable<T>,
|
|
325
|
-
chain: Chain<T, Next, Args,
|
|
326
|
-
|
|
327
|
-
context?:
|
|
387
|
+
chain: Chain<T, Next, Args, This>,
|
|
388
|
+
fail?: null | undefined,
|
|
389
|
+
context?: This | null | undefined,
|
|
328
390
|
...args: Args
|
|
329
391
|
): Awaitable<Next>
|
|
330
392
|
```
|
|
@@ -333,13 +395,33 @@ function when<
|
|
|
333
395
|
function when<
|
|
334
396
|
T,
|
|
335
397
|
Next = any,
|
|
398
|
+
Failure = Next,
|
|
336
399
|
Args extends any[] = any[],
|
|
337
|
-
|
|
400
|
+
Error = any,
|
|
401
|
+
This = unknown
|
|
338
402
|
>(
|
|
339
403
|
this: void,
|
|
340
404
|
value: Awaitable<T>,
|
|
341
|
-
chain:
|
|
342
|
-
|
|
405
|
+
chain: Chain<T, Next, Args, This>,
|
|
406
|
+
fail?: Fail<Failure, Error, This> | null | undefined,
|
|
407
|
+
context?: This | null | undefined,
|
|
408
|
+
...args: Args
|
|
409
|
+
): Awaitable<Failure | Next>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
function when<
|
|
414
|
+
T,
|
|
415
|
+
Next = any,
|
|
416
|
+
Failure = Next,
|
|
417
|
+
Args extends any[] = any[],
|
|
418
|
+
Error = any,
|
|
419
|
+
This = unknown
|
|
420
|
+
>(
|
|
421
|
+
this: void,
|
|
422
|
+
value: Awaitable<T>,
|
|
423
|
+
chain: Options<T, Next, Failure, Args, Error, This>
|
|
424
|
+
): Awaitable<Failure | Next>
|
|
343
425
|
```
|
|
344
426
|
|
|
345
427
|
#### Type Parameters
|
|
@@ -349,29 +431,41 @@ function when<
|
|
|
349
431
|
- `Next` (`any`, optional)
|
|
350
432
|
— the next resolved value
|
|
351
433
|
- **default**: `any`
|
|
434
|
+
- `Failure` (`any`, optional)
|
|
435
|
+
— the next resolved value on failure
|
|
436
|
+
- **default**: `Next`
|
|
352
437
|
- `Args` (`readonly any[]`, optional)
|
|
353
|
-
— the function arguments
|
|
438
|
+
— the chain function arguments
|
|
354
439
|
- **default**: `any[]`
|
|
355
|
-
- `
|
|
440
|
+
- `Error` (`any`, optional)
|
|
441
|
+
— the error to possibly handle
|
|
442
|
+
- **default**: `any`
|
|
443
|
+
- `This` (`any`, optional)
|
|
356
444
|
— the `this` context
|
|
357
445
|
- **default**: `unknown`
|
|
358
446
|
|
|
359
447
|
#### Parameters
|
|
360
448
|
|
|
361
449
|
- `value` ([`Awaitable<T>`][awaitable])
|
|
362
|
-
— the
|
|
363
|
-
- `chain` ([`Chain<T, Next, Args,
|
|
450
|
+
— the current [*awaitable*][awaitable-term]
|
|
451
|
+
- `chain` ([`Chain<T, Next, Args, This>`][chain] | [`Options<T, Next, Failure, Args, Error, This>`][options])
|
|
364
452
|
— the chain callback or options for chaining
|
|
365
|
-
- `
|
|
366
|
-
— the callback to fire when a
|
|
367
|
-
-
|
|
368
|
-
|
|
453
|
+
- `fail` ([`Fail<Failure, Error, This>`][fail] | `null` | `undefined`)
|
|
454
|
+
— the callback to fire when a failure occurs. failures include:
|
|
455
|
+
- rejections of the input [*thenable*][thenable]
|
|
456
|
+
- rejections returned from `chain`
|
|
457
|
+
- synchronous errors thrown in `chain`\
|
|
458
|
+
if no `fail` handler is provided, failures are re-thrown or re-propagated.
|
|
459
|
+
> 👉 **note**: for thenables, this callback is passed to `then` as the `onrejected` parameter,
|
|
460
|
+
> and if implemented, to `catch` as well to prevent unhandled rejections.
|
|
461
|
+
- `context` (`This` | `null` | `undefined`)
|
|
462
|
+
— the `this` context of the chain and `fail` callbacks
|
|
369
463
|
- `...args` (`Args`)
|
|
370
464
|
— the arguments to pass to the chain callback
|
|
371
465
|
|
|
372
466
|
#### Returns
|
|
373
467
|
|
|
374
|
-
([`Awaitable<Next>`][awaitable]) The next
|
|
468
|
+
([`Awaitable<Failure | Next>`][awaitable] | [`Awaitable<Next>`][awaitable]) The next [*awaitable*][awaitable-term]
|
|
375
469
|
|
|
376
470
|
## Types
|
|
377
471
|
|
|
@@ -390,7 +484,7 @@ type Awaitable<T> = PromiseLike<T> | T
|
|
|
390
484
|
- `T` (`any`)
|
|
391
485
|
— the resolved value
|
|
392
486
|
|
|
393
|
-
### `Chain<[T][, Next][, Args][,
|
|
487
|
+
### `Chain<[T][, Next][, Args][, This]>`
|
|
394
488
|
|
|
395
489
|
A chain callback (`type`).
|
|
396
490
|
|
|
@@ -399,8 +493,8 @@ type Chain<
|
|
|
399
493
|
T = any,
|
|
400
494
|
Next = any,
|
|
401
495
|
Args extends readonly any[] = any[],
|
|
402
|
-
|
|
403
|
-
> = (this:
|
|
496
|
+
This = unknown
|
|
497
|
+
> = (this: This, ...params: [...Args, T]) => Awaitable<Next>
|
|
404
498
|
```
|
|
405
499
|
|
|
406
500
|
#### Type Parameters
|
|
@@ -414,93 +508,107 @@ type Chain<
|
|
|
414
508
|
- `Args` (`readonly any[]`, optional)
|
|
415
509
|
— the function arguments
|
|
416
510
|
- **default**: `any[]`
|
|
417
|
-
- `
|
|
511
|
+
- `This` (`any`, optional)
|
|
418
512
|
— the `this` context
|
|
419
513
|
- **default**: `unknown`
|
|
420
514
|
|
|
421
515
|
#### Parameters
|
|
422
516
|
|
|
423
|
-
- **`this`** (`
|
|
517
|
+
- **`this`** (`This`)
|
|
424
518
|
- `...params` (`[...Args, T]`)
|
|
425
519
|
— the function parameters, with the last being the previously resolved value.
|
|
426
520
|
in cases where a promise is not being resolved, this is the same `value` passed to `when`
|
|
427
521
|
|
|
428
522
|
#### Returns
|
|
429
523
|
|
|
430
|
-
([`Awaitable<Next>`][awaitable]) The next
|
|
524
|
+
([`Awaitable<Next>`][awaitable]) The next [*awaitable*][awaitable-term]
|
|
431
525
|
|
|
432
|
-
### `
|
|
526
|
+
### `Fail<[Next][, Error][, This]>`
|
|
433
527
|
|
|
434
|
-
|
|
528
|
+
The callback to fire when a failure occurs (`type`).
|
|
435
529
|
|
|
436
530
|
```ts
|
|
437
|
-
|
|
438
|
-
T = any,
|
|
531
|
+
type Fail<
|
|
439
532
|
Next = any,
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
>
|
|
533
|
+
Error = any,
|
|
534
|
+
This = unknown
|
|
535
|
+
> = (this: This, e: Error) => Awaitable<Next>
|
|
443
536
|
```
|
|
444
537
|
|
|
445
538
|
#### Type Parameters
|
|
446
539
|
|
|
447
|
-
- `T` (`any`, optional)
|
|
448
|
-
— the previously resolved value
|
|
449
|
-
- **default**: `any`
|
|
450
540
|
- `Next` (`any`, optional)
|
|
451
541
|
— the next resolved value
|
|
452
542
|
- **default**: `any`
|
|
453
|
-
- `
|
|
454
|
-
— the
|
|
455
|
-
- **default**: `any[]`
|
|
456
|
-
- `Self` (`any`, optional)
|
|
457
|
-
— the `this` context
|
|
543
|
+
- `Error` (`any`, optional)
|
|
544
|
+
— the error to handle
|
|
458
545
|
- **default**: `any`
|
|
546
|
+
- `This` (`any`, optional)
|
|
547
|
+
— the `this` context
|
|
548
|
+
- **default**: `unknown`
|
|
459
549
|
|
|
460
|
-
####
|
|
550
|
+
#### Parameters
|
|
461
551
|
|
|
462
|
-
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
— the callback to fire when a promise is rejected or an error is thrown
|
|
552
|
+
- **`this`** (`This`)
|
|
553
|
+
- `e` (`Error`)
|
|
554
|
+
— the error
|
|
555
|
+
|
|
556
|
+
#### Returns
|
|
557
|
+
|
|
558
|
+
([`Awaitable<Next>`][awaitable]) The next [*awaitable*][awaitable-term]
|
|
470
559
|
|
|
471
|
-
### `
|
|
560
|
+
### `Options<[T][, Next][, Failure][, Args][, Error][, This]>`
|
|
472
561
|
|
|
473
|
-
|
|
562
|
+
Options for chaining (`interface`).
|
|
474
563
|
|
|
475
564
|
```ts
|
|
476
|
-
|
|
565
|
+
interface Options<
|
|
566
|
+
T = any,
|
|
477
567
|
Next = any,
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
568
|
+
Failure = Next,
|
|
569
|
+
Args extends readonly any[] = any[],
|
|
570
|
+
Error = any,
|
|
571
|
+
This = any
|
|
572
|
+
> { /* ... */ }
|
|
481
573
|
```
|
|
482
574
|
|
|
483
575
|
#### Type Parameters
|
|
484
576
|
|
|
577
|
+
- `T` (`any`, optional)
|
|
578
|
+
— the previously resolved value
|
|
579
|
+
- **default**: `any`
|
|
485
580
|
- `Next` (`any`, optional)
|
|
486
581
|
— the next resolved value
|
|
487
582
|
- **default**: `any`
|
|
488
|
-
- `
|
|
489
|
-
— the
|
|
583
|
+
- `Failure` (`any`, optional)
|
|
584
|
+
— the next resolved value on failure
|
|
585
|
+
- **default**: `Next`
|
|
586
|
+
- `Args` (`readonly any[]`, optional)
|
|
587
|
+
— the chain function arguments
|
|
588
|
+
- **default**: `any[]`
|
|
589
|
+
- `Error` (`any`, optional)
|
|
590
|
+
— the error to possibly handle
|
|
490
591
|
- **default**: `any`
|
|
491
|
-
- `
|
|
592
|
+
- `This` (`any`, optional)
|
|
492
593
|
— the `this` context
|
|
493
|
-
- **default**: `
|
|
494
|
-
|
|
495
|
-
#### Parameters
|
|
496
|
-
|
|
497
|
-
- **`this`** (`Self`)
|
|
498
|
-
- `e` (`Fail`)
|
|
499
|
-
— the error
|
|
594
|
+
- **default**: `any`
|
|
500
595
|
|
|
501
|
-
####
|
|
596
|
+
#### Properties
|
|
502
597
|
|
|
503
|
-
(
|
|
598
|
+
- `args?` (`Args` | `null` | `undefined`)
|
|
599
|
+
— the arguments to pass to the `chain` callback
|
|
600
|
+
- `chain` ([`Chain<T, Next, Args, This>`][chain])
|
|
601
|
+
— the chain callback
|
|
602
|
+
- `context?` (`This` | `null` | `undefined`)
|
|
603
|
+
— the `this` context of the `chain` and `fail` callbacks
|
|
604
|
+
- `fail?` ([`Fail<Next, Error, This>`][fail] | `null` | `undefined`)
|
|
605
|
+
— the callback to fire when a failure occurs. failures include:
|
|
606
|
+
- rejections of the input [*thenable*][thenable]
|
|
607
|
+
- rejections returned from `chain`
|
|
608
|
+
- synchronous errors thrown in `chain`\
|
|
609
|
+
if no `fail` handler is provided, failures are re-thrown or re-propagated.
|
|
610
|
+
> 👉 **note**: for thenables, this callback is passed to `then` as the `onrejected` parameter,
|
|
611
|
+
> and if implemented, to `catch` as well to prevent unhandled rejections.
|
|
504
612
|
|
|
505
613
|
## Glossary
|
|
506
614
|
|
|
@@ -510,11 +618,14 @@ A synchronous or [*thenable*][thenable] value.
|
|
|
510
618
|
|
|
511
619
|
### *thenable*
|
|
512
620
|
|
|
513
|
-
An object or function with a
|
|
621
|
+
An object or function with a `then` method.
|
|
514
622
|
|
|
515
623
|
JavaScript engines use duck-typing for promises.
|
|
516
|
-
|
|
517
|
-
like [`Promise.resolve`][promise-resolve] and the [`await` keyword][await] like native promises.
|
|
624
|
+
Arrays, functions, and objects with a `then` method will be treated as promise-like objects, and work with built-in
|
|
625
|
+
mechanisms like [`Promise.resolve`][promise-resolve] and the [`await` keyword][await] like native promises.
|
|
626
|
+
|
|
627
|
+
Some thenables also implement a `catch` method (like native promises).
|
|
628
|
+
When available, `when` uses it to ensure rejections are handled.
|
|
518
629
|
|
|
519
630
|
## Project
|
|
520
631
|
|
|
@@ -529,23 +640,36 @@ See [`CONTRIBUTING.md`](CONTRIBUTING.md).
|
|
|
529
640
|
This project has a [code of conduct](./CODE_OF_CONDUCT.md).
|
|
530
641
|
By interacting with this repository, organization, or community you agree to abide by its terms.
|
|
531
642
|
|
|
643
|
+
### Sponsor
|
|
644
|
+
|
|
645
|
+
This package is intentionally small — and intentionally maintained.
|
|
646
|
+
|
|
647
|
+
Small primitives power larger systems.
|
|
648
|
+
Support long-term stability by sponsoring Flex Development.
|
|
649
|
+
|
|
532
650
|
[await]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/await
|
|
533
651
|
|
|
652
|
+
[awaitable-term]: #awaitable
|
|
653
|
+
|
|
534
654
|
[awaitable]: #awaitablet
|
|
535
655
|
|
|
536
|
-
[chain]: #chaint-next-args-
|
|
656
|
+
[chain]: #chaint-next-args-this
|
|
537
657
|
|
|
538
658
|
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
|
|
539
659
|
|
|
540
660
|
[esmsh]: https://esm.sh
|
|
541
661
|
|
|
662
|
+
[fail]: #failnext-error-this
|
|
663
|
+
|
|
664
|
+
[ispromise]: #ispromisetvalue
|
|
665
|
+
|
|
542
666
|
[isthenable]: #isthenabletvalue
|
|
543
667
|
|
|
544
|
-
[options]: #optionst-next-args-
|
|
668
|
+
[options]: #optionst-next-failure-args-error-this
|
|
545
669
|
|
|
546
670
|
[promise-resolve]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
|
|
547
671
|
|
|
548
|
-
[
|
|
672
|
+
[promise-then]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
|
|
549
673
|
|
|
550
674
|
[semver]: https://semver.org
|
|
551
675
|
|
|
@@ -553,6 +677,6 @@ By interacting with this repository, organization, or community you agree to abi
|
|
|
553
677
|
|
|
554
678
|
[typescript]: https://www.typescriptlang.org
|
|
555
679
|
|
|
556
|
-
[when]: #whent-next-args-
|
|
680
|
+
[when]: #whent-next-failure-args-error-thisvalue-chain-fail-context-args
|
|
557
681
|
|
|
558
682
|
[yarn]: https://yarnpkg.com
|
package/dist/index.d.mts
CHANGED
|
@@ -10,12 +10,16 @@
|
|
|
10
10
|
* The previously resolved value
|
|
11
11
|
* @template {any} [Next=any]
|
|
12
12
|
* The next resolved value
|
|
13
|
+
* @template {any} [Failure=Next]
|
|
14
|
+
* The next resolved value on failure
|
|
13
15
|
* @template {ReadonlyArray<any>} [Args=any[]]
|
|
14
16
|
* The chain function arguments
|
|
15
|
-
* @template {any} [
|
|
17
|
+
* @template {any} [Error=any]
|
|
18
|
+
* The error to possibly handle
|
|
19
|
+
* @template {any} [This=any]
|
|
16
20
|
* The `this` context
|
|
17
21
|
*/
|
|
18
|
-
interface Options<T = any, Next = any, Args extends readonly any[] = any[],
|
|
22
|
+
interface Options<T = any, Next = any, Failure = Next, Args extends readonly any[] = any[], Error = any, This = any> {
|
|
19
23
|
/**
|
|
20
24
|
* The arguments to pass to the {@linkcode chain} callback.
|
|
21
25
|
*/
|
|
@@ -23,28 +27,74 @@ interface Options<T = any, Next = any, Args extends readonly any[] = any[], Self
|
|
|
23
27
|
/**
|
|
24
28
|
* The chain callback.
|
|
25
29
|
*
|
|
30
|
+
* > 👉 **Note**: For thenables, this callback is passed to `then` as
|
|
31
|
+
* > the `onfulfilled` parameter.
|
|
32
|
+
*
|
|
26
33
|
* @see {@linkcode Chain}
|
|
34
|
+
* @see {@linkcode PromiseLike.then}
|
|
27
35
|
*/
|
|
28
|
-
chain: Chain<T, Next, Args,
|
|
36
|
+
chain: Chain<T, Next, Args, This>;
|
|
29
37
|
/**
|
|
30
|
-
* The `this` context of the {@linkcode chain}
|
|
31
|
-
* and {@linkcode reject} callbacks.
|
|
38
|
+
* The `this` context of the {@linkcode chain} and {@linkcode fail} callbacks.
|
|
32
39
|
*/
|
|
33
|
-
context?:
|
|
40
|
+
context?: This | null | undefined;
|
|
34
41
|
/**
|
|
35
|
-
* The callback to fire when a
|
|
42
|
+
* The callback to fire when a failure occurs.
|
|
43
|
+
*
|
|
44
|
+
* Failures include:
|
|
45
|
+
*
|
|
46
|
+
* - Rejections of the input thenable
|
|
47
|
+
* - Rejections returned from {@linkcode chain}
|
|
48
|
+
* - Synchronous errors thrown in {@linkcode chain}
|
|
49
|
+
*
|
|
50
|
+
* If no `fail` handler is provided, failures are re-thrown or re-propagated.
|
|
51
|
+
*
|
|
52
|
+
* > 👉 **Note**: For thenables, this callback is passed to `then` as
|
|
53
|
+
* > the `onrejected` parameter, and if implemented, to `catch` as well
|
|
54
|
+
* > to prevent unhandled rejections.
|
|
55
|
+
*
|
|
56
|
+
* @see {@linkcode Fail}
|
|
57
|
+
* @see {@linkcode Promise.catch}
|
|
58
|
+
* @see {@linkcode PromiseLike.then}
|
|
36
59
|
*
|
|
37
|
-
* @
|
|
60
|
+
* @since 2.0.0
|
|
38
61
|
*/
|
|
39
|
-
|
|
62
|
+
fail?: Fail<Failure, Error, This> | null | undefined;
|
|
40
63
|
}
|
|
41
64
|
|
|
65
|
+
/**
|
|
66
|
+
* @file isPromise
|
|
67
|
+
* @module when/lib/isPromise
|
|
68
|
+
*/
|
|
69
|
+
/**
|
|
70
|
+
* Check if `value` looks like a {@linkcode Promise}.
|
|
71
|
+
*
|
|
72
|
+
* > 👉 **Note**: This function intentionally performs a structural check
|
|
73
|
+
* > instead of a brand check.
|
|
74
|
+
* > It does not rely on `instanceof Promise` or constructors, making it
|
|
75
|
+
* > compatible with cross-realm promises and custom thenables.
|
|
76
|
+
*
|
|
77
|
+
* @see {@linkcode isThenable}
|
|
78
|
+
*
|
|
79
|
+
* @template {any} T
|
|
80
|
+
* The resolved value
|
|
81
|
+
*
|
|
82
|
+
* @this {void}
|
|
83
|
+
*
|
|
84
|
+
* @param {unknown} value
|
|
85
|
+
* The thing to check
|
|
86
|
+
* @return {value is Promise<T>}
|
|
87
|
+
* `true` if `value` is a thenable with a `catch` method, `false` otherwise
|
|
88
|
+
*/
|
|
89
|
+
declare function isPromise<T>(this: void, value: unknown): value is Promise<T>;
|
|
90
|
+
|
|
42
91
|
/**
|
|
43
92
|
* @file isThenable
|
|
44
93
|
* @module when/lib/isThenable
|
|
45
94
|
*/
|
|
46
95
|
/**
|
|
47
|
-
* Check if `value` looks like a thenable
|
|
96
|
+
* Check if `value` looks like a thenable,
|
|
97
|
+
* i.e. a {@linkcode PromiseLike} object.
|
|
48
98
|
*
|
|
49
99
|
* @template {any} T
|
|
50
100
|
* The resolved value
|
|
@@ -54,7 +104,8 @@ interface Options<T = any, Next = any, Args extends readonly any[] = any[], Self
|
|
|
54
104
|
* @param {unknown} value
|
|
55
105
|
* The thing to check
|
|
56
106
|
* @return {value is PromiseLike<T>}
|
|
57
|
-
* `true` if `value` is a
|
|
107
|
+
* `true` if `value` is an object or function with a `then` method,
|
|
108
|
+
* `false` otherwise
|
|
58
109
|
*/
|
|
59
110
|
declare function isThenable<T>(this: void, value: unknown): value is PromiseLike<T>;
|
|
60
111
|
|
|
@@ -65,11 +116,11 @@ declare function isThenable<T>(this: void, value: unknown): value is PromiseLike
|
|
|
65
116
|
|
|
66
117
|
/**
|
|
67
118
|
* Chain a callback, calling the function after `value` is resolved,
|
|
68
|
-
* or immediately if `value` is not thenable.
|
|
119
|
+
* or immediately if `value` is not a thenable.
|
|
69
120
|
*
|
|
70
121
|
* @see {@linkcode Awaitable}
|
|
71
122
|
* @see {@linkcode Chain}
|
|
72
|
-
* @see {@linkcode
|
|
123
|
+
* @see {@linkcode Fail}
|
|
73
124
|
*
|
|
74
125
|
* @template {any} T
|
|
75
126
|
* The previously resolved value
|
|
@@ -77,28 +128,65 @@ declare function isThenable<T>(this: void, value: unknown): value is PromiseLike
|
|
|
77
128
|
* The next resolved value
|
|
78
129
|
* @template {ReadonlyArray<any>} [Args=any[]]
|
|
79
130
|
* The chain function arguments
|
|
80
|
-
* @template {any} [
|
|
131
|
+
* @template {any} [This=any]
|
|
81
132
|
* The `this` context
|
|
82
133
|
*
|
|
83
134
|
* @this {void}
|
|
84
135
|
*
|
|
85
136
|
* @param {Awaitable<T>} value
|
|
86
|
-
* The
|
|
87
|
-
* @param {Chain<T, Next, Args,
|
|
137
|
+
* The current awaitable
|
|
138
|
+
* @param {Chain<T, Next, Args, This>} chain
|
|
88
139
|
* The chain callback
|
|
89
|
-
* @param {
|
|
90
|
-
* The callback to fire when a
|
|
91
|
-
* @param {
|
|
92
|
-
* The `this` context of the chain and
|
|
140
|
+
* @param {null | undefined} [fail]
|
|
141
|
+
* The callback to fire when a failure occurs
|
|
142
|
+
* @param {This | null | undefined} [context]
|
|
143
|
+
* The `this` context of the chain and `fail` callbacks
|
|
93
144
|
* @param {Args} args
|
|
94
145
|
* The arguments to pass to the chain callback
|
|
95
146
|
* @return {Awaitable<Next>}
|
|
96
|
-
* The next
|
|
147
|
+
* The next awaitable
|
|
97
148
|
*/
|
|
98
|
-
declare function when<T, Next = any, Args extends any[] = any[],
|
|
149
|
+
declare function when<T, Next = any, Args extends any[] = any[], This = unknown>(this: void, value: Awaitable<T>, chain: Chain<T, Next, Args, This>, fail?: null | undefined, context?: This | null | undefined, ...args: Args): Awaitable<Next>;
|
|
99
150
|
/**
|
|
100
151
|
* Chain a callback, calling the function after `value` is resolved,
|
|
101
|
-
* or immediately if `value` is not thenable.
|
|
152
|
+
* or immediately if `value` is not a thenable.
|
|
153
|
+
*
|
|
154
|
+
* @see {@linkcode Awaitable}
|
|
155
|
+
* @see {@linkcode Chain}
|
|
156
|
+
* @see {@linkcode Fail}
|
|
157
|
+
*
|
|
158
|
+
* @template {any} T
|
|
159
|
+
* The previously resolved value
|
|
160
|
+
* @template {any} [Next=any]
|
|
161
|
+
* The next resolved value
|
|
162
|
+
* @template {any} [Failure=Next]
|
|
163
|
+
* The next resolved value on failure
|
|
164
|
+
* @template {ReadonlyArray<any>} [Args=any[]]
|
|
165
|
+
* The chain function arguments
|
|
166
|
+
* @template {any} [Error=any]
|
|
167
|
+
* The error to possibly handle
|
|
168
|
+
* @template {any} [This=any]
|
|
169
|
+
* The `this` context
|
|
170
|
+
*
|
|
171
|
+
* @this {void}
|
|
172
|
+
*
|
|
173
|
+
* @param {Awaitable<T>} value
|
|
174
|
+
* The current awaitable
|
|
175
|
+
* @param {Chain<T, Next, Args, This>} chain
|
|
176
|
+
* The chain callback
|
|
177
|
+
* @param {Fail<Failure, Error, This> | null | undefined} [fail]
|
|
178
|
+
* The callback to fire when a failure occurs
|
|
179
|
+
* @param {This | null | undefined} [context]
|
|
180
|
+
* The `this` context of the chain and `fail` callbacks
|
|
181
|
+
* @param {Args} args
|
|
182
|
+
* The arguments to pass to the chain callback
|
|
183
|
+
* @return {Awaitable<Failure | Next>}
|
|
184
|
+
* The next awaitable
|
|
185
|
+
*/
|
|
186
|
+
declare function when<T, Next = any, Failure = Next, Args extends any[] = any[], Error = any, This = unknown>(this: void, value: Awaitable<T>, chain: Chain<T, Next, Args, This>, fail?: Fail<Failure, Error, This> | null | undefined, context?: This | null | undefined, ...args: Args): Awaitable<Failure | Next>;
|
|
187
|
+
/**
|
|
188
|
+
* Chain a callback, calling the function after `value` is resolved,
|
|
189
|
+
* or immediately if `value` is not a thenable.
|
|
102
190
|
*
|
|
103
191
|
* @see {@linkcode Awaitable}
|
|
104
192
|
* @see {@linkcode Options}
|
|
@@ -107,21 +195,25 @@ declare function when<T, Next = any, Args extends any[] = any[], Self = unknown>
|
|
|
107
195
|
* The previously resolved value
|
|
108
196
|
* @template {any} [Next=any]
|
|
109
197
|
* The next resolved value
|
|
198
|
+
* @template {any} [Failure=Next]
|
|
199
|
+
* The next resolved value on failure
|
|
110
200
|
* @template {ReadonlyArray<any>} [Args=any[]]
|
|
111
201
|
* The chain function arguments
|
|
112
|
-
* @template {any} [
|
|
202
|
+
* @template {any} [Error=any]
|
|
203
|
+
* The error to possibly handle
|
|
204
|
+
* @template {any} [This=unknown]
|
|
113
205
|
* The `this` context
|
|
114
206
|
*
|
|
115
207
|
* @this {void}
|
|
116
208
|
*
|
|
117
209
|
* @param {Awaitable<T>} value
|
|
118
|
-
* The
|
|
119
|
-
* @param {Options<T, Next, Args,
|
|
210
|
+
* The current awaitable
|
|
211
|
+
* @param {Options<T, Next, Failure, Args, Error, This>} chain
|
|
120
212
|
* Options for chaining
|
|
121
|
-
* @return {Awaitable<Next>}
|
|
122
|
-
* The next
|
|
213
|
+
* @return {Awaitable<Failure | Next>}
|
|
214
|
+
* The next awaitable
|
|
123
215
|
*/
|
|
124
|
-
declare function when<T, Next = any, Args extends any[] = any[],
|
|
216
|
+
declare function when<T, Next = any, Failure = Next, Args extends any[] = any[], Error = any, This = unknown>(this: void, value: Awaitable<T>, chain: Options<T, Next, Failure, Args, Error, This>): Awaitable<Failure | Next>;
|
|
125
217
|
|
|
126
218
|
/**
|
|
127
219
|
* @file Type Aliases - Awaitable
|
|
@@ -151,46 +243,45 @@ type Awaitable<T> = PromiseLike<T> | T;
|
|
|
151
243
|
* The next resolved value
|
|
152
244
|
* @template {ReadonlyArray<any>} [Args=any[]]
|
|
153
245
|
* The function arguments
|
|
154
|
-
* @template {any} [
|
|
246
|
+
* @template {any} [This=unknown]
|
|
155
247
|
* The `this` context
|
|
156
248
|
*
|
|
157
|
-
* @this {
|
|
249
|
+
* @this {This}
|
|
158
250
|
*
|
|
159
251
|
* @param {[...Args, T]} params
|
|
160
252
|
* The function parameters, with the last being the previously resolved value.\
|
|
161
253
|
* In cases where a promise is not being resolved,
|
|
162
254
|
* this is the same `value` passed to `when`
|
|
163
255
|
* @return {Awaitable<Next>}
|
|
164
|
-
* The next
|
|
256
|
+
* The next awaitable
|
|
165
257
|
*/
|
|
166
|
-
type Chain<T = any, Next = any, Args extends readonly any[] = any[],
|
|
258
|
+
type Chain<T = any, Next = any, Args extends readonly any[] = any[], This = unknown> = (this: This, ...params: [...Args, T]) => Awaitable<Next>;
|
|
167
259
|
|
|
168
260
|
/**
|
|
169
|
-
* @file Type Aliases -
|
|
170
|
-
* @module when/types/
|
|
261
|
+
* @file Type Aliases - Fail
|
|
262
|
+
* @module when/types/Fail
|
|
171
263
|
*/
|
|
172
264
|
|
|
173
265
|
/**
|
|
174
|
-
* The callback to fire when a
|
|
175
|
-
* or an error is thrown from a synchronous function.
|
|
266
|
+
* The callback to fire when a failure occurs.
|
|
176
267
|
*
|
|
177
268
|
* @see {@linkcode Awaitable}
|
|
178
269
|
*
|
|
179
270
|
* @template {any} [Next=any]
|
|
180
271
|
* The next resolved value
|
|
181
|
-
* @template {any} [
|
|
272
|
+
* @template {any} [Error=any]
|
|
182
273
|
* The error to handle
|
|
183
|
-
* @template {any} [
|
|
274
|
+
* @template {any} [This=unknown]
|
|
184
275
|
* The `this` context
|
|
185
276
|
*
|
|
186
|
-
* @this {
|
|
277
|
+
* @this {This}
|
|
187
278
|
*
|
|
188
279
|
* @param {unknown} e
|
|
189
280
|
* The error
|
|
190
281
|
* @return {Awaitable<Next>}
|
|
191
|
-
* The next
|
|
282
|
+
* The next awaitable
|
|
192
283
|
*/
|
|
193
|
-
type
|
|
284
|
+
type Fail<Next = any, Error = any, This = unknown> = (this: This, e: Error) => Awaitable<Next>;
|
|
194
285
|
|
|
195
|
-
export { when as default, isThenable as isPromiseLike, isThenable, when };
|
|
196
|
-
export type { Awaitable, Chain,
|
|
286
|
+
export { when as default, isPromise, isThenable as isPromiseLike, isThenable, when };
|
|
287
|
+
export type { Awaitable, Chain, Fail, Options };
|
package/dist/lib/index.mjs
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file isPromise
|
|
3
|
+
* @module when/lib/isPromise
|
|
4
|
+
*/
|
|
5
|
+
import isThenable from '#lib/is-thenable';
|
|
6
|
+
/**
|
|
7
|
+
* Check if `value` looks like a {@linkcode Promise}.
|
|
8
|
+
*
|
|
9
|
+
* > 👉 **Note**: This function intentionally performs a structural check
|
|
10
|
+
* > instead of a brand check.
|
|
11
|
+
* > It does not rely on `instanceof Promise` or constructors, making it
|
|
12
|
+
* > compatible with cross-realm promises and custom thenables.
|
|
13
|
+
*
|
|
14
|
+
* @see {@linkcode isThenable}
|
|
15
|
+
*
|
|
16
|
+
* @template {any} T
|
|
17
|
+
* The resolved value
|
|
18
|
+
*
|
|
19
|
+
* @this {void}
|
|
20
|
+
*
|
|
21
|
+
* @param {unknown} value
|
|
22
|
+
* The thing to check
|
|
23
|
+
* @return {value is Promise<T>}
|
|
24
|
+
* `true` if `value` is a thenable with a `catch` method, `false` otherwise
|
|
25
|
+
*/
|
|
26
|
+
function isPromise(value) {
|
|
27
|
+
if (!isThenable(value))
|
|
28
|
+
return false;
|
|
29
|
+
return 'catch' in value && typeof value.catch === 'function';
|
|
30
|
+
}
|
|
31
|
+
export default isPromise;
|
package/dist/lib/is-thenable.mjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* @module when/lib/isThenable
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* Check if `value` looks like a thenable
|
|
6
|
+
* Check if `value` looks like a thenable,
|
|
7
|
+
* i.e. a {@linkcode PromiseLike} object.
|
|
7
8
|
*
|
|
8
9
|
* @template {any} T
|
|
9
10
|
* The resolved value
|
|
@@ -13,13 +14,14 @@
|
|
|
13
14
|
* @param {unknown} value
|
|
14
15
|
* The thing to check
|
|
15
16
|
* @return {value is PromiseLike<T>}
|
|
16
|
-
* `true` if `value` is a
|
|
17
|
+
* `true` if `value` is an object or function with a `then` method,
|
|
18
|
+
* `false` otherwise
|
|
17
19
|
*/
|
|
18
20
|
function isThenable(value) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
if (!value)
|
|
22
|
+
return false;
|
|
23
|
+
if (typeof value !== 'function' && typeof value !== 'object')
|
|
24
|
+
return false;
|
|
25
|
+
return 'then' in value && typeof value.then === 'function';
|
|
24
26
|
}
|
|
25
27
|
export default isThenable;
|
package/dist/lib/when.mjs
CHANGED
|
@@ -2,34 +2,35 @@
|
|
|
2
2
|
* @file when
|
|
3
3
|
* @module when/lib/when
|
|
4
4
|
*/
|
|
5
|
+
import isPromise from '#lib/is-promise';
|
|
5
6
|
import isThenable from '#lib/is-thenable';
|
|
6
7
|
export default when;
|
|
7
8
|
/**
|
|
8
9
|
* Chain a callback, calling the function after `value` is resolved,
|
|
9
|
-
* or immediately if `value` is not thenable.
|
|
10
|
+
* or immediately if `value` is not a thenable.
|
|
10
11
|
*
|
|
11
12
|
* @see {@linkcode Chain}
|
|
12
13
|
* @see {@linkcode Options}
|
|
13
|
-
* @see {@linkcode
|
|
14
|
+
* @see {@linkcode Fail}
|
|
14
15
|
*
|
|
15
16
|
* @this {void}
|
|
16
17
|
*
|
|
17
18
|
* @param {unknown} value
|
|
18
|
-
* The
|
|
19
|
+
* The current awaitable
|
|
19
20
|
* @param {Chain<any, unknown> | Options} chain
|
|
20
21
|
* The chain callback or options for chaining
|
|
21
|
-
* @param {
|
|
22
|
-
* The callback to fire when a
|
|
22
|
+
* @param {Fail | null | undefined} [fail]
|
|
23
|
+
* The callback to fire when a failure occurs
|
|
23
24
|
* @param {unknown} [context]
|
|
24
|
-
* The `this` context of the chain and
|
|
25
|
+
* The `this` context of the chain and `fail` callbacks
|
|
25
26
|
* @param {unknown[]} args
|
|
26
27
|
* The arguments to pass to the chain callback
|
|
27
28
|
* @return {unknown}
|
|
28
|
-
* The next
|
|
29
|
+
* The next awaitable
|
|
29
30
|
*/
|
|
30
|
-
function when(value, chain,
|
|
31
|
+
function when(value, chain, fail, context, ...args) {
|
|
31
32
|
if (typeof chain === 'object') {
|
|
32
|
-
|
|
33
|
+
fail = chain.fail;
|
|
33
34
|
context = chain.context;
|
|
34
35
|
args = chain.args ?? [];
|
|
35
36
|
chain = chain.chain;
|
|
@@ -37,14 +38,17 @@ function when(value, chain, reject, context, ...args) {
|
|
|
37
38
|
// no promise, call chain function immediately.
|
|
38
39
|
if (!isThenable(value)) {
|
|
39
40
|
try {
|
|
40
|
-
|
|
41
|
+
// try attaching "global" rejection handler with `catch`.
|
|
42
|
+
return katch(chain.call(context, ...args, value));
|
|
41
43
|
}
|
|
42
44
|
catch (e) {
|
|
43
|
-
return
|
|
45
|
+
return failure(e);
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
|
-
// already have a promise, chain callback.
|
|
47
|
-
|
|
48
|
+
// already have a promise, chain the chain callback.
|
|
49
|
+
value = value.then(res => chain.call(context, ...args, res), failure);
|
|
50
|
+
// try attaching "global" rejection handler with `catch`.
|
|
51
|
+
return katch(value);
|
|
48
52
|
/**
|
|
49
53
|
* @this {void}
|
|
50
54
|
*
|
|
@@ -54,9 +58,24 @@ function when(value, chain, reject, context, ...args) {
|
|
|
54
58
|
* The rejection result
|
|
55
59
|
* @throws {unknown}
|
|
56
60
|
*/
|
|
57
|
-
function
|
|
58
|
-
if (typeof
|
|
61
|
+
function failure(e) {
|
|
62
|
+
if (typeof fail !== 'function')
|
|
59
63
|
throw e;
|
|
60
|
-
return
|
|
64
|
+
return fail.call(context, e);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Try attaching a rejection handler with `catch`.
|
|
68
|
+
*
|
|
69
|
+
* @this {void}
|
|
70
|
+
*
|
|
71
|
+
* @param {unknown} value
|
|
72
|
+
* The awaitable
|
|
73
|
+
* @return {unknown}
|
|
74
|
+
* The `value`
|
|
75
|
+
*/
|
|
76
|
+
function katch(value) {
|
|
77
|
+
if (isPromise(value))
|
|
78
|
+
value = value.catch(failure);
|
|
79
|
+
return value;
|
|
61
80
|
}
|
|
62
81
|
}
|
package/package.json
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flex-development/when",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "
|
|
3
|
+
"description": "Chain callbacks on synchronous values or thenables without forcing Promise.resolve or microtasks.",
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"async",
|
|
6
7
|
"async",
|
|
7
8
|
"await",
|
|
8
9
|
"awaitable",
|
|
9
10
|
"callback",
|
|
10
11
|
"chain",
|
|
12
|
+
"esm",
|
|
13
|
+
"functional",
|
|
14
|
+
"hooks",
|
|
15
|
+
"microtask",
|
|
16
|
+
"pipeline",
|
|
11
17
|
"promise",
|
|
18
|
+
"promise-like",
|
|
12
19
|
"sync",
|
|
13
20
|
"synchronous",
|
|
14
21
|
"then",
|
|
15
22
|
"thenable",
|
|
16
|
-
"typescript"
|
|
23
|
+
"typescript",
|
|
24
|
+
"utility"
|
|
17
25
|
],
|
|
18
26
|
"license": "BSD-3-Clause",
|
|
19
27
|
"homepage": "https://github.com/flex-development/when",
|
|
@@ -114,7 +122,7 @@
|
|
|
114
122
|
},
|
|
115
123
|
"devDependencies": {
|
|
116
124
|
"@arethetypeswrong/cli": "0.18.2",
|
|
117
|
-
"@commitlint/cli": "20.4.
|
|
125
|
+
"@commitlint/cli": "20.4.2",
|
|
118
126
|
"@commitlint/types": "20.4.0",
|
|
119
127
|
"@edge-runtime/vm": "5.0.0",
|
|
120
128
|
"@flex-development/commitlint-config": "1.0.1",
|
|
@@ -140,7 +148,7 @@
|
|
|
140
148
|
"editorconfig": "3.0.1",
|
|
141
149
|
"eslint": "9.39.2",
|
|
142
150
|
"growl": "1.10.5",
|
|
143
|
-
"happy-dom": "20.6.
|
|
151
|
+
"happy-dom": "20.6.3",
|
|
144
152
|
"husky": "9.1.7",
|
|
145
153
|
"is-ci": "4.1.0",
|
|
146
154
|
"node-notifier": "10.0.1",
|