UNPKG

@synet/patterns

Version:

Robust, battle-tested collection of stable patterns used in Synet packages

179 lines (178 loc) 5.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Result = void 0; /** * A simple and versatile Result pattern implementation * Used for representing the outcome of operations that might fail */ class Result { constructor(_isSuccess, _value, _error) { this._isSuccess = _isSuccess; this._value = _value; this._error = _error; } /** * Returns whether this Result represents a successful operation */ get isSuccess() { return this._isSuccess; } /** * Returns whether this Result represents a failed operation */ get isFailure() { return !this._isSuccess; } /** * Returns the success value * @throws Error if called on a failed result */ get value() { if (!this.isSuccess) { throw new Error("Cannot get value from a failed result"); } return this._value; } /** * Returns the error details if this is a failure result */ get error() { return this._error; } /** * Returns the error message if this is a failure result */ get errorMessage() { return this._error?.message; } /** * Returns the error cause if this is a failure result */ get errorCause() { return this._error?.cause; } /** * Creates a successful result with a value * @param value The success value */ static success(value) { return new Result(true, value); } /** * Creates a failure result with a message, optional cause, and optional context data * @param message Error message describing what went wrong * @param cause Optional underlying error that caused the failure * @param data Optional additional context data for debugging */ static fail(message, cause, ...data) { return new Result(false, undefined, { message, cause, data: data.length > 0 ? data : undefined, }); } /** * Executes the given callback if this is a success result * @param fn Function to execute with the success value * @returns This result, for method chaining */ onSuccess(fn) { if (this.isSuccess) { fn(this.value); } return this; } /** * Executes the given callback if this is a failure result * @param fn Function to execute with the error details * @returns This result, for method chaining */ onFailure(fn) { if (this.isFailure && this._error) { fn(this._error.message, this._error.cause, this._error.data); } return this; } /** * Maps a successful result to another type using the provided function * @param fn Mapping function to apply to the success value * @returns A new Result with either the mapped value or the original error */ map(fn) { if (this.isSuccess) { return Result.success(fn(this.value)); } return Result.fail(this._error?.message || "Unknown error", this._error?.cause, ...(this._error?.data || [])); } /** * Maps a successful result to another Result using the provided function * @param fn Mapping function that returns a new Result * @returns The new Result or the original error */ flatMap(fn) { if (this.isSuccess) { return fn(this.value); } return Result.fail(this._error?.message || "Unknown error", this._error?.cause, ...(this._error?.data || [])); } /** * Recovers from a failure by providing a default value * @param defaultValue Value to use if this result is a failure * @returns A success result with either the original or default value */ recover(defaultValue) { if (this.isSuccess) { return this; } return Result.success(defaultValue); } /** * Attempts to recover from a failure by calling a function * @param fn Function that provides a recovery value * @returns A success result with either the original or recovered value */ recoverWith(fn) { if (this.isSuccess) { return this; } return Result.success(fn(this._error)); } /** * Ensures a condition is met or fails with the provided message * @param condition Predicate that must be true * @param message Error message if condition fails * @returns This result if successful and condition is met, otherwise a failure */ ensure(condition, message) { if (!this.isSuccess) { return this; } return condition(this.value) ? this : Result.fail(message); } /** * Checks if the result is null * @returns true if the result is null, false otherwise * */ isNull() { return this.isSuccess && this.value === null; } combine(results) { const errors = []; const values = []; for (const result of results) { if (result.isFailure) { if (result.error) { errors.push(result.error); } } else { values.push(result.value); } } if (errors.length > 0) { return Result.fail("One or more results failed", undefined, ...errors); } return Result.success(values); } } exports.Result = Result;