"use strict";
/** [[include:doc/result.md]] */
Object.defineProperty(exports, "__esModule", { value: true });
/** (keep typedoc from getting confused by the import) */
const maybe_1 = require("./maybe");
const unit_1 = require("./unit");
const utils_1 = require("./utils");
// So that it doesn't appear unused but can be exported.
utils_1._Brand; // tslint:disable-line:no-unused-expression
/**
  Discriminant for `Ok` and `Err` variants of `Result` type.

  You can use the discriminant via the `variant` property of `Result` instances
  if you need to match explicitly on it.
 */
var Variant;
(function (Variant) {
    Variant["Ok"] = "Ok";
    Variant["Err"] = "Err";
})(Variant = exports.Variant || (exports.Variant = {}));
/**
  An `Ok` instance is the *successful* variant instance of the
  [`Result`](../modules/_result_.html#result) type, representing a successful
  outcome from an operation which may fail. For a full discussion, see [the
  module docs](../modules/_result_.html).

  @typeparam T The type wrapped in this `Ok` variant of `Result`.
  @typeparam E The type which would be wrapped in an `Err` variant of `Result`.
 */
class Ok {
    /**
      Create an instance of `Result.Ok` with `new`.
  
      Note: While you *may* create the `Result` type via normal
      JavaScript class construction, it is not recommended for the functional
      style for which the library is intended. Instead, use [`Result.ok`].
  
      [`Result.ok`]: ../modules/_result_.html#ok
  
      ```ts
      // Avoid:
      const aString = new Result.Ok('characters');
  
      // Prefer:
      const aString = Result.ok('characters);
      ```
  
      Note that you may explicitly pass `Unit` to the `Ok` constructor to create
      a `Result<Unit, E>`. However, you may *not* call the `Ok` constructor with
      `null` or `undefined` to get that result (the type system won't allow you to
      construct it that way). Instead, for convenience, you can simply call
      `Result.ok()`, which will construct the type correctly.
  
      @param value
      The value to wrap in a `Result.Ok`.
  
      Note: `null` and `undefined` are allowed by the type signature so that the
      constructor may `throw` on those rather than constructing a type like
      `Result<undefined>`.
  
      @throws If you pass `null`.
     */
    constructor(value) {
        /** `Ok` is always [`Variant.Ok`](../enums/_result_.variant#ok). */
        this.variant = Variant.Ok;
        if (utils_1.isVoid(value)) {
            throw new Error('Tried to construct `Ok` with `null` or `undefined`. Maybe you want `Maybe.Nothing`?');
        }
        this.value = value;
    }
    /**
      Unwrap the contained value. A convenience method for functional idioms.
  
      A common scenario where you might want to use this is in a pipeline of
      functions:
  
      ```ts
      import Result, { Ok } from 'true-myth/result';
  
      function getLengths(results: Array<Result<string, string>>): Array<number> {
        return results
          .filter(Result.isOk)
          .map(Ok.unwrap)
          .map(s => s.length);
      }
      ```
     */
    static unwrap(theOk) {
        return theOk.value;
    }
    /** Method variant for [`Result.isOk`](../modules/_result_.html#isok) */
    isOk() {
        return true;
    }
    /** Method variant for [`Result.isErr`](../modules/_result_.html#iserr) */
    isErr() {
        return false;
    }
    /** Method variant for [`Result.map`](../modules/_result_.html#map) */
    map(mapFn) {
        return map(mapFn, this);
    }
    /** Method variant for [`Result.mapOr`](../modules/_result_.html#mapor) */
    mapOr(orU, mapFn) {
        return mapOr(orU, mapFn, this);
    }
    /** Method variant for [`Result.mapOrElse`](../modules/_result_.html#maporelse) */
    mapOrElse(orElseFn, mapFn) {
        return mapOrElse(orElseFn, mapFn, this);
    }
    /** Method variant for [`Result.match`](../modules/_result_.html#match) */
    match(matcher) {
        return match(matcher, this);
    }
    /** Method variant for [`Result.mapErr`](../modules/_result_.html#maperr) */
    mapErr(mapErrFn) {
        return mapErr(mapErrFn, this);
    }
    /** Method variant for [`Result.or`](../modules/_result_.html#or) */
    or(orResult) {
        return or(orResult, this);
    }
    /** Method variant for [`Result.orElse`](../modules/_result_.html#orelse) */
    orElse(orElseFn) {
        return orElse(orElseFn, this);
    }
    /** Method variant for [`Result.and`](../modules/_result_.html#and) */
    and(mAnd) {
        return and(mAnd, this);
    }
    /** Method variant for [`Result.andThen`](../modules/_result_.html#andthen) */
    andThen(andThenFn) {
        return andThen(andThenFn, this);
    }
    /** Method variant for [`Result.chain`](../modules/_result_.html#chain) */
    chain(chainFn) {
        return exports.chain(chainFn, this);
    }
    /** Method variant for [`Result.flatMap`](../modules/_result_.html#flatmap) */
    flatMap(flatMapFn) {
        return exports.flatMap(flatMapFn, this);
    }
    /** Method variant for [`Result.unwrap`](../modules/_result_.html#unwrap) */
    unsafelyUnwrap() {
        return this.value;
    }
    /** Method variant for [`Result.unwrapErr`](../modules/_result_.html#unwraperr) */
    unsafelyUnwrapErr() {
        throw new Error('Tried to `unsafelyUnwrapErr` an `Ok`');
    }
    /** Method variant for [`Result.unwrapOr`](../modules/_result_.html#unwrapor) */
    unwrapOr(defaultValue) {
        return unwrapOr(defaultValue, this);
    }
    /** Method variant for [`Result.unwrapOrElse`](../modules/_result_.html#unwrapOrElse) */
    unwrapOrElse(elseFn) {
        return unwrapOrElse(elseFn, this);
    }
    /** Method variant for [`Result.toMaybe`](../modules/_result_.html#tomaybe) */
    toMaybe() {
        return toMaybe(this);
    }
    /** Method variant for [`Result.toString`](../modules/_result_.html#tostring) */
    toString() {
        return exports.toString(this);
    }
    /** Method variant for [`Result.equals`](../modules/_result_.html#equals) */
    equals(comparison) {
        return equals(comparison, this);
    }
    /** Method variant for [`Result.ap`](../modules/_result_.html#ap) */
    ap(r) {
        return ap(this, r);
    }
}
exports.Ok = Ok;
/**
  An `Err` instance is the *failure* variant instance of the
  [`Result`](../modules/_result_.html#result) type, representing a failure
  outcome from an operation which may fail. For a full discussion, see [the
  module docs](../modules/_result_.html).

  @typeparam T The type which would be wrapped in an `Ok` variant of `Result`.
  @typeparam E The type wrapped in this `Err` variant of `Result`.
  */
