UNPKG

7.52 kBJavaScriptView Raw
1var childProcess = require('child_process')
2var colorette = require('colorette')
3var escalade = require('escalade/sync')
4var path = require('path')
5var fs = require('fs')
6
7var BrowserslistError = require('./error')
8
9var red = colorette.red
10var bold = colorette.bold
11var green = colorette.green
12var yellow = colorette.yellow
13
14function detectLockfile () {
15 var packageDir = escalade('.', function (dir, names) {
16 return names.indexOf('package.json') !== -1 ? dir : ''
17 })
18
19 if (!packageDir) {
20 throw new BrowserslistError(
21 'Cannot find package.json. ' +
22 'Is it a right project to run npx browserslist --update-db?'
23 )
24 }
25
26 var lockfileNpm = path.join(packageDir, 'package-lock.json')
27 var lockfileYarn = path.join(packageDir, 'yarn.lock')
28 var lockfilePnpm = path.join(packageDir, 'pnpm-lock.yaml')
29
30 /* istanbul ignore next */
31 if (fs.existsSync(lockfilePnpm)) {
32 return { mode: 'pnpm', file: lockfilePnpm }
33 } else if (fs.existsSync(lockfileNpm)) {
34 return { mode: 'npm', file: lockfileNpm }
35 } else if (fs.existsSync(lockfileYarn)) {
36 return { mode: 'yarn', file: lockfileYarn }
37 } else {
38 throw new BrowserslistError(
39 'No lockfile found. Run "npm install", "yarn install" or "pnpm install"'
40 )
41 }
42}
43
44function getCurrentVersion (lock) {
45 var match
46 /* istanbul ignore if */
47 if (lock.mode === 'pnpm') {
48 match = /\/caniuse-lite\/([^:]+):/.exec(lock.content)
49 if (match[1]) return match[1]
50 } else if (lock.mode === 'npm') {
51 var dependencies = JSON.parse(lock.content).dependencies
52 if (dependencies && dependencies['caniuse-lite']) {
53 return dependencies['caniuse-lite'].version
54 }
55 } else if (lock.mode === 'yarn') {
56 match = /caniuse-lite@[^:]+:\r?\n\s+version\s+"([^"]+)"/.exec(lock.content)
57 if (match[1]) return match[1]
58 }
59 return null
60}
61
62function getLatestInfo (lock) {
63 if (lock.mode !== 'yarn') {
64 return JSON.parse(
65 childProcess.execSync('npm show caniuse-lite --json').toString()
66 )
67 } else {
68 return JSON.parse(
69 childProcess.execSync('yarn info caniuse-lite --json').toString()
70 ).data
71 }
72}
73
74function getBrowsersList () {
75 return childProcess.execSync('npx browserslist').toString()
76 .trim()
77 .split('\n')
78 .map(function (line) {
79 return line.trim().split(' ')
80 })
81 .reduce(function (result, entry) {
82 if (!result[entry[0]]) {
83 result[entry[0]] = []
84 }
85 result[entry[0]].push(entry[1])
86 return result
87 }, {})
88}
89
90function diffBrowsersLists (old, current) {
91 var browsers = Object.keys(old).concat(
92 Object.keys(current).filter(function (browser) {
93 return old[browser] === undefined
94 })
95 )
96 return browsers.map(function (browser) {
97 var oldVersions = old[browser] || []
98 var currentVersions = current[browser] || []
99 var intersection = oldVersions.filter(function (version) {
100 return currentVersions.indexOf(version) !== -1
101 })
102 var addedVersions = currentVersions.filter(function (version) {
103 return intersection.indexOf(version) === -1
104 })
105 var removedVersions = oldVersions.filter(function (version) {
106 return intersection.indexOf(version) === -1
107 })
108 return removedVersions.map(function (version) {
109 return red('- ' + browser + ' ' + version)
110 }).concat(addedVersions.map(function (version) {
111 return green('+ ' + browser + ' ' + version)
112 }))
113 })
114 .reduce(function (result, array) {
115 return result.concat(array)
116 }, [])
117 .join('\n')
118}
119
120function updateLockfile (lock, latest) {
121 if (lock.mode === 'npm') {
122 var fixed = deletePackage(JSON.parse(lock.content))
123 return JSON.stringify(fixed, null, ' ')
124 } else {
125 var lines = lock.content.split('\n')
126 var i
127 /* istanbul ignore if */
128 if (lock.mode === 'pnpm') {
129 for (i = 0; i < lines.length; i++) {
130 if (lines[i].indexOf('caniuse-lite:') >= 0) {
131 lines[i] = lines[i].replace(/: .*$/, ': ' + latest.version)
132 } else if (lines[i].indexOf('/caniuse-lite') >= 0) {
133 lines[i] = lines[i].replace(/\/[^/:]+:/, '/' + latest.version + ':')
134 for (i = i + 1; i < lines.length; i++) {
135 if (lines[i].indexOf('integrity: ') !== -1) {
136 lines[i] = lines[i].replace(
137 /integrity: .+/, 'integrity: ' + latest.dist.integrity
138 )
139 } else if (lines[i].indexOf(' /') !== -1) {
140 break
141 }
142 }
143 }
144 }
145 } else if (lock.mode === 'yarn') {
146 for (i = 0; i < lines.length; i++) {
147 if (lines[i].indexOf('caniuse-lite@') !== -1) {
148 lines[i + 1] = lines[i + 1].replace(
149 /version "[^"]+"/, 'version "' + latest.version + '"'
150 )
151 lines[i + 2] = lines[i + 2].replace(
152 /resolved "[^"]+"/, 'resolved "' + latest.dist.tarball + '"'
153 )
154 lines[i + 3] = lines[i + 3].replace(
155 /integrity .+/, 'integrity ' + latest.dist.integrity
156 )
157 i += 4
158 }
159 }
160 }
161 return lines.join('\n')
162 }
163}
164
165function deletePackage (node) {
166 if (node.dependencies) {
167 delete node.dependencies['caniuse-lite']
168 for (var i in node.dependencies) {
169 node.dependencies[i] = deletePackage(node.dependencies[i])
170 }
171 }
172 return node
173}
174
175module.exports = function updateDB (print) {
176 var lock = detectLockfile()
177 lock.content = fs.readFileSync(lock.file).toString()
178
179 var current = getCurrentVersion(lock)
180 var latest = getLatestInfo(lock)
181 var browsersListRetrievalError
182 var oldBrowsersList
183 try {
184 oldBrowsersList = getBrowsersList()
185 } catch (e) {
186 browsersListRetrievalError = e
187 }
188
189 if (typeof current === 'string') {
190 print('Current version: ' + bold(red(current)) + '\n')
191 }
192 print(
193 'New version: ' + bold(green(latest.version)) + '\n' +
194 'Removing old caniuse-lite from lock file\n'
195 )
196
197 fs.writeFileSync(lock.file, updateLockfile(lock, latest))
198
199 var install = lock.mode === 'yarn' ? 'yarn add -W' : lock.mode + ' install'
200 print(
201 'Installing new caniuse-lite version\n' +
202 yellow('$ ' + install + ' caniuse-lite') + '\n'
203 )
204 try {
205 childProcess.execSync(install + ' caniuse-lite')
206 } catch (e) /* istanbul ignore next */ {
207 print(
208 red(
209 '\n' +
210 e.stack + '\n\n' +
211 'Problem with `' + install + ' caniuse-lite` call. ' +
212 'Run it manually.\n'
213 )
214 )
215 process.exit(1)
216 }
217
218 var del = lock.mode === 'yarn' ? 'yarn remove -W' : lock.mode + ' uninstall'
219 print(
220 'Cleaning package.json dependencies from caniuse-lite\n' +
221 yellow('$ ' + del + ' caniuse-lite') + '\n'
222 )
223 childProcess.execSync(del + ' caniuse-lite')
224
225 print('caniuse-lite has been successfully updated\n')
226
227 var currentBrowsersList
228 if (!browsersListRetrievalError) {
229 try {
230 currentBrowsersList = getBrowsersList()
231 } catch (e) /* istanbul ignore next */ {
232 browsersListRetrievalError = e
233 }
234 }
235
236 if (browsersListRetrievalError) {
237 print(
238 red(
239 '\n' +
240 browsersListRetrievalError.stack + '\n\n' +
241 'Problem with browsers list retrieval.\n' +
242 'Target browser changes won’t be shown.\n'
243 )
244 )
245 } else {
246 var targetBrowserChanges = diffBrowsersLists(
247 oldBrowsersList,
248 currentBrowsersList
249 )
250 if (targetBrowserChanges) {
251 print('\nTarget browser changes:\n')
252 print(targetBrowserChanges + '\n')
253 } else {
254 print('\n' + green('No target browser changes') + '\n')
255 }
256 }
257}