'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var Browserslist = require('browserslist');
var caniuseLite = require('caniuse-lite');
var compatData = require('@mdn/browser-compat-data');
var objectPath = require('object-path');
var semver = require('semver');
var uaParserJs = require('ua-parser-js');
var isbot = require('isbot');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var Browserslist__default = /*#__PURE__*/_interopDefaultLegacy(Browserslist);
var compatData__default = /*#__PURE__*/_interopDefaultLegacy(compatData);
var isbot__default = /*#__PURE__*/_interopDefaultLegacy(isbot);

/**
 * Coerces the given version
 */
function ensureSemver(browser, version) {
    if ((browser === "op_mini" || browser === "android") && version === "all") {
        return semver.coerce("0.0.0");
    }
    else if (browser === "safari" && version === "TP") {
        return SAFARI_TP_MAJOR_VERSION;
    }
    return semver.coerce(version, { loose: true });
}
/**
 * Coerces the given version
 */
function coerceToString(browser, version) {
    return ensureSemver(browser, version).toString();
}

/**
 * Compares two versions, a and b
 */
function compareVersions(a, b) {
    const normalizedA = isNaN(parseFloat(a)) ? a : parseFloat(a);
    const normalizedB = isNaN(parseFloat(b)) ? b : parseFloat(b);
    if (typeof normalizedA === "string" && typeof normalizedB !== "string") {
        return 1;
    }
    if (typeof normalizedB === "string" && typeof normalizedA !== "string") {
        return -1;
    }
    if (normalizedA < normalizedB)
        return -1;
    if (normalizedA > normalizedB)
        return 1;
    return 0;
}

/**
 * A Regular Expression that captures the part of a browser version that should be kept
 */
const NORMALIZE_BROWSER_VERSION_REGEXP = /(?![\d.,]+-)-*(.*)/;

const SAFARI_TP_MAJOR_VERSION = (() => {
    const versions = getSortedBrowserVersions("safari");
    const lastVersionBeforeTp = versions[versions.length - 2];
    const coerced = semver.coerce(lastVersionBeforeTp);
    if (coerced.minor === 9) {
        return semver.coerce(coerced.major + 1);
    }
    else {
        return semver.coerce(`${coerced.major}.${coerced.minor + 1}.0`);
    }
})();
/**
 * Ensures that for any given version of a browser, if it is newer than the latest known version, the last known version will be used as a fallback
 */
function normalizeBrowserVersion(browser, givenVersion, versions = getSortedBrowserVersions(browser)) {
    const givenVersionCoerced = ensureSemver(browser, givenVersion);
    const latestVersion = getLatestVersionOfBrowser(browser);
    const latestVersionCoerced = ensureSemver(browser, latestVersion);
    if (givenVersionCoerced == null || latestVersionCoerced == null) {
        throw new TypeError(`Could not detect the version of: '${givenVersion}' for browser: ${browser}`);
    }
    if (givenVersionCoerced.major > latestVersionCoerced.major ||
        (givenVersionCoerced.major === latestVersionCoerced.major && givenVersionCoerced.minor > latestVersionCoerced.minor) ||
        (givenVersionCoerced.major === latestVersionCoerced.major && givenVersionCoerced.minor === latestVersionCoerced.minor && givenVersionCoerced.patch > latestVersionCoerced.patch)) {
        return latestVersion;
    }
    return getClosestMatchingBrowserVersion(browser, givenVersion, versions);
}
/**
 * Gets the known version of the given browser that is closest to the given version
 */
function getClosestMatchingBrowserVersion(browser, version, versions = getSortedBrowserVersions(browser)) {
    const coerced = ensureSemver(browser, version);
    if (browser === "op_mini" && version === "all")
        return "all";
    if (browser === "safari") {
        if (version === "TP")
            return "TP";
        // If the given version is greater than or equal to the latest non-technical preview version of Safari, the closest match IS TP.
        else if (semver.gt(ensureSemver(browser, `${coerced.major}.${coerced.minor}`), ensureSemver(browser, versions.slice(-2)[0])))
            return "TP";
    }
    let candidate = versions[0];
    versions.forEach(currentVersion => {
        const currentCoerced = ensureSemver(browser, currentVersion);
        if (semver.gte(coerced, currentCoerced)) {
            candidate = currentVersion;
        }
    });
    return candidate;
}
function getSortedBrowserVersionsWithLeadingVersion(browser, inputVersion) {
    const versions = getSortedBrowserVersions(browser);
    const [firstVersion] = versions;
    if (firstVersion != null && inputVersion != null) {
        const firstVersionSemver = ensureSemver(browser, firstVersion);
        let nextInputVersion = inputVersion;
        while (true) {
            const nextInputSemver = ensureSemver(browser, nextInputVersion);
            if (semver.gt(firstVersionSemver, nextInputSemver)) {
                versions.unshift(nextInputVersion);
                nextInputVersion = String(nextInputSemver.major + 1);
            }
            else {
                break;
            }
        }
    }
    return versions;
}
/**
 * Gets all versions of the given browser, sorted
 */
function getSortedBrowserVersions(browser) {
    // Generate the Browserslist query
    const queryResult = Browserslist__default["default"]([`>= 0%`, `unreleased versions`]);
    const versions = [];
    // First, organize the different versions of the browsers inside the Map
    queryResult.forEach(part => {
        const [currentBrowser, version] = part.split(" ");
        if (currentBrowser !== browser)
            return;
        const versionMatch = version.match(NORMALIZE_BROWSER_VERSION_REGEXP);
        const normalizedVersion = versionMatch == null ? version : versionMatch[1];
        versions.push(normalizedVersion);
    });
    return versions.sort(compareVersions);
}
/**
 * Gets the latest version of the given browser
 */
function getLatestVersionOfBrowser(browser) {
    const versions = getSortedBrowserVersions(browser);
    return versions[versions.length - 1];
}
/**
 * Gets the oldest (stable) version of the given browser
 */
function getOldestVersionOfBrowser(browser) {
    const versions = getSortedBrowserVersions(browser);
    return versions[0];
}
/**
 * Gets the previous version of the given browser from the given version
 */
function getPreviousVersionOfBrowser(browser, version) {
    const versions = getSortedBrowserVersions(browser);
    const indexOfVersion = versions.indexOf(normalizeBrowserVersion(browser, version, versions));
    // If the version isn't included, or if it is the first version of it, return undefined
    if (indexOfVersion <= 0)
        return undefined;
    return versions[indexOfVersion - 1];
}
/**
 * Gets the previous version of the given browser from the given version
 */
function getNextVersionOfBrowser(browser, version) {
    const versions = getSortedBrowserVersions(browser);
    const indexOfVersion = versions.indexOf(normalizeBrowserVersion(browser, version, versions));
    // If the version isn't included, or if it is the first version of it, return undefined
    if (indexOfVersion <= 0)
        return undefined;
    return versions[indexOfVersion + 1];
}

/**
 * Caniuse has only a limited set of supported browsers.
 * There are cases where there is simply no way to guess
 * a browser based on a User Agent, and in these cases
 * this can be used as a fallback.
 * Chrome is the world's most used browser, and as an evergreen
 * browser, it is commonly the newest version. But to be safe
 * This fallback browser is placed a bit in the past
 */
const UNKNOWN_CANIUSE_BROWSER = {
    browser: "chrome",
    version: "80"
};

