"use strict";
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
var orRegex = /\s*\|\|\s*/g;
var andRegex = /\s*&&\s*/g;
var rangeRegex = /^\s*([<>=~^]*)\s*([\d.x]+)(-[^\s]+)?\s*/;
var xRegex = /[.]x/g;
/**
 * Check if the version is within the range
 * @param subject The version to check against the range
 * @param range The range to check the version against
 */
function withinVersionRange(subject, range) {
    var e_1, _a, e_2, _b;
    // prepare and verify subject
    subject = String(subject);
    var _c = __read(subject.split('.'), 3), _d = _c[0], subjectMajor = _d === void 0 ? null : _d, _e = _c[1], subjectMinor = _e === void 0 ? null : _e, _f = _c[2], subjectPatch = _f === void 0 ? null : _f;
    if (subjectMajor === null)
        throw new Error("subject was invalid: ".concat(JSON.stringify(subject)));
    var subjectMajorNumber = Number(subjectMajor || 0);
    var subjectMinorNumber = Number(subjectMinor || 0);
    var subjectPatchNumber = Number(subjectPatch || 0);
    // cycle through the conditions
    var orRanges = Array.isArray(range)
        ? range.slice()
        : String(range).split(orRegex);
    try {
        for (var orRanges_1 = __values(orRanges), orRanges_1_1 = orRanges_1.next(); !orRanges_1_1.done; orRanges_1_1 = orRanges_1.next()) {
            var orRange = orRanges_1_1.value;
            var orResult = false;
            var andRanges = String(orRange).split(andRegex);
            try {
                for (var andRanges_1 = (e_2 = void 0, __values(andRanges)), andRanges_1_1 = andRanges_1.next(); !andRanges_1_1.done; andRanges_1_1 = andRanges_1.next()) {
                    var andRange = andRanges_1_1.value;
                    var andResult = false;
                    // process range
                    var _g = __read(String(andRange).match(rangeRegex) || [], 4), match = _g[0], comparator = _g[1], targetRaw = _g[2], prerelease = _g[3];
                    var target = (targetRaw || '').replace(xRegex, '');
                    // // log
                    // console.log({
                    // 	orRange,
                    // 	andRange,
                    // 	match,
                    // 	comparator,
                    // 	target,
                    // 	prerelease,
                    // })
                    // prepare and verify target
                    var _h = __read(target.split('.'), 3), _j = _h[0], targetMajor = _j === void 0 ? null : _j, _k = _h[1], targetMinor = _k === void 0 ? null : _k, _l = _h[2], targetPatch = _l === void 0 ? null : _l;
                    if (!match || !target || targetMajor == null || prerelease)
                        throw new Error("range condition was invalid: ".concat(JSON.stringify(andRange)));
                    var targetMajorNumber = Number(targetMajor || 0);
                    var targetMinorNumber = Number(targetMinor || 0);
                    var targetPatchNumber = Number(targetPatch || 0);
                    // is there more range matches? add it to and condition
                    var remainder = String(andRange).slice(match.length);
                    if (remainder)
                        andRanges.push(remainder);
                    // handle comparator
                    switch (comparator) {
                        case '^':
                            if (subjectMajorNumber === targetMajorNumber) {
                                if (subjectMinorNumber === targetMinorNumber) {
                                    if (subjectPatchNumber >= targetPatchNumber) {
                                        andResult = true;
                                    }
                                }
                                else if (subjectMinorNumber >= targetMinorNumber) {
                                    andResult = true;
                                }
                            }
                            break;
                        case '~':
                            if (subjectMajorNumber === targetMajorNumber) {
                                if (subjectMinor !== null &&
                                    subjectMinorNumber === targetMinorNumber) {
                                    if (subjectPatchNumber >= targetPatchNumber) {
                                        andResult = true;
                                    }
                                }
                            }
                            break;
                        case '>=':
                            if (subjectMajorNumber === targetMajorNumber) {
                                if (subjectMinorNumber === targetMinorNumber) {
                                    if (subjectPatchNumber >= targetPatchNumber) {
                                        andResult = true;
                                    }
                                }
                                else if (subjectMinorNumber >= targetMinorNumber) {
                                    andResult = true;
                                }
                            }
                            else if (subjectMajorNumber >= targetMajorNumber) {
                                andResult = true;
                            }
                            break;
                        case '>':
                            if (subjectMajorNumber === targetMajorNumber) {
                                if (targetMinor === null) {
                                    // x > x = false
                                    // x.y > x = false
                                }
                                else if (subjectMinorNumber === targetMinorNumber) {
                                    if (targetPatch === null) {
                                        // x.y > x.y = false
                                        // x.y.z > x.y = false
                                    }
                                    else if (subjectPatchNumber > targetPatchNumber) {
                                        andResult = true;
                                    }
                                }
                                else if (subjectMinorNumber > targetMinorNumber) {
                                    andResult = true;
                                }
                            }
                            else if (subjectMajorNumber > targetMajorNumber) {
                                andResult = true;
                            }
                            break;
                        case '<':
                            if (subjectMajorNumber === targetMajorNumber) {
                                if (subjectMinor === null) {
                                    // x < x = false
                                    // x < x.y = false
                                }
                                else if (subjectMinorNumber === targetMinorNumber) {
                                    if (subjectPatch === null) {
                                        // x.y < x.y = false
                                        // x.y < x.y.z = false
                                    }
                                    else if (subjectPatchNumber < targetPatchNumber) {
                                        andResult = true;
                                    }
                                }
                                else if (subjectMinorNumber < targetMinorNumber) {
                                    andResult = true;
                                }
                            }
                            else if (subjectMajorNumber < targetMajorNumber) {
                                andResult = true;
                            }
                            break;
                        case '<=':
                            if (subjectMajorNumber === targetMajorNumber) {
                                if (subjectMinor === null) {
                                    if (targetMinor === null) {
                                        // x <= x = true
                                        andResult = true;
                                    }
                                    // x <= x.y = false
                                }
                                else if (targetMinor === null) {
                                    // x.y <= x = true
                                    andResult = true;
                                }
                                else if (subjectMinorNumber === targetMinorNumber) {
                                    if (subjectPatch === null) {
                                        if (targetPatch === null) {
                                            // x.y <= x.y = true
                                            andResult = true;
                                        }
                                        // x.y <= x.y.z = false
                                    }
                                    else if (targetPatch === null) {
                                        // x.y.z <= x.y = true
                                        andResult = true;
                                    }
                                    else if (subjectPatchNumber <= targetPatchNumber) {
                                        // x.y.z <= x.y.z = true
                                        andResult = true;
                                    }
                                }
                                else if (subjectMinorNumber <= targetMinorNumber) {
                                    andResult = true;
                                }
                            }
                            else if (subjectMajorNumber <= targetMajorNumber) {
                                andResult = true;
                            }
                            break;
                        case '=':
                        case '':
                            if (subjectMajor === targetMajor) {
                                if (targetMinor === null) {
                                    andResult = true;
                                }
                                else if (subjectMinor === targetMinor) {
                                    if (targetPatch === null || subjectPatch === targetPatch) {
                                        andResult = true;
                                    }
                                }
                            }
                            break;
                        default:
                            throw new Error("range comparator was invalid: ".concat(JSON.stringify(andRange)));
                    }
                    // if one of the and conditions failed, don't continue and checks, and note failure to the or condition
                    if (!andResult) {
                        orResult = false;
                        break;
                    }
                    else {
                        // otherwise note success to the or condition
                        orResult = true;
                    }
                }
            }
            catch (e_2_1) { e_2 = { error: e_2_1 }; }
            finally {
                try {
                    if (andRanges_1_1 && !andRanges_1_1.done && (_b = andRanges_1.return)) _b.call(andRanges_1);
                }
                finally { if (e_2) throw e_2.error; }
            }
            // if the entire and conditions passed, then we can break out of the or conditions
            if (orResult) {
                return true;
            }
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (orRanges_1_1 && !orRanges_1_1.done && (_a = orRanges_1.return)) _a.call(orRanges_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
    // nothing passed
    return false;
}
exports.default = withinVersionRange;
