diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 7e8acac..1fdc05e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,8 @@ # These are supported funding model platforms -github: [lambdalisue] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: [ + lambdalisue, +] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username diff --git a/README.md b/README.md index 6d6951e..302b7ed 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,10 @@ assertThrows( import { assertEquals } from "@std/assert"; import { attempt } from "@core/errorutil/attempt"; -assertEquals(attempt(() => 42), [undefined, 42]); +assertEquals( + attempt(() => 42), + [undefined, 42], +); assertEquals( attempt(() => { throw "err"; @@ -50,6 +53,26 @@ assertEquals( ); ``` +## asyncAttempt + +`asyncAttempt` is a function that executes a async function and returns the +result (`Promise<[error: unknown, value: T]>`). If the function is successful, +it returns `Promise.resolve([undefined, value])`. If the function throws an +error, it returns `Promise.resolve([error, undefined])`. + +```ts +import { assertEquals } from "@std/assert"; +import { asyncAttempt } from "@core/errorutil/async-attempt"; + +assertEquals(await asyncAttempt(async () => 42), [undefined, 42]); +assertEquals( + await asyncAttempt(async () => { + throw "err"; + }), + ["err", undefined], +); +``` + ## ErrorObject `ErrorObject` is a class that wraps an error object for serialization. It is diff --git a/async_attempt.ts b/async_attempt.ts new file mode 100644 index 0000000..0608d5a --- /dev/null +++ b/async_attempt.ts @@ -0,0 +1,27 @@ +import type { Result } from "./attempt.ts"; + +export type AsyncResult = Promise>; + +/** + * Attempt to execute a async function and return a AsyncResult. + * + * @param fn - The function to execute. + * @returns A AsyncResult where T is the return type of the async function and E is the error type. + * + * @example + * ```ts + * import { asyncAttempt } from "@core/errorutil/async-attempt"; + * + * console.log(await asyncAttempt(async () => 1)); // [undefined, 1] + * console.log(await asyncAttempt(async () => { throw "err" })); // ["err", undefined] + * ``` + */ +export async function asyncAttempt( + fn: () => Promise, +): Promise> { + try { + return [undefined, await fn()]; + } catch (e) { + return [e as E, undefined]; + } +} diff --git a/async_attempt_test.ts b/async_attempt_test.ts new file mode 100644 index 0000000..61d2657 --- /dev/null +++ b/async_attempt_test.ts @@ -0,0 +1,13 @@ +import { test } from "@cross/test"; +import { assertEquals } from "@std/assert"; +import { asyncAttempt } from "./async_attempt.ts"; + +test("asyncAttempt should return a Success when the async function is successful", async () => { + const result = await asyncAttempt(() => Promise.resolve(1)); + assertEquals(result, [undefined, 1]); +}); + +test("asyncAttempt should return a Failure when the async function is failed", async () => { + const result = await asyncAttempt(() => Promise.reject("err")); + assertEquals(result, ["err", undefined]); +}); diff --git a/deno.jsonc b/deno.jsonc index 8512103..8b76c54 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -5,6 +5,7 @@ ".": "./mod.ts", "./alter": "./alter.ts", "./alter-else": "./alter_else.ts", + "./async-attempt": "./async_attempt.ts", "./attempt": "./attempt.ts", "./error-object": "./error_object.ts", "./raise": "./raise.ts", @@ -13,25 +14,16 @@ "./unimplemented": "./unimplemented.ts", "./unreachable": "./unreachable.ts" }, - "exclude": [ - ".coverage/**" - ], + "exclude": [".coverage/**"], "publish": { - "include": [ - "**/*.ts", - "README.md", - "LICENSE" - ], - "exclude": [ - "**/*_bench.ts", - "**/*_test.ts", - ".*" - ] + "include": ["**/*.ts", "README.md", "LICENSE"], + "exclude": ["**/*_bench.ts", "**/*_test.ts", ".*"] }, "imports": { "@core/errorutil": "./mod.ts", "@core/errorutil/alter": "./alter.ts", "@core/errorutil/alter-else": "./alter_else.ts", + "@core/errorutil/async-attempt": "./async_attempt.ts", "@core/errorutil/attempt": "./attempt.ts", "@core/errorutil/error-object": "./error_object.ts", "@core/errorutil/raise": "./raise.ts", diff --git a/mod.ts b/mod.ts index 1088c23..2c11f50 100644 --- a/mod.ts +++ b/mod.ts @@ -1,5 +1,6 @@ export * from "./alter.ts"; export * from "./alter_else.ts"; +export * from "./async_attempt.ts"; export * from "./attempt.ts"; export * from "./error_object.ts"; export * from "./raise.ts";