• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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