const ES5_FEATURES = [
    "javascript.builtins.Object.create",
    "javascript.builtins.Object.getPrototypeOf",
    "javascript.builtins.Object.defineProperty",
    "javascript.builtins.Object.defineProperties",
    "javascript.builtins.Object.getOwnPropertyDescriptor",
    "javascript.builtins.Object.getOwnPropertyNames",
    "javascript.builtins.Object.keys",
    "javascript.builtins.Object.preventExtensions",
    "javascript.builtins.Object.isExtensible",
    "javascript.builtins.Object.seal",
    "javascript.builtins.Object.isSealed",
    "javascript.builtins.Object.freeze",
    "javascript.builtins.Object.isFrozen",
    "javascript.builtins.Function.bind",
    "javascript.builtins.String.trim",
    "javascript.builtins.Array.isArray",
    "javascript.builtins.Array.every",
    "javascript.builtins.Array.filter",
    "javascript.builtins.Array.forEach",
    "javascript.builtins.Array.indexOf",
    "javascript.builtins.Array.lastIndexOf",
    "javascript.builtins.Array.map",
    "javascript.builtins.Array.reduce",
    "javascript.builtins.Array.some",
    "javascript.builtins.JSON.parse",
    "javascript.builtins.JSON.stringify",
    "javascript.builtins.Date.now",
    "javascript.builtins.Date.toISOString"
];
const ES2015_FEATURES = [
    ...ES5_FEATURES,
    "javascript.classes",
    "javascript.statements.const",
    "javascript.statements.let",
    "javascript.functions.arrow_functions",
    "javascript.functions.rest_parameters",
    "javascript.grammar.template_literals",
    "javascript.operators.destructuring",
    "javascript.operators.spread.spread_in_arrays",
    "javascript.functions.default_parameters",
    "javascript.builtins.RegExp.sticky",
    "javascript.operators.object_initializer.shorthand_property_names",
    "javascript.operators.object_initializer.computed_property_names",
    "javascript.operators.object_initializer.shorthand_method_names"
];
const ES2016_FEATURES = [...ES2015_FEATURES, "javascript.operators.exponentiation", "javascript.builtins.Array.includes"];
const ES2017_FEATURES = [
    ...ES2016_FEATURES,
    "javascript.builtins.AsyncFunction",
    "javascript.builtins.Object.values",
    "javascript.builtins.Object.entries",
    "javascript.builtins.Object.getOwnPropertyDescriptors",
    "javascript.builtins.String.padStart",
    "javascript.builtins.String.padEnd"
];
const ES2018_FEATURES = [...ES2017_FEATURES, "javascript.operators.spread.spread_in_object_literals", "javascript.builtins.Promise.finally"];
const ES2019_FEATURES = [
    ...ES2018_FEATURES,
    "javascript.builtins.Array.flat",
    "javascript.builtins.Array.flatMap",
    "javascript.builtins.Object.fromEntries",
    "javascript.builtins.String.trimStart",
    "javascript.builtins.String.trimEnd",
    "javascript.builtins.JSON.json_superset",
    "javascript.builtins.JSON.stringify.well_formed_stringify",
    "javascript.builtins.Symbol.description",
    "javascript.statements.try_catch.optional_catch_binding"
];
const ES2020_FEATURES = [...ES2019_FEATURES, "javascript.builtins.String.matchAll"];
const ES2021_FEATURES = [
    ...ES2020_FEATURES,
    "javascript.operators.logical_or_assignment",
    "javascript.operators.logical_nullish_assignment",
    "javascript.operators.logical_and_assignment",
    "javascript.builtins.String.replaceAll",
    "javascript.grammar.numeric_separators",
    "javascript.builtins.Promise.any"
];
const ES2022_FEATURES = [
    ...ES2021_FEATURES,
    "javascript.classes.public_class_fields",
    "javascript.classes.private_class_fields",
    "javascript.classes.private_class_fields_in",
    "javascript.classes.static_class_fields",
    "javascript.operators.await.top_level",
    "javascript.builtins.RegExp.hasIndices",
];

/**
 * Applies the given correction within the given version range
 */
function rangeCorrection(browser, supportKind, start, end) {
    const versions = getSortedBrowserVersions(browser);
    const corrections = [];
    versions.forEach(version => {
        let shouldSet = false;
        if (start == null && end == null) {
            shouldSet = true;
        }
        else if (start != null && end == null) {
            if (version === "TP") {
                shouldSet = true;
            }
            else if (version === "all") {
                shouldSet = true;
            }
            else {
                shouldSet = semver.gte(coerceToString(browser, version), coerceToString(browser, start));
            }
        }
        else if (start == null && end != null) {
            if (version === "TP") {
                shouldSet = end === "TP";
            }
            else if (version === "all") {
                shouldSet = true;
            }
            else {
                shouldSet = semver.lte(coerceToString(browser, version), coerceToString(browser, end));
            }
        }
        else if (start != null && end != null) {
            if (version === "TP") {
                shouldSet = end === "TP";
            }
            else if (version === "all") {
                shouldSet = true;
            }
            else {
                shouldSet = semver.gte(coerceToString(browser, version), coerceToString(browser, start)) && semver.lte(coerceToString(browser, version), coerceToString(browser, end));
            }
        }
        if (shouldSet) {
            corrections.push({
                kind: supportKind,
                version
            });
        }
    });
    return corrections;
}

const FIREFOX_MATCH = /Firefox\/([\d.]+)/i;
const IOS_REGEX_1 = /(iPhone)|(iPad)/i;
const IOS_REGEX_2 = /(iOS)\s*([\d._]+)/i;
const UNDERSCORED_VERSION_REGEX = /\d+_/;
const FBSV_IOS_VERSION_REGEX = /FBSV\/([\d.]+)/i;
const IOS_14_5_UA_1 = /(CFNetwork\/1237\s+Darwin\/20.4)/i;
const IOS_3_2_UA_1 = /(^Mobile\/7B334b)/i;
// Extend 'isbot' with more matches
isbot__default["default"].extend(["bitdiscovery", "Dalvik/", "placid.app/v1", "WebsiteMetadataRetriever", "(compatible; aa/1.0)"]);
// These extension provide ua-parser-js with support for additional browsers
// such as Sogou Explorer
const PARSER_EXTENSIONS = {
    engine: [[/(Chrome)\/([\d.]+)/i], ["blink", "version"]],
    browser: [
        [/(MetaSr)\s*([\d.]+)/i],
        ["Sogou Explorer", "version"],
        [/(HeyTapBrowser)\/([\d.]+)/i],
        ["HeyTapBrowser", "version"],
        [/(SamsungBrowser)\/CrossApp/i],
        ["Samsung Browser"],
        [/(Nokia\d+\/[\d.]+.*Profile\/MIDP)/i],
        ["WAP"]
    ]
};
/**
 * A class that wraps UAParser
 */
class UaParserWrapper {
    constructor(userAgent) {
        this.userAgent = userAgent;
        this.parser = new uaParserJs.UAParser(userAgent, PARSER_EXTENSIONS);
    }
    /**
     * Gets the IUserAgentBrowser based on the UAParser
     */
    getBrowser() {
        return this.extendGetBrowserResult(this.parser.getBrowser());
    }
    /**
     * Gets the IUserAgentOS based on the UAParser
     */
    getOS() {
        return this.extendGetOsResult(this.parser.getOS());
    }
    /**
     * Gets the IUserAgentDevice based on the UAParser
     */
    getDevice() {
        return this.parser.getDevice();
    }
    /**
     * Gets the IEngine based on the UAParser
     */
    getEngine() {
        return this.extendGetEngineResult(this.parser.getEngine());
    }
    /**
     * Extends the result of calling 'getBrowser' on the UAParser and always takes bots into account
     */
    extendGetBrowserResult(result) {
        var _a, _b;
        // Ensure that the EdgeHTML version is used
        if (result.name === "Edge") {
            const engine = this.parser.getEngine();
            if (engine.name === "EdgeHTML") {
                result.version = engine.version;
                // noinspection JSDeprecatedSymbols
                result.major = String((_b = (_a = semver.coerce(engine.version)) === null || _a === void 0 ? void 0 : _a.major) !== null && _b !== void 0 ? _b : result.version);
            }
        }
        // Check if it is a bot and match it if so
        // Also treat Dalvik/ as a bot
        if (result.name !== "Chrome Headless" && isbot__default["default"](this.userAgent)) {
            if (this.userAgent.includes("http://www.google.com/bot.htm") || this.userAgent.includes("http://www.google.com/adsbot.htm")) {
                // As far as we know, the last reported update to Googlebot was the intent
                // to keep it evergreen, but so far it seems 74 is the latest official version
                result.name = "Chrome";
                result.version = "74";
                // noinspection JSDeprecatedSymbols
                result.major = "74";
            }
            // Treat all other bots as IE 11
            else {
                result.name = "IE";
                result.version = "11";
                // noinspection JSDeprecatedSymbols
                result.major = "11";
            }
        }
        if (result["Sogou Explorer"] != null) {
            result.name = "Sogou Explorer";
            delete result["Sogou Explorer"];
        }
        else if (result.HeyTapBrowser != null) {
            result.name = "HeyTapBrowser";
            delete result.HeyTapBrowser;
        }
        else if (result["Samsung Browser"] != null) {
            result.name = "Samsung Browser";
            delete result["Samsung Browser"];
        }
        else if (result.WAP != null) {
            result.name = "IE";
            result.version = "8";
            delete result.WAP;
        }
        return result;
    }
    /**
     * Extends the result of calling 'getEngine'
     */
    extendGetEngineResult(result) {
        if (result.blink != null) {
            result.name = "Blink";
            delete result.blink;
        }
        // The User Agent may hold additional information, such as the equivalent Firefox version
        if (result.name === "Goanna") {
            const ffMatch = this.userAgent.match(FIREFOX_MATCH);
            if (ffMatch != null) {
                result.name = "Gecko";
                result.version = ffMatch[1];
            }
        }
        return result;
    }
    /**
     * Extends the result of calling 'getOS'
     */
    extendGetOsResult(result) {
        if (result.version != null && UNDERSCORED_VERSION_REGEX.test(result.version)) {
            result.version = result.version.replace(/_/g, ".");
        }
        if ((result.name == null || result.name === "iOS") && (IOS_REGEX_1.test(this.userAgent) || IOS_REGEX_2.test(this.userAgent))) {
            result.name = "iOS";
            if (result.version == null) {
                // If it is the Facebook browser, the iOS version may be reported
                // through its FBSV/{version} part
                const fbsvMatch = this.userAgent.match(FBSV_IOS_VERSION_REGEX);
                if (fbsvMatch != null) {
                    result.version = fbsvMatch[1].replace(/_/g, ".");
                }
                else {
                    const iosRegex2Match = this.userAgent.match(IOS_REGEX_2);
                    if (iosRegex2Match != null) {
                        result.version = iosRegex2Match[2].replace(/_/g, ".");
                    }
                }
            }
        }
        if ((result.name == null || result.name === "iOS") && IOS_14_5_UA_1.test(this.userAgent)) {
            result.name = "iOS";
            result.version = "14.5";
        }
        if ((result.name == null || result.name === "iOS") && IOS_3_2_UA_1.test(this.userAgent)) {
            result.name = "iOS";
            result.version = "3.2";
        }
        return result;
    }
}

