Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import type { Boom } from "@hapi/boom";

/**
* Possible type matching rule. One of:
* - An error constructor (e.g. `SyntaxError`).
* - `'system'` - matches any language native error or node assertions.
* - `'boom'` - matches [**boom**](https://github.com/hapijs/boom) errors.
* - `'abort'` - matches an `AbortError`, as generated on an `AbortSignal` by `AbortController.abort()`.
* - `'timeout'` - matches a `TimeoutError`, as generated by `AbortSignal.timeout(delay)`.
* - an object where each property is compared with the error and must match the error property
* value. All the properties in the object must match the error but do not need to include all
* the error properties.
*/
type TypeRule = 'system' | 'boom' | 'abort' | 'timeout' | ErrorConstructor | { [key: PropertyKey]: any };

type Decoration = { [key: string]: any };

interface BounceOptions {

/**
* An object which is assigned to the `err`, copying the properties onto the error.
*/
decorate?: { [key: string]: any };

/**
* An error used to override `err` when `err` matches.
* If used with `decorate`, the `override` object is modified.
*/
override?: Error;

/**
* If `true`, the error is returned instead of thrown. Defaults to `false`.
*/
return?: boolean;
}

/**
* Throws the error passed if it matches any of the specified rules.
*
* @param err - the error object to test.
* @param type - a single {@link TypeRule `TypeRule`} or an array of {@link TypeRule `TypeRule`}.
* @param options - optional {@link BounceOptions settings}.
*
* @returns possibly an `Error` depending on value of the `return` and `decorate` options.
*/
export function rethrow<E extends Error, D extends Decoration>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D, override: E }): (E & D) | undefined;
export function rethrow<T extends object, D extends Decoration>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D }): (T & D) | undefined;
export function rethrow<E extends Error>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, override: E }): E | undefined;
export function rethrow<T>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true }): T | undefined;
export function rethrow(err: any, types: TypeRule | TypeRule[], options?: BounceOptions): void;

/**
* The opposite action of {@link rethrow `rethrow()`}. Ignores any errors matching the specified `types`.
* Any error not matching is thrown after applying the `options`.
*
* @param err - the error object to test.
* @param type - a single {@link TypeRule `TypeRule`} or an array of {@link TypeRule `TypeRule`}.
* @param options - optional {@link BounceOptions settings}.
*
* @returns possibly an `Error` depending on value of the `return` and `decorate` options.
*/
export function ignore<E extends Error, D extends Decoration>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D, override: E }): (E & D) | undefined;
export function ignore<T extends object, D extends Decoration>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, decorate: D }): (T & D) | undefined;
export function ignore<E extends Error>(err: any, types: TypeRule | TypeRule[], options: BounceOptions & { return: true, override: E }): E | undefined;
export function ignore<T>(err: T, types: TypeRule | TypeRule[], options: BounceOptions & { return: true }): T | undefined;
export function ignore(err: any, types: 'boom', options: { return?: false | undefined }): asserts err is Boom;
export function ignore(err: any, types: 'boom'): asserts err is Boom;
export function ignore(err: any, types: TypeRule | TypeRule[], options: { return?: false | undefined }): asserts err is Error;
export function ignore(err: any, types: TypeRule | TypeRule[]): asserts err is Error;
export function ignore(err: any, types: TypeRule | TypeRule[], options?: BounceOptions): void;

type Action = 'rethrow' | 'ignore';

/**
* Awaits for the value to resolve in the background and then apply either the {@link rethrow `rethrow()`} or {@link rethrow `ignore()`} action.
*
* @param operation - a function, promise, or value that is `await`ed on inside a `try...catch`
* and any error thrown processed by the `action` rule.
* @param action - one of `'rethrow'` or`'ignore'`. Defaults to`'rethrow'`.
* @param types - same as the `types` argument passed to {@link rethrow `rethrow()`} or {@link rethrow `ignore()`}. Defaults to `'system'`.
* @param options - same as the {@link BounceOptions `options`} argument passed to {@link rethrow `rethrow()`} or {@link rethrow `ignore()`}.
*/
export function background<E extends Error, D extends Decoration>(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions & { return: true, override: E, decorate: D }): Promise<(E & D) | undefined>;
export function background<E extends Error>(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions & { return: true, override: E }): Promise<E | undefined>;
export function background(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions & { return: true }): Promise<any>;
export function background(operation: any, action?: Action, types?: TypeRule | TypeRule[], options?: BounceOptions): Promise<void>;

/**
* Returns `true` when `err` is a [**boom**](https://github.com/hapijs/boom) error.
*
* @param err - Object to test.
*/
export function isBoom(err: unknown): err is Boom;

/**
* Returns `true` when `err` is an error.
*
* @param err - Object to test.
*/
export function isError(err: unknown): err is Error;

/**
* Return `true` when `err` is one of:
* - `EvalError`
* - `RangeError`
* - `ReferenceError`
* - `SyntaxError`
* - `TypeError`
* - `URIError`
* - Node's `AssertionError`
* - Hoek's `AssertError`
*
* @param err - Object to test.
*/
export function isSystem(err: unknown): err is Error;

/**
* Returns `true` when `err` is an `AbortError`, as generated by `AbortSignal.abort()`.
*
* Note that unlike other errors, `AbortError` cannot be considered a class in itself.
* The best way to create a custom `AbortError` is with `new DOMException(message, 'AbortError')`.
*
* @param err - Object to test.
*/
export function isAbort(err: unknown): err is Error & { name: 'AbortError' };

