browserslist 4.20.2 → 4.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -5,13 +5,13 @@ var path = require('path')
5
5
  var e2c = require('electron-to-chromium/versions')
6
6
 
7
7
  var BrowserslistError = require('./error')
8
+ var parse = require('./parse')
8
9
  var env = require('./node') // Will load browser.js in webpack
9
10
 
10
11
  var YEAR = 365.259641 * 24 * 60 * 60 * 1000
11
12
  var ANDROID_EVERGREEN_FIRST = 37
12
13
 
13
- var QUERY_OR = 1
14
- var QUERY_AND = 2
14
+ // Helpers
15
15
 
16
16
  function isVersionsMatch(versionA, versionB) {
17
17
  return (versionA + '.').indexOf(versionB + '.') === 0
@@ -71,8 +71,6 @@ function uniq(array) {
71
71
  return filtered
72
72
  }
73
73
 
74
- // Helpers
75
-
76
74
  function fillUsage(result, name, data) {
77
75
  for (var i in data) {
78
76
  result[name + ' ' + i] = data[i]
@@ -229,7 +227,7 @@ function mapVersions(data, map) {
229
227
  data.versions = data.versions.map(function (i) {
230
228
  return map[i] || i
231
229
  })
232
- data.released = data.versions.map(function (i) {
230
+ data.released = data.released.map(function (i) {
233
231
  return map[i] || i
234
232
  })
235
233
  var fixedDate = {}
@@ -302,117 +300,62 @@ function filterAndroid(list, versions, context) {
302
300
  }
303
301
  }
304
302
 
305
- /**
306
- * Resolves queries into a browser list.
307
- * @param {string|string[]} queries Queries to combine.
308
- * Either an array of queries or a long string of queries.
309
- * @param {object} [context] Optional arguments to
310
- * the select function in `queries`.
311
- * @returns {string[]} A list of browsers
312
- */
313
303
  function resolve(queries, context) {
314
- if (Array.isArray(queries)) {
315
- queries = flatten(queries.map(parse))
316
- } else {
317
- queries = parse(queries)
318
- }
319
-
320
- return queries.reduce(function (result, query, index) {
321
- var selection = query.queryString
322
-
323
- var isExclude = selection.indexOf('not ') === 0
324
- if (isExclude) {
325
- if (index === 0) {
326
- throw new BrowserslistError(
327
- 'Write any browsers query (for instance, `defaults`) ' +
328
- 'before `' +
329
- selection +
330
- '`'
331
- )
332
- }
333
- selection = selection.slice(4)
304
+ return parse(QUERIES, queries).reduce(function (result, node, index) {
305
+ if (node.not && index === 0) {
306
+ throw new BrowserslistError(
307
+ 'Write any browsers query (for instance, `defaults`) ' +
308
+ 'before `' +
309
+ node.query +
310
+ '`'
311
+ )
334
312
  }
313
+ var type = QUERIES[node.type]
314
+ var array = type.select.call(browserslist, context, node).map(function (j) {
315
+ var parts = j.split(' ')
316
+ if (parts[1] === '0') {
317
+ return parts[0] + ' ' + byName(parts[0], context).versions[0]
318
+ } else {
319
+ return j
320
+ }
321
+ })
335
322
 
336
- for (var i = 0; i < QUERIES.length; i++) {
337
- var type = QUERIES[i]
338
- var match = selection.match(type.regexp)
339
- if (match) {
340
- var args = [context].concat(match.slice(1))
341
- var array = type.select.apply(browserslist, args).map(function (j) {
342
- var parts = j.split(' ')
343
- if (parts[1] === '0') {
344
- return parts[0] + ' ' + byName(parts[0], context).versions[0]
345
- } else {
346
- return j
347
- }
323
+ if (node.compose === 'and') {
324
+ if (node.not) {
325
+ return result.filter(function (j) {
326
+ return array.indexOf(j) === -1
327
+ })
328
+ } else {
329
+ return result.filter(function (j) {
330
+ return array.indexOf(j) !== -1
331
+ })
332
+ }
333
+ } else {
334
+ if (node.not) {
335
+ var filter = {}
336
+ array.forEach(function (j) {
337
+ filter[j] = true
338
+ })
339
+ return result.filter(function (j) {
340
+ return !filter[j]
348
341
  })
349
-
350
- switch (query.type) {
351
- case QUERY_AND:
352
- if (isExclude) {
353
- return result.filter(function (j) {
354
- return array.indexOf(j) === -1
355
- })
356
- } else {
357
- return result.filter(function (j) {
358
- return array.indexOf(j) !== -1
359
- })
360
- }
361
- case QUERY_OR:
362
- default:
363
- if (isExclude) {
364
- var filter = {}
365
- array.forEach(function (j) {
366
- filter[j] = true
367
- })
368
- return result.filter(function (j) {
369
- return !filter[j]
370
- })
371
- }
372
- return result.concat(array)
373
- }
374
342
  }
343
+ return result.concat(array)
375
344
  }
376
-
377
- throw unknownQuery(selection)
378
345
  }, [])
379
346
  }
380
347
 
381
- var cache = {}
382
-
383
- /**
384
- * Return array of browsers by selection queries.
385
- *
386
- * @param {(string|string[])} [queries=browserslist.defaults] Browser queries.
387
- * @param {object} [opts] Options.
388
- * @param {string} [opts.path="."] Path to processed file.
389
- * It will be used to find config files.
390
- * @param {string} [opts.env="production"] Processing environment.
391
- * It will be used to take right
392
- * queries from config file.
393
- * @param {string} [opts.config] Path to config file with queries.
394
- * @param {object} [opts.stats] Custom browser usage statistics
395
- * for "> 1% in my stats" query.
396
- * @param {boolean} [opts.ignoreUnknownVersions=false] Do not throw on unknown
397
- * version in direct query.
398
- * @param {boolean} [opts.dangerousExtend] Disable security checks
399
- * for extend query.
400
- * @param {boolean} [opts.throwOnMissing] Throw error on missing env.
401
- * @param {boolean} [opts.mobileToDesktop] Alias mobile browsers to the desktop
402
- * version when Can I Use doesn't have
403
- * data about the specified version.
404
- * @returns {string[]} Array with browser names in Can I Use.
405
- *
406
- * @example
407
- * browserslist('IE >= 10, IE 8') //=> ['ie 11', 'ie 10', 'ie 8']
408
- */
409
- function browserslist(queries, opts) {
348
+ function prepareOpts(opts) {
410
349
  if (typeof opts === 'undefined') opts = {}
411
350
 
412
351
  if (typeof opts.path === 'undefined') {
413
352
  opts.path = path.resolve ? path.resolve('.') : '.'
414
353
  }
415
354
 
355
+ return opts
356
+ }
357
+
358
+ function prepareQueries(queries, opts) {
416
359
  if (typeof queries === 'undefined' || queries === null) {
417
360
  var config = browserslist.loadConfig(opts)
418
361
  if (config) {
@@ -422,11 +365,23 @@ function browserslist(queries, opts) {
422
365
  }
423
366
  }
424
367
 
368
+ return queries
369
+ }
370
+
371
+ function checkQueries(queries) {
425
372
  if (!(typeof queries === 'string' || Array.isArray(queries))) {
426
373
  throw new BrowserslistError(
427
374
  'Browser queries must be an array or string. Got ' + typeof queries + '.'
428
375
  )
429
376
  }
377
+ }
378
+
379
+ var cache = {}
380
+
381
+ function browserslist(queries, opts) {
382
+ opts = prepareOpts(opts)
383
+ queries = prepareQueries(queries, opts)
384
+ checkQueries(queries)
430
385
 
431
386
  var context = {
432
387
  ignoreUnknownVersions: opts.ignoreUnknownVersions,
@@ -468,48 +423,11 @@ function browserslist(queries, opts) {
468
423
  return result
469
424
  }
470
425
 
471
- function parse(queries) {
472
- var qs = []
473
- do {
474
- queries = doMatch(queries, qs)
475
- } while (queries)
476
- return qs
477
- }
478
-
479
- function doMatch(string, qs) {
480
- var or = /^(?:,\s*|\s+or\s+)(.*)/i
481
- var and = /^\s+and\s+(.*)/i
482
-
483
- return find(string, function (parsed, n, max) {
484
- if (and.test(parsed)) {
485
- qs.unshift({ type: QUERY_AND, queryString: parsed.match(and)[1] })
486
- return true
487
- } else if (or.test(parsed)) {
488
- qs.unshift({ type: QUERY_OR, queryString: parsed.match(or)[1] })
489
- return true
490
- } else if (n === max) {
491
- qs.unshift({ type: QUERY_OR, queryString: parsed.trim() })
492
- return true
493
- }
494
- return false
495
- })
496
- }
497
-
498
- function find(string, predicate) {
499
- for (var n = 1, max = string.length; n <= max; n++) {
500
- var parsed = string.substr(-n, n)
501
- if (predicate(parsed, n, max)) {
502
- return string.slice(0, -n)
503
- }
504
- }
505
- return ''
506
- }
507
-
508
- function flatten(array) {
509
- if (!Array.isArray(array)) return [array]
510
- return array.reduce(function (a, b) {
511
- return a.concat(flatten(b))
512
- }, [])
426
+ browserslist.parse = function (queries, opts) {
427
+ opts = prepareOpts(opts)
428
+ queries = prepareQueries(queries, opts)
429
+ checkQueries(queries)
430
+ return parse(QUERIES, queries)
513
431
  }
514
432
 
515
433
  // Will be filled by Can I Use data below
@@ -558,20 +476,6 @@ browserslist.readConfig = env.readConfig
558
476
  browserslist.findConfig = env.findConfig
559
477
  browserslist.loadConfig = env.loadConfig
560
478
 
561
- /**
562
- * Return browsers market coverage.
563
- *
564
- * @param {string[]} browsers Browsers names in Can I Use.
565
- * @param {string|object} [stats="global"] Which statistics should be used.
566
- * Country code or custom statistics.
567
- * Pass `"my stats"` to load statistics
568
- * from Browserslist files.
569
- *
570
- * @return {number} Total market coverage for all selected browsers.
571
- *
572
- * @example
573
- * browserslist.coverage(browserslist('> 1% in US'), 'US') //=> 83.1
574
- */
575
479
  browserslist.coverage = function (browsers, stats) {
576
480
  var data
577
481
  if (typeof stats === 'undefined') {
@@ -616,42 +520,44 @@ browserslist.coverage = function (browsers, stats) {
616
520
  }, 0)
617
521
  }
618
522
 
619
- function nodeQuery(context, version) {
523
+ function nodeQuery(context, node) {
620
524
  var matched = browserslist.nodeVersions.filter(function (i) {
621
- return isVersionsMatch(i, version)
525
+ return isVersionsMatch(i, node.version)
622
526
  })
623
527
  if (matched.length === 0) {
624
528
  if (context.ignoreUnknownVersions) {
625
529
  return []
626
530
  } else {
627
- throw new BrowserslistError('Unknown version ' + version + ' of Node.js')
531
+ throw new BrowserslistError(
532
+ 'Unknown version ' + node.version + ' of Node.js'
533
+ )
628
534
  }
629
535
  }
630
536
  return ['node ' + matched[matched.length - 1]]
631
537
  }
632
538
 
633
- function sinceQuery(context, year, month, date) {
634
- year = parseInt(year)
635
- month = parseInt(month || '01') - 1
636
- date = parseInt(date || '01')
539
+ function sinceQuery(context, node) {
540
+ var year = parseInt(node.year)
541
+ var month = parseInt(node.month || '01') - 1
542
+ var date = parseInt(node.date || '01')
637
543
  return filterByYear(Date.UTC(year, month, date, 0, 0, 0), context)
638
544
  }
639
545
 
640
- function coverQuery(context, coverage, statMode) {
641
- coverage = parseFloat(coverage)
546
+ function coverQuery(context, node) {
547
+ var coverage = parseFloat(node.coverage)
642
548
  var usage = browserslist.usage.global
643
- if (statMode) {
644
- if (statMode.match(/^my\s+stats$/i)) {
549
+ if (node.place) {
550
+ if (node.place.match(/^my\s+stats$/i)) {
645
551
  if (!context.customUsage) {
646
552
  throw new BrowserslistError('Custom usage statistics was not provided')
647
553
  }
648
554
  usage = context.customUsage
649
555
  } else {
650
556
  var place
651
- if (statMode.length === 2) {
652
- place = statMode.toUpperCase()
557
+ if (node.place.length === 2) {
558
+ place = node.place.toUpperCase()
653
559
  } else {
654
- place = statMode.toLowerCase()
560
+ place = node.place.toLowerCase()
655
561
  }
656
562
  env.loadCountry(browserslist.usage, place, browserslist.data)
657
563
  usage = browserslist.usage[place]
@@ -673,98 +579,109 @@ function coverQuery(context, coverage, statMode) {
673
579
  return result
674
580
  }
675
581
 
676
- var QUERIES = [
677
- {
582
+ var QUERIES = {
583
+ last_major_versions: {
584
+ matches: ['versions'],
678
585
  regexp: /^last\s+(\d+)\s+major\s+versions?$/i,
679
- select: function (context, versions) {
586
+ select: function (context, node) {
680
587
  return Object.keys(agents).reduce(function (selected, name) {
681
588
  var data = byName(name, context)
682
589
  if (!data) return selected
683
- var list = getMajorVersions(data.released, versions)
590
+ var list = getMajorVersions(data.released, node.versions)
684
591
  list = list.map(nameMapper(data.name))
685
592
  if (data.name === 'android') {
686
- list = filterAndroid(list, versions, context)
593
+ list = filterAndroid(list, node.versions, context)
687
594
  }
688
595
  return selected.concat(list)
689
596
  }, [])
690
597
  }
691
598
  },
692
- {
599
+ last_versions: {
600
+ matches: ['versions'],
693
601
  regexp: /^last\s+(\d+)\s+versions?$/i,
694
- select: function (context, versions) {
602
+ select: function (context, node) {
695
603
  return Object.keys(agents).reduce(function (selected, name) {
696
604
  var data = byName(name, context)
697
605
  if (!data) return selected
698
- var list = data.released.slice(-versions)
606
+ var list = data.released.slice(-node.versions)
699
607
  list = list.map(nameMapper(data.name))
700
608
  if (data.name === 'android') {
701
- list = filterAndroid(list, versions, context)
609
+ list = filterAndroid(list, node.versions, context)
702
610
  }
703
611
  return selected.concat(list)
704
612
  }, [])
705
613
  }
706
614
  },
707
- {
615
+ last_electron_major_versions: {
616
+ matches: ['versions'],
708
617
  regexp: /^last\s+(\d+)\s+electron\s+major\s+versions?$/i,
709
- select: function (context, versions) {
710
- var validVersions = getMajorVersions(Object.keys(e2c), versions)
618
+ select: function (context, node) {
619
+ var validVersions = getMajorVersions(Object.keys(e2c), node.versions)
711
620
  return validVersions.map(function (i) {
712
621
  return 'chrome ' + e2c[i]
713
622
  })
714
623
  }
715
624
  },
716
- {
625
+ last_node_major_versions: {
626
+ matches: ['versions'],
717
627
  regexp: /^last\s+(\d+)\s+node\s+major\s+versions?$/i,
718
- select: function (context, versions) {
719
- return getMajorVersions(browserslist.nodeVersions, versions).map(
628
+ select: function (context, node) {
629
+ return getMajorVersions(browserslist.nodeVersions, node.versions).map(
720
630
  function (version) {
721
631
  return 'node ' + version
722
632
  }
723
633
  )
724
634
  }
725
635
  },
726
- {
636
+ last_browser_major_versions: {
637
+ matches: ['versions', 'browser'],
727
638
  regexp: /^last\s+(\d+)\s+(\w+)\s+major\s+versions?$/i,
728
- select: function (context, versions, name) {
729
- var data = checkName(name, context)
730
- var validVersions = getMajorVersions(data.released, versions)
639
+ select: function (context, node) {
640
+ var data = checkName(node.browser, context)
641
+ var validVersions = getMajorVersions(data.released, node.versions)
731
642
  var list = validVersions.map(nameMapper(data.name))
732
643
  if (data.name === 'android') {
733
- list = filterAndroid(list, versions, context)
644
+ list = filterAndroid(list, node.versions, context)
734
645
  }
735
646
  return list
736
647
  }
737
648
  },
738
- {
649
+ last_electron_versions: {
650
+ matches: ['versions'],
739
651
  regexp: /^last\s+(\d+)\s+electron\s+versions?$/i,
740
- select: function (context, versions) {
652
+ select: function (context, node) {
741
653
  return Object.keys(e2c)
742
- .slice(-versions)
654
+ .slice(-node.versions)
743
655
  .map(function (i) {
744
656
  return 'chrome ' + e2c[i]
745
657
  })
746
658
  }
747
659
  },
748
- {
660
+ last_node_versions: {
661
+ matches: ['versions'],
749
662
  regexp: /^last\s+(\d+)\s+node\s+versions?$/i,
750
- select: function (context, versions) {
751
- return browserslist.nodeVersions.slice(-versions).map(function (version) {
752
- return 'node ' + version
753
- })
663
+ select: function (context, node) {
664
+ return browserslist.nodeVersions
665
+ .slice(-node.versions)
666
+ .map(function (version) {
667
+ return 'node ' + version
668
+ })
754
669
  }
755
670
  },
756
- {
671
+ last_browser_versions: {
672
+ matches: ['versions', 'browser'],
757
673
  regexp: /^last\s+(\d+)\s+(\w+)\s+versions?$/i,
758
- select: function (context, versions, name) {
759
- var data = checkName(name, context)
760
- var list = data.released.slice(-versions).map(nameMapper(data.name))
674
+ select: function (context, node) {
675
+ var data = checkName(node.browser, context)
676
+ var list = data.released.slice(-node.versions).map(nameMapper(data.name))
761
677
  if (data.name === 'android') {
762
- list = filterAndroid(list, versions, context)
678
+ list = filterAndroid(list, node.versions, context)
763
679
  }
764
680
  return list
765
681
  }
766
682
  },
767
- {
683
+ unreleased_versions: {
684
+ matches: [],
768
685
  regexp: /^unreleased\s+versions$/i,
769
686
  select: function (context) {
770
687
  return Object.keys(agents).reduce(function (selected, name) {
@@ -778,16 +695,18 @@ var QUERIES = [
778
695
  }, [])
779
696
  }
780
697
  },
781
- {
698
+ unreleased_electron_versions: {
699
+ matches: [],
782
700
  regexp: /^unreleased\s+electron\s+versions?$/i,
783
701
  select: function () {
784
702
  return []
785
703
  }
786
704
  },
787
- {
705
+ unreleased_browser_versions: {
706
+ matches: ['browser'],
788
707
  regexp: /^unreleased\s+(\w+)\s+versions?$/i,
789
- select: function (context, name) {
790
- var data = checkName(name, context)
708
+ select: function (context, node) {
709
+ var data = checkName(node.browser, context)
791
710
  return data.versions
792
711
  .filter(function (v) {
793
712
  return data.released.indexOf(v) === -1
@@ -795,39 +714,44 @@ var QUERIES = [
795
714
  .map(nameMapper(data.name))
796
715
  }
797
716
  },
798
- {
717
+ last_years: {
718
+ matches: ['years'],
799
719
  regexp: /^last\s+(\d*.?\d+)\s+years?$/i,
800
- select: function (context, years) {
801
- return filterByYear(Date.now() - YEAR * years, context)
720
+ select: function (context, node) {
721
+ return filterByYear(Date.now() - YEAR * node.years, context)
802
722
  }
803
723
  },
804
- {
724
+ since_y: {
725
+ matches: ['year'],
805
726
  regexp: /^since (\d+)$/i,
806
727
  select: sinceQuery
807
728
  },
808
- {
729
+ since_y_m: {
730
+ matches: ['year', 'month'],
809
731
  regexp: /^since (\d+)-(\d+)$/i,
810
732
  select: sinceQuery
811
733
  },
812
- {
734
+ since_y_m_d: {
735
+ matches: ['year', 'month', 'day'],
813
736
  regexp: /^since (\d+)-(\d+)-(\d+)$/i,
814
737
  select: sinceQuery
815
738
  },
816
- {
739
+ popularity: {
740
+ matches: ['sign', 'popularity'],
817
741
  regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%$/,
818
- select: function (context, sign, popularity) {
819
- popularity = parseFloat(popularity)
742
+ select: function (context, node) {
743
+ var popularity = parseFloat(node.popularity)
820
744
  var usage = browserslist.usage.global
821
745
  return Object.keys(usage).reduce(function (result, version) {
822
- if (sign === '>') {
746
+ if (node.sign === '>') {
823
747
  if (usage[version] > popularity) {
824
748
  result.push(version)
825
749
  }
826
- } else if (sign === '<') {
750
+ } else if (node.sign === '<') {
827
751
  if (usage[version] < popularity) {
828
752
  result.push(version)
829
753
  }
830
- } else if (sign === '<=') {
754
+ } else if (node.sign === '<=') {
831
755
  if (usage[version] <= popularity) {
832
756
  result.push(version)
833
757
  }
@@ -838,10 +762,11 @@ var QUERIES = [
838
762
  }, [])
839
763
  }
840
764
  },
841
- {
765
+ popularity_in_my_stats: {
766
+ matches: ['sign', 'popularity'],
842
767
  regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+my\s+stats$/,
843
- select: function (context, sign, popularity) {
844
- popularity = parseFloat(popularity)
768
+ select: function (context, node) {
769
+ var popularity = parseFloat(node.popularity)
845
770
  if (!context.customUsage) {
846
771
  throw new BrowserslistError('Custom usage statistics was not provided')
847
772
  }
@@ -852,15 +777,15 @@ var QUERIES = [
852
777
  return result
853
778
  }
854
779
 
855
- if (sign === '>') {
780
+ if (node.sign === '>') {
856
781
  if (percentage > popularity) {
857
782
  result.push(version)
858
783
  }
859
- } else if (sign === '<') {
784
+ } else if (node.sign === '<') {
860
785
  if (percentage < popularity) {
861
786
  result.push(version)
862
787
  }
863
- } else if (sign === '<=') {
788
+ } else if (node.sign === '<=') {
864
789
  if (percentage <= popularity) {
865
790
  result.push(version)
866
791
  }
@@ -871,11 +796,12 @@ var QUERIES = [
871
796
  }, [])
872
797
  }
873
798
  },
874
- {
799
+ popularity_in_config_stats: {
800
+ matches: ['sign', 'popularity', 'config'],
875
801
  regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+(\S+)\s+stats$/,
876
- select: function (context, sign, popularity, name) {
877
- popularity = parseFloat(popularity)
878
- var stats = env.loadStat(context, name, browserslist.data)
802
+ select: function (context, node) {
803
+ var popularity = parseFloat(node.popularity)
804
+ var stats = env.loadStat(context, node.config, browserslist.data)
879
805
  if (stats) {
880
806
  context.customUsage = {}
881
807
  for (var browser in stats) {
@@ -892,15 +818,15 @@ var QUERIES = [
892
818
  return result
893
819
  }
894
820
 
895
- if (sign === '>') {
821
+ if (node.sign === '>') {
896
822
  if (percentage > popularity) {
897
823
  result.push(version)
898
824
  }
899
- } else if (sign === '<') {
825
+ } else if (node.sign === '<') {
900
826
  if (percentage < popularity) {
901
827
  result.push(version)
902
828
  }
903
- } else if (sign === '<=') {
829
+ } else if (node.sign === '<=') {
904
830
  if (percentage <= popularity) {
905
831
  result.push(version)
906
832
  }
@@ -911,10 +837,12 @@ var QUERIES = [
911
837
  }, [])
912
838
  }
913
839
  },
914
- {
840
+ popularity_in_place: {
841
+ matches: ['sign', 'popularity', 'place'],
915
842
  regexp: /^(>=?|<=?)\s*(\d+|\d+\.\d+|\.\d+)%\s+in\s+((alt-)?\w\w)$/,
916
- select: function (context, sign, popularity, place) {
917
- popularity = parseFloat(popularity)
843
+ select: function (context, node) {
844
+ var popularity = parseFloat(node.popularity)
845
+ var place = node.place
918
846
  if (place.length === 2) {
919
847
  place = place.toUpperCase()
920
848
  } else {
@@ -928,15 +856,15 @@ var QUERIES = [
928
856
  return result
929
857
  }
930
858
 
931
- if (sign === '>') {
859
+ if (node.sign === '>') {
932
860
  if (percentage > popularity) {
933
861
  result.push(version)
934
862
  }
935
- } else if (sign === '<') {
863
+ } else if (node.sign === '<') {
936
864
  if (percentage < popularity) {
937
865
  result.push(version)
938
866
  }
939
- } else if (sign === '<=') {
867
+ } else if (node.sign === '<=') {
940
868
  if (percentage <= popularity) {
941
869
  result.push(version)
942
870
  }
@@ -947,19 +875,22 @@ var QUERIES = [
947
875
  }, [])
948
876
  }
949
877
  },
950
- {
878
+ cover: {
879
+ matches: ['coverage'],
951
880
  regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%$/i,
952
881
  select: coverQuery
953
882
  },
954
- {
883
+ cover_in: {
884
+ matches: ['coverage', 'place'],
955
885
  regexp: /^cover\s+(\d+|\d+\.\d+|\.\d+)%\s+in\s+(my\s+stats|(alt-)?\w\w)$/i,
956
886
  select: coverQuery
957
887
  },
958
- {
888
+ supports: {
889
+ matches: ['feature'],
959
890
  regexp: /^supports\s+([\w-]+)$/,
960
- select: function (context, feature) {
961
- env.loadFeature(browserslist.cache, feature)
962
- var features = browserslist.cache[feature]
891
+ select: function (context, node) {
892
+ env.loadFeature(browserslist.cache, node.feature)
893
+ var features = browserslist.cache[node.feature]
963
894
  return Object.keys(features).reduce(function (result, version) {
964
895
  var flags = features[version]
965
896
  if (flags.indexOf('y') >= 0 || flags.indexOf('a') >= 0) {
@@ -969,19 +900,20 @@ var QUERIES = [
969
900
  }, [])
970
901
  }
971
902
  },
972
- {
903
+ electron_range: {
904
+ matches: ['from', 'to'],
973
905
  regexp: /^electron\s+([\d.]+)\s*-\s*([\d.]+)$/i,
974
- select: function (context, from, to) {
975
- var fromToUse = normalizeElectron(from)
976
- var toToUse = normalizeElectron(to)
906
+ select: function (context, node) {
907
+ var fromToUse = normalizeElectron(node.from)
908
+ var toToUse = normalizeElectron(node.to)
909
+ var from = parseFloat(node.from)
910
+ var to = parseFloat(node.to)
977
911
  if (!e2c[fromToUse]) {
978
912
  throw new BrowserslistError('Unknown version ' + from + ' of electron')
979
913
  }
980
914
  if (!e2c[toToUse]) {
981
915
  throw new BrowserslistError('Unknown version ' + to + ' of electron')
982
916
  }
983
- from = parseFloat(from)
984
- to = parseFloat(to)
985
917
  return Object.keys(e2c)
986
918
  .filter(function (i) {
987
919
  var parsed = parseFloat(i)
@@ -992,23 +924,25 @@ var QUERIES = [
992
924
  })
993
925
  }
994
926
  },
995
- {
927
+ node_range: {
928
+ matches: ['from', 'to'],
996
929
  regexp: /^node\s+([\d.]+)\s*-\s*([\d.]+)$/i,
997
- select: function (context, from, to) {
930
+ select: function (context, node) {
998
931
  return browserslist.nodeVersions
999
- .filter(semverFilterLoose('>=', from))
1000
- .filter(semverFilterLoose('<=', to))
932
+ .filter(semverFilterLoose('>=', node.from))
933
+ .filter(semverFilterLoose('<=', node.to))
1001
934
  .map(function (v) {
1002
935
  return 'node ' + v
1003
936
  })
1004
937
  }
1005
938
  },
1006
- {
939
+ browser_range: {
940
+ matches: ['browser', 'from', 'to'],
1007
941
  regexp: /^(\w+)\s+([\d.]+)\s*-\s*([\d.]+)$/i,
1008
- select: function (context, name, from, to) {
1009
- var data = checkName(name, context)
1010
- from = parseFloat(normalizeVersion(data, from) || from)
1011
- to = parseFloat(normalizeVersion(data, to) || to)
942
+ select: function (context, node) {
943
+ var data = checkName(node.browser, context)
944
+ var from = parseFloat(normalizeVersion(data, node.from) || node.from)
945
+ var to = parseFloat(normalizeVersion(data, node.to) || node.to)
1012
946
  function filter(v) {
1013
947
  var parsed = parseFloat(v)
1014
948
  return parsed >= from && parsed <= to
@@ -1016,86 +950,96 @@ var QUERIES = [
1016
950
  return data.released.filter(filter).map(nameMapper(data.name))
1017
951
  }
1018
952
  },
1019
- {
953
+ electron_ray: {
954
+ matches: ['sign', 'version'],
1020
955
  regexp: /^electron\s*(>=?|<=?)\s*([\d.]+)$/i,
1021
- select: function (context, sign, version) {
1022
- var versionToUse = normalizeElectron(version)
956
+ select: function (context, node) {
957
+ var versionToUse = normalizeElectron(node.version)
1023
958
  return Object.keys(e2c)
1024
- .filter(generateFilter(sign, versionToUse))
959
+ .filter(generateFilter(node.sign, versionToUse))
1025
960
  .map(function (i) {
1026
961
  return 'chrome ' + e2c[i]
1027
962
  })
1028
963
  }
1029
964
  },
1030
- {
965
+ node_ray: {
966
+ matches: ['sign', 'version'],
1031
967
  regexp: /^node\s*(>=?|<=?)\s*([\d.]+)$/i,
1032
- select: function (context, sign, version) {
968
+ select: function (context, node) {
1033
969
  return browserslist.nodeVersions
1034
- .filter(generateSemverFilter(sign, version))
970
+ .filter(generateSemverFilter(node.sign, node.version))
1035
971
  .map(function (v) {
1036
972
  return 'node ' + v
1037
973
  })
1038
974
  }
1039
975
  },
1040
- {
976
+ browser_ray: {
977
+ matches: ['browser', 'sign', 'version'],
1041
978
  regexp: /^(\w+)\s*(>=?|<=?)\s*([\d.]+)$/,
1042
- select: function (context, name, sign, version) {
1043
- var data = checkName(name, context)
979
+ select: function (context, node) {
980
+ var version = node.version
981
+ var data = checkName(node.browser, context)
1044
982
  var alias = browserslist.versionAliases[data.name][version]
1045
- if (alias) {
1046
- version = alias
1047
- }
983
+ if (alias) version = alias
1048
984
  return data.released
1049
- .filter(generateFilter(sign, version))
985
+ .filter(generateFilter(node.sign, version))
1050
986
  .map(function (v) {
1051
987
  return data.name + ' ' + v
1052
988
  })
1053
989
  }
1054
990
  },
1055
- {
991
+ firefox_esr: {
992
+ matches: [],
1056
993
  regexp: /^(firefox|ff|fx)\s+esr$/i,
1057
994
  select: function () {
1058
995
  return ['firefox 91']
1059
996
  }
1060
997
  },
1061
- {
998
+ opera_mini_all: {
999
+ matches: [],
1062
1000
  regexp: /(operamini|op_mini)\s+all/i,
1063
1001
  select: function () {
1064
1002
  return ['op_mini all']
1065
1003
  }
1066
1004
  },
1067
- {
1005
+ electron_version: {
1006
+ matches: ['version'],
1068
1007
  regexp: /^electron\s+([\d.]+)$/i,
1069
- select: function (context, version) {
1070
- var versionToUse = normalizeElectron(version)
1008
+ select: function (context, node) {
1009
+ var versionToUse = normalizeElectron(node.version)
1071
1010
  var chrome = e2c[versionToUse]
1072
1011
  if (!chrome) {
1073
1012
  throw new BrowserslistError(
1074
- 'Unknown version ' + version + ' of electron'
1013
+ 'Unknown version ' + node.version + ' of electron'
1075
1014
  )
1076
1015
  }
1077
1016
  return ['chrome ' + chrome]
1078
1017
  }
1079
1018
  },
1080
- {
1019
+ node_major_version: {
1020
+ matches: ['version'],
1081
1021
  regexp: /^node\s+(\d+)$/i,
1082
1022
  select: nodeQuery
1083
1023
  },
1084
- {
1024
+ node_minor_version: {
1025
+ matches: ['version'],
1085
1026
  regexp: /^node\s+(\d+\.\d+)$/i,
1086
1027
  select: nodeQuery
1087
1028
  },
1088
- {
1029
+ node_patch_version: {
1030
+ matches: ['version'],
1089
1031
  regexp: /^node\s+(\d+\.\d+\.\d+)$/i,
1090
1032
  select: nodeQuery
1091
1033
  },
1092
- {
1034
+ current_node: {
1035
+ matches: [],
1093
1036
  regexp: /^current\s+node$/i,
1094
1037
  select: function (context) {
1095
1038
  return [env.currentNode(resolve, context)]
1096
1039
  }
1097
1040
  },
1098
- {
1041
+ maintained_node: {
1042
+ matches: [],
1099
1043
  regexp: /^maintained\s+node\s+versions$/i,
1100
1044
  select: function (context) {
1101
1045
  var now = Date.now()
@@ -1113,23 +1057,27 @@ var QUERIES = [
1113
1057
  return resolve(queries, context)
1114
1058
  }
1115
1059
  },
1116
- {
1060
+ phantomjs_1_9: {
1061
+ matches: [],
1117
1062
  regexp: /^phantomjs\s+1.9$/i,
1118
1063
  select: function () {
1119
1064
  return ['safari 5']
1120
1065
  }
1121
1066
  },
1122
- {
1067
+ phantomjs_2_1: {
1068
+ matches: [],
1123
1069
  regexp: /^phantomjs\s+2.1$/i,
1124
1070
  select: function () {
1125
1071
  return ['safari 6']
1126
1072
  }
1127
1073
  },
1128
- {
1074
+ browser_version: {
1075
+ matches: ['browser', 'version'],
1129
1076
  regexp: /^(\w+)\s+(tp|[\d.]+)$/i,
1130
- select: function (context, name, version) {
1077
+ select: function (context, node) {
1078
+ var version = node.version
1131
1079
  if (/^tp$/i.test(version)) version = 'TP'
1132
- var data = checkName(name, context)
1080
+ var data = checkName(node.browser, context)
1133
1081
  var alias = normalizeVersion(data, version)
1134
1082
  if (alias) {
1135
1083
  version = alias
@@ -1146,36 +1094,41 @@ var QUERIES = [
1146
1094
  return []
1147
1095
  } else {
1148
1096
  throw new BrowserslistError(
1149
- 'Unknown version ' + version + ' of ' + name
1097
+ 'Unknown version ' + version + ' of ' + node.browser
1150
1098
  )
1151
1099
  }
1152
1100
  }
1153
1101
  return [data.name + ' ' + version]
1154
1102
  }
1155
1103
  },
1156
- {
1104
+ browserslist_config: {
1105
+ matches: [],
1157
1106
  regexp: /^browserslist config$/i,
1158
1107
  select: function (context) {
1159
1108
  return browserslist(undefined, context)
1160
1109
  }
1161
1110
  },
1162
- {
1111
+ extends: {
1112
+ matches: ['config'],
1163
1113
  regexp: /^extends (.+)$/i,
1164
- select: function (context, name) {
1165
- return resolve(env.loadQueries(context, name), context)
1114
+ select: function (context, node) {
1115
+ return resolve(env.loadQueries(context, node.config), context)
1166
1116
  }
1167
1117
  },
1168
- {
1118
+ defaults: {
1119
+ matches: [],
1169
1120
  regexp: /^defaults$/i,
1170
1121
  select: function (context) {
1171
1122
  return resolve(browserslist.defaults, context)
1172
1123
  }
1173
1124
  },
1174
- {
1125
+ dead: {
1126
+ matches: [],
1175
1127
  regexp: /^dead$/i,
1176
1128
  select: function (context) {
1177
1129
  var dead = [
1178
- 'ie <= 10',
1130
+ 'Baidu >= 0',
1131
+ 'ie <= 11',
1179
1132
  'ie_mob <= 11',
1180
1133
  'bb <= 10',
1181
1134
  'op_mob <= 12.1',
@@ -1184,19 +1137,20 @@ var QUERIES = [
1184
1137
  return resolve(dead, context)
1185
1138
  }
1186
1139
  },
1187
- {
1140
+ unknown: {
1141
+ matches: [],
1188
1142
  regexp: /^(\w+)$/i,
1189
- select: function (context, name) {
1190
- if (byName(name, context)) {
1143
+ select: function (context, node) {
1144
+ if (byName(node.query, context)) {
1191
1145
  throw new BrowserslistError(
1192
- 'Specify versions in Browserslist query for browser ' + name
1146
+ 'Specify versions in Browserslist query for browser ' + node.query
1193
1147
  )
1194
1148
  } else {
1195
- throw unknownQuery(name)
1149
+ throw unknownQuery(node.query)
1196
1150
  }
1197
1151
  }
1198
1152
  }
1199
- ]
1153
+ }
1200
1154
 
1201
1155
  // Get and convert Can I Use data
1202
1156