/**
 * A Cache between user agent names and generated Browserslists
 */
const userAgentToBrowserslistCache = new Map();
/**
 * A Cache for retrieving browser support for some features
 * @type {Map<string, BrowserSupportForFeaturesCommonResult>}
 */
const browserSupportForFeaturesCache = new Map();
/**
 * A Cache between feature names and their CaniuseStats
 * @type {Map<string, CaniuseStatsNormalized>}
 */
const featureToCaniuseStatsCache = new Map();
/**
 * A Cache between user agents with any amount of features and whether or not they are supported by the user agent
 * @type {Map<string, boolean>}
 */
const userAgentWithFeaturesToSupportCache = new Map();
// tslint:disable:no-magic-numbers
/**
 * A Map between features and browsers that has partial support for them but should be allowed anyway
 * @type {Map<string, string[]>}
 */
const PARTIAL_SUPPORT_ALLOWANCES = new Map([
    ["shadowdomv1", "*"],
    ["custom-elementsv1", "*"],
    ["web-animation", "*"]
]);
/**
 * These browsers will be ignored all-together since they only report the latest
 * version from Caniuse and is considered unreliable because of it
 * @type {Set<string>}
 */
const IGNORED_BROWSERS_INPUT = ["and_chr", "and_ff", "and_uc", "and_qq", "baidu", "op_mini"];
const IGNORED_BROWSERS = new Set(IGNORED_BROWSERS_INPUT);
const TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT = {
    /* eslint-disable @typescript-eslint/naming-convention */
    android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `4`),
    chrome: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `7`),
    and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `7`),
    edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */, "12"),
    samsung: rangeCorrection("samsung", "AVAILABLE" /* AVAILABLE */, `4`),
    opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `12`),
    op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `12`),
    firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `4`),
    and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `4`),
    safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `6`),
    ios_saf: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `5`),
    ie: rangeCorrection("ie", "AVAILABLE" /* AVAILABLE */, `11`),
    op_mini: rangeCorrection("op_mini", "AVAILABLE" /* AVAILABLE */, `all`),
    bb: rangeCorrection("bb", "AVAILABLE" /* AVAILABLE */, `10`),
    and_uc: rangeCorrection("and_uc", "AVAILABLE" /* AVAILABLE */, `11.8`),
    and_qq: rangeCorrection("and_qq", "AVAILABLE" /* AVAILABLE */, `1.2`),
    baidu: rangeCorrection("baidu", "AVAILABLE" /* AVAILABLE */, `7.12`)
    /* eslint-enable @typescript-eslint/naming-convention */
};
const TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT = {
    /* eslint-disable @typescript-eslint/naming-convention */
    android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `45`),
    chrome: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `45`),
    and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `45`),
    edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */, "12"),
    samsung: rangeCorrection("samsung", "AVAILABLE" /* AVAILABLE */, `5`),
    opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `32`),
    op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `32`),
    firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `38`),
    and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `38`),
    safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`),
    ios_saf: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`),
    ie: rangeCorrection("ie", "AVAILABLE" /* AVAILABLE */, `11`),
    ie_mob: rangeCorrection("ie", "AVAILABLE" /* AVAILABLE */, `11`)
    /* eslint-enable @typescript-eslint/naming-convention */
};
const TYPED_ARRAY_ES2016_DATA_CORRECTIONS_INPUT = {
    /* eslint-disable @typescript-eslint/naming-convention */
    android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `47`),
    chrome: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `47`),
    and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `47`),
    edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */, "14"),
    samsung: rangeCorrection("samsung", "AVAILABLE" /* AVAILABLE */, `5`),
    opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `34`),
    op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `34`),
    firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `43`),
    and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `43`),
    safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`),
    ios_saf: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`)
    /* eslint-enable @typescript-eslint/naming-convention */
};
const TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT = {
    /* eslint-disable @typescript-eslint/naming-convention */
    android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `38`),
    chrome: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `38`),
    and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `38`),
    edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */, "12"),
    samsung: rangeCorrection("samsung", "AVAILABLE" /* AVAILABLE */, `5`),
    opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `26`),
    op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `26`),
    firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `37`),
    and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `37`),
    safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`),
    ios_saf: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`)
    /* eslint-enable @typescript-eslint/naming-convention */
};
const TYPED_ARRAY_SPECIES_DATA_CORRECTIONS_INPUT = {
    /* eslint-disable @typescript-eslint/naming-convention */
    android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `51`),
    chrome: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `51`),
    and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `51`),
    edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */, "13"),
    samsung: rangeCorrection("samsung", "AVAILABLE" /* AVAILABLE */, `5`),
    opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `38`),
    op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `38`),
    firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `48`),
    and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `48`),
    safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`),
    ios_saf: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`)
    /* eslint-enable @typescript-eslint/naming-convention */
};
/**
 * Not all Caniuse data is entirely correct. For some features, the data on https://kangax.github.io/compat-table/es6/
 * is more correct. When a Browserslist is generated based on support for specific features, it is really important
 * that it is correct, especially if the browserslist will be used as an input to tools such as @babel/preset-env.
 * This table provides some corrections to the Caniuse data that makes it align better with actual availability
 * @type {[string, CaniuseBrowserCorrection][]}
 */
