You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.0 KiB
JavaScript

"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)
})
*/