Repository: yargs/yargs
Pull request #840 (2017-03-27 01:04:53)

Allow command to override global strict
This adds a second argument to `strict` to disable it for a command.

bcoe: @zodern thanks for the patch; I'm not seeing immediately why this additional configuration option is required. Could you provide some information about your specific use-case.

Patch:
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..3fd345c
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,14 @@
+root = true
+
+[*]
+
+indent_style = space
+indent_size = 2
+
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5dc5fd..eadcd6a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,23 @@
 
 All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
 
+<a name="7.1.0"></a>
+# [7.1.0](https://github.com/yargs/yargs/compare/v7.0.2...v7.1.0) (2017-04-13)
+
+
+### Bug Fixes
+
+* fix demandOption no longer treats 'false' as truthy ([#829](https://github.com/yargs/yargs/issues/829)) ([c748dd2](https://github.com/yargs/yargs/commit/c748dd2))
+* get terminalWidth in non interactive mode no longer causes a validation exception ([#837](https://github.com/yargs/yargs/issues/837)) ([360e301](https://github.com/yargs/yargs/commit/360e301))
+* we shouldn't output help if we've printed a prior help-like message ([#847](https://github.com/yargs/yargs/issues/847)) ([17e89bd](https://github.com/yargs/yargs/commit/17e89bd))
+
+
+### Features
+
+* add support for numeric commands ([#825](https://github.com/yargs/yargs/issues/825)) ([fde0564](https://github.com/yargs/yargs/commit/fde0564))
+
+
+
 <a name="7.0.2"></a>
 ## [7.0.2](https://github.com/yargs/yargs/compare/v7.0.1...v7.0.2) (2017-03-10)
 
diff --git a/README.md b/README.md
index 34da336..0654760 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ With yargs, ye be havin' a map that leads straight to yer treasure! Treasure of
 [![NPM version][npm-image]][npm-url]
 [![Windows Tests][windows-image]][windows-url]
 [![js-standard-style][standard-image]][standard-url]
-[![standard-version][standard-version-image]][standard-version-url]
+[![Conventional Commits][conventional-commits-image]][conventional-commits-url]
 [![Gitter][gitter-image]][gitter-url]
 
 > Yargs is the official successor to optimist. Please feel free to submit issues and pull requests. If you'd like to contribute and don't know where to start, have a look at [the issue list](https://github.com/yargs/yargs/issues) :)
@@ -1809,7 +1809,7 @@ Specify --help for available options
 Specifies either a single option key (string), or an array of options.
 If any of the options is present, yargs validation is skipped.
 
-.strict([global=true])
+.strict([enabled=true])
 ---------
 
 Any command-line argument given that is not demanded, or does not have a
@@ -2011,7 +2011,7 @@ This module is loosely inspired by Perl's
 [windows-image]: https://img.shields.io/appveyor/ci/bcoe/yargs-ljwvf/master.svg?label=Windows%20Tests
 [standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg
 [standard-url]: http://standardjs.com/
-[standard-version-image]: https://img.shields.io/badge/release-standard%20version-brightgreen.svg
-[standard-version-url]: https://github.com/conventional-changelog/standard-version
+[conventional-commits-image]: https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg
+[conventional-commits-url]: https://conventionalcommits.org/
 [gitter-image]: https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=2592000
 [gitter-url]: https://gitter.im/yargs/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link
diff --git a/package.json b/package.json
index 4666807..a396ea7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "yargs",
-  "version": "7.0.2",
+  "version": "7.1.0",
   "description": "yargs the modern, pirate-themed, successor to optimist.",
   "main": "./index.js",
   "files": [
diff --git a/yargs.js b/yargs.js
index 4e34943..559f170 100644
--- a/yargs.js
+++ b/yargs.js
@@ -126,7 +126,6 @@ function Yargs (processArgs, cwd, parentRequire) {
     command = command ? command.reset() : Command(self, usage, validation)
     if (!completion) completion = Completion(self, usage, command)
 
-    if (!strictGlobal) strict = false
     completionCommand = null
     output = ''
     exitError = null
@@ -695,11 +694,9 @@ function Yargs (processArgs, cwd, parentRequire) {
   }
 
   var strict = false
-  var strictGlobal = false
-  self.strict = function (global) {
-    argsert('[boolean]', [global], arguments.length)
-    strict = true
-    strictGlobal = global !== false
+  self.strict = function (enabled) {
+    argsert('[boolean]', [enabled], arguments.length)
+    strict = enabled !== false
     return self
   }
   self.getStrict = function () {
@@ -922,7 +919,7 @@ function Yargs (processArgs, cwd, parentRequire) {
 
   self.terminalWidth = function () {
     argsert([], 0)
-    return process.stdout.columns
+    return typeof process.stdout.columns !== 'undefined' ? process.stdout.columns : null
   }
 
   Object.defineProperty(self, 'argv', {
@@ -983,7 +980,8 @@ function Yargs (processArgs, cwd, parentRequire) {
         var handlerKeys = command.getCommands()
         if (handlerKeys.length) {
           var firstUnknownCommand
-          for (var i = 0, cmd; (cmd = argv._[i]) !== undefined; i++) {
+          for (var i = 0, cmd; argv._[i] !== undefined; i++) {
+            cmd = String(argv._[i])
             if (~handlerKeys.indexOf(cmd) && cmd !== completionCommand) {
               setPlaceholderKeys(argv)
               return command.runCommand(cmd, self, parsed)
@@ -1035,21 +1033,24 @@ function Yargs (processArgs, cwd, parentRequire) {
       }
 
       // Handle 'help' and 'version' options
-      Object.keys(argv).forEach(function (key) {
-        if (key === helpOpt && argv[key]) {
-          if (exitProcess) setBlocking(true)
-
-          skipValidation = true
-          self.showHelp('log')
-          self.exit(0)
-        } else if (key === versionOpt && argv[key]) {
-          if (exitProcess) setBlocking(true)
-
-          skipValidation = true
-          usage.showVersion()
-          self.exit(0)
-        }
-      })
+      // if we haven't already output help!
+      if (!hasOutput) {
+        Object.keys(argv).forEach(function (key) {
+          if (key === helpOpt && argv[key]) {
+            if (exitProcess) setBlocking(true)
+
+            skipValidation = true
+            self.showHelp('log')
+            self.exit(0)
+          } else if (key === versionOpt && argv[key]) {
+            if (exitProcess) setBlocking(true)
+
+            skipValidation = true
+            usage.showVersion()
+            self.exit(0)
+          }
+        })
+      }
 
       // Check if any of the options to skip validation were provided
       if (!skipValidation && options.skipValidation.length > 0) {


Test patch:
diff --git a/test/command.js b/test/command.js
index 0af0929..196b783 100644
--- a/test/command.js
+++ b/test/command.js
@@ -1000,19 +1000,6 @@ describe('Command', function () {
         commandCalled.should.be.true
       })
 
-      it('does not apply strict globally when passed value of `false`', function () {
-        var commandCalled = false
-        yargs('hi')
-          .strict(false)
-          .command('hi', 'The hi command', function (innerYargs) {
-            commandCalled = true
-            innerYargs.getStrict().should.be.false
-          })
-        yargs.getStrict().should.be.true
-        yargs.argv // parse and run command
-        commandCalled.should.be.true
-      })
-
       // address regression introduced in #766, thanks @nexdrew!
       it('does not fail strict check due to postional command arguments', function (done) {
         yargs()
@@ -1037,6 +1024,19 @@ describe('Command', function () {
           })
       })
 
+      it('allows a command to override global`', function () {
+        var commandCalled = false
+        yargs('hi')
+         .strict()
+         .command('hi', 'The hi command', function (innerYargs) {
+           commandCalled = true
+           innerYargs.strict(false).getStrict().should.be.false
+         })
+        yargs.getStrict().should.be.true
+        yargs.argv // parse and run command
+        commandCalled.should.be.true
+      })
+
       it('does not fire command if validation fails', function (done) {
         var commandRun = false
         yargs()
@@ -1317,4 +1317,14 @@ describe('Command', function () {
     called.should.equal(false)
     r.errors.should.match(/Missing required argument/)
   })
+
+  it('should support numeric commands', function () {
+    var output = []
+    yargs('1')
+      .command('1', 'numeric command', function (yargs) {
+        output.push('1')
+      })
+      .argv
+    output.should.include('1')
+  })
 })
diff --git a/test/yargs.js b/test/yargs.js
index 078bee9..5e46d8b 100644
--- a/test/yargs.js
+++ b/test/yargs.js
@@ -225,7 +225,6 @@ describe('yargs dsl tests', function () {
         .implies('foo', 'snuh')
         .conflicts('qux', 'xyzzy')
         .group('foo', 'Group:')
-        .strict(false)
         .exitProcess(false)  // defaults to true.
         .global('foo', false)
         .global('qux', false)
@@ -266,7 +265,6 @@ describe('yargs dsl tests', function () {
       expect(y.getValidationInstance().getConflicting()).to.deep.equal({})
       expect(y.getCommandInstance().getCommandHandlers()).to.deep.equal({})
       expect(y.getExitProcess()).to.equal(false)
-      expect(y.getStrict()).to.equal(false)
       expect(y.getDemandedOptions()).to.deep.equal({})
       expect(y.getDemandedCommands()).to.deep.equal({})
       expect(y.getGroups()).to.deep.equal({})
@@ -339,6 +337,21 @@ describe('yargs dsl tests', function () {
       r.errors[1].should.match(/Did you mean goat/)
     })
 
+    // see: https://github.com/yargs/yargs/issues/822
+    it('does not print help message if recommendation has been made', function (done) {
+      const parser = yargs()
+        .command('goat')
+        .help()
+        .recommendCommands()
+
+      parser.parse('boat help', {}, function (err, _argv, output) {
+        // it should not have printed the help text twice!
+        err.message.should.equal('Did you mean goat?')
+        output.split('Commands:').length.should.equal(2)
+        return done()
+      })
+    })
+
     it("skips executing top-level command if builder's help is executed", function () {
       var r = checkOutput(function () {
         yargs(['blerg', '-h'])