From 1faa5b33dcc6d7e4eba1c0d85ad30cf0c237c9e1 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 20 Aug 2020 17:38:30 -0700 Subject: [PATCH] help: show usage when help-search finds no results Fix https://github.com/npm/cli/issues/1655 --- lib/help-search.js | 12 +++++- lib/help.js | 84 ++--------------------------------------- lib/utils/npm-usage.js | 85 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 82 deletions(-) create mode 100644 lib/utils/npm-usage.js diff --git a/lib/help-search.js b/lib/help-search.js index 8c29e7b74a4bb..6d8cf60069ecb 100644 --- a/lib/help-search.js +++ b/lib/help-search.js @@ -7,10 +7,14 @@ const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') const { promisify } = require('util') const readFile = promisify(fs.readFile) +const didYouMean = require('./utils/did-you-mean.js') +const { cmdList } = require('./utils/cmd-list.js') const usage = usageUtil('help-search', 'npm help-search ') const completion = require('./utils/completion/none.js') +const npmUsage = require('./utils/npm-usage.js') + const cmd = (args, cb) => helpSearch(args).then(() => cb()).catch(cb) const helpSearch = async args => { @@ -26,7 +30,13 @@ const helpSearch = async args => { const data = await readFiles(files) const results = await searchFiles(args, data, files) - output(formatResults(args, results)) + const formatted = formatResults(args, results) + if (!formatted.trim()) { + npmUsage(false) + } else { + output(formatted) + output(didYouMean(args[0], cmdList)) + } } const readFiles = async files => { diff --git a/lib/help.js b/lib/help.js index 7dddadf879a07..55e2de5776ae5 100644 --- a/lib/help.js +++ b/lib/help.js @@ -6,15 +6,13 @@ help.completion = function (opts, cb) { getSections(cb) } +const npmUsage = require('./utils/npm-usage.js') var path = require('path') var spawn = require('./utils/spawn') var npm = require('./npm.js') var log = require('npmlog') var openUrl = require('./utils/open-url') var glob = require('glob') -var didYouMean = require('./utils/did-you-mean') -var cmdList = require('./utils/cmd-list').cmdList -var commands = cmdList var output = require('./utils/output.js') const usage = require('./utils/usage.js') @@ -42,7 +40,8 @@ function help (args, cb) { // npm help : show basic usage if (!section) { var valid = argv[0] === 'help' ? 0 : 1 - return npmUsage(valid, cb) + npmUsage(argv[0] === 'help') + return cb() } // npm -h: show command usage @@ -161,83 +160,6 @@ function htmlMan (man) { return 'file://' + path.resolve(__dirname, '..', 'docs', 'public', sect, f, 'index.html') } -function npmUsage (valid, cb) { - npm.config.set('loglevel', 'silent') - log.level = 'silent' - output(` -Usage: npm - -npm install install all the dependencies in your project -npm install add the dependency to your project -npm test run this project's tests -npm run run the script named -npm -h quick help on -npm -l display usage info for all commands -npm help search for help on -npm help npm more involved overview - -All commands: -${npm.config.get('long') ? usages() : ('\n ' + wrap(commands))} - -Specify configs in the ini-formatted file: - ${npm.config.get('userconfig')} -or on the command line via: npm --key=value - -More configuration info: npm help config -Configuration fields: npm help 7 config - -npm@${npm.version} ${path.dirname(__dirname)} -`) - - if (npm.argv.length > 1) { - output(didYouMean(npm.argv[1], commands)) - } - - cb(valid) -} - -function usages () { - // return a string of : - var maxLen = 0 - return commands.reduce(function (set, c) { - set.push([c, require(`./${npm.deref(c)}.js`).usage || '']) - maxLen = Math.max(maxLen, c.length) - return set - }, []).sort((a, b) => { - return a[0].localeCompare(b[0]) - }).map(function (item) { - var c = item[0] - var usage = item[1] - return '\n ' + - c + (new Array(maxLen - c.length + 2).join(' ')) + - (usage.split('\n').join('\n' + (new Array(maxLen + 6).join(' ')))) - }).join('\n') -} - -function wrap (arr) { - var out = [''] - var l = 0 - var line - - line = process.stdout.columns - if (!line) { - line = 60 - } else { - line = Math.min(60, Math.max(line - 16, 24)) - } - - arr.sort(function (a, b) { return a < b ? -1 : 1 }) - .forEach(function (c) { - if (out[l].length + c.length + 2 < line) { - out[l] += ', ' + c - } else { - out[l++] += ',' - out[l] = c - } - }) - return out.join('\n ').substr(2) -} - function getSections (cb) { var g = path.resolve(__dirname, '../man/man[0-9]/*.[0-9]') glob(g, function (er, files) { diff --git a/lib/utils/npm-usage.js b/lib/utils/npm-usage.js new file mode 100644 index 0000000000000..8453329151dde --- /dev/null +++ b/lib/utils/npm-usage.js @@ -0,0 +1,85 @@ +const npm = require('../npm.js') +const didYouMean = require('./did-you-mean.js') +const { dirname } = require('path') +const output = require('./output.js') +const { cmdList } = require('./cmd-list') + +module.exports = (valid = true) => { + npm.config.set('loglevel', 'silent') + npm.log.level = 'silent' + output(` +Usage: npm + +npm install install all the dependencies in your project +npm install add the dependency to your project +npm test run this project's tests +npm run run the script named +npm -h quick help on +npm -l display usage info for all commands +npm help search for help on +npm help npm more involved overview + +All commands: +${npm.config.get('long') ? usages() : ('\n ' + wrap(cmdList))} + +Specify configs in the ini-formatted file: + ${npm.config.get('userconfig')} +or on the command line via: npm --key=value + +More configuration info: npm help config +Configuration fields: npm help 7 config + +npm@${npm.version} ${dirname(dirname(__dirname))} +`) + + if (npm.argv.length >= 1) { + output(didYouMean(npm.argv[0], cmdList)) + } + + if (!valid) { + process.exitCode = 1 + } +} + +const wrap = (arr) => { + var out = [''] + var l = 0 + var line + + line = process.stdout.columns + if (!line) { + line = 60 + } else { + line = Math.min(60, Math.max(line - 16, 24)) + } + + arr.sort(function (a, b) { return a < b ? -1 : 1 }) + .forEach(function (c) { + if (out[l].length + c.length + 2 < line) { + out[l] += ', ' + c + } else { + out[l++] += ',' + out[l] = c + } + }) + return out.join('\n ').substr(2) +} + +const usages = () => { + // return a string of : + var maxLen = 0 + return cmdList.reduce(function (set, c) { + set.push([c, require(`./${npm.deref(c)}.js`).usage || '']) + maxLen = Math.max(maxLen, c.length) + return set + }, []).sort((a, b) => { + return a[0].localeCompare(b[0]) + }).map(function (item) { + var c = item[0] + var usage = item[1] + return '\n ' + + c + (new Array(maxLen - c.length + 2).join(' ')) + + (usage.split('\n').join('\n' + (new Array(maxLen + 6).join(' ')))) + }).join('\n') +} +