Skip to content

Commit e5f1948

Browse files
committed
fix: run update notifier after exec but before waiting
1 parent f309c1c commit e5f1948

File tree

3 files changed

+30
-28
lines changed

3 files changed

+30
-28
lines changed

lib/cli/entry.js

+16-13
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ module.exports = async (process, validateEngines) => {
3636
log.warn('cli', validateEngines.unsupportedMessage)
3737
}
3838

39-
let cmd
4039
// Now actually fire up npm and run the command.
4140
// This is how to use npm programmatically:
4241
try {
@@ -46,20 +45,15 @@ module.exports = async (process, validateEngines) => {
4645
return exitHandler()
4746
}
4847

49-
cmd = npm.argv.shift()
50-
if (!cmd) {
48+
const command = npm.argv.shift()
49+
const args = npm.argv
50+
51+
if (!command) {
5152
output.standard(npm.usage)
5253
process.exitCode = 1
5354
return exitHandler()
5455
}
5556

56-
// this is async but we dont await it, since its ok if it doesnt
57-
// finish before the command finishes running. it uses command and argv
58-
// so it must be initiated here, after the command name is set
59-
const updateNotifier = require('./update-notifier.js')
60-
// eslint-disable-next-line promise/catch-or-return
61-
updateNotifier(npm).then((msg) => (npm.updateNotification = msg))
62-
6357
// Options are prefixed by a hyphen-minus (-, \u2d).
6458
// Other dash-type chars look similar but are invalid.
6559
const nonDashArgs = npm.argv.filter(a => /^[\u2010-\u2015\u2212\uFE58\uFE63\uFF0D]/.test(a))
@@ -71,13 +65,22 @@ module.exports = async (process, validateEngines) => {
7165
)
7266
}
7367

74-
await npm.exec(cmd)
68+
const execPromise = npm.exec(command, args)
69+
70+
// this is async but we dont await it, since its ok if it doesnt
71+
// finish before the command finishes running. it uses command and argv
72+
// so it must be initiated here, after the command name is set
73+
const updateNotifier = require('./update-notifier.js')
74+
// eslint-disable-next-line promise/catch-or-return
75+
updateNotifier(npm).then((msg) => (npm.updateNotification = msg))
76+
77+
await execPromise
7578
return exitHandler()
7679
} catch (err) {
7780
if (err.code === 'EUNKNOWNCOMMAND') {
7881
const didYouMean = require('../utils/did-you-mean.js')
79-
const suggestions = await didYouMean(npm.localPrefix, cmd)
80-
output.standard(`Unknown command: "${cmd}"${suggestions}\n`)
82+
const suggestions = await didYouMean(npm.localPrefix, err.command)
83+
output.standard(`Unknown command: "${err.command}"${suggestions}\n`)
8184
output.standard('To see a list of supported npm commands, run:\n npm help')
8285
process.exitCode = 1
8386
return exitHandler()

lib/npm.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Npm {
2222
if (!command) {
2323
throw Object.assign(new Error(`Unknown command ${c}`), {
2424
code: 'EUNKNOWNCOMMAND',
25+
command: c,
2526
})
2627
}
2728
return require(`./commands/${command}.js`)
@@ -90,18 +91,18 @@ class Npm {
9091
}
9192

9293
// Call an npm command
93-
// TODO: tests are currently the only time the second
94-
// parameter of args is used. When called via `lib/cli.js` the config is
95-
// loaded and this.argv is set to the remaining command line args. We should
96-
// consider testing the CLI the same way it is used and not allow args to be
97-
// passed in directly.
9894
async exec (cmd, args = this.argv) {
9995
const command = this.setCmd(cmd)
10096
return time.start(`command:${cmd}`, () => command.cmdExec(args))
10197
}
10298

10399
async load () {
104-
return time.start('npm:load', () => this.#load().then(r => r || { exec: true }))
100+
return time.start('npm:load', async () => {
101+
const { exec = true } = await this.#load().then(r => r ?? {})
102+
return {
103+
exec,
104+
}
105+
})
105106
}
106107

107108
get loaded () {

lib/utils/did-you-mean.js

+7-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const didYouMean = async (path, scmd) => {
88
let best = []
99
for (const str of close) {
1010
const cmd = Npm.cmd(str)
11-
best.push(` npm ${str} # ${cmd.description}`)
11+
best.push(` npm ${str} # ${cmd.description}`)
1212
}
1313
// We would already be suggesting this in `npm x` so omit them here
1414
const runScripts = ['stop', 'start', 'test', 'restart']
@@ -17,25 +17,23 @@ const didYouMean = async (path, scmd) => {
1717
best = best.concat(
1818
Object.keys(scripts || {})
1919
.filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && !runScripts.includes(cmd))
20-
.map(str => ` npm run ${str} # run the "${str}" package script`),
20+
.map(str => ` npm run ${str} # run the "${str}" package script`),
2121
Object.keys(bin || {})
2222
.filter(cmd => distance(scmd, cmd) < scmd.length * 0.4)
2323
/* eslint-disable-next-line max-len */
24-
.map(str => ` npm exec ${str} # run the "${str}" command from either this or a remote npm package`)
24+
.map(str => ` npm exec ${str} # run the "${str}" command from either this or a remote npm package`)
2525
)
26-
} catch (_) {
26+
} catch {
2727
// gracefully ignore not being in a folder w/ a package.json
2828
}
2929

3030
if (best.length === 0) {
3131
return ''
3232
}
3333

34-
const suggestion =
35-
best.length === 1
36-
? `\n\nDid you mean this?\n${best[0]}`
37-
: `\n\nDid you mean one of these?\n${best.slice(0, 3).join('\n')}`
38-
return suggestion
34+
return best.length === 1
35+
? `\n\nDid you mean this?\n${best[0]}`
36+
: `\n\nDid you mean one of these?\n${best.slice(0, 3).join('\n')}`
3937
}
4038

4139
module.exports = didYouMean

0 commit comments

Comments
 (0)