/**
* Returns `true` when `err` is a `TimeoutError`, as generated by `AbortSignal.timeout(delay)`.
*
* Note that unlike other errors, `TimeoutError` cannot be considered a class in itself.
* The best way to create a custom `TimeoutError` is with `new DOMException(message, 'TimeoutError')`.
*
* @param err - Object to test.
*/
export function isTimeout(err: unknown): err is Error & { name: 'TimeoutError' };
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"version": "3.0.1",
"repository": "git://github.com/hapijs/bounce",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib"
],
Expand All @@ -18,10 +19,12 @@
"devDependencies": {
"@hapi/code": "^9.0.0",
"@hapi/eslint-plugin": "^7.0.0",
"@hapi/lab": "^26.0.0"
"@hapi/lab": "^26.0.0",
"@types/node": "^18.19.57",
"typescript": "~5.6.3"
},
"scripts": {
"test": "lab -a @hapi/code -t 100 -L",
"test": "lab -a @hapi/code -t 100 -L -Y",
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html -L"
},
"license": "BSD-3-Clause"
Expand Down
130 changes: 130 additions & 0 deletions test/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import * as Bounce from '..';
import * as Boom from '@hapi/boom';
import * as Lab from '@hapi/lab';

const { expect } = Lab.types;

// rethrow()

expect.type<void>(Bounce.rethrow(new Error(), 'system'));
expect.type<void>(Bounce.rethrow(123, 'boom'));
expect.type<void>(Bounce.rethrow(new TypeError(), ['boom', RangeError, { prop: true }]));
expect.type<TypeError | undefined>(Bounce.rethrow(new TypeError(), 'boom', { return: true }));
expect.type<RangeError | undefined>(Bounce.rethrow(null, 'boom', { return: true, override: new RangeError() }));
expect.type<(TypeError & { prop: string }) | undefined>(Bounce.rethrow(new TypeError(), 'boom', { return: true, decorate: { prop: 'ok' } }));

expect.error(Bounce.rethrow(new Error()));
expect.error(Bounce.rethrow(new Error(), 'unknown'));
expect.error(Bounce.rethrow(new Error(), 'boom', true));
expect.error(Bounce.rethrow(new Error(), 'boom', { unknown: true }));
expect.error(Bounce.rethrow(new Error(), 'boom', { decorate: 123 }));
expect.error(Bounce.rethrow(new Error(), 'boom', { override: {} }));

// ignore()

expect.type<void>(Bounce.ignore(new TypeError(), 'system'));
expect.type<void>(Bounce.ignore(new Boom.Boom(), 'boom'));
expect.type<void>(Bounce.ignore(new RangeError(), ['boom', RangeError, { prop: true }]));
expect.type<TypeError | undefined>(Bounce.ignore(new TypeError(), 'boom', { return: true }));
expect.type<RangeError | undefined>(Bounce.ignore(null, 'boom', { return: true, override: new RangeError() }));
expect.type<(TypeError & { prop: string }) | undefined>(Bounce.ignore(new TypeError(), 'boom', { return: true, decorate: { prop: 'ok' } }));

// Narrows the error type

{
const error = new TypeError() as any;
Bounce.ignore(error, TypeError);
expect.type<Error>(error);
}

{
const error = new Boom.Boom() as any;
Bounce.ignore(error, 'boom');
expect.type<Boom.Boom>(error);
}

expect.error(Bounce.ignore(new Error()));
expect.error(Bounce.ignore(new Error(), 'unknown'));
expect.error(Bounce.ignore(new Error(), 'boom', true));
expect.error(Bounce.ignore(new Error(), 'boom', { unknown: true }));
expect.error(Bounce.ignore(new Error(), 'boom', { decorate: 123 }));
expect.error(Bounce.ignore(new Error(), 'boom', { override: {} }));

// background()

expect.type<Promise<void>>(Bounce.background(async () => undefined, 'ignore', 'system', { decorate: { a: true } }));
expect.type<Promise<any>>(Bounce.background(async () => undefined, 'rethrow', [RangeError], { return: true }));
expect.type<Promise<TypeError | undefined>>(Bounce.background(async () => undefined, undefined, undefined, { return: true, override: new TypeError() }));

expect.error(Bounce.background());
expect.error(Bounce.background(true, 'unknown'));

// isBoom()

expect.type<boolean>(Bounce.isBoom(new Error()));
expect.type<boolean>(Bounce.isBoom({}));
{
const obj = {};
if (Bounce.isBoom(obj)) {
expect.type<Boom.Boom>(obj); // Narrows type
}
}

expect.error(Bounce.isBoom());

// isError()

expect.type<boolean>(Bounce.isError(new Error()));
expect.type<boolean>(Bounce.isError(true));
{
const obj = {};
if (Bounce.isError(obj)) {
expect.type<Error>(obj); // Narrows type
}
}

expect.error(Bounce.isError());

// isSystem()

expect.type<boolean>(Bounce.isSystem(new Error()));
{
const err = new TypeError();
if (Bounce.isSystem(err)) {
expect.type<TypeError>(err); // Does not narrow type
}
}
{
const obj = {};
if (Bounce.isSystem(obj)) {
expect.type<Error>(obj); // Narrows type
}
}

expect.error(Bounce.isSystem());

// isAbort()

expect.type<boolean>(Bounce.isAbort(0));
{
const err = AbortSignal.abort().reason as any;
if (Bounce.isAbort(err)) {
expect.type<Error>(err); // Narrows type
expect.type<'AbortError'>(err.name); // Narrows name
}
}

expect.error(Bounce.isAbort());

// isTimeout()

expect.type<boolean>(Bounce.isTimeout(0));
{
const err = AbortSignal.timeout(1).reason as any;
if (Bounce.isTimeout(err)) {
expect.type<Error>(err); // Narrows type
expect.type<'TimeoutError'>(err.name); // Narrows name
}
}

expect.error(Bounce.isTimeout());
Loading