"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.orElse = exports.merge = exports.mapLeft = exports.mapLeft_ = exports.map = exports.map_ = exports.isRight = exports.isLeft = exports.getOrElse_ = exports.getOrElse = exports.fromPredicate_ = exports.fromPredicate = exports.fromOption_ = exports.fromOption = exports.fromNullable_ = exports.fromNullable = exports.fold_ = exports.fold = exports.flatten = exports.filterOrElse_ = exports.filterOrElse = exports.extend = exports.extend_ = exports.exists_ = exports.exists = exports.duplicate = exports.tap_ = exports.tap = exports.chain = exports.chain_ = exports.bimap = exports.bimap_ = exports.zipSecond_ = exports.zipSecond = exports.zipFirst_ = exports.zipFirst = exports.zip = exports.zip_ = exports.ap = exports.ap_ = exports.alt = exports.alt_ = exports.widenA = exports.widenE = exports.leftW = exports.left = exports.rightW = exports.right = exports.Right = exports.Left = void 0;
exports.reduceRight_ = exports.reduceRight = exports.reduce = exports.reduce_ = exports.compact = exports.tryCatch = exports.toError = exports.swap = exports.stringifyJSON = exports.stringifyJSON_ = exports.parseJSON = exports.parseJSON_ = exports.orElseEither_ = exports.orElseEither = exports.orElse_ = void 0;
// ets_tracing: off
/**
 * adapted from https://github.com/gcanti/fp-ts
 */
const Tp = __importStar(require("../Collections/Immutable/Tuple"));
const core_1 = require("../Option/core");
const St = __importStar(require("../Structural"));
const _leftHash = St.hashString("@effect-ts/system/Either/Left");
const _rightHash = St.hashString("@effect-ts/system/Either/Right");
/**
 * Definitions
 */
class Left {
    constructor(left) {
        this.left = left;
        this._tag = "Left";
    }
    [St.equalsSym](that) {
        return that instanceof Left && St.equals(this.left, that.left);
    }
    get [St.hashSym]() {
        return St.combineHash(_leftHash, St.hash(this.left));
    }
}
exports.Left = Left;
class Right {
    constructor(right) {
        this.right = right;
        this._tag = "Right";
    }
    [St.equalsSym](that) {
        return that instanceof Right && St.equals(this.right, that.right);
    }
    get [St.hashSym]() {
        return St.combineHash(_rightHash, St.hash(this.right));
    }
}
exports.Right = Right;
/**
 * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias
 * of this structure
 */
function right(a) {
    return new Right(a);
}
exports.right = right;
/**
 * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias
 * of this structure
 */
function rightW(a) {
    return new Right(a);
}
exports.rightW = rightW;
/**
 * Constructs a new `Either` holding a `Left` value. This usually represents a failure, due to the right-bias of this
 * structure
 */
function left(e) {
    return new Left(e);
}
exports.left = left;
/**
 * Constructs a new `Either` holding a `Left` value. This usually represents a failure, due to the right-bias of this
 * structure
 */
function leftW(e) {
    return new Left(e);
}
exports.leftW = leftW;
/**
 * Widen left side `Either[E, A] => Either[E | E1, A]`
 */
function widenE() {
    return (
    /**
     * @ets_optimize identity
     */
    (self) => self);
}
exports.widenE = widenE;
/**
 * Widen right side `Either[E, A] => Either[E, A | A1]`
 */
function widenA() {
    return (
    /**
     * @ets_optimize identity
     */
    (self) => self);
}
exports.widenA = widenA;
/**
 * Alternatively construct that if self is left
 */
function alt_(self, that) {
    return isLeft(self) ? that() : self;
}
exports.alt_ = alt_;
/**
 * Alternatively construct that if self is left
 *
 * @ets_data_first alt_
 */
function alt(that) {
    return (self) => alt_(self, that);
}
exports.alt = alt;
/**
 * Classic Applicative
 */
function ap_(fab, fa) {
    return isLeft(fab) ? fab : isLeft(fa) ? fa : right(fab.right(fa.right));
}
exports.ap_ = ap_;
/**
 * Classic Applicative
 *
 * @ets_data_first ap_
 */
