@fgv/ts-utils 5.1.0-11 → 5.1.0-12
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/README.md +21 -0
- package/dist/packlets/base/result.js +227 -2
- package/dist/ts-utils.d.ts +184 -1
- package/lib/packlets/base/result.d.ts +179 -1
- package/lib/packlets/base/result.js +231 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -56,6 +56,27 @@ function processData(input: string): Result<ProcessedData> {
|
|
|
56
56
|
}
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
### Async Chaining
|
|
60
|
+
|
|
61
|
+
Use `thenOnSuccess()` to chain async operations without breaking the fluent style:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { Result, succeed, captureAsyncResult } from '@fgv/ts-utils';
|
|
65
|
+
|
|
66
|
+
async function processData(input: string): Promise<Result<SavedData>> {
|
|
67
|
+
return parseInput(input)
|
|
68
|
+
.onSuccess((parsed) => validate(parsed))
|
|
69
|
+
.thenOnSuccess(async (valid) => fetchRelatedData(valid.id))
|
|
70
|
+
.onSuccess((data) => transform(data))
|
|
71
|
+
.thenOnSuccess(async (transformed) => saveData(transformed))
|
|
72
|
+
.withErrorFormat((msg) => `pipeline failed: ${msg}`);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`AsyncResult<T>` implements `PromiseLike`, so the entire chain can be directly `await`ed. Rejected promises are caught and converted to `Failure`.
|
|
77
|
+
|
|
78
|
+
[Full async chaining documentation →](./src/packlets/base/README.md#async-result-chaining)
|
|
79
|
+
|
|
59
80
|
### Error Context
|
|
60
81
|
|
|
61
82
|
```typescript
|
|
@@ -101,6 +101,26 @@ export class Success {
|
|
|
101
101
|
onFailure(__) {
|
|
102
102
|
return this;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
106
|
+
*/
|
|
107
|
+
thenOnSuccess(cb) {
|
|
108
|
+
try {
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
110
|
+
return new AsyncResult(cb(this._value));
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
114
|
+
return AsyncResult.from(fail(_errorMessage(err)));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
119
|
+
*/
|
|
120
|
+
thenOnFailure(__) {
|
|
121
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
122
|
+
return AsyncResult.from(this);
|
|
123
|
+
}
|
|
104
124
|
/**
|
|
105
125
|
* {@inheritDoc IResult.withErrorFormat}
|
|
106
126
|
*/
|
|
@@ -226,6 +246,26 @@ export class Failure {
|
|
|
226
246
|
onFailure(cb) {
|
|
227
247
|
return cb(this._message);
|
|
228
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
251
|
+
*/
|
|
252
|
+
thenOnSuccess(__) {
|
|
253
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
254
|
+
return AsyncResult.from(fail(this._message));
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
258
|
+
*/
|
|
259
|
+
thenOnFailure(cb) {
|
|
260
|
+
try {
|
|
261
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
262
|
+
return new AsyncResult(cb(this._message));
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
266
|
+
return AsyncResult.from(fail(_errorMessage(err)));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
229
269
|
/**
|
|
230
270
|
* {@inheritDoc IResult.withErrorFormat}
|
|
231
271
|
*/
|
|
@@ -591,13 +631,25 @@ export function propagateWithDetail(result, detail, successDetail) {
|
|
|
591
631
|
? succeedWithDetail(result.value, successDetail !== null && successDetail !== void 0 ? successDetail : detail)
|
|
592
632
|
: failWithDetail(result.message, detail);
|
|
593
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Extracts a message string from an unknown thrown/rejected value.
|
|
636
|
+
* @param err - The caught error value.
|
|
637
|
+
* @returns The error message string.
|
|
638
|
+
* @internal
|
|
639
|
+
*/
|
|
640
|
+
export function _errorMessage(err) {
|
|
641
|
+
if (err instanceof Error) {
|
|
642
|
+
return err.message;
|
|
643
|
+
}
|
|
644
|
+
return String(err);
|
|
645
|
+
}
|
|
594
646
|
/**
|
|
595
647
|
* Wraps a function which might throw to convert exception results
|
|
596
648
|
* to {@link Failure}.
|
|
597
649
|
* @param func - The function to be captured.
|
|
598
650
|
* @returns Returns {@link Success} with a value of type `<T>` on
|
|
599
651
|
* success , or {@link Failure} with the thrown error message if
|
|
600
|
-
* `func` throws an `Error
|
|
652
|
+
* `func` throws an `Error` or string.
|
|
601
653
|
* @public
|
|
602
654
|
*/
|
|
603
655
|
export function captureResult(func) {
|
|
@@ -605,7 +657,180 @@ export function captureResult(func) {
|
|
|
605
657
|
return succeed(func());
|
|
606
658
|
}
|
|
607
659
|
catch (err) {
|
|
608
|
-
return fail(err
|
|
660
|
+
return fail(_errorMessage(err));
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Wraps a `Promise` of a {@link Result} to enable fluent chaining of both
|
|
665
|
+
* synchronous and asynchronous operations.
|
|
666
|
+
*
|
|
667
|
+
* @remarks
|
|
668
|
+
* `AsyncResult<T>` implements `PromiseLike` so it can be directly `await`ed.
|
|
669
|
+
* Use the `thenOnSuccess` and `thenOnFailure` methods on {@link Result} to bridge
|
|
670
|
+
* from synchronous to asynchronous result chains.
|
|
671
|
+
*
|
|
672
|
+
* @example
|
|
673
|
+
* ```typescript
|
|
674
|
+
* const result: Result<Final> = await parseInput(input)
|
|
675
|
+
* .thenOnSuccess(async (parsed) => fetchData(parsed))
|
|
676
|
+
* .onSuccess((data) => transform(data))
|
|
677
|
+
* .thenOnSuccess(async (transformed) => saveData(transformed))
|
|
678
|
+
* .withErrorFormat((msg) => `pipeline failed: ${msg}`);
|
|
679
|
+
* ```
|
|
680
|
+
*
|
|
681
|
+
* @public
|
|
682
|
+
*/
|
|
683
|
+
export class AsyncResult {
|
|
684
|
+
/**
|
|
685
|
+
* Constructs an {@link AsyncResult} wrapping the supplied promise.
|
|
686
|
+
* @remarks
|
|
687
|
+
* If the supplied promise rejects, the rejection is caught and converted
|
|
688
|
+
* to a {@link Failure}, ensuring that awaiting an {@link AsyncResult} always
|
|
689
|
+
* yields a {@link Result}.
|
|
690
|
+
* @param promise - A `Promise` that resolves to a {@link Result}.
|
|
691
|
+
*/
|
|
692
|
+
constructor(promise) {
|
|
693
|
+
this._promise = promise.catch((err) => fail(_errorMessage(err)));
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Calls a supplied {@link SuccessContinuation | success continuation} if
|
|
697
|
+
* the wrapped result is successful.
|
|
698
|
+
* @param cb - The synchronous {@link SuccessContinuation | success continuation}
|
|
699
|
+
* to be called in the event of success.
|
|
700
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
701
|
+
*/
|
|
702
|
+
onSuccess(cb) {
|
|
703
|
+
return new AsyncResult(this._promise.then((r) => r.onSuccess(cb)));
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Calls a supplied {@link AsyncSuccessContinuation | async success continuation} if
|
|
707
|
+
* the wrapped result is successful.
|
|
708
|
+
* @remarks
|
|
709
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
710
|
+
* and converted to a {@link Failure}.
|
|
711
|
+
* @param cb - The {@link AsyncSuccessContinuation | async success continuation}
|
|
712
|
+
* to be called in the event of success.
|
|
713
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
714
|
+
*/
|
|
715
|
+
thenOnSuccess(cb) {
|
|
716
|
+
return new AsyncResult(this._promise.then(async (r) => {
|
|
717
|
+
if (r.isFailure()) {
|
|
718
|
+
return fail(r.message);
|
|
719
|
+
}
|
|
720
|
+
try {
|
|
721
|
+
return await cb(r.value);
|
|
722
|
+
}
|
|
723
|
+
catch (err) {
|
|
724
|
+
return fail(_errorMessage(err));
|
|
725
|
+
}
|
|
726
|
+
}));
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Calls a supplied {@link FailureContinuation | failure continuation} if
|
|
730
|
+
* the wrapped result is a failure.
|
|
731
|
+
* @param cb - The synchronous {@link FailureContinuation | failure continuation}
|
|
732
|
+
* to be called in the event of failure.
|
|
733
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
734
|
+
*/
|
|
735
|
+
onFailure(cb) {
|
|
736
|
+
return new AsyncResult(this._promise.then((r) => r.onFailure(cb)));
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Calls a supplied {@link AsyncFailureContinuation | async failure continuation} if
|
|
740
|
+
* the wrapped result is a failure.
|
|
741
|
+
* @remarks
|
|
742
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
743
|
+
* and converted to a {@link Failure}.
|
|
744
|
+
* @param cb - The {@link AsyncFailureContinuation | async failure continuation}
|
|
745
|
+
* to be called in the event of failure.
|
|
746
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
747
|
+
*/
|
|
748
|
+
thenOnFailure(cb) {
|
|
749
|
+
return new AsyncResult(this._promise.then(async (r) => {
|
|
750
|
+
if (r.isSuccess()) {
|
|
751
|
+
return r;
|
|
752
|
+
}
|
|
753
|
+
try {
|
|
754
|
+
return await cb(r.message);
|
|
755
|
+
}
|
|
756
|
+
catch (err) {
|
|
757
|
+
return fail(_errorMessage(err));
|
|
758
|
+
}
|
|
759
|
+
}));
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Calls a supplied {@link ErrorFormatter | error formatter} if
|
|
763
|
+
* the wrapped result is a failure.
|
|
764
|
+
* @param cb - The {@link ErrorFormatter | error formatter} to
|
|
765
|
+
* be called in the event of failure.
|
|
766
|
+
* @returns A new {@link AsyncResult} with the formatted error message,
|
|
767
|
+
* or the original success result.
|
|
768
|
+
*/
|
|
769
|
+
withErrorFormat(cb) {
|
|
770
|
+
return new AsyncResult(this._promise.then((r) => r.withErrorFormat(cb)));
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* Propagates the wrapped result, appending any error message to the
|
|
774
|
+
* supplied errors aggregator.
|
|
775
|
+
* @param errors - {@link IMessageAggregator | Error aggregator} in which
|
|
776
|
+
* errors will be aggregated.
|
|
777
|
+
* @param formatter - An optional {@link ErrorFormatter | error formatter}
|
|
778
|
+
* to be used to format the error message.
|
|
779
|
+
* @returns A new {@link AsyncResult} wrapping the result after aggregation.
|
|
780
|
+
*/
|
|
781
|
+
aggregateError(errors, formatter) {
|
|
782
|
+
return new AsyncResult(this._promise.then((r) => {
|
|
783
|
+
r.aggregateError(errors, formatter);
|
|
784
|
+
return r;
|
|
785
|
+
}));
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Reports the wrapped result to the supplied reporter.
|
|
789
|
+
* @param reporter - The {@link IResultReporter | reporter} to which the result
|
|
790
|
+
* will be reported.
|
|
791
|
+
* @param options - The {@link IResultReportOptions | options} for reporting the result.
|
|
792
|
+
* @returns A new {@link AsyncResult} wrapping the result after reporting.
|
|
793
|
+
*/
|
|
794
|
+
report(reporter, options) {
|
|
795
|
+
return new AsyncResult(this._promise.then((r) => {
|
|
796
|
+
r.report(reporter, options);
|
|
797
|
+
return r;
|
|
798
|
+
}));
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Implementation of `PromiseLike.then` enabling `await` on {@link AsyncResult}.
|
|
802
|
+
* @param onfulfilled - Callback invoked when the promise resolves.
|
|
803
|
+
* @param onrejected - Callback invoked when the promise rejects.
|
|
804
|
+
* @returns A `Promise` resolving to the callback result.
|
|
805
|
+
*/
|
|
806
|
+
/* eslint-disable @rushstack/no-new-null */
|
|
807
|
+
then(onfulfilled, onrejected) {
|
|
808
|
+
/* eslint-enable @rushstack/no-new-null */
|
|
809
|
+
return this._promise.then(onfulfilled, onrejected);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Creates an {@link AsyncResult} from a {@link Result}.
|
|
813
|
+
* @param result - The {@link Result} to wrap.
|
|
814
|
+
* @returns A new {@link AsyncResult} wrapping the supplied result.
|
|
815
|
+
*/
|
|
816
|
+
static from(result) {
|
|
817
|
+
return new AsyncResult(Promise.resolve(result));
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Wraps an async function which might throw to convert exception results
|
|
822
|
+
* to {@link Failure}.
|
|
823
|
+
* @param func - The async function to be captured.
|
|
824
|
+
* @returns Returns a `Promise` of {@link Success} with a value of type `<T>` on
|
|
825
|
+
* success, or {@link Failure} with the thrown error message if `func` throws or rejects.
|
|
826
|
+
* @public
|
|
827
|
+
*/
|
|
828
|
+
export async function captureAsyncResult(func) {
|
|
829
|
+
try {
|
|
830
|
+
return succeed(await func());
|
|
831
|
+
}
|
|
832
|
+
catch (err) {
|
|
833
|
+
return fail(_errorMessage(err));
|
|
609
834
|
}
|
|
610
835
|
}
|
|
611
836
|
//# sourceMappingURL=result.js.map
|
package/dist/ts-utils.d.ts
CHANGED
|
@@ -420,6 +420,131 @@ declare interface ArrayValidatorConstructorParams<T, TC = unknown> extends Valid
|
|
|
420
420
|
*/
|
|
421
421
|
declare function asValidator<T, TC = unknown>(converterOrValidator: Converter<T, TC> | Validator<T, TC>): Validator<T, TC>;
|
|
422
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Async continuation callback to be called in the event that a
|
|
425
|
+
* {@link Result} fails, returning a `Promise` of a new {@link Result}.
|
|
426
|
+
* @public
|
|
427
|
+
*/
|
|
428
|
+
export declare type AsyncFailureContinuation<T> = (message: string) => Promise<Result<T>>;
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Wraps a `Promise` of a {@link Result} to enable fluent chaining of both
|
|
432
|
+
* synchronous and asynchronous operations.
|
|
433
|
+
*
|
|
434
|
+
* @remarks
|
|
435
|
+
* `AsyncResult<T>` implements `PromiseLike` so it can be directly `await`ed.
|
|
436
|
+
* Use the `thenOnSuccess` and `thenOnFailure` methods on {@link Result} to bridge
|
|
437
|
+
* from synchronous to asynchronous result chains.
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```typescript
|
|
441
|
+
* const result: Result<Final> = await parseInput(input)
|
|
442
|
+
* .thenOnSuccess(async (parsed) => fetchData(parsed))
|
|
443
|
+
* .onSuccess((data) => transform(data))
|
|
444
|
+
* .thenOnSuccess(async (transformed) => saveData(transformed))
|
|
445
|
+
* .withErrorFormat((msg) => `pipeline failed: ${msg}`);
|
|
446
|
+
* ```
|
|
447
|
+
*
|
|
448
|
+
* @public
|
|
449
|
+
*/
|
|
450
|
+
export declare class AsyncResult<T> implements PromiseLike<Result<T>> {
|
|
451
|
+
private readonly _promise;
|
|
452
|
+
/**
|
|
453
|
+
* Constructs an {@link AsyncResult} wrapping the supplied promise.
|
|
454
|
+
* @remarks
|
|
455
|
+
* If the supplied promise rejects, the rejection is caught and converted
|
|
456
|
+
* to a {@link Failure}, ensuring that awaiting an {@link AsyncResult} always
|
|
457
|
+
* yields a {@link Result}.
|
|
458
|
+
* @param promise - A `Promise` that resolves to a {@link Result}.
|
|
459
|
+
*/
|
|
460
|
+
constructor(promise: Promise<Result<T>>);
|
|
461
|
+
/**
|
|
462
|
+
* Calls a supplied {@link SuccessContinuation | success continuation} if
|
|
463
|
+
* the wrapped result is successful.
|
|
464
|
+
* @param cb - The synchronous {@link SuccessContinuation | success continuation}
|
|
465
|
+
* to be called in the event of success.
|
|
466
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
467
|
+
*/
|
|
468
|
+
onSuccess<TN>(cb: SuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
469
|
+
/**
|
|
470
|
+
* Calls a supplied {@link AsyncSuccessContinuation | async success continuation} if
|
|
471
|
+
* the wrapped result is successful.
|
|
472
|
+
* @remarks
|
|
473
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
474
|
+
* and converted to a {@link Failure}.
|
|
475
|
+
* @param cb - The {@link AsyncSuccessContinuation | async success continuation}
|
|
476
|
+
* to be called in the event of success.
|
|
477
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
478
|
+
*/
|
|
479
|
+
thenOnSuccess<TN>(cb: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
480
|
+
/**
|
|
481
|
+
* Calls a supplied {@link FailureContinuation | failure continuation} if
|
|
482
|
+
* the wrapped result is a failure.
|
|
483
|
+
* @param cb - The synchronous {@link FailureContinuation | failure continuation}
|
|
484
|
+
* to be called in the event of failure.
|
|
485
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
486
|
+
*/
|
|
487
|
+
onFailure(cb: FailureContinuation<T>): AsyncResult<T>;
|
|
488
|
+
/**
|
|
489
|
+
* Calls a supplied {@link AsyncFailureContinuation | async failure continuation} if
|
|
490
|
+
* the wrapped result is a failure.
|
|
491
|
+
* @remarks
|
|
492
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
493
|
+
* and converted to a {@link Failure}.
|
|
494
|
+
* @param cb - The {@link AsyncFailureContinuation | async failure continuation}
|
|
495
|
+
* to be called in the event of failure.
|
|
496
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
497
|
+
*/
|
|
498
|
+
thenOnFailure(cb: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
499
|
+
/**
|
|
500
|
+
* Calls a supplied {@link ErrorFormatter | error formatter} if
|
|
501
|
+
* the wrapped result is a failure.
|
|
502
|
+
* @param cb - The {@link ErrorFormatter | error formatter} to
|
|
503
|
+
* be called in the event of failure.
|
|
504
|
+
* @returns A new {@link AsyncResult} with the formatted error message,
|
|
505
|
+
* or the original success result.
|
|
506
|
+
*/
|
|
507
|
+
withErrorFormat(cb: ErrorFormatter): AsyncResult<T>;
|
|
508
|
+
/**
|
|
509
|
+
* Propagates the wrapped result, appending any error message to the
|
|
510
|
+
* supplied errors aggregator.
|
|
511
|
+
* @param errors - {@link IMessageAggregator | Error aggregator} in which
|
|
512
|
+
* errors will be aggregated.
|
|
513
|
+
* @param formatter - An optional {@link ErrorFormatter | error formatter}
|
|
514
|
+
* to be used to format the error message.
|
|
515
|
+
* @returns A new {@link AsyncResult} wrapping the result after aggregation.
|
|
516
|
+
*/
|
|
517
|
+
aggregateError(errors: IMessageAggregator, formatter?: ErrorFormatter): AsyncResult<T>;
|
|
518
|
+
/**
|
|
519
|
+
* Reports the wrapped result to the supplied reporter.
|
|
520
|
+
* @param reporter - The {@link IResultReporter | reporter} to which the result
|
|
521
|
+
* will be reported.
|
|
522
|
+
* @param options - The {@link IResultReportOptions | options} for reporting the result.
|
|
523
|
+
* @returns A new {@link AsyncResult} wrapping the result after reporting.
|
|
524
|
+
*/
|
|
525
|
+
report(reporter?: IResultReporter<T>, options?: IResultReportOptions<unknown>): AsyncResult<T>;
|
|
526
|
+
/**
|
|
527
|
+
* Implementation of `PromiseLike.then` enabling `await` on {@link AsyncResult}.
|
|
528
|
+
* @param onfulfilled - Callback invoked when the promise resolves.
|
|
529
|
+
* @param onrejected - Callback invoked when the promise rejects.
|
|
530
|
+
* @returns A `Promise` resolving to the callback result.
|
|
531
|
+
*/
|
|
532
|
+
then<TResult1 = Result<T>, TResult2 = never>(onfulfilled?: ((value: Result<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
533
|
+
/**
|
|
534
|
+
* Creates an {@link AsyncResult} from a {@link Result}.
|
|
535
|
+
* @param result - The {@link Result} to wrap.
|
|
536
|
+
* @returns A new {@link AsyncResult} wrapping the supplied result.
|
|
537
|
+
*/
|
|
538
|
+
static from<T>(result: Result<T>): AsyncResult<T>;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Async continuation callback to be called in the event that a
|
|
543
|
+
* {@link Result} is successful, returning a `Promise` of a new {@link Result}.
|
|
544
|
+
* @public
|
|
545
|
+
*/
|
|
546
|
+
export declare type AsyncSuccessContinuation<T, TN> = (value: T) => Promise<Result<TN>>;
|
|
547
|
+
|
|
423
548
|
declare namespace Base {
|
|
424
549
|
export {
|
|
425
550
|
GenericValidatorConstructorParams,
|
|
@@ -778,13 +903,23 @@ declare class CacheInvalidatingResultMapWrapper<TK extends string, TSRC, TTARGET
|
|
|
778
903
|
toReadOnly(): IReadOnlyResultMap<TK, TSRC>;
|
|
779
904
|
}
|
|
780
905
|
|
|
906
|
+
/**
|
|
907
|
+
* Wraps an async function which might throw to convert exception results
|
|
908
|
+
* to {@link Failure}.
|
|
909
|
+
* @param func - The async function to be captured.
|
|
910
|
+
* @returns Returns a `Promise` of {@link Success} with a value of type `<T>` on
|
|
911
|
+
* success, or {@link Failure} with the thrown error message if `func` throws or rejects.
|
|
912
|
+
* @public
|
|
913
|
+
*/
|
|
914
|
+
export declare function captureAsyncResult<T>(func: () => Promise<T>): Promise<Result<T>>;
|
|
915
|
+
|
|
781
916
|
/**
|
|
782
917
|
* Wraps a function which might throw to convert exception results
|
|
783
918
|
* to {@link Failure}.
|
|
784
919
|
* @param func - The function to be captured.
|
|
785
920
|
* @returns Returns {@link Success} with a value of type `<T>` on
|
|
786
921
|
* success , or {@link Failure} with the thrown error message if
|
|
787
|
-
* `func` throws an `Error
|
|
922
|
+
* `func` throws an `Error` or string.
|
|
788
923
|
* @public
|
|
789
924
|
*/
|
|
790
925
|
export declare function captureResult<T>(func: () => T): Result<T>;
|
|
@@ -2070,6 +2205,14 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
|
|
|
2070
2205
|
*/
|
|
2071
2206
|
export declare type ErrorFormatter<TD = unknown> = (message: string, detail?: TD) => string;
|
|
2072
2207
|
|
|
2208
|
+
/**
|
|
2209
|
+
* Extracts a message string from an unknown thrown/rejected value.
|
|
2210
|
+
* @param err - The caught error value.
|
|
2211
|
+
* @returns The error message string.
|
|
2212
|
+
* @internal
|
|
2213
|
+
*/
|
|
2214
|
+
export declare function _errorMessage(err: unknown): string;
|
|
2215
|
+
|
|
2073
2216
|
/**
|
|
2074
2217
|
* Returns {@link Failure | Failure<T>} with the supplied error message.
|
|
2075
2218
|
* @param message - Error message to be returned.
|
|
@@ -2161,6 +2304,14 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
|
|
|
2161
2304
|
* {@inheritDoc IResult.onFailure}
|
|
2162
2305
|
*/
|
|
2163
2306
|
onFailure(cb: FailureContinuation<T>): Result<T>;
|
|
2307
|
+
/**
|
|
2308
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
2309
|
+
*/
|
|
2310
|
+
thenOnSuccess<TN>(__: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
2311
|
+
/**
|
|
2312
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
2313
|
+
*/
|
|
2314
|
+
thenOnFailure(cb: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
2164
2315
|
/**
|
|
2165
2316
|
* {@inheritDoc IResult.withErrorFormat}
|
|
2166
2317
|
*/
|
|
@@ -3276,6 +3427,30 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
|
|
|
3276
3427
|
* was successful, propagates the result value from the successful event.
|
|
3277
3428
|
*/
|
|
3278
3429
|
onFailure(cb: FailureContinuation<T>): Result<T>;
|
|
3430
|
+
/**
|
|
3431
|
+
* Calls a supplied {@link AsyncSuccessContinuation | async success continuation} if
|
|
3432
|
+
* the operation was a success, bridging into an {@link AsyncResult} chain.
|
|
3433
|
+
* @remarks
|
|
3434
|
+
* If the async callback rejects, the rejection is caught and converted
|
|
3435
|
+
* to a {@link Failure}.
|
|
3436
|
+
* @param cb - The {@link AsyncSuccessContinuation | async success continuation} to
|
|
3437
|
+
* be called in the event of success.
|
|
3438
|
+
* @returns An {@link AsyncResult} wrapping the async continuation result, or
|
|
3439
|
+
* propagating the error message from this failure.
|
|
3440
|
+
*/
|
|
3441
|
+
thenOnSuccess<TN>(cb: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
3442
|
+
/**
|
|
3443
|
+
* Calls a supplied {@link AsyncFailureContinuation | async failure continuation} if
|
|
3444
|
+
* the operation failed, bridging into an {@link AsyncResult} chain.
|
|
3445
|
+
* @remarks
|
|
3446
|
+
* If the async callback rejects, the rejection is caught and converted
|
|
3447
|
+
* to a {@link Failure}.
|
|
3448
|
+
* @param cb - The {@link AsyncFailureContinuation | async failure continuation} to
|
|
3449
|
+
* be called in the event of failure.
|
|
3450
|
+
* @returns An {@link AsyncResult} wrapping the async continuation result, or
|
|
3451
|
+
* propagating the success value from this result.
|
|
3452
|
+
*/
|
|
3453
|
+
thenOnFailure(cb: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
3279
3454
|
/**
|
|
3280
3455
|
* Calls a supplied {@link ErrorFormatter | error formatter} if
|
|
3281
3456
|
* the operation failed.
|
|
@@ -5557,6 +5732,14 @@ declare class Collectible<TKEY extends string = string, TINDEX extends number =
|
|
|
5557
5732
|
* {@inheritDoc IResult.onFailure}
|
|
5558
5733
|
*/
|
|
5559
5734
|
onFailure(__: FailureContinuation<T>): Result<T>;
|
|
5735
|
+
/**
|
|
5736
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
5737
|
+
*/
|
|
5738
|
+
thenOnSuccess<TN>(cb: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
5739
|
+
/**
|
|
5740
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
5741
|
+
*/
|
|
5742
|
+
thenOnFailure(__: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
5560
5743
|
/**
|
|
5561
5744
|
* {@inheritDoc IResult.withErrorFormat}
|
|
5562
5745
|
*/
|
|
@@ -266,6 +266,30 @@ export interface IResult<T> {
|
|
|
266
266
|
* was successful, propagates the result value from the successful event.
|
|
267
267
|
*/
|
|
268
268
|
onFailure(cb: FailureContinuation<T>): Result<T>;
|
|
269
|
+
/**
|
|
270
|
+
* Calls a supplied {@link AsyncSuccessContinuation | async success continuation} if
|
|
271
|
+
* the operation was a success, bridging into an {@link AsyncResult} chain.
|
|
272
|
+
* @remarks
|
|
273
|
+
* If the async callback rejects, the rejection is caught and converted
|
|
274
|
+
* to a {@link Failure}.
|
|
275
|
+
* @param cb - The {@link AsyncSuccessContinuation | async success continuation} to
|
|
276
|
+
* be called in the event of success.
|
|
277
|
+
* @returns An {@link AsyncResult} wrapping the async continuation result, or
|
|
278
|
+
* propagating the error message from this failure.
|
|
279
|
+
*/
|
|
280
|
+
thenOnSuccess<TN>(cb: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
281
|
+
/**
|
|
282
|
+
* Calls a supplied {@link AsyncFailureContinuation | async failure continuation} if
|
|
283
|
+
* the operation failed, bridging into an {@link AsyncResult} chain.
|
|
284
|
+
* @remarks
|
|
285
|
+
* If the async callback rejects, the rejection is caught and converted
|
|
286
|
+
* to a {@link Failure}.
|
|
287
|
+
* @param cb - The {@link AsyncFailureContinuation | async failure continuation} to
|
|
288
|
+
* be called in the event of failure.
|
|
289
|
+
* @returns An {@link AsyncResult} wrapping the async continuation result, or
|
|
290
|
+
* propagating the success value from this result.
|
|
291
|
+
*/
|
|
292
|
+
thenOnFailure(cb: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
269
293
|
/**
|
|
270
294
|
* Calls a supplied {@link ErrorFormatter | error formatter} if
|
|
271
295
|
* the operation failed.
|
|
@@ -380,6 +404,14 @@ export declare class Success<out T> implements IResult<T> {
|
|
|
380
404
|
* {@inheritDoc IResult.onFailure}
|
|
381
405
|
*/
|
|
382
406
|
onFailure(__: FailureContinuation<T>): Result<T>;
|
|
407
|
+
/**
|
|
408
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
409
|
+
*/
|
|
410
|
+
thenOnSuccess<TN>(cb: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
411
|
+
/**
|
|
412
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
413
|
+
*/
|
|
414
|
+
thenOnFailure(__: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
383
415
|
/**
|
|
384
416
|
* {@inheritDoc IResult.withErrorFormat}
|
|
385
417
|
*/
|
|
@@ -476,6 +508,14 @@ export declare class Failure<out T> implements IResult<T> {
|
|
|
476
508
|
* {@inheritDoc IResult.onFailure}
|
|
477
509
|
*/
|
|
478
510
|
onFailure(cb: FailureContinuation<T>): Result<T>;
|
|
511
|
+
/**
|
|
512
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
513
|
+
*/
|
|
514
|
+
thenOnSuccess<TN>(__: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
515
|
+
/**
|
|
516
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
517
|
+
*/
|
|
518
|
+
thenOnFailure(cb: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
479
519
|
/**
|
|
480
520
|
* {@inheritDoc IResult.withErrorFormat}
|
|
481
521
|
*/
|
|
@@ -772,14 +812,152 @@ export declare function failsWithDetail<T, TD>(message: string, detail?: TD): De
|
|
|
772
812
|
* @public
|
|
773
813
|
*/
|
|
774
814
|
export declare function propagateWithDetail<T, TD>(result: Result<T>, detail: TD, successDetail?: TD): DetailedResult<T, TD>;
|
|
815
|
+
/**
|
|
816
|
+
* Extracts a message string from an unknown thrown/rejected value.
|
|
817
|
+
* @param err - The caught error value.
|
|
818
|
+
* @returns The error message string.
|
|
819
|
+
* @internal
|
|
820
|
+
*/
|
|
821
|
+
export declare function _errorMessage(err: unknown): string;
|
|
775
822
|
/**
|
|
776
823
|
* Wraps a function which might throw to convert exception results
|
|
777
824
|
* to {@link Failure}.
|
|
778
825
|
* @param func - The function to be captured.
|
|
779
826
|
* @returns Returns {@link Success} with a value of type `<T>` on
|
|
780
827
|
* success , or {@link Failure} with the thrown error message if
|
|
781
|
-
* `func` throws an `Error
|
|
828
|
+
* `func` throws an `Error` or string.
|
|
782
829
|
* @public
|
|
783
830
|
*/
|
|
784
831
|
export declare function captureResult<T>(func: () => T): Result<T>;
|
|
832
|
+
/**
|
|
833
|
+
* Async continuation callback to be called in the event that a
|
|
834
|
+
* {@link Result} is successful, returning a `Promise` of a new {@link Result}.
|
|
835
|
+
* @public
|
|
836
|
+
*/
|
|
837
|
+
export type AsyncSuccessContinuation<T, TN> = (value: T) => Promise<Result<TN>>;
|
|
838
|
+
/**
|
|
839
|
+
* Async continuation callback to be called in the event that a
|
|
840
|
+
* {@link Result} fails, returning a `Promise` of a new {@link Result}.
|
|
841
|
+
* @public
|
|
842
|
+
*/
|
|
843
|
+
export type AsyncFailureContinuation<T> = (message: string) => Promise<Result<T>>;
|
|
844
|
+
/**
|
|
845
|
+
* Wraps a `Promise` of a {@link Result} to enable fluent chaining of both
|
|
846
|
+
* synchronous and asynchronous operations.
|
|
847
|
+
*
|
|
848
|
+
* @remarks
|
|
849
|
+
* `AsyncResult<T>` implements `PromiseLike` so it can be directly `await`ed.
|
|
850
|
+
* Use the `thenOnSuccess` and `thenOnFailure` methods on {@link Result} to bridge
|
|
851
|
+
* from synchronous to asynchronous result chains.
|
|
852
|
+
*
|
|
853
|
+
* @example
|
|
854
|
+
* ```typescript
|
|
855
|
+
* const result: Result<Final> = await parseInput(input)
|
|
856
|
+
* .thenOnSuccess(async (parsed) => fetchData(parsed))
|
|
857
|
+
* .onSuccess((data) => transform(data))
|
|
858
|
+
* .thenOnSuccess(async (transformed) => saveData(transformed))
|
|
859
|
+
* .withErrorFormat((msg) => `pipeline failed: ${msg}`);
|
|
860
|
+
* ```
|
|
861
|
+
*
|
|
862
|
+
* @public
|
|
863
|
+
*/
|
|
864
|
+
export declare class AsyncResult<T> implements PromiseLike<Result<T>> {
|
|
865
|
+
private readonly _promise;
|
|
866
|
+
/**
|
|
867
|
+
* Constructs an {@link AsyncResult} wrapping the supplied promise.
|
|
868
|
+
* @remarks
|
|
869
|
+
* If the supplied promise rejects, the rejection is caught and converted
|
|
870
|
+
* to a {@link Failure}, ensuring that awaiting an {@link AsyncResult} always
|
|
871
|
+
* yields a {@link Result}.
|
|
872
|
+
* @param promise - A `Promise` that resolves to a {@link Result}.
|
|
873
|
+
*/
|
|
874
|
+
constructor(promise: Promise<Result<T>>);
|
|
875
|
+
/**
|
|
876
|
+
* Calls a supplied {@link SuccessContinuation | success continuation} if
|
|
877
|
+
* the wrapped result is successful.
|
|
878
|
+
* @param cb - The synchronous {@link SuccessContinuation | success continuation}
|
|
879
|
+
* to be called in the event of success.
|
|
880
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
881
|
+
*/
|
|
882
|
+
onSuccess<TN>(cb: SuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
883
|
+
/**
|
|
884
|
+
* Calls a supplied {@link AsyncSuccessContinuation | async success continuation} if
|
|
885
|
+
* the wrapped result is successful.
|
|
886
|
+
* @remarks
|
|
887
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
888
|
+
* and converted to a {@link Failure}.
|
|
889
|
+
* @param cb - The {@link AsyncSuccessContinuation | async success continuation}
|
|
890
|
+
* to be called in the event of success.
|
|
891
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
892
|
+
*/
|
|
893
|
+
thenOnSuccess<TN>(cb: AsyncSuccessContinuation<T, TN>): AsyncResult<TN>;
|
|
894
|
+
/**
|
|
895
|
+
* Calls a supplied {@link FailureContinuation | failure continuation} if
|
|
896
|
+
* the wrapped result is a failure.
|
|
897
|
+
* @param cb - The synchronous {@link FailureContinuation | failure continuation}
|
|
898
|
+
* to be called in the event of failure.
|
|
899
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
900
|
+
*/
|
|
901
|
+
onFailure(cb: FailureContinuation<T>): AsyncResult<T>;
|
|
902
|
+
/**
|
|
903
|
+
* Calls a supplied {@link AsyncFailureContinuation | async failure continuation} if
|
|
904
|
+
* the wrapped result is a failure.
|
|
905
|
+
* @remarks
|
|
906
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
907
|
+
* and converted to a {@link Failure}.
|
|
908
|
+
* @param cb - The {@link AsyncFailureContinuation | async failure continuation}
|
|
909
|
+
* to be called in the event of failure.
|
|
910
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
911
|
+
*/
|
|
912
|
+
thenOnFailure(cb: AsyncFailureContinuation<T>): AsyncResult<T>;
|
|
913
|
+
/**
|
|
914
|
+
* Calls a supplied {@link ErrorFormatter | error formatter} if
|
|
915
|
+
* the wrapped result is a failure.
|
|
916
|
+
* @param cb - The {@link ErrorFormatter | error formatter} to
|
|
917
|
+
* be called in the event of failure.
|
|
918
|
+
* @returns A new {@link AsyncResult} with the formatted error message,
|
|
919
|
+
* or the original success result.
|
|
920
|
+
*/
|
|
921
|
+
withErrorFormat(cb: ErrorFormatter): AsyncResult<T>;
|
|
922
|
+
/**
|
|
923
|
+
* Propagates the wrapped result, appending any error message to the
|
|
924
|
+
* supplied errors aggregator.
|
|
925
|
+
* @param errors - {@link IMessageAggregator | Error aggregator} in which
|
|
926
|
+
* errors will be aggregated.
|
|
927
|
+
* @param formatter - An optional {@link ErrorFormatter | error formatter}
|
|
928
|
+
* to be used to format the error message.
|
|
929
|
+
* @returns A new {@link AsyncResult} wrapping the result after aggregation.
|
|
930
|
+
*/
|
|
931
|
+
aggregateError(errors: IMessageAggregator, formatter?: ErrorFormatter): AsyncResult<T>;
|
|
932
|
+
/**
|
|
933
|
+
* Reports the wrapped result to the supplied reporter.
|
|
934
|
+
* @param reporter - The {@link IResultReporter | reporter} to which the result
|
|
935
|
+
* will be reported.
|
|
936
|
+
* @param options - The {@link IResultReportOptions | options} for reporting the result.
|
|
937
|
+
* @returns A new {@link AsyncResult} wrapping the result after reporting.
|
|
938
|
+
*/
|
|
939
|
+
report(reporter?: IResultReporter<T>, options?: IResultReportOptions<unknown>): AsyncResult<T>;
|
|
940
|
+
/**
|
|
941
|
+
* Implementation of `PromiseLike.then` enabling `await` on {@link AsyncResult}.
|
|
942
|
+
* @param onfulfilled - Callback invoked when the promise resolves.
|
|
943
|
+
* @param onrejected - Callback invoked when the promise rejects.
|
|
944
|
+
* @returns A `Promise` resolving to the callback result.
|
|
945
|
+
*/
|
|
946
|
+
then<TResult1 = Result<T>, TResult2 = never>(onfulfilled?: ((value: Result<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
947
|
+
/**
|
|
948
|
+
* Creates an {@link AsyncResult} from a {@link Result}.
|
|
949
|
+
* @param result - The {@link Result} to wrap.
|
|
950
|
+
* @returns A new {@link AsyncResult} wrapping the supplied result.
|
|
951
|
+
*/
|
|
952
|
+
static from<T>(result: Result<T>): AsyncResult<T>;
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Wraps an async function which might throw to convert exception results
|
|
956
|
+
* to {@link Failure}.
|
|
957
|
+
* @param func - The async function to be captured.
|
|
958
|
+
* @returns Returns a `Promise` of {@link Success} with a value of type `<T>` on
|
|
959
|
+
* success, or {@link Failure} with the thrown error message if `func` throws or rejects.
|
|
960
|
+
* @public
|
|
961
|
+
*/
|
|
962
|
+
export declare function captureAsyncResult<T>(func: () => Promise<T>): Promise<Result<T>>;
|
|
785
963
|
//# sourceMappingURL=result.d.ts.map
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* SOFTWARE.
|
|
22
22
|
*/
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.DetailedFailure = exports.DetailedSuccess = exports.Failure = exports.Success = void 0;
|
|
24
|
+
exports.AsyncResult = exports.DetailedFailure = exports.DetailedSuccess = exports.Failure = exports.Success = void 0;
|
|
25
25
|
exports.isDeferredResult = isDeferredResult;
|
|
26
26
|
exports.succeed = succeed;
|
|
27
27
|
exports.succeeds = succeeds;
|
|
@@ -33,7 +33,9 @@ exports.succeedsWithDetail = succeedsWithDetail;
|
|
|
33
33
|
exports.failWithDetail = failWithDetail;
|
|
34
34
|
exports.failsWithDetail = failsWithDetail;
|
|
35
35
|
exports.propagateWithDetail = propagateWithDetail;
|
|
36
|
+
exports._errorMessage = _errorMessage;
|
|
36
37
|
exports.captureResult = captureResult;
|
|
38
|
+
exports.captureAsyncResult = captureAsyncResult;
|
|
37
39
|
/**
|
|
38
40
|
* Checks if a result is a deferred result.
|
|
39
41
|
* @param result - The result to check.
|
|
@@ -116,6 +118,26 @@ class Success {
|
|
|
116
118
|
onFailure(__) {
|
|
117
119
|
return this;
|
|
118
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
123
|
+
*/
|
|
124
|
+
thenOnSuccess(cb) {
|
|
125
|
+
try {
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
127
|
+
return new AsyncResult(cb(this._value));
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
131
|
+
return AsyncResult.from(fail(_errorMessage(err)));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
136
|
+
*/
|
|
137
|
+
thenOnFailure(__) {
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
139
|
+
return AsyncResult.from(this);
|
|
140
|
+
}
|
|
119
141
|
/**
|
|
120
142
|
* {@inheritDoc IResult.withErrorFormat}
|
|
121
143
|
*/
|
|
@@ -242,6 +264,26 @@ class Failure {
|
|
|
242
264
|
onFailure(cb) {
|
|
243
265
|
return cb(this._message);
|
|
244
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* {@inheritDoc IResult.thenOnSuccess}
|
|
269
|
+
*/
|
|
270
|
+
thenOnSuccess(__) {
|
|
271
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
272
|
+
return AsyncResult.from(fail(this._message));
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* {@inheritDoc IResult.thenOnFailure}
|
|
276
|
+
*/
|
|
277
|
+
thenOnFailure(cb) {
|
|
278
|
+
try {
|
|
279
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
280
|
+
return new AsyncResult(cb(this._message));
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
284
|
+
return AsyncResult.from(fail(_errorMessage(err)));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
245
287
|
/**
|
|
246
288
|
* {@inheritDoc IResult.withErrorFormat}
|
|
247
289
|
*/
|
|
@@ -610,13 +652,25 @@ function propagateWithDetail(result, detail, successDetail) {
|
|
|
610
652
|
? succeedWithDetail(result.value, successDetail !== null && successDetail !== void 0 ? successDetail : detail)
|
|
611
653
|
: failWithDetail(result.message, detail);
|
|
612
654
|
}
|
|
655
|
+
/**
|
|
656
|
+
* Extracts a message string from an unknown thrown/rejected value.
|
|
657
|
+
* @param err - The caught error value.
|
|
658
|
+
* @returns The error message string.
|
|
659
|
+
* @internal
|
|
660
|
+
*/
|
|
661
|
+
function _errorMessage(err) {
|
|
662
|
+
if (err instanceof Error) {
|
|
663
|
+
return err.message;
|
|
664
|
+
}
|
|
665
|
+
return String(err);
|
|
666
|
+
}
|
|
613
667
|
/**
|
|
614
668
|
* Wraps a function which might throw to convert exception results
|
|
615
669
|
* to {@link Failure}.
|
|
616
670
|
* @param func - The function to be captured.
|
|
617
671
|
* @returns Returns {@link Success} with a value of type `<T>` on
|
|
618
672
|
* success , or {@link Failure} with the thrown error message if
|
|
619
|
-
* `func` throws an `Error
|
|
673
|
+
* `func` throws an `Error` or string.
|
|
620
674
|
* @public
|
|
621
675
|
*/
|
|
622
676
|
function captureResult(func) {
|
|
@@ -624,7 +678,181 @@ function captureResult(func) {
|
|
|
624
678
|
return succeed(func());
|
|
625
679
|
}
|
|
626
680
|
catch (err) {
|
|
627
|
-
return fail(err
|
|
681
|
+
return fail(_errorMessage(err));
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Wraps a `Promise` of a {@link Result} to enable fluent chaining of both
|
|
686
|
+
* synchronous and asynchronous operations.
|
|
687
|
+
*
|
|
688
|
+
* @remarks
|
|
689
|
+
* `AsyncResult<T>` implements `PromiseLike` so it can be directly `await`ed.
|
|
690
|
+
* Use the `thenOnSuccess` and `thenOnFailure` methods on {@link Result} to bridge
|
|
691
|
+
* from synchronous to asynchronous result chains.
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* ```typescript
|
|
695
|
+
* const result: Result<Final> = await parseInput(input)
|
|
696
|
+
* .thenOnSuccess(async (parsed) => fetchData(parsed))
|
|
697
|
+
* .onSuccess((data) => transform(data))
|
|
698
|
+
* .thenOnSuccess(async (transformed) => saveData(transformed))
|
|
699
|
+
* .withErrorFormat((msg) => `pipeline failed: ${msg}`);
|
|
700
|
+
* ```
|
|
701
|
+
*
|
|
702
|
+
* @public
|
|
703
|
+
*/
|
|
704
|
+
class AsyncResult {
|
|
705
|
+
/**
|
|
706
|
+
* Constructs an {@link AsyncResult} wrapping the supplied promise.
|
|
707
|
+
* @remarks
|
|
708
|
+
* If the supplied promise rejects, the rejection is caught and converted
|
|
709
|
+
* to a {@link Failure}, ensuring that awaiting an {@link AsyncResult} always
|
|
710
|
+
* yields a {@link Result}.
|
|
711
|
+
* @param promise - A `Promise` that resolves to a {@link Result}.
|
|
712
|
+
*/
|
|
713
|
+
constructor(promise) {
|
|
714
|
+
this._promise = promise.catch((err) => fail(_errorMessage(err)));
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Calls a supplied {@link SuccessContinuation | success continuation} if
|
|
718
|
+
* the wrapped result is successful.
|
|
719
|
+
* @param cb - The synchronous {@link SuccessContinuation | success continuation}
|
|
720
|
+
* to be called in the event of success.
|
|
721
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
722
|
+
*/
|
|
723
|
+
onSuccess(cb) {
|
|
724
|
+
return new AsyncResult(this._promise.then((r) => r.onSuccess(cb)));
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Calls a supplied {@link AsyncSuccessContinuation | async success continuation} if
|
|
728
|
+
* the wrapped result is successful.
|
|
729
|
+
* @remarks
|
|
730
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
731
|
+
* and converted to a {@link Failure}.
|
|
732
|
+
* @param cb - The {@link AsyncSuccessContinuation | async success continuation}
|
|
733
|
+
* to be called in the event of success.
|
|
734
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
735
|
+
*/
|
|
736
|
+
thenOnSuccess(cb) {
|
|
737
|
+
return new AsyncResult(this._promise.then(async (r) => {
|
|
738
|
+
if (r.isFailure()) {
|
|
739
|
+
return fail(r.message);
|
|
740
|
+
}
|
|
741
|
+
try {
|
|
742
|
+
return await cb(r.value);
|
|
743
|
+
}
|
|
744
|
+
catch (err) {
|
|
745
|
+
return fail(_errorMessage(err));
|
|
746
|
+
}
|
|
747
|
+
}));
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Calls a supplied {@link FailureContinuation | failure continuation} if
|
|
751
|
+
* the wrapped result is a failure.
|
|
752
|
+
* @param cb - The synchronous {@link FailureContinuation | failure continuation}
|
|
753
|
+
* to be called in the event of failure.
|
|
754
|
+
* @returns A new {@link AsyncResult} wrapping the continuation result.
|
|
755
|
+
*/
|
|
756
|
+
onFailure(cb) {
|
|
757
|
+
return new AsyncResult(this._promise.then((r) => r.onFailure(cb)));
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Calls a supplied {@link AsyncFailureContinuation | async failure continuation} if
|
|
761
|
+
* the wrapped result is a failure.
|
|
762
|
+
* @remarks
|
|
763
|
+
* Both synchronous throws and async rejections from the callback are caught
|
|
764
|
+
* and converted to a {@link Failure}.
|
|
765
|
+
* @param cb - The {@link AsyncFailureContinuation | async failure continuation}
|
|
766
|
+
* to be called in the event of failure.
|
|
767
|
+
* @returns A new {@link AsyncResult} wrapping the async continuation result.
|
|
768
|
+
*/
|
|
769
|
+
thenOnFailure(cb) {
|
|
770
|
+
return new AsyncResult(this._promise.then(async (r) => {
|
|
771
|
+
if (r.isSuccess()) {
|
|
772
|
+
return r;
|
|
773
|
+
}
|
|
774
|
+
try {
|
|
775
|
+
return await cb(r.message);
|
|
776
|
+
}
|
|
777
|
+
catch (err) {
|
|
778
|
+
return fail(_errorMessage(err));
|
|
779
|
+
}
|
|
780
|
+
}));
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Calls a supplied {@link ErrorFormatter | error formatter} if
|
|
784
|
+
* the wrapped result is a failure.
|
|
785
|
+
* @param cb - The {@link ErrorFormatter | error formatter} to
|
|
786
|
+
* be called in the event of failure.
|
|
787
|
+
* @returns A new {@link AsyncResult} with the formatted error message,
|
|
788
|
+
* or the original success result.
|
|
789
|
+
*/
|
|
790
|
+
withErrorFormat(cb) {
|
|
791
|
+
return new AsyncResult(this._promise.then((r) => r.withErrorFormat(cb)));
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Propagates the wrapped result, appending any error message to the
|
|
795
|
+
* supplied errors aggregator.
|
|
796
|
+
* @param errors - {@link IMessageAggregator | Error aggregator} in which
|
|
797
|
+
* errors will be aggregated.
|
|
798
|
+
* @param formatter - An optional {@link ErrorFormatter | error formatter}
|
|
799
|
+
* to be used to format the error message.
|
|
800
|
+
* @returns A new {@link AsyncResult} wrapping the result after aggregation.
|
|
801
|
+
*/
|
|
802
|
+
aggregateError(errors, formatter) {
|
|
803
|
+
return new AsyncResult(this._promise.then((r) => {
|
|
804
|
+
r.aggregateError(errors, formatter);
|
|
805
|
+
return r;
|
|
806
|
+
}));
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Reports the wrapped result to the supplied reporter.
|
|
810
|
+
* @param reporter - The {@link IResultReporter | reporter} to which the result
|
|
811
|
+
* will be reported.
|
|
812
|
+
* @param options - The {@link IResultReportOptions | options} for reporting the result.
|
|
813
|
+
* @returns A new {@link AsyncResult} wrapping the result after reporting.
|
|
814
|
+
*/
|
|
815
|
+
report(reporter, options) {
|
|
816
|
+
return new AsyncResult(this._promise.then((r) => {
|
|
817
|
+
r.report(reporter, options);
|
|
818
|
+
return r;
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Implementation of `PromiseLike.then` enabling `await` on {@link AsyncResult}.
|
|
823
|
+
* @param onfulfilled - Callback invoked when the promise resolves.
|
|
824
|
+
* @param onrejected - Callback invoked when the promise rejects.
|
|
825
|
+
* @returns A `Promise` resolving to the callback result.
|
|
826
|
+
*/
|
|
827
|
+
/* eslint-disable @rushstack/no-new-null */
|
|
828
|
+
then(onfulfilled, onrejected) {
|
|
829
|
+
/* eslint-enable @rushstack/no-new-null */
|
|
830
|
+
return this._promise.then(onfulfilled, onrejected);
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Creates an {@link AsyncResult} from a {@link Result}.
|
|
834
|
+
* @param result - The {@link Result} to wrap.
|
|
835
|
+
* @returns A new {@link AsyncResult} wrapping the supplied result.
|
|
836
|
+
*/
|
|
837
|
+
static from(result) {
|
|
838
|
+
return new AsyncResult(Promise.resolve(result));
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
exports.AsyncResult = AsyncResult;
|
|
842
|
+
/**
|
|
843
|
+
* Wraps an async function which might throw to convert exception results
|
|
844
|
+
* to {@link Failure}.
|
|
845
|
+
* @param func - The async function to be captured.
|
|
846
|
+
* @returns Returns a `Promise` of {@link Success} with a value of type `<T>` on
|
|
847
|
+
* success, or {@link Failure} with the thrown error message if `func` throws or rejects.
|
|
848
|
+
* @public
|
|
849
|
+
*/
|
|
850
|
+
async function captureAsyncResult(func) {
|
|
851
|
+
try {
|
|
852
|
+
return succeed(await func());
|
|
853
|
+
}
|
|
854
|
+
catch (err) {
|
|
855
|
+
return fail(_errorMessage(err));
|
|
628
856
|
}
|
|
629
857
|
}
|
|
630
858
|
//# sourceMappingURL=result.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fgv/ts-utils",
|
|
3
|
-
"version": "5.1.0-
|
|
3
|
+
"version": "5.1.0-12",
|
|
4
4
|
"description": "Assorted Typescript Utilities",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"@rushstack/heft-jest-plugin": "1.2.6",
|
|
55
55
|
"eslint-plugin-tsdoc": "~0.5.2",
|
|
56
56
|
"typedoc": "~0.28.16",
|
|
57
|
-
"@fgv/heft-dual-rig": "5.1.0-
|
|
58
|
-
"@fgv/typedoc-compact-theme": "5.1.0-
|
|
57
|
+
"@fgv/heft-dual-rig": "5.1.0-12",
|
|
58
|
+
"@fgv/typedoc-compact-theme": "5.1.0-12"
|
|
59
59
|
},
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|