const FEATURE_TO_BROWSER_DATA_CORRECTIONS_INPUT = [
    /* eslint-disable @typescript-eslint/naming-convention */
    [
        "xhr2",
        {
            ie: [
                {
                    // Caniuse reports that XMLHttpRequest support is partial in Internet Explorer 11, but it is in fact properly supported
                    kind: "AVAILABLE" /* AVAILABLE */,
                    version: "11"
                }
            ]
        }
    ],
    [
        // Caniuse reports that Safari 12.1 and iOS Safari 12.2 has partial support for Web Animations,
        // but they do not - They require enabling it as an experimental feature
        "web-animation",
        {
            safari: rangeCorrection("safari", "UNAVAILABLE" /* UNAVAILABLE */, `0`, "13.4"),
            ios_saf: rangeCorrection("ios_saf", "UNAVAILABLE" /* UNAVAILABLE */, `0`, "13.4")
        }
    ],
    [
        "es6-class",
        {
            edge: [
                {
                    // Caniuse reports that Microsoft Edge has been supporting classes since v12, but it was prefixed until v13
                    kind: "PREFIXED" /* PREFIXED */,
                    version: "12"
                }
            ],
            ios_saf: [
                {
                    // Caniuse reports that iOS Safari has been supporting classes since v9, but the implementation was only partial
                    kind: "PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */,
                    version: "9"
                },
                {
                    // Caniuse reports that iOS Safari has been supporting classes since v9, but the implementation was only partial
                    kind: "PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */,
                    version: "9.2"
                },
                {
                    // Caniuse reports that iOS Safari has been supporting classes since v9, but the implementation was only partial
                    kind: "PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */,
                    version: "9.3"
                }
            ],
            safari: [
                {
                    // Caniuse reports that Safari has been supporting classes since v9, but the implementation was only partial
                    kind: "PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */,
                    version: "9"
                },
                {
                    // Caniuse reports that Safari has been supporting classes since v9, but the implementation was only partial
                    kind: "PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */,
                    version: "9.1"
                }
            ]
        }
    ],
    [
        "api.Element.classList",
        {
            edge: [
                {
                    // Caniuse reports that Microsoft Edge v15 has only partial support for class-list since it doesn't support SVG elements,
                    // but we don't want feature detections to return false for that browser
                    kind: "AVAILABLE" /* AVAILABLE */,
                    version: "15"
                }
            ],
            ie: [
                {
                    // Caniuse reports that IE 10 has only partial support for class-list since it doesn't support SVG elements,
                    // but we don't want feature detections to return false for that browser
                    kind: "AVAILABLE" /* AVAILABLE */,
                    version: "10"
                },
                {
                    // Caniuse reports that IE 11 has only partial support for class-list since it doesn't support SVG elements,
                    // but we don't want feature detections to return false for that browser
                    kind: "AVAILABLE" /* AVAILABLE */,
                    version: "11"
                }
            ]
        }
    ],
    ["javascript.builtins.TypedArray.from", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.of", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.subarray", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.copyWithin", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.every", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.fill", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.filter", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.find", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.findIndex", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.forEach", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.indexOf", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.join", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.lastIndexOf", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.map", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.reduce", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.reduceRight", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.reverse", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.some", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.sort", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.toLocaleString", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.toString", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.slice", TYPED_ARRAY_ES2015_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.includes", TYPED_ARRAY_ES2016_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.keys", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.values", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.entries", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.@@iterator", TYPED_ARRAY_KEYS_VALUES_ENTRIES_ITERATOR_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray.@@species", TYPED_ARRAY_SPECIES_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.TypedArray", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Int8Array", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Int16Array", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Int32Array", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Float32Array", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Float64Array", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Uint8Array", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Uint8ClampedArray", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Uint16ClampedArray", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    ["javascript.builtins.Uint32ClampedArray", TYPED_ARRAY_BASE_DATA_CORRECTIONS_INPUT],
    [
        "javascript.builtins.String.@@iterator",
        {
            android: rangeCorrection("chrome", "AVAILABLE" /* AVAILABLE */, `38`),
            chrome: rangeCorrection("chrome", "AVAILABLE" /* AVAILABLE */, `38`),
            and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `38`),
            edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */, `12`),
            opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `25`),
            op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `25`),
            firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `36`),
            and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `36`),
            safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `9`),
            ios_saf: rangeCorrection("ios_saf", "AVAILABLE" /* AVAILABLE */, `9`),
            samsung: rangeCorrection("samsung", "AVAILABLE" /* AVAILABLE */, `3`)
        }
    ],
    [
        "javascript.builtins.Symbol.asyncIterator",
        {
            android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `63`),
            chrome: rangeCorrection("chrome", "AVAILABLE" /* AVAILABLE */, `63`),
            and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `63`),
            opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `50`),
            op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `50`),
            firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `57`),
            and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `57`),
            safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `11.1`),
            ios_saf: rangeCorrection("ios_saf", "AVAILABLE" /* AVAILABLE */, `11.1`)
        }
    ],
    [
        "javascript.builtins.Array.@@species",
        {
            android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `51`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Chrome v51
            chrome: rangeCorrection("chrome", "AVAILABLE" /* AVAILABLE */, `51`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Chrome for Android v51
            and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `51`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Edge v14
            edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */, `14`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Firefox v41
            firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `41`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Firefox for Android v41
            and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `41`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Opera v38
            opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `38`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Opera for Android v38
            op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `38`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Safari v10
            safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`),
            // MDN reports that it doesn't support Array.@@species, but it does and has done since Safari for iOS v10
            ios_saf: rangeCorrection("ios_saf", "AVAILABLE" /* AVAILABLE */, `10`)
        }
    ],
    [
        "javascript.builtins.Date.@@toPrimitive",
        {
            android: rangeCorrection("android", "AVAILABLE" /* AVAILABLE */, `48`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Chrome v48
            chrome: rangeCorrection("chrome", "AVAILABLE" /* AVAILABLE */, `48`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Chrome for Android v48
            and_chr: rangeCorrection("and_chr", "AVAILABLE" /* AVAILABLE */, `48`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done in all Edge versions
            edge: rangeCorrection("edge", "AVAILABLE" /* AVAILABLE */),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Firefox v44
            firefox: rangeCorrection("firefox", "AVAILABLE" /* AVAILABLE */, `44`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Firefox for Android v44
            and_ff: rangeCorrection("and_ff", "AVAILABLE" /* AVAILABLE */, `44`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Opera v35
            opera: rangeCorrection("opera", "AVAILABLE" /* AVAILABLE */, `35`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Opera for Android v35
            op_mob: rangeCorrection("op_mob", "AVAILABLE" /* AVAILABLE */, `35`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Safari v10
            safari: rangeCorrection("safari", "AVAILABLE" /* AVAILABLE */, `10`),
            // MDN reports that it doesn't support Date.@@toPrimitive, but it does and has done since Safari for iOS v10
            ios_saf: rangeCorrection("ios_saf", "AVAILABLE" /* AVAILABLE */, `10`),
            // MDN reports that it doesn't support the Date.@@toPrimitive method, but it does and has done for all Samsung Internet versions
            samsung: rangeCorrection("samsung", "AVAILABLE" /* AVAILABLE */)
        }
    ],
    [
        "fetch",
        {
            edge: [
                {
                    // Caniuse reports that Microsoft Edge has been supporting fetch since v14, but the implementation was quite unstable until v15
                    kind: "UNAVAILABLE" /* UNAVAILABLE */,
                    version: "14"
                }
            ]
        }
    ],
    [
        "api.Window",
        {
            chrome: rangeCorrection("chrome", "UNAVAILABLE" /* UNAVAILABLE */, `0`, `18`),
            safari: rangeCorrection("safari", "UNAVAILABLE" /* UNAVAILABLE */, `0`, `5.1`),
            ie: rangeCorrection("ie", "UNAVAILABLE" /* UNAVAILABLE */, `0`, `7`),
            opera: rangeCorrection("safari", "UNAVAILABLE" /* UNAVAILABLE */, `0`, `11.1`)
        }
    ],
    [
        "javascript.builtins.String.matchAll",
        {
            samsung: rangeCorrection("samsung", "UNAVAILABLE" /* UNAVAILABLE */, `0`, `9.4`)
        }
    ],
    [
        "resizeobserver",
        {
            safari: rangeCorrection("safari", "UNAVAILABLE" /* UNAVAILABLE */, `0`)
        }
    ]
    /* eslint-enable @typescript-eslint/naming-convention */
];
/**
 * A Map between caniuse features and corrections to apply (see above)
 * @type {Map<string, CaniuseBrowserCorrection>}
 */
const FEATURE_TO_BROWSER_DATA_CORRECTIONS_MAP = new Map(FEATURE_TO_BROWSER_DATA_CORRECTIONS_INPUT);
/**
 * Returns the input query, but extended with the given options
 */
function extendQueryWith(query, extendWith) {
    const normalizedExtendWith = Array.isArray(extendWith) ? extendWith : [extendWith];
    return [...new Set([...query, ...normalizedExtendWith])];
}
/**
 * Normalizes the given Browserslist
 */
function normalizeBrowserslist(browserslist) {
    return Browserslist__default["default"](browserslist);
}
/**
 * Returns the input query, but extended with 'unreleased versions'
 *
 * @param query
 * @param browsers
 * @returns
 */
function extendQueryWithUnreleasedVersions(query, browsers) {
    return extendQueryWith(query, Array.from(browsers).map(browser => `unreleased ${browser} versions`));
}
/**
 * Generates a Browserslist based on browser support for the given features
 *
 * @param features
 * @returns
 */
function browsersWithSupportForFeatures(...features) {
    const { query, browsers } = browserSupportForFeaturesCommon(">=", ...features);
    return extendQueryWithUnreleasedVersions(query, browsers);
}
/**
 * Returns true if the given Browserslist supports the given EcmaVersion
 * @param browserslist
 * @param version
 */
function browserslistSupportsEcmaVersion(browserslist, version) {
    switch (version) {
        case "es3":
            // ES3 is the lowest possible target and will always be treated as supported
            return true;
        case "es5":
            return browserslistSupportsFeatures(browserslist, ...ES5_FEATURES);
        case "es2015":
            return browserslistSupportsFeatures(browserslist, ...ES2015_FEATURES);
        case "es2016":
            return browserslistSupportsFeatures(browserslist, ...ES2016_FEATURES);
        case "es2017":
            return browserslistSupportsFeatures(browserslist, ...ES2017_FEATURES);
        case "es2018":
            return browserslistSupportsFeatures(browserslist, ...ES2018_FEATURES);
        case "es2019":
            return browserslistSupportsFeatures(browserslist, ...ES2019_FEATURES);
        case "es2020":
            return browserslistSupportsFeatures(browserslist, ...ES2020_FEATURES);
        case "es2021":
            return browserslistSupportsFeatures(browserslist, ...ES2021_FEATURES);
        case "es2022":
            return browserslistSupportsFeatures(browserslist, ...ES2022_FEATURES);
    }
}
/**
 * Returns the appropriate Ecma version for the given Browserslist
 */
function getAppropriateEcmaVersionForBrowserslist(browserslist) {
    if (browserslistSupportsEcmaVersion(browserslist, "es2022"))
        return "es2022";
    if (browserslistSupportsEcmaVersion(browserslist, "es2021"))
        return "es2021";
    if (browserslistSupportsEcmaVersion(browserslist, "es2020"))
        return "es2020";
    if (browserslistSupportsEcmaVersion(browserslist, "es2019"))
        return "es2019";
    if (browserslistSupportsEcmaVersion(browserslist, "es2018"))
        return "es2018";
    else if (browserslistSupportsEcmaVersion(browserslist, "es2017"))
        return "es2017";
    else if (browserslistSupportsEcmaVersion(browserslist, "es2016"))
        return "es2016";
    else if (browserslistSupportsEcmaVersion(browserslist, "es2015"))
        return "es2015";
    else if (browserslistSupportsEcmaVersion(browserslist, "es5"))
        return "es5";
    else
        return "es3";
}
/**
 * Generates a Browserslist based on browser support for the given ECMA version
 */
function browsersWithSupportForEcmaVersion(version) {
    switch (version) {
        case "es3":
            return browsersWithoutSupportForFeatures(...ES5_FEATURES);
        case "es5":
            return browsersWithSupportForFeatures(...ES5_FEATURES);
        case "es2015":
            return browsersWithSupportForFeatures(...ES2015_FEATURES);
        case "es2016":
            return browsersWithSupportForFeatures(...ES2016_FEATURES);
        case "es2017":
            return browsersWithSupportForFeatures(...ES2017_FEATURES);
        case "es2018":
            return browsersWithSupportForFeatures(...ES2018_FEATURES);
        case "es2019":
            return browsersWithSupportForFeatures(...ES2019_FEATURES);
        case "es2020":
            return browsersWithSupportForFeatures(...ES2020_FEATURES);
        case "es2021":
            return browsersWithSupportForFeatures(...ES2021_FEATURES);
        case "es2022":
            return browsersWithSupportForFeatures(...ES2022_FEATURES);
    }
}
/**
 * Returns true if the given browserslist support all of the given features
 *
 * @param browserslist
 * @param features
 * @returns
 */
function browserslistSupportsFeatures(browserslist, ...features) {
    // First, generate an ideal browserslist that would target the given features exactly
    const normalizedIdealBrowserslist = normalizeBrowserslist(browsersWithSupportForFeatures(...features));
    // Now, normalize the input browserslist
    const normalizedInputBrowserslist = normalizeBrowserslist(browserslist);
    // Now, compare the two and see if they align. If they do, the input browserslist *does* support all of the given features.
    // They align if all members of the input browserslist are included in the ideal browserslist
    return normalizedInputBrowserslist.every(option => normalizedIdealBrowserslist.includes(option));
}
/**
 * Generates a Browserslist based on browsers that *doesn't* support the given features
 *
 * @param features
 * @returns
 */
function browsersWithoutSupportForFeatures(...features) {
    return browserSupportForFeaturesCommon("<", ...features).query;
}
/**
 * Returns true if the given browser should be ignored. The data reported from Caniuse is a bit lacking.
 * For example, only the latest version of and_ff, and_qq, and_uc and baidu is reported, and since
 * android went to use Chromium for the WebView, it has only reported the latest Chromium version
 *
 * @param browser
 * @param version
 * @returns
 */
function shouldIgnoreBrowser(browser, version) {
    return ((browser === "android" && semver.gt(coerceToString(browser, version), coerceToString(browser, "4.4.4"))) ||
        (browser === "op_mob" && semver.gt(coerceToString(browser, version), coerceToString(browser, "12.1"))) ||
        IGNORED_BROWSERS.has(browser));
}
/**
 * Normalizes the given ICaniuseLiteFeature
 *
 * @param stats
 * @param featureName
 * @returns
 */
function getCaniuseLiteFeatureNormalized(stats, featureName) {
    // Check if a correction exists for this browser
    const featureCorrectionMatch = FEATURE_TO_BROWSER_DATA_CORRECTIONS_MAP.get(featureName);
    const keys = Object.keys(stats);
    keys.forEach(browser => {
        const browserDict = stats[browser];
        Object.entries(browserDict).forEach(([version, support]) => {
            const versionMatch = version.match(NORMALIZE_BROWSER_VERSION_REGEXP);
            const normalizedVersion = versionMatch == null ? version : versionMatch[1];
            let supportKind;
            if (support === "AVAILABLE" /* AVAILABLE */ ||
                support === "UNAVAILABLE" /* UNAVAILABLE */ ||
                support === "PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */ ||
                support === "PREFIXED" /* PREFIXED */) {
                supportKind = support;
            }
            else if (support.startsWith("y")) {
                supportKind = "AVAILABLE" /* AVAILABLE */;
            }
            else if (support.startsWith("n")) {
                supportKind = "UNAVAILABLE" /* UNAVAILABLE */;
            }
            else if (support.startsWith("a")) {
                supportKind = "PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */;
            }
            else {
                supportKind = "PREFIXED" /* PREFIXED */;
            }
            // Delete the rewritten version
            if (version !== normalizedVersion) {
                delete browserDict[version];
            }
            if (support !== supportKind) {
                browserDict[normalizedVersion] = supportKind;
            }
            // If a feature correction exists for this feature, apply applicable corrections
            if (featureCorrectionMatch != null) {
                // Check if the browser has some corrections
                const browserMatch = featureCorrectionMatch[browser];
                if (browserMatch != null) {
                    // Apply all corrections
                    browserMatch.forEach(correction => {
                        browserDict[correction.version] = correction.kind;
                    });
                }
            }
        });
    });
    return stats;
}
/**
 * Gets the support from caniuse for the given feature
 *
 * @param feature
 * @returns
 */
function getCaniuseFeatureSupport(feature) {
    const rawStats = caniuseLite.feature(caniuseLite.features[feature]).stats;
    for (const browser of Object.keys(rawStats)) {
        const browserDict = rawStats[browser];
        for (const version of Object.keys(browserDict)) {
            // If browser is Android and version is greater than "4.4.4", or if the browser is Chrome, Firefox, UC, QQ for Android, or Baidu,
            // strip it entirely from the data, since Caniuse only reports the latest versions of those browsers
            if (shouldIgnoreBrowser(browser, version)) {
                delete browserDict[version];
            }
        }
    }
    return getCaniuseLiteFeatureNormalized(rawStats, feature);
}
/**
 * Returns true if the given feature is a Caniuse feature
 * @param feature
 */
function isCaniuseFeature(feature) {
    return caniuseLite.features[feature] != null;
}
/**
 * Returns true if the given feature is a MDN feature
 * @param feature
 */
function isMdnFeature(feature) {
    return objectPath.get(compatData__default["default"], feature) != null;
}
/**
 * Asserts that the given feature is a valid Caniuse or MDN feature name
 *
 * @param feature
 */
function assertKnownFeature(feature) {
    if (!isCaniuseFeature(feature) && !isMdnFeature(feature)) {
        throw new TypeError(`The given feature: '${feature}' is unknown. It must be a valid Caniuse or MDN feature!`);
    }
}
/**
 * Gets the feature support for the given feature
 *
 * @param feature
 * @returns
 */
function getFeatureSupport(feature) {
    // First check if the cache has a match and return it if so
    const cacheHit = featureToCaniuseStatsCache.get(feature);
    if (cacheHit != null)
        return cacheHit;
    // Assert that the feature is in fact known
    assertKnownFeature(feature);
    const result = isMdnFeature(feature) ? getMdnFeatureSupport(feature) : getCaniuseFeatureSupport(feature);
    // Store it in the cache before returning it
    featureToCaniuseStatsCache.set(feature, result);
    return result;
}
/**
 * Gets the support from caniuse for the given feature
 *
 * @param feature
 * @returns
 */
function getMdnFeatureSupport(feature) {
    const match = objectPath.get(compatData__default["default"], feature);
    const supportMap = match.__compat.support;
    const formatBrowser = (mdnBrowser, caniuseBrowser) => {
        const versionMap = supportMap[mdnBrowser];
        const versionAdded = versionMap == null
            ? false
            : Array.isArray(versionMap)
                ? // If there are multiple entries, take the one that hasn't been removed yet, if any
                    (() => {
                        const versionStillInBrowser = versionMap.filter(element => element.version_removed == null)[0];
                        return versionStillInBrowser == null || versionStillInBrowser.version_added == null ? false : versionStillInBrowser.version_added;
                    })()
                : versionMap.version_added;
        const dict = {};
        const supportedSince = versionAdded === false ? null : versionAdded === true ? getOldestVersionOfBrowser(caniuseBrowser) : versionAdded;
        getSortedBrowserVersionsWithLeadingVersion(caniuseBrowser, typeof versionAdded === "string" ? versionAdded : undefined).forEach(version => {
            // If the features has never been supported, mark the feature as unavailable
            if (supportedSince == null) {
                dict[version] = "UNAVAILABLE" /* UNAVAILABLE */;
            }
            else {
                dict[version] =
                    version === "TP" || version === "all" || semver.gte(coerceToString(caniuseBrowser, version), coerceToString(caniuseBrowser, supportedSince))
                        ? "AVAILABLE" /* AVAILABLE */
                        : "UNAVAILABLE" /* UNAVAILABLE */;
            }
        });
        return dict;
    };
    const stats = {
        /* eslint-disable @typescript-eslint/naming-convention */
        and_chr: formatBrowser("chrome_android", "and_chr"),
        chrome: formatBrowser("chrome", "chrome"),
        and_ff: formatBrowser("firefox_android", "and_ff"),
        and_qq: {},
        and_uc: {},
        android: formatBrowser("webview_android", "android"),
        baidu: {},
        bb: {},
        edge: formatBrowser("edge", "edge"),
        samsung: formatBrowser("samsunginternet_android", "samsung"),
        ie: formatBrowser("ie", "ie"),
        ie_mob: formatBrowser("ie", "ie_mob"),
        safari: formatBrowser("safari", "safari"),
        ios_saf: formatBrowser("safari_ios", "ios_saf"),
        opera: formatBrowser("opera", "opera"),
        op_mini: {},
        op_mob: {},
        firefox: formatBrowser("firefox", "firefox")
        /* eslint-enable @typescript-eslint/naming-convention */
    };
    return getCaniuseLiteFeatureNormalized(stats, feature);
}
/**
 * Gets the first version that matches the given CaniuseSupportKind
 *
 * @param kind
 * @param stats
 * @returns
 */
function getFirstVersionWithSupportKind(kind, stats) {
    // Sort all keys of the object
    const sortedKeys = Object.keys(stats).sort(compareVersions);
    for (const key of sortedKeys) {
        if (stats[key] === kind) {
            return key;
        }
    }
    return undefined;
}
/**
 * Sorts the given browserslist. Ensures that 'not' expressions come last
 *
 * @param a
 * @param b
 * @returns
 */
function sortBrowserslist(a, b) {
    if (a.startsWith("not") && !b.startsWith("not"))
        return 1;
    if (!a.startsWith("not") && b.startsWith("not"))
        return -1;
    return 0;
}
/**
 * Gets a Map between browser names and the first version of them that supported the given feature
 *
 * @param feature
 * @returns
 */
function getFirstVersionsWithFullSupport(feature) {
    const support = getFeatureSupport(feature);
    // A map between browser names and their required versions
    const browserMap = new Map();
    const entries = Object.entries(support);
    entries.forEach(([browser, stats]) => {
        const fullSupportVersion = getFirstVersionWithSupportKind("AVAILABLE" /* AVAILABLE */, stats);
        if (fullSupportVersion != null) {
            browserMap.set(browser, fullSupportVersion);
        }
    });
    return browserMap;
}
/**
 * Gets the Cache key for the given combination of a comparison operator and any amount of features
 *
 * @param comparisonOperator
 * @param features
 */
function getBrowserSupportForFeaturesCacheKey(comparisonOperator, features) {
    return `${comparisonOperator}.${features.sort().join(",")}`;
}
/**
 * Common logic for the functions that generate browserslists based on feature support
 */
function browserSupportForFeaturesCommon(comparisonOperator, ...features) {
    const cacheKey = getBrowserSupportForFeaturesCacheKey(comparisonOperator, features);
    // First check if the cache has a hit and return it if so
    const cacheHit = browserSupportForFeaturesCache.get(cacheKey);
    if (cacheHit != null) {
        return cacheHit;
    }
    // All of the generated browser maps
    const browserMaps = [];
    for (const feature of features) {
        const support = getFeatureSupport(feature);
        // A map between browser names and their required versions
        const browserMap = new Map();
        const entries = Object.entries(support);
        entries.forEach(([browser, stats]) => {
            const fullSupportVersion = getFirstVersionWithSupportKind("AVAILABLE" /* AVAILABLE */, stats);
            const partialSupportVersion = getFirstVersionWithSupportKind("PARTIAL_SUPPORT" /* PARTIAL_SUPPORT */, stats);
            let versionToSet;
            if (fullSupportVersion != null) {
                versionToSet = fullSupportVersion;
            }
            // Otherwise, check if partial support exists and should be allowed
            if (partialSupportVersion != null) {
                // Get all partial support allowances for this specific feature
                const partialSupportMatch = PARTIAL_SUPPORT_ALLOWANCES.get(feature);
                // Check if partial support exists for the browser. // If no full supported version exists or if the partial supported version has a lower version number than the full supported one, use that one instead
                if (partialSupportMatch != null &&
                    (partialSupportMatch === "*" || partialSupportMatch.includes(browser)) &&
                    (fullSupportVersion == null || compareVersions(partialSupportVersion, fullSupportVersion) < 0)) {
                    versionToSet = partialSupportVersion;
                }
            }
            if (versionToSet == null) {
                // Apply additional checks depending on the comparison operator
                switch (comparisonOperator) {
                    case "<":
                    case "<=":
                        // Add all browsers with no support whatsoever, or those that require prefixing or flags
                        versionToSet = "-1";
                }
            }
            if (versionToSet != null) {
                browserMap.set(browser, versionToSet);
            }
        });
        browserMaps.push(browserMap);
    }
    // Now, remove all browsers that isn't part of all generated browser maps
    for (const browserMap of browserMaps) {
        for (const browser of browserMap.keys()) {
            if (!browserMaps.every(map => map.has(browser))) {
                // Delete the browser if it isn't included in all of the browser maps
                browserMap.delete(browser);
            }
        }
    }
    // Now, prepare a combined browser map
    const combinedBrowserMap = new Map();
    for (const browserMap of browserMaps) {
        for (const [browser, version] of browserMap.entries()) {
            // Take the existing entry from the combined map
            const existingVersion = combinedBrowserMap.get(browser);
            // The browser should be set in the map if it has no entry already
            const shouldSet = existingVersion !== "-1" && (existingVersion == null || version === "-1" || compareVersions(version, existingVersion) >= 0);
            if (shouldSet) {
                // Set the version in the map
                combinedBrowserMap.set(browser, version);
            }
        }
    }
    // Finally, generate a string array of the browsers
    // Make sure that 'not' expressions come last
    const query = [].concat
        .apply([], Array.from(combinedBrowserMap.entries()).map(([browser, version]) => {
        // The version is not a number, so we can't do comparisons on it.
        if (isNaN(parseFloat(version))) {
            switch (comparisonOperator) {
                case "<":
                case "<=": {
                    const previousVersion = getPreviousVersionOfBrowser(browser, version);
                    return [`not ${browser} ${version}`, ...(previousVersion == null ? [] : [`${browser} ${comparisonOperator} ${previousVersion}`])];
                }
                case ">":
                case ">=": {
                    const nextVersion = getNextVersionOfBrowser(browser, version);
                    return [`${browser} ${version}`, ...(nextVersion == null ? [] : [`${browser} ${comparisonOperator} ${nextVersion}`])];
                }
            }
        }
        return parseInt(version) === -1
            ? [
                `${comparisonOperator === ">" || comparisonOperator === ">=" ? "not " : ""}${browser} ${browser === "op_mini" ? "all" : "> 0"}`,
                `${comparisonOperator === ">" || comparisonOperator === ">=" ? "not " : ""}unreleased ${browser} versions`
            ]
            : [`${browser} ${comparisonOperator} ${version}`];
    }))
        .sort(sortBrowserslist);
    const returnObject = {
        query,
        browsers: new Set(combinedBrowserMap.keys())
    };
    // Store it in the cache before returning it
    browserSupportForFeaturesCache.set(cacheKey, returnObject);
    return returnObject;
}
/**
 * Gets the matching CaniuseBrowser for the given UseragentBrowser. Not all are supported, so it may return undefined
 */
function getCaniuseBrowserForUseragentBrowser(parser) {
    var _a, _b;
    const browser = parser.getBrowser();
    const device = parser.getDevice();
    const os = parser.getOS();
    const engine = parser.getEngine();
    // If the OS is iOS, it is actually Safari that drives the WebView
    if (os.name === "iOS") {
        // Opera Mini with the Presto runtime actually works around
        // the restrictions os the Safari WebView
        if (browser.name === "Opera Mini" && engine.name === "Presto") {
            return {
                browser: "op_mini",
                version: browser.version
            };
        }
        // In all other cases, it is always Safari driving the WebView
        return {
            browser: "ios_saf",
            version: (_a = os.version) !== null && _a !== void 0 ? _a : browser.version
        };
    }
    // First, if it is a Blackberry device, it will always be the 'bb' browser
    if (device.vendor === "BlackBerry" || os.name === "BlackBerry") {
        return {
            browser: "bb",
            version: browser.version
        };
    }
    // For platforms where the HeyTapBrowser doesn't report which Chrome version
    // it is based on, we'll have to rely on knowledge from similar user agent strings.
    // as far as we know, HeyTapBrowser on non-iOS is always based on Chrome 70 or 77,
    // seemingly at random. So we'll have to assume Chrome 70 here.
    if (browser.name === "HeyTapBrowser" && engine.name === "WebKit") {
        return {
            browser: "chrome",
            version: "70"
        };
    }
    // Unfortunately, since Caniuse doesn't support PaleMoon,
    // we will have to remap it to its closest equivalent Firefox
    // version (which it is similar to and a fork of).
    // This is less than ideal, but unfortunately a requirement for the time being
    if (browser.name === "PaleMoon" && engine.name === "Goanna" && browser.version != null) {
        const semver$1 = ensureSemver(undefined, browser.version);
        // The data comes from this table: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser)#Releases
        if (semver.lte(semver$1, "5.0.0")) {
            return {
                browser: "firefox",
                version: "2"
            };
        }
        // Between these two versions, the version numbers followed Firefox/Gecko
        else if (semver.lte(semver$1, "24.0.0")) {
            return {
                browser: "firefox",
                version: browser.version
            };
        }
        // It kept staying at Firefox 24 for all we know
        else if (semver.lt(semver$1, "27.0.0")) {
            return {
                browser: "firefox",
                version: "24.0.0"
            };
        }
        // Then, from v27, it was based on a re-fork of Firefox 38.
        // Unfortunately, we don't have fresh data as for the versions
        // in between 27 and 29, so we'll have to stay at version 38 in
        // this range
        else if (semver.lt(semver$1, "29.0.0")) {
            return {
                browser: "firefox",
                version: "38"
            };
        }
        // We know that v29 points to Firefox 68 in some of its user agents
        else {
            return {
                browser: "firefox",
                version: "68"
            };
        }
    }
    // For the MIUIBrowser, there are some rare instances for major versions 8 and 9 where they'll have no declared Chromium engine.
    // as part of the UA. Under these circumstances, we have to rely on knowledge gathered from scraping related User Agents
    // to determine the equivalent Chromium version
    if (browser.name === "MIUI Browser" && browser.version != null && os.name === "Android" && engine.name == null) {
        const semver = ensureSemver(undefined, browser.version);
        if (semver.major === 8 || semver.major === 9) {
            return {
                browser: "chrome",
                version: "53"
            };
        }
    }
    switch (browser.name) {
        case "Samsung Browser":
            if (browser.version != null) {
                return {
                    browser: "samsung",
                    version: browser.version
                };
            }
            else if (engine.name === "Blink" && engine.version != null) {
                return {
                    browser: "chrome",
                    version: engine.version
                };
            }
            else {
                break;
            }
        case "Android Browser": {
            // If the vendor is Samsung, the default browser is Samsung Internet
            if (device.vendor === "Samsung") {
                return {
                    browser: "samsung",
                    version: browser.version
                };
            }
            // Default to the stock android browser
            return {
                browser: "android",
                version: browser.version
            };
        }
        case "WebKit":
            // This will be the case if we're in an iOS Safari WebView
            if (device.type === "mobile" || device.type === "tablet" || device.type === "smarttv" || device.type === "wearable" || device.type === "embedded") {
                return {
                    browser: "ios_saf",
                    version: os.version
                };
            }
            // Otherwise, fall back to Safari
            return {
                browser: "safari",
                version: browser.version
            };
        case "Baidu":
            return {
                browser: "baidu",
                version: browser.version
            };
        case "Chrome Headless":
        case "Chrome WebView":
            return {
                browser: "chrome",
                version: browser.version
            };
        case "Facebook":
            // We've already asserted that this isn't iOS above, so we must be on Android and inside of a WebView
            return {
                browser: "chrome",
                version: browser.version
            };
        case "Chrome": {
            // Check if the OS is Android, in which case this is actually Chrome for Android. Make it report as regular Chrome
            if (os.name === "Android") {
                // Handle a special case on Android where the Chrome version
                // is actually the WebKit version, and it is actually the stock
                // Android browser.
                if (os.version != null && browser.version != null) {
                    const browserSemver = ensureSemver("chrome", browser.version);
                    const osSemver = ensureSemver(undefined, os.version);
                    if (semver.lte(osSemver, "4.4.4") && semver.gte(browserSemver, "400.0.0")) {
                        return {
                            browser: "android",
                            version: os.version
                        };
                    }
                }
                return {
                    browser: "chrome",
                    version: browser.version
                };
            }
            // Otherwise, fall back to chrome
            return {
                browser: "chrome",
                version: browser.version
            };
        }
        case "Edge": {
            // If the Engine is Blink, it's Chrome-based
            if (engine.name === "Blink") {
                // If there is no browser version, fall back to Chrome
                if (browser.version == null) {
                    return {
                        browser: "chrome",
                        version: engine.version
                    };
                }
                const semverVersion = ensureSemver("edge", browser.version);
                // If the Major version is in between 18 and 79, this will be Edge Mobile on Android,
                // which is Chromium based but has no related Caniuse browser name. Treat it as Chrome
                if (semverVersion.major > 18 && semverVersion.major < 79) {
                    return {
                        browser: "chrome",
                        version: engine.version
                    };
                }
            }
            return {
                browser: "edge",
                version: browser.version
            };
        }
        case "Firefox":
            // Check if the OS is Android, in which case this is actually Firefox for Android.
            if (os.name === "Android") {
                return {
                    browser: "and_ff",
                    version: browser.version
                };
            }
            // Default to Firefox
            return {
                browser: "firefox",
                version: browser.version
            };
        case "IE":
            return {
                browser: "ie",
                version: browser.version
            };
        case "IE Mobile":
        case "IEMobile":
            return {
                browser: "ie_mob",
                version: browser.version
            };
        case "Safari":
            // If no browser version is reported, and it is based on WebKit,
            // we will have to attempt to "guess" the Safari version with mapping the
            // WebKit version to an equivalent Safari version based on the data
            // here: https://en.wikipedia.org/wiki/Safari_version_history, even
            // though this doesn't seem to map correctly to real-world data
            if (browser.version == null && engine.name === "WebKit" && engine.version != null) {
                const semver$1 = ensureSemver(undefined, engine.version);
                if (semver.lt(semver$1, "412.0.0")) {
                    return {
                        browser: "safari",
                        version: "1.0"
                    };
                }
                if (semver.lt(semver$1, "522.0.0")) {
                    return {
                        browser: "safari",
                        version: "2.0"
                    };
                }
                if (semver.lt(semver$1, "526.0.0")) {
                    return {
                        browser: "safari",
                        version: "3.0"
                    };
                }
                if (semver.lt(semver$1, "533.0.0")) {
                    return {
                        browser: "safari",
                        version: "4.0"
                    };
                }
                if (semver.lt(semver$1, "536.0.0")) {
                    return {
                        browser: "safari",
                        version: "5.0"
                    };
                }
                if (semver.lt(semver$1, "537.71.0")) {
                    return {
                        browser: "safari",
                        version: "6.0"
                    };
                }
                if (semver.lt(semver$1, "600.0.0")) {
                    return {
                        browser: "safari",
                        version: "7.0"
                    };
                }
                if (semver.lt(semver$1, "601.0.0")) {
                    return {
                        browser: "safari",
                        version: "8.0"
                    };
                }
                if (semver.lt(semver$1, "602.0.0")) {
                    return {
                        browser: "safari",
                        version: "9.0"
                    };
                }
                if (semver.lt(semver$1, "604.0.0")) {
                    return {
                        browser: "safari",
                        version: "10.0"
                    };
                }
                if (semver.lt(semver$1, "606.0.0")) {
                    return {
                        browser: "safari",
                        version: "11.0"
                    };
                }
                if (semver.lt(semver$1, "608.0.0")) {
                    return {
                        browser: "safari",
                        version: "12.0"
                    };
                }
                if (semver.lt(semver$1, "610.0.0")) {
                    return {
                        browser: "safari",
                        version: "13.0"
                    };
                }
                // Else it is the current Safari version.
                // Keep this updated regularly
                return {
                    browser: "safari",
                    version: "14.0"
                };
            }
            return {
                browser: "safari",
                version: browser.version
            };
        case "Mobile Safari":
        case "MobileSafari":
        case "Safari Mobile":
        case "SafariMobile":
            return {
                browser: "ios_saf",
                version: (_b = os.version) !== null && _b !== void 0 ? _b : browser.version
            };
        case "Opera":
            return {
                browser: "opera",
                version: browser.version
            };
        case "Opera Mini":
            return {
                browser: "op_mini",
                version: browser.version
            };
        case "Opera Mobi":
            return {
                browser: "op_mob",
                version: browser.version
            };
        case "QQBrowser":
            return {
                browser: "and_qq",
                version: browser.version
            };
        case "UCBrowser":
            return {
                browser: "and_uc",
                version: browser.version
            };
        default:
            switch (engine.name) {
                // If the Engine is Blink, it's Chrome
                case "Blink":
                    return {
                        browser: "chrome",
                        version: engine.version
                    };
                case "WebKit":
                    return {
                        browser: "safari",
                        version: browser.version
                    };
                case "EdgeHTML":
                    return {
                        browser: "edge",
                        version: browser.version
                    };
                case "Gecko":
                    return {
                        browser: "firefox",
                        version: engine.version
                    };
                case "Presto":
                    return {
                        browser: "opera",
                        version: browser.version
                    };
            }
    }
    // Fall back to the unknown Caniuse browser when all
    // we received was the name of the OS
    if (browser.name == null && engine.name == null && device.type == null && os.name != null) {
        return UNKNOWN_CANIUSE_BROWSER;
    }
    return {};
}
/**
 * Normalizes the version of the browser such that it plays well with Caniuse
 */
function getCaniuseVersionForUseragentVersion({ browser, version }, useragentBrowser, useragentOs, useragentEngine) {
    var _a;
    // Always use 'all' with Opera Mini
    if (browser === "op_mini") {
        return "all";
    }
    else if (browser === "safari") {
        // Check if there is a newer version of the browser
        const nextBrowserVersion = getNextVersionOfBrowser(browser, version);
        // If there isn't we're in the Technology Preview
        if (nextBrowserVersion == null) {
            return "TP";
        }
    }
    const coerced = ensureSemver(browser, version);
    // Make sure that we have a proper Semver version to work with
    if (coerced == null)
        throw new TypeError(`Could not detect the version of: '${version}' for browser: ${browser}`);
    // Unpack the semver version
    const { major, minor, patch } = coerced;
    // Generates a Semver version
    const buildSemverVersion = (majorVersion, minorVersion, patchVersion) => `${majorVersion}${minorVersion == null || minorVersion === 0 ? "" : `.${minorVersion}`}${patchVersion == null || patchVersion === 0 ? "" : `.${patchVersion}`}`;
    switch (browser) {
        case "chrome":
            if (useragentEngine.name === "Blink") {
                return buildSemverVersion(ensureSemver(browser, getClosestMatchingBrowserVersion(browser, (_a = useragentEngine.version) !== null && _a !== void 0 ? _a : version)).major);
            }
            return buildSemverVersion(major);
        case "ie":
        case "ie_mob":
        case "edge":
        case "bb":
        case "and_chr":
        case "and_ff":
            // Always use the major version of these browser
            return buildSemverVersion(major);
        case "opera":
        case "op_mob":
            // Opera may have minor versions before it went to Chromium. After that, always use major versions
            if (major === 10 || major === 11 || major === 12) {
                return buildSemverVersion(major, minor);
            }
            // For anything else, only use the major version
            return buildSemverVersion(major);
        case "ios_saf": {
            // For browsers that report as iOS safari, they may actually be other browsers using Safari's WebView.
            // We want them to report as iOS safari since they will support the same browsers, but we have to apply
            // some tricks in order to get the version number
            // If it is in fact mobile Safari, just use the reported version
            if (useragentBrowser.name === "Safari" || useragentBrowser.name === "Mobile Safari") {
                // iOS may have minor releases, but never patch releases, according to caniuse
                return buildSemverVersion(major, minor);
            }
            // Otherwise, try to get the assumed Safari version from the OS version
            else {
                if (useragentOs.version == null)
                    throw new ReferenceError(`Could not detect OS version of iOS for ${useragentBrowser.name} on iOS`);
                // Decide the Semver version
                const osSemver = ensureSemver(undefined, getClosestMatchingBrowserVersion(browser, useragentOs.version));
                // iOS may have minor releases, but never patch releases, according to caniuse
                return buildSemverVersion(osSemver.major, osSemver.minor);
            }
        }
        case "safari":
        case "firefox": {
            // These may have minor releases, but never patch releases, according to caniuse
            return buildSemverVersion(major, minor);
        }
        case "android":
            // Up to version 4.4.4, these could include patch releases. After that, only use major versions
            if (major < 4) {
                return buildSemverVersion(major, minor);
            }
            else if (major === 4) {
                return buildSemverVersion(major, minor, patch);
            }
            else {
                return buildSemverVersion(major);
            }
        case "and_uc":
        case "samsung":
        case "and_qq":
        case "baidu":
            // These may always contain minor versions
            return buildSemverVersion(major, minor);
        default:
            // For anything else, just use the major version
            return buildSemverVersion(major);
    }
}
/**
 * Generates a browserslist from the provided useragent string
 */
function generateBrowserslistFromUseragent(useragent) {
    // Check if a user agent has been generated previously for this specific user agent
    const cacheHit = userAgentToBrowserslistCache.get(useragent);
    if (cacheHit != null)
        return cacheHit;
    // Otherwise, generate a new one
    const parser = new UaParserWrapper(useragent);
    const browser = parser.getBrowser();
    const os = parser.getOS();
    const engine = parser.getEngine();
    // Prepare a CaniuseBrowser name from the useragent string
    let { browser: caniuseBrowserName, version: caniuseBrowserVersion } = getCaniuseBrowserForUseragentBrowser(parser);
    // console.log({browser, os, engine, caniuseBrowserName, caniuseBrowserVersion});
    // If the browser name or version couldn't be determined, return false immediately
    if (caniuseBrowserName == null || caniuseBrowserVersion == null) {
        throw new TypeError(`No caniuse browser and/or version could be determined for User Agent: ${useragent}`);
    }
    caniuseBrowserVersion = normalizeBrowserVersion(caniuseBrowserName, caniuseBrowserVersion);
    const caniuseBrowser = { browser: caniuseBrowserName, version: caniuseBrowserVersion };
    // Prepare a version from the useragent that plays well with caniuse
    caniuseBrowserVersion = getCaniuseVersionForUseragentVersion(caniuseBrowser, browser, os, engine);
    // Prepare a browserslist from the useragent itself
    const normalizedBrowserslist = normalizeBrowserslist([`${caniuseBrowserName} ${caniuseBrowserVersion}`]);
    // Store it in the cache before returning it
    userAgentToBrowserslistCache.set(useragent, normalizedBrowserslist);
    return normalizedBrowserslist;
}
/**
 * Generates a browserslist from the provided useragent string and checks if it matches
 * the given browserslist
 */
function matchBrowserslistOnUserAgent(useragent, browserslist) {
    const useragentBrowserslist = generateBrowserslistFromUseragent(useragent);
    // Pipe the input browserslist through Browserslist to normalize it
    const normalizedInputBrowserslist = normalizeBrowserslist(browserslist);
    // Now, compare the two, and if the normalized input browserslist includes every option from the user agent, it is matched
    return useragentBrowserslist.every(option => normalizedInputBrowserslist.includes(option));
}
/**
 * Returns a key to use for the cache between user agents with feature names and whether or not the user agent supports them
 */
function userAgentWithFeaturesCacheKey(useragent, features) {
    return `${useragent}.${features.join(",")}`;
}
/**
 * Returns true if the given user agent supports the given features
 */
function userAgentSupportsFeatures(useragent, ...features) {
    // Check if these features has been computed previously for the given user agent
    const cacheKey = userAgentWithFeaturesCacheKey(useragent, features);
    const cacheHit = userAgentWithFeaturesToSupportCache.get(cacheKey);
    // If so, return the cache hit
    if (cacheHit != null)
        return cacheHit;
    // Prepare a browserslist from the useragent itself
    const useragentBrowserslist = generateBrowserslistFromUseragent(useragent);
    // Prepare a browserslist for browsers that support the given features
    const supportedBrowserslist = normalizeBrowserslist(browsersWithSupportForFeatures(...features));
    // Now, compare the two, and if the browserslist with supported browsers includes every option from the user agent, the user agent supports all of the given features
    const support = useragentBrowserslist.every(option => supportedBrowserslist.includes(option));
    // Set it in the cache and return it
    userAgentWithFeaturesToSupportCache.set(cacheKey, support);
    return support;
}

exports.browsersWithSupportForEcmaVersion = browsersWithSupportForEcmaVersion;
exports.browsersWithSupportForFeatures = browsersWithSupportForFeatures;
exports.browsersWithoutSupportForFeatures = browsersWithoutSupportForFeatures;
exports.browserslistSupportsEcmaVersion = browserslistSupportsEcmaVersion;
exports.browserslistSupportsFeatures = browserslistSupportsFeatures;
exports.generateBrowserslistFromUseragent = generateBrowserslistFromUseragent;
exports.getAppropriateEcmaVersionForBrowserslist = getAppropriateEcmaVersionForBrowserslist;
exports.getFirstVersionsWithFullSupport = getFirstVersionsWithFullSupport;
exports.matchBrowserslistOnUserAgent = matchBrowserslistOnUserAgent;
exports.normalizeBrowserslist = normalizeBrowserslist;
exports.userAgentSupportsFeatures = userAgentSupportsFeatures;
//# sourceMappingURL=index.js.map