class Err {
    /**
      Create an instance of `Result.Err` with `new`.
  
      Note: While you *may* create the `Result` type via normal
      JavaScript class construction, it is not recommended for the functional
      style for which the library is intended. Instead, use [`Result.err`].
  
      [`Result.err`]: ../modules/_result_.html#err
  
      ```ts
      // Avoid:
      const anErr = new Result.Err('alas, failure');
  
      // Prefer:
      const anErr = Result.err('alas, failure');
      ```
  
      Note that you may explicitly pass `Unit` to the `Err` constructor to create
      a `Result<T, Unit>`. However, you may *not* call the `Err` constructor with
      `null` or `undefined` to get that result (the type system won't allow you to
      construct it that way). Instead, for convenience, you can simply call
      `Result.err()`, which will construct the type correctly.
  
      @param error
      The value to wrap in a `Result.Err`.
  
      `Note: null` and `undefined` are allowed by the type signature so that the
      constructor may `throw` on those rather than constructing a type like
      `Result<number, undefined>`.
  
      @throws If you pass `null` or `undefined`.
     */
    constructor(error) {
        /** `Err` is always [`Variant.Err`](../enums/_result_.variant#err). */
        this.variant = Variant.Err;
        if (utils_1.isVoid(error)) {
            throw new Error('Tried to construct `Err` with `null` or `undefined`. Maybe you want `Maybe.Nothing`?');
        }
        this.error = error;
    }
    /**
      Unwrap the contained error . A convenience method for functional idioms.
  
      A common scenario where you might want to use this is in a pipeline of
      functions:
  
      ```ts
      import Result, { Ok } from 'true-myth/result';
  
      function getMessages(results: Array<Result<string, Error>>): Array<number> {
        return maybeStrings
          .filter(Result.isErr)
          .map(Err.unwrapErr)
          .map(e => e.message);
      }
      ```
     */
    static unwrapErr(theErr) {
        return theErr.error;
    }
    /** Method variant for [`Result.isOk`](../modules/_result_.html#isok) */
    isOk() {
        return false;
    }
    /** Method variant for [`Result.isErr`](../modules/_result_.html#iserr) */
    isErr() {
        return true;
    }
    /** Method variant for [`Result.map`](../modules/_result_.html#map) */
    map(mapFn) {
        return map(mapFn, this);
    }
    /** Method variant for [`Result.mapOr`](../modules/_result_.html#mapor) */
    mapOr(orU, mapFn) {
        return mapOr(orU, mapFn, this);
    }
    /** Method variant for [`Result.mapOrElse`](../modules/_result_.html#maporelse) */
    mapOrElse(orElseFn, mapFn) {
        return mapOrElse(orElseFn, mapFn, this);
    }
    /** Method variant for [`Result.match`](../modules/_result_.html#match) */
    match(matchObj) {
        return match(matchObj, this);
    }
    /** Method variant for [`Result.mapErr`](../modules/_result_.html#maperr) */
    mapErr(mapErrFn) {
        return mapErr(mapErrFn, this);
    }
    /** Method variant for [`Result.or`](../modules/_result_.html#or) */
    or(orResult) {
        return or(orResult, this);
    }
    /** Method variant for [`Result.orElse`](../modules/_result_.html#orelse) */
    orElse(orElseFn) {
        return orElse(orElseFn, this);
    }
    /** Method variant for [`Result.and`](../modules/_result_.html#and) */
    and(mAnd) {
        return and(mAnd, this);
    }
    /** Method variant for [`Result.andThen`](../modules/_result_.html#andthen) */
    andThen(andThenFn) {
        return andThen(andThenFn, this);
    }
    /** Method variant for [`Result.chain`](../modules/_result_.html#chain) */
    chain(chainFn) {
        return this.andThen(chainFn);
    }
    /** Method variant for [`Result.flatMap`](../modules/_result_.html#flatmap) */
    flatMap(flatMapFn) {
        return this.andThen(flatMapFn);
    }
    /** Method variant for [`Result.unsafelyUnwrap`](../modules/_result_.html#unsafelyunwrap) */
    unsafelyUnwrap() {
        throw new Error('Tried to `unsafelyUnwrap an Err`');
    }
    /** Method variant for [`Result.unsafelyUnwrapErr`](../modules/_result_.html#unsafelyunwraperr) */
    unsafelyUnwrapErr() {
        return this.error;
    }
    /** Method variant for [`Result.unwrapOr`](../modules/_result_.html#unwrapor) */
    unwrapOr(defaultValue) {
        return unwrapOr(defaultValue, this);
    }
    /** Method variant for [`Result.unwrapOrElse`](../modules/_result_.html#unwraporelse) */
    unwrapOrElse(elseFn) {
        return unwrapOrElse(elseFn, this);
    }
    /** Method variant for [`Result.toMaybe`](../modules/_result_.html#tomaybe) */
    toMaybe() {
        return toMaybe(this);
    }
    /** Method variant for [`Result.toString`](../modules/_result_.html#tostring) */
    toString() {
        return exports.toString(this);
    }
    /** Method variant for [`Result.equals`](../modules/_result_.html#equals) */
    equals(comparison) {
        return equals(comparison, this);
    }
    /** Method variant for [`Result.ap`](../modules/_result_.html#ap) */
    ap(r) {
        return ap(this, r);
    }
}
exports.Err = Err;
/**
  Is this `Result` an `Ok` instance?

  In TypeScript, narrows the type from `Result<T, E>` to `Ok<T, E>`.
 */
