import type { ResultWithDefault } from './types.js' import { success } from './result-helpers.js' import { isPromise, getErrorMessage, resolveDefault } from './internals.js' /** * Executes a function, promise, or value and returns a Result type with a fallback default. * If an error occurs, it returns the error message and the default value. * * @template T The type of the successful result * @param {T | Promise | (() => T | Promise)} value - The value, promise, or function to execute * @param {T | (() => T)} defaultValue - The default value or a function to compute it (only called on failure) * @returns {ResultWithDefault | Promise>} A tuple of [error, value] or Promise thereof * * @example * // With a static default * const [err, config] = goTryOr(() => JSON.parse('invalid'), { port: 3000 }) * // err is the error message, config is { port: 3000 } * * @example * // With a computed default (lazy evaluation) * const [err, user] = await goTryOr(fetchUser(id), () => ({ * id: 'anonymous', * name: 'Guest' * })) */ export function goTryOr(fn: () => never, defaultValue: T | (() => T)): ResultWithDefault export function goTryOr( fn: () => Promise, defaultValue: T | (() => T), ): Promise> export function goTryOr( promise: Promise, defaultValue: T | (() => T), ): Promise> export function goTryOr(fn: () => T, defaultValue: T | (() => T)): ResultWithDefault export function goTryOr(value: T, defaultValue: T | (() => T)): ResultWithDefault export function goTryOr( value: T | Promise | (() => T | Promise), defaultValue: T | (() => T), ): ResultWithDefault | Promise> { try { const result = typeof value === 'function' ? (value as () => T | Promise)() : value if (isPromise(result)) { return result .then((resolvedValue) => success(resolvedValue)) .catch((err) => [getErrorMessage(err), resolveDefault(defaultValue)] as const) } return success(result) } catch (err) { return [getErrorMessage(err), resolveDefault(defaultValue)] as const } }