.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / browserslist / index.js
1 var path = require('path')
2 var e2c = require('electron-to-chromium/versions')
3
4 var agents = require('caniuse-lite/dist/unpacker/agents').agents
5 var region = require('caniuse-lite/dist/unpacker/region').default
6
7 var BrowserslistError = require('./error')
8 var env = require('./node') // Will load browser.js in webpack
9
10 var FLOAT_RANGE = /^\d+(\.\d+)?(-\d+(\.\d+)?)*$/
11
12 function normalize (versions) {
13   return versions.filter(function (version) {
14     return typeof version === 'string'
15   })
16 }
17
18 function nameMapper (name) {
19   return function mapName (version) {
20     return name + ' ' + version
21   }
22 }
23
24 function getMajor (version) {
25   return parseInt(version.split('.')[0])
26 }
27
28 function getMajorVersions (released, number) {
29   if (released.length === 0) return []
30   var minimum = getMajor(released[released.length - 1]) - parseInt(number) + 1
31   var selected = []
32   for (var i = released.length - 1; i >= 0; i--) {
33     if (minimum > getMajor(released[i])) break
34     selected.unshift(released[i])
35   }
36   return selected
37 }
38
39 function uniq (array) {
40   var filtered = []
41   for (var i = 0; i < array.length; i++) {
42     if (filtered.indexOf(array[i]) === -1) filtered.push(array[i])
43   }
44   return filtered
45 }
46
47 // Helpers
48
49 function fillUsage (result, name, data) {
50   for (var i in data) {
51     result[name + ' ' + i] = data[i]
52   }
53 }
54
55 function generateFilter (sign, version) {
56   version = parseFloat(version)
57   if (sign === '>') {
58     return function (v) {
59       return parseFloat(v) > version
60     }
61   } else if (sign === '>=') {
62     return function (v) {
63       return parseFloat(v) >= version
64     }
65   } else if (sign === '<') {
66     return function (v) {
67       return parseFloat(v) < version
68     }
69   } else {
70     return function (v) {
71       return parseFloat(v) <= version
72     }
73   }
74 }
75
76 function compareStrings (a, b) {
77   if (a < b) return -1
78   if (a > b) return +1
79   return 0
80 }
81
82 function normalizeVersion (data, version) {
83   if (data.versions.indexOf(version) !== -1) {
84     return version
85   } else if (browserslist.versionAliases[data.name][version]) {
86     return browserslist.versionAliases[data.name][version]
87   } else if (data.versions.length === 1) {
88     return data.versions[0]
89   } else {
90     return false
91   }
92 }
93
94 function loadCountryStatistics (country) {
95   country = country.replace(/[^\w-]/g, '')
96   if (!browserslist.usage[country]) {
97     var usage = { }
98     // eslint-disable-next-line security/detect-non-literal-require
99     var compressed = require('caniuse-lite/data/regions/' + country + '.js')
100     var data = region(compressed)
101     for (var i in data) {
102       fillUsage(usage, i, data[i])
103     }
104     browserslist.usage[country] = usage
105   }
106 }
107
108 function filterByYear (since) {
109   return Object.keys(agents).reduce(function (selected, name) {
110     var data = byName(name)
111     if (!data) return selected
112     var versions = Object.keys(data.releaseDate).filter(function (v) {
113       return data.releaseDate[v] >= since
114     })
115     return selected.concat(versions.map(nameMapper(data.name)))
116   }, [])
117 }
118
119 function byName (name) {
120   name = name.toLowerCase()
121   name = browserslist.aliases[name] || name
122   return browserslist.data[name]
123 }
124
125 function checkName (name) {
126   var data = byName(name)
127   if (!data) throw new BrowserslistError('Unknown browser ' + name)
128   return data
129 }
130
131 function resolve (queries, context) {
132   return queries.reduce(function (result, selection, index) {
133     selection = selection.trim()
134     if (selection === '') return result
135
136     var isExclude = selection.indexOf('not ') === 0
137     if (isExclude) {
138       if (index === 0) {
139         throw new BrowserslistError(
140           'Write any browsers query (for instance, `defaults`) ' +
141           'before `' + selection + '`')
142       }
143       selection = selection.slice(4)
144     }
145
146     for (var i = 0; i < QUERIES.length; i++) {
147       var type = QUERIES[i]
148       var match = selection.match(type.regexp)
149       if (match) {
150         var args = [context].concat(match.slice(1))
151         var array = type.select.apply(browserslist, args)
152         if (isExclude) {
153           array = array.concat(array.map(function (j) {
154             return j.replace(/\s\d+/, ' 0')
155           }))
156           return result.filter(function (j) {
157             return array.indexOf(j) === -1
158           })
159         }
160         return result.concat(array)
161       }
162     }
163
164     throw new BrowserslistError('Unknown browser query `' + selection + '`')
165   }, [])
166 }
167
168 /**
169  * Return array of browsers by selection queries.
170  *
171  * @param {(string|string[])} [queries=browserslist.defaults] Browser queries.
172  * @param {object} opts Options.
173  * @param {string} [opts.path="."] Path to processed file.
174  *                                 It will be used to find config files.
175  * @param {string} [opts.env="development"] Processing environment.
176  *                                          It will be used to take right
177  *                                          queries from config file.
178  * @param {string} [opts.config] Path to config file with queries.
179  * @param {object} [opts.stats] Custom browser usage statistics
180  *                              for "> 1% in my stats" query.
181  * @return {string[]} Array with browser names in Can I Use.
182  *
183  * @example
184  * browserslist('IE >= 10, IE 8') //=> ['ie 11', 'ie 10', 'ie 8']
185  */
186 function browserslist (queries, opts) {
187   if (typeof opts === 'undefined') opts = { }
188
189   if (!opts.hasOwnProperty('path')) {
190     opts.path = path.resolve ? path.resolve('.') : '.'
191   }
192
193   if (typeof queries === 'undefined' || queries === null) {
194     var config = env.loadConfig(opts)
195     if (config) {
196       queries = config
197     } else {
198       queries = browserslist.defaults
199     }
200   }
201
202   if (typeof queries === 'string') {
203     queries = queries.split(/,\s*/)
204   }
205
206   if (!Array.isArray(queries)) {
207     throw new BrowserslistError(
208       'Browser queries must be an array. Got ' + typeof queries + '.')
209   }
210
211   var context = { dangerousExtend: opts.dangerousExtend }
212
213   var stats = env.getStat(opts)
214   if (stats) {
215     if ('dataByBrowser' in stats) {
216       stats = stats.dataByBrowser
217     }
218     context.customUsage = { }
219     for (var browser in stats) {
220       fillUsage(context.customUsage, browser, stats[browser])
221     }
222   }
223
224   var result = resolve(queries, context).map(function (i) {
225     var parts = i.split(' ')
226     var name = parts[0]
227     var version = parts[1]
228     if (version === '0') {
229       return name + ' ' + byName(name).versions[0]
230     } else {
231       return i
232     }
233   }).sort(function (name1, name2) {
234     name1 = name1.split(' ')
235     name2 = name2.split(' ')
236     if (name1[0] === name2[0]) {
237       if (FLOAT_RANGE.test(name1[1]) && FLOAT_RANGE.test(name2[1])) {
238         return parseFloat(name2[1]) - parseFloat(name1[1])
239       } else {
240         return compareStrings(name2[1], name1[1])
241       }
242     } else {
243       return compareStrings(name1[0], name2[0])
244     }
245   })
246
247   return uniq(result)
248 }
249
250 // Will be filled by Can I Use data below
251 browserslist.data = { }
252 browserslist.usage = {
253   global: { },
254   custom: null
255 }
256
257 // Default browsers query
258 browserslist.defaults = [
259   '> 1%',
260   'last 2 versions',
261   'Firefox ESR'
262 ]
263
264 // Browser names aliases
265 browserslist.aliases = {
266   fx: 'firefox',
267   ff: 'firefox',
268   ios: 'ios_saf',
269   explorer: 'ie',
270   blackberry: 'bb',
271   explorermobile: 'ie_mob',
272   operamini: 'op_mini',
273   operamobile: 'op_mob',
274   chromeandroid: 'and_chr',
275   firefoxandroid: 'and_ff',
276   ucandroid: 'and_uc',
277   qqandroid: 'and_qq'
278 }
279
280 // Aliases to work with joined versions like `ios_saf 7.0-7.1`
281 browserslist.versionAliases = { }
282
283 browserslist.clearCaches = env.clearCaches
284 browserslist.parseConfig = env.parseConfig
285 browserslist.readConfig = env.readConfig
286 browserslist.findConfig = env.findConfig
287
288 /**
289  * Return browsers market coverage.
290  *
291  * @param {string[]} browsers Browsers names in Can I Use.
292  * @param {string} [country="global"] Which country statistics should be used.
293  *
294  * @return {number} Total market coverage for all selected browsers.
295  *
296  * @example
297  * browserslist.coverage(browserslist('> 1% in US'), 'US') //=> 83.1
298  */
299 browserslist.coverage = function (browsers, country) {
300   if (country && country !== 'global') {
301     if (country.length > 2) {
302       country = country.toLowerCase()
303     } else {
304       country = country.toUpperCase()
305     }
306     loadCountryStatistics(country)
307   } else {
308     country = 'global'
309   }
310
311   return browsers.reduce(function (all, i) {
312     var usage = browserslist.usage[country][i]
313     if (usage === undefined) {
314       usage = browserslist.usage[country][i.replace(/ [\d.]+$/, ' 0')]
315     }
316     return all + (usage || 0)
317   }, 0)
318 }
319
320 var QUERIES = [
321   {
322     regexp: /^last\s+(\d+)\s+major versions?$/i,
323     select: function (context, versions) {
324       return Object.keys(agents).reduce(function (selected, name) {
325         var data = byName(name)
326         if (!data) return selected
327         var array = getMajorVersions(data.released, versions)
328
329         array = array.map(nameMapper(data.name))
330         return selected.concat(array)
331       }, [])
332     }
333   },
334   {
335     regexp: /^last\s+(\d+)\s+versions?$/i,
336     select: function (context, versions) {
337       return Object.keys(agents).reduce(function (selected, name) {
338         var data = byName(name)
339         if (!data) return selected
340         var array = data.released.slice(-versions)
341
342         array = array.map(nameMapper(data.name))
343         return selected.concat(array)
344       }, [])
345     }
346   },
347   {
348     regexp: /^last\s+(\d+)\s+electron\s+major versions?$/i,
349     select: function (context, versions) {
350       var validVersions = getMajorVersions(Object.keys(e2c).reverse(), versions)
351       return validVersions.map(function (i) {
352         return 'chrome ' + e2c[i]
353       })
354     }
355   },
356   {
357     regexp: /^last\s+(\d+)\s+(\w+)\s+major versions?$/i,
358     select: function (context, versions, name) {
359       var data = checkName(name)
360       var validVersions = getMajorVersions(data.released, versions)
361       return validVersions.map(nameMapper(data.name))
362     }
363   },
364   {
365     regexp: /^last\s+(\d+)\s+electron\s+versions?$/i,
366     select: function (context, versions) {
367       return Object.keys(e2c).reverse().slice(-versions).map(function (i) {
368         return 'chrome ' + e2c[i]
369       })
370     }
371   },
372   {
373     regexp: /^last\s+(\d+)\s+(\w+)\s+versions?$/i,
374     select: function (context, versions, name) {
375       var data = checkName(name)
376       return data.released.slice(-versions).map(nameMapper(data.name))
377     }
378   },
379   {
380     regexp: /^unreleased\s+versions$/i,
381     select: function () {
382       return Object.keys(agents).reduce(function (selected, name) {
383         var data = byName(name)
384         if (!data) return selected
385         var array = data.versions.filter(function (v) {
386           return data.released.indexOf(v) === -1
387         })
388
389         array = array.map(nameMapper(data.name))
390         return selected.concat(array)
391       }, [])
392     }
393   },
394   {
395     regexp: /^unreleased\s+electron\s+versions?$/i,
396     select: function () {
397       return []
398     }
399   },
400   {
401     regexp: /^unreleased\s+(\w+)\s+versions?$/i,
402     select: function (context, name) {
403       var data = checkName(name)
404       return data.versions.filter(function (v) {
405         return data.released.indexOf(v) === -1
406       }).map(nameMapper(data.name))
407     }
408   },
409   {
410     regexp: /^last\s+(\d+)\s+years?$/i,
411     select: function (context, years) {
412       var date = new Date()
413       var since = date.setFullYear(date.getFullYear() - years) / 1000
414
415       return filterByYear(since)
416     }
417   },
418   {
419     regexp: /^since (\d+)(?:-(\d+))?(?:-(\d+))?$/i,
420     select: function (context, year, month, date) {
421       year = parseInt(year)
422       month = parseInt(month || '01') - 1
423       date = parseInt(date || '01')
424       var since = Date.UTC(year, month, date, 0, 0, 0) / 1000
425
426       return filterByYear(since)
427     }
428   },
429   {
430     regexp: /^(>=?|<=?)\s*(\d*\.?\d+)%$/,
431     select: function (context, sign, popularity) {
432       popularity = parseFloat(popularity)
433       var usage = browserslist.usage.global
434
435       return Object.keys(usage).reduce(function (result, version) {
436         if (sign === '>') {
437           if (usage[version] > popularity) {
438             result.push(version)
439           }
440         } else if (sign === '<') {
441           if (usage[version] < popularity) {
442             result.push(version)
443           }
444         } else if (sign === '<=') {
445           if (usage[version] <= popularity) {
446             result.push(version)
447           }
448         } else if (usage[version] >= popularity) {
449           result.push(version)
450         }
451         return result
452       }, [])
453     }
454   },
455   {
456     regexp: /^(>=?|<=?)\s*(\d*\.?\d+)%\s+in\s+my\s+stats$/,
457     select: function (context, sign, popularity) {
458       popularity = parseFloat(popularity)
459
460       if (!context.customUsage) {
461         throw new BrowserslistError('Custom usage statistics was not provided')
462       }
463
464       var usage = context.customUsage
465
466       return Object.keys(usage).reduce(function (result, version) {
467         if (sign === '>') {
468           if (usage[version] > popularity) {
469             result.push(version)
470           }
471         } else if (sign === '<') {
472           if (usage[version] < popularity) {
473             result.push(version)
474           }
475         } else if (sign === '<=') {
476           if (usage[version] <= popularity) {
477             result.push(version)
478           }
479         } else if (usage[version] >= popularity) {
480           result.push(version)
481         }
482         return result
483       }, [])
484     }
485   },
486   {
487     regexp: /^(>=?|<=?)\s*(\d*\.?\d+)%\s+in\s+((alt-)?\w\w)$/,
488     select: function (context, sign, popularity, place) {
489       popularity = parseFloat(popularity)
490
491       if (place.length === 2) {
492         place = place.toUpperCase()
493       } else {
494         place = place.toLowerCase()
495       }
496
497       loadCountryStatistics(place)
498       var usage = browserslist.usage[place]
499
500       return Object.keys(usage).reduce(function (result, version) {
501         if (sign === '>') {
502           if (usage[version] > popularity) {
503             result.push(version)
504           }
505         } else if (sign === '<') {
506           if (usage[version] < popularity) {
507             result.push(version)
508           }
509         } else if (sign === '<=') {
510           if (usage[version] <= popularity) {
511             result.push(version)
512           }
513         } else if (usage[version] >= popularity) {
514           result.push(version)
515         }
516         return result
517       }, [])
518     }
519   },
520   {
521     regexp: /^electron\s+([\d.]+)\s*-\s*([\d.]+)$/i,
522     select: function (context, from, to) {
523       if (!e2c[from]) {
524         throw new BrowserslistError('Unknown version ' + from + ' of electron')
525       }
526       if (!e2c[to]) {
527         throw new BrowserslistError('Unknown version ' + to + ' of electron')
528       }
529
530       from = parseFloat(from)
531       to = parseFloat(to)
532
533       return Object.keys(e2c).filter(function (i) {
534         var parsed = parseFloat(i)
535         return parsed >= from && parsed <= to
536       }).map(function (i) {
537         return 'chrome ' + e2c[i]
538       })
539     }
540   },
541   {
542     regexp: /^(\w+)\s+([\d.]+)\s*-\s*([\d.]+)$/i,
543     select: function (context, name, from, to) {
544       var data = checkName(name)
545       from = parseFloat(normalizeVersion(data, from) || from)
546       to = parseFloat(normalizeVersion(data, to) || to)
547
548       function filter (v) {
549         var parsed = parseFloat(v)
550         return parsed >= from && parsed <= to
551       }
552
553       return data.released.filter(filter).map(nameMapper(data.name))
554     }
555   },
556   {
557     regexp: /^electron\s*(>=?|<=?)\s*([\d.]+)$/i,
558     select: function (context, sign, version) {
559       return Object.keys(e2c)
560         .filter(generateFilter(sign, version))
561         .map(function (i) {
562           return 'chrome ' + e2c[i]
563         })
564     }
565   },
566   {
567     regexp: /^(\w+)\s*(>=?|<=?)\s*([\d.]+)$/,
568     select: function (context, name, sign, version) {
569       var data = checkName(name)
570       var alias = browserslist.versionAliases[data.name][version]
571       if (alias) {
572         version = alias
573       }
574       return data.released
575         .filter(generateFilter(sign, version))
576         .map(function (v) {
577           return data.name + ' ' + v
578         })
579     }
580   },
581   {
582     regexp: /^(firefox|ff|fx)\s+esr$/i,
583     select: function () {
584       return ['firefox 52']
585     }
586   },
587   {
588     regexp: /(operamini|op_mini)\s+all/i,
589     select: function () {
590       return ['op_mini all']
591     }
592   },
593   {
594     regexp: /^electron\s+([\d.]+)$/i,
595     select: function (context, version) {
596       var chrome = e2c[version]
597       if (!chrome) {
598         throw new BrowserslistError(
599           'Unknown version ' + version + ' of electron')
600       }
601       return ['chrome ' + chrome]
602     }
603   },
604   {
605     regexp: /^(\w+)\s+(tp|[\d.]+)$/i,
606     select: function (context, name, version) {
607       if (/^tp$/i.test(version)) version = 'TP'
608       var data = checkName(name)
609       var alias = normalizeVersion(data, version)
610       if (alias) {
611         version = alias
612       } else {
613         if (version.indexOf('.') === -1) {
614           alias = version + '.0'
615         } else if (/\.0$/.test(version)) {
616           alias = version.replace(/\.0$/, '')
617         }
618         alias = normalizeVersion(data, alias)
619         if (alias) {
620           version = alias
621         } else {
622           throw new BrowserslistError(
623             'Unknown version ' + version + ' of ' + name)
624         }
625       }
626       return [data.name + ' ' + version]
627     }
628   },
629   {
630     regexp: /^extends (.+)$/i,
631     select: function (context, name) {
632       return resolve(env.loadQueries(context, name), context)
633     }
634   },
635   {
636     regexp: /^defaults$/i,
637     select: function () {
638       return browserslist(browserslist.defaults)
639     }
640   }
641 ];
642
643 // Get and convert Can I Use data
644
645 (function () {
646   for (var name in agents) {
647     var browser = agents[name]
648     browserslist.data[name] = {
649       name: name,
650       versions: normalize(agents[name].versions),
651       released: normalize(agents[name].versions.slice(0, -3)),
652       releaseDate: agents[name].release_date
653     }
654     fillUsage(browserslist.usage.global, name, browser.usage_global)
655
656     browserslist.versionAliases[name] = { }
657     for (var i = 0; i < browser.versions.length; i++) {
658       var full = browser.versions[i]
659       if (!full) continue
660
661       if (full.indexOf('-') !== -1) {
662         var interval = full.split('-')
663         for (var j = 0; j < interval.length; j++) {
664           browserslist.versionAliases[name][interval[j]] = full
665         }
666       }
667     }
668   }
669 }())
670
671 module.exports = browserslist