function ap(fa) {
    return (fab) => ap_(fab, fa);
}
exports.ap = ap;
/**
 * Apply both and return both
 */
function zip_(fa, fb) {
    return chain_(fa, (a) => map_(fb, (b) => Tp.tuple(a, b)));
}
exports.zip_ = zip_;
/**
 * Apply both and return both
 *
 * @ets_data_first zip_
 */
function zip(fb) {
    return (fa) => zip_(fa, fb);
}
exports.zip = zip;
/**
 * Apply both and return first
 *
 * @ets_data_first zipFirst_
 */
function zipFirst(fb) {
    return (fa) => zipFirst_(fa, fb);
}
exports.zipFirst = zipFirst;
/**
 * Apply both and return first
 */
function zipFirst_(fa, fb) {
    return ap_(map_(fa, (a) => () => a), fb);
}
exports.zipFirst_ = zipFirst_;
/**
 * Apply both and return second
 *
 * @ets_data_first zipSecond_
 */
function zipSecond(fb) {
    return (fa) => zipSecond_(fa, fb);
}
exports.zipSecond = zipSecond;
/**
 * Apply both and return second
 */
function zipSecond_(fa, fb) {
    return ap_(map_(fa, () => (b) => b), fb);
}
exports.zipSecond_ = zipSecond_;
/**
 * Maps both left and right
 */
function bimap_(fea, f, g) {
    return isLeft(fea) ? left(f(fea.left)) : right(g(fea.right));
}
exports.bimap_ = bimap_;
/**
 * Maps both left and right
 *
 * @ets_data_first bimap_
 */
function bimap(f, g) {
    return (fa) => bimap_(fa, f, g);
}
exports.bimap = bimap;
/**
 * Extends this computation with another computation that depends on the
 * result of this computation by running the first computation, using its
 * result to generate a second computation, and running that computation.
 */
function chain_(fa, f) {
    return isLeft(fa) ? fa : f(fa.right);
}
exports.chain_ = chain_;
/**
 * Extends this computation with another computation that depends on the
 * result of this computation by running the first computation, using its
 * result to generate a second computation, and running that computation.
 *
 * @ets_data_first chain_
 */
function chain(f) {
    return (ma) => chain_(ma, f);
}
exports.chain = chain;
/**
 * Like chain but ignores the constructed outout
 *
 * @ets_data_first tap_
 */
function tap(f) {
    return (ma) => chain_(ma, (a) => map_(f(a), () => a));
}
exports.tap = tap;
/**
 * Like chain but ignores the constructed outout
 */
function tap_(ma, f) {
    return chain_(ma, (a) => map_(f(a), () => a));
}
exports.tap_ = tap_;
/**
 * Self embed `Either[E, A]` into `Either[E, Either[E, A]]`
 */
function duplicate(ma) {
    return extend_(ma, (x) => x);
}
exports.duplicate = duplicate;
/**
 * Returns `false` if `Left` or returns the result of the application of the given predicate to the `Right` value.
 *
 * @ets_data_first exists_
 */
function exists(predicate) {
    return (ma) => (isLeft(ma) ? false : predicate(ma.right));
}
exports.exists = exists;
/**
 * Returns `false` if `Left` or returns the result of the application of the given predicate to the `Right` value.
 */
function exists_(ma, predicate) {
    return isLeft(ma) ? false : predicate(ma.right);
}
exports.exists_ = exists_;
/**
 * Apply `Either[E, A] => B` in case self is right returning `Either[E, B]`
 */
function extend_(wa, f) {
    return isLeft(wa) ? wa : right(f(wa));
}
exports.extend_ = extend_;
/**
 * Apply `Either[E, A] => B` in case self is right returning `Either[E, B]`
 *
 * @ets_data_first extend_
 */
