browserslist 4.8.7 → 4.11.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/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # Change Log
2
2
  This project adheres to [Semantic Versioning](http://semver.org/).
3
3
 
4
+ ## 4.11
5
+ * Add `npx browserslist --mobile-to-desktop` (by James Ross).
6
+
7
+ ## 4.10
8
+ * Add `npx browserslist --update-db` (by Ivan Solovev).
9
+
10
+ ## 4.9.1
11
+ * Normalize incorrect Can I Use regional data (by Huáng Jùnliàng).
12
+
13
+ ## 4.9
14
+ * Add `node X-Y` query support (by Yuping Zuo).
15
+
4
16
  ## 4.8.7
5
17
  * Fix `last N major versions` (by Valeriy Trubachev).
6
18
 
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright 2014 Andrey Sitnik <andrey@sitnik.ru>
3
+ Copyright 2014 Andrey Sitnik <andrey@sitnik.ru> and other contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
package/README.md CHANGED
@@ -37,7 +37,7 @@ not IE_Mob 11
37
37
  maintained node versions
38
38
  ```
39
39
 
40
- Developers set their version lists using queries like `last 2 version`
40
+ Developers set their version lists using queries like `last 2 versions`
41
41
  to be free from updating versions manually.
42
42
  Browserslist will use [`caniuse-lite`] with [Can I Use] data for this queries.
43
43
 
@@ -91,12 +91,14 @@ Browserslist will take queries from tool option,
91
91
  by user agent string to match Browserslist.
92
92
  * [`browserslist-browserstack`] runs BrowserStack tests for all browsers
93
93
  in Browserslist config.
94
+ * [`browserslist-adobe-analytics`] use Adobe Analytics data to target browsers.
94
95
  * [`caniuse-api`] returns browsers which support some specific feature.
95
96
  * Run `npx browserslist` in your project directory to see project’s
96
97
  target browsers. This CLI tool is built-in and available in any project
97
98
  with Autoprefixer.
98
99
 
99
100
  [`browserslist-useragent-regexp`]: https://github.com/browserslist/browserslist-useragent-regexp
101
+ [`browserslist-adobe-analytics`]: https://github.com/xeroxinteractive/browserslist-adobe-analytics
100
102
  [`browserslist-useragent-ruby`]: https://github.com/browserslist/browserslist-useragent-ruby
101
103
  [`browserslist-browserstack`]: https://github.com/xeroxinteractive/browserslist-browserstack
102
104
  [`browserslist-ga-export`]: https://github.com/browserslist/browserslist-ga-export
package/cli.js CHANGED
@@ -3,19 +3,23 @@
3
3
  var fs = require('fs')
4
4
 
5
5
  var browserslist = require('./')
6
+ var updateDb = require('./update-db')
6
7
  var pkg = require('./package.json')
8
+
7
9
  var args = process.argv.slice(2)
8
10
 
9
11
  var USAGE = 'Usage:\n' +
10
- ' ' + pkg.name + '\n' +
11
- ' ' + pkg.name + ' "QUERIES"\n' +
12
- ' ' + pkg.name + ' --json "QUERIES"\n' +
13
- ' ' + pkg.name + ' --config="path/to/browserlist/file"\n' +
14
- ' ' + pkg.name + ' --coverage "QUERIES"\n' +
15
- ' ' + pkg.name + ' --coverage=US "QUERIES"\n' +
16
- ' ' + pkg.name + ' --coverage=US,RU,global "QUERIES"\n' +
17
- ' ' + pkg.name + ' --env="environment name defined in config"\n' +
18
- ' ' + pkg.name + ' --stats="path/to/browserlist/stats/file"'
12
+ ' npx browserslist\n' +
13
+ ' npx browserslist "QUERIES"\n' +
14
+ ' npx browserslist --json "QUERIES"\n' +
15
+ ' npx browserslist --config="path/to/browserlist/file"\n' +
16
+ ' npx browserslist --coverage "QUERIES"\n' +
17
+ ' npx browserslist --coverage=US "QUERIES"\n' +
18
+ ' npx browserslist --coverage=US,RU,global "QUERIES"\n' +
19
+ ' npx browserslist --env="environment name defined in config"\n' +
20
+ ' npx browserslist --stats="path/to/browserlist/stats/file"\n' +
21
+ ' npx browserslist --mobile-to-desktop\n' +
22
+ ' npx browserslist --update-db'
19
23
 
20
24
  function isArg (arg) {
21
25
  return args.some(function (str) {
@@ -24,14 +28,18 @@ function isArg (arg) {
24
28
  }
25
29
 
26
30
  function error (msg) {
27
- process.stderr.write(pkg.name + ': ' + msg + '\n')
31
+ process.stderr.write('browserslist: ' + msg + '\n')
28
32
  process.exit(1)
29
33
  }
30
34
 
31
35
  if (isArg('--help') || isArg('-h')) {
32
36
  process.stdout.write(pkg.description + '.\n\n' + USAGE + '\n')
33
37
  } else if (isArg('--version') || isArg('-v')) {
34
- process.stdout.write(pkg.name + ' ' + pkg.version + '\n')
38
+ process.stdout.write('browserslist ' + pkg.version + '\n')
39
+ } else if (isArg('--update-db')) {
40
+ updateDb(function (str) {
41
+ process.stdout.write(str)
42
+ })
35
43
  } else {
36
44
  var mode = 'browsers'
37
45
  var opts = { }
@@ -65,6 +73,8 @@ if (isArg('--help') || isArg('-h')) {
65
73
  }
66
74
  } else if (name === '--json') {
67
75
  mode = 'json'
76
+ } else if (name === '--mobile-to-desktop') {
77
+ opts.mobileToDesktop = true
68
78
  } else {
69
79
  error('Unknown arguments ' + args[i] + '.\n\n' + USAGE)
70
80
  }
package/index.js CHANGED
@@ -148,6 +148,43 @@ function compareSemver (a, b) {
148
148
  )
149
149
  }
150
150
 
151
+ // this follows the npm-like semver behavior
152
+ function 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
+ default:
166
+ case '>=':
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
175
+ function 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
+
151
188
  function resolveVersion (data, version) {
152
189
  if (data.versions.indexOf(version) !== -1) {
153
190
  return version
@@ -551,7 +588,7 @@ browserslist.coverage = function (browsers, stats) {
551
588
  } else {
552
589
  stats = stats.toUpperCase()
553
590
  }
554
- env.loadCountry(browserslist.usage, stats)
591
+ env.loadCountry(browserslist.usage, stats, browserslist.data)
555
592
  data = browserslist.usage[stats]
556
593
  } else {
557
594
  if ('dataByBrowser' in stats) {
@@ -786,7 +823,7 @@ var QUERIES = [
786
823
  } else {
787
824
  place = place.toLowerCase()
788
825
  }
789
- env.loadCountry(browserslist.usage, place)
826
+ env.loadCountry(browserslist.usage, place, browserslist.data)
790
827
  var usage = browserslist.usage[place]
791
828
  return Object.keys(usage).reduce(function (result, version) {
792
829
  if (sign === '>') {
@@ -829,7 +866,7 @@ var QUERIES = [
829
866
  } else {
830
867
  place = place.toLowerCase()
831
868
  }
832
- env.loadCountry(browserslist.usage, place)
869
+ env.loadCountry(browserslist.usage, place, browserslist.data)
833
870
  usage = browserslist.usage[place]
834
871
  }
835
872
  }
@@ -870,6 +907,31 @@ var QUERIES = [
870
907
  })
871
908
  }
872
909
  },
910
+ {
911
+ regexp: /^node\s+([\d.]+)\s*-\s*([\d.]+)$/i,
912
+ select: function (context, from, to) {
913
+ var nodeVersions = jsReleases.filter(function (i) {
914
+ return i.name === 'nodejs'
915
+ }).map(function (i) {
916
+ return i.version
917
+ })
918
+ var semverRegExp = /^(0|[1-9]\d*)(\.(0|[1-9]\d*)){0,2}$/
919
+ if (!semverRegExp.test(from)) {
920
+ throw new BrowserslistError(
921
+ 'Unknown version ' + from + ' of Node.js')
922
+ }
923
+ if (!semverRegExp.test(to)) {
924
+ throw new BrowserslistError(
925
+ 'Unknown version ' + to + ' of Node.js')
926
+ }
927
+ return nodeVersions
928
+ .filter(semverFilterLoose('>=', from))
929
+ .filter(semverFilterLoose('<=', to))
930
+ .map(function (v) {
931
+ return 'node ' + v
932
+ })
933
+ }
934
+ },
873
935
  {
874
936
  regexp: /^(\w+)\s+([\d.]+)\s*-\s*([\d.]+)$/i,
875
937
  select: function (context, name, from, to) {
package/node.js CHANGED
@@ -137,6 +137,20 @@ function normalizeStats (data, stats) {
137
137
  return normalized
138
138
  }
139
139
 
140
+ function normalizeUsageData (usageData, data) {
141
+ for (var browser in usageData) {
142
+ var browserUsage = usageData[browser]
143
+ // eslint-disable-next-line max-len
144
+ // https://github.com/browserslist/browserslist/issues/431#issuecomment-565230615
145
+ // caniuse-db returns { 0: "percentage" } for `and_*` regional stats
146
+ if ('0' in browserUsage) {
147
+ var versions = data[browser].versions
148
+ browserUsage[versions[versions.length - 1]] = browserUsage[0]
149
+ delete browserUsage[0]
150
+ }
151
+ }
152
+ }
153
+
140
154
  module.exports = {
141
155
  loadQueries: function loadQueries (context, name) {
142
156
  if (!context.dangerousExtend) checkExtend(name)
@@ -201,16 +215,17 @@ module.exports = {
201
215
  }
202
216
  },
203
217
 
204
- loadCountry: function loadCountry (usage, country) {
218
+ loadCountry: function loadCountry (usage, country, data) {
205
219
  var code = country.replace(/[^\w-]/g, '')
206
220
  if (!usage[code]) {
207
221
  // eslint-disable-next-line security/detect-non-literal-require
208
222
  var compressed = require('caniuse-lite/data/regions/' + code + '.js')
209
- var data = region(compressed)
223
+ var usageData = region(compressed)
224
+ normalizeUsageData(usageData, data)
210
225
  usage[country] = { }
211
- for (var i in data) {
212
- for (var j in data[i]) {
213
- usage[country][i + ' ' + j] = data[i][j]
226
+ for (var i in usageData) {
227
+ for (var j in usageData[i]) {
228
+ usage[country][i + ' ' + j] = usageData[i][j]
214
229
  }
215
230
  }
216
231
  }
@@ -327,14 +342,7 @@ module.exports = {
327
342
  var halfYearAgo = Date.now() - TIME_TO_UPDATE_CANIUSE
328
343
 
329
344
  if (latest !== 0 && latest < halfYearAgo) {
330
- var command = 'npm update'
331
- eachParent(__filename, function (dir) {
332
- var pckg = path.join(dir, 'package.json')
333
- var yarnLock = path.join(dir, 'yarn.lock')
334
- if (isFile(pckg) && isFile(yarnLock)) {
335
- command = 'yarn upgrade'
336
- }
337
- })
345
+ var command = 'npx browserslist --update-db'
338
346
  console.warn(
339
347
  'Browserslist: caniuse-lite is outdated. ' +
340
348
  'Please run the following command: `' + command + '`'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browserslist",
3
- "version": "4.8.7",
3
+ "version": "4.11.0",
4
4
  "description": "Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-env-preset",
5
5
  "keywords": [
6
6
  "caniuse",
@@ -15,9 +15,10 @@
15
15
  "license": "MIT",
16
16
  "repository": "browserslist/browserslist",
17
17
  "dependencies": {
18
- "caniuse-lite": "^1.0.30001027",
19
- "electron-to-chromium": "^1.3.349",
20
- "node-releases": "^1.1.49"
18
+ "caniuse-lite": "^1.0.30001035",
19
+ "electron-to-chromium": "^1.3.380",
20
+ "node-releases": "^1.1.52",
21
+ "pkg-up": "^3.1.0"
21
22
  },
22
23
  "bin": "./cli.js",
23
24
  "browser": {
@@ -26,9 +27,5 @@
26
27
  },
27
28
  "eslintIgnore": [
28
29
  "test/fixtures"
29
- ],
30
- "sharec": {
31
- "config": "@logux/sharec-config",
32
- "version": "0.5.7"
33
- }
30
+ ]
34
31
  }
package/update-db.js ADDED
@@ -0,0 +1,131 @@
1
+ var childProcess = require('child_process')
2
+ var pkgUp = require('pkg-up')
3
+ var path = require('path')
4
+ var fs = require('fs')
5
+
6
+ var BrowserslistError = require('./error')
7
+
8
+ function detectLockfile () {
9
+ var packagePath = pkgUp.sync()
10
+ if (!packagePath) {
11
+ throw new BrowserslistError(
12
+ 'Cannot find package.json. ' +
13
+ 'Is it a right project to run npx browserslist --update-db?'
14
+ )
15
+ }
16
+
17
+ var rootDir = path.dirname(packagePath)
18
+ var lockfileNpm = path.join(rootDir, 'package-lock.json')
19
+ var lockfileYarn = path.join(rootDir, 'yarn.lock')
20
+ var lockfilePnpm = path.join(rootDir, 'pnpm-lock.yaml')
21
+
22
+ if (fs.existsSync(lockfileNpm)) {
23
+ return { mode: 'npm', file: lockfileNpm }
24
+ } else if (fs.existsSync(lockfileYarn)) {
25
+ return { mode: 'yarn', file: lockfileYarn }
26
+ } else if (fs.existsSync(lockfilePnpm)) {
27
+ return { mode: 'pnpm', file: lockfilePnpm }
28
+ } else {
29
+ throw new BrowserslistError(
30
+ 'No lockfile found. Run "npm install", "yarn install" or "pnpm install"'
31
+ )
32
+ }
33
+ }
34
+
35
+ function getCurrentVersion (lock) {
36
+ var match
37
+ if (lock.mode === 'npm') {
38
+ var dependencies = JSON.parse(lock.content).dependencies
39
+ if (dependencies && dependencies['caniuse-lite']) {
40
+ return dependencies['caniuse-lite'].version
41
+ }
42
+ } else if (lock.mode === 'yarn') {
43
+ match = /caniuse-lite@[^:]+:\n\s+version\s+"([^"]+)"/.exec(lock.content)
44
+ if (match[1]) return match[1]
45
+ } else if (lock.mode === 'pnpm') {
46
+ match = /\/caniuse-lite\/([^:]+):/.exec(lock.content)
47
+ if (match[1]) return match[1]
48
+ }
49
+ return null
50
+ }
51
+
52
+ function getLastestInfo () {
53
+ return JSON.parse(
54
+ childProcess.execSync('npm show caniuse-lite --json').toString()
55
+ )
56
+ }
57
+
58
+ function updateLockfile (lock, latest) {
59
+ if (lock.mode === 'npm') {
60
+ var fixed = deletePackage(JSON.parse(lock.content))
61
+ return JSON.stringify(fixed, null, ' ')
62
+ } else {
63
+ var lines = lock.content.split('\n')
64
+ var i
65
+ if (lock.mode === 'yarn') {
66
+ for (i = 0; i < lines.length; i++) {
67
+ if (lines[i].indexOf('caniuse-lite@') !== -1) {
68
+ lines[i + 1] = lines[i + 1].replace(
69
+ /version "[^"]+"/, 'version "' + latest.version + '"'
70
+ )
71
+ lines[i + 2] = lines[i + 2].replace(
72
+ /resolved "[^"]+"/, 'resolved "' + latest.dist.tarball + '"'
73
+ )
74
+ lines[i + 3] = lines[i + 3].replace(
75
+ /integrity .+/, 'integrity ' + latest.dist.integrity
76
+ )
77
+ i += 4
78
+ }
79
+ }
80
+ } else if (lock.mode === 'pnpm') {
81
+ for (i = 0; i < lines.length; i++) {
82
+ if (lines[i].indexOf('caniuse-lite:') >= 0) {
83
+ lines[i] = lines[i].replace(/: .*$/, ': ' + latest.version)
84
+ } else if (lines[i].indexOf('/caniuse-lite') >= 0) {
85
+ lines[i] = lines[i].replace(/\/[^/:]+:/, '/' + latest.version + ':')
86
+ for (i = i + 1; i < lines.length; i++) {
87
+ if (lines[i].indexOf('integrity: ') !== -1) {
88
+ lines[i] = lines[i].replace(
89
+ /integrity: .+/, 'integrity: ' + latest.dist.integrity
90
+ )
91
+ } else if (lines[i].indexOf(' /') !== -1) {
92
+ break
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ return lines.join('\n')
99
+ }
100
+ }
101
+
102
+ function deletePackage (node) {
103
+ if (node.dependencies) {
104
+ delete node.dependencies['caniuse-lite']
105
+ for (var i in node.dependencies) {
106
+ node.dependencies[i] = deletePackage(node.dependencies[i])
107
+ }
108
+ }
109
+ return node
110
+ }
111
+
112
+ module.exports = function updateDB (print) {
113
+ var lock = detectLockfile()
114
+ lock.content = fs.readFileSync(lock.file).toString()
115
+
116
+ var current = getCurrentVersion(lock)
117
+ var latest = getLastestInfo()
118
+
119
+ if (typeof current === 'string') {
120
+ print('Current version: ' + current + '\n')
121
+ }
122
+ print(
123
+ 'New version: ' + latest.version + '\n' +
124
+ 'Updating caniuse-lite…\n'
125
+ )
126
+
127
+ fs.writeFileSync(lock.file, updateLockfile(lock, latest))
128
+ childProcess.execSync(lock.mode + ' install')
129
+
130
+ print('caniuse-lite has been successfully updated')
131
+ }