UNPKG

@zeix/cause-effect

Version:

Cause & Effect - reactive state management primitives library for TypeScript.

181 lines (164 loc) 4.41 kB
import { isFunction, valueString } from './util' /* === Types === */ /** * A type guard function that validates whether an unknown value is of type T. * Used to ensure type safety when updating signals. * * @template T - The type to guard against * @param value - The value to check * @returns True if the value is of type T */ type Guard<T extends {}> = (value: unknown) => value is T /* === Error Classes === */ /** * Error thrown on re-entrance on an already running function. */ class CircularDependencyError extends Error { /** * Constructs a new CircularDependencyError. * * @param where - The location where the error occurred. */ constructor(where: string) { super(`[${where}] Circular dependency detected`) this.name = 'CircularDependencyError' } } /** * Error thrown when a signal value is null or undefined. */ class NullishSignalValueError extends TypeError { /** * Constructs a new NullishSignalValueError. * * @param where - The location where the error occurred. */ constructor(where: string) { super(`[${where}] Signal value cannot be null or undefined`) this.name = 'NullishSignalValueError' } } /** * Error thrown when a signal is read before it has a value. */ class UnsetSignalValueError extends Error { /** * Constructs a new UnsetSignalValueError. * * @param where - The location where the error occurred. */ constructor(where: string) { super(`[${where}] Signal value is unset`) this.name = 'UnsetSignalValueError' } } /** * Error thrown when a signal value is invalid. */ class InvalidSignalValueError extends TypeError { /** * Constructs a new InvalidSignalValueError. * * @param where - The location where the error occurred. * @param value - The invalid value. */ constructor(where: string, value: unknown) { super(`[${where}] Signal value ${valueString(value)} is invalid`) this.name = 'InvalidSignalValueError' } } /** * Error thrown when a callback is invalid. */ class InvalidCallbackError extends TypeError { /** * Constructs a new InvalidCallbackError. * * @param where - The location where the error occurred. * @param value - The invalid value. */ constructor(where: string, value: unknown) { super(`[${where}] Callback ${valueString(value)} is invalid`) this.name = 'InvalidCallbackError' } } class ReadonlySignalError extends Error { /** * Constructs a new ReadonlySignalError. * * @param where - The location where the error occurred. */ constructor(where: string) { super(`[${where}] Signal is read-only`) this.name = 'ReadonlySignalError' } } /** * Error thrown when an API requiring an owner is called without one. */ class RequiredOwnerError extends Error { /** * Constructs a new RequiredOwnerError. * * @param where - The location where the error occurred. */ constructor(where: string) { super(`[${where}] Active owner is required`) this.name = 'RequiredOwnerError' } } class DuplicateKeyError extends Error { constructor(where: string, key: string, value?: unknown) { super( `[${where}] Could not add key "${key}"${ value ? ` with value ${JSON.stringify(value)}` : '' } because it already exists`, ) this.name = 'DuplicateKeyError' } } /* === Validation Functions === */ function validateSignalValue<T extends {}>( where: string, value: unknown, guard?: Guard<T>, ): asserts value is T { if (value == null) throw new NullishSignalValueError(where) if (guard && !guard(value)) throw new InvalidSignalValueError(where, value) } function validateReadValue<T extends {}>( where: string, value: T | null | undefined, ): asserts value is T { if (value == null) throw new UnsetSignalValueError(where) } function validateCallback( where: string, value: unknown, ): asserts value is (...args: unknown[]) => unknown function validateCallback<T>( where: string, value: unknown, guard: (value: unknown) => value is T, ): asserts value is T function validateCallback( where: string, value: unknown, guard: (value: unknown) => boolean = isFunction, ): void { if (!guard(value)) throw new InvalidCallbackError(where, value) } export { type Guard, CircularDependencyError, NullishSignalValueError, InvalidSignalValueError, UnsetSignalValueError, InvalidCallbackError, ReadonlySignalError, RequiredOwnerError, DuplicateKeyError, validateSignalValue, validateReadValue, validateCallback, }