diff --git a/lib/command.js b/lib/command.js index 248ef67e7..2deac2706 100644 --- a/lib/command.js +++ b/lib/command.js @@ -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() diff --git a/lib/validation.ts b/lib/validation.ts index 8277e4374..731e18caa 100644 --- a/lib/validation.ts +++ b/lib/validation.ts @@ -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() @@ -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) @@ -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 @@ -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 } diff --git a/test/validation.js b/test/validation.js index f562a93a3..8d438eaa2 100644 --- a/test/validation.js +++ b/test/validation.js @@ -320,6 +320,7 @@ describe('validation tests', () => { return done() }) .parse() + expect.fail('no parsing failure') }) it('fails in strict mode with invalid command', (done) => { @@ -333,6 +334,7 @@ describe('validation tests', () => { return done() }) .parse() + expect.fail('no parsing failure') }) it('fails in strict mode with extra positionals', (done) => { @@ -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 ', '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) diff --git a/yargs.js b/yargs.js index 623d77a85..e00fa0329 100644 --- a/yargs.js +++ b/yargs.js @@ -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) @@ -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)