"use strict"; function createResultObject(isSuccessful, containedValue) { return { __isResultType: true, isOK: isSuccessful, isError: !isSuccessful, error: function () { if (!isSuccessful) { return containedValue; } else { // FIXME: Clearer error message, definitely a bug! throw new Error(`The Result is in a success state`); } }, value: function () { if (isSuccessful) { return containedValue; } else { throw containedValue; } }, valueOr: function (defaultValue) { if (isSuccessful) { return containedValue; } else { return defaultValue; } }, mapTo: function ({ ok, error }) { let okMapper = ok ?? ((value) => Result.ok(value)); let errorMapper = error ?? ((error) => Result.error(error)); if (this.isOK) { let mapped = okMapper(containedValue); return (Result.isResult(mapped)) ? mapped : Result.ok(mapped); } else { let mapped = errorMapper(containedValue); return (Result.isResult(mapped)) ? mapped : Result.error(mapped); } }, // valueOr: function (errorCode, errorMessage) { // if (isSuccessful) { // return containedValue; // } else { // // FIXME: Integrate with error-chain somehow? // let error = new Error(errorMessage); // error.code = errorCode; // throw error; // } // }, // FIXME: Chaining, Promise chain integration? // FIXME: Serialization // FIXME: Chaining with error filtering }; } let Result = module.exports = { isResult: function (value) { return (value != null && value.__isResultType === true); }, ok: function (value) { // Emulate what Promises do on `resolve(...)` if (this.isResult(value)) { return value; } else { return createResultObject(true, value); } }, error: function (error) { return createResultObject(false, error); }, wrap: function (callback) { // Always returns a Result try { let result = callback(); return this.ok(result); } catch (error) { return this.error(error); } }, wrapAsync: function (callback) { // Always returns a Promise that resolves to a Result return new Promise((resolve, _reject) => { resolve(callback()); }).then((result) => { return this.ok(result); }).catch((error) => { return this.error(error); }); }, // The below methods are used when it's unknown whether something will produce a Result or just return/throw unwrapValue: function (value) { if (Result.isResult(value)) { return value.unwrap(); } else { return value; } }, unwrap: function (callback) { return Result.unwrapValue(callback()); }, unwrapAsync: function (callback) { return new Promise((resolve, _reject) => { resolve(callback()); }).then((result) => { return Result.unwrapValue(result); }); } }; /* IDEA: result.mapTo({ ok: (value) => value * 2, error: (error) => chain(error, ErrorType, "Foo Bar") }) result.mapTo({ // can return either a result or any value ok: (value) => value * 2, // can return either a result or an Error error: (_error) => result.ok(0) }) */