source: imaps-frontend/node_modules/browserslist/index.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 33.3 KB
Line 
1var jsReleases = require('node-releases/data/processed/envs.json')
2var agents = require('caniuse-lite/dist/unpacker/agents').agents
3var jsEOL = require('node-releases/data/release-schedule/release-schedule.json')
4var path = require('path')
5var e2c = require('electron-to-chromium/versions')
6
7var BrowserslistError = require('./error')
8var parse = require('./parse')
9var env = require('./node') // Will load browser.js in webpack
10
11var YEAR = 365.259641 * 24 * 60 * 60 * 1000
12var ANDROID_EVERGREEN_FIRST = '37'
13var OP_MOB_BLINK_FIRST = 14
14
15// Helpers
16
17function isVersionsMatch(versionA, versionB) {
18 return (versionA + '.').indexOf(versionB + '.') === 0
19}
20
21function isEolReleased(name) {
22 var version = name.slice(1)
23 return browserslist.nodeVersions.some(function (i) {
24 return isVersionsMatch(i, version)
25 })
26}
27
28function normalize(versions) {
29 return versions.filter(function (version) {
30 return typeof version === 'string'
31 })
32}
33
34function normalizeElectron(version) {
35 var versionToUse = version
36 if (version.split('.').length === 3) {
37 versionToUse = version.split('.').slice(0, -1).join('.')
38 }
39 return versionToUse
40}
41
42function nameMapper(name) {
43 return function mapName(version) {
44 return name + ' ' + version
45 }
46}
47
48function getMajor(version) {
49 return parseInt(version.split('.')[0])
50}
51
52function getMajorVersions(released, number) {
53 if (released.length === 0) return []
54 var majorVersions = uniq(released.map(getMajor))
55 var minimum = majorVersions[majorVersions.length - number]
56 if (!minimum) {
57 return released
58 }
59 var selected = []
60 for (var i = released.length - 1; i >= 0; i--) {
61 if (minimum > getMajor(released[i])) break
62 selected.unshift(released[i])
63 }
64 return selected
65}
66
67function uniq(array) {
68 var filtered = []
69 for (var i = 0; i < array.length; i++) {
70 if (filtered.indexOf(array[i]) === -1) filtered.push(array[i])
71 }
72 return filtered
73}
74
75function fillUsage(result, name, data) {
76 for (var i in data) {
77 result[name + ' ' + i] = data[i]
78 }
79}
80
81function generateFilter(sign, version) {
82 version = parseFloat(version)
83 if (sign === '>') {
84 return function (v) {
85 return parseLatestFloat(v) > version
86 }
87 } else if (sign === '>=') {
88 return function (v) {
89 return parseLatestFloat(v) >= version
90 }
91 } else if (sign === '<') {
92 return function (v) {
93 return parseFloat(v) < version
94 }
95 } else {
96 return function (v) {
97 return parseFloat(v) <= version
98 }
99 }
100
101 function parseLatestFloat(v) {
102 return parseFloat(v.split('-')[1] || v)
103 }
104}
105
106function generateSemverFilter(sign, version) {
107 version = version.split('.').map(parseSimpleInt)
108 version[1] = version[1] || 0
109 version[2] = version[2] || 0
110 if (sign === '>') {
111 return function (v) {
112 v = v.split('.').map(parseSimpleInt)
113 return compareSemver(v, version) > 0
114 }
115 } else if (sign === '>=') {
116 return function (v) {
117 v = v.split('.').map(parseSimpleInt)
118 return compareSemver(v, version) >= 0
119 }
120 } else if (sign === '<') {
121 return function (v) {
122 v = v.split('.').map(parseSimpleInt)
123 return compareSemver(version, v) > 0
124 }
125 } else {
126 return function (v) {
127 v = v.split('.').map(parseSimpleInt)
128 return compareSemver(version, v) >= 0
129 }
130 }
131}
132
133function parseSimpleInt(x) {
134 return parseInt(x)
135}
136
137function compare(a, b) {
138 if (a < b) return -1
139 if (a > b) return +1
140 return 0
141}
142
143function compareSemver(a, b) {
144 return (
145 compare(parseInt(a[0]), parseInt(b[0])) ||
146 compare(parseInt(a[1] || '0'), parseInt(b[1] || '0')) ||
147 compare(parseInt(a[2] || '0'), parseInt(b[2] || '0'))
148 )
149}
150
151// this follows the npm-like semver behavior
152function semverFilterLoose(operator, range) {
153 range = range.split('.').map(parseSimpleInt)
154 if (typeof range[1] === 'undefined') {
155 range[1] = 'x'
156 }
157 // ignore any patch version because we only return minor versions
158 // range[2] = 'x'
159 switch (operator) {
160 case '<=':
161 return function (version) {
162 version = version.split('.').map(parseSimpleInt)
163 return compareSemverLoose(version, range) <= 0
164 }
165 case '>=':
166 default:
167 return function (version) {
168 version = version.split('.').map(parseSimpleInt)
169 return compareSemverLoose(version, range) >= 0
170 }
171 }
172}
173
174// this follows the npm-like semver behavior
175function compareSemverLoose(version, range) {
176 if (version[0] !== range[0]) {
177 return version[0] < range[0] ? -1 : +1
178 }
179 if (range[1] === 'x') {
180 return 0
181 }
182 if (version[1] !== range[1]) {
183 return version[1] < range[1] ? -1 : +1
184 }
185 return 0
186}
187
188function resolveVersion(data, version) {
189 if (data.versions.indexOf(version) !== -1) {
190 return version
191 } else if (browserslist.versionAliases[data.name][version]) {
192 return browserslist.versionAliases[data.name][version]
193 } else {
194 return false
195 }
196}
197
198function normalizeVersion(data, version) {
199 var resolved = resolveVersion(data, version)
200 if (resolved) {
201 return resolved
202 } else if (data.versions.length === 1) {
203 return data.versions[0]
204 } else {
205 return false
206 }
207}
208
209function filterByYear(since, context) {
210 since = since / 1000
211 return Object.keys(agents).reduce(function (selected, name) {
212 var data = byName(name, context)
213 if (!data) return selected
214 var versions = Object.keys(data.releaseDate).filter(function (v) {
215 var date = data.releaseDate[v]
216 return date !== null && date >= since
217 })
218 return selected.concat(versions.map(nameMapper(data.name)))
219 }, [])
220}
221
222function cloneData(data) {
223 return {
224 name: data.name,
225 versions: data.versions,
226 released: data.released,
227 releaseDate: data.releaseDate
228 }
229}
230
231function byName(name, context) {
232 name = name.toLowerCase()
233 name = browserslist.aliases[name] || name
234 if (context.mobileToDesktop && browserslist.desktopNames[name]) {
235 var desktop = browserslist.data[browserslist.desktopNames[name]]
236 if (name === 'android') {
237 return normalizeAndroidData(cloneData(browserslist.data[name]), desktop)
238 } else {
239 var cloned = cloneData(desktop)
240 cloned.name = name
241 return cloned
242 }
243 }
244 return browserslist.data[name]
245}
246
247function normalizeAndroidVersions(androidVersions, chromeVersions) {
248 var iFirstEvergreen = chromeVersions.indexOf(ANDROID_EVERGREEN_FIRST)
249 return androidVersions
250 .filter(function (version) {
251 return /^(?:[2-4]\.|[34]$)/.test(version)
252 })
253 .concat(chromeVersions.slice(iFirstEvergreen))
254}
255
256function copyObject(obj) {
257 var copy = {}
258 for (var key in obj) {
259 copy[key] = obj[key]
260 }
261 return copy
262}
263
264function normalizeAndroidData(android, chrome) {
265 android.released = normalizeAndroidVersions(android.released, chrome.released)
266 android.versions = normalizeAndroidVersions(android.versions, chrome.versions)
267 android.releaseDate = copyObject(android.releaseDate)
268 android.released.forEach(function (v) {
269 if (android.releaseDate[v] === undefined) {
270 android.releaseDate[v] = chrome.releaseDate[v]
271 }
272 })
273 return android
274}
275
276function checkName(name, context) {
277 var data = byName(name, context)
278 if (!data) throw new BrowserslistError('Unknown browser ' + name)
279 return data
280}
281
282function unknownQuery(query) {
283 return new BrowserslistError(
284 'Unknown browser query `' +
285 query +
286 '`. ' +
287 'Maybe you are using old Browserslist or made typo in query.'
288 )
289}
290
291// Adjusts last X versions queries for some mobile browsers,
292// where caniuse data jumps from a legacy version to the latest
293function filterJumps(list, name, nVersions, context) {
294 var jump = 1
295 switch (name) {
296 case 'android':
297 if (context.mobileToDesktop) return list
298 var released = browserslist.data.chrome.released
299 jump = released.length - released.indexOf(ANDROID_EVERGREEN_FIRST)
300 break
301 case 'op_mob':
302 var latest = browserslist.data.op_mob.released.slice(-1)[0]
303 jump = getMajor(latest) - OP_MOB_BLINK_FIRST + 1
304 break
305 default:
306 return list
307 }
308 if (nVersions <= jump) {
309 return list.slice(-1)
310 }
311 return list.slice(jump - 1 - nVersions)
312}
313
314function isSupported(flags, withPartial) {
315 return (
316 typeof flags === 'string' &&
317 (flags.indexOf('y') >= 0 || (withPartial && flags.indexOf('a') >= 0))
318 )
319}
320
321function resolve(queries, context) {
322 return parse(QUERIES, queries).reduce(function (result, node, index) {
323 if (node.not && index === 0) {
324 throw new BrowserslistError(
325 'Write any browsers query (for instance, `defaults`) ' +
326 'before `' +
327 node.query +
328 '`'
329 )
330 }
331 var type = QUERIES[node.type]
332 var array = type.select.call(browserslist, context, node).map(function (j) {
333 var parts = j.split(' ')
334 if (parts[1] === '0') {
335 return parts[0] + ' ' + byName(parts[0], context).versions[0]
336 } else {
337 return j
338 }
339 })
340
341 if (node.compose === 'and') {
342 if (node.not) {
343 return result.filter(function (j) {
344 return array.indexOf(j) === -1
345 })
346 } else {
347 return result.filter(function (j) {
348 return array.indexOf(j) !== -1
349 })
350 }
351 } else {
352 if (node.not) {
353 var filter = {}
354 array.forEach(function (j) {
355 filter[j] = true
356 })
357 return result.filter(function (j) {
358 return !filter[j]
359 })
360 }
361 return result.concat(array)
362 }
363 }, [])
364}
365
366function prepareOpts(opts) {
367 if (typeof opts === 'undefined') opts = {}
368
369 if (typeof opts.path === 'undefined') {
370 opts.path = path.resolve ? path.resolve('.') : '.'
371 }
372
373 return opts
374}
375
376function prepareQueries(queries, opts) {
377 if (typeof queries === 'undefined' || queries === null) {
378 var config = browserslist.loadConfig(opts)
379 if (config) {
380 queries = config
381 } else {
382 queries = browserslist.defaults
383 }
384 }
385
386 return queries
387}
388
389function checkQueries(queries) {
390 if (!(typeof queries === 'string' || Array.isArray(queries))) {
391 throw new BrowserslistError(
392 'Browser queries must be an array or string. Got ' + typeof queries + '.'
393 )
394 }
395}
396
397var cache = {}
398
399function browserslist(queries, opts) {
400 opts = prepareOpts(opts)
401 queries = prepareQueries(queries, opts)
402 checkQueries(queries)
403
404 var context = {
405 ignoreUnknownVersions: opts.ignoreUnknownVersions,
406 dangerousExtend: opts.dangerousExtend,
407 mobileToDesktop: opts.mobileToDesktop,
408 path: opts.path,
409 env: opts.env
410 }
411
412 env.oldDataWarning(browserslist.data)
413 var stats = env.getStat(opts, browserslist.data)
414 if (stats) {
415 context.customUsage = {}
416 for (var browser in stats) {
417 fillUsage(context.customUsage, browser, stats[browser])
418 }
419 }
420
421 var cacheKey = JSON.stringify([queries, context])
422 if (cache[cacheKey]) return cache[cacheKey]
423
424 var result = uniq(resolve(queries, context)).sort(function (name1, name2) {
425 name1 = name1.split(' ')
426 name2 = name2.split(' ')
427 if (name1[0] === name2[0]) {
428 // assumptions on caniuse data
429 // 1) version ranges never overlaps
430 // 2) if version is not a range, it never contains `-`
431 var version1 = name1[1].split('-')[0]
432 var version2 = name2[1].split('-')[0]
433 return compareSemver(version2.split('.'), version1.split('.'))
434 } else {
435 return compare(name1[0], name2[0])
436 }
437 })
438 if (!env.env.BROWSERSLIST_DISABLE_CACHE) {
439 cache[cacheKey] = result
440 }
441 return result
442}
443
444browserslist.parse = function (queries, opts) {
445 opts = prepareOpts(opts)
446 queries = prepareQueries(queries, opts)
447 checkQueries(queries)
448 return parse(QUERIES, queries)
449}
450
451// Will be filled by Can I Use data below
452browserslist.cache = {}
453browserslist.data = {}
454browserslist.usage = {
455 global: {},
456 custom: null
457}
458
459// Default browsers query
460browserslist.defaults = ['> 0.5%', 'last 2 versions', 'Firefox ESR', 'not dead']
461
462// Browser names aliases
463browserslist.aliases = {
464 fx: 'firefox',
465 ff: 'firefox',
466 ios: 'ios_saf',
467 explorer: 'ie',
468 blackberry: 'bb',
469 explorermobile: 'ie_mob',
470 operamini: 'op_mini',
471 operamobile: 'op_mob',
472 chromeandroid: 'and_chr',
473 firefoxandroid: 'and_ff',
474 ucandroid: 'and_uc',
475 qqandroid: 'and_qq'
476}
477
478// Can I Use only provides a few versions for some browsers (e.g. and_chr).
479// Fallback to a similar browser for unknown versions
480// Note op_mob is not included as its chromium versions are not in sync with Opera desktop
481browserslist.desktopNames = {
482 and_chr: 'chrome',
483 and_ff: 'firefox',
484 ie_mob: 'ie',
485 android: 'chrome' // has extra processing logic
486}
487
488// Aliases to work with joined versions like `ios_saf 7.0-7.1`
489browserslist.versionAliases = {}
490
491browserslist.clearCaches = env.clearCaches
492browserslist.parseConfig = env.parseConfig
493browserslist.readConfig = env.readConfig
494browserslist.findConfig = env.findConfig
495browserslist.loadConfig = env.loadConfig
496
497browserslist.coverage = function (browsers, stats) {
498 var data
499 if (typeof stats === 'undefined') {
500 data = browserslist.usage.global
501 } else if (stats === 'my stats') {
502 var opts = {}
503 opts.path = path.resolve ? path.resolve('.') : '.'
504 var customStats = env.getStat(opts)
505 if (!customStats) {
506 throw new BrowserslistError('Custom usage statistics was not provided')
507 }
508 data = {}
509 for (var browser in customStats) {
510 fillUsage(data, browser, customStats[browser])
511 }
512 } else if (typeof stats === 'string') {
513 if (stats.length > 2) {
514 stats = stats.toLowerCase()
515 } else {
516 stats = stats.toUpperCase()
517 }
518 env.loadCountry(browserslist.usage, stats, browserslist.data)
519 data = browserslist.usage[stats]
520 } else {
521 if ('dataByBrowser' in stats) {
522 stats = stats.dataByBrowser
523 }
524 data = {}
525 for (var name in stats) {
526 for (var version in stats[name]) {
527 data[name + ' ' + version] = stats[name][version]
528 }
529 }
530 }
531
532 return browsers.reduce(function (all, i) {
533 var usage = data[i]
534 if (usage === undefined) {
535 usage = data[i.replace(/ \S+$/, ' 0')]
536 }
537 return all + (usage || 0)
538 }, 0)
539}
540
541function nodeQuery(context, node) {
542 var matched = browserslist.nodeVersions.filter(function (i) {
543 return isVersionsMatch(i, node.version)
544 })
545 if (matched.length === 0) {
546 if (context.ignoreUnknownVersions) {
547 return []
548 } else {
549 throw new BrowserslistError(
550 'Unknown version ' + node.version + ' of Node.js'
551 )
552 }
553 }
554 return ['node ' + matched[matched.length - 1]]
555}
556
557function sinceQuery(context, node) {
558 var year = parseInt(node.year)
559 var month = parseInt(node.month || '01') - 1
560 var day = parseInt(node.day || '01')
561 return filterByYear(Date.UTC(year, month, day, 0, 0, 0), context)
562}
563
564function coverQuery(context, node) {
565 var coverage = parseFloat(node.coverage)
566 var usage = browserslist.usage.global
567 if (node.place) {
568 if (node.place.match(/^my\s+stats$/i)) {
569 if (!context.customUsage) {
570 throw new BrowserslistError('Custom usage statistics was not provided')
571 }
572 usage = context.customUsage
573 } else {
574 var place
575 if (node.place.length === 2) {
576 place = node.place.toUpperCase()
577 } else {
578 place = node.place.toLowerCase()
579 }
580 env.loadCountry(browserslist.usage, place, browserslist.data)
581 usage = browserslist.usage[place]
582 }
583 }
584 var versions = Object.keys(usage).sort(function (a, b) {
585 return usage[b] - usage[a]
586 })
587 var coveraged = 0
588 var result = []
589 var version
590 for (var i = 0; i < versions.length; i++) {
591 version = versions[i]
592 if (usage[version] === 0) break
593 coveraged += usage[version]
594 result.push(version)
595 if (coveraged >= coverage) break
596 }
597 return result
598}
599
600var QUERIES = {
601 last_major_versions: {
602 matches: ['versions'],
603 regexp: /^last\s+(\d+)\s+major\s+versions?$/i,
604 select: function (context, node) {
605 return Object.keys(agents).reduce(function (selected, name) {
606 var data = byName(name, context)
607 if (!data) return selected
608 var list = getMajorVersions(data.released, node.versions)
609 list = list.map(nameMapper(data.name))
610 list = filterJumps(list, data.name, node.versions, context)
611 return selected.concat(list)
612 }, [])
613 }
614 },
615 last_versions: {
616 matches: ['versions'],
617 regexp: /^last\s+(\d+)\s+versions?$/i,
618 select: function (context, node) {
619 return Object.keys(agents).reduce(function (selected, name) {
620 var data = byName(name, context)
621 if (!data) return selected
622 var list = data.released.slice(-node.versions)
623 list = list.map(nameMapper(data.name))
624 list = filterJumps(list, data.name, node.versions, context)
625 return selected.concat(list)
626 }, [])
627 }
628 },
629 last_electron_major_versions: {
630 matches: ['versions'],
631 regexp: /^last\s+(\d+)\s+electron\s+major\s+versions?$/i,
632 select: function (context, node) {
633 var validVersions = getMajorVersions(Object.keys(e2c), node.versions)
634 return validVersions.map(function (i) {
635 return 'chrome ' + e2c[i]
636 })
637 }
638 },
639 last_node_major_versions: {
640 matches: ['versions'],
641 regexp: /^last\s+(\d+)\s+node\s+major\s+versions?$/i,
642 select: function (context, node) {
643 return getMajorVersions(browserslist.nodeVersions, node.versions).map(
644 function (version) {
645 return 'node ' + version
646 }
647 )
648 }
649 },
650 last_browser_major_versions: {
651 matches: ['versions', 'browser'],
652 regexp: /^last\s+(\d+)\s+(\w+)\s+major\s+versions?$/i,
653 select: function (context, node) {
654 var data = checkName(node.browser, context)
655 var validVersions = getMajorVersions(data.released, node.versions)
656 var list = validVersions.map(nameMapper(data.name))
657 list = filterJumps(list, data.name, node.versions, context)
658 return list
659 }
660 },
661 last_electron_versions: {
662 matches: ['versions'],
663 regexp: /^last\s+(\d+)\s+electron\s+versions?$/i,
664 select: function (context, node) {
665 return Object.keys(e2c)
666 .slice(-node.versions)
667 .map(function (i) {
668 return 'chrome ' + e2c[i]
669 })
670 }
671 },
672 last_node_versions: {
673 matches: ['versions'],
674 regexp: /^last\s+(\d+)\s+node\s+versions?$/i,
675 select: function (context, node) {
676 return browserslist.nodeVersions
677 .slice(-node.versions)
678 .map(function (version) {
679 return 'node ' + version
680 })
681 }
682 },
683 last_browser_versions: {
684 matches: ['versions', 'browser'],
685 regexp: /^last\s+(\d+)\s+(\w+)\s+versions?$/i,
686 select: function (context, node) {
687 var data = checkName(node.browser, context)
688 var list = data.released.slice(-node.versions).map(nameMapper(data.name))
689 list = filterJumps(list, data.name, node.versions, context)
690 return list
691 }
692 },
693 unreleased_versions: {
694 matches: [],
695 regexp: /^unreleased\s+versions$/i,
696 select: function (context) {
697 return Object.keys(agents).reduce(function (selected, name) {
698 var data = byName(name, context)
699 if (!data) return selected
700 var list = data.versions.filter(function (v) {
701 return data.released.indexOf(v) === -1
702 })
703 list = list.map(nameMapper(data.name))
704 return selected.concat(list)
705 }, [])
706 }
707 },
708 unreleased_electron_versions: {
709 matches: [],
710 regexp: /^unreleased\s+electron\s+versions?$/i,
711 select: function () {
712 return []
713 }
714 },
715 unreleased_browser_versions: {
716 matches: ['browser'],
717 regexp: /^unreleased\s+(\w+)\s+versions?$/i,
718 select: function (context, node) {
719 var data = checkName(node.browser, context)
720 return data.versions
721 .filter(function (v) {
722 return data.released.indexOf(v) === -1
723 })
724 .map(nameMapper(data.name))
725 }
726 },
727 last_years: {
728 matches: ['years'],
729 regexp: /^last\s+(\d*.?\d+)\s+years?$/i,
730 select: function (context, node) {
731 return filterByYear(Date.now() - YEAR * node.years, context)
732 }
733 },
734 since_y: {
735 matches: ['year'],
736 regexp: /^since (\d+)$/i,
737 select: sinceQuery
738 },
739 since_y_m: {
740 matches: ['year', 'month'],
741 regexp: /^since (\d+)-(\d+)$/i,
742 select: sinceQuery
743 },
744 since_y_m_d: {
745 matches: ['year', 'month', 'day'],
746 regexp: /^since (\d+)-(\d+)-(\d+)$/i,
747 select: sinceQuery
748 },
749 popularity: {
750 matches: ['sign', 'popularity'],
751 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%$/,
752 select: function (context, node) {
753 var popularity = parseFloat(node.popularity)
754 var usage = browserslist.usage.global
755 return Object.keys(usage).reduce(function (result, version) {
756 if (node.sign === '>') {
757 if (usage[version] > popularity) {
758 result.push(version)
759 }
760 } else if (node.sign === '<') {
761 if (usage[version] < popularity) {
762 result.push(version)
763 }
764 } else if (node.sign === '<=') {
765 if (usage[version] <= popularity) {
766 result.push(version)
767 }
768 } else if (usage[version] >= popularity) {
769 result.push(version)
770 }
771 return result
772 }, [])
773 }
774 },
775 popularity_in_my_stats: {
776 matches: ['sign', 'popularity'],
777 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+my\s+stats$/,
778 select: function (context, node) {
779 var popularity = parseFloat(node.popularity)
780 if (!context.customUsage) {
781 throw new BrowserslistError('Custom usage statistics was not provided')
782 }
783 var usage = context.customUsage
784 return Object.keys(usage).reduce(function (result, version) {
785 var percentage = usage[version]
786 if (percentage == null) {
787 return result
788 }
789
790 if (node.sign === '>') {
791 if (percentage > popularity) {
792 result.push(version)
793 }
794 } else if (node.sign === '<') {
795 if (percentage < popularity) {
796 result.push(version)
797 }
798 } else if (node.sign === '<=') {
799 if (percentage <= popularity) {
800 result.push(version)
801 }
802 } else if (percentage >= popularity) {
803 result.push(version)
804 }
805 return result
806 }, [])
807 }
808 },
809 popularity_in_config_stats: {
810 matches: ['sign', 'popularity', 'config'],
811 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+(\S+)\s+stats$/,
812 select: function (context, node) {
813 var popularity = parseFloat(node.popularity)
814 var stats = env.loadStat(context, node.config, browserslist.data)
815 if (stats) {
816 context.customUsage = {}
817 for (var browser in stats) {
818 fillUsage(context.customUsage, browser, stats[browser])
819 }
820 }
821 if (!context.customUsage) {
822 throw new BrowserslistError('Custom usage statistics was not provided')
823 }
824 var usage = context.customUsage
825 return Object.keys(usage).reduce(function (result, version) {
826 var percentage = usage[version]
827 if (percentage == null) {
828 return result
829 }
830
831 if (node.sign === '>') {
832 if (percentage > popularity) {
833 result.push(version)
834 }
835 } else if (node.sign === '<') {
836 if (percentage < popularity) {
837 result.push(version)
838 }
839 } else if (node.sign === '<=') {
840 if (percentage <= popularity) {
841 result.push(version)
842 }
843 } else if (percentage >= popularity) {
844 result.push(version)
845 }
846 return result
847 }, [])
848 }
849 },
850 popularity_in_place: {
851 matches: ['sign', 'popularity', 'place'],
852 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+((alt-)?\w\w)$/,
853 select: function (context, node) {
854 var popularity = parseFloat(node.popularity)
855 var place = node.place
856 if (place.length === 2) {
857 place = place.toUpperCase()
858 } else {
859 place = place.toLowerCase()
860 }
861 env.loadCountry(browserslist.usage, place, browserslist.data)
862 var usage = browserslist.usage[place]
863 return Object.keys(usage).reduce(function (result, version) {
864 var percentage = usage[version]
865 if (percentage == null) {
866 return result
867 }
868
869 if (node.sign === '>') {
870 if (percentage > popularity) {
871 result.push(version)
872 }
873 } else if (node.sign === '<') {
874 if (percentage < popularity) {
875 result.push(version)
876 }
877 } else if (node.sign === '<=') {
878 if (percentage <= popularity) {
879 result.push(version)
880 }
881 } else if (percentage >= popularity) {
882 result.push(version)
883 }
884 return result
885 }, [])
886 }
887 },
888 cover: {
889 matches: ['coverage'],
890 regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%$/i,
891 select: coverQuery
892 },
893 cover_in: {
894 matches: ['coverage', 'place'],
895 regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%\s+in\s+(my\s+stats|(alt-)?\w\w)$/i,
896 select: coverQuery
897 },
898 supports: {
899 matches: ['supportType', 'feature'],
900 regexp: /^(?:(fully|partially)\s+)?supports\s+([\w-]+)$/,
901 select: function (context, node) {
902 env.loadFeature(browserslist.cache, node.feature)
903 var withPartial = node.supportType !== 'fully'
904 var features = browserslist.cache[node.feature]
905 var result = []
906 for (var name in features) {
907 var data = byName(name, context)
908 // Only check desktop when latest released mobile has support
909 var iMax = data.released.length - 1
910 while (iMax >= 0) {
911 if (data.released[iMax] in features[name]) break
912 iMax--
913 }
914 var checkDesktop =
915 context.mobileToDesktop &&
916 name in browserslist.desktopNames &&
917 isSupported(features[name][data.released[iMax]], withPartial)
918 data.versions.forEach(function (version) {
919 var flags = features[name][version]
920 if (flags === undefined && checkDesktop) {
921 flags = features[browserslist.desktopNames[name]][version]
922 }
923 if (isSupported(flags, withPartial)) {
924 result.push(name + ' ' + version)
925 }
926 })
927 }
928 return result
929 }
930 },
931 electron_range: {
932 matches: ['from', 'to'],
933 regexp: /^electron\s+([\d.]+)\s*-\s*([\d.]+)$/i,
934 select: function (context, node) {
935 var fromToUse = normalizeElectron(node.from)
936 var toToUse = normalizeElectron(node.to)
937 var from = parseFloat(node.from)
938 var to = parseFloat(node.to)
939 if (!e2c[fromToUse]) {
940 throw new BrowserslistError('Unknown version ' + from + ' of electron')
941 }
942 if (!e2c[toToUse]) {
943 throw new BrowserslistError('Unknown version ' + to + ' of electron')
944 }
945 return Object.keys(e2c)
946 .filter(function (i) {
947 var parsed = parseFloat(i)
948 return parsed >= from && parsed <= to
949 })
950 .map(function (i) {
951 return 'chrome ' + e2c[i]
952 })
953 }
954 },
955 node_range: {
956 matches: ['from', 'to'],
957 regexp: /^node\s+([\d.]+)\s*-\s*([\d.]+)$/i,
958 select: function (context, node) {
959 return browserslist.nodeVersions
960 .filter(semverFilterLoose('>=', node.from))
961 .filter(semverFilterLoose('<=', node.to))
962 .map(function (v) {
963 return 'node ' + v
964 })
965 }
966 },
967 browser_range: {
968 matches: ['browser', 'from', 'to'],
969 regexp: /^(\w+)\s+([\d.]+)\s*-\s*([\d.]+)$/i,
970 select: function (context, node) {
971 var data = checkName(node.browser, context)
972 var from = parseFloat(normalizeVersion(data, node.from) || node.from)
973 var to = parseFloat(normalizeVersion(data, node.to) || node.to)
974 function filter(v) {
975 var parsed = parseFloat(v)
976 return parsed >= from && parsed <= to
977 }
978 return data.released.filter(filter).map(nameMapper(data.name))
979 }
980 },
981 electron_ray: {
982 matches: ['sign', 'version'],
983 regexp: /^electron\s*(>=?|<=?)\s*([\d.]+)$/i,
984 select: function (context, node) {
985 var versionToUse = normalizeElectron(node.version)
986 return Object.keys(e2c)
987 .filter(generateFilter(node.sign, versionToUse))
988 .map(function (i) {
989 return 'chrome ' + e2c[i]
990 })
991 }
992 },
993 node_ray: {
994 matches: ['sign', 'version'],
995 regexp: /^node\s*(>=?|<=?)\s*([\d.]+)$/i,
996 select: function (context, node) {
997 return browserslist.nodeVersions
998 .filter(generateSemverFilter(node.sign, node.version))
999 .map(function (v) {
1000 return 'node ' + v
1001 })
1002 }
1003 },
1004 browser_ray: {
1005 matches: ['browser', 'sign', 'version'],
1006 regexp: /^(\w+)\s*(>=?|<=?)\s*([\d.]+)$/,
1007 select: function (context, node) {
1008 var version = node.version
1009 var data = checkName(node.browser, context)
1010 var alias = browserslist.versionAliases[data.name][version]
1011 if (alias) version = alias
1012 return data.released
1013 .filter(generateFilter(node.sign, version))
1014 .map(function (v) {
1015 return data.name + ' ' + v
1016 })
1017 }
1018 },
1019 firefox_esr: {
1020 matches: [],
1021 regexp: /^(firefox|ff|fx)\s+esr$/i,
1022 select: function () {
1023 return ['firefox 115', 'firefox 128']
1024 }
1025 },
1026 opera_mini_all: {
1027 matches: [],
1028 regexp: /(operamini|op_mini)\s+all/i,
1029 select: function () {
1030 return ['op_mini all']
1031 }
1032 },
1033 electron_version: {
1034 matches: ['version'],
1035 regexp: /^electron\s+([\d.]+)$/i,
1036 select: function (context, node) {
1037 var versionToUse = normalizeElectron(node.version)
1038 var chrome = e2c[versionToUse]
1039 if (!chrome) {
1040 throw new BrowserslistError(
1041 'Unknown version ' + node.version + ' of electron'
1042 )
1043 }
1044 return ['chrome ' + chrome]
1045 }
1046 },
1047 node_major_version: {
1048 matches: ['version'],
1049 regexp: /^node\s+(\d+)$/i,
1050 select: nodeQuery
1051 },
1052 node_minor_version: {
1053 matches: ['version'],
1054 regexp: /^node\s+(\d+\.\d+)$/i,
1055 select: nodeQuery
1056 },
1057 node_patch_version: {
1058 matches: ['version'],
1059 regexp: /^node\s+(\d+\.\d+\.\d+)$/i,
1060 select: nodeQuery
1061 },
1062 current_node: {
1063 matches: [],
1064 regexp: /^current\s+node$/i,
1065 select: function (context) {
1066 return [env.currentNode(resolve, context)]
1067 }
1068 },
1069 maintained_node: {
1070 matches: [],
1071 regexp: /^maintained\s+node\s+versions$/i,
1072 select: function (context) {
1073 var now = Date.now()
1074 var queries = Object.keys(jsEOL)
1075 .filter(function (key) {
1076 return (
1077 now < Date.parse(jsEOL[key].end) &&
1078 now > Date.parse(jsEOL[key].start) &&
1079 isEolReleased(key)
1080 )
1081 })
1082 .map(function (key) {
1083 return 'node ' + key.slice(1)
1084 })
1085 return resolve(queries, context)
1086 }
1087 },
1088 phantomjs_1_9: {
1089 matches: [],
1090 regexp: /^phantomjs\s+1.9$/i,
1091 select: function () {
1092 return ['safari 5']
1093 }
1094 },
1095 phantomjs_2_1: {
1096 matches: [],
1097 regexp: /^phantomjs\s+2.1$/i,
1098 select: function () {
1099 return ['safari 6']
1100 }
1101 },
1102 browser_version: {
1103 matches: ['browser', 'version'],
1104 regexp: /^(\w+)\s+(tp|[\d.]+)$/i,
1105 select: function (context, node) {
1106 var version = node.version
1107 if (/^tp$/i.test(version)) version = 'TP'
1108 var data = checkName(node.browser, context)
1109 var alias = normalizeVersion(data, version)
1110 if (alias) {
1111 version = alias
1112 } else {
1113 if (version.indexOf('.') === -1) {
1114 alias = version + '.0'
1115 } else {
1116 alias = version.replace(/\.0$/, '')
1117 }
1118 alias = normalizeVersion(data, alias)
1119 if (alias) {
1120 version = alias
1121 } else if (context.ignoreUnknownVersions) {
1122 return []
1123 } else {
1124 throw new BrowserslistError(
1125 'Unknown version ' + version + ' of ' + node.browser
1126 )
1127 }
1128 }
1129 return [data.name + ' ' + version]
1130 }
1131 },
1132 browserslist_config: {
1133 matches: [],
1134 regexp: /^browserslist config$/i,
1135 select: function (context) {
1136 return browserslist(undefined, context)
1137 }
1138 },
1139 extends: {
1140 matches: ['config'],
1141 regexp: /^extends (.+)$/i,
1142 select: function (context, node) {
1143 return resolve(env.loadQueries(context, node.config), context)
1144 }
1145 },
1146 defaults: {
1147 matches: [],
1148 regexp: /^defaults$/i,
1149 select: function (context) {
1150 return resolve(browserslist.defaults, context)
1151 }
1152 },
1153 dead: {
1154 matches: [],
1155 regexp: /^dead$/i,
1156 select: function (context) {
1157 var dead = [
1158 'Baidu >= 0',
1159 'ie <= 11',
1160 'ie_mob <= 11',
1161 'bb <= 10',
1162 'op_mob <= 12.1',
1163 'samsung 4'
1164 ]
1165 return resolve(dead, context)
1166 }
1167 },
1168 unknown: {
1169 matches: [],
1170 regexp: /^(\w+)$/i,
1171 select: function (context, node) {
1172 if (byName(node.query, context)) {
1173 throw new BrowserslistError(
1174 'Specify versions in Browserslist query for browser ' + node.query
1175 )
1176 } else {
1177 throw unknownQuery(node.query)
1178 }
1179 }
1180 }
1181}
1182
1183// Get and convert Can I Use data
1184
1185;(function () {
1186 for (var name in agents) {
1187 var browser = agents[name]
1188 browserslist.data[name] = {
1189 name: name,
1190 versions: normalize(agents[name].versions),
1191 released: normalize(agents[name].versions.slice(0, -3)),
1192 releaseDate: agents[name].release_date
1193 }
1194 fillUsage(browserslist.usage.global, name, browser.usage_global)
1195
1196 browserslist.versionAliases[name] = {}
1197 for (var i = 0; i < browser.versions.length; i++) {
1198 var full = browser.versions[i]
1199 if (!full) continue
1200
1201 if (full.indexOf('-') !== -1) {
1202 var interval = full.split('-')
1203 for (var j = 0; j < interval.length; j++) {
1204 browserslist.versionAliases[name][interval[j]] = full
1205 }
1206 }
1207 }
1208 }
1209
1210 browserslist.nodeVersions = jsReleases.map(function (release) {
1211 return release.version
1212 })
1213})()
1214
1215module.exports = browserslist
Note: See TracBrowser for help on using the repository browser.