diff --git a/deno.json b/deno.json index 042b0bf..7246943 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@eman/oxy", - "version": "0.1.3", + "version": "0.1.4", "exports": "./main.ts", "tasks": { "dev": "deno run --watch index.ts" diff --git a/error_enum.ts b/error_enum.ts index 238d43b..06c3c4c 100644 --- a/error_enum.ts +++ b/error_enum.ts @@ -1,5 +1,9 @@ import type { Err } from './result.ts'; +/** + * Represents an object where each key is associated with a function returning an Err type. + * @template ErrObject - The type of the error object. + */ export type ErrorObject = { [key: string]: (...args: any[]) => Err<{ readonly type: string; @@ -7,18 +11,34 @@ export type ErrorObject = { readonly message: string; }>; }; + +/** + * Wraps an error object type, preserving the function signatures. + * @template T - The type of the error object. + */ export type ErrorObjWrapper = Record< keyof T, T[keyof T] extends (...args: any[]) => Err ? (...args: any[]) => Err : never >; + +/** + * Extracts the keys of an ErrorObjWrapper as a union type. + * @template T - The type of the error object wrapper. + */ export type ErrorObjectNames = keyof ErrorObjWrapper; +/** + * Determines the error type for a given key in an error object. + * @template T - The key type. + * @template U - The error object type. + */ export type ErrorType = T extends keyof ErrorObjWrapper ? ReturnType : T extends undefined ? ReturnType[keyof ErrorObjWrapper]> : never; + // let one = { type: "one", name: "one", message: "one" } as const; // import { err } from "./Result"; // const Blah = { diff --git a/json_rpc.ts b/json_rpc.ts index b8cb3db..0f2a8e5 100644 --- a/json_rpc.ts +++ b/json_rpc.ts @@ -1,9 +1,18 @@ + import { P } from "npm:ts-pattern@5.1.1"; +/** + * Represents a successful JSON-RPC response. + * @template Data - The type of the result data. + */ export type JsonRpcSuccess = P.infer & { result: Data; }; +/** + * Represents an error JSON-RPC response. + * @template ErrorData - The type of the error data. + */ export type JsonRpcError = P.infer & { error: { code: number; @@ -12,13 +21,37 @@ export type JsonRpcError = P.infer & { }; }; +/** + * Checks if the given object is a JSON-RPC error response. + * @template T - The type of the error data. + * @param {object} obj - The object to check. + * @param {unknown} obj.jsonrpc - The JSON-RPC version. + * @param {unknown} obj.result - The result of the JSON-RPC call. + * @param {unknown} obj.id - The identifier of the JSON-RPC call. + * @param {unknown} obj.error - The error object of the JSON-RPC call. + * @returns {boolean} True if the object is a JSON-RPC error response, otherwise false. + */ function isJsonRpcError(obj: { jsonrpc?: unknown, result?: unknown, id?: unknown, error?: unknown }): obj is JsonRpcError { return obj["jsonrpc"] && obj["result"] && obj["error"] ? true : false; } + +/** + * Checks if the given object is a successful JSON-RPC response. + * @template T - The type of the result data. + * @param {object} obj - The object to check. + * @param {unknown} obj.jsonrpc - The JSON-RPC version. + * @param {unknown} obj.result - The result of the JSON-RPC call. + * @param {unknown} obj.id - The identifier of the JSON-RPC call. + * @param {unknown} obj.error - The error object of the JSON-RPC call. + * @returns {boolean} True if the object is a successful JSON-RPC response, otherwise false. + */ function isJsonRpcSuccess(obj: { jsonrpc?: unknown, result?: unknown, id?: unknown, error?: unknown }): obj is JsonRpcSuccess { return obj["jsonrpc"] && obj["id"] && obj["result"] ? true : false; } +/** + * Pattern for matching successful JSON-RPC responses. + */ export const JsonRpcSuccessPattern: { readonly id: any; readonly jsonrpc: any; @@ -31,6 +64,9 @@ export const JsonRpcSuccessPattern: { result: { data: P.any } } as const; +/** + * Pattern for matching JSON-RPC error responses. + */ export const JsonRpcErrorPattern: { readonly id: any; readonly jsonrpc: any; @@ -53,4 +89,3 @@ export const JsonRpcErrorPattern: { }, } as const; - diff --git a/option.ts b/option.ts index f407372..34670ff 100644 --- a/option.ts +++ b/option.ts @@ -2,11 +2,22 @@ import { isMatching, P } from "npm:ts-pattern@5.1.1"; /** * Represents an optional value, either `Some` containing a value or `None`. + * @template Thing - The type of the value. */ export type Option = Some | None; /** * Represents an optional value that contains a value. + * @template Thing - The type of the value. + */ +export type Some = { + readonly isSome: true; + readonly data: Thing; + readonly isNone: false; +}; + +/** + * Represents an optional value that does not contain a value. */ export type None = { readonly isSome: false; @@ -14,15 +25,19 @@ export type None = { readonly isNone: true; }; +/** + * Creates an instance of Some. + * @template Thing - The type of the value. + * @param {Thing} data - The value to be contained. + * @returns {Some} An instance of Some. + */ export const some = (data: Thing): Some => { return { isSome: true, data, isNone: false } as Some; }; -export type Some = { - readonly isSome: true; - readonly data: Thing; - readonly isNone: false; -}; +/** + * Represents a constant `Some` with any type of data. + */ export const SOMETHING: { readonly isSome: true; readonly isNone: false; @@ -32,15 +47,18 @@ export const SOMETHING: { isNone: false, data: P.select(), } as const; -export const NOTHING: None = { isSome: false, isNone: true } as None; -// export const isSome = (option: Option): option is Some => { -// return option.isSome; -// }; -// export const isNone = (option: Option): option is Nothing => { -// return option.isNone; -// }; +/** + * Represents a constant `None`. + */ +export const NOTHING: None = { isSome: false, isNone: true } as None; +/** + * Wraps a function call in a promise that resolves to an Option. + * @template F - The type of the function. + * @param {F} someFunction - The function to wrap. + * @returns {Promise>>>>} A promise resolving to an Option. + */ export function OptionOf any>( someFunction: F ): Promise>>>> { @@ -60,9 +78,17 @@ export function OptionOf any>( }); } +/** + * Represents the Some variant type. + * @template R - The type of the option. + */ export type SomeVariant> = R extends Some ? R : never; + +/** + * Utility object for creating and managing Option types. + */ export const Option = { some, SOMETHING, @@ -70,6 +96,12 @@ export const Option = { OptionOf, }; +/** + * Converts a value to an Option. + * @template T - The type of the value. + * @param {T} data - The value to convert. + * @returns {Option} An Option containing the value. + */ const optionOfThing = (data: T): Option => { const thingIsNullish = data === null || data === undefined; @@ -95,19 +127,9 @@ const optionOfThing = (data: T): Option => { } else { return some(data); } - // - // I dont consider this kind of thing clean code despite its conciseness: - // - // const optionOfRes = (data: any) => - // null || undefined || - // !thing.length || - // thing.is === "nothing" || - // (typeof thing === "object" ? JSON.stringify(thing) === "{}" : true) - // ? Nothing - // : some(thing.is ? thing["thing"] : thing); - // }; + // This library provides a way to represent values that may or may not exist. It does this by introducing the Option type, which can be either a Some variant, representing a value that is present, or a Nothing variant, representing a value that is not present. // // Why this is useful? diff --git a/result.ts b/result.ts index 680cc37..cbec0eb 100644 --- a/result.ts +++ b/result.ts @@ -1,25 +1,56 @@ import { P, match } from 'npm:ts-pattern@5.1.1'; import { JsonRpcSuccessPattern, JsonRpcErrorPattern } from './json_rpc.ts'; +/** + * Represents a result of an operation, which can either be `Ok` or `Err`. + * @template Thing - The type of the successful result. + * @template Error - The type of the error result. + */ export type Result = Thing extends Ok ? Ok : Ok | (Error extends Err ? Err : Err); +/** + * Represents a successful result. + * @template Thing - The type of the contained value. + */ export type Ok = { readonly isOk: true; readonly data: Thing; readonly isError: false; + /** + * Applies a function to the contained value. + * @template U - The type of the result of the function. + * @param {(data: Thing) => U} fn - The function to apply. + * @returns {Ok} A new Ok instance with the mapped value. + */ map(fn: (data: Thing) => U): Ok; }; +/** + * Represents a failed result. + * @template ErrorData - The type of the error data. + */ export type Err = { readonly isOk: false; readonly data: ErrorData; readonly isError: true; readonly timestamp: Date; + /** + * Applies a function to the contained value (never called). + * @template U - The type of the result of the function. + * @param {(data: never) => U} fn - The function to apply. + * @returns {Err} The same Err instance. + */ map(fn: (data: never) => U): Err; }; +/** + * Creates an Ok instance. + * @template Thing - The type of the contained value. + * @param {Thing} thing - The value to contain. + * @returns {Ok} An Ok instance containing the value. + */ export const Ok = (thing: Thing): Ok => ({ isOk: true, data: thing, @@ -30,53 +61,55 @@ export const Ok = (thing: Thing): Ok => ({ } }); -// Implement the Err factory function with map method +/** + * Creates an Err instance. + * @template ErrorData - The type of the error data. + * @param {ErrorData} errorData - The error data to contain. + * @returns {Err} An Err instance containing the error data. + */ export const Err = (errorData: ErrorData): Err => ({ isOk: false, data: errorData, isError: true, timestamp: new Date(), map(fn: (data: never) => U): Err { - // Err's map simply returns itself, ignoring the map function. return this; } }); -// // Implement the map function for Ok and Err types -// Ok.map = function (fn: (value: T) => U): Result { -// return Ok(fn(this.data)) as Result; -// }; -// -// Err.map = function (fn: (value: T) => any): Result { -// return this; -// }; - +/** + * Represents the Ok variant type. + * @template R - The type of the result. + */ export type OkVariant> = R extends Ok ? R : never; -export type ErrorVariant> = R extends Ok ? never : R; -// export const isOk = ( -// result: Result -// ): result is Ok => { -// return result.isOk; -// }; -// export const isErr = ( -// result: Ok | Err -// ): result is Err => { -// return !result.ok; -// }; +/** + * Represents the Err variant type. + * @template R - The type of the result. + */ +export type ErrorVariant> = R extends Ok ? never : R; +/** + * Represents a constant Err instance with any type of data. + */ export const ERROR: { readonly isOk: false; readonly isError: true; readonly data: any; -} - = { isOk: false, isError: true, data: P.select() } as const; +} = { isOk: false, isError: true, data: P.select() } as const; + +/** + * Represents a constant Ok instance with any type of data. + */ export const OK: { readonly isOk: true; readonly isError: false; readonly data: any; } = { isOk: true, isError: false, data: P.select() } as const; +/** + * Represents the Axios error pattern for matching error responses. + */ const AxiosErrorPattern = { response: { headers: { @@ -85,8 +118,11 @@ const AxiosErrorPattern = { }, data: P.select() } -} as const +} as const; +/** + * Represents the fetch response pattern for matching fetch responses. + */ const FetchResponsePattern = { ok: P.boolean, redirected: P.boolean, @@ -94,6 +130,14 @@ const FetchResponsePattern = { statusText: P.string, } as const; +/** + * Tries to execute a function and returns a Result. + * @template HappyPath - The type of the happy path function. + * @template T - The type of the sad path result. + * @param {HappyPath} happyPath - The function to try. + * @param {(...args: any[]) => T} [sadPath] - The optional sad path function. + * @returns {Promise extends Ok ? OkVariant>['data'] : ReturnType>, T extends Err ? U : T>>} A promise resolving to a Result. + */ export async function Try any, T>( happyPath: HappyPath, sadPath?: (...args: any[]) => T @@ -108,7 +152,7 @@ export async function Try any, T>( > > { const promise = new Promise((resolve) => { - //first try to run the function as if it were async + // first try to run the function as if it were async try { return happyPath() .then((valueWeWant: any) => { @@ -135,7 +179,7 @@ export async function Try any, T>( ); }); } catch { - //if happypath doesnt return a promise well land here + // if happypath doesn't return a promise we'll land here try { const valueWeWant = happyPath(); return resolve( @@ -165,6 +209,9 @@ export async function Try any, T>( >; } +/** + * Utility object for creating and managing Result types. + */ const Result = { ok: Ok, err: Err,