Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(strict mode): report default command unknown arguments #1626

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/command.js
Expand Up @@ -197,7 +197,7 @@ module.exports = function command (yargs, usage, validation, globalMiddleware) {

// we apply validation post-hoc, so that custom
// checks get passed populated positional arguments.
if (!yargs._hasOutput()) yargs._runValidation(innerArgv, aliases, positionalMap, yargs.parsed.error)
if (!yargs._hasOutput()) yargs._runValidation(innerArgv, aliases, positionalMap, yargs.parsed.error, !command)

if (commandHandler.handler && !yargs._hasOutput()) {
yargs._setHasOutput()
Expand Down
13 changes: 9 additions & 4 deletions lib/validation.ts
Expand Up @@ -114,7 +114,7 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1
}

// check for unknown arguments (strict-mode).
self.unknownArguments = function unknownArguments (argv, aliases, positionalMap) {
self.unknownArguments = function unknownArguments (argv, aliases, positionalMap, isDefaultCommand) {
const commandKeys = yargs.getCommandInstance().getCommands()
const unknown: string[] = []
const currentContext = yargs.getContext()
Expand All @@ -129,7 +129,7 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1
}
})

if ((currentContext.commands.length > 0) || (commandKeys.length > 0)) {
if ((currentContext.commands.length > 0) || (commandKeys.length > 0) || isDefaultCommand) {
argv._.slice(currentContext.commands.length).forEach((key) => {
if (commandKeys.indexOf(key) === -1) {
unknown.push(key)
Expand Down Expand Up @@ -405,7 +405,7 @@ export function validation (yargs: YargsInstance, usage: UsageInstance, y18n: Y1
}

/** Instance of the validation module. */
interface ValidationInstance {
export interface ValidationInstance {
check(f: CustomCheck['func'], global: boolean): void
conflicting(argv: Arguments): void
conflicts(key: string, value: string | string[]): void
Expand All @@ -425,7 +425,12 @@ interface ValidationInstance {
requiredArguments(argv: Arguments): void
reset(localLookup: Dictionary): ValidationInstance
unfreeze(): void
unknownArguments(argv: Arguments, aliases: DetailedArguments['aliases'], positionalMap: Dictionary): void
unknownArguments(
argv: Arguments,
aliases: DetailedArguments['aliases'],
positionalMap: Dictionary,
isDefaultCommand: boolean
): void
unknownCommands(argv: Arguments): boolean
}

Expand Down
14 changes: 14 additions & 0 deletions test/validation.js
Expand Up @@ -320,6 +320,7 @@ describe('validation tests', () => {
return done()
})
.parse()
expect.fail('no parsing failure')
})

it('fails in strict mode with invalid command', (done) => {
Expand All @@ -333,6 +334,7 @@ describe('validation tests', () => {
return done()
})
.parse()
expect.fail('no parsing failure')
})

it('fails in strict mode with extra positionals', (done) => {
Expand All @@ -347,6 +349,18 @@ describe('validation tests', () => {
expect.fail('no parsing failure')
})

it('fails in strict mode with extra positionals for default command', (done) => {
yargs(['jumping', 'fast'])
.command('$0 <status>', 'kangaroo handlers')
.strict()
.fail((msg) => {
msg.should.equal('Unknown argument: fast')
return done()
})
.parse()
expect.fail('no parsing failure')
})

it('does not fail in strict mode when no commands configured', () => {
const argv = yargs('koala')
.demand(1)
Expand Down
4 changes: 2 additions & 2 deletions yargs.js
Expand Up @@ -1261,7 +1261,7 @@ function Yargs (processArgs, cwd, parentRequire) {
return argv
}

self._runValidation = function runValidation (argv, aliases, positionalMap, parseErrors) {
self._runValidation = function runValidation (argv, aliases, positionalMap, parseErrors, isDefaultCommand = false) {
if (parseErrors) throw new YError(parseErrors.message)
validation.nonOptionCount(argv)
validation.requiredArguments(argv)
Expand All @@ -1270,7 +1270,7 @@ function Yargs (processArgs, cwd, parentRequire) {
failedStrictCommands = validation.unknownCommands(argv)
}
if (strict && !failedStrictCommands) {
validation.unknownArguments(argv, aliases, positionalMap)
validation.unknownArguments(argv, aliases, positionalMap, isDefaultCommand)
}
validation.customChecks(argv, aliases)
validation.limitedChoices(argv)
Expand Down