source: imaps-frontend/node_modules/browserslist/index.js@ 0c6b92a

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • 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 e2c = require('electron-to-chromium/versions')
4var jsEOL = require('node-releases/data/release-schedule/release-schedule.json')
5var path = require('path')
6
7var BrowserslistError = require('./error')
8var env = require('./node')
9var parse = require('./parse') // 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.findConfigFile = env.findConfigFile
495browserslist.findConfig = env.findConfig
496browserslist.loadConfig = env.loadConfig
497
498browserslist.coverage = function (browsers, stats) {
499 var data
500 if (typeof stats === 'undefined') {
501 data = browserslist.usage.global
502 } else if (stats === 'my stats') {
503 var opts = {}
504 opts.path = path.resolve ? path.resolve('.') : '.'
505 var customStats = env.getStat(opts)
506 if (!customStats) {
507 throw new BrowserslistError('Custom usage statistics was not provided')
508 }
509 data = {}
510 for (var browser in customStats) {
511 fillUsage(data, browser, customStats[browser])
512 }
513 } else if (typeof stats === 'string') {
514 if (stats.length > 2) {
515 stats = stats.toLowerCase()
516 } else {
517 stats = stats.toUpperCase()
518 }
519 env.loadCountry(browserslist.usage, stats, browserslist.data)
520 data = browserslist.usage[stats]
521 } else {
522 if ('dataByBrowser' in stats) {
523 stats = stats.dataByBrowser
524 }
525 data = {}
526 for (var name in stats) {
527 for (var version in stats[name]) {
528 data[name + ' ' + version] = stats[name][version]
529 }
530 }
531 }
532
533 return browsers.reduce(function (all, i) {
534 var usage = data[i]
535 if (usage === undefined) {
536 usage = data[i.replace(/ \S+$/, ' 0')]
537 }
538 return all + (usage || 0)
539 }, 0)
540}
541
542function nodeQuery(context, node) {
543 var matched = browserslist.nodeVersions.filter(function (i) {
544 return isVersionsMatch(i, node.version)
545 })
546 if (matched.length === 0) {
547 if (context.ignoreUnknownVersions) {
548 return []
549 } else {
550 throw new BrowserslistError(
551 'Unknown version ' + node.version + ' of Node.js'
552 )
553 }
554 }
555 return ['node ' + matched[matched.length - 1]]
556}
557
558function sinceQuery(context, node) {
559 var year = parseInt(node.year)
560 var month = parseInt(node.month || '01') - 1
561 var day = parseInt(node.day || '01')
562 return filterByYear(Date.UTC(year, month, day, 0, 0, 0), context)
563}
564
565function coverQuery(context, node) {
566 var coverage = parseFloat(node.coverage)
567 var usage = browserslist.usage.global
568 if (node.place) {
569 if (node.place.match(/^my\s+stats$/i)) {
570 if (!context.customUsage) {
571 throw new BrowserslistError('Custom usage statistics was not provided')
572 }
573 usage = context.customUsage
574 } else {
575 var place
576 if (node.place.length === 2) {
577 place = node.place.toUpperCase()
578 } else {
579 place = node.place.toLowerCase()
580 }
581 env.loadCountry(browserslist.usage, place, browserslist.data)
582 usage = browserslist.usage[place]
583 }
584 }
585 var versions = Object.keys(usage).sort(function (a, b) {
586 return usage[b] - usage[a]
587 })
588 var coveraged = 0
589 var result = []
590 var version
591 for (var i = 0; i < versions.length; i++) {
592 version = versions[i]
593 if (usage[version] === 0) break
594 coveraged += usage[version]
595 result.push(version)
596 if (coveraged >= coverage) break
597 }
598 return result
599}
600
601var QUERIES = {
602 last_major_versions: {
603 matches: ['versions'],
604 regexp: /^last\s+(\d+)\s+major\s+versions?$/i,
605 select: function (context, node) {
606 return Object.keys(agents).reduce(function (selected, name) {
607 var data = byName(name, context)
608 if (!data) return selected
609 var list = getMajorVersions(data.released, node.versions)
610 list = list.map(nameMapper(data.name))
611 list = filterJumps(list, data.name, node.versions, context)
612 return selected.concat(list)
613 }, [])
614 }
615 },
616 last_versions: {
617 matches: ['versions'],
618 regexp: /^last\s+(\d+)\s+versions?$/i,
619 select: function (context, node) {
620 return Object.keys(agents).reduce(function (selected, name) {
621 var data = byName(name, context)
622 if (!data) return selected
623 var list = data.released.slice(-node.versions)
624 list = list.map(nameMapper(data.name))
625 list = filterJumps(list, data.name, node.versions, context)
626 return selected.concat(list)
627 }, [])
628 }
629 },
630 last_electron_major_versions: {
631 matches: ['versions'],
632 regexp: /^last\s+(\d+)\s+electron\s+major\s+versions?$/i,
633 select: function (context, node) {
634 var validVersions = getMajorVersions(Object.keys(e2c), node.versions)
635 return validVersions.map(function (i) {
636 return 'chrome ' + e2c[i]
637 })
638 }
639 },
640 last_node_major_versions: {
641 matches: ['versions'],
642 regexp: /^last\s+(\d+)\s+node\s+major\s+versions?$/i,
643 select: function (context, node) {
644 return getMajorVersions(browserslist.nodeVersions, node.versions).map(
645 function (version) {
646 return 'node ' + version
647 }
648 )
649 }
650 },
651 last_browser_major_versions: {
652 matches: ['versions', 'browser'],
653 regexp: /^last\s+(\d+)\s+(\w+)\s+major\s+versions?$/i,
654 select: function (context, node) {
655 var data = checkName(node.browser, context)
656 var validVersions = getMajorVersions(data.released, node.versions)
657 var list = validVersions.map(nameMapper(data.name))
658 list = filterJumps(list, data.name, node.versions, context)
659 return list
660 }
661 },
662 last_electron_versions: {
663 matches: ['versions'],
664 regexp: /^last\s+(\d+)\s+electron\s+versions?$/i,
665 select: function (context, node) {
666 return Object.keys(e2c)
667 .slice(-node.versions)
668 .map(function (i) {
669 return 'chrome ' + e2c[i]
670 })
671 }
672 },
673 last_node_versions: {
674 matches: ['versions'],
675 regexp: /^last\s+(\d+)\s+node\s+versions?$/i,
676 select: function (context, node) {
677 return browserslist.nodeVersions
678 .slice(-node.versions)
679 .map(function (version) {
680 return 'node ' + version
681 })
682 }
683 },
684 last_browser_versions: {
685 matches: ['versions', 'browser'],
686 regexp: /^last\s+(\d+)\s+(\w+)\s+versions?$/i,
687 select: function (context, node) {
688 var data = checkName(node.browser, context)
689 var list = data.released.slice(-node.versions).map(nameMapper(data.name))
690 list = filterJumps(list, data.name, node.versions, context)
691 return list
692 }
693 },
694 unreleased_versions: {
695 matches: [],
696 regexp: /^unreleased\s+versions$/i,
697 select: function (context) {
698 return Object.keys(agents).reduce(function (selected, name) {
699 var data = byName(name, context)
700 if (!data) return selected
701 var list = data.versions.filter(function (v) {
702 return data.released.indexOf(v) === -1
703 })
704 list = list.map(nameMapper(data.name))
705 return selected.concat(list)
706 }, [])
707 }
708 },
709 unreleased_electron_versions: {
710 matches: [],
711 regexp: /^unreleased\s+electron\s+versions?$/i,
712 select: function () {
713 return []
714 }
715 },
716 unreleased_browser_versions: {
717 matches: ['browser'],
718 regexp: /^unreleased\s+(\w+)\s+versions?$/i,
719 select: function (context, node) {
720 var data = checkName(node.browser, context)
721 return data.versions
722 .filter(function (v) {
723 return data.released.indexOf(v) === -1
724 })
725 .map(nameMapper(data.name))
726 }
727 },
728 last_years: {
729 matches: ['years'],
730 regexp: /^last\s+(\d*.?\d+)\s+years?$/i,
731 select: function (context, node) {
732 return filterByYear(Date.now() - YEAR * node.years, context)
733 }
734 },
735 since_y: {
736 matches: ['year'],
737 regexp: /^since (\d+)$/i,
738 select: sinceQuery
739 },
740 since_y_m: {
741 matches: ['year', 'month'],
742 regexp: /^since (\d+)-(\d+)$/i,
743 select: sinceQuery
744 },
745 since_y_m_d: {
746 matches: ['year', 'month', 'day'],
747 regexp: /^since (\d+)-(\d+)-(\d+)$/i,
748 select: sinceQuery
749 },
750 popularity: {
751 matches: ['sign', 'popularity'],
752 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%$/,
753 select: function (context, node) {
754 var popularity = parseFloat(node.popularity)
755 var usage = browserslist.usage.global
756 return Object.keys(usage).reduce(function (result, version) {
757 if (node.sign === '>') {
758 if (usage[version] > popularity) {
759 result.push(version)
760 }
761 } else if (node.sign === '<') {
762 if (usage[version] < popularity) {
763 result.push(version)
764 }
765 } else if (node.sign === '<=') {
766 if (usage[version] <= popularity) {
767 result.push(version)
768 }
769 } else if (usage[version] >= popularity) {
770 result.push(version)
771 }
772 return result
773 }, [])
774 }
775 },
776 popularity_in_my_stats: {
777 matches: ['sign', 'popularity'],
778 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+my\s+stats$/,
779 select: function (context, node) {
780 var popularity = parseFloat(node.popularity)
781 if (!context.customUsage) {
782 throw new BrowserslistError('Custom usage statistics was not provided')
783 }
784 var usage = context.customUsage
785 return Object.keys(usage).reduce(function (result, version) {
786 var percentage = usage[version]
787 if (percentage == null) {
788 return result
789 }
790
791 if (node.sign === '>') {
792 if (percentage > popularity) {
793 result.push(version)
794 }
795 } else if (node.sign === '<') {
796 if (percentage < popularity) {
797 result.push(version)
798 }
799 } else if (node.sign === '<=') {
800 if (percentage <= popularity) {
801 result.push(version)
802 }
803 } else if (percentage >= popularity) {
804 result.push(version)
805 }
806 return result
807 }, [])
808 }
809 },
810 popularity_in_config_stats: {
811 matches: ['sign', 'popularity', 'config'],
812 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+(\S+)\s+stats$/,
813 select: function (context, node) {
814 var popularity = parseFloat(node.popularity)
815 var stats = env.loadStat(context, node.config, browserslist.data)
816 if (stats) {
817 context.customUsage = {}
818 for (var browser in stats) {
819 fillUsage(context.customUsage, browser, stats[browser])
820 }
821 }
822 if (!context.customUsage) {
823 throw new BrowserslistError('Custom usage statistics was not provided')
824 }
825 var usage = context.customUsage
826 return Object.keys(usage).reduce(function (result, version) {
827 var percentage = usage[version]
828 if (percentage == null) {
829 return result
830 }
831
832 if (node.sign === '>') {
833 if (percentage > popularity) {
834 result.push(version)
835 }
836 } else if (node.sign === '<') {
837 if (percentage < popularity) {
838 result.push(version)
839 }
840 } else if (node.sign === '<=') {
841 if (percentage <= popularity) {
842 result.push(version)
843 }
844 } else if (percentage >= popularity) {
845 result.push(version)
846 }
847 return result
848 }, [])
849 }
850 },
851 popularity_in_place: {
852 matches: ['sign', 'popularity', 'place'],
853 regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+((alt-)?\w\w)$/,
854 select: function (context, node) {
855 var popularity = parseFloat(node.popularity)
856 var place = node.place
857 if (place.length === 2) {
858 place = place.toUpperCase()
859 } else {
860 place = place.toLowerCase()
861 }
862 env.loadCountry(browserslist.usage, place, browserslist.data)
863 var usage = browserslist.usage[place]
864 return Object.keys(usage).reduce(function (result, version) {
865 var percentage = usage[version]
866 if (percentage == null) {
867 return result
868 }
869
870 if (node.sign === '>') {
871 if (percentage > popularity) {
872 result.push(version)
873 }
874 } else if (node.sign === '<') {
875 if (percentage < popularity) {
876 result.push(version)
877 }
878 } else if (node.sign === '<=') {
879 if (percentage <= popularity) {
880 result.push(version)
881 }
882 } else if (percentage >= popularity) {
883 result.push(version)
884 }
885 return result
886 }, [])
887 }
888 },
889 cover: {
890 matches: ['coverage'],
891 regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%$/i,
892 select: coverQuery
893 },
894 cover_in: {
895 matches: ['coverage', 'place'],
896 regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%\s+in\s+(my\s+stats|(alt-)?\w\w)$/i,
897 select: coverQuery
898 },
899 supports: {
900 matches: ['supportType', 'feature'],
901 regexp: /^(?:(fully|partially)\s+)?supports\s+([\w-]+)$/,
902 select: function (context, node) {
903 env.loadFeature(browserslist.cache, node.feature)
904 var withPartial = node.supportType !== 'fully'
905 var features = browserslist.cache[node.feature]
906 var result = []
907 for (var name in features) {
908 var data = byName(name, context)
909 // Only check desktop when latest released mobile has support
910 var iMax = data.released.length - 1
911 while (iMax >= 0) {
912 if (data.released[iMax] in features[name]) break
913 iMax--
914 }
915 var checkDesktop =
916 context.mobileToDesktop &&
917 name in browserslist.desktopNames &&
918 isSupported(features[name][data.released[iMax]], withPartial)
919 data.versions.forEach(function (version) {
920 var flags = features[name][version]
921 if (flags === undefined && checkDesktop) {
922 flags = features[browserslist.desktopNames[name]][version]
923 }
924 if (isSupported(flags, withPartial)) {
925 result.push(name + ' ' + version)
926 }
927 })
928 }
929 return result
930 }
931 },
932 electron_range: {
933 matches: ['from', 'to'],
934 regexp: /^electron\s+([\d.]+)\s*-\s*([\d.]+)$/i,
935 select: function (context, node) {
936 var fromToUse = normalizeElectron(node.from)
937 var toToUse = normalizeElectron(node.to)
938 var from = parseFloat(node.from)
939 var to = parseFloat(node.to)
940 if (!e2c[fromToUse]) {
941 throw new BrowserslistError('Unknown version ' + from + ' of electron')
942 }
943 if (!e2c[toToUse]) {
944 throw new BrowserslistError('Unknown version ' + to + ' of electron')
945 }
946 return Object.keys(e2c)
947 .filter(function (i) {
948 var parsed = parseFloat(i)
949 return parsed >= from && parsed <= to
950 })
951 .map(function (i) {
952 return 'chrome ' + e2c[i]
953 })
954 }
955 },
956 node_range: {
957 matches: ['from', 'to'],
958 regexp: /^node\s+([\d.]+)\s*-\s*([\d.]+)$/i,
959 select: function (context, node) {
960 return browserslist.nodeVersions
961 .filter(semverFilterLoose('>=', node.from))
962 .filter(semverFilterLoose('<=', node.to))
963 .map(function (v) {
964 return 'node ' + v
965 })
966 }
967 },
968 browser_range: {
969 matches: ['browser', 'from', 'to'],
970 regexp: /^(\w+)\s+([\d.]+)\s*-\s*([\d.]+)$/i,
971 select: function (context, node) {
972 var data = checkName(node.browser, context)
973 var from = parseFloat(normalizeVersion(data, node.from) || node.from)
974 var to = parseFloat(normalizeVersion(data, node.to) || node.to)
975 function filter(v) {
976 var parsed = parseFloat(v)
977 return parsed >= from && parsed <= to
978 }
979 return data.released.filter(filter).map(nameMapper(data.name))
980 }
981 },
982 electron_ray: {
983 matches: ['sign', 'version'],
984 regexp: /^electron\s*(>=?|<=?)\s*([\d.]+)$/i,
985 select: function (context, node) {
986 var versionToUse = normalizeElectron(node.version)
987 return Object.keys(e2c)
988 .filter(generateFilter(node.sign, versionToUse))
989 .map(function (i) {
990 return 'chrome ' + e2c[i]
991 })
992 }
993 },
994 node_ray: {
995 matches: ['sign', 'version'],
996 regexp: /^node\s*(>=?|<=?)\s*([\d.]+)$/i,
997 select: function (context, node) {
998 return browserslist.nodeVersions
999 .filter(generateSemverFilter(node.sign, node.version))
1000 .map(function (v) {
1001 return 'node ' + v
1002 })
1003 }
1004 },
1005 browser_ray: {
1006 matches: ['browser', 'sign', 'version'],
1007 regexp: /^(\w+)\s*(>=?|<=?)\s*([\d.]+)$/,
1008 select: function (context, node) {
1009 var version = node.version
1010 var data = checkName(node.browser, context)
1011 var alias = browserslist.versionAliases[data.name][version]
1012 if (alias) version = alias
1013 return data.released
1014 .filter(generateFilter(node.sign, version))
1015 .map(function (v) {
1016 return data.name + ' ' + v
1017 })
1018 }
1019 },
1020 firefox_esr: {
1021 matches: [],
1022 regexp: /^(firefox|ff|fx)\s+esr$/i,
1023 select: function () {
1024 return ['firefox 115', 'firefox 128']
1025 }
1026 },
1027 opera_mini_all: {
1028 matches: [],
1029 regexp: /(operamini|op_mini)\s+all/i,
1030 select: function () {
1031 return ['op_mini all']
1032 }
1033 },
1034 electron_version: {
1035 matches: ['version'],
1036 regexp: /^electron\s+([\d.]+)$/i,
1037 select: function (context, node) {
1038 var versionToUse = normalizeElectron(node.version)
1039 var chrome = e2c[versionToUse]
1040 if (!chrome) {
1041 throw new BrowserslistError(
1042 'Unknown version ' + node.version + ' of electron'
1043 )
1044 }
1045 return ['chrome ' + chrome]
1046 }
1047 },
1048 node_major_version: {
1049 matches: ['version'],
1050 regexp: /^node\s+(\d+)$/i,
1051 select: nodeQuery
1052 },
1053 node_minor_version: {
1054 matches: ['version'],
1055 regexp: /^node\s+(\d+\.\d+)$/i,
1056 select: nodeQuery
1057 },
1058 node_patch_version: {
1059 matches: ['version'],
1060 regexp: /^node\s+(\d+\.\d+\.\d+)$/i,
1061 select: nodeQuery
1062 },
1063 current_node: {
1064 matches: [],
1065 regexp: /^current\s+node$/i,
1066 select: function (context) {
1067 return [env.currentNode(resolve, context)]
1068 }
1069 },
1070 maintained_node: {
1071 matches: [],
1072 regexp: /^maintained\s+node\s+versions$/i,
1073 select: function (context) {
1074 var now = Date.now()
1075 var queries = Object.keys(jsEOL)
1076 .filter(function (key) {
1077 return (
1078 now < Date.parse(jsEOL[key].end) &&
1079 now > Date.parse(jsEOL[key].start) &&
1080 isEolReleased(key)
1081 )
1082 })
1083 .map(function (key) {
1084 return 'node ' + key.slice(1)
1085 })
1086 return resolve(queries, context)
1087 }
1088 },
1089 phantomjs_1_9: {
1090 matches: [],
1091 regexp: /^phantomjs\s+1.9$/i,
1092 select: function () {
1093 return ['safari 5']
1094 }
1095 },
1096 phantomjs_2_1: {
1097 matches: [],
1098 regexp: /^phantomjs\s+2.1$/i,
1099 select: function () {
1100 return ['safari 6']
1101 }
1102 },
1103 browser_version: {
1104 matches: ['browser', 'version'],
1105 regexp: /^(\w+)\s+(tp|[\d.]+)$/i,
1106 select: function (context, node) {
1107 var version = node.version
1108 if (/^tp$/i.test(version)) version = 'TP'
1109 var data = checkName(node.browser, context)
1110 var alias = normalizeVersion(data, version)
1111 if (alias) {
1112 version = alias
1113 } else {
1114 if (version.indexOf('.') === -1) {
1115 alias = version + '.0'
1116 } else {
1117 alias = version.replace(/\.0$/, '')
1118 }
1119 alias = normalizeVersion(data, alias)
1120 if (alias) {
1121 version = alias
1122 } else if (context.ignoreUnknownVersions) {
1123 return []
1124 } else {
1125 throw new BrowserslistError(
1126 'Unknown version ' + version + ' of ' + node.browser
1127 )
1128 }
1129 }
1130 return [data.name + ' ' + version]
1131 }
1132 },
1133 browserslist_config: {
1134 matches: [],
1135 regexp: /^browserslist config$/i,
1136 select: function (context) {
1137 return browserslist(undefined, context)
1138 }
1139 },
1140 extends: {
1141 matches: ['config'],
1142 regexp: /^extends (.+)$/i,
1143 select: function (context, node) {
1144 return resolve(env.loadQueries(context, node.config), context)
1145 }
1146 },
1147 defaults: {
1148 matches: [],
1149 regexp: /^defaults$/i,
1150 select: function (context) {
1151 return resolve(browserslist.defaults, context)
1152 }
1153 },
1154 dead: {
1155 matches: [],
1156 regexp: /^dead$/i,
1157 select: function (context) {
1158 var dead = [
1159 'Baidu >= 0',
1160 'ie <= 11',
1161 'ie_mob <= 11',
1162 'bb <= 10',
1163 'op_mob <= 12.1',
1164 'samsung 4'
1165 ]
1166 return resolve(dead, context)
1167 }
1168 },
1169 unknown: {
1170 matches: [],
1171 regexp: /^(\w+)$/i,
1172 select: function (context, node) {
1173 if (byName(node.query, context)) {
1174 throw new BrowserslistError(
1175 'Specify versions in Browserslist query for browser ' + node.query
1176 )
1177 } else {
1178 throw unknownQuery(node.query)
1179 }
1180 }
1181 }
1182}
1183
1184// Get and convert Can I Use data
1185
1186;(function () {
1187 for (var name in agents) {
1188 var browser = agents[name]
1189 browserslist.data[name] = {
1190 name: name,
1191 versions: normalize(agents[name].versions),
1192 released: normalize(agents[name].versions.slice(0, -3)),
1193 releaseDate: agents[name].release_date
1194 }
1195 fillUsage(browserslist.usage.global, name, browser.usage_global)
1196
1197 browserslist.versionAliases[name] = {}
1198 for (var i = 0; i < browser.versions.length; i++) {
1199 var full = browser.versions[i]
1200 if (!full) continue
1201
1202 if (full.indexOf('-') !== -1) {
1203 var interval = full.split('-')
1204 for (var j = 0; j < interval.length; j++) {
1205 browserslist.versionAliases[name][interval[j]] = full
1206 }
1207 }
1208 }
1209 }
1210
1211 browserslist.nodeVersions = jsReleases.map(function (release) {
1212 return release.version
1213 })
1214})()
1215
1216module.exports = browserslist
Note: See TracBrowser for help on using the repository browser.