did-you-mean.js 1.3 KB

12345678910111213141516171819202122232425262728293031323334
  1. const { distance } = require('fastest-levenshtein')
  2. const readJson = require('read-package-json-fast')
  3. const { cmdList } = require('./cmd-list.js')
  4. const didYouMean = async (npm, path, scmd) => {
  5. let best = cmdList
  6. .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && scmd !== cmd)
  7. .map(str => ` npm ${str} # ${npm.commands[str].description}`)
  8. // We would already be suggesting this in `npm x` so omit them here
  9. const runScripts = ['stop', 'start', 'test', 'restart']
  10. try {
  11. const { bin, scripts } = await readJson(`${path}/package.json`)
  12. best = best.concat(
  13. Object.keys(scripts || {})
  14. .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 &&
  15. !runScripts.includes(cmd))
  16. .map(str => ` npm run ${str} # run the "${str}" package script`),
  17. Object.keys(bin || {})
  18. .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4)
  19. .map(str => ` npm exec ${str} # run the "${str}" command from either this or a remote npm package`)
  20. )
  21. } catch (_) {
  22. // gracefully ignore not being in a folder w/ a package.json
  23. }
  24. if (best.length === 0)
  25. return ''
  26. const suggestion = best.length === 1 ? `\n\nDid you mean this?\n${best[0]}`
  27. : `\n\nDid you mean one of these?\n${best.slice(0, 3).join('\n')}`
  28. return suggestion
  29. }
  30. module.exports = didYouMean