function isOk(result) {
    return result.variant === Variant.Ok;
}
exports.isOk = isOk;
/**
  Is this `Result` an `Err` instance?

  In TypeScript, narrows the type from `Result<T, E>` to `Err<T, E>`.
 */
function isErr(result) {
    return result.variant === Variant.Err;
}
exports.isErr = isErr;
function ok(value) {
    return value === undefined ? new Ok(unit_1.default) : new Ok(value);
}
exports.ok = ok;
/** `Result.of` is an alias for `Result.ok`. */
exports.of = ok;
function err(error) {
    return utils_1.isVoid(error) ? new Err(unit_1.default) : new Err(error);
}
exports.err = err;
function tryOr(error, callback) {
    const op = (cb) => {
        try {
            return exports.Result.ok(cb());
        }
        catch (_a) {
            return exports.Result.err(error);
        }
    };
    return utils_1.curry1(op, callback);
}
exports.tryOr = tryOr;
function tryOrElse(onError, callback) {
    const op = (cb) => {
        try {
            return exports.Result.ok(cb());
        }
        catch (e) {
            return exports.Result.err(onError(e));
        }
    };
    return utils_1.curry1(op, callback);
}
exports.tryOrElse = tryOrElse;
function map(mapFn, result) {
    const op = (r) => (isOk(r) ? ok(mapFn(r.value)) : r);
    return utils_1.curry1(op, result);
}
exports.map = map;
function mapOr(orU, mapFn, result) {
    function fullOp(fn, r) {
        return isOk(r) ? fn(r.value) : orU;
    }
    function partialOp(fn, curriedResult) {
        return curriedResult !== undefined
            ? fullOp(fn, curriedResult)
            : (extraCurriedResult) => fullOp(fn, extraCurriedResult);
    }
    return mapFn === undefined
        ? partialOp
        : result === undefined
            ? partialOp(mapFn)
            : partialOp(mapFn, result);
}
exports.mapOr = mapOr;
function mapOrElse(orElseFn, mapFn, result) {
    function fullOp(fn, r) {
        return isOk(r) ? fn(r.value) : orElseFn(r.error);
    }
    function partialOp(fn, curriedResult) {
        return curriedResult !== undefined
            ? fullOp(fn, curriedResult)
            : (extraCurriedResult) => fullOp(fn, extraCurriedResult);
    }
    return mapFn === undefined
        ? partialOp
        : result === undefined
            ? partialOp(mapFn)
            : partialOp(mapFn, result);
}
exports.mapOrElse = mapOrElse;
function mapErr(mapErrFn, result) {
    const op = (r) => (isOk(r) ? r : err(mapErrFn(r.error)));
    return utils_1.curry1(op, result);
}
exports.mapErr = mapErr;
function and(andResult, result) {
    const op = (r) => (isOk(r) ? andResult : r);
    return utils_1.curry1(op, result);
}
exports.and = and;
function andThen(thenFn, result) {
    const op = (r) => (isOk(r) ? thenFn(r.value) : r);
    return utils_1.curry1(op, result);
}
exports.andThen = andThen;
/** Alias for [`andThen`](#andthen). */
exports.chain = andThen;
/** Alias for [`andThen`](#andthen). */
exports.flatMap = andThen;
function or(defaultResult, result) {
    const op = (r) => (isOk(r) ? r : defaultResult);
    return utils_1.curry1(op, result);
}
exports.or = or;
function orElse(elseFn, result) {
    const op = (r) => (isOk(r) ? r : elseFn(r.unsafelyUnwrapErr()));
    return utils_1.curry1(op, result);
}
exports.orElse = orElse;
/**
  Get the value out of the `Result`.

  Returns the content of an `Ok`, but **throws if the `Result` is `Err`.**
  Prefer to use [`unwrapOr`](#unwrapor) or [`unwrapOrElse`](#unwraporelse).

  @throws If the `Result` instance is `Nothing`.
 */
