AK-21/Graphite-Industrial-Intelligence
0
1var bbm = require('baseline-browser-mapping')2var jsReleases = require('node-releases/data/processed/envs.json')3var agents = require('caniuse-lite/dist/unpacker/agents').agents4var e2c = require('electron-to-chromium/versions')5var jsEOL = require('node-releases/data/release-schedule/release-schedule.json')6var path = require('path')7 8var BrowserslistError = require('./error')9var env = require('./node')10var parseWithoutCache = require('./parse') // Will load browser.js in webpack11 12var YEAR = 365.259641 * 24 * 60 * 60 * 100013var ANDROID_EVERGREEN_FIRST = '37'14var OP_MOB_BLINK_FIRST = 1415var FIREFOX_ESR_VERSION = '140'16 17// Helpers18 19function isVersionsMatch(versionA, versionB) {20 return (versionA + '.').indexOf(versionB + '.') === 021}22 23function isEolReleased(name) {24 var version = name.slice(1)25 return browserslist.nodeVersions.some(function (i) {26 return isVersionsMatch(i, version)27 })28}29 30function normalize(versions) {31 return versions.filter(function (version) {32 return typeof version === 'string'33 })34}35 36function normalizeElectron(version) {37 var versionToUse = version38 if (version.split('.').length === 3) {39 versionToUse = version.split('.').slice(0, -1).join('.')40 }41 return versionToUse42}43 44function nameMapper(name) {45 return function mapName(version) {46 return name + ' ' + version47 }48}49 50function getMajor(version) {51 return parseInt(version.split('.')[0])52}53 54function getMajorVersions(released, number) {55 if (released.length === 0) return []56 var majorVersions = uniq(released.map(getMajor))57 var minimum = majorVersions[majorVersions.length - number]58 if (!minimum) {59 return released60 }61 var selected = []62 for (var i = released.length - 1; i >= 0; i--) {63 if (minimum > getMajor(released[i])) break64 selected.unshift(released[i])65 }66 return selected67}68 69function uniq(array) {70 var filtered = []71 for (var i = 0; i < array.length; i++) {72 if (filtered.indexOf(array[i]) === -1) filtered.push(array[i])73 }74 return filtered75}76 77function fillUsage(result, name, data) {78 for (var i in data) {79 result[name + ' ' + i] = data[i]80 }81}82 83function generateFilter(sign, version) {84 version = parseFloat(version)85 if (sign === '>') {86 return function (v) {87 return parseLatestFloat(v) > version88 }89 } else if (sign === '>=') {90 return function (v) {91 return parseLatestFloat(v) >= version92 }93 } else if (sign === '<') {94 return function (v) {95 return parseFloat(v) < version96 }97 } else {98 return function (v) {99 return parseFloat(v) <= version100 }101 }102 103 function parseLatestFloat(v) {104 return parseFloat(v.split('-')[1] || v)105 }106}107 108function generateSemverFilter(sign, version) {109 version = version.split('.').map(parseSimpleInt)110 version[1] = version[1] || 0111 version[2] = version[2] || 0112 if (sign === '>') {113 return function (v) {114 v = v.split('.').map(parseSimpleInt)115 return compareSemver(v, version) > 0116 }117 } else if (sign === '>=') {118 return function (v) {119 v = v.split('.').map(parseSimpleInt)120 return compareSemver(v, version) >= 0121 }122 } else if (sign === '<') {123 return function (v) {124 v = v.split('.').map(parseSimpleInt)125 return compareSemver(version, v) > 0126 }127 } else {128 return function (v) {129 v = v.split('.').map(parseSimpleInt)130 return compareSemver(version, v) >= 0131 }132 }133}134 135function parseSimpleInt(x) {136 return parseInt(x)137}138 139function compare(a, b) {140 if (a < b) return -1141 if (a > b) return +1142 return 0143}144 145function compareSemver(a, b) {146 return (147 compare(parseInt(a[0]), parseInt(b[0])) ||148 compare(parseInt(a[1] || '0'), parseInt(b[1] || '0')) ||149 compare(parseInt(a[2] || '0'), parseInt(b[2] || '0'))150 )151}152 153// this follows the npm-like semver behavior154function semverFilterLoose(operator, range) {155 range = range.split('.').map(parseSimpleInt)156 if (typeof range[1] === 'undefined') {157 range[1] = 'x'158 }159 // ignore any patch version because we only return minor versions160 // range[2] = 'x'161 switch (operator) {162 case '<=':163 return function (version) {164 version = version.split('.').map(parseSimpleInt)165 return compareSemverLoose(version, range) <= 0166 }167 case '>=':168 default:169 return function (version) {170 version = version.split('.').map(parseSimpleInt)171 return compareSemverLoose(version, range) >= 0172 }173 }174}175 176// this follows the npm-like semver behavior177function compareSemverLoose(version, range) {178 if (version[0] !== range[0]) {179 return version[0] < range[0] ? -1 : +1180 }181 if (range[1] === 'x') {182 return 0183 }184 if (version[1] !== range[1]) {185 return version[1] < range[1] ? -1 : +1186 }187 return 0188}189 190function resolveVersion(data, version) {191 if (data.versions.indexOf(version) !== -1) {192 return version193 } else if (browserslist.versionAliases[data.name][version]) {194 return browserslist.versionAliases[data.name][version]195 } else {196 return false197 }198}199 200function normalizeVersion(data, version) {201 var resolved = resolveVersion(data, version)202 if (resolved) {203 return resolved204 } else if (data.versions.length === 1) {205 return data.versions[0]206 } else {207 return false208 }209}210 211function filterByYear(since, context) {212 since = since / 1000213 return Object.keys(agents).reduce(function (selected, name) {214 var data = byName(name, context)215 if (!data) return selected216 var versions = Object.keys(data.releaseDate).filter(function (v) {217 var date = data.releaseDate[v]218 return date !== null && date >= since219 })220 return selected.concat(versions.map(nameMapper(data.name)))221 }, [])222}223 224function cloneData(data) {225 return {226 name: data.name,227 versions: data.versions,228 released: data.released,229 releaseDate: data.releaseDate230 }231}232 233function byName(name, context) {234 name = name.toLowerCase()235 name = browserslist.aliases[name] || name236 if (context.mobileToDesktop && browserslist.desktopNames[name]) {237 var desktop = browserslist.data[browserslist.desktopNames[name]]238 if (name === 'android') {239 return normalizeAndroidData(cloneData(browserslist.data[name]), desktop)240 } else {241 var cloned = cloneData(desktop)242 cloned.name = name243 return cloned244 }245 }246 return browserslist.data[name]247}248 249function normalizeAndroidVersions(androidVersions, chromeVersions) {250 var iFirstEvergreen = chromeVersions.indexOf(ANDROID_EVERGREEN_FIRST)251 return androidVersions252 .filter(function (version) {253 return /^(?:[2-4]\.|[34]$)/.test(version)254 })255 .concat(chromeVersions.slice(iFirstEvergreen))256}257 258var DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype']259 260function copyObject(obj) {261 var copy = {}262 for (var key in obj) {263 if (DANGEROUS_KEYS.indexOf(key) === -1) {264 copy[key] = obj[key]265 }266 }267 return copy268}269 270function normalizeAndroidData(android, chrome) {271 android.released = normalizeAndroidVersions(android.released, chrome.released)272 android.versions = normalizeAndroidVersions(android.versions, chrome.versions)273 android.releaseDate = copyObject(android.releaseDate)274 android.released.forEach(function (v) {275 if (android.releaseDate[v] === undefined) {276 android.releaseDate[v] = chrome.releaseDate[v]277 }278 })279 return android280}281 282function checkName(name, context) {283 var data = byName(name, context)284 if (!data) throw new BrowserslistError('Unknown browser ' + name)285 return data286}287 288function unknownQuery(query) {289 return new BrowserslistError(290 'Unknown browser query `' +291 query +292 '`. ' +293 'Maybe you are using old Browserslist or made typo in query.'294 )295}296 297// Adjusts last X versions queries for some mobile browsers,298// where caniuse data jumps from a legacy version to the latest299function filterJumps(list, name, nVersions, context) {300 var jump = 1301 switch (name) {302 case 'android':303 if (context.mobileToDesktop) return list304 var released = browserslist.data.chrome.released305 jump = released.length - released.indexOf(ANDROID_EVERGREEN_FIRST)306 break307 case 'op_mob':308 var latest = browserslist.data.op_mob.released.slice(-1)[0]309 jump = getMajor(latest) - OP_MOB_BLINK_FIRST + 1310 break311 default:312 return list313 }314 if (nVersions <= jump) {315 return list.slice(-1)316 }317 return list.slice(jump - 1 - nVersions)318}319 320function isSupported(flags, withPartial) {321 return (322 typeof flags === 'string' &&323 (flags.indexOf('y') >= 0 || (withPartial && flags.indexOf('a') >= 0))324 )325}326 327function resolve(queries, context) {328 return parseQueries(queries).reduce(function (result, node, index) {329 if (node.not && index === 0) {330 throw new BrowserslistError(331 'Write any browsers query (for instance, `defaults`) ' +332 'before `' +333 node.query +334 '`'335 )336 }337 var type = QUERIES[node.type]338 var array = type.select.call(browserslist, context, node).map(function (j) {339 var parts = j.split(' ')340 if (parts[1] === '0') {341 return parts[0] + ' ' + byName(parts[0], context).versions[0]342 } else {343 return j344 }345 })346 347 if (node.compose === 'and') {348 if (node.not) {349 return result.filter(function (j) {350 return array.indexOf(j) === -1351 })352 } else {353 return result.filter(function (j) {354 return array.indexOf(j) !== -1355 })356 }357 } else {358 if (node.not) {359 var filter = {}360 array.forEach(function (j) {361 filter[j] = true362 })363 return result.filter(function (j) {364 return !filter[j]365 })366 }367 return result.concat(array)368 }369 }, [])370}371 372function prepareOpts(opts) {373 if (typeof opts === 'undefined') opts = {}374 375 if (typeof opts.path === 'undefined') {376 opts.path = path.resolve ? path.resolve('.') : '.'377 }378 379 return opts380}381 382function prepareQueries(queries, opts) {383 if (typeof queries === 'undefined' || queries === null) {384 var config = browserslist.loadConfig(opts)385 if (config) {386 queries = config387 } else {388 queries = browserslist.defaults389 }390 }391 392 return queries393}394 395function checkQueries(queries) {396 if (!(typeof queries === 'string' || Array.isArray(queries))) {397 throw new BrowserslistError(398 'Browser queries must be an array or string. Got ' + typeof queries + '.'399 )400 }401}402 403var cache = {}404var parseCache = {}405 406function browserslist(queries, opts) {407 opts = prepareOpts(opts)408 queries = prepareQueries(queries, opts)409 checkQueries(queries)410 411 var needsPath = parseQueries(queries).some(function (node) {412 return QUERIES[node.type].needsPath413 })414 var context = {415 ignoreUnknownVersions: opts.ignoreUnknownVersions,416 dangerousExtend: opts.dangerousExtend,417 throwOnMissing: opts.throwOnMissing,418 mobileToDesktop: opts.mobileToDesktop,419 env: opts.env420 }421 // Removing to avoid using context.path without marking query as needsPath422 if (needsPath) {423 context.path = opts.path424 }425 426 env.oldDataWarning(browserslist.data)427 var stats = env.getStat(opts, browserslist.data)428 if (stats) {429 context.customUsage = {}430 for (var browser in stats) {431 fillUsage(context.customUsage, browser, stats[browser])432 }433 }434 435 var cacheKey = JSON.stringify([queries, context])436 if (cache[cacheKey]) return cache[cacheKey]437 438 var result = uniq(resolve(queries, context)).sort(function (name1, name2) {439 name1 = name1.split(' ')440 name2 = name2.split(' ')441 if (name1[0] === name2[0]) {442 // assumptions on caniuse data443 // 1) version ranges never overlaps444 // 2) if version is not a range, it never contains `-`445 var version1 = name1[1].split('-')[0]446 var version2 = name2[1].split('-')[0]447 return compareSemver(version2.split('.'), version1.split('.'))448 } else {449 return compare(name1[0], name2[0])450 }451 })452 if (!env.env.BROWSERSLIST_DISABLE_CACHE) {453 cache[cacheKey] = result454 }455 return result456}457 458function parseQueries(queries) {459 var cacheKey = JSON.stringify(queries)460 if (cacheKey in parseCache) return parseCache[cacheKey]461 var result = parseWithoutCache(QUERIES, queries)462 if (!env.env.BROWSERSLIST_DISABLE_CACHE) {463 parseCache[cacheKey] = result464 }465 return result466}467 468function loadCustomUsage(context, config) {469 var stats = env.loadStat(context, config, browserslist.data)470 if (stats) {471 context.customUsage = {}472 for (var browser in stats) {473 fillUsage(context.customUsage, browser, stats[browser])474 }475 }476 if (!context.customUsage) {477 throw new BrowserslistError('Custom usage statistics was not provided')478 }479 return context.customUsage480}481 482browserslist.parse = function (queries, opts) {483 opts = prepareOpts(opts)484 queries = prepareQueries(queries, opts)485 checkQueries(queries)486 return parseQueries(queries)487}488 489// Will be filled by Can I Use data below490browserslist.cache = {}491browserslist.data = {}492browserslist.usage = {493 global: {},494 custom: null495}496 497// Default browsers query498browserslist.defaults = ['> 0.5%', 'last 2 versions', 'Firefox ESR', 'not dead']499 500// Browser names aliases501browserslist.aliases = {502 fx: 'firefox',503 ff: 'firefox',504 ios: 'ios_saf',505 explorer: 'ie',506 blackberry: 'bb',507 explorermobile: 'ie_mob',508 operamini: 'op_mini',509 operamobile: 'op_mob',510 chromeandroid: 'and_chr',511 firefoxandroid: 'and_ff',512 ucandroid: 'and_uc',513 qqandroid: 'and_qq'514}515 516// Can I Use only provides a few versions for some browsers (e.g. and_chr).517// Fallback to a similar browser for unknown versions518// Note op_mob is not included as its chromium versions are not in sync with Opera desktop519browserslist.desktopNames = {520 and_chr: 'chrome',521 and_ff: 'firefox',522 ie_mob: 'ie',523 android: 'chrome' // has extra processing logic524}525 526// Aliases to work with joined versions like `ios_saf 7.0-7.1`527browserslist.versionAliases = {}528 529browserslist.clearCaches = env.clearCaches530browserslist.parseConfig = env.parseConfig531browserslist.readConfig = env.readConfig532browserslist.findConfigFile = env.findConfigFile533browserslist.findConfig = env.findConfig534browserslist.loadConfig = env.loadConfig535 536browserslist.coverage = function (browsers, stats) {537 var data538 if (typeof stats === 'undefined') {539 data = browserslist.usage.global540 } else if (stats === 'my stats') {541 var opts = {}542 opts.path = path.resolve ? path.resolve('.') : '.'543 var customStats = env.getStat(opts)544 if (!customStats) {545 throw new BrowserslistError('Custom usage statistics was not provided')546 }547 data = {}548 for (var browser in customStats) {549 fillUsage(data, browser, customStats[browser])550 }551 } else if (typeof stats === 'string') {552 if (stats.length > 2) {553 stats = stats.toLowerCase()554 } else {555 stats = stats.toUpperCase()556 }557 env.loadCountry(browserslist.usage, stats, browserslist.data)558 data = browserslist.usage[stats]559 } else {560 if ('dataByBrowser' in stats) {561 stats = stats.dataByBrowser562 }563 data = {}564 for (var name in stats) {565 for (var version in stats[name]) {566 data[name + ' ' + version] = stats[name][version]567 }568 }569 }570 571 return browsers.reduce(function (all, i) {572 var usage = data[i]573 if (usage === undefined) {574 usage = data[i.replace(/ \S+$/, ' 0')]575 }576 return all + (usage || 0)577 }, 0)578}579 580function nodeQuery(context, node) {581 var matched = browserslist.nodeVersions.filter(function (i) {582 return isVersionsMatch(i, node.version)583 })584 if (matched.length === 0) {585 if (context.ignoreUnknownVersions) {586 return []587 } else {588 throw new BrowserslistError(589 'Unknown version ' + node.version + ' of Node.js'590 )591 }592 }593 return ['node ' + matched[matched.length - 1]]594}595 596function sinceQuery(context, node) {597 var year = parseInt(node.year)598 var month = parseInt(node.month || '01') - 1599 var day = parseInt(node.day || '01')600 return filterByYear(Date.UTC(year, month, day, 0, 0, 0), context)601}602 603function bbmTransform(bbmVersions) {604 var browsers = {605 chrome: 'chrome',606 chrome_android: 'and_chr',607 edge: 'edge',608 firefox: 'firefox',609 firefox_android: 'and_ff',610 safari: 'safari',611 safari_ios: 'ios_saf',612 webview_android: 'android',613 samsunginternet_android: 'samsung',614 opera_android: 'op_mob',615 opera: 'opera',616 qq_android: 'and_qq',617 uc_android: 'and_uc',618 kai_os: 'kaios'619 }620 621 return bbmVersions622 .filter(function (version) {623 return Object.keys(browsers).indexOf(version.browser) !== -1624 })625 .map(function (version) {626 return browsers[version.browser] + ' >= ' + version.version627 })628}629 630function coverQuery(context, node) {631 var coverage = parseFloat(node.coverage)632 var usage = browserslist.usage.global633 if (node.place) {634 if (node.place.match(/^my\s+stats$/i)) {635 if (!context.customUsage) {636 throw new BrowserslistError('Custom usage statistics was not provided')637 }638 usage = context.customUsage639 } else {640 var place641 if (node.place.length === 2) {642 place = node.place.toUpperCase()643 } else {644 place = node.place.toLowerCase()645 }646 env.loadCountry(browserslist.usage, place, browserslist.data)647 usage = browserslist.usage[place]648 }649 } else if (node.config) {650 usage = loadCustomUsage(context, node.config)651 }652 var versions = Object.keys(usage).sort(function (a, b) {653 return usage[b] - usage[a]654 })655 var covered = 0656 var result = []657 var version658 for (var i = 0; i < versions.length; i++) {659 version = versions[i]660 if (usage[version] === 0) break661 covered += usage[version]662 result.push(version)663 if (covered >= coverage) break664 }665 return result666}667 668var QUERIES = {669 last_major_versions: {670 matches: ['versions'],671 regexp: /^last\s+(\d+)\s+major\s+versions?$/i,672 select: function (context, node) {673 return Object.keys(agents).reduce(function (selected, name) {674 var data = byName(name, context)675 if (!data) return selected676 var list = getMajorVersions(data.released, node.versions)677 list = list.map(nameMapper(data.name))678 list = filterJumps(list, data.name, node.versions, context)679 return selected.concat(list)680 }, [])681 }682 },683 last_versions: {684 matches: ['versions'],685 regexp: /^last\s+(\d+)\s+versions?$/i,686 select: function (context, node) {687 return Object.keys(agents).reduce(function (selected, name) {688 var data = byName(name, context)689 if (!data) return selected690 var list = data.released.slice(-node.versions)691 list = list.map(nameMapper(data.name))692 list = filterJumps(list, data.name, node.versions, context)693 return selected.concat(list)694 }, [])695 }696 },697 last_electron_major_versions: {698 matches: ['versions'],699 regexp: /^last\s+(\d+)\s+electron\s+major\s+versions?$/i,700 select: function (context, node) {701 var validVersions = getMajorVersions(Object.keys(e2c), node.versions)702 return validVersions.map(function (i) {703 return 'chrome ' + e2c[i]704 })705 }706 },707 last_node_major_versions: {708 matches: ['versions'],709 regexp: /^last\s+(\d+)\s+node\s+major\s+versions?$/i,710 select: function (context, node) {711 return getMajorVersions(browserslist.nodeVersions, node.versions).map(712 function (version) {713 return 'node ' + version714 }715 )716 }717 },718 last_browser_major_versions: {719 matches: ['versions', 'browser'],720 regexp: /^last\s+(\d+)\s+(\w+)\s+major\s+versions?$/i,721 select: function (context, node) {722 var data = checkName(node.browser, context)723 var validVersions = getMajorVersions(data.released, node.versions)724 var list = validVersions.map(nameMapper(data.name))725 list = filterJumps(list, data.name, node.versions, context)726 return list727 }728 },729 last_electron_versions: {730 matches: ['versions'],731 regexp: /^last\s+(\d+)\s+electron\s+versions?$/i,732 select: function (context, node) {733 return Object.keys(e2c)734 .slice(-node.versions)735 .map(function (i) {736 return 'chrome ' + e2c[i]737 })738 }739 },740 last_node_versions: {741 matches: ['versions'],742 regexp: /^last\s+(\d+)\s+node\s+versions?$/i,743 select: function (context, node) {744 return browserslist.nodeVersions745 .slice(-node.versions)746 .map(function (version) {747 return 'node ' + version748 })749 }750 },751 last_browser_versions: {752 matches: ['versions', 'browser'],753 regexp: /^last\s+(\d+)\s+(\w+)\s+versions?$/i,754 select: function (context, node) {755 var data = checkName(node.browser, context)756 var list = data.released.slice(-node.versions).map(nameMapper(data.name))757 list = filterJumps(list, data.name, node.versions, context)758 return list759 }760 },761 unreleased_versions: {762 matches: [],763 regexp: /^unreleased\s+versions$/i,764 select: function (context) {765 return Object.keys(agents).reduce(function (selected, name) {766 var data = byName(name, context)767 if (!data) return selected768 var list = data.versions.filter(function (v) {769 return data.released.indexOf(v) === -1770 })771 list = list.map(nameMapper(data.name))772 return selected.concat(list)773 }, [])774 }775 },776 unreleased_electron_versions: {777 matches: [],778 regexp: /^unreleased\s+electron\s+versions?$/i,779 select: function () {780 return []781 }782 },783 unreleased_browser_versions: {784 matches: ['browser'],785 regexp: /^unreleased\s+(\w+)\s+versions?$/i,786 select: function (context, node) {787 var data = checkName(node.browser, context)788 return data.versions789 .filter(function (v) {790 return data.released.indexOf(v) === -1791 })792 .map(nameMapper(data.name))793 }794 },795 last_years: {796 matches: ['years'],797 regexp: /^last\s+((\d+\.)?\d+)\s+years?$/i,798 select: function (context, node) {799 return filterByYear(Date.now() - YEAR * node.years, context)800 }801 },802 since_y: {803 matches: ['year'],804 regexp: /^since (\d+)$/i,805 select: sinceQuery806 },807 since_y_m: {808 matches: ['year', 'month'],809 regexp: /^since (\d+)-(\d+)$/i,810 select: sinceQuery811 },812 since_y_m_d: {813 matches: ['year', 'month', 'day'],814 regexp: /^since (\d+)-(\d+)-(\d+)$/i,815 select: sinceQuery816 },817 baseline: {818 matches: ['year', 'availability', 'date', 'downstream', 'kaios'],819 // Matches:820 // baseline 2024821 // baseline newly available822 // baseline widely available823 // baseline widely available on 2024-06-01824 // ...with downstream825 // ...including kaios826 regexp:827 /^baseline\s+(?:(\d+)|(newly|widely)\s+available(?:\s+on\s+(\d{4}-\d{2}-\d{2}))?)?(\s+with\s+downstream)?(\s+including\s+kaios)?$/i,828 select: function (context, node) {829 var baselineVersions830 var includeDownstream = !!node.downstream831 var includeKaiOS = !!node.kaios832 var availability = node.availability && node.availability.toLowerCase()833 if (availability === 'newly' && node.date) {834 throw new BrowserslistError(835 'Using newly available with a date is not supported, please use "widely available on YYYY-MM-DD" and add 30 months to the date you specified.'836 )837 }838 if (node.year) {839 baselineVersions = bbm.getCompatibleVersions({840 targetYear: node.year,841 includeDownstreamBrowsers: includeDownstream,842 includeKaiOS: includeKaiOS,843 suppressWarnings: true844 })845 } else if (node.date) {846 baselineVersions = bbm.getCompatibleVersions({847 widelyAvailableOnDate: node.date,848 includeDownstreamBrowsers: includeDownstream,849 includeKaiOS: includeKaiOS,850 suppressWarnings: true851 })852 } else if (availability === 'newly') {853 var future30months = new Date().setMonth(new Date().getMonth() + 30)854 baselineVersions = bbm.getCompatibleVersions({855 widelyAvailableOnDate: future30months,856 includeDownstreamBrowsers: includeDownstream,857 includeKaiOS: includeKaiOS,858 suppressWarnings: true859 })860 } else {861 baselineVersions = bbm.getCompatibleVersions({862 includeDownstreamBrowsers: includeDownstream,863 includeKaiOS: includeKaiOS,864 suppressWarnings: true865 })866 }867 return resolve(bbmTransform(baselineVersions), context)868 }869 },870 popularity: {871 matches: ['sign', 'popularity'],872 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%$/,873 select: function (context, node) {874 var popularity = parseFloat(node.popularity)875 var usage = browserslist.usage.global876 return Object.keys(usage).reduce(function (result, version) {877 if (node.sign === '>') {878 if (usage[version] > popularity) {879 result.push(version)880 }881 } else if (node.sign === '<') {882 if (usage[version] < popularity) {883 result.push(version)884 }885 } else if (node.sign === '<=') {886 if (usage[version] <= popularity) {887 result.push(version)888 }889 } else if (usage[version] >= popularity) {890 result.push(version)891 }892 return result893 }, [])894 }895 },896 popularity_in_my_stats: {897 matches: ['sign', 'popularity'],898 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+my\s+stats$/,899 select: function (context, node) {900 var popularity = parseFloat(node.popularity)901 if (!context.customUsage) {902 throw new BrowserslistError('Custom usage statistics was not provided')903 }904 var usage = context.customUsage905 return Object.keys(usage).reduce(function (result, version) {906 var percentage = usage[version]907 if (percentage == null) {908 return result909 }910 911 if (node.sign === '>') {912 if (percentage > popularity) {913 result.push(version)914 }915 } else if (node.sign === '<') {916 if (percentage < popularity) {917 result.push(version)918 }919 } else if (node.sign === '<=') {920 if (percentage <= popularity) {921 result.push(version)922 }923 } else if (percentage >= popularity) {924 result.push(version)925 }926 return result927 }, [])928 }929 },930 popularity_in_config_stats: {931 matches: ['sign', 'popularity', 'config'],932 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+(\S+)\s+stats$/,933 select: function (context, node) {934 var popularity = parseFloat(node.popularity)935 var usage = loadCustomUsage(context, node.config)936 return Object.keys(usage).reduce(function (result, version) {937 var percentage = usage[version]938 if (percentage == null) {939 return result940 }941 942 if (node.sign === '>') {943 if (percentage > popularity) {944 result.push(version)945 }946 } else if (node.sign === '<') {947 if (percentage < popularity) {948 result.push(version)949 }950 } else if (node.sign === '<=') {951 if (percentage <= popularity) {952 result.push(version)953 }954 } else if (percentage >= popularity) {955 result.push(version)956 }957 return result958 }, [])959 }960 },961 popularity_in_place: {962 matches: ['sign', 'popularity', 'place'],963 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+((alt-)?\w\w)$/,964 select: function (context, node) {965 var popularity = parseFloat(node.popularity)966 var place = node.place967 if (place.length === 2) {968 place = place.toUpperCase()969 } else {970 place = place.toLowerCase()971 }972 env.loadCountry(browserslist.usage, place, browserslist.data)973 var usage = browserslist.usage[place]974 return Object.keys(usage).reduce(function (result, version) {975 var percentage = usage[version]976 if (percentage == null) {977 return result978 }979 980 if (node.sign === '>') {981 if (percentage > popularity) {982 result.push(version)983 }984 } else if (node.sign === '<') {985 if (percentage < popularity) {986 result.push(version)987 }988 } else if (node.sign === '<=') {989 if (percentage <= popularity) {990 result.push(version)991 }992 } else if (percentage >= popularity) {993 result.push(version)994 }995 return result996 }, [])997 }998 },999 cover: {1000 matches: ['coverage'],1001 regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%$/i,1002 select: coverQuery1003 },1004 cover_in: {1005 matches: ['coverage', 'place'],1006 regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%\s+in\s+(my\s+stats|(alt-)?\w\w)$/i,1007 select: coverQuery1008 },1009 cover_config: {1010 matches: ['coverage', 'config'],1011 regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%\s+in\s+(\S+)\s+stats$/i,1012 select: coverQuery1013 },1014 supports: {1015 matches: ['supportType', 'feature'],1016 regexp: /^(?:(fully|partially)\s+)?supports\s+([\w-]+)$/,1017 select: function (context, node) {1018 env.loadFeature(browserslist.cache, node.feature)1019 var withPartial = node.supportType !== 'fully'1020 var features = browserslist.cache[node.feature]1021 var result = []1022 for (var name in features) {1023 var data = byName(name, context)1024 // Only check desktop when latest released mobile has support1025 var iMax = data.released.length - 11026 while (iMax >= 0) {1027 if (data.released[iMax] in features[name]) break1028 iMax--1029 }1030 var checkDesktop =1031 context.mobileToDesktop &&1032 name in browserslist.desktopNames &&1033 isSupported(features[name][data.released[iMax]], withPartial)1034 data.versions.forEach(function (version) {1035 var flags = features[name][version]1036 if (flags === undefined && checkDesktop) {1037 flags = features[browserslist.desktopNames[name]][version]1038 }1039 if (isSupported(flags, withPartial)) {1040 result.push(name + ' ' + version)1041 }1042 })1043 }1044 return result1045 }1046 },1047 electron_range: {1048 matches: ['from', 'to'],1049 regexp: /^electron\s+([\d.]+)\s*-\s*([\d.]+)$/i,1050 select: function (context, node) {1051 var fromToUse = normalizeElectron(node.from)1052 var toToUse = normalizeElectron(node.to)1053 var from = parseFloat(node.from)1054 var to = parseFloat(node.to)1055 if (!e2c[fromToUse]) {1056 throw new BrowserslistError('Unknown version ' + from + ' of electron')1057 }1058 if (!e2c[toToUse]) {1059 throw new BrowserslistError('Unknown version ' + to + ' of electron')1060 }1061 return Object.keys(e2c)1062 .filter(function (i) {1063 var parsed = parseFloat(i)1064 return parsed >= from && parsed <= to1065 })1066 .map(function (i) {1067 return 'chrome ' + e2c[i]1068 })1069 }1070 },1071 node_range: {1072 matches: ['from', 'to'],1073 regexp: /^node\s+([\d.]+)\s*-\s*([\d.]+)$/i,1074 select: function (context, node) {1075 return browserslist.nodeVersions1076 .filter(semverFilterLoose('>=', node.from))1077 .filter(semverFilterLoose('<=', node.to))1078 .map(function (v) {1079 return 'node ' + v1080 })1081 }1082 },1083 browser_range: {1084 matches: ['browser', 'from', 'to'],1085 regexp: /^(\w+)\s+([\d.]+)\s*-\s*([\d.]+)$/i,1086 select: function (context, node) {1087 var data = checkName(node.browser, context)1088 var from = parseFloat(normalizeVersion(data, node.from) || node.from)1089 var to = parseFloat(normalizeVersion(data, node.to) || node.to)1090 function filter(v) {1091 var parsed = parseFloat(v)1092 return parsed >= from && parsed <= to1093 }1094 return data.released.filter(filter).map(nameMapper(data.name))1095 }1096 },1097 electron_ray: {1098 matches: ['sign', 'version'],1099 regexp: /^electron\s*(>=?|<=?)\s*([\d.]+)$/i,1100 select: function (context, node) {1101 var versionToUse = normalizeElectron(node.version)1102 return Object.keys(e2c)1103 .filter(generateFilter(node.sign, versionToUse))1104 .map(function (i) {1105 return 'chrome ' + e2c[i]1106 })1107 }1108 },1109 node_ray: {1110 matches: ['sign', 'version'],1111 regexp: /^node\s*(>=?|<=?)\s*([\d.]+)$/i,1112 select: function (context, node) {1113 return browserslist.nodeVersions1114 .filter(generateSemverFilter(node.sign, node.version))1115 .map(function (v) {1116 return 'node ' + v1117 })1118 }1119 },1120 browser_ray: {1121 matches: ['browser', 'sign', 'version'],1122 regexp: /^(\w+)\s*(>=?|<=?)\s*([\d.]+|esr)$/i,1123 select: function (context, node) {1124 var version = node.version1125 var data = checkName(node.browser, context)1126 var alias = browserslist.versionAliases[data.name][version.toLowerCase()]1127 if (alias) version = alias1128 if (!/[\d.]+/.test(version)) {1129 throw new BrowserslistError(1130 'Unknown version ' + version + ' of ' + node.browser1131 )1132 }1133 return data.released1134 .filter(generateFilter(node.sign, version))1135 .map(function (v) {1136 return data.name + ' ' + v1137 })1138 }1139 },1140 firefox_esr: {1141 matches: [],1142 regexp: /^(firefox|ff|fx)\s+esr$/i,1143 select: function () {1144 return ['firefox ' + FIREFOX_ESR_VERSION]1145 }1146 },1147 opera_mini_all: {1148 matches: [],1149 regexp: /(operamini|op_mini)\s+all/i,1150 select: function () {1151 return ['op_mini all']1152 }1153 },1154 electron_version: {1155 matches: ['version'],1156 regexp: /^electron\s+([\d.]+)$/i,1157 select: function (context, node) {1158 var versionToUse = normalizeElectron(node.version)1159 var chrome = e2c[versionToUse]1160 if (!chrome) {1161 throw new BrowserslistError(1162 'Unknown version ' + node.version + ' of electron'1163 )1164 }1165 return ['chrome ' + chrome]1166 }1167 },1168 node_major_version: {1169 matches: ['version'],1170 regexp: /^node\s+(\d+)$/i,1171 select: nodeQuery1172 },1173 node_minor_version: {1174 matches: ['version'],1175 regexp: /^node\s+(\d+\.\d+)$/i,1176 select: nodeQuery1177 },1178 node_patch_version: {1179 matches: ['version'],1180 regexp: /^node\s+(\d+\.\d+\.\d+)$/i,1181 select: nodeQuery1182 },1183 current_node: {1184 matches: [],1185 regexp: /^current\s+node$/i,1186 select: function (context) {1187 return [env.currentNode(resolve, context)]1188 }1189 },1190 maintained_node: {1191 matches: [],1192 regexp: /^maintained\s+node\s+versions$/i,1193 select: function (context) {1194 var now = Date.now()1195 var queries = Object.keys(jsEOL)1196 .filter(function (key) {1197 return (1198 now < Date.parse(jsEOL[key].end) &&1199 now > Date.parse(jsEOL[key].start) &&1200 isEolReleased(key)