mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-13 07:26:26 +00:00
feat: Support .catch
method for Result
(#23505)
This commit is contained in:
parent
894a18354b
commit
f28fc24201
2 changed files with 159 additions and 0 deletions
|
@ -107,6 +107,16 @@ describe('util/result', () => {
|
|||
.unwrap()
|
||||
).toThrow('oops');
|
||||
});
|
||||
|
||||
it('returns ok-value for unwrapOrThrow', () => {
|
||||
const res = Result.ok(42);
|
||||
expect(res.unwrapOrThrow()).toBe(42);
|
||||
});
|
||||
|
||||
it('throws error for unwrapOrThrow on error result', () => {
|
||||
const res = Result.err('oops');
|
||||
expect(() => res.unwrapOrThrow()).toThrow('oops');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Transforming', () => {
|
||||
|
@ -140,6 +150,36 @@ describe('util/result', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Catch', () => {
|
||||
it('bypasses ok result', () => {
|
||||
const res = Result.ok(42);
|
||||
expect(res.catch(() => Result.ok(0))).toEqual(Result.ok(42));
|
||||
expect(res.catch(() => Result.ok(0))).toBe(res);
|
||||
});
|
||||
|
||||
it('bypasses uncaught transform errors', () => {
|
||||
const res = Result.ok(42).transform(() => {
|
||||
throw 'oops';
|
||||
});
|
||||
expect(res.catch(() => Result.ok(0))).toEqual(Result._uncaught('oops'));
|
||||
expect(res.catch(() => Result.ok(0))).toBe(res);
|
||||
});
|
||||
|
||||
it('converts error to Result', () => {
|
||||
const result = Result.err<string>('oops').catch(() =>
|
||||
Result.ok<number>(42)
|
||||
);
|
||||
expect(result).toEqual(Result.ok(42));
|
||||
});
|
||||
|
||||
it('handles error thrown in catch function', () => {
|
||||
const result = Result.err<string>('oops').catch(() => {
|
||||
throw 'oops';
|
||||
});
|
||||
expect(result).toEqual(Result._uncaught('oops'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AsyncResult', () => {
|
||||
|
@ -222,6 +262,16 @@ describe('util/result', () => {
|
|||
const res = Result.wrap(Promise.reject('oops'));
|
||||
await expect(res.unwrap(42)).resolves.toBe(42);
|
||||
});
|
||||
|
||||
it('returns ok-value for unwrapOrThrow', async () => {
|
||||
const res = Result.wrap(Promise.resolve(42));
|
||||
await expect(res.unwrapOrThrow()).resolves.toBe(42);
|
||||
});
|
||||
|
||||
it('rejects for error for unwrapOrThrow', async () => {
|
||||
const res = Result.wrap(Promise.reject('oops'));
|
||||
await expect(res.unwrapOrThrow()).rejects.toBe('oops');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Transforming', () => {
|
||||
|
@ -367,5 +417,33 @@ describe('util/result', () => {
|
|||
expect(res).toEqual(Result.ok('F-O-O'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Catch', () => {
|
||||
it('converts error to AsyncResult', async () => {
|
||||
const result = await Result.err<string>('oops').catch(() =>
|
||||
AsyncResult.ok(42)
|
||||
);
|
||||
expect(result).toEqual(Result.ok(42));
|
||||
});
|
||||
|
||||
it('converts error to Promise', async () => {
|
||||
const fallback = Promise.resolve(Result.ok(42));
|
||||
const result = await Result.err<string>('oops').catch(() => fallback);
|
||||
expect(result).toEqual(Result.ok(42));
|
||||
});
|
||||
|
||||
it('handles error thrown in Promise result', async () => {
|
||||
const fallback = Promise.reject('oops');
|
||||
const result = await Result.err<string>('oops').catch(() => fallback);
|
||||
expect(result).toEqual(Result._uncaught('oops'));
|
||||
});
|
||||
|
||||
it('converts AsyncResult error to Result', async () => {
|
||||
const result = await AsyncResult.err<string>('oops').catch(() =>
|
||||
AsyncResult.ok<number>(42)
|
||||
);
|
||||
expect(result).toEqual(Result.ok(42));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -226,6 +226,17 @@ export class Result<T, E = Error> {
|
|||
return this.res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ok-value or throw the error.
|
||||
*/
|
||||
unwrapOrThrow(): NonNullable<T> {
|
||||
if (this.res.ok) {
|
||||
return this.res.val;
|
||||
}
|
||||
|
||||
throw this.res.err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the ok-value, sync or async way.
|
||||
*
|
||||
|
@ -301,6 +312,48 @@ export class Result<T, E = Error> {
|
|||
return Result._uncaught(err);
|
||||
}
|
||||
}
|
||||
|
||||
catch<U = T, EE = E>(
|
||||
fn: (err: NonNullable<E>) => Result<U, E | EE>
|
||||
): Result<T | U, E | EE>;
|
||||
catch<U = T, EE = E>(
|
||||
fn: (err: NonNullable<E>) => AsyncResult<U, E | EE>
|
||||
): AsyncResult<T | U, E | EE>;
|
||||
catch<U = T, EE = E>(
|
||||
fn: (err: NonNullable<E>) => Promise<Result<U, E | EE>>
|
||||
): AsyncResult<T | U, E | EE>;
|
||||
catch<U = T, EE = E>(
|
||||
fn: (
|
||||
err: NonNullable<E>
|
||||
) => Result<U, E | EE> | AsyncResult<U, E | EE> | Promise<Result<U, E | EE>>
|
||||
): Result<T | U, E | EE> | AsyncResult<T | U, E | EE> {
|
||||
if (this.res.ok) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (this.res._uncaught) {
|
||||
return this;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = fn(this.res.err);
|
||||
|
||||
if (result instanceof Promise) {
|
||||
return AsyncResult.wrap(result, (err) => {
|
||||
logger.warn(
|
||||
{ err },
|
||||
'Result: unexpected error in async catch handler'
|
||||
);
|
||||
return Result._uncaught(err);
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
logger.warn({ err }, 'Result: unexpected error in catch handler');
|
||||
return Result._uncaught(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -401,6 +454,14 @@ export class AsyncResult<T, E> implements PromiseLike<Result<T, E>> {
|
|||
: this.asyncResult.then<NonNullable<T>>((res) => res.unwrap(fallback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ok-value or throw the error.
|
||||
*/
|
||||
async unwrapOrThrow(): Promise<NonNullable<T>> {
|
||||
const result = await this.asyncResult;
|
||||
return result.unwrapOrThrow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the ok-value, sync or async way.
|
||||
*
|
||||
|
@ -484,4 +545,24 @@ export class AsyncResult<T, E> implements PromiseLike<Result<T, E>> {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
catch<U = T, EE = E>(
|
||||
fn: (err: NonNullable<E>) => Result<U, E | EE>
|
||||
): AsyncResult<T | U, E | EE>;
|
||||
catch<U = T, EE = E>(
|
||||
fn: (err: NonNullable<E>) => AsyncResult<U, E | EE>
|
||||
): AsyncResult<T | U, E | EE>;
|
||||
catch<U = T, EE = E>(
|
||||
fn: (err: NonNullable<E>) => Promise<Result<U, E | EE>>
|
||||
): AsyncResult<T | U, E | EE>;
|
||||
catch<U = T, EE = E>(
|
||||
fn: (
|
||||
err: NonNullable<E>
|
||||
) => Result<U, E | EE> | AsyncResult<U, E | EE> | Promise<Result<U, E | EE>>
|
||||
): AsyncResult<T | U, E | EE> {
|
||||
const caughtAsyncResult = this.asyncResult.then((result) =>
|
||||
result.catch(fn as never)
|
||||
);
|
||||
return AsyncResult.wrap(caughtAsyncResult);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue