AK-21/Graphite-Industrial-Intelligence
0
1let { execSync } = require('child_process')2let escalade = require('escalade/sync')3let { existsSync, readFileSync, writeFileSync } = require('fs')4let { join } = require('path')5let pico = require('picocolors')6 7const { detectEOL, detectIndent } = require('./utils')8 9function BrowserslistUpdateError(message) {10 this.name = 'BrowserslistUpdateError'11 this.message = message12 this.browserslist = true13 if (Error.captureStackTrace) {14 Error.captureStackTrace(this, BrowserslistUpdateError)15 }16}17 18BrowserslistUpdateError.prototype = Error.prototype19 20// Check if HADOOP_HOME is set to determine if this is running in a Hadoop environment21const IsHadoopExists = !!process.env.HADOOP_HOME22const yarnCommand = IsHadoopExists ? 'yarnpkg' : 'yarn'23 24/* c8 ignore next 3 */25function defaultPrint(str) {26 process.stdout.write(str)27}28 29function detectLockfile() {30 let packageDir = escalade('.', (dir, names) => {31 return names.indexOf('package.json') !== -1 ? dir : ''32 })33 34 if (!packageDir) {35 throw new BrowserslistUpdateError(36 'Cannot find package.json. ' +37 'Is this the right directory to run `npx update-browserslist-db` in?'38 )39 }40 41 let lockfileNpm = join(packageDir, 'package-lock.json')42 let lockfileShrinkwrap = join(packageDir, 'npm-shrinkwrap.json')43 let lockfileYarn = join(packageDir, 'yarn.lock')44 let lockfilePnpm = join(packageDir, 'pnpm-lock.yaml')45 let lockfileBun = join(packageDir, 'bun.lock')46 let lockfileBunBinary = join(packageDir, 'bun.lockb')47 48 if (existsSync(lockfilePnpm)) {49 return { file: lockfilePnpm, mode: 'pnpm' }50 } else if (existsSync(lockfileBun) || existsSync(lockfileBunBinary)) {51 return { file: lockfileBun, mode: 'bun' }52 } else if (existsSync(lockfileNpm)) {53 return { file: lockfileNpm, mode: 'npm' }54 } else if (existsSync(lockfileYarn)) {55 let lock = { file: lockfileYarn, mode: 'yarn' }56 lock.content = readFileSync(lock.file).toString()57 lock.version = /# yarn lockfile v1/.test(lock.content) ? 1 : 258 return lock59 } else if (existsSync(lockfileShrinkwrap)) {60 return { file: lockfileShrinkwrap, mode: 'npm' }61 }62 throw new BrowserslistUpdateError(63 'No lockfile found. Run "npm install", "yarn install" or "pnpm install"'64 )65}66 67function getLatestInfo(lock) {68 if (lock.mode === 'yarn') {69 if (lock.version === 1) {70 return JSON.parse(71 execSync(yarnCommand + ' info caniuse-lite --json').toString()72 ).data73 } else {74 return JSON.parse(75 execSync(yarnCommand + ' npm info caniuse-lite --json').toString()76 )77 }78 }79 if (lock.mode === 'pnpm') {80 return JSON.parse(execSync('pnpm info caniuse-lite --json').toString())81 }82 if (lock.mode === 'bun') {83 return JSON.parse(execSync(' bun info caniuse-lite --json').toString())84 }85 86 return JSON.parse(execSync('npm show caniuse-lite --json').toString())87}88 89function getBrowsers() {90 let browserslist = require('browserslist')91 return browserslist().reduce((result, entry) => {92 if (!result[entry[0]]) {93 result[entry[0]] = []94 }95 result[entry[0]].push(entry[1])96 return result97 }, {})98}99 100function diffBrowsers(old, current) {101 let browsers = Object.keys(old).concat(102 Object.keys(current).filter(browser => old[browser] === undefined)103 )104 return browsers105 .map(browser => {106 let oldVersions = old[browser] || []107 let currentVersions = current[browser] || []108 let common = oldVersions.filter(v => currentVersions.includes(v))109 let added = currentVersions.filter(v => !common.includes(v))110 let removed = oldVersions.filter(v => !common.includes(v))111 return removed112 .map(v => pico.red('- ' + browser + ' ' + v))113 .concat(added.map(v => pico.green('+ ' + browser + ' ' + v)))114 })115 .reduce((result, array) => result.concat(array), [])116 .join('\n')117}118 119function updateNpmLockfile(lock, latest) {120 let metadata = { latest, versions: [] }121 let content = deletePackage(JSON.parse(lock.content), metadata)122 metadata.content = JSON.stringify(content, null, detectIndent(lock.content))123 return metadata124}125 126function deletePackage(node, metadata) {127 if (node.dependencies) {128 if (node.dependencies['caniuse-lite']) {129 let version = node.dependencies['caniuse-lite'].version130 metadata.versions[version] = true131 delete node.dependencies['caniuse-lite']132 }133 for (let i in node.dependencies) {134 node.dependencies[i] = deletePackage(node.dependencies[i], metadata)135 }136 }137 if (node.packages) {138 for (let path in node.packages) {139 if (path.endsWith('/caniuse-lite')) {140 metadata.versions[node.packages[path].version] = true141 delete node.packages[path]142 }143 }144 }145 return node146}147 148let yarnVersionRe = /version "(.*?)"/149 150function updateYarnLockfile(lock, latest) {151 let blocks = lock.content.split(/(\n{2,})/).map(block => {152 return block.split('\n')153 })154 let versions = {}155 blocks.forEach(lines => {156 if (lines[0].indexOf('caniuse-lite@') !== -1) {157 let match = yarnVersionRe.exec(lines[1])158 versions[match[1]] = true159 if (match[1] !== latest.version) {160 lines[1] = lines[1].replace(161 /version "[^"]+"/,162 'version "' + latest.version + '"'163 )164 lines[2] = lines[2].replace(165 /resolved "[^"]+"/,166 'resolved "' + latest.dist.tarball + '"'167 )168 if (lines.length === 4) {169 lines[3] = latest.dist.integrity170 ? lines[3].replace(171 /integrity .+/,172 'integrity ' + latest.dist.integrity173 )174 : ''175 }176 }177 }178 })179 let content = blocks.map(lines => lines.join('\n')).join('')180 return { content, versions }181}182 183function updateLockfile(lock, latest) {184 if (!lock.content) lock.content = readFileSync(lock.file).toString()185 186 let updatedLockFile187 if (lock.mode === 'yarn') {188 updatedLockFile = updateYarnLockfile(lock, latest)189 } else {190 updatedLockFile = updateNpmLockfile(lock, latest)191 }192 updatedLockFile.content = updatedLockFile.content.replace(193 /\n/g,194 detectEOL(lock.content)195 )196 return updatedLockFile197}198 199function updatePackageManually(print, lock, latest) {200 let lockfileData = updateLockfile(lock, latest)201 let caniuseVersions = Object.keys(lockfileData.versions).sort()202 if (caniuseVersions.length === 1 && caniuseVersions[0] === latest.version) {203 print(204 'Installed version: ' +205 pico.bold(pico.green(caniuseVersions[0])) +206 '\n' +207 pico.bold(pico.green('caniuse-lite is up to date')) +208 '\n'209 )210 return211 }212 213 if (caniuseVersions.length === 0) {214 caniuseVersions[0] = 'none'215 }216 print(217 'Installed version' +218 (caniuseVersions.length === 1 ? ': ' : 's: ') +219 pico.bold(pico.red(caniuseVersions.join(', '))) +220 '\n' +221 'Removing old caniuse-lite from lock file\n'222 )223 writeFileSync(lock.file, lockfileData.content)224 225 let install =226 lock.mode === 'yarn' ? yarnCommand + ' add -W' : lock.mode + ' install'227 print(228 'Installing new caniuse-lite version\n' +229 pico.yellow('$ ' + install + ' caniuse-lite baseline-browser-mapping') +230 '\n'231 )232 try {233 execSync(install + ' caniuse-lite baseline-browser-mapping')234 } catch (e) /* c8 ignore start */ {235 print(236 pico.red(237 '\n' +238 e.stack +239 '\n\n' +240 'Problem with `' +241 install +242 ' caniuse-lite` call. ' +243 'Run it manually.\n'244 )245 )246 process.exit(1)247 } /* c8 ignore end */248 249 let del =250 lock.mode === 'yarn' ? yarnCommand + ' remove -W' : lock.mode + ' uninstall'251 print(252 'Cleaning package.json dependencies from caniuse-lite\n' +253 pico.yellow('$ ' + del + ' caniuse-lite baseline-browser-mapping') +254 '\n'255 )256 execSync(del + ' caniuse-lite baseline-browser-mapping')257}258 259function updateWith(print, cmd) {260 print('Updating caniuse-lite version\n' + pico.yellow('$ ' + cmd) + '\n')261 try {262 execSync(cmd)263 } catch (e) /* c8 ignore start */ {264 print(pico.red(e.stdout.toString()))265 print(266 pico.red(267 '\n' +268 e.stack +269 '\n\n' +270 'Problem with `' +271 cmd +272 '` call. ' +273 'Run it manually.\n'274 )275 )276 process.exit(1)277 } /* c8 ignore end */278}279 280module.exports = function updateDB(print = defaultPrint) {281 let lock = detectLockfile()282 let latest = getLatestInfo(lock)283 284 let listError285 let oldList286 try {287 oldList = getBrowsers()288 } catch (e) {289 listError = e290 }291 292 print('Latest version: ' + pico.bold(pico.green(latest.version)) + '\n')293 294 if (lock.mode === 'yarn' && lock.version !== 1) {295 updateWith(296 print,297 yarnCommand + ' up -R caniuse-lite baseline-browser-mapping'298 )299 } else if (lock.mode === 'pnpm') {300 let lockContent = readFileSync(lock.file).toString()301 let packages = lockContent.includes('baseline-browser-mapping')302 ? 'caniuse-lite baseline-browser-mapping'303 : 'caniuse-lite'304 updateWith(print, 'pnpm up --depth=Infinity --no-save ' + packages)305 } else if (lock.mode === 'bun') {306 updateWith(print, 'bun update caniuse-lite baseline-browser-mapping')307 } else {308 updatePackageManually(print, lock, latest)309 }310 311 print('caniuse-lite has been successfully updated\n')312 313 let newList314 if (!listError) {315 try {316 newList = getBrowsers()317 } catch (e) /* c8 ignore start */ {318 listError = e319 } /* c8 ignore end */320 }321 322 if (listError) {323 if (listError.message.includes("Cannot find module 'browserslist'")) {324 print(325 pico.gray(326 'Install `browserslist` to your direct dependencies ' +327 'to see target browser changes\n'328 )329 )330 } else {331 print(332 pico.gray(333 'Problem with browser list retrieval.\n' +334 'Target browser changes won’t be shown.\n'335 )336 )337 }338 } else {339 let changes = diffBrowsers(oldList, newList)340 if (changes) {341 print('\nTarget browser changes:\n')342 print(changes + '\n')343 } else {344 print('\n' + pico.green('No target browser changes') + '\n')345 }346 }347}348 