function unsafelyUnwrap(result) {
    return result.unsafelyUnwrap();
}
exports.unsafelyUnwrap = unsafelyUnwrap;
/** Alias for [`unsafelyUnwrap`](#unsafelyunwrap) */
exports.unsafelyGet = unsafelyUnwrap;
/** Alias for [`unsafelyUnwrap`](#unsafelyunwrap) */
exports.unsafeGet = unsafelyUnwrap;
/**
  Get the error value out of the [`Result`](#result).

  Returns the content of an `Err`, but **throws if the `Result` is `Ok`**.
  Prefer to use [`unwrapOrElse`](#unwraporelse).

  @param result
  @throws Error If the `Result` instance is `Nothing`.
 */
function unsafelyUnwrapErr(result) {
    return result.unsafelyUnwrapErr();
}
exports.unsafelyUnwrapErr = unsafelyUnwrapErr;
/** Alias for [`unsafelyUnwrapErr`](#unsafelyunwraperr) */
exports.unsafelyGetErr = unsafelyUnwrapErr;
function unwrapOr(defaultValue, result) {
    const op = (r) => (isOk(r) ? r.value : defaultValue);
    return utils_1.curry1(op, result);
}
exports.unwrapOr = unwrapOr;
/** Alias for [`unwrapOr`](#unwrapor) */
exports.getOr = unwrapOr;
function unwrapOrElse(orElseFn, result) {
    const op = (r) => (isOk(r) ? r.value : orElseFn(r.error));
    return utils_1.curry1(op, result);
}
exports.unwrapOrElse = unwrapOrElse;
/** Alias for [`unwrapOrElse`](#unwraporelse) */
exports.getOrElse = unwrapOrElse;
/**
  Convert a [`Result`](#result) to a [`Maybe`](../modules/_maybe_.html#maybe).

  The converted type will be [`Just`] if the `Result` is [`Ok`] or [`Nothing`]
  if the `Result` is [`Err`]; the wrapped error value will be discarded.

  [`Just`]: ../classes/_maybe_.just.html
  [`Nothing`]: ../classes/_maybe_.nothing.html
  [`Ok`]: ../classes/_result_.ok.html
  [`Err`]: ../classes/_result_.err.html

  @param result The `Result` to convert to a `Maybe`
  @returns      `Just` the value in `result` if it is `Ok`; otherwise `Nothing`
 */
