From 978e119fa252e280221307847b0e34976d353c40 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 4 Oct 2024 15:23:59 -0700 Subject: [PATCH 1/5] Make either an array and an object --- jsr.json | 3 +- package.json | 5 -- src/Either.ts | 31 ++++++++- src/go/Either.ts | 45 +++++++++++-- src/go/mightFail.ts | 10 +-- src/mightFail.ts | 18 ++--- src/tuple/Either.ts | 12 ---- src/tuple/index.ts | 23 ------- src/tuple/makeMightFail.ts | 85 ------------------------ src/tuple/mightFail.ts | 99 ---------------------------- src/utils.type.ts | 23 +------ test/go/mightFail.test.ts | 15 +++-- test/tuple/makeMightFail.test.ts | 2 +- test/tuple/makeMightFailSync.test.ts | 2 +- test/tuple/mightFail.test.ts | 17 +++-- test/tuple/mightFailSync.test.ts | 2 +- 16 files changed, 107 insertions(+), 285 deletions(-) delete mode 100644 src/tuple/Either.ts delete mode 100644 src/tuple/index.ts delete mode 100644 src/tuple/makeMightFail.ts delete mode 100644 src/tuple/mightFail.ts diff --git a/jsr.json b/jsr.json index ea6e460..9d0f5f8 100644 --- a/jsr.json +++ b/jsr.json @@ -3,8 +3,7 @@ "version": "0.5.1", "exports": { ".": "./src/index.ts", - "./go": "./src/go/index.ts", - "./tuple": "./src/tuple/index.ts" + "./go": "./src/go/index.ts" }, "license": "MIT" } diff --git a/package.json b/package.json index cab029c..c2af7af 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,6 @@ "require": "./dist/cjs/index.js", "types": "./dist/index.d.ts" }, - "./tuple": { - "import": "./dist/tuple/index.js", - "require": "./dist/cjs/tuple/index.js", - "types": "./dist/tuple/index.d.ts" - }, "./go": { "import": "./dist/go/index.js", "require": "./dist/cjs/go/index.js", diff --git a/src/Either.ts b/src/Either.ts index e74c049..9688138 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1,3 +1,4 @@ + /** * Either type represents a data structure that encapsulates a successful result or an Error. * It wraps the result of a Promise in an object, making it easier to handle errors by returning @@ -6,11 +7,37 @@ * @template T The type of the result value. */ export type Either = + | ({ + error: Error + result: undefined + } & [Error, undefined]) + | ({ + result: T + error: undefined + } & [undefined, T]) + +export const createEither = ({ + result, + error, +}: | { error: Error result: undefined } | { - result: T error: undefined - } + result: T + }): Either => { + if (error) { + const array: [Error, undefined] = [error, undefined] + const obj = Object.create(array) + obj.error = error + obj.result = undefined + return obj + } + const array: [undefined, T] = [undefined, result] + const obj = Object.create(array) + obj.error = undefined + obj.result = result + return obj +} diff --git a/src/go/Either.ts b/src/go/Either.ts index c3ef383..6e7601f 100644 --- a/src/go/Either.ts +++ b/src/go/Either.ts @@ -1,12 +1,43 @@ + /** - * Either type represents a tuple that encapsulates a successful result or an Error. - * - * `[undefined, Error]` represents a failed result. - * `[T, undefined]` represents a successful result. - * + * Either type represents a data structure that encapsulates a successful result or an Error. * It wraps the result of a Promise in an object, making it easier to handle errors by returning - * an array that either contains a 'result' value of type T (if successful), or an 'error' of type Error. + * an object that either contains a 'result' value of type T (if successful), or an 'error' of type Error. * * @template T The type of the result value. */ -export type Either = [undefined, Error] | [T, undefined] +export type Either = + | ({ + error: Error + result: undefined + } & [undefined, Error]) + | ({ + result: T + error: undefined + } & [T, undefined]) + +export const createEither = ({ + result, + error, +}: + | { + error: Error + result: undefined + } + | { + error: undefined + result: T + }): Either => { + if (error) { + const array: [undefined, Error] = [undefined, error] + const obj = Object.create(array) + obj.error = error + obj.result = undefined + return obj + } + const array: [T, undefined] = [result, undefined] + const obj = Object.create(array) + obj.error = undefined + obj.result = result + return obj +} diff --git a/src/go/mightFail.ts b/src/go/mightFail.ts index dc84a8d..6b293c9 100644 --- a/src/go/mightFail.ts +++ b/src/go/mightFail.ts @@ -1,11 +1,11 @@ import standard from "../index" -import { type Either } from "./Either" +import { type Either, createEither } from "./Either" import { makeProxyHandler } from "../utils" import { MightFail, MightFailFunction, NonUndefined } from "../utils.type" const mightFailFunction: MightFailFunction<"go"> = async function (promise: Promise) { const { result, error } = await standard.mightFailFunction(promise) - return error ? [undefined, error] : [result, undefined] + return error ? createEither({ result: undefined, error }) : createEither({ result, error: undefined }) } /** @@ -69,7 +69,7 @@ export const mightFail: MightFail<"go"> = new Proxy( */ export function mightFailSync(func: () => T): Either { const { result, error } = standard.mightFailSync(func) - return error ? [undefined, error] : [result, undefined] + return error ? createEither({ result: undefined, error }) : createEither({ result, error: undefined }) } @@ -81,7 +81,7 @@ export function mightFailSync(func: () => T): Either { */ export function Might(result: NonUndefined): Either { const standardMight = standard.Might(result) - return [standardMight.result as T, undefined] + return createEither({ result: standardMight.result as T, error: undefined }) } /** @@ -94,5 +94,5 @@ export function Might(result: NonUndefined): Either { */ export function Fail(error: unknown): Either { const standardFail = standard.Fail(error) - return [undefined, standardFail.error] + return createEither({ result: undefined, error: standardFail.error }) } diff --git a/src/mightFail.ts b/src/mightFail.ts index 2d202ad..89885ff 100644 --- a/src/mightFail.ts +++ b/src/mightFail.ts @@ -1,16 +1,19 @@ -import { type Either } from "./Either" +import { type Either, createEither } from "./Either" import { handleError, makeProxyHandler } from "./utils" import { MightFail, MightFailFunction, NonUndefined } from "./utils.type" + + + export const mightFailFunction: MightFailFunction<"standard"> = async function ( promise: Promise ): Promise> { try { const result = await promise - return { error: undefined, result } as Either + return createEither({result, error: undefined}) } catch (err) { const error = handleError(err) - return { error, result: undefined } + return createEither({ error, result: undefined }) } } @@ -78,14 +81,13 @@ export const mightFail: MightFail<"standard"> = new Proxy( export function mightFailSync(func: () => T): Either { try { const result = func() - return { error: undefined, result } + return createEither({ error: undefined, result }) } catch (err) { const error = handleError(err) - return { error, result: undefined } + return createEither({ error, result: undefined }) } } - /** * A pure constructor function that takes a non-null value and returns an Either object with the value as the result and undefined as the error. * @@ -93,7 +95,7 @@ export function mightFailSync(func: () => T): Either { * @constructor */ export function Might(result: NonUndefined): Either { - return { result, error: undefined } + return createEither({ result, error: undefined }) } /** @@ -105,5 +107,5 @@ export function Might(result: NonUndefined): Either { * @constructor */ export function Fail(error: unknown): Either { - return { result: undefined, error: handleError(error) } + return createEither({ result: undefined, error: handleError(error) }) } diff --git a/src/tuple/Either.ts b/src/tuple/Either.ts deleted file mode 100644 index 9044d37..0000000 --- a/src/tuple/Either.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Either type represents a tuple that encapsulates a successful result or an Error. - * - * `[Error, undefined]` represents a failed result. - * `[undefined, T]` represents a successful result. - * - * It wraps the result of a Promise in an object, making it easier to handle errors by returning - * an array that either contains a 'result' value of type T (if successful), or an 'error' of type Error. - * - * @template T The type of the result value. - */ -export type Either = [Error, undefined] | [undefined, T] diff --git a/src/tuple/index.ts b/src/tuple/index.ts deleted file mode 100644 index 5c86b4d..0000000 --- a/src/tuple/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @module - * - * This module contains the interface to use the result of mightFail as an error-first tuple. - * - * This mimics the behaviour of golang. - * - * If you want to use error-first style, use the `/tuple` module. - * -+ * @example -+ * ```ts -+ * import { mightFail } from "@might/fail/tuple"; -+ * -+ * const [result, error] = await mightFail(promise); -+ * ``` - */ - -import { type Either } from "./Either" -import { mightFail, mightFailSync, Might, Fail } from "./mightFail" -import { makeMightFail, makeMightFailSync } from "./makeMightFail" - -export { Either, mightFail, makeMightFail, mightFailSync, makeMightFailSync, Might, Fail } -export default { mightFail, makeMightFail, mightFailSync, makeMightFailSync, Might, Fail } diff --git a/src/tuple/makeMightFail.ts b/src/tuple/makeMightFail.ts deleted file mode 100644 index af8e481..0000000 --- a/src/tuple/makeMightFail.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { type Either } from "./Either" -import { mightFail, mightFailSync } from "./mightFail" - -/** - * Utility type that unwraps a Promise type. If T is a Promise, it extracts the type the Promise resolves to, - * providing direct access to the underlying value type. - * - * @template T The type to be unwrapped if it's a Promise. - */ -type UnwrapPromise = T extends Promise ? U : T - -/** - * Wraps a promise-returning function in another function that instead of returning a Promise directly, - * returns a Promise that resolves with an Either tuple. This allows for the handling of both resolved values and - * errors in a consistent, functional way. - * - * @export - * @template T The function type that returns a Promise. - * @param {T} func - The async function to be wrapped. This function should return a Promise. - * @return {Function} A new function that, when called, returns a Promise that resolves with an Either tuple. - * The Either tuple is [undefined, T] where T is the resolved value of the original Promise if successful, - * or [Error, undefined] if the Promise was rejected. - * - * @example - * // Example of wrapping an async function that might fail: - * async function fetchData(url: string): Promise { - * const response = await fetch(url); - * if (!response.ok) { - * throw new Error('Network response was not ok'); - * } - * return response.text(); - * } - * - * const safeFetchData = makeMightFail(fetchData); - * const [error, result] = await safeFetchData('https://example.com'); - * - * if (error) { - * console.error('Fetching failed:', error.message); - * return; - * } - * console.log('Fetched data:', result); - */ -export function makeMightFail Promise>( - func: T -): (...funcArgs: Parameters) => Promise>>> { - return async (...args: Parameters) => { - const promise = func(...args) - return mightFail(promise) - } -} - -/** - * Wraps a synchronous function that might throw an exception in another function that, - * instead of throwing, returns an Either tuple. This tuple contains either undefined as the first element - * and the value returned by the function as the second if it executes successfully, - * or an Error as the first element and undefined as the second if the function throws. - * - * @export - * @template T The function type that might throw an error. - * @param {T} func - The function to be wrapped. This function might throw an exception. - * @return {Function} A new function that, when called, returns an Either tuple with either [undefined, T] or [Error, undefined]. - * - * @example - * // Example of wrapping a synchronous function that might throw an error: - * function parseJSON(jsonString: string) { - * return JSON.parse(jsonString); // This might throw - * } - * - * const safeParseJSON = makeMightFailSync(parseJSON); - * const [error, result] = safeParseJSON('{"valid": "json"}'); - * - * if (error) { - * console.error('Parsing failed:', error); - * return; - * } - * console.log('Parsed object:', result); - */ -export function makeMightFailSync any>( - func: T -): (...funcArgs: Parameters) => Either> { - return (...args: Parameters) => { - const throwingFunction = () => func(...args) - return mightFailSync(throwingFunction) - } -} diff --git a/src/tuple/mightFail.ts b/src/tuple/mightFail.ts deleted file mode 100644 index 0f8595b..0000000 --- a/src/tuple/mightFail.ts +++ /dev/null @@ -1,99 +0,0 @@ -import standard from "../index" -import { type Either } from "./Either" -import { makeProxyHandler } from "../utils" -import { MightFail, MightFailFunction, NonUndefined } from "../utils.type" - -const mightFailFunction: MightFailFunction<"tuple"> = async function (promise: Promise) { - const { result, error } = await standard.mightFailFunction(promise) - return error ? [error, undefined] : [undefined, result] -} - -/** - * Wraps a promise in an Either tuple to safely handle both its resolution and rejection. This function - * takes a Promise of type T and returns a Promise which resolves with an Either tuple. This tuple - * either contains an Error as the first element and undefined as the second if the promise is rejected, - * or undefined as the first element and a 'result' of type T as the second if the promise resolves successfully. - * - * @export - * @template T The type of the result value. - * @param {Promise} promise - The promise to be wrapped in an Either. This is an asynchronous operation that - * should resolve with a value of type T or reject with an Error. - * @return {Promise>} A Promise that resolves with an Either tuple. This Either is [undefined, T] with - * the second element set to the value resolved by the promise if successful. In case of failure, it's [Error, undefined] - * with the first element being the Error. The Error will always be an instance of Error. - * - * @example - * // Example of wrapping an async function that might fail: - * async function fetchData(url: string): Promise { - * const response = await fetch(url); - * if (!response.ok) { - * throw new Error('Network response was not ok'); - * } - * return response.text(); - * } - * - * const [error, result] = await mightFail(fetchData('https://example.com')); - * - * if (error) { - * console.error('Fetching failed:', error.message); - * return; - * } - * console.log('Fetched data:', result); - */ -export const mightFail: MightFail<"tuple"> = new Proxy( - mightFailFunction, - makeProxyHandler(mightFailFunction) -) as MightFail<"tuple"> - -/** - * Wraps a synchronous function in an Either tuple to safely handle exceptions. This function - * executes a provided function that returns a value of type T, capturing any thrown errors. - * It returns a tuple that either contains an Error as the first element and undefined as the second - * if the function throws, or undefined as the first element and a value of type T as the second - * if the function succeeds. - * - * @export - * @template T The type of the result value. - * @param {() => T} func - A wrapper function that is expected to invoke the throwing function. - * That function should return a value of type T or throw an error. - * @return {Either} A tuple that is either [undefined, T] with the second element set to the value returned by `func`, - * or [Error, undefined] with the first element set to the caught error. - * @example - * // Example of wrapping a synchronous function that might throw an error: - * const [error, result] = mightFailSync(() => JSON.parse("")); - * - * if (error) { - * console.error('Parsing failed:', error); - * return; - * } - * console.log('Parsed object:', result); - */ -export function mightFailSync(func: () => T): Either { - const { result, error } = standard.mightFailSync(func) - return error ? [error, undefined] : [undefined, result] -} - - -/** - * A pure constructor function that takes a non-null value and returns an Either object with the value as the result and undefined as the error. - * - * @param result - * @constructor - */ -export function Might(result: NonUndefined): Either { - const standardMight = standard.Might(result) - return [undefined, standardMight.result as T] -} - -/** - * A constructor function that takes an error and returns an Either object with undefined as the result and the error as the error. - * - * The error will **always** be an instance of Error. - * - * @param error - * @constructor - */ -export function Fail(error: unknown): Either { - const standardFail = standard.Fail(error) - return [standardFail.error, undefined] -} diff --git a/src/utils.type.ts b/src/utils.type.ts index ce4d33b..f24bb95 100644 --- a/src/utils.type.ts +++ b/src/utils.type.ts @@ -1,18 +1,15 @@ import type { Either as StandardEither } from "./Either" -import type { Either as TupleEither } from "./tuple" import type { Either as GoEither } from "./go" -export type EitherMode = "standard" | "tuple" | "go" | "any" +export type EitherMode = "standard" | "go" | "any" -export type AnyEither = StandardEither | TupleEither | GoEither +export type AnyEither = StandardEither | GoEither export type MightFailFunction = ( promise: Promise ) => Promise< TEitherMode extends "standard" ? StandardEither - : TEitherMode extends "tuple" - ? TupleEither : TEitherMode extends "go" ? GoEither : AnyEither @@ -45,8 +42,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? Awaited> - : TEitherMode extends "tuple" - ? Awaited> : TEitherMode extends "go" ? Awaited> : Awaited> @@ -63,8 +58,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? StandardEither<{ -readonly [P in keyof T]: Awaited }> - : TEitherMode extends "tuple" - ? TupleEither<{ -readonly [P in keyof T]: Awaited }> : TEitherMode extends "go" ? GoEither<{ -readonly [P in keyof T]: Awaited }> : AnyEither<{ -readonly [P in keyof T]: Awaited }> @@ -82,8 +75,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? Awaited> - : TEitherMode extends "tuple" - ? Awaited> : TEitherMode extends "go" ? Awaited> : Awaited> @@ -100,8 +91,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? Awaited> - : TEitherMode extends "tuple" - ? Awaited> : TEitherMode extends "go" ? Awaited> : Awaited> @@ -118,8 +107,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? StandardEither<{ -readonly [P in keyof T]: PromiseSettledResult> }> - : TEitherMode extends "tuple" - ? TupleEither<{ -readonly [P in keyof T]: PromiseSettledResult> }> : TEitherMode extends "go" ? GoEither<{ -readonly [P in keyof T]: PromiseSettledResult> }> : AnyEither<{ -readonly [P in keyof T]: PromiseSettledResult> }> @@ -136,8 +123,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? StandardEither>[]> - : TEitherMode extends "tuple" - ? TupleEither>[]> : TEitherMode extends "go" ? GoEither>[]> : AnyEither>[]> @@ -155,8 +140,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? StandardEither> - : TEitherMode extends "tuple" - ? TupleEither> : TEitherMode extends "go" ? GoEither> : AnyEither> @@ -174,8 +157,6 @@ export interface PromiseStaticMethods { ): Promise< TEitherMode extends "standard" ? StandardEither> - : TEitherMode extends "tuple" - ? TupleEither> : TEitherMode extends "go" ? GoEither> : AnyEither> diff --git a/test/go/mightFail.test.ts b/test/go/mightFail.test.ts index 7deacd9..82c6229 100644 --- a/test/go/mightFail.test.ts +++ b/test/go/mightFail.test.ts @@ -127,21 +127,24 @@ describe("promise concurrent method wrappers", () => { describe("Either factories (Might & Fail)", () => { describe("Might", () => { it("should return an Either with the value as the result and undefined as the error", () => { - const result = Might(5) - expect(result).toEqual([5, undefined]) + const [result, error] = Might(5) + expect(result).toEqual(5) + expect(error).toEqual(undefined) }) }) describe("Fail", () => { it("should return an Either with undefined as the result and the error as the error", () => { const error = new Error("error") - const result = Fail(error) - expect(result).toEqual([undefined, error]) + const [failResult, failError] = Fail(error) + expect(failResult).toEqual(undefined) + expect(failError).toEqual(error) }) it("should return an Either with undefined as the result and the error must be an instance of Error", () => { const error = "error" - const result = Fail(error) - expect(result).toEqual([undefined, new Error(error)]) + const [failResult, failError] = Fail(error) + expect(failResult).toEqual(undefined) + expect(failError).toEqual(new Error(error)) }) }) }) diff --git a/test/tuple/makeMightFail.test.ts b/test/tuple/makeMightFail.test.ts index a08c5b2..b9ecc99 100644 --- a/test/tuple/makeMightFail.test.ts +++ b/test/tuple/makeMightFail.test.ts @@ -1,5 +1,5 @@ import { expect, test } from "vitest" -import { makeMightFail } from "../../src/tuple/index" +import { makeMightFail } from "../../src/index" test("success returns the response", async () => { const resolve = (value: { message: string }) => Promise.resolve(value) diff --git a/test/tuple/makeMightFailSync.test.ts b/test/tuple/makeMightFailSync.test.ts index 32b72a4..3c2545d 100644 --- a/test/tuple/makeMightFailSync.test.ts +++ b/test/tuple/makeMightFailSync.test.ts @@ -1,5 +1,5 @@ import { expect, test } from "vitest" -import { makeMightFailSync } from "../../src/tuple/index" +import { makeMightFailSync } from "../../src/index" function somethingThatThrows(input: string) { if (!input) { diff --git a/test/tuple/mightFail.test.ts b/test/tuple/mightFail.test.ts index bd2437d..7ec3f75 100644 --- a/test/tuple/mightFail.test.ts +++ b/test/tuple/mightFail.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, test } from "vitest" -import { mightFail, Might, Fail } from "../../src/tuple/index" +import { mightFail, Might, Fail } from "../../src/index" test("success returns the response", async () => { const [error, result] = await mightFail(Promise.resolve("success")) @@ -127,21 +127,24 @@ describe("promise concurrent method wrappers", () => { describe("Either factories (Might & Fail)", () => { describe("Might", () => { it("should return an Either with the value as the result and undefined as the error", () => { - const result = Might(5) - expect(result).toEqual([undefined, 5]) + const [errResult, resResult] = Might(5) + expect(errResult).toEqual(undefined) + expect(resResult).toEqual(5) }) }) describe("Fail", () => { it("should return an Either with undefined as the result and the error as the error", () => { const error = new Error("error") - const result = Fail(error) - expect(result).toEqual([error, undefined]) + const [errResult, resResult] = Fail(error) + expect(errResult).toEqual(error) + expect(resResult).toEqual(undefined) }) it("should return an Either with undefined as the result and the error must be an instance of Error", () => { const error = "error" - const result = Fail(error) - expect(result).toEqual([new Error(error), undefined]) + const [errResult, resResult] = Fail(error) + expect(errResult).toEqual(new Error(error)) + expect(resResult).toEqual(undefined) }) }) }) diff --git a/test/tuple/mightFailSync.test.ts b/test/tuple/mightFailSync.test.ts index a24a91c..efda2a1 100644 --- a/test/tuple/mightFailSync.test.ts +++ b/test/tuple/mightFailSync.test.ts @@ -1,5 +1,5 @@ import { expect, test } from "vitest" -import { mightFailSync } from "../../src/tuple/index" +import { mightFailSync } from "../../src/index" function somethingThatThrows(input: string) { if (!input) { From ddd5d2a326986e77dce4fc45acf0a910cca69602 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 4 Oct 2024 16:43:31 -0700 Subject: [PATCH 2/5] change it to a proxy everythin seems to act the same and the tests still pass, but now inspecting the results with something like console.log doesn't display a bunch of shit about arrays because it's **not** an array anymore --- examples/mightFailBasic.ts | 13 +++++++++++ examples/mightFailBasicTuple.ts | 4 ++-- src/Either.ts | 30 ++++++++++++++----------- src/go/Either.ts | 17 +++++++++----- src/utils.ts | 40 +++++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/examples/mightFailBasic.ts b/examples/mightFailBasic.ts index 13cdeb1..4387c64 100644 --- a/examples/mightFailBasic.ts +++ b/examples/mightFailBasic.ts @@ -10,3 +10,16 @@ async function main() { } main() +async function main2() { + const result = await mightFail(Promise.resolve({ message: "success" })) + console.log(result) +} + +main2() + +async function main3() { + const result = await mightFail(Promise.reject(new Error("error"))) + console.log(result) +} + +main3() diff --git a/examples/mightFailBasicTuple.ts b/examples/mightFailBasicTuple.ts index 382609c..d463275 100644 --- a/examples/mightFailBasicTuple.ts +++ b/examples/mightFailBasicTuple.ts @@ -1,7 +1,7 @@ -import { mightFail } from "../src/tuple" +import { mightFail } from "../src" async function main() { - const [result, error] = await mightFail(Promise.resolve({ message: "success" })) + const [error, result] = await mightFail(Promise.resolve({ message: "success" })) if (error) { console.error(error) return diff --git a/src/Either.ts b/src/Either.ts index 9688138..d1d8dfe 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1,3 +1,4 @@ +import { createArrayProxy } from "./utils" /** * Either type represents a data structure that encapsulates a successful result or an Error. @@ -28,16 +29,19 @@ export const createEither = ({ error: undefined result: T }): Either => { - if (error) { - const array: [Error, undefined] = [error, undefined] - const obj = Object.create(array) - obj.error = error - obj.result = undefined - return obj - } - const array: [undefined, T] = [undefined, result] - const obj = Object.create(array) - obj.error = undefined - obj.result = result - return obj -} + if (error) { + const array: [Error, undefined] = [error, undefined] + // const obj = Object.create(array) + const obj = {} as any + obj.error = error + obj.result = undefined + return createArrayProxy(obj, array) + } + const array: [undefined, T] = [undefined, result] + // const obj = Object.create(array) + const obj = {} as any + obj.error = undefined + obj.result = result + return createArrayProxy(obj, array) + } + \ No newline at end of file diff --git a/src/go/Either.ts b/src/go/Either.ts index 6e7601f..27bc886 100644 --- a/src/go/Either.ts +++ b/src/go/Either.ts @@ -1,4 +1,4 @@ - +import { createArrayProxy } from "../utils" /** * Either type represents a data structure that encapsulates a successful result or an Error. * It wraps the result of a Promise in an object, making it easier to handle errors by returning @@ -16,6 +16,11 @@ export type Either = error: undefined } & [T, undefined]) + + + + + export const createEither = ({ result, error, @@ -30,14 +35,16 @@ export const createEither = ({ }): Either => { if (error) { const array: [undefined, Error] = [undefined, error] - const obj = Object.create(array) + // const obj = Object.create(array) + const obj = {} as any obj.error = error obj.result = undefined - return obj + return createArrayProxy(obj, array) } const array: [T, undefined] = [result, undefined] - const obj = Object.create(array) + // const obj = Object.create(array) + const obj = {} as any obj.error = undefined obj.result = result - return obj + return createArrayProxy(obj, array) } diff --git a/src/utils.ts b/src/utils.ts index e473d1a..fdb6351 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -36,3 +36,43 @@ export const makeProxyHandler = (obj: any, array: (undefined | Error | T)[]) => { + // Proxy to intercept array methods and properties + return new Proxy(obj, { + get(target, prop, receiver) { + // If the property exists on the object itself, return it + if (prop in target) { + return Reflect.get(target, prop, receiver) + } + + // If the property exists on the internal array, proxy it + if (prop in array) { + const value = (array as any)[prop] // TypeScript array typing here + if (typeof value === "function") { + // Proxy array methods + return function (...args: any[]) { + console.log(`Array method called: ${String(prop)}, Arguments: ${args}`) + return value.apply(array, args) + } + } else { + // Return array properties (like length) + return value + } + } + + // Handle the iterator separately + if (prop === Symbol.iterator) { + const originalIterator = array[Symbol.iterator]() + return function* () { + for (let item of originalIterator) { + console.log(`Iterating item: ${item}`) + yield item + } + } + } + + return undefined + }, + }) +} From 52fd61d2d38cb0706d62074cd6946ed62e69934a Mon Sep 17 00:00:00 2001 From: Ilia Abedianamiri <37903573+iliaamiri@users.noreply.github.com> Date: Fri, 4 Oct 2024 23:15:27 -0700 Subject: [PATCH 3/5] chore: centralize the createEither utility function - clean up console.log and dead comments --- src/Either.ts | 31 ------------------------------- src/go/Either.ts | 34 ---------------------------------- src/go/mightFail.ts | 19 +++++++++++-------- src/mightFail.ts | 13 +++++-------- src/utils.ts | 37 +++++++++++++++++++++++++++++++++---- 5 files changed, 49 insertions(+), 85 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index d1d8dfe..fd964ff 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1,5 +1,3 @@ -import { createArrayProxy } from "./utils" - /** * Either type represents a data structure that encapsulates a successful result or an Error. * It wraps the result of a Promise in an object, making it easier to handle errors by returning @@ -16,32 +14,3 @@ export type Either = result: T error: undefined } & [undefined, T]) - -export const createEither = ({ - result, - error, -}: - | { - error: Error - result: undefined - } - | { - error: undefined - result: T - }): Either => { - if (error) { - const array: [Error, undefined] = [error, undefined] - // const obj = Object.create(array) - const obj = {} as any - obj.error = error - obj.result = undefined - return createArrayProxy(obj, array) - } - const array: [undefined, T] = [undefined, result] - // const obj = Object.create(array) - const obj = {} as any - obj.error = undefined - obj.result = result - return createArrayProxy(obj, array) - } - \ No newline at end of file diff --git a/src/go/Either.ts b/src/go/Either.ts index 27bc886..05e1ec4 100644 --- a/src/go/Either.ts +++ b/src/go/Either.ts @@ -1,4 +1,3 @@ -import { createArrayProxy } from "../utils" /** * Either type represents a data structure that encapsulates a successful result or an Error. * It wraps the result of a Promise in an object, making it easier to handle errors by returning @@ -15,36 +14,3 @@ export type Either = result: T error: undefined } & [T, undefined]) - - - - - - -export const createEither = ({ - result, - error, -}: - | { - error: Error - result: undefined - } - | { - error: undefined - result: T - }): Either => { - if (error) { - const array: [undefined, Error] = [undefined, error] - // const obj = Object.create(array) - const obj = {} as any - obj.error = error - obj.result = undefined - return createArrayProxy(obj, array) - } - const array: [T, undefined] = [result, undefined] - // const obj = Object.create(array) - const obj = {} as any - obj.error = undefined - obj.result = result - return createArrayProxy(obj, array) -} diff --git a/src/go/mightFail.ts b/src/go/mightFail.ts index 6b293c9..3f8c182 100644 --- a/src/go/mightFail.ts +++ b/src/go/mightFail.ts @@ -1,11 +1,13 @@ import standard from "../index" -import { type Either, createEither } from "./Either" -import { makeProxyHandler } from "../utils" +import { type Either } from "./Either" +import { createEither, makeProxyHandler } from "../utils" import { MightFail, MightFailFunction, NonUndefined } from "../utils.type" const mightFailFunction: MightFailFunction<"go"> = async function (promise: Promise) { const { result, error } = await standard.mightFailFunction(promise) - return error ? createEither({ result: undefined, error }) : createEither({ result, error: undefined }) + return error + ? createEither({ result: undefined, error }, "go") + : createEither({ result, error: undefined }, "go") } /** @@ -42,7 +44,7 @@ const mightFailFunction: MightFailFunction<"go"> = async function (promise: P */ export const mightFail: MightFail<"go"> = new Proxy( mightFailFunction, - makeProxyHandler(mightFailFunction) + makeProxyHandler(mightFailFunction), ) as MightFail<"go"> /** @@ -69,10 +71,11 @@ export const mightFail: MightFail<"go"> = new Proxy( */ export function mightFailSync(func: () => T): Either { const { result, error } = standard.mightFailSync(func) - return error ? createEither({ result: undefined, error }) : createEither({ result, error: undefined }) + return error + ? createEither({ result: undefined, error }, "go") + : createEither({ result, error: undefined }, "go") } - /** * A pure constructor function that takes a non-null value and returns an Either object with the value as the result and undefined as the error. * @@ -81,7 +84,7 @@ export function mightFailSync(func: () => T): Either { */ export function Might(result: NonUndefined): Either { const standardMight = standard.Might(result) - return createEither({ result: standardMight.result as T, error: undefined }) + return createEither({ result: standardMight.result as T, error: undefined }, "go") } /** @@ -94,5 +97,5 @@ export function Might(result: NonUndefined): Either { */ export function Fail(error: unknown): Either { const standardFail = standard.Fail(error) - return createEither({ result: undefined, error: standardFail.error }) + return createEither({ result: undefined, error: standardFail.error }, "go") } diff --git a/src/mightFail.ts b/src/mightFail.ts index 89885ff..b415eac 100644 --- a/src/mightFail.ts +++ b/src/mightFail.ts @@ -1,16 +1,13 @@ -import { type Either, createEither } from "./Either" -import { handleError, makeProxyHandler } from "./utils" +import { type Either } from "./Either" +import { createEither, handleError, makeProxyHandler } from "./utils" import { MightFail, MightFailFunction, NonUndefined } from "./utils.type" - - - export const mightFailFunction: MightFailFunction<"standard"> = async function ( - promise: Promise + promise: Promise, ): Promise> { try { const result = await promise - return createEither({result, error: undefined}) + return createEither({ result, error: undefined }) } catch (err) { const error = handleError(err) return createEither({ error, result: undefined }) @@ -51,7 +48,7 @@ export const mightFailFunction: MightFailFunction<"standard"> = async function < */ export const mightFail: MightFail<"standard"> = new Proxy( mightFailFunction, - makeProxyHandler(mightFailFunction) + makeProxyHandler(mightFailFunction), ) as MightFail<"standard"> /** diff --git a/src/utils.ts b/src/utils.ts index fdb6351..5e417d7 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,6 @@ import { EitherMode, MightFailFunction } from "./utils.type" +import { Either as StandardEither } from "./Either" +import { Either as GoEither } from "./go/Either" export function handleError(error: unknown): Error { if (error instanceof Error) { @@ -17,7 +19,7 @@ export function handleError(error: unknown): Error { } export const makeProxyHandler = >( - mightFailFunction: TMightFailFunction + mightFailFunction: TMightFailFunction, ) => ({ get(_: TMightFailFunction, property: string) { if (Object.getOwnPropertyDescriptor(Promise, property) === undefined) { @@ -37,7 +39,36 @@ export const makeProxyHandler = (obj: any, array: (undefined | Error | T)[]) => { +export const createEither = ( + { + result, + error, + }: + | { + error: Error + result: undefined + } + | { + error: undefined + result: T + }, + eitherMode: EitherMode = "standard", +): TEitherMode extends "standard" ? StandardEither : GoEither => { + if (error) { + const array = eitherMode === "standard" ? [error, undefined] : [undefined, error] + const obj = {} as any + obj.error = error + obj.result = undefined + return createArrayProxy(obj, array) + } + const array = eitherMode === "standard" ? [undefined, result] : [result, undefined] + const obj = {} as any + obj.error = undefined + obj.result = result + return createArrayProxy(obj, array) +} + +const createArrayProxy = (obj: any, array: (undefined | Error | T)[]) => { // Proxy to intercept array methods and properties return new Proxy(obj, { get(target, prop, receiver) { @@ -52,7 +83,6 @@ export const createArrayProxy = (obj: any, array: (undefined | Error | T)[]) if (typeof value === "function") { // Proxy array methods return function (...args: any[]) { - console.log(`Array method called: ${String(prop)}, Arguments: ${args}`) return value.apply(array, args) } } else { @@ -66,7 +96,6 @@ export const createArrayProxy = (obj: any, array: (undefined | Error | T)[]) const originalIterator = array[Symbol.iterator]() return function* () { for (let item of originalIterator) { - console.log(`Iterating item: ${item}`) yield item } } From ea18dddb0321d2a40f0ccd2edb13cfd2e1dcc162 Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 5 Oct 2024 09:58:40 -0700 Subject: [PATCH 4/5] update examples --- examples/mightFailBasicTuple.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/mightFailBasicTuple.ts b/examples/mightFailBasicTuple.ts index d463275..f69fffb 100644 --- a/examples/mightFailBasicTuple.ts +++ b/examples/mightFailBasicTuple.ts @@ -1,6 +1,6 @@ import { mightFail } from "../src" -async function main() { +async function success() { const [error, result] = await mightFail(Promise.resolve({ message: "success" })) if (error) { console.error(error) @@ -9,4 +9,15 @@ async function main() { console.log(result.message) } -main() +success() + +async function error() { + const [error, result] = await mightFail<{ message: string }>(Promise.reject("error")) + if (error) { + console.error(error) + return + } + console.log(result.message) +} + +error() From 9587d510edf86281c5fd823f27c105288b9b4aee Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 5 Oct 2024 16:33:17 -0700 Subject: [PATCH 5/5] add js/tsdoc and adjust some of the docs --- docs/content/contents.mdx | 28 + docs/content/getting-started.mdx | 46 + docs/content/home.mdx | 16 +- docs/content/jsdocs/functions/Fail.mdx | 19 + docs/content/jsdocs/functions/Might.mdx | 23 + docs/content/jsdocs/functions/mightFail.mdx | 51 + .../jsdocs/functions/mightFailFunction.mdx | 21 + .../jsdocs/functions/mightFailSync.mdx | 43 + docs/content/jsdocs/index.mdx | 29 + docs/content/jsdocs/type-aliases/Either.mdx | 21 + docs/content/jsdocs/variables/default.mdx | 25 + docs/content/mightFail.mdx | 58 +- docs/content/mightFailSync.mdx | 63 +- docs/content/try-catch-finally-is-bad.mdx | 5 +- examples/mightFailBasic.ts | 13 - package-lock.json | 1580 ++++++++++++++++- package.json | 6 +- src/Either.ts | 4 + src/go/Either.ts | 4 + src/go/makeMightFail.ts | 4 +- src/go/mightFail.ts | 9 +- src/makeMightFail.ts | 4 +- src/mightFail.ts | 38 +- src/{utils.ts => utils/createEither.ts} | 55 +- src/utils/errors.ts | 25 + src/utils/staticMethodsProxy.ts | 22 + src/{ => utils}/utils.type.ts | 20 +- typedoc.json | 25 + 28 files changed, 2122 insertions(+), 135 deletions(-) create mode 100644 docs/content/getting-started.mdx create mode 100644 docs/content/jsdocs/functions/Fail.mdx create mode 100644 docs/content/jsdocs/functions/Might.mdx create mode 100644 docs/content/jsdocs/functions/mightFail.mdx create mode 100644 docs/content/jsdocs/functions/mightFailFunction.mdx create mode 100644 docs/content/jsdocs/functions/mightFailSync.mdx create mode 100644 docs/content/jsdocs/index.mdx create mode 100644 docs/content/jsdocs/type-aliases/Either.mdx create mode 100644 docs/content/jsdocs/variables/default.mdx rename src/{utils.ts => utils/createEither.ts} (53%) create mode 100644 src/utils/errors.ts create mode 100644 src/utils/staticMethodsProxy.ts rename src/{ => utils}/utils.type.ts (91%) create mode 100644 typedoc.json diff --git a/docs/content/contents.mdx b/docs/content/contents.mdx index 50f5848..ed6ce62 100644 --- a/docs/content/contents.mdx +++ b/docs/content/contents.mdx @@ -3,6 +3,8 @@ course: title: "Might Fail" parts: - title: "Getting Started" + slug: getting-started + filePath: /getting-started.mdx icon: "rocket" pages: - title: "❌ try, catch, finally" @@ -29,4 +31,30 @@ course: filePath: /might-and-fail.mdx slug: might-and-fail type: documentation + - title: "API Reference" + slug: api-reference + filePath: /jsdocs/variables/default.mdx + icon: "file-text" + pages: + - title: "`mightFail`" + filePath: /jsdocs/functions/mightFail.mdx + slug: api-might-fail + type: documentation + - title: "`mightFailSync`" + filePath: /jsdocs/functions/mightFailSync.mdx + slug: api-might-fail-sync + type: documentation + - title: "`Either`" + filePath: /jsdocs/type-aliases/Either.mdx + slug: api-either + type: documentation + - title: "`Fail`" + filePath: /jsdocs/functions/Fail.mdx + slug: api-fail + type: documentation + - title: "`Might`" + filePath: /jsdocs/functions/Might.mdx + slug: api-might + type: documentation + --- diff --git a/docs/content/getting-started.mdx b/docs/content/getting-started.mdx new file mode 100644 index 0000000..c455540 --- /dev/null +++ b/docs/content/getting-started.mdx @@ -0,0 +1,46 @@ +# Getting Started + +* [❌ try, catch, finally](/try-catch-finally-is-bad) +* [`mightFail`](/might-fail) +* [`mightFailSync`](/might-fail-sync) +* [Static Methods](/static-methods) +* [Either Type](/either) +* [Might & Fail](/might-and-fail) + +## Change the way you catch errors + +That's it, that's all this library helps you do. No major re-writes for your code base, no major changes at all. Just start handling your errors in a **much** better way. + +You still throw errors or let other libraries throw errors. Just stop using `try, catch, finally` and use `mightFail` or `mightFailSync` instead. + +## `catch` Sucks. Guarding is Good. + +Guarding allows you to handle your errors early and return from the function early, making them more readable and easier to reason about. + +```ts +const [ networkError, result ] = await mightFail(fetch("/posts")); +// guard against a network error +if (networkError) { + return; +} +// guard against an error response from the server +if (!result.ok) { + return; +} +const [ convertToJSONError, posts ] = await mightFail( + result.json() +); +// guard against an error converting the response to JSON +if (convertToJSONError) { + return; +} + +// success case, unnested and at the bottom of the function +posts.map((post) => console.log(post.title)); +``` + +The success case is now the only code that is **not** nested in another block. It's also at the very bottom of the function making it easy to find. + + + The sucess case is always at the bottom of the function. All of your error handling logic is next to where the error might occur. + diff --git a/docs/content/home.mdx b/docs/content/home.mdx index 5fdb454..cec5f8f 100644 --- a/docs/content/home.mdx +++ b/docs/content/home.mdx @@ -5,8 +5,6 @@ A TypeScript library for handling async and sync errors without `try` and `catch This works for **sync** and **async** code, and you can choose the error handling style that you like. -Check out the motivation section for why `try,catch,finally` blocks are bad. - ## Install @@ -88,10 +86,10 @@ import { mightFail } from "@might/fail" - + ```ts import { mightFail } from "might-fail" -const { error: networkError, result } = await mightFail(fetch("/posts")) +const [networkError, result] = await mightFail(fetch("/posts")) if (networkError) { // handle network error @@ -103,7 +101,7 @@ if (!result.ok) { return } -const { error: convertToJSONError, result: posts } = await mightFail( +const [convertToJSONError, posts] = await mightFail( result.json() ) @@ -115,10 +113,10 @@ if (convertToJSONError) { posts.map((post) => console.log(post.title)) ``` - + ```ts -import { mightFail } from "might-fail/tuple" -const [networkError, result] = await mightFail(fetch("/posts")) +import { mightFail } from "might-fail" +const { error: networkError, result } = await mightFail(fetch("/posts")) if (networkError) { // handle network error @@ -130,7 +128,7 @@ if (!result.ok) { return } -const [convertToJSONError, posts] = await mightFail( +const { error: convertToJSONError, result: posts } = await mightFail( result.json() ) diff --git a/docs/content/jsdocs/functions/Fail.mdx b/docs/content/jsdocs/functions/Fail.mdx new file mode 100644 index 0000000..a217888 --- /dev/null +++ b/docs/content/jsdocs/functions/Fail.mdx @@ -0,0 +1,19 @@ +# Function: Fail() + +```ts +function Fail(error: unknown): Either +``` + +A constructor function that takes an error and returns an `Either` object with undefined as the result and the error as the error. + +The error will **always** be an instance of Error. + +## Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `error` | `unknown` | | + +## Returns + +[`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`undefined`\> diff --git a/docs/content/jsdocs/functions/Might.mdx b/docs/content/jsdocs/functions/Might.mdx new file mode 100644 index 0000000..ba0f0d7 --- /dev/null +++ b/docs/content/jsdocs/functions/Might.mdx @@ -0,0 +1,23 @@ +# Function: Might() + +```ts +function Might(result: NonUndefined): Either +``` + +A pure constructor function that takes a non-null value and returns an `Either` object with the value as the result and undefined as the error. + +## Type Parameters + +| Type Parameter | +| ------ | +| `T` | + +## Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `result` | `NonUndefined`\<`T`\> | | + +## Returns + +[`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`T`\> diff --git a/docs/content/jsdocs/functions/mightFail.mdx b/docs/content/jsdocs/functions/mightFail.mdx new file mode 100644 index 0000000..9422a79 --- /dev/null +++ b/docs/content/jsdocs/functions/mightFail.mdx @@ -0,0 +1,51 @@ +# Function: mightFail() + +```ts +function mightFail(promise: Promise): Promise> +``` + +Wraps a promise in an Either to safely handle both its resolution and rejection. This function +takes a Promise of type T and returns a Promise which resolves with an object. This object +either contains a 'result' of type T if the promise resolves successfully, or an 'error' of type Error +if the promise is rejected. + +## Type Parameters + +| Type Parameter | Description | +| ------ | ------ | +| `T` | The type of the result value. | + +## Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `promise` | `Promise`\<`T`\> | The promise to be wrapped in an Either. This is an asynchronous operation that should resolve with a value of type T or reject with an Error. | + +## Returns + +`Promise`\<[`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`T`\>\> + +A Promise that resolves with an Either. This Either is a `Success` with +the 'result' property set to the value resolved by the promise if successful, and 'error' as undefined. +In case of failure, it's a `Failure` with 'result' as undefined and 'error' of type Error. `error` will **always** be an instance of Error. + +## Example + +```ts +// Example of wrapping an async function that might fail: +async function fetchData(url: string): Promise { + const response = await fetch(url); + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.text(); +} + +const {error, result} = await mightFail(fetchData('https://example.com')); + +if (error) { + console.error('Fetching failed:', error.message); + return; +} +console.log('Fetched data:', result); +``` diff --git a/docs/content/jsdocs/functions/mightFailFunction.mdx b/docs/content/jsdocs/functions/mightFailFunction.mdx new file mode 100644 index 0000000..415be1d --- /dev/null +++ b/docs/content/jsdocs/functions/mightFailFunction.mdx @@ -0,0 +1,21 @@ +# Function: mightFailFunction() + +```ts +function mightFailFunction(promise: Promise): Promise> +``` + +## Type Parameters + +| Type Parameter | +| ------ | +| `T` | + +## Parameters + +| Parameter | Type | +| ------ | ------ | +| `promise` | `Promise`\<`T`\> | + +## Returns + +`Promise`\<[`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`T`\>\> diff --git a/docs/content/jsdocs/functions/mightFailSync.mdx b/docs/content/jsdocs/functions/mightFailSync.mdx new file mode 100644 index 0000000..1ea830b --- /dev/null +++ b/docs/content/jsdocs/functions/mightFailSync.mdx @@ -0,0 +1,43 @@ +# Function: mightFailSync() + +```ts +function mightFailSync(func: () => T): Either +``` + +Wraps a synchronous function in an Either type to safely handle exceptions. This function +executes a provided function that returns a value of type T, capturing any thrown errors. +It returns an object that either contains a 'result' of type T if the function succeeds, +or an 'error' of type Error if the function throws an error. + +## Type Parameters + +| Type Parameter | Description | +| ------ | ------ | +| `T` | The type of the result value.◊ | + +## Parameters + +| Parameter | Type | Description | +| ------ | ------ | ------ | +| `func` | () => `T` | A wrapper function that is expected to invoke the throwing function. That function should return a value of type T or throw an error. | + +## Returns + +[`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`T`\> + +An object that is either a `Success` with the result property set to the value returned by `func`, + or a `Failure` with the error property set to the caught error. `Success` has a 'result' of type T + and 'error' as null. `Failure` has 'result' as null and 'error' of type Error. + +## Example + +```ts +// Example of wrapping a synchronous function that might throw an error: +const {error, result} = mightFailSync(() => JSON.parse("")); + +if (error) { + console.error('Parsing failed:', error); + return; +} +console.log('Parsed object:', result); +``` diff --git a/docs/content/jsdocs/index.mdx b/docs/content/jsdocs/index.mdx new file mode 100644 index 0000000..68bd396 --- /dev/null +++ b/docs/content/jsdocs/index.mdx @@ -0,0 +1,29 @@ +# might-fail + +## References + +### makeMightFail + +Re-exports makeMightFail + +*** + +### makeMightFailSync + +Re-exports makeMightFailSync + +## Type Aliases + +- [Either](https://mightfail.dev/type-aliases/Either.mdx) + +## Variables + +- [default](https://mightfail.dev/variables/default.mdx) + +## Functions + +- [Fail](https://mightfail.dev/functions/Fail.mdx) +- [Might](https://mightfail.dev/functions/Might.mdx) +- [mightFail](https://mightfail.dev/functions/mightFail.mdx) +- [mightFailFunction](https://mightfail.dev/functions/mightFailFunction.mdx) +- [mightFailSync](https://mightfail.dev/functions/mightFailSync.mdx) diff --git a/docs/content/jsdocs/type-aliases/Either.mdx b/docs/content/jsdocs/type-aliases/Either.mdx new file mode 100644 index 0000000..d970530 --- /dev/null +++ b/docs/content/jsdocs/type-aliases/Either.mdx @@ -0,0 +1,21 @@ +# Type Alias: Either\ + +```ts +type Either: { + error: Error; + result: undefined; + } & [Error, undefined] | { + error: undefined; + result: T; + } & [undefined, T]; +``` + +Either type represents a data structure that encapsulates a successful result or an Error. +It wraps the result of a Promise in an object, making it easier to handle errors by returning +an object that either contains a 'result' value of type T (if successful), or an 'error' of type Error. + +## Type Parameters + +| Type Parameter | Description | +| ------ | ------ | +| `T` | The type of the result value. | diff --git a/docs/content/jsdocs/variables/default.mdx b/docs/content/jsdocs/variables/default.mdx new file mode 100644 index 0000000..57d9254 --- /dev/null +++ b/docs/content/jsdocs/variables/default.mdx @@ -0,0 +1,25 @@ +# Variable: default + +```ts +default: { + Fail: (error: unknown) => Either; + makeMightFail: (func: T) => (...funcArgs: Parameters) => Promise>>>; + makeMightFailSync: (func: T) => (...funcArgs: Parameters) => Either>; + Might: (result: NonUndefined) => Either; + mightFail: MightFail<"standard">; + mightFailFunction: MightFailFunction<"standard">; + mightFailSync: (func: () => T) => Either; +}; +``` + +## Type declaration + +| Name | Type | +| ------ | ------ | +| `Fail` | (`error`: `unknown`) => [`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`undefined`\> | +| `makeMightFail` | \<`T`\>(`func`: `T`) => (...`funcArgs`: `Parameters`\<`T`\>) => `Promise`\<[`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`UnwrapPromise`\<`ReturnType`\<`T`\>\>\>\> | +| `makeMightFailSync` | \<`T`\>(`func`: `T`) => (...`funcArgs`: `Parameters`\<`T`\>) => [`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`ReturnType`\<`T`\>\> | +| `Might` | \<`T`\>(`result`: `NonUndefined`\<`T`\>) => [`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`T`\> | +| `mightFail` | `MightFail`\<`"standard"`\> | +| `mightFailFunction` | `MightFailFunction`\<`"standard"`\> | +| `mightFailSync` | \<`T`\>(`func`: () => `T`) => [`Either`](https://mightfail.dev/type-aliases/Either.mdx)\<`T`\> | diff --git a/docs/content/mightFail.mdx b/docs/content/mightFail.mdx index 07c9148..63fe85e 100644 --- a/docs/content/mightFail.mdx +++ b/docs/content/mightFail.mdx @@ -2,12 +2,43 @@ # `mightFail` Async -## Wrap Promise in `mightFail` +## Wrap Promise + +Simply wrap any promise in `mightFail` and await the result. + +You will get and `Either` object that contains either an error or the result. Never both. + +```ts +const EitherObject = await mightFail(fetch("/posts")); +``` + +But **don't** store the `Either` object directly. Instead, destructure it in the same statement. + +```ts +// tuple destructuring +const [ error, result ] = await mightFail(fetch("/posts")); + +// object destructuring +const { error, result } = await mightFail(fetch("/posts")); + +// go destructuring +// import { mightFail } from "might-fail/go"; +const [ result, error ] = await mightFail(fetch("/posts")); +``` + +You can choose to destructure this object as a tuple or as an object. Or as a backwards tuple if you prefer it that way. + +We think that the **tuple** option is the best, but you do you. + +## Guard + +Once you've awaited and destructured the `Either` object, use guard clauses to handle the error, and handle the success case at the end. - + + ```ts -const { error: networkError, result } = await mightFail(fetch("/posts")); +const [ networkError, result ] = await mightFail(fetch("/posts")); if (networkError) { // handle network error @@ -19,7 +50,7 @@ if (!result.ok) { return; } -const { error: convertToJSONError, result: posts } = await mightFail( +const [convertToJSONError, posts] = await mightFail( result.json() ); @@ -32,9 +63,9 @@ posts.map((post) => console.log(post.title)); ``` - + ```ts -const [ networkError, result ] = await mightFail(fetch("/posts")); +const { error: networkError, result } = await mightFail(fetch("/posts")); if (networkError) { // handle network error @@ -46,7 +77,7 @@ if (!result.ok) { return; } -const [convertToJSONError, posts] = await mightFail( +const { error: convertToJSONError, result: posts } = await mightFail( result.json() ); @@ -58,6 +89,7 @@ if (convertToJSONError) { posts.map((post) => console.log(post.title)); ``` + ```ts const [ result, networkError ] = await mightFail(fetch("/posts")); @@ -86,13 +118,15 @@ posts.map((post) => console.log(post.title)); -## Or Wrap Async Function in `makeMightFail` +## `makeMightFail` + +You also have the option to make your own `mightFail` wrapper function. Pass in any async function to `makeMightFail` and it will return a `mightFail` wrapper function for you to use. - + ```ts const get = makeMightFail(axios.get); -const { error, result } = await get("/posts"); +const [ error, result ] = await get("/posts"); if (error) { // handle error @@ -103,10 +137,10 @@ const posts = result.data posts.map((post) => console.log(post.title)); ``` - + ```ts const get = makeMightFail(axios.get); -const [ error, result ] = await get("/posts"); +const { error, result } = await get("/posts"); if (error) { // handle error diff --git a/docs/content/mightFailSync.mdx b/docs/content/mightFailSync.mdx index 76ddfd3..e181726 100644 --- a/docs/content/mightFailSync.mdx +++ b/docs/content/mightFailSync.mdx @@ -3,6 +3,19 @@ ## Wrap throwing functions in `mightFailSync` + + +```ts +const [error, result] = mightFailSync(() => JSON.parse("")); // JSON.parse might throw +if (error) { + console.error('Parsing failed:', error); + return +} +console.log('Parsed object:', result); +``` + + + ```ts const {error, result} = mightFailSync(() => JSON.parse("")); // JSON.parse might throw if (error) { @@ -11,9 +24,39 @@ if (error) { } console.log('Parsed object:', result); ``` + + +```ts +const [result, error] = mightFailSync(() => JSON.parse("")); // JSON.parse might throw +if (error) { + console.error('Parsing failed:', error); + return +} +console.log('Parsed object:', result); +``` + + ## Or Wrap Sync Function in `makeMightFailSync` + + +```ts +function parseJSON(jsonString: string) { + return JSON.parse(jsonString); // This might throw +} +const safeParseJSON = makeMightFailSync(parseJSON); + +const [error, result] = safeParseJSON(""); + +if (error) { + console.error("Parsing failed:", error); + return; +} +console.log("Parsed object:", result); +``` + + ```ts function parseJSON(jsonString: string) { return JSON.parse(jsonString); // This might throw @@ -27,4 +70,22 @@ if (error) { return; } console.log("Parsed object:", result); -``` \ No newline at end of file +``` + + +```ts +function parseJSON(jsonString: string) { + return JSON.parse(jsonString); // This might throw +} +const safeParseJSON = makeMightFailSync(parseJSON); + +const [result, error] = safeParseJSON(""); + +if (error) { + console.error("Parsing failed:", error); + return; +} +console.log("Parsed object:", result); +``` + + \ No newline at end of file diff --git a/docs/content/try-catch-finally-is-bad.mdx b/docs/content/try-catch-finally-is-bad.mdx index 5452438..7dba464 100644 --- a/docs/content/try-catch-finally-is-bad.mdx +++ b/docs/content/try-catch-finally-is-bad.mdx @@ -11,7 +11,7 @@ This mostly happens at the most "user facing" part of the code like an api endpo Guarding allows you to handle your errors early and return from the function early, making them more readable and easier to reason about. ```ts -const { error: networkError, result } = await mightFail(fetch("/posts")); +const [ networkError, result ] = await mightFail(fetch("/posts")); // guard against a network error if (networkError) { return; @@ -20,7 +20,7 @@ if (networkError) { if (!result.ok) { return; } -const { error: convertToJSONError, result: posts } = await mightFail( +const [ convertToJSONError, posts ] = await mightFail( result.json() ); // guard against an error converting the response to JSON @@ -105,4 +105,3 @@ console.log(something()) ``` Can every single dev in your team understand what the above code will print out? - diff --git a/examples/mightFailBasic.ts b/examples/mightFailBasic.ts index 4387c64..13cdeb1 100644 --- a/examples/mightFailBasic.ts +++ b/examples/mightFailBasic.ts @@ -10,16 +10,3 @@ async function main() { } main() -async function main2() { - const result = await mightFail(Promise.resolve({ message: "success" })) - console.log(result) -} - -main2() - -async function main3() { - const result = await mightFail(Promise.reject(new Error("error"))) - console.log(result) -} - -main3() diff --git a/package-lock.json b/package-lock.json index 17b127a..1eab93d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,68 @@ { "name": "might-fail", - "version": "0.4.1", + "version": "0.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "might-fail", - "version": "0.4.1", + "version": "0.5.1", "license": "MIT", "devDependencies": { + "jsdoc-to-markdown": "^9.0.2", + "typedoc": "^0.26.8", + "typedoc-plugin-markdown": "^4.2.9", "typescript": "^5.6.2", "vitest": "^2.1.1" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", + "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", + "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz", + "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.25.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz", + "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -387,6 +437,53 @@ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, + "node_modules/@jsdoc/salty": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz", + "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.22.5", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.5.tgz", @@ -595,12 +692,115 @@ "win32" ] }, + "node_modules/@shikijs/core": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.21.0.tgz", + "integrity": "sha512-zAPMJdiGuqXpZQ+pWNezQAk5xhzRXBNiECFPcJLtUdsFM3f//G95Z15EHTnHchYycU8kIIysqGgxp8OVSj1SPQ==", + "dev": true, + "dependencies": { + "@shikijs/engine-javascript": "1.21.0", + "@shikijs/engine-oniguruma": "1.21.0", + "@shikijs/types": "1.21.0", + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.3" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.21.0.tgz", + "integrity": "sha512-jxQHNtVP17edFW4/0vICqAVLDAxmyV31MQJL4U/Kg+heQALeKYVOWo0sMmEZ18FqBt+9UCdyqGKYE7bLRtk9mg==", + "dev": true, + "dependencies": { + "@shikijs/types": "1.21.0", + "@shikijs/vscode-textmate": "^9.2.2", + "oniguruma-to-js": "0.4.3" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.21.0.tgz", + "integrity": "sha512-AIZ76XocENCrtYzVU7S4GY/HL+tgHGbVU+qhiDyNw1qgCA5OSi4B4+HY4BtAoJSMGuD/L5hfTzoRVbzEm2WTvg==", + "dev": true, + "dependencies": { + "@shikijs/types": "1.21.0", + "@shikijs/vscode-textmate": "^9.2.2" + } + }, + "node_modules/@shikijs/types": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.21.0.tgz", + "integrity": "sha512-tzndANDhi5DUndBtpojEq/42+dpUF2wS7wdCDQaFtIXm3Rd1QkrcVgSSRLOvEwexekihOXfbYJINW37g96tJRw==", + "dev": true, + "dependencies": { + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.2.2.tgz", + "integrity": "sha512-TMp15K+GGYrWlZM8+Lnj9EaHEFmOen0WJBrfa17hF7taDOYthuPPV0GWzfd/9iMij0akS/8Yw2ikquH7uVi/fg==", + "dev": true + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@vitest/expect": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.1.tgz", @@ -708,6 +908,36 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -717,6 +947,39 @@ "node": ">=12" } }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -726,6 +989,48 @@ "node": ">=8" } }, + "node_modules/cache-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-3.0.0.tgz", + "integrity": "sha512-LDGNWYv/tqRWAAZxMy75PIYynaIuhcyoyjJtwA7X5uMZjdzvGm+XmTey/GXUy2EJ+lwc2eBFzFYxjvNYyE/0Iw==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "^0.1.1" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chai": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", @@ -742,6 +1047,57 @@ "node": ">=12" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -751,6 +1107,100 @@ "node": ">= 16" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/command-line-args": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.0.tgz", + "integrity": "sha512-zDdHxHzlCp/gA1gy0VtPK3YL0Aob3ijJdwZ7H3HSl55hh8EziLtRlyj/od8EGRJfX8IjussC/mQkScl2Ms5Suw==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "find-replace": "^5.0.1", + "lodash.camelcase": "^4.3.0", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/command-line-usage": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", + "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "chalk-template": "^0.4.0", + "table-layout": "^4.1.0", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/common-sequence": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-2.0.2.tgz", + "integrity": "sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/config-master": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", + "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==", + "dev": true, + "dependencies": { + "walk-back": "^2.0.1" + } + }, + "node_modules/config-master/node_modules/walk-back": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", + "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/current-module-paths": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/current-module-paths/-/current-module-paths-1.1.2.tgz", + "integrity": "sha512-H4s4arcLx/ugbu1XkkgSvcUZax0L6tXUqnppGniQb8l5VjUKGHoayXE5RiriiPhYDd+kjZnaok1Uig13PKtKYQ==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -777,6 +1227,66 @@ "node": ">=6" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dmd": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-7.0.7.tgz", + "integrity": "sha512-UXNLJkci/tiVNct+JgrpfTlSs8cSyLbR3q4xkYQ4do6cRCUPj0HodfMsBLPhC7KG3qGRp1YJgfNjdgCrYEcHWQ==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "cache-point": "^3.0.0", + "common-sequence": "^2.0.2", + "file-set": "^5.2.2", + "handlebars": "^4.7.8", + "marked": "^4.3.0", + "walk-back": "^5.1.1" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -815,6 +1325,15 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -824,15 +1343,90 @@ "@types/estree": "^1.0.0" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-set": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.2.2.tgz", + "integrity": "sha512-/KgJI1V/QaDK4enOk/E2xMFk1cTWJghEr7UmWiRZfZ6upt6gQCfMn4jJ7aOm64OKurj4TaVnSSgSDqv5ZKYA3A==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "fast-glob": "^3.3.2" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-replace": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz", + "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==", + "dev": true, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" ], "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" @@ -847,6 +1441,275 @@ "node": "*" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.3.tgz", + "integrity": "sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.3.tgz", + "integrity": "sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc-api": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.1.tgz", + "integrity": "sha512-pgZ5nrLnzF8Swxbv5OV8RYAoM/S3Cbf1UHncNYMRCQwU4KlCfg5bz5/VZlg0a1EATSHclIBf9Hm55GkXz0VItA==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "cache-point": "^3.0.0", + "current-module-paths": "^1.1.2", + "file-set": "^5.2.0", + "jsdoc": "^4.0.3", + "object-to-spawn-args": "^2.0.1", + "walk-back": "^5.1.1" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/jsdoc-parse": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.4.tgz", + "integrity": "sha512-MQA+lCe3ioZd0uGbyB3nDCDZcKgKC7m/Ivt0LgKZdUoOlMJxUWJQ3WI6GeyHp9ouznKaCjlp7CU9sw5k46yZTw==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "find-replace": "^5.0.1", + "lodash.omit": "^4.5.0", + "sort-array": "^5.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdoc-to-markdown": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-9.0.2.tgz", + "integrity": "sha512-4T/7sCxq5RDXT37inCpVLetXOyjaFCMtVYH4Yvyfk/0v2aksMn74FqYdtSOc/+wceu+5ItJop6krCtGZjpJTxA==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "command-line-args": "^6.0.0", + "command-line-usage": "^7.0.3", + "config-master": "^3.1.0", + "dmd": "^7.0.7", + "jsdoc-api": "^9.3.1", + "jsdoc-parse": "^6.2.4", + "walk-back": "^5.1.1" + }, + "bin": { + "jsdoc2md": "bin/cli.js" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==", + "dev": true + }, "node_modules/loupe": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", @@ -856,6 +1719,12 @@ "get-func-name": "^2.0.1" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -865,6 +1734,219 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -889,6 +1971,33 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/object-to-spawn-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz", + "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/oniguruma-to-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-js/-/oniguruma-to-js-0.4.3.tgz", + "integrity": "sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==", + "dev": true, + "dependencies": { + "regex": "^4.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -910,6 +2019,18 @@ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", @@ -938,6 +2059,70 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/regex": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/regex/-/regex-4.3.3.tgz", + "integrity": "sha512-r/AadFO7owAq1QJVeZ/nq9jNS1vyZt+6t1p/E59B56Rn2GCya+gr1KSyOzNL/er+r+B7phv5jG2xU2Nz1YkmJg==", + "dev": true + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.22.5", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.5.tgz", @@ -973,12 +2158,79 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shiki": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.21.0.tgz", + "integrity": "sha512-apCH5BoWTrmHDPGgg3RF8+HAAbEL/CdbYr8rMw7eIrdhCkZHdVGat5mMNlRtd1erNG01VPMIKHNQ0Pj2HMAiog==", + "dev": true, + "dependencies": { + "@shikijs/core": "1.21.0", + "@shikijs/engine-javascript": "1.21.0", + "@shikijs/engine-oniguruma": "1.21.0", + "@shikijs/types": "1.21.0", + "@shikijs/vscode-textmate": "^9.2.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true }, + "node_modules/sort-array": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-5.0.0.tgz", + "integrity": "sha512-Sg9MzajSGprcSrMIxsXyNT0e0JB47RJRfJspC+7co4Z5BdNsNl8FmWI+lXEpyKq+vkMG6pHgAhqyCO+bkDTfFQ==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "typical": "^7.1.1" + }, + "engines": { + "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "^0.1.1" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -988,6 +2240,16 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -1000,6 +2262,57 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", + "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", + "dev": true, + "dependencies": { + "array-back": "^6.2.2", + "wordwrapjs": "^5.1.0" + }, + "engines": { + "node": ">=12.17" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -1039,6 +2352,71 @@ "node": ">=14.0.0" } }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/typedoc": { + "version": "0.26.8", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.26.8.tgz", + "integrity": "sha512-QBF0BMbnNeUc6U7pRHY7Jb8pjhmiNWZNQT8LU6uk9qP9t3goP9bJptdlNqMC0wBB2w9sQrxjZt835bpRSSq1LA==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "shiki": "^1.16.2", + "yaml": "^2.5.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x" + } + }, + "node_modules/typedoc-plugin-markdown": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.2.9.tgz", + "integrity": "sha512-Wqmx+7ezKFgtTklEq/iUhQ5uFeBDhAT6wiS2na9cFLidIpl9jpDHJy/COYh8jUZXgIRIZVQ/bPNjyrnPFoDwzg==", + "dev": true, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typedoc": "0.26.x" + } + }, "node_modules/typescript": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", @@ -1052,6 +2430,136 @@ "node": ">=14.17" } }, + "node_modules/typical": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-7.2.0.tgz", + "integrity": "sha512-W1+HdVRUl8fS3MZ9ogD51GOb46xMmhAZzR0WPw5jcgIZQJVvkddYzAl4YTU6g5w33Y1iRQLdIi2/1jhi2RNL0g==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "5.4.8", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", @@ -1196,6 +2704,15 @@ } } }, + "node_modules/walk-back": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz", + "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", @@ -1211,6 +2728,49 @@ "engines": { "node": ">=8" } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wordwrapjs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", + "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", + "dev": true, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index c2af7af..9b50d7c 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "build:esm": "tsc", "build:cjs": "tsc --project tsconfig.cjs.json", "test": "vitest", - "publish": "npm run build && npm publish" + "publish": "npm run build && npm publish", + "typedoc": "typedoc src" }, "files": [ "dist" @@ -47,6 +48,9 @@ "typescript" ], "devDependencies": { + "jsdoc-to-markdown": "^9.0.2", + "typedoc": "^0.26.8", + "typedoc-plugin-markdown": "^4.2.9", "typescript": "^5.6.2", "vitest": "^2.1.1" } diff --git a/src/Either.ts b/src/Either.ts index fd964ff..4f4c7ca 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -14,3 +14,7 @@ export type Either = result: T error: undefined } & [undefined, T]) + +// Note this array interface is undesireable, we would much rather use just an itterator here but TS doesn't yet support that well enough +// So it has an array interface and proxies array methods. +// See the utils `makeEither` for more information. \ No newline at end of file diff --git a/src/go/Either.ts b/src/go/Either.ts index 05e1ec4..22dc28b 100644 --- a/src/go/Either.ts +++ b/src/go/Either.ts @@ -14,3 +14,7 @@ export type Either = result: T error: undefined } & [T, undefined]) + +// Note this array interface is undesireable, we would much rather use just an itterator here but TS doesn't yet support that well enough +// So it has an array interface and proxies array methods. +// See the utils `makeEither` for more information. \ No newline at end of file diff --git a/src/go/makeMightFail.ts b/src/go/makeMightFail.ts index 80871fe..40538f3 100644 --- a/src/go/makeMightFail.ts +++ b/src/go/makeMightFail.ts @@ -14,7 +14,7 @@ type UnwrapPromise = T extends Promise ? U : T * returns a Promise that resolves with an Either. This allows for the handling of both resolved values and * errors in a consistent, functional way. * - * @export + * @template T The function type that returns a Promise. * @param {T} func - The async function to be wrapped. This function should return a Promise. * @return {Function} A new function that, when called, returns a Promise that resolves with an Either tuple. @@ -55,7 +55,7 @@ export function makeMightFail Promise>( * if it executes successfully as the first element and undefined as the second, or undefined as the first element * and an Error as the second if the function throws. * - * @export + * @template T The function type that might throw an error. * @param {T} func - The function to be wrapped. This function might throw an exception. * @return {Function} A new function that, when called, returns an Either tuple with either a result or an error. diff --git a/src/go/mightFail.ts b/src/go/mightFail.ts index 3f8c182..7a20dff 100644 --- a/src/go/mightFail.ts +++ b/src/go/mightFail.ts @@ -1,7 +1,8 @@ import standard from "../index" import { type Either } from "./Either" -import { createEither, makeProxyHandler } from "../utils" -import { MightFail, MightFailFunction, NonUndefined } from "../utils.type" +import { createEither } from "../utils/createEither" +import { makeProxyHandler } from "../utils/staticMethodsProxy" +import { MightFail, MightFailFunction, NonUndefined } from "../utils/utils.type" const mightFailFunction: MightFailFunction<"go"> = async function (promise: Promise) { const { result, error } = await standard.mightFailFunction(promise) @@ -16,7 +17,7 @@ const mightFailFunction: MightFailFunction<"go"> = async function (promise: P * either contains the resolved value of type T as the first element and undefined as the second if the promise * resolves successfully, or undefined as the first element and an Error as the second if the promise is rejected. * - * @export + * @template T The type of the result value. * @param {Promise} promise - The promise to be wrapped in an Either. This is an asynchronous operation that * should resolve with a value of type T or reject with an Error. @@ -53,7 +54,7 @@ export const mightFail: MightFail<"go"> = new Proxy( * It returns an Either tuple that either contains the value of type T as the first element and undefined as the second * if the function succeeds, or undefined as the first element and an Error as the second if the function throws an error. * - * @export + * @template T The type of the result value. * @param {() => T} func - A wrapper function that is expected to invoke the throwing function. * That function should return a value of type T or throw an error. diff --git a/src/makeMightFail.ts b/src/makeMightFail.ts index f4eb47b..3c2d4f4 100644 --- a/src/makeMightFail.ts +++ b/src/makeMightFail.ts @@ -14,7 +14,7 @@ type UnwrapPromise = T extends Promise ? U : T * returns a Promise that resolves with an Either. This allows for the handling of both resolved values and * errors in a consistent, functional way. * - * @export + * @template T The function type that returns a Promise. * @param {T} func - The async function to be wrapped. This function should return a Promise. * @return {Function} A new function that, when called, returns a Promise that resolves with an Either object. @@ -53,7 +53,7 @@ export function makeMightFail Promise>( * instead of throwing, returns an Either object. This object contains either a 'result' * with the value returned by the function if it executes successfully, or an 'error' if the function throws. * - * @export + * @template T The function type that might throw an error. * @param {T} func - The function to be wrapped. This function might throw an exception. * @return {Function} A new function that, when called, returns an Either object with either a 'result' or an 'error'. diff --git a/src/mightFail.ts b/src/mightFail.ts index b415eac..23d75b1 100644 --- a/src/mightFail.ts +++ b/src/mightFail.ts @@ -1,9 +1,11 @@ import { type Either } from "./Either" -import { createEither, handleError, makeProxyHandler } from "./utils" -import { MightFail, MightFailFunction, NonUndefined } from "./utils.type" +import { makeProxyHandler } from "./utils/staticMethodsProxy" +import { handleError } from "./utils/errors" +import { createEither } from "./utils/createEither" +import { MightFail, MightFailFunction, NonUndefined } from "./utils/utils.type" export const mightFailFunction: MightFailFunction<"standard"> = async function ( - promise: Promise, + promise: Promise ): Promise> { try { const result = await promise @@ -20,13 +22,12 @@ export const mightFailFunction: MightFailFunction<"standard"> = async function < * either contains a 'result' of type T if the promise resolves successfully, or an 'error' of type Error * if the promise is rejected. * - * @export * @template T The type of the result value. * @param {Promise} promise - The promise to be wrapped in an Either. This is an asynchronous operation that * should resolve with a value of type T or reject with an Error. - * @return {Promise>} A Promise that resolves with an Either. This Either is a Success with + * @return {Promise>} A Promise that resolves with an Either. This Either is a `Success` with * the 'result' property set to the value resolved by the promise if successful, and 'error' as undefined. - * In case of failure, it's a Failure with 'result' as undefined and 'error' of type Error. `error` will **always** be an instance of Error. + * In case of failure, it's a `Failure` with 'result' as undefined and 'error' of type Error. `error` will **always** be an instance of Error. * * @example * // Example of wrapping an async function that might fail: @@ -48,7 +49,7 @@ export const mightFailFunction: MightFailFunction<"standard"> = async function < */ export const mightFail: MightFail<"standard"> = new Proxy( mightFailFunction, - makeProxyHandler(mightFailFunction), + makeProxyHandler(mightFailFunction) ) as MightFail<"standard"> /** @@ -57,13 +58,12 @@ export const mightFail: MightFail<"standard"> = new Proxy( * It returns an object that either contains a 'result' of type T if the function succeeds, * or an 'error' of type Error if the function throws an error. * - * @export - * @template T The type of the result value. + * @template T The type of the result value.◊ * @param {() => T} func - A wrapper function that is expected to invoke the throwing function. * That function should return a value of type T or throw an error. - * @return {Either} An object that is either a Success with the result property set to the value returned by `func`, - * or a Failure with the error property set to the caught error. Success has a 'result' of type T - * and 'error' as null. Failure has 'result' as null and 'error' of type Error. + * @return {Either} An object that is either a `Success` with the result property set to the value returned by `func`, + * or a `Failure` with the error property set to the caught error. `Success` has a 'result' of type T + * and 'error' as null. `Failure` has 'result' as null and 'error' of type Error. * @example * // Example of wrapping a synchronous function that might throw an error: * const {error, result} = mightFailSync(() => JSON.parse("")); @@ -74,8 +74,7 @@ export const mightFail: MightFail<"standard"> = new Proxy( * } * console.log('Parsed object:', result); */ - -export function mightFailSync(func: () => T): Either { +export const mightFailSync = function mightFailSync(func: () => T): Either { try { const result = func() return createEither({ error: undefined, result }) @@ -86,23 +85,22 @@ export function mightFailSync(func: () => T): Either { } /** - * A pure constructor function that takes a non-null value and returns an Either object with the value as the result and undefined as the error. + * A pure constructor function that takes a non-null value and returns an `Either` object with the value as the result and undefined as the error. * * @param result - * @constructor */ -export function Might(result: NonUndefined): Either { +export const Might = function Might(result: NonUndefined): Either { return createEither({ result, error: undefined }) } /** - * A constructor function that takes an error and returns an Either object with undefined as the result and the error as the error. + * A constructor function that takes an error and returns an `Either` object with undefined as the result and the error as the error. * * The error will **always** be an instance of Error. * * @param error - * @constructor */ -export function Fail(error: unknown): Either { +export const Fail = function Fail(error: unknown): Either { return createEither({ result: undefined, error: handleError(error) }) } + diff --git a/src/utils.ts b/src/utils/createEither.ts similarity index 53% rename from src/utils.ts rename to src/utils/createEither.ts index 4af03f7..07a135c 100644 --- a/src/utils.ts +++ b/src/utils/createEither.ts @@ -1,53 +1,12 @@ -import { EitherMode, MightFailFunction } from "./utils.type" -import { Either as StandardEither } from "./Either" -import { Either as GoEither } from "./go/Either" +import { EitherMode } from "./utils.type" +import type { Either as StandardEither } from "../Either" +import type { Either as GoEither } from "../go/Either" -export function handleError(error: unknown): Error { - if (error instanceof Error) { - return error - } - if (typeof error === "string") { - return createErrorWithoutMightFailStackTraces(error) - } - if (typeof error === "object" && error !== null) { - if ("message" in error && typeof error.message === "string") { - return createErrorWithoutMightFailStackTraces(error.message) - } - return createErrorWithoutMightFailStackTraces(error as any) - } - return createErrorWithoutMightFailStackTraces("Unknown error") -} - -function createErrorWithoutMightFailStackTraces(message: any): Error { - const error = new Error(message) - - const stack = error.stack?.split("\n") - stack?.splice(1, 3) - error.stack = stack?.join("\n") - - return error -} - -export const makeProxyHandler = >( - mightFailFunction: TMightFailFunction, -) => ({ - get(_: TMightFailFunction, property: string) { - if (Object.getOwnPropertyDescriptor(Promise, property) === undefined) { - return mightFailFunction(Promise.reject(new Error(`property ${property} not found on Promise`))) - } - - const value = (Promise as any)[property] - - if (typeof value !== "function") { - return mightFailFunction(Promise.reject(new Error(`property ${property} is not a Promise method`))) - } - return function (...args: any[]) { - const promise = value.apply(Promise, args) - return mightFailFunction(promise) - } - }, -}) +// This is not how we intended the tuple feature to work but this is the only way we could currently get TypeScript to play nice +// this really should just be an interator on the either object, but it's much more complicated because of TS. +// All the details are in this PR https://github.com/meech-ward/might-fail/pull/7#issuecomment-2395122593 +// hopefully we can change this with a future version of TS. export const createEither = ( { diff --git a/src/utils/errors.ts b/src/utils/errors.ts new file mode 100644 index 0000000..074f7fa --- /dev/null +++ b/src/utils/errors.ts @@ -0,0 +1,25 @@ +export function handleError(error: unknown): Error { + if (error instanceof Error) { + return error + } + if (typeof error === "string") { + return createErrorWithoutMightFailStackTraces(error) + } + if (typeof error === "object" && error !== null) { + if ("message" in error && typeof error.message === "string") { + return createErrorWithoutMightFailStackTraces(error.message) + } + return createErrorWithoutMightFailStackTraces(error as any) + } + return createErrorWithoutMightFailStackTraces("Unknown error") +} + +function createErrorWithoutMightFailStackTraces(message: any): Error { + const error = new Error(message) + + const stack = error.stack?.split("\n") + stack?.splice(1, 3) + error.stack = stack?.join("\n") + + return error +} \ No newline at end of file diff --git a/src/utils/staticMethodsProxy.ts b/src/utils/staticMethodsProxy.ts new file mode 100644 index 0000000..c2bb01b --- /dev/null +++ b/src/utils/staticMethodsProxy.ts @@ -0,0 +1,22 @@ +import { EitherMode, MightFailFunction } from "./utils.type" + +export const makeProxyHandler = >( + mightFailFunction: TMightFailFunction, +) => ({ + get(_: TMightFailFunction, property: string) { + if (Object.getOwnPropertyDescriptor(Promise, property) === undefined) { + return mightFailFunction(Promise.reject(new Error(`property ${property} not found on Promise`))) + } + + const value = (Promise as any)[property] + + if (typeof value !== "function") { + return mightFailFunction(Promise.reject(new Error(`property ${property} is not a Promise method`))) + } + + return function (...args: any[]) { + const promise = value.apply(Promise, args) + return mightFailFunction(promise) + } + }, +}) diff --git a/src/utils.type.ts b/src/utils/utils.type.ts similarity index 91% rename from src/utils.type.ts rename to src/utils/utils.type.ts index f24bb95..ba991cf 100644 --- a/src/utils.type.ts +++ b/src/utils/utils.type.ts @@ -1,5 +1,5 @@ -import type { Either as StandardEither } from "./Either" -import type { Either as GoEither } from "./go" +import type { Either as StandardEither } from "../Either" +import type { Either as GoEither } from "../go/Either" export type EitherMode = "standard" | "go" | "any" @@ -33,7 +33,7 @@ export type MightFail< export interface PromiseStaticMethods { /** * Wraps a Promise.all call in a mightFail function. - * @params values + * @param values - An iterable of promises * @template T The type of the resolved values * @return {Promise} - Promise>> */ @@ -49,7 +49,7 @@ export interface PromiseStaticMethods { /** * Wraps a Promise.all call in a mightFail function. - * @params values + * @param values - An array of promises * @template T The type of the resolved values * @return {Promise} - Promise; }>> */ @@ -66,7 +66,7 @@ export interface PromiseStaticMethods { /** * Wraps a Promise.race call in a mightFail function. * - * @params values - An iterable of promises + * @param values - An array of promises * @template T The type of the resolved values * @return {Promise} - Promise>> */ @@ -82,7 +82,7 @@ export interface PromiseStaticMethods { /** * Wraps a Promise.race call in a mightFail function. - * @params values + * @param values - An array of promises * @template T The type of the resolved values * @return {Promise} - Promise>> */ @@ -98,7 +98,7 @@ export interface PromiseStaticMethods { /** * Wraps a Promise.allSettled call in a mightFail function. - * @params values + * @param values - An array of promises * @template T The type of the resolved values * @return {Promise} - Promise>}>> */ @@ -114,7 +114,7 @@ export interface PromiseStaticMethods { /** * Wraps a Promise.allSettled call in a mightFail function. - * @params values + * @param values - An iterable of promises * @template T The type of the resolved values * @return {Promise} - Promise>[]>> */ @@ -131,7 +131,7 @@ export interface PromiseStaticMethods { /** * Wraps a Promise.any call in a mightFail function. * - * @params values + * @param values - An array of promises * @template T The type of the resolved values * @return {Promise} - Promise>> */ @@ -148,7 +148,7 @@ export interface PromiseStaticMethods { /** * Wraps a Promise.any call in a mightFail function. * - * @params values + * @param values - An iterable of promises * @template T The type of the resolved values * @return {Promise} - Promise>> */ diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..6d0e835 --- /dev/null +++ b/typedoc.json @@ -0,0 +1,25 @@ +{ + "plugin": [ + "typedoc-plugin-markdown" + ], + "out": "./docs/content/jsdocs", + "outputFileStrategy": "members", + "hidePageHeader": true, + "hideBreadcrumbs": true, + "useCodeBlocks": true, + "expandObjects": true, + "expandParameters": true, + "parametersFormat": "table", + "interfacePropertiesFormat": "table", + "classPropertiesFormat": "table", + "enumMembersFormat": "table", + "typeDeclarationFormat": "table", + "propertyMembersFormat": "table", + "publicPath": "https://mightfail.dev", + "sanitizeComments": true, + "anchorPrefix": "markdown-header", + "fileExtension": ".mdx", + "entryFileName": "index", + "readme": "none", + "disableSources": true +} \ No newline at end of file