"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 isNull = stream.isNull;
const isUndefined = stream.isUndefined;
const map = stream.map;
const negate = stream.negate;
const reduce = stream.reduce;
// Project
const invokeIn = include("src/invokeIn");
/**
* The {@link Maybe} type is intended for values that may or may not be null or undefined. It is a disjunction similar
* to <code>Either</code>. The key difference of the {@link Maybe} type is the focus on a value or nothing. Much like
* <code>Either</code>, {@link Maybe} is right-biased.
* @param {*} value - Value to wrap.
* @return {Maybe} {@link Maybe} wrapped <code>value</code>.
* @example <caption>Via <code>new</code></caption>
*
* const v1 = new Just(value);
* const v2 = new Nothing();
*
* @example <caption>Via function</caption>
*
* const v3 = Just.from(value);
* const v4 = Nothing.from();
*
* @example <caption>Via Maybe function</caption>
*
* const getOr = require("lodash/fp/getOr");
* const Maybe = require("lodash-fantasy/data/Maybe");
*
* function getValue(path, context) {
* return getOr(Maybe.Nothing.from(), path, context);
* }
*
* module.exports = getValue;
*/
class Maybe {
/**
* @static
* @property {Just} Just - Maybe just.
*/
static get Just() {
return Just;
}
/**
* @static
* @property {Nothing} Nothing - Maybe nothing.
*/
static get Nothing() {
return Nothing;
}
/**
* Returns a {@link Maybe} that resolves all of the maybes in the collection into a single Maybe.
* @static
* @member
* @param {Maybe[]} maybes - Collection of maybes.
* @return {Maybe} A {@link Maybe} representing all {@link Just} values or a singular {@link Nothing}.
* @example
*
* const m1 = getArbitraryProperty(context1);
* // => Just(context1)
*
* const m2 = getArbitraryProperty(context2);
* // => Just(context2)
*
* const m3 = getArbitraryProperty(context3);
* // => Nothing()
*
* const m4 = getArbitraryProperty(context4);
* // => Nothing()
*
* Maybe.all([m1, m2]);
* // => Just([context1, context2])
*
* Maybe.all([m1, m2, m3]);
* // => Nothing()
*
* Maybe.all([m1, m2, m3, m4]);
* // => Nothing()
*/
static all(maybes) {
return find(Maybe.isNothing, maybes) || Maybe.of(stream(maybes).map(get("value")).reduce(concat, []));
}
/**
* Returns the first {@link Just} in the collection or finally a {@link Nothing}.
* @static
* @member
* @param {Maybe[]} maybes - Collection of maybes.
* @return {Maybe} First {@link Just} or finally a {@link Nothing}.
* @example
*
* const m1 = getArbitraryProperty(context1);
* // => Just(context1)
*
* const m2 = getArbitraryProperty(context2);
* // => Just(context2)
*
* const m3 = getArbitraryProperty(context3);
* // => Nothing()
*
* const m4 = getArbitraryProperty(context4);
* // => Nothing()
*
* Maybe.any([m1, m2]);
* // => Just(context1)
*
* Maybe.any([m2, m3]);
* // => Just(context2)
*
* Maybe.any([m3, m4]);
* // => Nothing()
*/
static any(maybes) {
return find(Maybe.isJust, maybes) || new Nothing();
}
/**
* Creates a new {@link Maybe} from a <code>value</code>. If the <code>value</code> is already a {@link Maybe}
* instance, the <code>value</code> is returned unchanged. Otherwise, a new {@link Just} is made with the
* <code>value</code>.
* @static
* @member
* @param {*} value - Value to wrap in a {@link Maybe}.
* @return {Maybe} {@link Maybe} when is the <code>value</code> already wrapped or {@link Just} wrapped
* <code>value</code>.
*
* Maybe.from();
* // => Just()
*
* Maybe.from(true);
* // => Just(true)
*
* Maybe.from(Just.from(value));
* // => Just(value)
*
* Maybe.from(Nothing.from());
* // => Nothing()
*/
static from(value) {
return this.isMaybe(value) ? value : this.ofNullable(value);
}
/**
* Determines whether or not the value is a {@link Just}.
* @static
* @member
* @param {*} value - Value to check.
* @return {Boolean} <code>true</code> for {@link Just}; <code>false</code> for {@link Nothing}.
* @example
*
* isJust();
* // => false
*
* isJust(null);
* // => false
*
* isJust(Just.from());
* // => true
*
* isJust(Nothing.from());
* // => false
*/
static isJust(value) {
return value instanceof Just;
}
/**
* Determines whether or not the value is a {@link Maybe}.
* @static
* @member
* @param {*} value - Value to check.
* @return {Boolean} <code>true</code> for {@link Maybe}; <code>false</code> for anything else.
* @example
*
* isMaybe();
* // => false
*
* isMaybe(null);
* // => false
*
* isMaybe(Just.from());
* // => true
*
* isMaybe(Nothing.from());
* // => true
*/
static isMaybe(value) {
return value instanceof Maybe;
}
/**
* Determines whether or not the value is a {@link Nothing}.
* @static
* @member
* @param {*} value - Value to check.
* @return {Boolean} <code>true</code> for {@link Nothing}; <code>false</code> for {@link Just}.
* @example
*
* isNothing();
* // => false
*
* isNothing(null);
* // => false
*
* isNothing(Nothing.from());
* // => true
*
* isNothing(Just.from());
* // => false
*/
static isNothing(value) {
return value instanceof Nothing;
}
/**
* Wraps the <code>value</code> in a {@link Just}. No parts of <code>value</code> are checked.
* @static
* @member
* @param {*} value - Value to wrap.
* @return {Just} {@link Just} wrapped <code>value</code>.
* @example
*
* Maybe.of();
* // => Just()
*
* Maybe.of(true);
* // => Just(true)
*
* Maybe.of(Just.from(value));
* // => Just(Just(value))
*
* Maybe.of(Nothing.from());
* // => Just(Nothing())
*/
static of(value) {
return new Just(value);
}
/**
* Wraps the <code>value</code> in a {@link Just} if the value is not <code>null</code>, <code>undefined</code>, or
* {@link Nothing}.
* @static
* @member
* @param {*} value - Value to wrap.
* @return {Maybe} {@link Just} wrapped <code>value</code> or {@link Nothing}.
* @example
*
* Maybe.ofNullable();
* // => Nothing()
*
* Maybe.ofNullable(null);
* // => Nothing()
*
* Maybe.ofNullable(true);
* // => Just(true)
*
* Maybe.ofNullable(Just.from(value));
* // => Just(Just(value))
*
* Maybe.ofNullable(Nothing.from());
* // => Nothing()
*/
static ofNullable(value) {
return isNull(value) || isUndefined(value) || Maybe.isNothing(value) ?
new Nothing() :
new Just(value);
}
/**
* Tries to invoke a <code>supplier</code>. The result of the <code>supplier</code> is returned in a
* {@link Just}. If an exception is thrown, a {@link Nothing} is returned. The <code>function</code> takes no
* arguments.
* @static
* @member
* @param {Supplier} supplier - Function to invoke.
* @return {Maybe} {@link Just} wrapped supplier result or {@link Nothing} wrapped <code>error</code>.
* @example
*
* Maybe.try(normalFunction);
* // => Just(returnValue)
*
* Maybe.try(throwableFunction);
* // => Nothing()
*/
static try(method) {
try {
return Just.from(method());
} catch (error) {
return Nothing.from();
}
}
constructor(value) {
this.value = value;
}
/**
* Applies the function contained in the instance of a {@link Just} to the value contained in the provided
* {@link Just}, producing a {@link Just} containing the result. If the instance is a {@link Nothing}, the result
* is the {@link Nothing} instance. If the instance is a {@link Just} and the provided {@link Maybe} is
* {@link Nothing}, the result is the provided {@link Nothing}.
* @abstract
* @function ap
* @memberof Maybe
* @instance
* @param {Maybe} other - Value to apply to the function wrapped in the {@link Just}.
* @return {Maybe} {@link Just} wrapped applied function or {@link Nothing}.
* @example <caption>Just#ap</caption>
*
* const findPerson = curryN(3, Person.find); // Person.find(name, birthdate, address)
*
* Just.from(findPerson) // => Just(findPerson)
* .ap(Just.ofNullable(name)) // => Just(name)
* .ap(Just.ofNullable(birthdate)) // => Just(birthdate)
* .ap(Just.ofNullable(address)) // => Just(address)
* .ifJust(console.log); // => Log Person.find() response
*/
/**
* Applies the provided function to the value contained for a {@link Just}. The function should return the value
* wrapped in a {@link Maybe}. If the instance is a {@link Nothing}, the function is ignored and then instance is
* returned unchanged.
* @abstract
* @function chain
* @memberof Maybe
* @instance
* @param {Chain.<Maybe>} method - The function to invoke with the value.
* @return {Maybe} {@link Maybe} wrapped value returned by the provided <code>method</code>.
* @example <caption>Just#chain</caption>
*
* // Using lodash/fp/curry and get
* const getConfigOption = curry((path, config) => Maybe.ofNullable(get(path, config));
*
* Maybe.ofNullable(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 Maybes 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 Maybe. This is used for workflow continuation where the context has shifted.
* @abstract
* @function extend
* @memberof Maybe
* @instance
* @param {Extend.<Maybe>} - method - The function to invoke with the value.
* @return {Maybe}
* @example <caption>Workflow continuation</caption>
*
* // Workflow from makeRequest.js
* const makeRequest = requestOptions => requestAsPromise(requestOptions)
* .then(Just.from)
* .catch(Nothing.from);
*
* // Workflow from savePerson.js
* const savePerson = curry((requestOptions, optionalPerson) => optionalPerson
* .map(Person.from)
* .map(person => set("body", person, requestOptions))
* .map(makeRequest)
* );
*
* // Workflow from processResponse.js
* const processResponse = optionalResponse => optionalResponse
* .ifJust(console.log);
*
* Maybe.ofNullable(person)
* .extend(savePerson({ method: "POST" }))
* .extend(processResponse);
*/
/**
* Returns the value if the instance is a {@link Just} otherwise the <code>null</code>.
* @function get
* @memberof Maybe
* @instance
* @return {*}
* @example <caption>Just#get</caption>
*
* Just.from(value).get();
* // => value
*
* @example <caption>Nothing#get</caption>
*
* Nothing.from().get();
* // => null
*/
get() {
return this.value;
}
/**
* Applies the provided function to the value contain for a {@link Just}. Any return value from the function is
* ignored. If the instance is a {@link Nothing}, the function is ignored and the instance is returned.
* @abstract
* @function ifJust
* @memberof Maybe
* @instance
* @param {Consumer} method - The function to invoke with the value.
* @return {Maybe} Current instance.
* @example <caption>Just#ifJust</caption>
*
* Just.from(value).ifJust(doSomething); // doSomething(value)
* // => Just(value)
*
* @example <caption>Nothing#ifJust</caption>
*
* Nothing.from().ifJust(doSomething); // void
* // => Nothing()
*/
/**
* Applies the provided function to the value contain for a {@link Nothing}. Any return value from the function is
* ignored. If the instance is a {@link Just}, the function is ignored and the instance is returned.
* @abstract
* @function ifNothing
* @memberof Maybe
* @instance
* @param {Callable} method - The function to invoke.
* @return {Maybe} Current instance.
* @example <caption>Just#ifNothing</caption>
*
* Just.from(value).ifNothing(doSomething); // void
* // => Just(value)
*
* @example <caption>Nothing#ifNothing</caption>
*
* Nothing.from().ifNothing(doSomething); // doSomething()
* // => Nothing()
*/
/**
* Determines whether or not the instance is a {@link Nothing}.
* @return {Boolean} <code>true</code> if the instance is a {@link Nothing}; <code>false</code> is not.
* @example <caption>Just#isNothing</caption>
*
* Just.from(value).isNothing();
* // => false
*
* @example <caption>Nothing#isNothing</caption>
*
* Nothing.from().isNothing();
* // => true
*/
isNothing() {
return this instanceof Nothing;
}
/**
* Determines whether or not the instance is a {@link Just}.
* @return {Boolean} <code>true</code> if the instance is a {@link Just}; <code>false</code> is not.
* @example <caption>Just</caption>
*
* Just.from(value).isNothing();
* // => true
*
* @example <caption>Nothing#isJust</caption>
*
* Nothing.from().isNothing();
* // => false
*/
isJust() {
return this instanceof Just;
}
/**
* Applies the provided function to the value contained for a {@link Just} which is, in turn, wrapped in a
* {@link Just}. If the instance is a {@link Nothing}, the function is ignored and then instance is returned
* unchanged.
* @abstract
* @function map
* @memberof Maybe
* @instance
* @param {Function} method - The function to invoke with the value.
* @return {Maybe} {@link Maybe} wrapped value mapped with the provided <code>method</code>.
* @example
*
* // Using lodash/fp/flow and sort
* Just.from([1, 3, 2]).map(flow(sort, join(", ")));
* // => Just("1, 2, 3")
*
* Nothing.from().map(flow(sort, join(", ")));
* // => Nothing()
*/
/**
* @see Maybe.ofNullable
*/
of(value) {
return Maybe.of(value);
}
/**
* Returns the value if the instance is a {@link Just} otherwise returns the value supplied if the instance is a
* {@link Nothing}.
* @abstract
* @function orElse
* @memberof Maybe
* @instance
* @param {Consumer} method - The function to invoke with the value.
* @return {*}
* @example <caption>Just#orElse</caption>
*
* Just.from(value).orElse(otherValue);
* // => value
*
* @example <caption>Nothing#orElse</caption>
*
* Nothing.from().orElse(otherValue);
* // => otherValue
*/
/**
* Return the value if the instance is a {@link Just} otherwise returns the value from the function provided.
* @abstract
* @function orElseGet
* @memberof Maybe
* @instance
* @param {Supplier} method - The function supplying the optional value.
* @return {*}
* @example <caption>Just#orElseGet</caption>
*
* Just.from(value).orElseGet(getOtherValue);
* // => value
*
* @example <caption>Nothing#orElseGet</caption>
*
* Nothing.from().orElseGet(getOtherValue);
* // => otherValue
*/
/**
* Returns the value if the instance is a {@link Just} otheriwse throws the <code>Error</code> supplied by the
* function provided.
* @abstract
* @function orElseThrow
* @memberof Maybe
* @instance
* @param {Supplier} method - The function to invoke with the value.
* @return {*}
* @throws {Error} returned by the provided function.
* @example <caption>Just#orElseThrow</caption>
*
* Just.from(value).orElseThrow(createException);
* // => value
*
* @example <caption>Nothing#orElseThrow</caption>
*
* Nothing.from().orElseThrow(createException); // throw createException()
*/
/**
* Converts the {@link Maybe} to an {@link Either}. {@link Just} becomes a {@link Right} and {@link Nothing} becomes a
* {@link Left}.
* @abstract
* @function toEither
* @memberof Maybe
* @instance
* @param {Either} either - Either implementation.
* @return {Either} {@link Either} wrapped <code>value</code>.
* @example <caption>Just#toEither</caption>
*
* const Either = require("lodash-fantasy/data/Either");
*
* Just.from(value).toEither(Either);
* // => Either.Right(value);
*
* @example <caption>Nothing#toEither</caption>
*
* const Either = require("lodash-fantasy/data/Either");
*
* Nothing.from().toEither(Either);
* // => Either.Left(null);
*/
/**
* Converts the Maybe to a <code>Promise</code> using the provided <code>Promise</code> implementation.
* @abstract
* @function toPromise
* @memberof Maybe
* @instance
* @param {Promise} promise - Promise implementation.
* @return {Promise} <code>Promise</code> wrapped <code>value</code>.
* @example <caption>Just#toPromise</caption>
*
* const Bluebird = require("bluebird");
*
* Just.from(value).toPromise(Bluebird);
* // => Promise.resolve(value);
*
* @example <caption>Nothing#toPromise</caption>
*
* const Bluebird = require("bluebird");
*
* Nothing.from().toPromise(Bluebird);
* // => Promise.reject(null);
*/
/**
* Returns a <code>String</code> representation of the {@link Maybe}.
* @abstract
* @function toString
* @memberof Maybe
* @instance
* @return {String} <code>String</code> representation.
* @example <caption>Just#toString</caption>
*
* Just.from(1).toString();
* // => "Maybe.Just(1)"
*
* @example <caption>Nothing#toString</caption>
*
* Nothing.from().toString();
* // => "Maybe.Nothing(null)"
*/
/**
* Converts the {@link Maybe} to an {@link Validation}. {@link Just} becomes a {@link Success} and {@link Nothing}
* becomes a {@link Failure}.
* @abstract
* @function toValidation
* @memberof Maybe
* @instance
* @param {Validation} validation - Validation implementation.
* @return {Validation} {@link Validation} wrapped <code>value</code>.
* @example <caption>Just#toValidation</caption>
*
* const Validation = require("lodash-fantasy/data/Validation");
*
* Just.from(value).toValidation(Validation);
* // => Validation.Success(value);
*
* @example <caption>Nothing#toValidation</caption>
*
* const Validation = require("lodash-fantasy/data/Validation");
*
* Nothing.from().toValidation(Validation);
* // => Validation.Failure([null]);
*/
}
/**
* Iterates over a collection of maybes and invokes the <code>iteratee</code> for each {@link Maybe}. The
* <code>iteratee</code> is invoked with one argument: <code>(value)</code>. Iteratee functions may exit iteration
* early by explicitly returning a {@link Nothing}.
* @static
* @member
* @param {Consumer} iteratee - The function to invoke per iteration.
* @param {Maybe[]} values - Collection of Maybes over which to iterate.
* @return {Maybe[]} Current {@link Maybe} collection.
* @example
*
* const optionalValues = [
* getValue(path1, source), // => Just(value1)
* getValue(path2, source), // => Just(value2)
* getValue(path3, source), // => Nothing()
* getValue(path4, source) // => Nothing()
* ];
*
* Maybe.each(optionalValue => optionalValue.ifJust(console.log), optionalValues);
* // => Just(value1)
* // => Just(value2)
*/
Maybe.each = curry((iteratee, values) => each(
flow(iteratee, negate(Maybe.isNothing)),
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>
*
* Maybe.equals(v1, v1) === true;
* // => true
*
* @example <caption>Symmetry</caption>
*
* Maybe(v1, v2) === Maybe.equals(v2, v1);
* // => true
*
* @example <caption>Transitivity</caption>
*
* (Maybe.equals(v1, v2) === Maybe.equals(v2, v3)) && Maybe.equals(v1, v3)
* // => true
*/
Maybe.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 {Maybes[]} values - Collection of values over which to iterate.
* @return {Maybes[]} Filtered {@link Maybe} collection.
* @example <caption>Filter and log failures</caption>
*
* const optionalValues = [
* getValue(path1, config), // => Just(value1)
* getValue(path2, config), // => Just(value2)
* getValue(path3, config), // => Nothing()
* getValue(path4, config) // => Nothing()
* ];
*
* Maybe.filter(Maybe.isJust, optionalValues);
* // => [Just(value1), Just(value2)]
*/
Maybe.filter = filter;
/**
* Creates an array of values by invoking {@link Maybe#map} with the <code>iteratee</code> for each {@link Maybe} 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 {Maybe[]} values - Collection of values over which to iterate.
* @return {Maybe[]} Mapped {@link Maybe} collection.
* @example <caption>Mapping each Maybe's value</caption>
*
* const optionalValues = [
* getValue(path1, config), // => Just(1.5)
* getValue(path2, config), // => Just(2.25)
* getValue(path3, config), // => Nothing()
* getValue(path4, config) // => Nothing()
* ];
*
* Maybe.mapIn(Math.floor, optionalValues);
* // => [Just(1), Just(2), Nothing(), Nothing()]
*/
Maybe.mapIn = curry((iteratee, values) => map(invokeIn("map", iteratee), values));
/**
* Creates an array of values by running each {@link Maybe} 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 {Maybe[]} values - Collection of values over which to iterate.
* @return {Maybe[]} Mapped collection.
* @example <caption>Mapping all values to promises</caption>
*
* const optionalValues = [
* getValue(path1, config), // => Just(value1)
* getValue(path2, config), // => Just(value2)
* getValue(path3, config), // => Nothing()
* getValue(path4, config) // => Nothing()
* ];
*
* Maybe.map(Maybe.toPromise, optionalValues);
* // => [Promise.resolve(price1), Promise.resolve(price2), Promise.reject(null), Promise.reject(null)]
*/
Maybe.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 {Maybe[]} values - Collection of values over which to iterate.
* @return {*} Accumulator.
* @example
*
* const optionalValues = [
* getValue(path1, config), // => Just(value1)
* getValue(path2, config), // => Just(value2)
* getValue(path3, config), // => Nothing()
* getValue(path4, config) // => Nothing()
* ];
*
* // Using lodash/fp/concat
* Maybe.reduce(
* (result, value) => value.isJust() ? concat(result, value.get()) : result,
* [],
* optionalValues
* );
* // => [value1, value2]
*/
Maybe.reduce = reduce;
/**
* Converts a {@link Maybe} to a {@link Either}. {@link Just} becomes a {@link Right} and {@link Nothing} becomes a
* {@link Left}.
* @static
* @member
* @param {Either} either - Either implementation.
* @param {Maybe} value - Maybe to convert.
* @return {Either} {@link Either} wrapped <code>value</code>.
* @example <caption>Just to Right</caption>
*
* Maybe.toEither(Either, Just.from(value));
* // => Either.Right(value);
*
* @example <caption>Nothing to Left</caption>
*
* Maybe.toEither(Either, Nothing.from());
* // => Either.Left(null);
*/
Maybe.toEither = invokeIn("toEither");
/**
* Converts a validation to a <code>Promise</code> using the provided <code>Promise</code> implementation.
* @static
* @member
* @param {Promise} promise - Promise implementation.
* @param {Maybe} value - Maybe to convert.
* @return {Promise} <code>Promise</code> wrapped <code>value</code>.
* @example <caption>Convert with bluebird's implementation of Promise</caption>
*
* const toBluebird = Maybe.toPromise(require("bluebird"));
*
* toBluebird(Just.from(value));
* // => Promise.resolve(value);
*
* toBluebird(Nothing.from());
* // => Promise.reject(null);
*/
Maybe.toPromise = invokeIn("toPromise");
/**
* Converts a {@link Maybe} to a {@link Validation}. {@link Just} becomes a {@link Success} and {@link Nothing} becomes
* a {@link Failure}.
* @static
* @member
* @param {Validation} validation - Validation implementation.
* @param {Maybe} value - Maybe to convert.
* @return {Validation} {@link Validation} wrapped <code>value</code>.
* @example <caption>Just to Success</caption>
*
* Maybe.toValidation(Validation, Just.from(value));
* // => Validation.Success(value);
*
* @example <caption>Nothing to Failure</caption>
*
* Maybe.toValidation(Validation, Nothing.from());
* // => Validation.Failure(null);
*/
Maybe.toValidation = invokeIn("toValidation");
/**
* @extends Maybe
* @inheritdoc
*/
class Just extends Maybe {
/**
* Creates a new {@link Just} from a <code>value</code>. If the <code>value</code> is already a {@link Maybe}
* instance, the <code>value</code> is returned unchanged. Otherwise, a new {@link Just} is made with the
* <code>value</code>.
* @static
* @param {*} value - Value to wrap in a {@link Just}.
* @return {Maybe} {@link Maybe} when is the <code>value</code> already wrapped or {@link Just} wrapped
* <code>value</code>.
* @example <caption>Just from nothing</caption>
*
* Just.from();
* // => Just()
*
* @example <caption>Just from arbitrary value</caption>
*
* Just.from(true);
* // => Just(true)
*
* @example <caption>Just from another Just</caption>
*
* Just.from(Just.from(value));
* // => Just(value)
*
* @example <caption>Just from Nothing</caption>
*
* Just.from(Nothing.from());
* // => Nothing()
*/
static from(value) {
return Maybe.isMaybe(value) ?
value :
new Just(value);
}
constructor(value) {
super(value);
}
ap(other) {
return other.map(this.value);
}
chain(method) {
return Maybe.from(method(this.value));
}
extend(method) {
return Maybe.from(method(this));
}
ifJust(method) {
method(this.value);
return this;
}
ifNothing() {
return this;
}
map(method) {
return Just.ofNullable(method(this.value));
}
orElse() {
return this.value;
}
orElseGet() {
return this.value;
}
orElseThrow() {
return this.value;
}
toEither(either) {
return new either.Right(this.value);
}
toPromise(promise) {
return promise.resolve(this.value);
}
toString() {
return `Maybe.Just(${this.value})`;
}
toValidation(validation) {
return new validation.Success(this.value);
}
}
/**
* @extends Maybe
* @inheritdoc
*/
class Nothing extends Maybe {
/**
* Creates a new {@link Nothing} from a <code>value</code>. If the <code>value</code> is already a {@link Maybe}
* instance, the <code>value</code> is returned unchanged. Otherwise, a new {@link Nothing} is made with the
* <code>value</code>.
* @static
* @param {*} value - Value to wrap in a {@link Nothing}.
* @return {Maybe} {@link Maybe} when is the <code>value</code> already wrapped or {@link Nothing} wrapped
* <code>value</code>.
* @example <caption>Nothing from nothing</caption>
*
* Nothing.from();
* // => Nothing()
*
* @example <caption>Nothing from arbitrary value</caption>
*
* Nothing.from(true);
* // => Nothing()
*
* @example <caption>Nothing from Just</caption>
*
* Nothing.from(Just.from(value));
* // => Just.from(value)
*
* @example <caption>Nothing from another Nothing</caption>
*
* Nothing.from(Nothing.from());
* // => Nothing()
*/
static from(value) {
return Maybe.isMaybe(value) ?
value :
new Nothing();
}
constructor() {
super(null);
}
ap() {
return this;
}
chain() {
return this;
}
extend() {
return this;
}
ifJust() {
return this;
}
ifNothing(method) {
method();
return this;
}
map() {
return this;
}
orElse(value) {
return value;
}
orElseGet(method) {
return method();
}
orElseThrow(method) {
throw method();
}
toEither(either) {
return new either.Left(this.value);
}
toPromise(promise) {
return promise.reject(this.value);
}
toString() {
return "Maybe.Nothing(null)";
}
toValidation(validation) {
return new validation.Failure(this.value);
}
}
module.exports = Maybe;