function toMaybe(result) {
    return isOk(result) ? maybe_1.just(result.value) : maybe_1.nothing();
}
exports.toMaybe = toMaybe;
function fromMaybe(errValue, maybe) {
    const op = (m) => (maybe_1.isJust(m) ? ok(maybe_1.default.unsafelyUnwrap(m)) : err(errValue));
    return utils_1.curry1(op, maybe);
}
exports.fromMaybe = fromMaybe;
/**
  Create a `String` representation of a `result` instance.

  An `Ok` instance will be printed as `Ok(<representation of the value>)`, and
  an `Err` instance will be printed as `Err(<representation of the error>)`,
  where the representation of the value or error is simply the value or error's
  own `toString` representation. For example:

                call                |         output
  --------------------------------- | ----------------------
  `toString(ok(42))`                | `Ok(42)`
  `toString(ok([1, 2, 3]))`         | `Ok(1,2,3)`
  `toString(ok({ an: 'object' }))`  | `Ok([object Object])`n
  `toString(err(42))`               | `Err(42)`
  `toString(err([1, 2, 3]))`        | `Err(1,2,3)`
  `toString(err({ an: 'object' }))` | `Err([object Object])`

  @typeparam T The type of the wrapped value; its own `.toString` will be used
               to print the interior contents of the `Just` variant.
  @param maybe The value to convert to a string.
  @returns     The string representation of the `Maybe`.
 */
exports.toString = (result) => {
    const body = (isOk(result) ? result.value : result.error).toString();
    return `${result.variant.toString()}(${body})`;
};
function match(matcher, result) {
    const op = (r) => mapOrElse(matcher.Err, matcher.Ok, r);
    return utils_1.curry1(op, result);
}
exports.match = match;
/** Alias for [`match`](#match) */
exports.cata = match;
function equals(resultB, resultA) {
    return resultA !== undefined
        ? resultA.match({
            Err: () => isErr(resultB),
            Ok: a => isOk(resultB) && resultB.unsafelyUnwrap() === a,
        })
        : (curriedResultA) => curriedResultA.match({
            Err: () => isErr(resultB),
            Ok: a => isOk(resultB) && resultB.unsafelyUnwrap() === a,
        });
}
exports.equals = equals;
function ap(resultFn, result) {
    const op = (r) => r.match({
        Ok: val => resultFn.map(fn => fn(val)),
        Err: e => exports.Result.err(e),
    });
    return utils_1.curry1(op, result);
}
exports.ap = ap;
/**
  Determine whether an item is an instance of `Just` or `Nothing`.

  @param item The item to check.
 */
function isInstance(item) {
    return item instanceof Ok || item instanceof Err;
}
exports.isInstance = isInstance;
exports.Result = {
    Variant,
    Ok,
    Err,
    isOk,
    isErr,
    ok,
    err,
    tryOr,
    tryOrElse,
    map,
    mapOr,
    mapOrElse,
    mapErr,
    and,
    andThen,
    chain: exports.chain,
    flatMap: exports.flatMap,
    or,
    orElse,
    unsafelyUnwrap,
    unsafelyGet: exports.unsafelyGet,
    unsafeGet: exports.unsafeGet,
    unsafelyUnwrapErr,
    unsafelyGetErr: exports.unsafelyGetErr,
    unwrapOr,
    getOr: exports.getOr,
    unwrapOrElse,
    getOrElse: exports.getOrElse,
    toMaybe,
    fromMaybe,
    toString: exports.toString,
    match,
    cata: exports.cata,
    equals,
    ap,
    isInstance,
};
exports.default = exports.Result;
//# sourceMappingURL=result.js.map