From b1e2c8fd5cb5dfa46bc440a12eafaf56cd844b1c Mon Sep 17 00:00:00 2001 From: Philipp Tanlak Date: Mon, 24 Nov 2025 20:54:57 +0100 Subject: Docs --- node_modules/browserslist/index.js | 1197 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1197 insertions(+) create mode 100644 node_modules/browserslist/index.js (limited to 'node_modules/browserslist/index.js') diff --git a/node_modules/browserslist/index.js b/node_modules/browserslist/index.js new file mode 100644 index 0000000..18021be --- /dev/null +++ b/node_modules/browserslist/index.js @@ -0,0 +1,1197 @@ +var jsReleases = require('node-releases/data/processed/envs.json') +var agents = require('caniuse-lite/dist/unpacker/agents').agents +var jsEOL = require('node-releases/data/release-schedule/release-schedule.json') +var path = require('path') +var e2c = require('electron-to-chromium/versions') + +var BrowserslistError = require('./error') +var parse = require('./parse') +var env = require('./node') // Will load browser.js in webpack + +var YEAR = 365.259641 * 24 * 60 * 60 * 1000 +var ANDROID_EVERGREEN_FIRST = '37' +var OP_MOB_BLINK_FIRST = 14 + +// Helpers + +function isVersionsMatch(versionA, versionB) { + return (versionA + '.').indexOf(versionB + '.') === 0 +} + +function isEolReleased(name) { + var version = name.slice(1) + return browserslist.nodeVersions.some(function (i) { + return isVersionsMatch(i, version) + }) +} + +function normalize(versions) { + return versions.filter(function (version) { + return typeof version === 'string' + }) +} + +function normalizeElectron(version) { + var versionToUse = version + if (version.split('.').length === 3) { + versionToUse = version.split('.').slice(0, -1).join('.') + } + return versionToUse +} + +function nameMapper(name) { + return function mapName(version) { + return name + ' ' + version + } +} + +function getMajor(version) { + return parseInt(version.split('.')[0]) +} + +function getMajorVersions(released, number) { + if (released.length === 0) return [] + var majorVersions = uniq(released.map(getMajor)) + var minimum = majorVersions[majorVersions.length - number] + if (!minimum) { + return released + } + var selected = [] + for (var i = released.length - 1; i >= 0; i--) { + if (minimum > getMajor(released[i])) break + selected.unshift(released[i]) + } + return selected +} + +function uniq(array) { + var filtered = [] + for (var i = 0; i < array.length; i++) { + if (filtered.indexOf(array[i]) === -1) filtered.push(array[i]) + } + return filtered +} + +function fillUsage(result, name, data) { + for (var i in data) { + result[name + ' ' + i] = data[i] + } +} + +function generateFilter(sign, version) { + version = parseFloat(version) + if (sign === '>') { + return function (v) { + return parseFloat(v) > version + } + } else if (sign === '>=') { + return function (v) { + return parseFloat(v) >= version + } + } else if (sign === '<') { + return function (v) { + return parseFloat(v) < version + } + } else { + return function (v) { + return parseFloat(v) <= version + } + } +} + +function generateSemverFilter(sign, version) { + version = version.split('.').map(parseSimpleInt) + version[1] = version[1] || 0 + version[2] = version[2] || 0 + if (sign === '>') { + return function (v) { + v = v.split('.').map(parseSimpleInt) + return compareSemver(v, version) > 0 + } + } else if (sign === '>=') { + return function (v) { + v = v.split('.').map(parseSimpleInt) + return compareSemver(v, version) >= 0 + } + } else if (sign === '<') { + return function (v) { + v = v.split('.').map(parseSimpleInt) + return compareSemver(version, v) > 0 + } + } else { + return function (v) { + v = v.split('.').map(parseSimpleInt) + return compareSemver(version, v) >= 0 + } + } +} + +function parseSimpleInt(x) { + return parseInt(x) +} + +function compare(a, b) { + if (a < b) return -1 + if (a > b) return +1 + return 0 +} + +function compareSemver(a, b) { + return ( + compare(parseInt(a[0]), parseInt(b[0])) || + compare(parseInt(a[1] || '0'), parseInt(b[1] || '0')) || + compare(parseInt(a[2] || '0'), parseInt(b[2] || '0')) + ) +} + +// this follows the npm-like semver behavior +function semverFilterLoose(operator, range) { + range = range.split('.').map(parseSimpleInt) + if (typeof range[1] === 'undefined') { + range[1] = 'x' + } + // ignore any patch version because we only return minor versions + // range[2] = 'x' + switch (operator) { + case '<=': + return function (version) { + version = version.split('.').map(parseSimpleInt) + return compareSemverLoose(version, range) <= 0 + } + case '>=': + default: + return function (version) { + version = version.split('.').map(parseSimpleInt) + return compareSemverLoose(version, range) >= 0 + } + } +} + +// this follows the npm-like semver behavior +function compareSemverLoose(version, range) { + if (version[0] !== range[0]) { + return version[0] < range[0] ? -1 : +1 + } + if (range[1] === 'x') { + return 0 + } + if (version[1] !== range[1]) { + return version[1] < range[1] ? -1 : +1 + } + return 0 +} + +function resolveVersion(data, version) { + if (data.versions.indexOf(version) !== -1) { + return version + } else if (browserslist.versionAliases[data.name][version]) { + return browserslist.versionAliases[data.name][version] + } else { + return false + } +} + +function normalizeVersion(data, version) { + var resolved = resolveVersion(data, version) + if (resolved) { + return resolved + } else if (data.versions.length === 1) { + return data.versions[0] + } else { + return false + } +} + +function filterByYear(since, context) { + since = since / 1000 + return Object.keys(agents).reduce(function (selected, name) { + var data = byName(name, context) + if (!data) return selected + var versions = Object.keys(data.releaseDate).filter(function (v) { + var date = data.releaseDate[v] + return date !== null && date >= since + }) + return selected.concat(versions.map(nameMapper(data.name))) + }, []) +} + +function cloneData(data) { + return { + name: data.name, + versions: data.versions, + released: data.released, + releaseDate: data.releaseDate + } +} + +function byName(name, context) { + name = name.toLowerCase() + name = browserslist.aliases[name] || name + if (context.mobileToDesktop && browserslist.desktopNames[name]) { + var desktop = browserslist.data[browserslist.desktopNames[name]] + if (name === 'android') { + return normalizeAndroidData(cloneData(browserslist.data[name]), desktop) + } else { + var cloned = cloneData(desktop) + cloned.name = name + return cloned + } + } + return browserslist.data[name] +} + +function normalizeAndroidVersions(androidVersions, chromeVersions) { + var iFirstEvergreen = chromeVersions.indexOf(ANDROID_EVERGREEN_FIRST) + return androidVersions + .filter(function (version) { + return /^(?:[2-4]\.|[34]$)/.test(version) + }) + .concat(chromeVersions.slice(iFirstEvergreen)) +} + +function normalizeAndroidData(android, chrome) { + android.released = normalizeAndroidVersions(android.released, chrome.released) + android.versions = normalizeAndroidVersions(android.versions, chrome.versions) + android.released.forEach(function (v) { + if (android.releaseDate[v] === undefined) { + android.releaseDate[v] = chrome.releaseDate[v] + } + }) + return android +} + +function checkName(name, context) { + var data = byName(name, context) + if (!data) throw new BrowserslistError('Unknown browser ' + name) + return data +} + +function unknownQuery(query) { + return new BrowserslistError( + 'Unknown browser query `' + + query + + '`. ' + + 'Maybe you are using old Browserslist or made typo in query.' + ) +} + +// Adjusts last X versions queries for some mobile browsers, +// where caniuse data jumps from a legacy version to the latest +function filterJumps(list, name, nVersions, context) { + var jump = 1 + switch (name) { + case 'android': + if (context.mobileToDesktop) return list + var released = browserslist.data.chrome.released + jump = released.length - released.indexOf(ANDROID_EVERGREEN_FIRST) + break + case 'op_mob': + var latest = browserslist.data.op_mob.released.slice(-1)[0] + jump = getMajor(latest) - OP_MOB_BLINK_FIRST + 1 + break + default: + return list + } + if (nVersions <= jump) { + return list.slice(-1) + } + return list.slice(jump - 1 - nVersions) +} + +function isSupported(flags, withPartial) { + return ( + typeof flags === 'string' && + (flags.indexOf('y') >= 0 || (withPartial && flags.indexOf('a') >= 0)) + ) +} + +function resolve(queries, context) { + return parse(QUERIES, queries).reduce(function (result, node, index) { + if (node.not && index === 0) { + throw new BrowserslistError( + 'Write any browsers query (for instance, `defaults`) ' + + 'before `' + + node.query + + '`' + ) + } + var type = QUERIES[node.type] + var array = type.select.call(browserslist, context, node).map(function (j) { + var parts = j.split(' ') + if (parts[1] === '0') { + return parts[0] + ' ' + byName(parts[0], context).versions[0] + } else { + return j + } + }) + + if (node.compose === 'and') { + if (node.not) { + return result.filter(function (j) { + return array.indexOf(j) === -1 + }) + } else { + return result.filter(function (j) { + return array.indexOf(j) !== -1 + }) + } + } else { + if (node.not) { + var filter = {} + array.forEach(function (j) { + filter[j] = true + }) + return result.filter(function (j) { + return !filter[j] + }) + } + return result.concat(array) + } + }, []) +} + +function prepareOpts(opts) { + if (typeof opts === 'undefined') opts = {} + + if (typeof opts.path === 'undefined') { + opts.path = path.resolve ? path.resolve('.') : '.' + } + + return opts +} + +function prepareQueries(queries, opts) { + if (typeof queries === 'undefined' || queries === null) { + var config = browserslist.loadConfig(opts) + if (config) { + queries = config + } else { + queries = browserslist.defaults + } + } + + return queries +} + +function checkQueries(queries) { + if (!(typeof queries === 'string' || Array.isArray(queries))) { + throw new BrowserslistError( + 'Browser queries must be an array or string. Got ' + typeof queries + '.' + ) + } +} + +var cache = {} + +function browserslist(queries, opts) { + opts = prepareOpts(opts) + queries = prepareQueries(queries, opts) + checkQueries(queries) + + var context = { + ignoreUnknownVersions: opts.ignoreUnknownVersions, + dangerousExtend: opts.dangerousExtend, + mobileToDesktop: opts.mobileToDesktop, + path: opts.path, + env: opts.env + } + + env.oldDataWarning(browserslist.data) + var stats = env.getStat(opts, browserslist.data) + if (stats) { + context.customUsage = {} + for (var browser in stats) { + fillUsage(context.customUsage, browser, stats[browser]) + } + } + + var cacheKey = JSON.stringify([queries, context]) + if (cache[cacheKey]) return cache[cacheKey] + + var result = uniq(resolve(queries, context)).sort(function (name1, name2) { + name1 = name1.split(' ') + name2 = name2.split(' ') + if (name1[0] === name2[0]) { + // assumptions on caniuse data + // 1) version ranges never overlaps + // 2) if version is not a range, it never contains `-` + var version1 = name1[1].split('-')[0] + var version2 = name2[1].split('-')[0] + return compareSemver(version2.split('.'), version1.split('.')) + } else { + return compare(name1[0], name2[0]) + } + }) + if (!env.env.BROWSERSLIST_DISABLE_CACHE) { + cache[cacheKey] = result + } + return result +} + +browserslist.parse = function (queries, opts) { + opts = prepareOpts(opts) + queries = prepareQueries(queries, opts) + checkQueries(queries) + return parse(QUERIES, queries) +} + +// Will be filled by Can I Use data below +browserslist.cache = {} +browserslist.data = {} +browserslist.usage = { + global: {}, + custom: null +} + +// Default browsers query +browserslist.defaults = ['> 0.5%', 'last 2 versions', 'Firefox ESR', 'not dead'] + +// Browser names aliases +browserslist.aliases = { + fx: 'firefox', + ff: 'firefox', + ios: 'ios_saf', + explorer: 'ie', + blackberry: 'bb', + explorermobile: 'ie_mob', + operamini: 'op_mini', + operamobile: 'op_mob', + chromeandroid: 'and_chr', + firefoxandroid: 'and_ff', + ucandroid: 'and_uc', + qqandroid: 'and_qq' +} + +// Can I Use only provides a few versions for some browsers (e.g. and_chr). +// Fallback to a similar browser for unknown versions +// Note op_mob is not included as its chromium versions are not in sync with Opera desktop +browserslist.desktopNames = { + and_chr: 'chrome', + and_ff: 'firefox', + ie_mob: 'ie', + android: 'chrome' // has extra processing logic +} + +// Aliases to work with joined versions like `ios_saf 7.0-7.1` +browserslist.versionAliases = {} + +browserslist.clearCaches = env.clearCaches +browserslist.parseConfig = env.parseConfig +browserslist.readConfig = env.readConfig +browserslist.findConfig = env.findConfig +browserslist.loadConfig = env.loadConfig + +browserslist.coverage = function (browsers, stats) { + var data + if (typeof stats === 'undefined') { + data = browserslist.usage.global + } else if (stats === 'my stats') { + var opts = {} + opts.path = path.resolve ? path.resolve('.') : '.' + var customStats = env.getStat(opts) + if (!customStats) { + throw new BrowserslistError('Custom usage statistics was not provided') + } + data = {} + for (var browser in customStats) { + fillUsage(data, browser, customStats[browser]) + } + } else if (typeof stats === 'string') { + if (stats.length > 2) { + stats = stats.toLowerCase() + } else { + stats = stats.toUpperCase() + } + env.loadCountry(browserslist.usage, stats, browserslist.data) + data = browserslist.usage[stats] + } else { + if ('dataByBrowser' in stats) { + stats = stats.dataByBrowser + } + data = {} + for (var name in stats) { + for (var version in stats[name]) { + data[name + ' ' + version] = stats[name][version] + } + } + } + + return browsers.reduce(function (all, i) { + var usage = data[i] + if (usage === undefined) { + usage = data[i.replace(/ \S+$/, ' 0')] + } + return all + (usage || 0) + }, 0) +} + +function nodeQuery(context, node) { + var matched = browserslist.nodeVersions.filter(function (i) { + return isVersionsMatch(i, node.version) + }) + if (matched.length === 0) { + if (context.ignoreUnknownVersions) { + return [] + } else { + throw new BrowserslistError( + 'Unknown version ' + node.version + ' of Node.js' + ) + } + } + return ['node ' + matched[matched.length - 1]] +} + +function sinceQuery(context, node) { + var year = parseInt(node.year) + var month = parseInt(node.month || '01') - 1 + var day = parseInt(node.day || '01') + return filterByYear(Date.UTC(year, month, day, 0, 0, 0), context) +} + +function coverQuery(context, node) { + var coverage = parseFloat(node.coverage) + var usage = browserslist.usage.global + if (node.place) { + if (node.place.match(/^my\s+stats$/i)) { + if (!context.customUsage) { + throw new BrowserslistError('Custom usage statistics was not provided') + } + usage = context.customUsage + } else { + var place + if (node.place.length === 2) { + place = node.place.toUpperCase() + } else { + place = node.place.toLowerCase() + } + env.loadCountry(browserslist.usage, place, browserslist.data) + usage = browserslist.usage[place] + } + } + var versions = Object.keys(usage).sort(function (a, b) { + return usage[b] - usage[a] + }) + var coveraged = 0 + var result = [] + var version + for (var i = 0; i < versions.length; i++) { + version = versions[i] + if (usage[version] === 0) break + coveraged += usage[version] + result.push(version) + if (coveraged >= coverage) break + } + return result +} + +var QUERIES = { + last_major_versions: { + matches: ['versions'], + regexp: /^last\s+(\d+)\s+major\s+versions?$/i, + select: function (context, node) { + return Object.keys(agents).reduce(function (selected, name) { + var data = byName(name, context) + if (!data) return selected + var list = getMajorVersions(data.released, node.versions) + list = list.map(nameMapper(data.name)) + list = filterJumps(list, data.name, node.versions, context) + return selected.concat(list) + }, []) + } + }, + last_versions: { + matches: ['versions'], + regexp: /^last\s+(\d+)\s+versions?$/i, + select: function (context, node) { + return Object.keys(agents).reduce(function (selected, name) { + var data = byName(name, context) + if (!data) return selected + var list = data.released.slice(-node.versions) + list = list.map(nameMapper(data.name)) + list = filterJumps(list, data.name, node.versions, context) + return selected.concat(list) + }, []) + } + }, + last_electron_major_versions: { + matches: ['versions'], + regexp: /^last\s+(\d+)\s+electron\s+major\s+versions?$/i, + select: function (context, node) { + var validVersions = getMajorVersions(Object.keys(e2c), node.versions) + return validVersions.map(function (i) { + return 'chrome ' + e2c[i] + }) + } + }, + last_node_major_versions: { + matches: ['versions'], + regexp: /^last\s+(\d+)\s+node\s+major\s+versions?$/i, + select: function (context, node) { + return getMajorVersions(browserslist.nodeVersions, node.versions).map( + function (version) { + return 'node ' + version + } + ) + } + }, + last_browser_major_versions: { + matches: ['versions', 'browser'], + regexp: /^last\s+(\d+)\s+(\w+)\s+major\s+versions?$/i, + select: function (context, node) { + var data = checkName(node.browser, context) + var validVersions = getMajorVersions(data.released, node.versions) + var list = validVersions.map(nameMapper(data.name)) + list = filterJumps(list, data.name, node.versions, context) + return list + } + }, + last_electron_versions: { + matches: ['versions'], + regexp: /^last\s+(\d+)\s+electron\s+versions?$/i, + select: function (context, node) { + return Object.keys(e2c) + .slice(-node.versions) + .map(function (i) { + return 'chrome ' + e2c[i] + }) + } + }, + last_node_versions: { + matches: ['versions'], + regexp: /^last\s+(\d+)\s+node\s+versions?$/i, + select: function (context, node) { + return browserslist.nodeVersions + .slice(-node.versions) + .map(function (version) { + return 'node ' + version + }) + } + }, + last_browser_versions: { + matches: ['versions', 'browser'], + regexp: /^last\s+(\d+)\s+(\w+)\s+versions?$/i, + select: function (context, node) { + var data = checkName(node.browser, context) + var list = data.released.slice(-node.versions).map(nameMapper(data.name)) + list = filterJumps(list, data.name, node.versions, context) + return list + } + }, + unreleased_versions: { + matches: [], + regexp: /^unreleased\s+versions$/i, + select: function (context) { + return Object.keys(agents).reduce(function (selected, name) { + var data = byName(name, context) + if (!data) return selected + var list = data.versions.filter(function (v) { + return data.released.indexOf(v) === -1 + }) + list = list.map(nameMapper(data.name)) + return selected.concat(list) + }, []) + } + }, + unreleased_electron_versions: { + matches: [], + regexp: /^unreleased\s+electron\s+versions?$/i, + select: function () { + return [] + } + }, + unreleased_browser_versions: { + matches: ['browser'], + regexp: /^unreleased\s+(\w+)\s+versions?$/i, + select: function (context, node) { + var data = checkName(node.browser, context) + return data.versions + .filter(function (v) { + return data.released.indexOf(v) === -1 + }) + .map(nameMapper(data.name)) + } + }, + last_years: { + matches: ['years'], + regexp: /^last\s+(\d*.?\d+)\s+years?$/i, + select: function (context, node) { + return filterByYear(Date.now() - YEAR * node.years, context) + } + }, + since_y: { + matches: ['year'], + regexp: /^since (\d+)$/i, + select: sinceQuery + }, + since_y_m: { + matches: ['year', 'month'], + regexp: /^since (\d+)-(\d+)$/i, + select: sinceQuery + }, + since_y_m_d: { + matches: ['year', 'month', 'day'], + regexp: /^since (\d+)-(\d+)-(\d+)$/i, + select: sinceQuery + }, + popularity: { + matches: ['sign', 'popularity'], + regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%$/, + select: function (context, node) { + var popularity = parseFloat(node.popularity) + var usage = browserslist.usage.global + return Object.keys(usage).reduce(function (result, version) { + if (node.sign === '>') { + if (usage[version] > popularity) { + result.push(version) + } + } else if (node.sign === '<') { + if (usage[version] < popularity) { + result.push(version) + } + } else if (node.sign === '<=') { + if (usage[version] <= popularity) { + result.push(version) + } + } else if (usage[version] >= popularity) { + result.push(version) + } + return result + }, []) + } + }, + popularity_in_my_stats: { + matches: ['sign', 'popularity'], + regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+my\s+stats$/, + select: function (context, node) { + var popularity = parseFloat(node.popularity) + if (!context.customUsage) { + throw new BrowserslistError('Custom usage statistics was not provided') + } + var usage = context.customUsage + return Object.keys(usage).reduce(function (result, version) { + var percentage = usage[version] + if (percentage == null) { + return result + } + + if (node.sign === '>') { + if (percentage > popularity) { + result.push(version) + } + } else if (node.sign === '<') { + if (percentage < popularity) { + result.push(version) + } + } else if (node.sign === '<=') { + if (percentage <= popularity) { + result.push(version) + } + } else if (percentage >= popularity) { + result.push(version) + } + return result + }, []) + } + }, + popularity_in_config_stats: { + matches: ['sign', 'popularity', 'config'], + regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+(\S+)\s+stats$/, + select: function (context, node) { + var popularity = parseFloat(node.popularity) + var stats = env.loadStat(context, node.config, browserslist.data) + if (stats) { + context.customUsage = {} + for (var browser in stats) { + fillUsage(context.customUsage, browser, stats[browser]) + } + } + if (!context.customUsage) { + throw new BrowserslistError('Custom usage statistics was not provided') + } + var usage = context.customUsage + return Object.keys(usage).reduce(function (result, version) { + var percentage = usage[version] + if (percentage == null) { + return result + } + + if (node.sign === '>') { + if (percentage > popularity) { + result.push(version) + } + } else if (node.sign === '<') { + if (percentage < popularity) { + result.push(version) + } + } else if (node.sign === '<=') { + if (percentage <= popularity) { + result.push(version) + } + } else if (percentage >= popularity) { + result.push(version) + } + return result + }, []) + } + }, + popularity_in_place: { + matches: ['sign', 'popularity', 'place'], + regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+((alt-)?\w\w)$/, + select: function (context, node) { + var popularity = parseFloat(node.popularity) + var place = node.place + if (place.length === 2) { + place = place.toUpperCase() + } else { + place = place.toLowerCase() + } + env.loadCountry(browserslist.usage, place, browserslist.data) + var usage = browserslist.usage[place] + return Object.keys(usage).reduce(function (result, version) { + var percentage = usage[version] + if (percentage == null) { + return result + } + + if (node.sign === '>') { + if (percentage > popularity) { + result.push(version) + } + } else if (node.sign === '<') { + if (percentage < popularity) { + result.push(version) + } + } else if (node.sign === '<=') { + if (percentage <= popularity) { + result.push(version) + } + } else if (percentage >= popularity) { + result.push(version) + } + return result + }, []) + } + }, + cover: { + matches: ['coverage'], + regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%$/i, + select: coverQuery + }, + cover_in: { + matches: ['coverage', 'place'], + regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%\s+in\s+(my\s+stats|(alt-)?\w\w)$/i, + select: coverQuery + }, + supports: { + matches: ['supportType', 'feature'], + regexp: /^(?:(fully|partially) )?supports\s+([\w-]+)$/, + select: function (context, node) { + env.loadFeature(browserslist.cache, node.feature) + var withPartial = node.supportType !== 'fully' + var features = browserslist.cache[node.feature] + var result = [] + for (var name in features) { + var data = byName(name, context) + // Only check desktop when latest released mobile has support + var checkDesktop = + context.mobileToDesktop && + name in browserslist.desktopNames && + isSupported(features[name][data.released.slice(-1)[0]], withPartial) + data.versions.forEach(function (version) { + var flags = features[name][version] + if (flags === undefined && checkDesktop) { + flags = features[browserslist.desktopNames[name]][version] + } + if (isSupported(flags, withPartial)) { + result.push(name + ' ' + version) + } + }) + } + return result + } + }, + electron_range: { + matches: ['from', 'to'], + regexp: /^electron\s+([\d.]+)\s*-\s*([\d.]+)$/i, + select: function (context, node) { + var fromToUse = normalizeElectron(node.from) + var toToUse = normalizeElectron(node.to) + var from = parseFloat(node.from) + var to = parseFloat(node.to) + if (!e2c[fromToUse]) { + throw new BrowserslistError('Unknown version ' + from + ' of electron') + } + if (!e2c[toToUse]) { + throw new BrowserslistError('Unknown version ' + to + ' of electron') + } + return Object.keys(e2c) + .filter(function (i) { + var parsed = parseFloat(i) + return parsed >= from && parsed <= to + }) + .map(function (i) { + return 'chrome ' + e2c[i] + }) + } + }, + node_range: { + matches: ['from', 'to'], + regexp: /^node\s+([\d.]+)\s*-\s*([\d.]+)$/i, + select: function (context, node) { + return browserslist.nodeVersions + .filter(semverFilterLoose('>=', node.from)) + .filter(semverFilterLoose('<=', node.to)) + .map(function (v) { + return 'node ' + v + }) + } + }, + browser_range: { + matches: ['browser', 'from', 'to'], + regexp: /^(\w+)\s+([\d.]+)\s*-\s*([\d.]+)$/i, + select: function (context, node) { + var data = checkName(node.browser, context) + var from = parseFloat(normalizeVersion(data, node.from) || node.from) + var to = parseFloat(normalizeVersion(data, node.to) || node.to) + function filter(v) { + var parsed = parseFloat(v) + return parsed >= from && parsed <= to + } + return data.released.filter(filter).map(nameMapper(data.name)) + } + }, + electron_ray: { + matches: ['sign', 'version'], + regexp: /^electron\s*(>=?|<=?)\s*([\d.]+)$/i, + select: function (context, node) { + var versionToUse = normalizeElectron(node.version) + return Object.keys(e2c) + .filter(generateFilter(node.sign, versionToUse)) + .map(function (i) { + return 'chrome ' + e2c[i] + }) + } + }, + node_ray: { + matches: ['sign', 'version'], + regexp: /^node\s*(>=?|<=?)\s*([\d.]+)$/i, + select: function (context, node) { + return browserslist.nodeVersions + .filter(generateSemverFilter(node.sign, node.version)) + .map(function (v) { + return 'node ' + v + }) + } + }, + browser_ray: { + matches: ['browser', 'sign', 'version'], + regexp: /^(\w+)\s*(>=?|<=?)\s*([\d.]+)$/, + select: function (context, node) { + var version = node.version + var data = checkName(node.browser, context) + var alias = browserslist.versionAliases[data.name][version] + if (alias) version = alias + return data.released + .filter(generateFilter(node.sign, version)) + .map(function (v) { + return data.name + ' ' + v + }) + } + }, + firefox_esr: { + matches: [], + regexp: /^(firefox|ff|fx)\s+esr$/i, + select: function () { + return ['firefox 115'] + } + }, + opera_mini_all: { + matches: [], + regexp: /(operamini|op_mini)\s+all/i, + select: function () { + return ['op_mini all'] + } + }, + electron_version: { + matches: ['version'], + regexp: /^electron\s+([\d.]+)$/i, + select: function (context, node) { + var versionToUse = normalizeElectron(node.version) + var chrome = e2c[versionToUse] + if (!chrome) { + throw new BrowserslistError( + 'Unknown version ' + node.version + ' of electron' + ) + } + return ['chrome ' + chrome] + } + }, + node_major_version: { + matches: ['version'], + regexp: /^node\s+(\d+)$/i, + select: nodeQuery + }, + node_minor_version: { + matches: ['version'], + regexp: /^node\s+(\d+\.\d+)$/i, + select: nodeQuery + }, + node_patch_version: { + matches: ['version'], + regexp: /^node\s+(\d+\.\d+\.\d+)$/i, + select: nodeQuery + }, + current_node: { + matches: [], + regexp: /^current\s+node$/i, + select: function (context) { + return [env.currentNode(resolve, context)] + } + }, + maintained_node: { + matches: [], + regexp: /^maintained\s+node\s+versions$/i, + select: function (context) { + var now = Date.now() + var queries = Object.keys(jsEOL) + .filter(function (key) { + return ( + now < Date.parse(jsEOL[key].end) && + now > Date.parse(jsEOL[key].start) && + isEolReleased(key) + ) + }) + .map(function (key) { + return 'node ' + key.slice(1) + }) + return resolve(queries, context) + } + }, + phantomjs_1_9: { + matches: [], + regexp: /^phantomjs\s+1.9$/i, + select: function () { + return ['safari 5'] + } + }, + phantomjs_2_1: { + matches: [], + regexp: /^phantomjs\s+2.1$/i, + select: function () { + return ['safari 6'] + } + }, + browser_version: { + matches: ['browser', 'version'], + regexp: /^(\w+)\s+(tp|[\d.]+)$/i, + select: function (context, node) { + var version = node.version + if (/^tp$/i.test(version)) version = 'TP' + var data = checkName(node.browser, context) + var alias = normalizeVersion(data, version) + if (alias) { + version = alias + } else { + if (version.indexOf('.') === -1) { + alias = version + '.0' + } else { + alias = version.replace(/\.0$/, '') + } + alias = normalizeVersion(data, alias) + if (alias) { + version = alias + } else if (context.ignoreUnknownVersions) { + return [] + } else { + throw new BrowserslistError( + 'Unknown version ' + version + ' of ' + node.browser + ) + } + } + return [data.name + ' ' + version] + } + }, + browserslist_config: { + matches: [], + regexp: /^browserslist config$/i, + select: function (context) { + return browserslist(undefined, context) + } + }, + extends: { + matches: ['config'], + regexp: /^extends (.+)$/i, + select: function (context, node) { + return resolve(env.loadQueries(context, node.config), context) + } + }, + defaults: { + matches: [], + regexp: /^defaults$/i, + select: function (context) { + return resolve(browserslist.defaults, context) + } + }, + dead: { + matches: [], + regexp: /^dead$/i, + select: function (context) { + var dead = [ + 'Baidu >= 0', + 'ie <= 11', + 'ie_mob <= 11', + 'bb <= 10', + 'op_mob <= 12.1', + 'samsung 4' + ] + return resolve(dead, context) + } + }, + unknown: { + matches: [], + regexp: /^(\w+)$/i, + select: function (context, node) { + if (byName(node.query, context)) { + throw new BrowserslistError( + 'Specify versions in Browserslist query for browser ' + node.query + ) + } else { + throw unknownQuery(node.query) + } + } + } +} + +// Get and convert Can I Use data + +;(function () { + for (var name in agents) { + var browser = agents[name] + browserslist.data[name] = { + name: name, + versions: normalize(agents[name].versions), + released: normalize(agents[name].versions.slice(0, -3)), + releaseDate: agents[name].release_date + } + fillUsage(browserslist.usage.global, name, browser.usage_global) + + browserslist.versionAliases[name] = {} + for (var i = 0; i < browser.versions.length; i++) { + var full = browser.versions[i] + if (!full) continue + + if (full.indexOf('-') !== -1) { + var interval = full.split('-') + for (var j = 0; j < interval.length; j++) { + browserslist.versionAliases[name][interval[j]] = full + } + } + } + } + + browserslist.nodeVersions = jsReleases.map(function (release) { + return release.version + }) +})() + +module.exports = browserslist -- cgit v1.2.3