UNPKG

lodash-fantasy

Version:

Fantasy Land compatible types built with lodash.

1,077 lines (997 loc) 30.2 kB
"use strict"; // Third Party const include = require("include")(__dirname); const stream = require("lodash/fp"); // Third Party Aliases const concat = stream.concat; const curry = stream.curry; const each = stream.each; const filter = stream.filter; const find = stream.find; const flow = stream.flow; const get = stream.get; const isEqual = stream.isEqual; const map = stream.map; const negate = stream.negate; const reduce = stream.reduce; // Project const invokeIn = include("src/invokeIn"); /** * The {@link Either} type is intended for handling disjointed, but related values such as the result or exceptional * behavior of some function. It is a disjunction similar to <code>Validation</code>. The key difference of the * {@link Either} type is the focus on the single error as opposed to aggregating many errors. Much like * <code>Validation</code>, {@link Either} is right-biased. * @param {*} value - Value to wrap. * @return {Either} {@link Either} wrapped <code>value</code>. * @example <caption>Via <code>new</code></caption> * * const v1 = new Right(value); * const v2 = new Left(otherValue); * * @example <caption>Via function</caption> * * const v3 = Right.from(value); * const v4 = Left.from(otherValue); * * @example <caption>Via Either function</caption> * * const fs = require("fs"); * const Either = require("lodash-fantasy/data/Either"); * * function readFileSyncSafe(filePath, options) { * let result = null; * * try { * result = Either.Right.from(fs.readFileSync(filePath, options)); * } catch (error) { * result = Either.Left.from(error); * } * * return result; * } * * module.exports = getValue; */ class Either { /** * @static * @property {Right} Right - Either right. */ static get Right() { return Right; } /** * @static * @property {Left} Left - Either left. */ static get Left() { return Left; } /** * Returns a {@link Either} that resolves all of the eithers in the collection into a single Either. * @static * @member * @param {Either[]} eithers - Collection of eithers. * @return {Either} A {@link Either} representing all {@link Right} values or a singular {@link Left}. * @example * * const e1 = fs.readFileSync(filePath1); * // => Right(contents1) * * const e2 = fs.readFileSync(filePath2); * // => Right(contents2) * * const e3 = fs.readFileSync(filePath3); * // => Left(error3) * * const e4 = fs.readFileSync(filePath4); * // => Left(error4) * * Either.all([e1, e2]); * // => Right([contents1, contents2]) * * Either.all([e1, e2, e3]); * // => Left(error3) * * Either.all([e1, e2, e3, e4]); * // => Left(error3) */ static all(eithers) { return find(Either.isLeft, eithers) || Either.of(stream(eithers).map(get("value")).reduce(concat, [])); } /** * Returns the first {@link Right} in the collection or finally a {@link Left}. * @static * @member * @param {Either[]} eithers - Collection of eithers. * @return {Either} First {@link Right} or finally a {@link Left}. * @example * * const e1 = fs.readFileSync(filePath1); * // => Right(contents1) * * const e2 = fs.readFileSync(filePath2); * // => Right(contents2) * * const e3 = fs.readFileSync(filePath3); * // => Left(error3) * * const e4 = fs.readFileSync(filePath4); * // => Left(error4) * * Either.any([e1, e2]); * // => Right(contents1) * * Either.any([e2, e3]); * // => Right(contents2) * * Either.any([e3, e4]); * // => Left(error3) */ static any(either) { return find(Either.isRight, either) || find(Either.isLeft, either); } /** * Creates a new {@link Either} from a <code>value</code>. If the <code>value</code> is already a {@link Either} * instance, the <code>value</code> is returned unchanged. Otherwise, a new {@link Right} is made with the * <code>value</code>. * @static * @member * @param {*} value - Value to wrap in a {@link Either}. * @return {Either} {@link Either} when is the <code>value</code> already wrapped or {@link Right} wrapped * <code>value</code>. * * Either.from(); * // => Right() * * Either.from(true); * // => Right(true) * * Either.from(Right.from(value)); * // => Right(value) * * Either.from(Left.from(error)); * // => Left(error) */ static from(value) { return this.isEither(value) ? value : this.of(value); } /** * Determines whether or not the value is a {@link Either}. * @static * @member * @param {*} value - Value to check. * @return {Boolean} <code>true</code> for {@link Either}; <code>false</code> for anything else. * @example * * isEither(); * // => false * * isEither(Right.from()); * // => true * * isEither(Left.from(error)); * // => true */ static isEither(value) { return value instanceof Either; } /** * Determines whether or not the value is a {@link Left}. * @static * @member * @param {*} value - Value to check. * @return {Boolean} <code>true</code> for {@link Left}; <code>false</code> for {@link Right}. * @example * * isLeft(); * // => false * * isLeft(Left.from(error)); * // => true * * isLeft(Right.from()); * // => false */ static isLeft(value) { return value instanceof Left; } /** * Determines whether or not the value is a {@link Right}. * @static * @member * @param {*} value - Value to check. * @return {Boolean} <code>true</code> for {@link Right}; <code>false</code> for {@link Left}. * @example * * isRight(); * // => false * * isRight(Right.from()); * // => true * * isRight(Left.from(error)); * // => false */ static isRight(value) { return value instanceof Right; } /** * Wraps the <code>value</code> in a {@link Right}. No parts of <code>value</code> are checked. * @static * @member * @param {*} value - Value to wrap. * @return {Right} {@link Right} wrapped <code>value</code>. * @example * * Either.of(); * // => Right() * * Either.of(true); * // => Right(true) * * Either.of(Right.from(value)); * // => Right(Right(value)) * * Either.of(Left.from(error)); * // => Right(Left(error)) */ static of(value) { return new Right(value); } /** * Tries to invoke a <code>supplier</code>. The result of the <code>supplier</code> is returned in a {@link Right}. * If an exception is thrown, the error is returned in a {@link Left}. The <code>function</code> takes no arguments. * @static * @member * @param {Supplier} supplier - Function to invoke. * @return {Either} {@link Right} wrapped supplier result or {@link Left} wrapped <code>error</code>. * @example * * Either.try(normalFunction); * // => Right(returnValue) * * Either.try(throwableFunction); * // => Left(error) */ static try(method) { try { return Right.from(method()); } catch (error) { return Left.from(error); } } constructor(value) { this.value = value; } /** * Applies the function contained in the instance of a {@link Right} to the value contained in the provided * {@link Right}, producing a {@link Right} containing the result. If the instance is a {@link Left}, the result * is the {@link Left} instance. If the instance is a {@link Right} and the provided {@link Either} is {@link Left}, * the result is the provided {@link Left}. * @abstract * @function ap * @memberof Either * @instance * @param {Either} other - Value to apply to the function wrapped in the {@link Right}. * @return {Either} {@link Right} wrapped applied function or {@link Left}. * @example <caption>Right#ap</caption> * * const findPerson = curryN(3, Person.find); // Person.find(name, birthdate, address) * * Right.from(findPerson) // => Right(findPerson) * .ap(Right.try(getName())) // => Right(name) * .ap(Right.try(getBirthdate())) // => Right(birthdate) * .ap(Right.try(getAddress())) // => Right(address) * .ifRight(console.log); // => Log Person.find() response */ /** * Transforms a {@link Either} by applying the first function to the contained value for a {@link Left} or the * second function for a {@link Right}. The result of each map is wrapped in the corresponding type. * @abstract * @function bimap * @memberof Either * @instance * @param {Function} failureMap - Map to apply to the {@link Left}. * @param {Function} successMap - Map to apply to the {@link Right}. * @return {Either} {@link Either} wrapped value mapped with the corresponding mapping function. * @example * * // Using lodash/fp/get * Either.try(loadFile) * .bimap(get("message"), parseFile) * // ... other actions in workflow */ /** * Applies the provided function to the value contained for a {@link Right}. The function should return the value * wrapped in a {@link Either}. If the instance is a {@link Left}, the function is ignored and then instance is * returned unchanged. * @abstract * @function chain * @memberof Either * @instance * @param {Chain.<Either>} method - The function to invoke with the value. * @return {Either} {@link Either} wrapped value returned by the provided <code>method</code>. * @example <caption>Right#chain</caption> * * // Using lodash/fp/curry and getOr * const getConfigOption = curry((path, config) => Either.Right.from(getOr( * Either.Left.from(`Value not found at "${path}"`), * path, * config * ))); * * Either.of(config) * .chain(getConfigOption("path.to.option")) */ /** * Determines whether or not the <code>other</code> is equal in value to the current (<code>this</code>). This is * <strong>not</strong> a reference check. * @param {*} other - Other value to check. * @return {Boolean} <code>true</code> if the two Eithers are equal; <code>false</code> if not equal. * @example <caption>Reflexivity</caption> * * v1.equals(v1) === true; * // => true * * @example <caption>Symmetry</caption> * * v1.equals(v2) === v2.equals(v1); * // => true * * @example <caption>Transitivity</caption> * * (v1.equals(v2) === v2.equals(v3)) && v1.equals(v3) * // => true */ equals(other) { return isEqual(this, other); } /** * Extends the Either. This is used for workflow continuation where the context has shifted. * @abstract * @function extend * @memberof Either * @instance * @param {Extend.<Either>} - method - The function to invoke with the value. * @return {Either} * @example <caption>Workflow continuation</caption> * * // Workflow from makeRequest.js * const makeRequest = requestOptions => requestAsPromise(requestOptions) * .then(Right.from) * .catch(Left.from); * * // Workflow from savePerson.js * const savePerson = curry((requestOptions, eitherPerson) => eitherPerson * .map(Person.from) * .map(person => set("body", person, requestOptions)) * .map(makeRequest) * ); * * // Workflow from processResponse.js * const processResponse = eitherResponse => eitherResponse * .ifLeft(console.error) * .ifRight(console.log); * * Either.of(person) * .extend(savePerson({ method: "POST" })) * .extend(processResponse); */ /** * Returns the value if the instance is a {@link Right} otherwise the <code>null</code>. * @function get * @memberof Either * @instance * @return {*} * @example <caption>Right#get</caption> * * Right.from(value).get(); * // => value * * @example <caption>Left#get</caption> * * Left.from(error).get(); * // => null */ /** * Applies the provided function to the value contain for a {@link Left}. Any return value from the function is * ignored. If the instance is a {@link Right}, the function is ignored and the instance is returned. * @abstract * @function ifLeft * @memberof Either * @instance * @param {Consumer} method - The function to invoke with the value. * @return {Either} Current instance. * @example <caption>Right#ifLeft</caption> * * Right.from(value).ifLeft(doSomething); // void * // => Right(value) * * @example <caption>Left#ifLeft</caption> * * Left.from(error).ifLeft(doSomething); // doSomething(error) * // => Left(error) */ /** * Applies the provided function to the value contain for a {@link Right}. Any return value from the function is * ignored. If the instance is a {@link Left}, the function is ignored and the instance is returned. * @abstract * @function ifRight * @memberof Either * @instance * @param {Consumer} method - The function to invoke with the value. * @return {Either} Current instance. * @example <caption>Right#ifRight</caption> * * Right.from(value).ifRight(doSomething); // doSomething(value) * // => Right(value) * * @example <caption>Left#ifRight</caption> * * Left.from(error).ifRight(doSomething); // void * // => Left(error) */ /** * Determines whether or not the instance is a {@link Left}. * @return {Boolean} <code>true</code> if the instance is a {@link Left}; <code>false</code> is not. * @example <caption>Right#isLeft</caption> * * Right.from(value).isLeft(); * // => false * * @example <caption>Left#isLeft</caption> * * Left.from(error).isLeft(); * // => true */ isLeft() { return this instanceof Left; } /** * Determines whether or not the instance is a {@link Right}. * @return {Boolean} <code>true</code> if the instance is a {@link Right}; <code>false</code> is not. * @example <caption>Right</caption> * * Right.from(value).isLeft(); * // => true * * @example <caption>Left#isRight</caption> * * Left.from(error).isLeft(); * // => false */ isRight() { return this instanceof Right; } /** * Applies the provided function to the value contained for a {@link Right} which is, in turn, wrapped in a * {@link Right}. If the instance is a {@link Left}, the function is ignored and then instance is returned unchanged. * @abstract * @function map * @memberof Either * @instance * @param {Function} method - The function to invoke with the value. * @return {Either} {@link Either} wrapped value mapped with the provided <code>method</code>. * @example * * // Using lodash/fp/flow and sort * Right.from([1, 3, 2]).map(flow(sort, join(", "))); * // => Right("1, 2, 3") * * Left.from(error).map(flow(sort, join(", "))); * // => Left(error) */ /** * @see Either.of */ of(value) { return Either.of(value); } /** * Returns the value if the instance is a {@link Right} otherwise returns the value supplied if the instance is a * {@link Left}. * @abstract * @function orElse * @memberof Either * @instance * @param {Consumer} method - The function to invoke with the value. * @return {*} * @example <caption>Right#orElse</caption> * * Right.from(value).orElse(otherValue); * // => value * * @example <caption>Left#orElse</caption> * * Left.from(error).orElse(otherValue); * // => otherValue */ /** * Return the value if the instance is a {@link Right} otherwise returns the value from the function provided. * @abstract * @function orElseGet * @memberof Either * @instance * @param {Supplier} method - The function supplying the optional value. * @return {*} * @example <caption>Right#orElseGet</caption> * * Right.from(value).orElseGet(getOtherValue); * // => value * * @example <caption>Left#orElseGet</caption> * * Left.from(error).orElse(getOtherValue); * // => otherValue */ /** * Returns the value if the instance is a {@link Right} otheriwse throws the <code>Error</code> supplied by the * function provided. The function receives the value of the {@link Left} as its argument. * @abstract * @function orElseThrow * @memberof Either * @instance * @param {Function} method - The function to invoke with the value. * @return {*} * @throws {Error} returned by the provided function. * @example <caption>Right#orElseThrow</caption> * * Right.from(value).orElseThrow(createException); * // => value * * @example <caption>Left#orElseThrow</caption> * * Left.from(error).orElseThrow(createException); // throw createException(error) */ /** * Converts the Either to a {@link Maybe}. {@link Right} becomes {@link Just} and {@link Left} becomes * {@link Nothing}. * @abstract * @function toMaybe * @memberof Either * @instance * @param {Maybe} maybe - Maybe implementation. * @return {Maybe} {@link Maybe} wrapped <code>value</code>. * @example <caption>Right#toMaybe</caption> * * Right.from(value).toMaybe(Maybe); * // => Maybe.Just(value); * * @example <caption>Left#toMaybe</caption> * * Left.from(error).toMaybe(Maybe); * // => Maybe.Nothing(); */ /** * Converts the Either to a <code>Promise</code> using the provided <code>Promise</code> implementation. * @abstract * @function toPromise * @memberof Either * @instance * @param {Promise} promise - Promise implementation. * @return {Promise} <code>Promise</code> wrapped <code>value</code>. * @example <caption>Right#toPromise</caption> * * const Bluebird = require("bluebird"); * * Right.from(value).toPromise(Bluebird); * // => Promise.resolve(value); * * @example <caption>Left#toPromise</caption> * * const Bluebird = require("bluebird"); * * Left.from(error).toPromise(Bluebird); * // => Promise.reject(error); */ /** * Returns a <code>String</code> representation of the {@link Either}. * @abstract * @function toString * @memberof Either * @instance * @return {String} <code>String</code> representation. * @example <caption>Right#toString</caption> * * Right.from(1).toString(); * // => "Either.Right(1)" * * @example <caption>Left#toString</caption> * * Left.from(error).toString(); * // => "Either.Left(error)" */ /** * Converts the Either to a {@link Validation}. {@link Right} becomes {@link Success} and {@link Left} becomes * {@link Failure}. * @abstract * @function toValidation * @memberof Either * @instance * @param {Validation} validation - Validation implementation. * @return {Validation} {@link Validation} wrapped <code>value</code>. * @example <caption>Right#toValidation</caption> * * Right.from(value).toValidation(Validation); * // => Validation.Success(value); * * @example <caption>Left#toValidation</caption> * * Left.from(error).toValidation(Validation); * // => Validation.Failure(); */ } /** * Iterates over a collection of eithers and invokes the <code>iteratee</code> for each {@link Either}. The * <code>iteratee</code> is invoked with one argument: <code>(value)</code>. Iteratee functions may exit iteration * early by explicitly returning a {@link Left}. * @static * @member * @param {Consumer} iteratee - The function to invoke per iteration. * @param {Either[]} values - Collection of Eithers over which to iterate. * @return {Either[]} Current {@link Either} collection. * @example * * const optionalValues = [ * getValue(path1, source), // => Right(value1) * getValue(path2, source), // => Right(value2) * getValue(path3, source), // => Left() * getValue(path4, source) // => Left() * ]; * * Either.each(eitherValue => eitherValue.ifRight(console.log), optionalValues); * // => Right(value1) * // => Right(value2) */ Either.each = curry((iteratee, values) => each( flow(iteratee, negate(Either.isLeft)), values )); /** * Determines whether or not the <code>other</code> is equal in value to the current (<code>this</code>). This is * <strong>not</strong> a reference check. * @static * @member * @param {*} other - Other value to check. * @return {Boolean} <code>true</code> if the two validations are equal; <code>false</code> if not equal. * @example <caption>Reflexivity</caption> * * Either.equals(v1, v1) === true; * // => true * * @example <caption>Symmetry</caption> * * Either(v1, v2) === Either.equals(v2, v1); * // => true * * @example <caption>Transitivity</caption> * * (Either.equals(v1, v2) === Either.equals(v2, v3)) && Either.equals(v1, v3) * // => true */ Either.equals = isEqual; /** * Iterates over a collection of values, returning an array of all values the <code>predicate</code> for which returns * truthy. The <code>predicate</code> is invoked with one argument: <code>(value)</code>. * @static * @member * @param {Predicate} predicate - The function to invoke per iteration. * @param {Eithers[]} values - Collection of values over which to iterate. * @return {Eithers[]} Filtered {@link Either} collection. * @example <caption>Filter and log failures</caption> * * const optionalValues = [ * getValue(path1, config), // => Right(value1) * getValue(path2, config), // => Right(value2) * getValue(path3, config), // => Left() * getValue(path4, config) // => Left() * ]; * * Either.filter(Either.isRight, optionalValues); * // => [Right(value1), Right(value2)] */ Either.filter = filter; /** * Creates an array of values by invoking {@link Either#map} with the <code>iteratee</code> for each {@link Either} in * the collection. The iteratee is invoked with one argument: <code>(value)</code>. * @static * @member * @param {Function} iteratee - The function to invoke per iteration. * @param {Either[]} values - Collection of values over which to iterate. * @return {Either[]} Mapped {@link Either} collection. * @example <caption>Mapping each Either's value</caption> * * const optionalValues = [ * getValue(path1, config), // => Right(1.5) * getValue(path2, config), // => Right(2.25) * getValue(path3, config), // => Left(error1) * getValue(path4, config) // => Left(error2) * ]; * * Either.mapIn(Math.floor, optionalValues); * // => [Right(1), Right(2), Left(error1), Left(error2)] */ Either.mapIn = curry((iteratee, values) => map(invokeIn("map", iteratee), values)); /** * Creates an array of values by running each {@link Either} in collection through the <code>iteratee</code>. The * iteratee is invoked with one argument: <code>(value)</code>. * @static * @member * @param {Function} iteratee - The function to invoke per iteration. * @param {Either[]} values - Collection of values over which to iterate. * @return {Either[]} Mapped collection. * @example <caption>Mapping all values to promises</caption> * * const optionalValues = [ * getValue(path1, config), // => Right(value1) * getValue(path2, config), // => Right(value2) * getValue(path3, config), // => Left(error1) * getValue(path4, config) // => Left(error2) * ]; * * Either.map(Either.toPromise, optionalValues); * // => [Promise.resolve(price1), Promise.resolve(price2), Promise.reject(error1), Promise.reject(error2)] */ Either.map = map; /** * Reduces collection to a value which is the accumulated result of running each value in the <code>values</code> * collection through the <code>iteratee</code>, where each successive invocation is supplied the return value of the * previous. The iteratee is invoked with two arguments: <code>(accumulator, value)</code>. * @static * @member * @param {Reduction} iteratee - The function to invoke per iteration. * @param {*} accumulator - The initial value. * @param {Either[]} values - Collection of values over which to iterate. * @return {*} Accumulator. * @example * * const eitherValues = [ * getValue(path1, config), // => Right(value1) * getValue(path2, config), // => Right(value2) * getValue(path3, config), // => Left(error1) * getValue(path4, config) // => Left(error2) * ]; * * // Using lodash/fp/concat * Either.reduce( * (result, value) => value.isRight() ? concat(result, value.get()) : result, * [], * eitherValues * ); * // => [value1, value2] */ Either.reduce = reduce; /** * Converts a {@link Either} to a {@link Maybe}. {@link Right} becomes a {@link Just} and {@link Left} becomes * {@link Nothing}. * @static * @member * @param {Maybe} maybe - Maybe implementation. * @param {Either} value - Either to convert. * @return {Maybe} {@link Maybe} wrapped <code>value</code>. * @example <caption>Right to Just</caption> * * Either.toMaybe(Maybe, Right.from(value)); * // => Maybe.Just(value); * * @example <caption>Left to Nothing</caption> * * Either.toMaybe(Maybe, Left.from(error)); * // => Maybe.Nothing(); */ Either.toMaybe = invokeIn("toMaybe"); /** * Converts a validation to a <code>Promise</code> using the provided <code>Promise</code> implementation. * @static * @member * @param {Promise} promise - Promise implementation. * @param {Either} value - Either to convert. * @return {Promise} <code>Promise</code> wrapped <code>value</code>. * @example <caption>Convert with bluebird's implementation of Promise</caption> * * const toBluebird = Either.toPromise(require("bluebird")); * * toBluebird(Right.from(value)); * // => Promise.resolve(value); * * toBluebird(Left.from(error)); * // => Promise.reject(error); */ Either.toPromise = invokeIn("toPromise"); /** * Converts a {@link Either} to a {@link Validation}. {@link Right} becomes a {@link Success} and {@link Left} becomes * {@link Failure}. * @static * @member * @param {Validation} validation - Validation implementation. * @param {Either} value - Either to convert. * @return {Validation} {@link Validation} wrapped <code>value</code>. * @example <caption>Right to Success</caption> * * Either.toValidation(Validation, Right.from(value)); * // => Validation.Success(value); * * @example <caption>Left to Failure</caption> * * Either.toValidation(Validation, Left.from(error)); * // => Validation.Failure(); */ Either.toValidation = invokeIn("toValidation"); /** * @extends Either * @inheritdoc */ class Left extends Either { /** * Creates a new {@link Left} from a <code>value</code>. If the <code>value</code> is already a {@link Either} * instance, the <code>value</code> is returned unchanged. Otherwise, a new {@link Left} is made with the * <code>value</code>. * @static * @param {*} value - Value to wrap in a {@link Left}. * @return {Either} {@link Either} when is the <code>value</code> already wrapped or {@link Left} wrapped * <code>value</code>. * @example <caption>Left from nothing</caption> * * Left.from(); * // => Left() * * @example <caption>Left from arbitrary value</caption> * * Left.from(error); * // => Left(error) * * @example <caption>Left from Right</caption> * * Left.from(Right.from(value)); * // => Right.from(value) * * @example <caption>Left from another Left</caption> * * Left.from(Left.from(error)); * // => Left(error) */ static from(value) { return Either.isEither(value) ? value : new Left(value); } constructor(value) { super(value); } ap() { return this; } bimap(leftMap) { return Left.from(leftMap(this.value)); } chain() { return this; } extend() { return this; } get() { return null; } ifLeft(method) { method(); return this; } ifRight() { return this; } map() { return this; } orElse(value) { return value; } orElseGet(method) { return method(); } orElseThrow(method) { throw method(this.value); } toMaybe(maybe) { return new maybe.Nothing(); } toPromise(promise) { return promise.reject(this.value); } toString() { return `Either.Left(${this.value})`; } toValidation(validation) { return new validation.Failure(this.value); } } /** * @extends Either * @inheritdoc */ class Right extends Either { /** * Creates a new {@link Right} from a <code>value</code>. If the <code>value</code> is already a {@link Either} * instance, the <code>value</code> is returned unchanged. Otherwise, a new {@link Right} is made with the * <code>value</code>. * @static * @param {*} value - Value to wrap in a {@link Right}. * @return {Either} {@link Either} when is the <code>value</code> already wrapped or {@link Right} wrapped * <code>value</code>. * @example <caption>Right from nothing</caption> * * Right.from(); * // => Right() * * @example <caption>Right from arbitrary value</caption> * * Right.from(true); * // => Right(true) * * @example <caption>Right from another Right</caption> * * Right.from(Right.from(value)); * // => Right(value) * * @example <caption>Right from Left</caption> * * Right.from(Left.from(error)); * // => Left(error) */ static from(value) { return Either.isEither(value) ? value : new Right(value); } constructor(value) { super(value); } ap(other) { return other.map(this.value); } bimap(leftMap, rightMap) { return Right.from(rightMap(this.value)); } chain(method) { return Either.from(method(this.value)); } extend(method) { return Either.from(method(this)); } get() { return this.value; } ifLeft() { return this; } ifRight(method) { method(this.value); return this; } map(method) { return Right.of(method(this.value)); } orElse() { return this.value; } orElseGet() { return this.value; } orElseThrow() { return this.value; } toMaybe(maybe) { return new maybe.Just(this.value); } toPromise(promise) { return promise.resolve(this.value); } toString() { return `Either.Right(${this.value})`; } toValidation(validation) { return new validation.Success(this.value); } } module.exports = Either;