1'use strict' 2 3const ansiTrim = require('./utils/ansi-trim') 4const chain = require('slide').chain 5const color = require('ansicolors') 6const defaultRegistry = require('./config/defaults').defaults.registry 7const log = require('npmlog') 8const npm = require('./npm') 9const output = require('./utils/output') 10const path = require('path') 11const semver = require('semver') 12const styles = require('ansistyles') 13const table = require('text-table') 14 15// steps 16const checkFilesPermission = require('./doctor/check-files-permission') 17const checkPing = require('./doctor/check-ping') 18const getGitPath = require('./doctor/get-git-path') 19const getLatestNodejsVersion = require('./doctor/get-latest-nodejs-version') 20const getLatestNpmVersion = require('./doctor/get-latest-npm-version') 21const verifyCachedFiles = require('./doctor/verify-cached-files') 22 23const globalNodeModules = path.join(npm.config.globalPrefix, 'lib', 'node_modules') 24const localNodeModules = path.join(npm.config.localPrefix, 'node_modules') 25 26module.exports = doctor 27 28doctor.usage = 'npm doctor' 29 30function doctor (args, silent, cb) { 31 args = args || {} 32 if (typeof cb !== 'function') { 33 cb = silent 34 silent = false 35 } 36 37 const actionsToRun = [ 38 [checkPing], 39 [getLatestNpmVersion], 40 [getLatestNodejsVersion, args['node-url']], 41 [getGitPath], 42 [checkFilesPermission, npm.cache, 4, 6], 43 [checkFilesPermission, globalNodeModules, 4, 4], 44 [checkFilesPermission, localNodeModules, 6, 6], 45 [verifyCachedFiles, path.join(npm.cache, '_cacache')] 46 ] 47 48 log.info('doctor', 'Running checkup') 49 chain(actionsToRun, function (stderr, stdout) { 50 if (stderr && stderr.message !== 'not found: git') return cb(stderr) 51 const list = makePretty(stdout) 52 let outHead = ['Check', 'Value', 'Recommendation'] 53 let outBody = list 54 55 if (npm.color) { 56 outHead = outHead.map(function (item) { 57 return styles.underline(item) 58 }) 59 outBody = outBody.map(function (item) { 60 if (item[2]) { 61 item[0] = color.red(item[0]) 62 item[2] = color.magenta(item[2]) 63 } 64 return item 65 }) 66 } 67 68 const outTable = [outHead].concat(outBody) 69 const tableOpts = { 70 stringLength: function (s) { return ansiTrim(s).length } 71 } 72 73 if (!silent) output(table(outTable, tableOpts)) 74 75 cb(null, list) 76 }) 77} 78 79function makePretty (p) { 80 const ping = p[1] 81 const npmLTS = p[2] 82 const nodeLTS = p[3].replace('v', '') 83 const whichGit = p[4] || 'not installed' 84 const readbleCaches = p[5] ? 'ok' : 'notOk' 85 const executableGlobalModules = p[6] ? 'ok' : 'notOk' 86 const executableLocalModules = p[7] ? 'ok' : 'notOk' 87 const cacheStatus = p[8] ? `verified ${p[8].verifiedContent} tarballs` : 'notOk' 88 const npmV = npm.version 89 const nodeV = process.version.replace('v', '') 90 const registry = npm.config.get('registry') || '' 91 const list = [ 92 ['npm ping', ping], 93 ['npm -v', 'v' + npmV], 94 ['node -v', 'v' + nodeV], 95 ['npm config get registry', registry], 96 ['which git', whichGit], 97 ['Perms check on cached files', readbleCaches], 98 ['Perms check on global node_modules', executableGlobalModules], 99 ['Perms check on local node_modules', executableLocalModules], 100 ['Verify cache contents', cacheStatus] 101 ] 102 103 if (p[0] !== 200) list[0][2] = 'Check your internet connection' 104 if (!semver.satisfies(npmV, '>=' + npmLTS)) list[1][2] = 'Use npm v' + npmLTS 105 if (!semver.satisfies(nodeV, '>=' + nodeLTS)) list[2][2] = 'Use node v' + nodeLTS 106 if (registry !== defaultRegistry) list[3][2] = 'Try `npm config set registry ' + defaultRegistry + '`' 107 if (whichGit === 'not installed') list[4][2] = 'Install git and ensure it\'s in your PATH.' 108 if (readbleCaches !== 'ok') list[5][2] = 'Check the permissions of your files in ' + npm.config.get('cache') 109 if (executableGlobalModules !== 'ok') list[6][2] = globalNodeModules + ' must be readable and writable by the current user.' 110 if (executableLocalModules !== 'ok') list[7][2] = localNodeModules + ' must be readable and writable by the current user.' 111 112 return list 113} 114