Skip to content

Commit

Permalink
fix(help): allow printing for invalid commands
Browse files Browse the repository at this point in the history
When an invalid subcommand is used, you can pass `data.argv.remain`
to the `help` command's run function and it will make it visible
what the error is.

Semver: patch
  • Loading branch information
evanlucas authored and esatterwhite committed Mar 1, 2021
1 parent f5f287e commit 1a13e9c
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 5 deletions.
26 changes: 24 additions & 2 deletions lib/commands/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,37 @@ module.exports = new Command({
})

const commands = require('./')
const cls = lookup.length
let cls = lookup.length
? commands.resolve(lookup)
: commands.get(cmd)

let output = []
if (cls === undefined && lookup.length) {
while (cls === undefined && lookup.length) {
// This means the last lookup failed.
// So, pop it off
const bad_command = lookup.pop()
const pre_command = conf.get('name') + ' ' + lookup.join(' ')
const len = pre_command.length + 1
output = [
'Invalid command:'
, ''
, `$ ${pre_command} ${this.colorize('red', bad_command)}`
, '-'.repeat(len + 2) + '^'.repeat(bad_command.length)
, ''
, `Below is the usage for ${this.colorize('bold', pre_command)}:`
, ''
]

cls = commands.resolve(lookup)
}
}

const instance = HELP_REGEX.test(cmd)
? this
: typeof cls === 'function' ? new cls() : cls

let output = [instance.description]
output.push(instance.description)

try {
const breaker = '='.repeat(instance.description.length)
Expand Down
56 changes: 53 additions & 3 deletions test/command.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ test('command', async (t) => {
})

// usage parsing
t.test('~usage', async (tt) => {
test('should accept a single string', async (t) => {
t.test('~usage', async (t) => {
t.test('should accept a single string', async (t) => {
const UsageCommand = new Command({
usage: "usage -a 'fake' --verbose"
, args: ['--no-color']
Expand Down Expand Up @@ -104,7 +104,7 @@ test('command', async (t) => {
commands.unregister('usage')
})

test('should accept an array of strings', async (t) => {
t.test('should accept an array of strings', async (t) => {
const UsageCommand = new Command({
usage: [
"usage -a 'fake' --verbose"
Expand All @@ -116,6 +116,56 @@ test('command', async (t) => {
const stdout = fs.readFileSync(fixture_path, 'utf8')
t.equal(strip(UsageCommand.usage), stdout)
})

t.test('handles missing subcommands', async (t) => {
const a = new Command({
name: 'a'
, usage: ['get a']
, run: async function() {}
})

const b = new Command({
name: 'b'
, usage: ['get b']
, run: async function() {}
})

const CmdA = new Command({
name: 'get'
, usage: [
...a.options.usage
, ...b.options.usage
]
, commands: [a, b]
, run: async function(cmd, flags) {
if (cmd && !this.has(cmd)) {
const error = new Error(`unknown waves action ${cmd}`)
error.code = 'ENOCOMMAND'
throw error
}

const help = cli.commands.get('help')
console.log(flags.argv.remain)
return help.run(flags.argv.remain)
}
})

commands.register(CmdA)
t.on('end', () => {
commands.unregister('get')
})
Help.removeAllListeners()
Help.reset()
Help.setOptions({
args: ['--no-color', 'get', 'c']
})

{
const content = await Help.run()
t.match(content.trim(), /Invalid command:/)
t.match(content, /\$ command\.spec get c/)
}
})
})

// internal argv parsing
Expand Down

0 comments on commit 1a13e9c

Please sign in to comment.