diff --git a/__tests__/try.spec.ts b/__tests__/try.spec.ts index e3d5952..2b648f5 100644 --- a/__tests__/try.spec.ts +++ b/__tests__/try.spec.ts @@ -1,5 +1,6 @@ import { Try } from "@src/try"; import { ObjectError } from "@src/error/object.error"; +import { AsyncMethodError } from "@src/error/async.method.error"; class FirstCustomError extends Error {} class ChildOfFirstCustomError extends FirstCustomError {} @@ -19,6 +20,48 @@ describe("Try", () => { expect(errorThrown).toBe(true); }); + + it("Should allow sync", async () => { + let errorThrown = false; + + Try.to(() => { + throw new FirstCustomError(); + }) + .catch(FirstCustomError, (error) => { + errorThrown = true; + }) + .runSync(); + + expect(errorThrown).toBe(true); + }); + + it("Should allow sync return", async () => { + const response = Try.to(() => { + return true; + }) + .runSync(); + + expect(response).toBe(true); + }); + + it("Should complain about sync", async () => { + expect(() => Try.to(async () => { + const a = true; + }) + .runSync()).toThrow(AsyncMethodError); + }); + + it("Should allow sync exception", async () => { + const result = Try.to(() => { + throw new FirstCustomError(); + }) + .catch(FirstCustomError, (error) => { + return true; + }) + .runSync(); + + expect(result).toBe(true); + }); it("Should allow error inheritance", async () => { let errorThrown = false; diff --git a/package.json b/package.json index 85bf6a3..6bb8b7c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@randock/try", - "version": "0.0.8", + "version": "0.0.11", "description": "Typed try/catch in typescript", "author": "Jop Peters", "private": false, diff --git a/src/error/async.method.error.ts b/src/error/async.method.error.ts new file mode 100644 index 0000000..a98d2f3 --- /dev/null +++ b/src/error/async.method.error.ts @@ -0,0 +1,6 @@ +export class AsyncMethodError extends Error { + constructor(message: string) { + super(message); + } + } + \ No newline at end of file diff --git a/src/try.ts b/src/try.ts index eec9ddd..0438e6a 100644 --- a/src/try.ts +++ b/src/try.ts @@ -1,3 +1,4 @@ +import { AsyncMethodError } from "./error/async.method.error"; import { ObjectError } from "./error/object.error"; export type AcceptFunction = (error: Error) => boolean; @@ -115,10 +116,71 @@ export class Try { return this.run(); } + runSync>(this: T): Response { + try { + const result = this.tryFunction(); + if (result instanceof Promise) { + throw new AsyncMethodError('Cannot cal runSync if returnType of to() is a Promise. Use run() instead.'); + } + + return result; + + } catch (e: any) { + if (e instanceof AsyncMethodError) { + throw e; + } + + // if it is not an error object, we will convert it + if (!(e instanceof Error)) { + e = new ObjectError("Non Error thrown as an error.", e); + } + + // we need to sort the catch block, so the "null" (is catch all) type goes last + this.catchBlocks.sort((a, b) => { + if (a.checker || b.checker) { + return a.checker ? -1 : 1; + } + + if (a.types.includes(null) && !b.types.includes(null)) { + return 1; + } else if (b.types.includes(null)) { + return -1; + } + + return 0; + }); + + // find the first matching catch block + for (const catchBlock of this.catchBlocks) { + if (catchBlock.types) { + for (const acceptedType of catchBlock.types) { + if (acceptedType === null || e instanceof acceptedType) { + return catchBlock.method(e); + } + } + } + + if (catchBlock.checker !== undefined) { + if (catchBlock.checker(e)) { + return catchBlock.method(e); + } + } + } + + // no matching block, so throw the error + throw e; + } finally { + if (this.finallyFunction !== null) { + this.finallyFunction(); + } + } + } + /** * You only need to call run, if you don't register a finally method */ async run>(this: T): Promise { + try { return await this.tryFunction(); } catch (e: any) {