function extend(f) {
    return (ma) => extend_(ma, f);
}
exports.extend = extend;
function filterOrElse(predicate, onFalse) {
    return (ma) => chain_(ma, (a) => (predicate(a) ? right(a) : left(onFalse(a))));
}
exports.filterOrElse = filterOrElse;
function filterOrElse_(ma, predicate, onFalse) {
    return chain_(ma, (a) => (predicate(a) ? right(a) : left(onFalse(a))));
}
exports.filterOrElse_ = filterOrElse_;
/**
 * Flatten nested `Either[E, Either[E1, A]]` into `Either[E | E1, A]`
 */
function flatten(mma) {
    return chain_(mma, (x) => x);
}
exports.flatten = flatten;
/**
 * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the first function,
 * if the value is a `Right` the inner value is applied to the second function.
 *
 * @ets_data_first fold_
 */
function fold(onLeft, onRight) {
    return (ma) => (isLeft(ma) ? onLeft(ma.left) : onRight(ma.right));
}
exports.fold = fold;
/**
 * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the first function,
 * if the value is a `Right` the inner value is applied to the second function.
 */
function fold_(ma, onLeft, onRight) {
    return isLeft(ma) ? onLeft(ma.left) : onRight(ma.right);
}
exports.fold_ = fold_;
/**
 * Takes a default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use
 * the provided default as a `Left`
 *
 * @ets_data_first fromNullable_
 */
function fromNullable(e) {
    return (a) => (a == null ? left(e()) : right(a));
}
exports.fromNullable = fromNullable;
/**
 * Takes a default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use
 * the provided default as a `Left`
 */
function fromNullable_(a, e) {
    return a == null ? left(e()) : right(a);
}
exports.fromNullable_ = fromNullable_;
/**
 * Construct `Either[E, A]` from `Option[A]` constructing `E` with `onNone`
 *
 * @ets_data_first fromOption_
 */
function fromOption(onNone) {
    return (ma) => (0, core_1.isNone)(ma) ? left(onNone()) : right(ma.value);
}
exports.fromOption = fromOption;
/**
 * Construct `Either[E, A]` from `Option[A]` constructing `E` with `onNone`
 */
function fromOption_(ma, onNone) {
    return (0, core_1.isNone)(ma) ? left(onNone()) : right(ma.value);
}
exports.fromOption_ = fromOption_;
function fromPredicate(predicate, onFalse) {
    return (a) => (predicate(a) ? right(a) : left(onFalse(a)));
}
exports.fromPredicate = fromPredicate;
function fromPredicate_(a, predicate, onFalse) {
    return predicate(a) ? right(a) : left(onFalse(a));
}
exports.fromPredicate_ = fromPredicate_;
/**
 * Get `A` or in case self is left return `onLeft` result
 *
 * @ets_data_first getOrElse_
 */
function getOrElse(onLeft) {
    return (ma) => getOrElse_(ma, onLeft);
}
exports.getOrElse = getOrElse;
/**
 * Get `A` or in case self is left return `onLeft` result
 */
function getOrElse_(self, onLeft) {
    return isLeft(self) ? onLeft(self.left) : self.right;
}
exports.getOrElse_ = getOrElse_;
/**
 * Returns `true` if the either is an instance of `Left`, `false` otherwise
 */
function isLeft(ma) {
    switch (ma._tag) {
        case "Left":
            return true;
        case "Right":
            return false;
    }
}
exports.isLeft = isLeft;
/**
 * Returns `true` if the either is an instance of `Right`, `false` otherwise
 */
function isRight(ma) {
    return ma._tag === "Right" ? true : false;
}
exports.isRight = isRight;
/**
 * Use `A => B` to transform `Either[E, A]` to `Either[E, B]`
 */
function map_(fa, f) {
    return isLeft(fa) ? fa : right(f(fa.right));
}
exports.map_ = map_;
/**
 * Use `A => B` to transform `Either[E, A]` to `Either[E, B]`
 *
 * @ets_data_first map_
 */
function map(f) {
    return (fa) => map_(fa, f);
}
exports.map = map;
/**
 * Use `E => E1` to transform `Either[E, A]` to `Either[E1, A]`
 */
function mapLeft_(fea, f) {
    return isLeft(fea) ? left(f(fea.left)) : fea;
}
exports.mapLeft_ = mapLeft_;
/**
 * Use `E => E1` to transform `Either[E, A]` to `Either[E1, A]`
 *
 * @ets_data_first mapLeft_
 */
function mapLeft(f) {
    return (fa) => mapLeft_(fa, f);
}
exports.mapLeft = mapLeft;
/**
 * Merges Left<E> | Right<B> into A | B
 */
function merge(self) {
    return fold_(self, (x) => x, (x) => x);
}
exports.merge = merge;
/**
 * Alternatively run onLeft
 *
 * @ets_data_first orElse_
 */
function orElse(onLeft) {
    return (ma) => orElse_(ma, onLeft);
}
exports.orElse = orElse;
/**
 * Alternatively run onLeft
 */
function orElse_(ma, onLeft) {
    return isLeft(ma) ? onLeft(ma.left) : ma;
}
exports.orElse_ = orElse_;
/**
 * Alternatively run onLeft returning
 *
 * @ets_data_first orElseEither_
 */
function orElseEither(onLeft) {
    return (ma) => orElseEither_(ma, onLeft);
}
exports.orElseEither = orElseEither;
/**
 * Alternatively run onLeft returning
 */
function orElseEither_(ma, onLeft) {
    return orElse_(map_(ma, left), (e) => map_(onLeft(e), right));
}
exports.orElseEither_ = orElseEither_;
/**
 * Converts a JavaScript Object Notation (JSON) string into an object.
 */
function parseJSON_(s, onError) {
    return tryCatch(() => JSON.parse(s), onError);
}
exports.parseJSON_ = parseJSON_;
/**
 * Converts a JavaScript Object Notation (JSON) string into an object.
 *
 * @ets_data_first parseJSON_
 */
function parseJSON(onError) {
    return (s) => tryCatch(() => JSON.parse(s), onError);
}
exports.parseJSON = parseJSON;
/**
 * Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
 */
function stringifyJSON_(u, onError) {
    return tryCatch(() => JSON.stringify(u), onError);
}
exports.stringifyJSON_ = stringifyJSON_;
/**
 * Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
 *
 * @ets_data_first stringifyJSON_
 */
function stringifyJSON(onError) {
    return (u) => tryCatch(() => JSON.stringify(u), onError);
}
exports.stringifyJSON = stringifyJSON;
/**
 * Inverts `Either[E, A]` into `Either[A, E]`
 */
function swap(ma) {
    return isLeft(ma) ? right(ma.left) : left(ma.right);
}
exports.swap = swap;
/**
 * Default value for the `onError` argument of `tryCatch`
 */
function toError(e) {
    return e instanceof Error ? e : new Error(String(e));
}
exports.toError = toError;
/**
 * Constructs a new `Either` from a function that might throw
 */
function tryCatch(f, onError) {
    try {
        return right(f());
    }
    catch (e) {
        return left(onError(e));
    }
}
exports.tryCatch = tryCatch;
/**
 * Compact types Either<E, A> | Either<E2, B> = Either<E | E2, A | B>
 *
 * @ets_optimize identity
 */
function compact(_) {
    return _;
}
exports.compact = compact;
/**
 * Reduce a value `b` through an `Either`
 */
function reduce_(fa, b, f) {
    return isLeft(fa) ? b : f(b, fa.right);
}
exports.reduce_ = reduce_;
/**
 * Reduce a value `b` through an `Either`
 *
 * @ets_data_first reduce_
 */
function reduce(b, f) {
    return (fa) => reduce_(fa, b, f);
}
exports.reduce = reduce;
/**
 * Reduce a value `b` through an `Either` in inverted order
 *
 * @ets_data_first reduceRight_
 */
function reduceRight(b, f) {
    return (fa) => reduceRight_(fa, b, f);
}
exports.reduceRight = reduceRight;
/**
 * Reduce a value `b` through an `Either` in inverted order
 */
function reduceRight_(fa, b, f) {
    return isLeft(fa) ? b : f(fa.right, b);
}
exports.reduceRight_ = reduceRight_;
//# sourceMappingURL=core.js.map