[Pkg-javascript-commits] [node-yargs-parser] 01/03: Import Upstream version 4.0.2

Sruthi Chandran srud-guest at moszumanska.debian.org
Thu Nov 3 13:42:01 UTC 2016


This is an automated email from the git hooks/post-receive script.

srud-guest pushed a commit to branch master
in repository node-yargs-parser.

commit 1568158ce2923589cfdcd86266e85b5e41186c52
Author: Sruthi <srud at disroot.org>
Date:   Thu Nov 3 19:00:30 2016 +0530

    Import Upstream version 4.0.2
---
 .gitignore                       |    4 +
 .travis.yml                      |   15 +
 CHANGELOG.md                     |  118 +++
 LICENSE.txt                      |   14 +
 README.md                        |  219 ++++
 appveyor.yml                     |   21 +
 example.js                       |    3 +
 index.js                         |  727 +++++++++++++
 lib/tokenize-arg-string.js       |   34 +
 package.json                     |   43 +
 test/fixtures/config.json        |    7 +
 test/fixtures/config.txt         |    2 +
 test/fixtures/nested_config.json |    8 +
 test/fixtures/settings.js        |    6 +
 test/tokenize-arg-string.js      |   40 +
 test/yargs-parser.js             | 2094 ++++++++++++++++++++++++++++++++++++++
 yargs-logo.png                   |  Bin 0 -> 17177 bytes
 17 files changed, 3355 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2454630
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.nyc_output
+node_modules
+.DS_Store
+./test/fixtures/package.json
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..f3760a1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,15 @@
+language: node_js
+os:
+  - linux
+node_js:
+  - "0.10"
+  - "0.12"
+  - "4.1"
+  - "node"
+after_script: npm run coverage
+deploy:
+  provider: npm
+  email: ben at npmjs.com
+  api_key: $NPM_TOKEN
+  on:
+    tags: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..547591d
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,118 @@
+# Change Log
+
+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="4.0.2"></a>
+## [4.0.2](https://github.com/yargs/yargs-parser/compare/v4.0.1...v4.0.2) (2016-09-30)
+
+
+### Bug Fixes
+
+* whoops, let's make the assign not change the Object key order ([29d069a](https://github.com/yargs/yargs-parser/commit/29d069a))
+
+
+
+<a name="4.0.1"></a>
+## [4.0.1](https://github.com/yargs/yargs-parser/compare/v4.0.0...v4.0.1) (2016-09-30)
+
+
+### Bug Fixes
+
+* lodash.assign was deprecated ([#59](https://github.com/yargs/yargs-parser/issues/59)) ([5e7eb11](https://github.com/yargs/yargs-parser/commit/5e7eb11))
+
+
+
+<a name="4.0.0"></a>
+# [4.0.0](https://github.com/yargs/yargs-parser/compare/v3.2.0...v4.0.0) (2016-09-26)
+
+
+### Bug Fixes
+
+* coerce should be applied to the final objects and arrays created ([#57](https://github.com/yargs/yargs-parser/issues/57)) ([4ca69da](https://github.com/yargs/yargs-parser/commit/4ca69da))
+
+
+### BREAKING CHANGES
+
+* coerce is no longer applied to individual arguments in an implicit array.
+
+
+
+<a name="3.2.0"></a>
+# [3.2.0](https://github.com/yargs/yargs-parser/compare/v3.1.0...v3.2.0) (2016-08-13)
+
+
+### Features
+
+* coerce full array instead of each element ([#51](https://github.com/yargs/yargs-parser/issues/51)) ([cc4dc56](https://github.com/yargs/yargs-parser/commit/cc4dc56))
+
+
+
+<a name="3.1.0"></a>
+# [3.1.0](https://github.com/yargs/yargs-parser/compare/v3.0.0...v3.1.0) (2016-08-09)
+
+
+### Bug Fixes
+
+* address pkgConf parsing bug outlined in [#37](https://github.com/yargs/yargs-parser/issues/37) ([#45](https://github.com/yargs/yargs-parser/issues/45)) ([be76ee6](https://github.com/yargs/yargs-parser/commit/be76ee6))
+* better parsing of negative values ([#44](https://github.com/yargs/yargs-parser/issues/44)) ([2e43692](https://github.com/yargs/yargs-parser/commit/2e43692))
+* check aliases when guessing defaults for arguments fixes [#41](https://github.com/yargs/yargs-parser/issues/41) ([#43](https://github.com/yargs/yargs-parser/issues/43)) ([f3e4616](https://github.com/yargs/yargs-parser/commit/f3e4616))
+
+
+### Features
+
+* added coerce option, for providing specialized argument parsing ([#42](https://github.com/yargs/yargs-parser/issues/42)) ([7b49cd2](https://github.com/yargs/yargs-parser/commit/7b49cd2))
+
+
+
+<a name="3.0.0"></a>
+# [3.0.0](https://github.com/yargs/yargs-parser/compare/v2.4.1...v3.0.0) (2016-08-07)
+
+
+### Bug Fixes
+
+* parsing issue with numeric character in group of options ([#19](https://github.com/yargs/yargs-parser/issues/19)) ([f743236](https://github.com/yargs/yargs-parser/commit/f743236))
+* upgraded lodash.assign ([5d7fdf4](https://github.com/yargs/yargs-parser/commit/5d7fdf4))
+
+### BREAKING CHANGES
+
+* subtle change to how values are parsed in a group of single-character arguments.
+* _first released in 3.1.0, better handling of negative values should be considered a breaking change._
+
+
+
+<a name="2.4.1"></a>
+## [2.4.1](https://github.com/yargs/yargs-parser/compare/v2.4.0...v2.4.1) (2016-07-16)
+
+
+### Bug Fixes
+
+* **count:** do not increment a default value ([#39](https://github.com/yargs/yargs-parser/issues/39)) ([b04a189](https://github.com/yargs/yargs-parser/commit/b04a189))
+
+
+
+<a name="2.4.0"></a>
+# [2.4.0](https://github.com/yargs/yargs-parser/compare/v2.3.0...v2.4.0) (2016-04-11)
+
+
+### Features
+
+* **environment:** Support nested options in environment variables ([#26](https://github.com/yargs/yargs-parser/issues/26)) thanks [@elas7](https://github.com/elas7) \o/ ([020778b](https://github.com/yargs/yargs-parser/commit/020778b))
+
+
+
+<a name="2.3.0"></a>
+# [2.3.0](https://github.com/yargs/yargs-parser/compare/v2.2.0...v2.3.0) (2016-04-09)
+
+
+### Bug Fixes
+
+* **boolean:** fix for boolean options with non boolean defaults (#20) ([2dbe86b](https://github.com/yargs/yargs-parser/commit/2dbe86b)), closes [(#20](https://github.com/(/issues/20)
+* **package:** remove tests from tarball ([0353c0d](https://github.com/yargs/yargs-parser/commit/0353c0d))
+* **parsing:** handle calling short option with an empty string as the next value. ([a867165](https://github.com/yargs/yargs-parser/commit/a867165))
+* boolean flag when next value contains the strings 'true' or 'false'. ([69941a6](https://github.com/yargs/yargs-parser/commit/69941a6))
+* update dependencies; add standard-version bin for next release (#24) ([822d9d5](https://github.com/yargs/yargs-parser/commit/822d9d5))
+
+### Features
+
+* **configuration:** Allow to pass configuration objects to yargs-parser ([0780900](https://github.com/yargs/yargs-parser/commit/0780900))
+* **normalize:** allow normalize to work with arrays ([e0eaa1a](https://github.com/yargs/yargs-parser/commit/e0eaa1a))
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..836440b
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,14 @@
+Copyright (c) 2016, Contributors
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice
+appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
+LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..01270d8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,219 @@
+# yargs-parser
+
+[![Build Status](https://travis-ci.org/yargs/yargs-parser.png)](https://travis-ci.org/yargs/yargs-parser)
+[![Coverage Status](https://coveralls.io/repos/yargs/yargs-parser/badge.svg?branch=)](https://coveralls.io/r/yargs/yargs-parser?branch=master)
+[![NPM version](https://img.shields.io/npm/v/yargs-parser.svg)](https://www.npmjs.com/package/yargs-parser)
+[![Windows Tests](https://img.shields.io/appveyor/ci/bcoe/yargs-parser/master.svg?label=Windows%20Tests)](https://ci.appveyor.com/project/bcoe/yargs-parser)
+[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)
+
+
+The mighty option parser used by [yargs](https://github.com/yargs/yargs).
+
+visit the [yargs website](http://yargs.js.org/) for more examples, and thorough usage instructions.
+
+<img width="250" src="yargs-logo.png">
+
+## Example
+
+```sh
+npm i yargs-parser --save
+```
+
+```js
+var argv = require('yargs-parser')(process.argv.slice(2))
+console.log(argv)
+```
+
+```sh
+node example.js --foo=33 --bar hello
+{ _: [], foo: 33, bar: 'hello' }
+```
+
+_or parse a string!_
+
+```js
+var argv = require('./')('--foo=99 --bar=33')
+console.log(argv)
+```
+
+```sh
+{ _: [], foo: 99, bar: 33 }
+```
+
+Convert an array of mixed types before passing to `yargs-parser`:
+
+```js
+var parse = require('yargs-parser')
+parse(['-f', 11, '--zoom', 55].join(' '))   // <-- array to string
+parse(['-f', 11, '--zoom', 55].map(String)) // <-- array of strings
+```
+
+## API
+
+### require('yargs-parser')(args, opts={})
+
+Parses command line arguments returning a simple mapping of keys and values.
+
+**expects:**
+
+* `args`: a string or array of strings representing the options to parse.
+* `opts`: provide a set of hints indicating how `args` should be parsed:
+  * `opts.alias`: an object representing the set of aliases for a key: `{alias: {foo: ['f']}}`.
+  * `opts.array`: indicate that keys should be parsed as an array: `{array: ['foo', 'bar']}`.
+  * `opts.boolean`: arguments should be parsed as booleans: `{boolean: ['x', 'y']}`.
+  * `opts.config`: indicate a key that represents a path to a configuration file (this file will be loaded and parsed).
+  * `opts.coerce`: provide a custom synchronous function that returns a coerced value from the argument provided
+    (or throws an error), e.g. `{coerce: {foo: function (arg) {return modifiedArg}}}`.
+  * `opts.count`: indicate a key that should be used as a counter, e.g., `-vvv` = `{v: 3}`.
+  * `opts.default`: provide default values for keys: `{default: {x: 33, y: 'hello world!'}}`.
+  * `opts.envPrefix`: environment variables (`process.env`) with the prefix provided should be parsed.
+  * `opts.narg`: specify that a key requires `n` arguments: `{narg: {x: 2}}`.
+  * `opts.normalize`: `path.normalize()` will be applied to values set to this key.
+  * `opts.string`: keys should be treated as strings (even if they resemble a number `-x 33`).
+  * `opts.configuration`: provide configuration options to the yargs-parser (see: [configuration](#configuration)).
+  * `opts.number`: keys should be treated as numbers.
+
+**returns:**
+
+* `obj`: an object representing the parsed value of `args`
+  * `key/value`: key value pairs for each argument and their aliases.
+  * `_`: an array representing the positional arguments.
+
+### require('yargs-parser').detailed(args, opts={})
+
+Parses a command line string, returning detailed information required by the
+yargs engine.
+
+**expects:**
+
+* `args`: a string or array of strings representing options to parse.
+* `opts`: provide a set of hints indicating how `args`, inputs are identical to `require('yargs-parser')(args, opts={})`.
+
+**returns:**
+
+* `argv`: an object representing the parsed value of `args`
+  * `key/value`: key value pairs for each argument and their aliases.
+  * `_`: an array representing the positional arguments.
+* `error`: populated with an error object if an exception occurred during parsing.
+* `aliases`: the inferred list of aliases built by combining lists in `opts.alias`.
+* `newAliases`: any new aliases added via camel-case expansion.
+* `configuration`: the configuration loaded from the `yargs` stanza in package.json.
+
+<a name="configuration"></a>
+### Configuration
+
+The yargs-parser applies several automated transformations on the keys provided
+in `args`. These features can be turned on and off using the `configuration` field
+of `opts`.
+
+```js
+var parsed = parser(['--no-dice'], {
+  configuration: {
+    'boolean-negation': false
+  }
+})
+```
+
+### short option groups
+
+* default: `true`.
+* key: `short-option-groups`.
+
+Should a group of short-options be treated as boolean flags?
+
+```sh
+node example.js -abc
+{ _: [], a: true, b: true, c: true }
+```
+
+_if disabled:_
+
+```sh
+node example.js -abc
+{ _: [], abc: true }
+```
+
+### camel-case expansion
+
+* default: `true`.
+* key: `camel-case-expansion`.
+
+Should hyphenated arguments be expanded into camel-case aliases?
+
+```sh
+node example.js --foo-bar
+{ _: [], 'foo-bar': true, fooBar: true }
+```
+
+_if disabled:_
+
+```sh
+node example.js --foo-bar
+{ _: [], 'foo-bar': true }
+```
+
+### dot-notation
+
+* default: `true`
+* key: `dot-notation`
+
+Should keys that contain `.` be treated as objects?
+
+```sh
+node example.js --foo.bar
+{ _: [], foo: { bar: true } }
+```
+
+_if disabled:_
+
+```sh
+node example.js --foo.bar
+{ _: [], "foo.bar": true }
+```
+
+### parse numbers
+
+* default: `true`
+* key: 'parse-numbers'
+
+Should keys that look like numbers be treated as such?
+
+```sh
+node example.js --foo=99.3
+{ _: [], foo: 99.3 }
+```
+
+_if disabled:_
+
+```sh
+node example.js --foo=99.3
+{ _: [], foo: "99.3" }
+```
+
+### boolean negation
+
+* default: `true`
+* key: 'boolean-negation'
+
+Should variables prefixed with `--no` be treated as negations?
+
+```sh
+node example.js --no-foo
+{ _: [], foo: false }
+```
+
+_if disabled:_
+
+```sh
+node example.js --no-foo
+{ _: [], "no-foo": true }
+```
+
+## Special Thanks
+
+The yargs project evolves from optimist and minimist. It owes its
+existence to a lot of James Halliday's hard work. Thanks [substack](https://github.com/substack) **beep** **boop** \o/
+
+## License
+
+ISC
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..2f85f7f
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,21 @@
+environment:
+  matrix:
+    - nodejs_version: '5'
+    - nodejs_version: '4'
+    - nodejs_version: '0.12'
+install:
+  - ps: Install-Product node $env:nodejs_version
+  - set CI=true
+  - npm -g install npm at latest
+  - set PATH=%APPDATA%\npm;%PATH%
+  - npm install
+matrix:
+  fast_finish: true
+build: off
+version: '{build}'
+shallow_clone: true
+clone_depth: 1
+test_script:
+  - node --version
+  - npm --version
+  - npm test
diff --git a/example.js b/example.js
new file mode 100755
index 0000000..1c1ea63
--- /dev/null
+++ b/example.js
@@ -0,0 +1,3 @@
+var parser = require('./')
+var parse = parser(['-cats', 'meow'])
+console.log(parse)
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..564cb2e
--- /dev/null
+++ b/index.js
@@ -0,0 +1,727 @@
+var camelCase = require('camelcase')
+var path = require('path')
+var tokenizeArgString = require('./lib/tokenize-arg-string')
+var util = require('util')
+
+function parse (args, opts) {
+  if (!opts) opts = {}
+  // allow a string argument to be passed in rather
+  // than an argv array.
+  args = tokenizeArgString(args)
+  // aliases might have transitive relationships, normalize this.
+  var aliases = combineAliases(opts.alias || {})
+  var configuration = assign({
+    'short-option-groups': true,
+    'camel-case-expansion': true,
+    'dot-notation': true,
+    'parse-numbers': true,
+    'boolean-negation': true
+  }, opts.configuration)
+  var defaults = opts.default || {}
+  var configObjects = opts.configObjects || []
+  var envPrefix = opts.envPrefix
+  var newAliases = {}
+  // allow a i18n handler to be passed in, default to a fake one (util.format).
+  var __ = opts.__ || function (str) {
+    return util.format.apply(util, Array.prototype.slice.call(arguments))
+  }
+  var error = null
+  var flags = {
+    aliases: {},
+    arrays: {},
+    bools: {},
+    strings: {},
+    numbers: {},
+    counts: {},
+    normalize: {},
+    configs: {},
+    defaulted: {},
+    nargs: {},
+    coercions: {}
+  }
+  var negative = /^-[0-9]+(\.[0-9]+)?/
+
+  ;[].concat(opts.array).filter(Boolean).forEach(function (key) {
+    flags.arrays[key] = true
+  })
+
+  ;[].concat(opts.boolean).filter(Boolean).forEach(function (key) {
+    flags.bools[key] = true
+  })
+
+  ;[].concat(opts.string).filter(Boolean).forEach(function (key) {
+    flags.strings[key] = true
+  })
+
+  ;[].concat(opts.number).filter(Boolean).forEach(function (key) {
+    flags.numbers[key] = true
+  })
+
+  ;[].concat(opts.count).filter(Boolean).forEach(function (key) {
+    flags.counts[key] = true
+  })
+
+  ;[].concat(opts.normalize).filter(Boolean).forEach(function (key) {
+    flags.normalize[key] = true
+  })
+
+  Object.keys(opts.narg || {}).forEach(function (k) {
+    flags.nargs[k] = opts.narg[k]
+  })
+
+  Object.keys(opts.coerce || {}).forEach(function (k) {
+    flags.coercions[k] = opts.coerce[k]
+  })
+
+  if (Array.isArray(opts.config) || typeof opts.config === 'string') {
+    ;[].concat(opts.config).filter(Boolean).forEach(function (key) {
+      flags.configs[key] = true
+    })
+  } else {
+    Object.keys(opts.config || {}).forEach(function (k) {
+      flags.configs[k] = opts.config[k]
+    })
+  }
+
+  // create a lookup table that takes into account all
+  // combinations of aliases: {f: ['foo'], foo: ['f']}
+  extendAliases(opts.key, aliases, opts.default, flags.arrays)
+
+  // apply default values to all aliases.
+  Object.keys(defaults).forEach(function (key) {
+    (flags.aliases[key] || []).forEach(function (alias) {
+      defaults[alias] = defaults[key]
+    })
+  })
+
+  var argv = { _: [] }
+
+  Object.keys(flags.bools).forEach(function (key) {
+    setArg(key, !(key in defaults) ? false : defaults[key])
+    setDefaulted(key)
+  })
+
+  var notFlags = []
+  if (args.indexOf('--') !== -1) {
+    notFlags = args.slice(args.indexOf('--') + 1)
+    args = args.slice(0, args.indexOf('--'))
+  }
+
+  for (var i = 0; i < args.length; i++) {
+    var arg = args[i]
+    var broken
+    var key
+    var letters
+    var m
+    var next
+    var value
+
+    // -- seperated by =
+    if (arg.match(/^--.+=/) || (
+      !configuration['short-option-groups'] && arg.match(/^-.+=/)
+    )) {
+      // Using [\s\S] instead of . because js doesn't support the
+      // 'dotall' regex modifier. See:
+      // http://stackoverflow.com/a/1068308/13216
+      m = arg.match(/^--?([^=]+)=([\s\S]*)$/)
+
+      // nargs format = '--f=monkey washing cat'
+      if (checkAllAliases(m[1], flags.nargs)) {
+        args.splice(i + 1, 0, m[2])
+        i = eatNargs(i, m[1], args)
+      // arrays format = '--f=a b c'
+      } else if (checkAllAliases(m[1], flags.arrays) && args.length > i + 1) {
+        args.splice(i + 1, 0, m[2])
+        i = eatArray(i, m[1], args)
+      } else {
+        setArg(m[1], m[2])
+      }
+    } else if (arg.match(/^--no-.+/) && configuration['boolean-negation']) {
+      key = arg.match(/^--no-(.+)/)[1]
+      setArg(key, false)
+
+    // -- seperated by space.
+    } else if (arg.match(/^--.+/) || (
+      !configuration['short-option-groups'] && arg.match(/^-.+/)
+    )) {
+      key = arg.match(/^--?(.+)/)[1]
+
+      // nargs format = '--foo a b c'
+      if (checkAllAliases(key, flags.nargs)) {
+        i = eatNargs(i, key, args)
+      // array format = '--foo a b c'
+      } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
+        i = eatArray(i, key, args)
+      } else {
+        next = args[i + 1]
+
+        if (next !== undefined && (!next.match(/^-/) ||
+          next.match(negative)) &&
+          !checkAllAliases(key, flags.bools) &&
+          !checkAllAliases(key, flags.counts)) {
+          setArg(key, next)
+          i++
+        } else if (/^(true|false)$/.test(next)) {
+          setArg(key, next)
+          i++
+        } else {
+          setArg(key, defaultForType(guessType(key, flags)))
+        }
+      }
+
+    // dot-notation flag seperated by '='.
+    } else if (arg.match(/^-.\..+=/)) {
+      m = arg.match(/^-([^=]+)=([\s\S]*)$/)
+      setArg(m[1], m[2])
+
+    // dot-notation flag seperated by space.
+    } else if (arg.match(/^-.\..+/)) {
+      next = args[i + 1]
+      key = arg.match(/^-(.\..+)/)[1]
+
+      if (next !== undefined && !next.match(/^-/) &&
+        !checkAllAliases(key, flags.bools) &&
+        !checkAllAliases(key, flags.counts)) {
+        setArg(key, next)
+        i++
+      } else {
+        setArg(key, defaultForType(guessType(key, flags)))
+      }
+    } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) {
+      letters = arg.slice(1, -1).split('')
+      broken = false
+
+      for (var j = 0; j < letters.length; j++) {
+        next = arg.slice(j + 2)
+
+        if (letters[j + 1] && letters[j + 1] === '=') {
+          value = arg.slice(j + 3)
+          key = letters[j]
+
+          // nargs format = '-f=monkey washing cat'
+          if (checkAllAliases(key, flags.nargs)) {
+            args.splice(i + 1, 0, value)
+            i = eatNargs(i, key, args)
+          // array format = '-f=a b c'
+          } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
+            args.splice(i + 1, 0, value)
+            i = eatArray(i, key, args)
+          } else {
+            setArg(key, value)
+          }
+
+          broken = true
+          break
+        }
+
+        if (next === '-') {
+          setArg(letters[j], next)
+          continue
+        }
+
+        // current letter is an alphabetic character and next value is a number
+        if (/[A-Za-z]/.test(letters[j]) &&
+          /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
+          setArg(letters[j], next)
+          broken = true
+          break
+        }
+
+        if (letters[j + 1] && letters[j + 1].match(/\W/)) {
+          setArg(letters[j], next)
+          broken = true
+          break
+        } else {
+          setArg(letters[j], defaultForType(guessType(letters[j], flags)))
+        }
+      }
+
+      key = arg.slice(-1)[0]
+
+      if (!broken && key !== '-') {
+        // nargs format = '-f a b c'
+        if (checkAllAliases(key, flags.nargs)) {
+          i = eatNargs(i, key, args)
+        // array format = '-f a b c'
+        } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
+          i = eatArray(i, key, args)
+        } else {
+          next = args[i + 1]
+
+          if (next !== undefined && (!/^(-|--)[^-]/.test(next) ||
+            next.match(negative)) &&
+            !checkAllAliases(key, flags.bools) &&
+            !checkAllAliases(key, flags.counts)) {
+            setArg(key, next)
+            i++
+          } else if (/^(true|false)$/.test(next)) {
+            setArg(key, next)
+            i++
+          } else {
+            setArg(key, defaultForType(guessType(key, flags)))
+          }
+        }
+      }
+    } else {
+      argv._.push(
+        flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
+      )
+    }
+  }
+
+  // order of precedence:
+  // 1. command line arg
+  // 2. value from config file
+  // 3. value from config objects
+  // 4. value from env var
+  // 5. configured default value
+  applyEnvVars(argv, true) // special case: check env vars that point to config file
+  setConfig(argv)
+  setConfigObjects()
+  applyEnvVars(argv, false)
+  applyCoercions(argv)
+  applyDefaultsAndAliases(argv, flags.aliases, defaults)
+
+  // for any counts either not in args or without an explicit default, set to 0
+  Object.keys(flags.counts).forEach(function (key) {
+    if (!hasKey(argv, key.split('.'))) setArg(key, 0)
+  })
+
+  notFlags.forEach(function (key) {
+    argv._.push(key)
+  })
+
+  // how many arguments should we consume, based
+  // on the nargs option?
+  function eatNargs (i, key, args) {
+    var toEat = checkAllAliases(key, flags.nargs)
+
+    if (args.length - (i + 1) < toEat) error = Error(__('Not enough arguments following: %s', key))
+
+    for (var ii = i + 1; ii < (toEat + i + 1); ii++) {
+      setArg(key, args[ii])
+    }
+
+    return (i + toEat)
+  }
+
+  // if an option is an array, eat all non-hyphenated arguments
+  // following it... YUM!
+  // e.g., --foo apple banana cat becomes ["apple", "banana", "cat"]
+  function eatArray (i, key, args) {
+    var start = i + 1
+    for (var ii = i + 1; ii < args.length; ii++) {
+      if (/^-/.test(args[ii]) && !negative.test(args[ii])) {
+        if (ii === start) {
+          setArg(key, defaultForType('array'))
+        }
+        break
+      }
+      i = ii
+      setArg(key, args[ii])
+    }
+
+    return i
+  }
+
+  function setArg (key, val) {
+    unsetDefaulted(key)
+
+    // handle parsing boolean arguments --foo=true --bar false.
+    if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {
+      if (typeof val === 'string') val = val === 'true'
+    }
+
+    if (/-/.test(key) && !(flags.aliases[key] && flags.aliases[key].length) && configuration['camel-case-expansion']) {
+      var c = camelCase(key)
+      flags.aliases[key] = [c]
+      newAliases[c] = true
+    }
+
+    var value = val
+    if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.coercions)) {
+      if (isNumber(val)) value = Number(val)
+      if (!isUndefined(val) && !isNumber(val) && checkAllAliases(key, flags.numbers)) value = NaN
+    }
+
+    // increment a count given as arg (either no value or value parsed as boolean)
+    if (checkAllAliases(key, flags.counts) && (isUndefined(value) || typeof value === 'boolean')) {
+      value = increment
+    }
+
+    // Set normalized value when key is in 'normalize' and in 'arrays'
+    if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) {
+      if (Array.isArray(val)) value = val.map(path.normalize)
+      else value = path.normalize(val)
+    }
+
+    var splitKey = key.split('.')
+    setKey(argv, splitKey, value)
+
+    // handle populating aliases of the full key
+    if (flags.aliases[key]) {
+      flags.aliases[key].forEach(function (x) {
+        x = x.split('.')
+        setKey(argv, x, value)
+      })
+    }
+
+    // handle populating aliases of the first element of the dot-notation key
+    if (splitKey.length > 1 && configuration['dot-notation']) {
+      ;(flags.aliases[splitKey[0]] || []).forEach(function (x) {
+        x = x.split('.')
+
+        // expand alias with nested objects in key
+        var a = [].concat(splitKey)
+        a.shift() // nuke the old key.
+        x = x.concat(a)
+
+        setKey(argv, x, value)
+      })
+    }
+
+    // Set normalize getter and setter when key is in 'normalize' but isn't an array
+    if (checkAllAliases(key, flags.normalize) && !checkAllAliases(key, flags.arrays)) {
+      var keys = [key].concat(flags.aliases[key] || [])
+      keys.forEach(function (key) {
+        argv.__defineSetter__(key, function (v) {
+          val = path.normalize(v)
+        })
+
+        argv.__defineGetter__(key, function () {
+          return typeof val === 'string' ? path.normalize(val) : val
+        })
+      })
+    }
+  }
+
+  // set args from config.json file, this should be
+  // applied last so that defaults can be applied.
+  function setConfig (argv) {
+    var configLookup = {}
+
+    // expand defaults/aliases, in-case any happen to reference
+    // the config.json file.
+    applyDefaultsAndAliases(configLookup, flags.aliases, defaults)
+
+    Object.keys(flags.configs).forEach(function (configKey) {
+      var configPath = argv[configKey] || configLookup[configKey]
+      if (configPath) {
+        try {
+          var config = null
+          var resolvedConfigPath = path.resolve(process.cwd(), configPath)
+
+          if (typeof flags.configs[configKey] === 'function') {
+            try {
+              config = flags.configs[configKey](resolvedConfigPath)
+            } catch (e) {
+              config = e
+            }
+            if (config instanceof Error) {
+              error = config
+              return
+            }
+          } else {
+            config = require(resolvedConfigPath)
+          }
+
+          setConfigObject(config)
+        } catch (ex) {
+          if (argv[configKey]) error = Error(__('Invalid JSON config file: %s', configPath))
+        }
+      }
+    })
+  }
+
+  // set args from config object.
+  // it recursively checks nested objects.
+  function setConfigObject (config, prev) {
+    Object.keys(config).forEach(function (key) {
+      var value = config[key]
+      var fullKey = prev ? prev + '.' + key : key
+
+      if (Object.prototype.toString.call(value) === '[object Object]') {
+        // if the value is an object but not an array, check nested object
+        setConfigObject(value, fullKey)
+      } else {
+        // setting arguments via CLI takes precedence over
+        // values within the config file.
+        if (!hasKey(argv, fullKey.split('.')) || (flags.defaulted[fullKey])) {
+          setArg(fullKey, value)
+        }
+      }
+    })
+  }
+
+  // set all config objects passed in opts
+  function setConfigObjects () {
+    if (typeof configObjects === 'undefined') return
+    configObjects.forEach(function (configObject) {
+      setConfigObject(configObject)
+    })
+  }
+
+  function applyEnvVars (argv, configOnly) {
+    if (typeof envPrefix === 'undefined') return
+
+    var prefix = typeof envPrefix === 'string' ? envPrefix : ''
+    Object.keys(process.env).forEach(function (envVar) {
+      if (prefix === '' || envVar.lastIndexOf(prefix, 0) === 0) {
+        // get array of nested keys and convert them to camel case
+        var keys = envVar.split('__').map(function (key, i) {
+          if (i === 0) {
+            key = key.substring(prefix.length)
+          }
+          return camelCase(key)
+        })
+
+        if (((configOnly && flags.configs[keys.join('.')]) || !configOnly) && (!hasKey(argv, keys) || flags.defaulted[keys.join('.')])) {
+          setArg(keys.join('.'), process.env[envVar])
+        }
+      }
+    })
+  }
+
+  function applyCoercions (argv) {
+    var coerce
+    Object.keys(argv).forEach(function (key) {
+      coerce = checkAllAliases(key, flags.coercions)
+      if (typeof coerce === 'function') {
+        try {
+          argv[key] = coerce(argv[key])
+        } catch (err) {
+          error = err
+        }
+      }
+    })
+  }
+
+  function applyDefaultsAndAliases (obj, aliases, defaults) {
+    Object.keys(defaults).forEach(function (key) {
+      if (!hasKey(obj, key.split('.'))) {
+        setKey(obj, key.split('.'), defaults[key])
+
+        ;(aliases[key] || []).forEach(function (x) {
+          if (hasKey(obj, x.split('.'))) return
+          setKey(obj, x.split('.'), defaults[key])
+        })
+      }
+    })
+  }
+
+  function hasKey (obj, keys) {
+    var o = obj
+
+    if (!configuration['dot-notation']) keys = [keys.join('.')]
+
+    keys.slice(0, -1).forEach(function (key) {
+      o = (o[key] || {})
+    })
+
+    var key = keys[keys.length - 1]
+
+    if (typeof o !== 'object') return false
+    else return key in o
+  }
+
+  function setKey (obj, keys, value) {
+    var o = obj
+
+    if (!configuration['dot-notation']) keys = [keys.join('.')]
+
+    keys.slice(0, -1).forEach(function (key) {
+      if (o[key] === undefined) o[key] = {}
+      o = o[key]
+    })
+
+    var key = keys[keys.length - 1]
+
+    if (value === increment) {
+      o[key] = increment(o[key])
+    } else if (o[key] === undefined && checkAllAliases(key, flags.arrays)) {
+      o[key] = Array.isArray(value) ? value : [value]
+    } else if (o[key] === undefined || checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {
+      o[key] = value
+    } else if (Array.isArray(o[key])) {
+      o[key].push(value)
+    } else {
+      o[key] = [ o[key], value ]
+    }
+  }
+
+  // extend the aliases list with inferred aliases.
+  function extendAliases () {
+    Array.prototype.slice.call(arguments).forEach(function (obj) {
+      Object.keys(obj || {}).forEach(function (key) {
+        // short-circuit if we've already added a key
+        // to the aliases array, for example it might
+        // exist in both 'opts.default' and 'opts.key'.
+        if (flags.aliases[key]) return
+
+        flags.aliases[key] = [].concat(aliases[key] || [])
+        // For "--option-name", also set argv.optionName
+        flags.aliases[key].concat(key).forEach(function (x) {
+          if (/-/.test(x) && configuration['camel-case-expansion']) {
+            var c = camelCase(x)
+            flags.aliases[key].push(c)
+            newAliases[c] = true
+          }
+        })
+        flags.aliases[key].forEach(function (x) {
+          flags.aliases[x] = [key].concat(flags.aliases[key].filter(function (y) {
+            return x !== y
+          }))
+        })
+      })
+    })
+  }
+
+  // check if a flag is set for any of a key's aliases.
+  function checkAllAliases (key, flag) {
+    var isSet = false
+    var toCheck = [].concat(flags.aliases[key] || [], key)
+
+    toCheck.forEach(function (key) {
+      if (flag[key]) isSet = flag[key]
+    })
+
+    return isSet
+  }
+
+  function setDefaulted (key) {
+    [].concat(flags.aliases[key] || [], key).forEach(function (k) {
+      flags.defaulted[k] = true
+    })
+  }
+
+  function unsetDefaulted (key) {
+    [].concat(flags.aliases[key] || [], key).forEach(function (k) {
+      delete flags.defaulted[k]
+    })
+  }
+
+  // return a default value, given the type of a flag.,
+  // e.g., key of type 'string' will default to '', rather than 'true'.
+  function defaultForType (type) {
+    var def = {
+      boolean: true,
+      string: '',
+      number: undefined,
+      array: []
+    }
+
+    return def[type]
+  }
+
+  // given a flag, enforce a default type.
+  function guessType (key, flags) {
+    var type = 'boolean'
+
+    if (checkAllAliases(key, flags.strings)) type = 'string'
+    else if (checkAllAliases(key, flags.numbers)) type = 'number'
+    else if (checkAllAliases(key, flags.arrays)) type = 'array'
+
+    return type
+  }
+
+  function isNumber (x) {
+    if (!configuration['parse-numbers']) return false
+    if (typeof x === 'number') return true
+    if (/^0x[0-9a-f]+$/i.test(x)) return true
+    return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x)
+  }
+
+  function isUndefined (num) {
+    return num === undefined
+  }
+
+  return {
+    argv: argv,
+    error: error,
+    aliases: flags.aliases,
+    newAliases: newAliases,
+    configuration: configuration
+  }
+}
+
+// if any aliases reference each other, we should
+// merge them together.
+function combineAliases (aliases) {
+  var aliasArrays = []
+  var change = true
+  var combined = {}
+
+  // turn alias lookup hash {key: ['alias1', 'alias2']} into
+  // a simple array ['key', 'alias1', 'alias2']
+  Object.keys(aliases).forEach(function (key) {
+    aliasArrays.push(
+      [].concat(aliases[key], key)
+    )
+  })
+
+  // combine arrays until zero changes are
+  // made in an iteration.
+  while (change) {
+    change = false
+    for (var i = 0; i < aliasArrays.length; i++) {
+      for (var ii = i + 1; ii < aliasArrays.length; ii++) {
+        var intersect = aliasArrays[i].filter(function (v) {
+          return aliasArrays[ii].indexOf(v) !== -1
+        })
+
+        if (intersect.length) {
+          aliasArrays[i] = aliasArrays[i].concat(aliasArrays[ii])
+          aliasArrays.splice(ii, 1)
+          change = true
+          break
+        }
+      }
+    }
+  }
+
+  // map arrays back to the hash-lookup (de-dupe while
+  // we're at it).
+  aliasArrays.forEach(function (aliasArray) {
+    aliasArray = aliasArray.filter(function (v, i, self) {
+      return self.indexOf(v) === i
+    })
+    combined[aliasArray.pop()] = aliasArray
+  })
+
+  return combined
+}
+
+function assign (defaults, configuration) {
+  var o = {}
+  configuration = configuration || {}
+
+  Object.keys(defaults).forEach(function (k) {
+    o[k] = defaults[k]
+  })
+  Object.keys(configuration).forEach(function (k) {
+    o[k] = configuration[k]
+  })
+
+  return o
+}
+
+// this function should only be called when a count is given as an arg
+// it is NOT called to set a default value
+// thus we can start the count at 1 instead of 0
+function increment (orig) {
+  return orig !== undefined ? orig + 1 : 1
+}
+
+function Parser (args, opts) {
+  var result = parse(args.slice(), opts)
+
+  return result.argv
+}
+
+// parse arguments and return detailed
+// meta information, aliases, etc.
+Parser.detailed = function (args, opts) {
+  return parse(args.slice(), opts)
+}
+
+module.exports = Parser
diff --git a/lib/tokenize-arg-string.js b/lib/tokenize-arg-string.js
new file mode 100644
index 0000000..23d39e1
--- /dev/null
+++ b/lib/tokenize-arg-string.js
@@ -0,0 +1,34 @@
+// take an un-split argv string and tokenize it.
+module.exports = function (argString) {
+  if (Array.isArray(argString)) return argString
+
+  var i = 0
+  var c = null
+  var opening = null
+  var args = []
+
+  for (var ii = 0; ii < argString.length; ii++) {
+    c = argString.charAt(ii)
+
+    // split on spaces unless we're in quotes.
+    if (c === ' ' && !opening) {
+      i++
+      continue
+    }
+
+    // don't split the string if we're in matching
+    // opening or closing single and double quotes.
+    if (c === opening) {
+      opening = null
+      continue
+    } else if ((c === "'" || c === '"') && !opening) {
+      opening = c
+      continue
+    }
+
+    if (!args[i]) args[i] = ''
+    args[i] += c
+  }
+
+  return args
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..81c511e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,43 @@
+{
+  "name": "yargs-parser",
+  "version": "4.0.2",
+  "description": "the mighty option parser used by yargs",
+  "main": "index.js",
+  "scripts": {
+    "pretest": "standard",
+    "test": "nyc mocha test/*.js",
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "release": "standard-version"
+  },
+  "repository": {
+    "url": "git at github.com:yargs/yargs-parser.git"
+  },
+  "keywords": [
+    "argument",
+    "parser",
+    "yargs",
+    "command",
+    "cli",
+    "parsing",
+    "option",
+    "args",
+    "argument"
+  ],
+  "author": "Ben Coe <ben at npmjs.com>",
+  "license": "ISC",
+  "devDependencies": {
+    "chai": "^3.5.0",
+    "coveralls": "^2.11.12",
+    "mocha": "^3.0.1",
+    "nyc": "^8.1.0",
+    "standard": "^8.0.0",
+    "standard-version": "^2.1.2"
+  },
+  "dependencies": {
+    "camelcase": "^3.0.0"
+  },
+  "files": [
+    "lib",
+    "index.js"
+  ]
+}
diff --git a/test/fixtures/config.json b/test/fixtures/config.json
new file mode 100644
index 0000000..4337646
--- /dev/null
+++ b/test/fixtures/config.json
@@ -0,0 +1,7 @@
+{
+    "herp": "derp",
+    "z": 55,
+    "foo": "baz",
+    "version": "1.0.2",
+    "truthy": true
+}
diff --git a/test/fixtures/config.txt b/test/fixtures/config.txt
new file mode 100644
index 0000000..8e6e5a4
--- /dev/null
+++ b/test/fixtures/config.txt
@@ -0,0 +1,2 @@
+AWESOME=banana
+BATMAN=grumpy
diff --git a/test/fixtures/nested_config.json b/test/fixtures/nested_config.json
new file mode 100644
index 0000000..973083b
--- /dev/null
+++ b/test/fixtures/nested_config.json
@@ -0,0 +1,8 @@
+{
+  "a": "a",
+  "nested": {
+    "foo": "baz",
+    "bar": "bar"
+  },
+  "b": "b"
+}
\ No newline at end of file
diff --git a/test/fixtures/settings.js b/test/fixtures/settings.js
new file mode 100644
index 0000000..225c910
--- /dev/null
+++ b/test/fixtures/settings.js
@@ -0,0 +1,6 @@
+module.exports = {
+  calculate: function (a) {
+    return a + 55
+  },
+  herp: 'derp'
+}
diff --git a/test/tokenize-arg-string.js b/test/tokenize-arg-string.js
new file mode 100644
index 0000000..9b9f9a0
--- /dev/null
+++ b/test/tokenize-arg-string.js
@@ -0,0 +1,40 @@
+/* global describe, it */
+
+var tokenizeArgString = require('../lib/tokenize-arg-string')
+
+require('chai').should()
+
+describe('TokenizeArgString', function () {
+  it('handles unquoted string', function () {
+    var args = tokenizeArgString('--foo 99')
+    args[0].should.equal('--foo')
+    args[1].should.equal('99')
+  })
+
+  it('handles quoted string with no spaces', function () {
+    var args = tokenizeArgString("--foo 'hello'")
+    args[0].should.equal('--foo')
+    args[1].should.equal('hello')
+  })
+
+  it('handles single quoted string with spaces', function () {
+    var args = tokenizeArgString("--foo 'hello world' --bar='foo bar'")
+    args[0].should.equal('--foo')
+    args[1].should.equal('hello world')
+    args[2].should.equal('--bar=foo bar')
+  })
+
+  it('handles double quoted string with spaces', function () {
+    var args = tokenizeArgString('--foo "hello world" --bar="foo bar"')
+    args[0].should.equal('--foo')
+    args[1].should.equal('hello world')
+    args[2].should.equal('--bar=foo bar')
+  })
+
+  it('handles quoted string with embeded quotes', function () {
+    var args = tokenizeArgString('--foo "hello \'world\'" --bar=\'foo "bar"\'')
+    args[0].should.equal('--foo')
+    args[1].should.equal('hello \'world\'')
+    args[2].should.equal('--bar=foo "bar"')
+  })
+})
diff --git a/test/yargs-parser.js b/test/yargs-parser.js
new file mode 100644
index 0000000..dac993c
--- /dev/null
+++ b/test/yargs-parser.js
@@ -0,0 +1,2094 @@
+/* global beforeEach, describe, it */
+
+require('chai').should()
+
+var expect = require('chai').expect
+var fs = require('fs')
+var parser = require('../')
+var path = require('path')
+
+describe('yargs-parser', function () {
+  it('should parse a "short boolean"', function () {
+    var parse = parser([ '-b' ])
+    parse.should.have.property('b').to.be.ok.and.be.a('boolean')
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should parse a "long boolean"', function () {
+    var parse = parser('--bool')
+    parse.should.have.property('bool', true)
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should place bare options in the _ array', function () {
+    var parse = parser('foo bar baz')
+    parse.should.have.property('_').and.deep.equal(['foo', 'bar', 'baz'])
+  })
+
+  it('should set the value of the final option in a group to the next supplied value', function () {
+    var parse = parser(['-cats', 'meow'])
+    parse.should.have.property('c', true)
+    parse.should.have.property('a', true)
+    parse.should.have.property('t', true)
+    parse.should.have.property('s', 'meow')
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should set the value of a single long option to the next supplied value', function () {
+    var parse = parser(['--pow', 'xixxle'])
+    parse.should.have.property('pow', 'xixxle')
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should set the value of a single long option to the next supplied value, even if the value is empty', function () {
+    var parse = parser(['--pow', ''])
+    parse.should.have.property('pow', '')
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should set the value of a single long option if an = was used', function () {
+    var parse = parser(['--pow=xixxle'])
+    parse.should.have.property('pow', 'xixxle')
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should set the value of multiple long options to the next supplied values relative to each', function () {
+    var parse = parser(['--host', 'localhost', '--port', '555'])
+    parse.should.have.property('host', 'localhost')
+    parse.should.have.property('port', 555)
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should set the value of multiple long options if = signs were used', function () {
+    var parse = parser(['--host=localhost', '--port=555'])
+    parse.should.have.property('host', 'localhost')
+    parse.should.have.property('port', 555)
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should still set values appropriately if a mix of short, long, and grouped short options are specified', function () {
+    var parse = parser(['-h', 'localhost', '-fp', '555', 'script.js'])
+    parse.should.have.property('f', true)
+    parse.should.have.property('p', 555)
+    parse.should.have.property('h', 'localhost')
+    parse.should.have.property('_').and.deep.equal(['script.js'])
+  })
+
+  it('should still set values appropriately if a mix of short and long options are specified', function () {
+    var parse = parser(['-h', 'localhost', '--port', '555'])
+    parse.should.have.property('h', 'localhost')
+    parse.should.have.property('port', 555)
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should explicitly set a boolean option to false if preceeded by "--no-"', function () {
+    var parse = parser(['--no-moo'])
+    parse.should.have.property('moo', false)
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should still set values appropriately if we supply a comprehensive list of various types of options', function () {
+    var parse = parser([
+      '--name=meowmers', 'bare', '-cats', 'woo',
+      '-h', 'awesome', '--multi=quux',
+      '--key', 'value',
+      '-b', '--bool', '--no-meep', '--multi=baz',
+      '--', '--not-a-flag', '-', '-h', '-multi', '--', 'eek'
+    ])
+    parse.should.have.property('c', true)
+    parse.should.have.property('a', true)
+    parse.should.have.property('t', true)
+    parse.should.have.property('s', 'woo')
+    parse.should.have.property('h', 'awesome')
+    parse.should.have.property('b', true)
+    parse.should.have.property('bool', true)
+    parse.should.have.property('key', 'value')
+    parse.should.have.property('multi').and.deep.equal(['quux', 'baz'])
+    parse.should.have.property('meep', false)
+    parse.should.have.property('name', 'meowmers')
+    parse.should.have.property('_').and.deep.equal(['bare', '--not-a-flag', '-', '-h', '-multi', '--', 'eek'])
+  })
+
+  it('should parse numbers appropriately', function () {
+    var argv = parser([
+      '-x', '1234',
+      '-y', '5.67',
+      '-z', '1e7',
+      '-w', '10f',
+      '--hex', '0xdeadbeef',
+      '789'
+    ])
+    argv.should.have.property('x', 1234).and.be.a('number')
+    argv.should.have.property('y', 5.67).and.be.a('number')
+    argv.should.have.property('z', 1e7).and.be.a('number')
+    argv.should.have.property('w', '10f').and.be.a('string')
+    argv.should.have.property('hex', 0xdeadbeef).and.be.a('number')
+    argv.should.have.property('_').and.deep.equal([789])
+    argv._[0].should.be.a('number')
+  })
+
+  // addresses: https://github.com/yargs/yargs-parser/issues/33
+  it('should handle parsing negative #s', function () {
+    var argv = parser([
+      '-33', '-177', '33',
+      '--n1', '-33',
+      '-n', '-44',
+      '--n2=-55',
+      '--foo.bar', '-33',
+      '-o=-55',
+      '--bounds', '-180', '99', '-180', '90',
+      '--other', '-99', '-220'
+    ], {
+      array: 'bounds',
+      narg: {'other': 2}
+    })
+
+    argv._.should.deep.equal([-33, -177, 33])
+    argv.n1.should.equal(-33)
+    argv.n.should.equal(-44)
+    argv.n2.should.equal(-55)
+    argv.foo.bar.should.equal(-33)
+    argv.o.should.equal(-55)
+    argv.bounds.should.deep.equal([-180, 99, -180, 90])
+    argv.other.should.deep.equal([-99, -220])
+  })
+
+  it('should set the value of a single short option to the next supplied value, even if the value is empty', function () {
+    var parse = parser(['-p', ''])
+    parse.should.have.property('p', '')
+    parse.should.have.property('_').with.length(0)
+  })
+
+  it('should not set the next value as the value of a short option if that option is explicitly defined as a boolean', function () {
+    var parse = parser([ '-t', 'moo' ], {
+      boolean: 't'
+    })
+    parse.should.have.property('t', true).and.be.a('boolean')
+    parse.should.have.property('_').and.deep.equal(['moo'])
+  })
+
+  it('should set boolean options values if the next value is "true" or "false"', function () {
+    var parse = parser(['--verbose', 'false', 'moo', '-t', 'true'], {
+      boolean: ['t', 'verbose'],
+      default: {
+        verbose: true
+      }
+    })
+    parse.should.have.property('verbose', false).and.be.a('boolean')
+    parse.should.have.property('t', true).and.be.a('boolean')
+    parse.should.have.property('_').and.deep.equal(['moo'])
+  })
+
+  it('should not set boolean options values if the next value only contains the words "true" or "false"', function () {
+    var parse = parser(['--verbose', 'aaatrueaaa', 'moo', '-t', 'aaafalseaaa'], {
+      boolean: ['t', 'verbose']
+    })
+    parse.should.have.property('verbose', true).and.be.a('boolean')
+    parse.should.have.property('t', true).and.be.a('boolean')
+    parse.should.have.property('_').and.deep.equal(['aaatrueaaa', 'moo', 'aaafalseaaa'])
+  })
+
+  it('should allow defining options as boolean in groups', function () {
+    var parse = parser([ '-x', '-z', 'one', 'two', 'three' ], {
+      boolean: ['x', 'y', 'z']
+    })
+    parse.should.have.property('x', true).and.be.a('boolean')
+    parse.should.have.property('y', false).and.be.a('boolean')
+    parse.should.have.property('z', true).and.be.a('boolean')
+    parse.should.have.property('_').and.deep.equal(['one', 'two', 'three'])
+  })
+
+  it('should preserve newlines in option values', function () {
+    var args = parser(['-s', 'X\nX'])
+    args.should.have.property('_').with.length(0)
+    args.should.have.property('s', 'X\nX')
+    // reproduce in bash:
+    // VALUE="new
+    // line"
+    // node program.js --s="$VALUE"
+    args = parser(['--s=X\nX'])
+    args.should.have.property('_').with.length(0)
+    args.should.have.property('s', 'X\nX')
+  })
+
+  it('should not convert numbers to type number if explicitly defined as strings', function () {
+    var s = parser([ '-s', '0001234' ], {
+      string: 's'
+    }).s
+    s.should.be.a('string').and.equal('0001234')
+    var x = parser([ '-x', '56' ], {
+      string: ['x']
+    }).x
+    x.should.be.a('string').and.equal('56')
+  })
+
+  it('should default numbers to undefined', function () {
+    var n = parser([ '-n' ], {
+      number: ['n']
+    }).n
+    expect(n).to.equal(undefined)
+  })
+
+  it('should default number to NaN if value is not a valid number', function () {
+    var n = parser([ '-n', 'string' ], {
+      number: ['n']
+    }).n
+    expect(n).to.deep.equal(NaN)
+  })
+
+  // Fixes: https://github.com/bcoe/yargs/issues/68
+  it('should parse flag arguments with no right-hand-value as strings, if defined as strings', function () {
+    var s = parser([ '-s' ], {
+      string: ['s']
+    }).s
+    s.should.be.a('string').and.equal('')
+
+    s = parser([ '-sf' ], {
+      string: ['s']
+    }).s
+    s.should.be.a('string').and.equal('')
+
+    s = parser([ '--string' ], {
+      string: ['string']
+    }).string
+    s.should.be.a('string').and.equal('')
+  })
+
+  it('should leave all non-hyphenated values as strings if _ is defined as a string', function () {
+    var s = parser([ '  ', '  ' ], {
+      string: ['_']
+    })._
+    s.should.have.length(2)
+    s[0].should.be.a('string').and.equal('  ')
+    s[1].should.be.a('string').and.equal('  ')
+  })
+
+  describe('normalize', function () {
+    it('should normalize redundant paths', function () {
+      var a = parser([ '-s', ['', 'tmp', '..', ''].join(path.sep) ], {
+        alias: {
+          s: ['save']
+        },
+        normalize: 's'
+      })
+      a.should.have.property('s', path.sep)
+      a.should.have.property('save', path.sep)
+    })
+
+    it('should normalize redundant paths when a value is later assigned', function () {
+      var a = parser(['-s'], {
+        normalize: ['s']
+      })
+      a.should.have.property('s', true)
+      a.s = ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep)
+      a.s.should.equal(['', 'path', 'to', ''].join(path.sep))
+    })
+
+    it('should normalize when key is also an array', function () {
+      var a = parser([ '-s', ['', 'tmp', '..', ''].join(path.sep), ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep) ], {
+        alias: {
+          s: ['save']
+        },
+        normalize: 's',
+        array: 's'
+      })
+      var expected = [path.sep, ['', 'path', 'to', ''].join(path.sep)]
+      a.should.have.property('s').and.deep.equal(expected)
+      a.should.have.property('save').and.deep.equal(expected)
+    })
+  })
+
+  describe('alias', function () {
+    it('should set alias value to the same value as the full option', function () {
+      var argv = parser([ '-f', '11', '--zoom', '55' ], {
+        alias: {
+          z: ['zoom']
+        }
+      })
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('z', 55)
+      argv.should.have.property('f', 11)
+    })
+
+    it('should allow multiple aliases to be specified', function () {
+      var argv = parser([ '-f', '11', '--zoom', '55' ], {
+        alias: {
+          z: ['zm', 'zoom']
+        }
+      })
+
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('z', 55)
+      argv.should.have.property('zm', 55)
+      argv.should.have.property('f', 11)
+    })
+
+    // regression, see https://github.com/chevex/yargs/issues/63
+    it('should not add the same key to argv multiple times, when creating camel-case aliases', function () {
+      var argv = parser(['--health-check=banana', '--second-key', 'apple', '-t=blarg'], {
+        alias: {
+          h: ['health-check'],
+          'second-key': ['s'],
+          'third-key': ['t']
+        },
+        default: {
+          h: 'apple',
+          'second-key': 'banana',
+          'third-key': 'third'
+        }
+      })
+
+      // before this fix, yargs failed parsing
+      // one but not all forms of an arg.
+      argv.secondKey.should.eql('apple')
+      argv.s.should.eql('apple')
+      argv['second-key'].should.eql('apple')
+
+      argv.healthCheck.should.eql('banana')
+      argv.h.should.eql('banana')
+      argv['health-check'].should.eql('banana')
+
+      argv.thirdKey.should.eql('blarg')
+      argv.t.should.eql('blarg')
+      argv['third-key'].should.eql('blarg')
+    })
+
+    it('should allow transitive aliases to be specified', function () {
+      var argv = parser([ '-f', '11', '--zoom', '55' ], {
+        alias: {
+          z: 'zm',
+          zm: 'zoom'
+        }
+      })
+
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('z', 55)
+      argv.should.have.property('zm', 55)
+      argv.should.have.property('f', 11)
+    })
+
+    it('should merge two lists of aliases if they collide', function () {
+      var argv = parser(['-f', '11', '--zoom', '55'], {
+        alias: {
+          z: 'zm',
+          zoom: 'zoop',
+          zm: 'zoom'
+        }
+      })
+
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('zoop', 55)
+      argv.should.have.property('z', 55)
+      argv.should.have.property('zm', 55)
+      argv.should.have.property('f', 11)
+    })
+  })
+
+  it('should assign data after forward slash to the option before the slash', function () {
+    var parse = parser(['-I/foo/bar/baz'])
+    parse.should.have.property('_').with.length(0)
+    parse.should.have.property('I', '/foo/bar/baz')
+    parse = parser(['-xyz/foo/bar/baz'])
+    parse.should.have.property('x', true)
+    parse.should.have.property('y', true)
+    parse.should.have.property('z', '/foo/bar/baz')
+    parse.should.have.property('_').with.length(0)
+  })
+
+  describe('config', function () {
+    var jsonPath = path.resolve(__dirname, './fixtures/config.json')
+
+    // See: https://github.com/chevex/yargs/issues/12
+    it('should load options and values from default config if specified', function () {
+      var argv = parser([ '--foo', 'bar' ], {
+        alias: {
+          z: 'zoom'
+        },
+        default: {
+          settings: jsonPath
+        },
+        config: 'settings'
+      })
+
+      argv.should.have.property('herp', 'derp')
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('foo').and.deep.equal('bar')
+    })
+
+    it('should use value from config file, if argv value is using default value', function () {
+      var argv = parser([], {
+        alias: {
+          z: 'zoom'
+        },
+        config: ['settings'],
+        default: {
+          settings: jsonPath,
+          foo: 'banana'
+        }
+      })
+
+      argv.should.have.property('herp', 'derp')
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('foo').and.deep.equal('baz')
+    })
+
+    it('should use value from config file, if argv key is a boolean', function () {
+      var argv = parser([], {
+        config: ['settings'],
+        default: {
+          settings: jsonPath
+        },
+        boolean: ['truthy']
+      })
+
+      argv.should.have.property('truthy', true)
+    })
+
+    it('should use value from cli, if cli overrides boolean argv key', function () {
+      var argv = parser(['--no-truthy'], {
+        config: ['settings'],
+        default: {
+          settings: jsonPath
+        },
+        boolean: ['truthy']
+      })
+
+      argv.should.have.property('truthy', false)
+    })
+
+    it('should use cli value, if cli value is set and both cli and default value match', function () {
+      var argv = parser(['--foo', 'banana'], {
+        alias: {
+          z: 'zoom'
+        },
+        config: ['settings'],
+        default: {
+          settings: jsonPath,
+          foo: 'banana'
+        }
+      })
+
+      argv.should.have.property('herp', 'derp')
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('foo').and.deep.equal('banana')
+    })
+
+    it("should allow config to be set as flag in 'option'", function () {
+      var argv = parser([ '--settings', jsonPath, '--foo', 'bar' ], {
+        alias: {
+          z: 'zoom'
+        },
+        config: ['settings']
+      })
+
+      argv.should.have.property('herp', 'derp')
+      argv.should.have.property('zoom', 55)
+      argv.should.have.property('foo').and.deep.equal('bar')
+    })
+
+    it('should load options and values from a JS file when config has .js extention', function () {
+      var jsPath = path.resolve(__dirname, './fixtures/settings.js')
+      var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], {
+        config: ['settings']
+      })
+
+      argv.should.have.property('herp', 'derp')
+      argv.should.have.property('foo', 'bar')
+      argv.should.have.property('calculate').and.be.a('function')
+    })
+
+    it('should raise an appropriate error if JSON file is not found', function () {
+      var argv = parser.detailed(['--settings', 'fake.json', '--foo', 'bar'], {
+        alias: {
+          z: 'zoom'
+        },
+        config: ['settings']
+      })
+
+      argv.error.message.should.equal('Invalid JSON config file: fake.json')
+    })
+
+    // see: https://github.com/bcoe/yargs/issues/172
+    it('should not raise an exception if config file is set as default argument value', function () {
+      var argv = parser.detailed([], {
+        default: {
+          config: 'foo.json'
+        },
+        config: ['config']
+      })
+
+      expect(argv.error).to.equal(null)
+    })
+
+    it('should load nested options from config file', function () {
+      var jsonPath = path.resolve(__dirname, './fixtures/nested_config.json')
+      var argv = parser(['--settings', jsonPath, '--nested.foo', 'bar'], {
+        config: ['settings']
+      })
+
+      argv.should.have.property('a', 'a')
+      argv.should.have.property('b', 'b')
+      argv.should.have.property('nested').and.deep.equal({
+        foo: 'bar',
+        bar: 'bar'
+      })
+    })
+
+    it('should use nested value from config file, if argv value is using default value', function () {
+      var jsonPath = path.resolve(__dirname, './fixtures/nested_config.json')
+      var argv = parser(['--settings', jsonPath], {
+        config: ['settings'],
+        default: {
+          'nested.foo': 'banana'
+        }
+      })
+
+      argv.should.have.property('a', 'a')
+      argv.should.have.property('b', 'b')
+      argv.should.have.property('nested').and.deep.equal({
+        foo: 'baz',
+        bar: 'bar'
+      })
+    })
+
+    it('allows a custom parsing function to be provided', function () {
+      var jsPath = path.resolve(__dirname, './fixtures/config.txt')
+      var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], {
+        config: {
+          settings: function (configPath) {
+            // as an example, parse an environment
+            // variable style config:
+            // FOO=99
+            // BATMAN=grumpy
+            var config = {}
+            var txt = fs.readFileSync(configPath, 'utf-8')
+            txt.split(/\r?\n/).forEach(function (l) {
+              var kv = l.split('=')
+              config[kv[0].toLowerCase()] = kv[1]
+            })
+            return config
+          }
+        }
+      })
+
+      argv.batman.should.equal('grumpy')
+      argv.awesome.should.equal('banana')
+      argv.foo.should.equal('bar')
+    })
+
+    it('allows a custom parsing function to be provided as an alias', function () {
+      var jsPath = path.resolve(__dirname, './fixtures/config.json')
+      var argv = parser([ '--settings', jsPath, '--foo', 'bar' ], {
+        config: {
+          s: function (configPath) {
+            return JSON.parse(fs.readFileSync(configPath, 'utf-8'))
+          }
+        },
+        alias: {
+          s: ['settings']
+        }
+      })
+
+      argv.should.have.property('herp', 'derp')
+      argv.should.have.property('foo', 'bar')
+    })
+
+    it('outputs an error returned by the parsing function', function () {
+      var argv = parser.detailed(['--settings=./package.json'], {
+        config: {
+          settings: function (configPath) {
+            return Error('someone set us up the bomb')
+          }
+        }
+      })
+
+      argv.error.message.should.equal('someone set us up the bomb')
+    })
+
+    it('outputs an error if thrown by the parsing function', function () {
+      var argv = parser.detailed(['--settings=./package.json'], {
+        config: {
+          settings: function (configPath) {
+            throw Error('someone set us up the bomb')
+          }
+        }
+      })
+
+      argv.error.message.should.equal('someone set us up the bomb')
+    })
+  })
+
+  describe('config objects', function () {
+    it('should load options from config object', function () {
+      var argv = parser([ '--foo', 'bar' ], {
+        configObjects: [{
+          apple: 'apple',
+          banana: 42,
+          foo: 'baz'
+        }]
+      })
+
+      argv.should.have.property('apple', 'apple')
+      argv.should.have.property('banana', 42)
+      argv.should.have.property('foo', 'bar')
+    })
+
+    it('should use value from config object, if argv value is using default value', function () {
+      var argv = parser([], {
+        configObjects: [{
+          apple: 'apple',
+          banana: 42,
+          foo: 'baz'
+        }],
+        default: {
+          foo: 'banana'
+        }
+      })
+
+      argv.should.have.property('apple', 'apple')
+      argv.should.have.property('banana', 42)
+      argv.should.have.property('foo', 'baz')
+    })
+
+    it('should use value from config object to all aliases', function () {
+      var argv = parser([], {
+        configObjects: [{
+          apple: 'apple',
+          banana: 42,
+          foo: 'baz'
+        }],
+        alias: {
+          a: ['apple'],
+          banana: ['b']
+        }
+      })
+
+      argv.should.have.property('apple', 'apple')
+      argv.should.have.property('a', 'apple')
+      argv.should.have.property('banana', 42)
+      argv.should.have.property('b', 42)
+      argv.should.have.property('foo', 'baz')
+    })
+
+    it('should load nested options from config object', function () {
+      var argv = parser(['--nested.foo', 'bar'], {
+        configObjects: [{
+          a: 'a',
+          nested: {
+            foo: 'baz',
+            bar: 'bar'
+          },
+          b: 'b'
+        }]
+      })
+
+      argv.should.have.property('a', 'a')
+      argv.should.have.property('b', 'b')
+      argv.should.have.property('nested').and.deep.equal({
+        foo: 'bar',
+        bar: 'bar'
+      })
+    })
+
+    it('should use nested value from config object, if argv value is using default value', function () {
+      var argv = parser([], {
+        configObjects: [{
+          a: 'a',
+          nested: {
+            foo: 'baz',
+            bar: 'bar'
+          },
+          b: 'b'
+        }],
+        default: {
+          'nested.foo': 'banana'
+        }
+      })
+
+      argv.should.have.property('a', 'a')
+      argv.should.have.property('b', 'b')
+      argv.should.have.property('nested').and.deep.equal({
+        foo: 'baz',
+        bar: 'bar'
+      })
+    })
+  })
+
+  describe('dot notation', function () {
+    it('should allow object graph traversal via dot notation', function () {
+      var argv = parser([
+        '--foo.bar', '3', '--foo.baz', '4',
+        '--foo.quux.quibble', '5', '--foo.quux.o_O',
+        '--beep.boop'
+      ])
+      argv.should.have.property('foo').and.deep.equal({
+        bar: 3,
+        baz: 4,
+        quux: {
+          quibble: 5,
+          o_O: true
+        }
+      })
+      argv.should.have.property('beep').and.deep.equal({ boop: true })
+    })
+
+    it('should apply defaults to dot notation arguments', function () {
+      var argv = parser([], {
+        default: {
+          'foo.bar': 99
+        }
+      })
+
+      argv.foo.bar.should.eql(99)
+    })
+
+    // see #279
+    it('should allow default to be overridden when an alias is provided', function () {
+      var argv = parser(['--foo.bar', '200'], {
+        default: {
+          'foo.bar': 99
+        }
+      })
+
+      argv.foo.bar.should.eql(200)
+    })
+
+    // see #279
+    it('should also override alias', function () {
+      var argv = parser(['--foo.bar', '200'], {
+        alias: {
+          'foo.bar': ['f']
+        },
+        default: {
+          'foo.bar': 99
+        }
+      })
+
+      argv.f.should.eql(200)
+    })
+
+    // see #279
+    it('should not set an undefined dot notation key', function () {
+      var argv = parser(['--foo.bar', '200'], {
+        default: {
+          'foo.bar': 99
+        },
+        alias: {
+          'foo.bar': ['f']
+        }
+      })
+
+      ;('foo.bar' in argv).should.equal(false)
+    })
+
+    it('should respect .string() for dot notation arguments', function () {
+      var argv = parser(['--foo.bar', '99', '--bar.foo=99'], {
+        string: ['foo.bar']
+      })
+
+      argv.foo.bar.should.eql('99')
+      argv.bar.foo.should.eql(99)
+    })
+
+    it('should populate aliases when dot notation is used', function () {
+      var argv = parser(['--foo.bar', '99'], {
+        alias: {
+          foo: ['f']
+        }
+      })
+
+      argv.f.bar.should.eql(99)
+    })
+
+    it('should populate aliases when nested dot notation is used', function () {
+      var argv = parser(['--foo.bar.snuh', '99', '--foo.apple', '33', '--foo.bar.cool', '11'], {
+        alias: {
+          foo: ['f']
+        }
+      })
+
+      argv.f.bar.snuh.should.eql(99)
+      argv.foo.bar.snuh.should.eql(99)
+
+      argv.f.apple.should.eql(33)
+      argv.foo.apple.should.eql(33)
+
+      argv.f.bar.cool.should.eql(11)
+      argv.foo.bar.cool.should.eql(11)
+    })
+
+    it("should allow flags to use dot notation, when seperated by '='", function () {
+      var argv = parser(['-f.foo=99'])
+      argv.f.foo.should.eql(99)
+    })
+
+    it("should allow flags to use dot notation, when seperated by ' '", function () {
+      var argv = parser(['-f.foo', '99'])
+      argv.f.foo.should.eql(99)
+    })
+
+    it('should allow flags to use dot notation when no right-hand-side is given', function () {
+      var argv = parser(['-f.foo', '99', '-f.bar'])
+      argv.f.foo.should.eql(99)
+      argv.f.bar.should.eql(true)
+    })
+  })
+
+  it('should set boolean and alias using explicit true', function () {
+    var aliased = [ '-h', 'true' ]
+    var aliasedArgv = parser(aliased, {
+      boolean: ['h'],
+      alias: {
+        h: ['herp']
+      }
+    })
+
+    aliasedArgv.should.have.property('herp', true)
+    aliasedArgv.should.have.property('h', true)
+    aliasedArgv.should.have.property('_').with.length(0)
+  })
+
+  // regression, see https://github.com/substack/node-optimist/issues/71
+  it('should set boolean and --x=true', function () {
+    var parsed = parser(['--boool', '--other=true'], {
+      boolean: ['boool']
+    })
+    parsed.should.have.property('boool', true)
+    parsed.should.have.property('other', 'true')
+    parsed = parser(['--boool', '--other=false'], {
+      boolean: ['boool']
+    })
+    parsed.should.have.property('boool', true)
+    parsed.should.have.property('other', 'false')
+  })
+
+  // regression, see https://github.com/chevex/yargs/issues/66
+  it('should set boolean options values if next value is "true" or "false" with = as separator', function () {
+    var argv = parser(['--bool=false'], {
+      boolean: ['b'],
+      alias: {
+        b: ['bool']
+      },
+      default: {
+        b: true
+      }
+    })
+
+    argv.bool.should.eql(false)
+  })
+
+  describe('short options', function () {
+    it('should set the value of multiple single short options to the next supplied values relative to each', function () {
+      var parse = parser(['-h', 'localhost', '-p', '555'])
+      parse.should.have.property('h', 'localhost')
+      parse.should.have.property('p', 555)
+      parse.should.have.property('_').with.length(0)
+    })
+
+    it('should set the value of a single short option to the next supplied value', function () {
+      var parse = parser(['-h', 'localhost'])
+      parse.should.have.property('h', 'localhost')
+      parse.should.have.property('_').with.length(0)
+    })
+
+    it('should expand grouped short options to a hash with a key for each', function () {
+      var parse = parser(['-cats'])
+      parse.should.have.property('c', true)
+      parse.should.have.property('a', true)
+      parse.should.have.property('t', true)
+      parse.should.have.property('s', true)
+      parse.should.have.property('_').with.length(0)
+    })
+
+    it('should set n to the numeric value 123', function () {
+      var argv = parser([ '-n123' ])
+      argv.should.have.property('n', 123)
+    })
+
+    it('should set n to the numeric value 123, with n at the end of a group', function () {
+      var argv = parser([ '-ab5n123' ])
+      argv.should.have.property('a', true)
+      argv.should.have.property('b', true)
+      argv.should.have.property('5', true)
+      argv.should.have.property('n', 123)
+      argv.should.have.property('_').with.length(0)
+    })
+
+    it('should set n to the numeric value 123, with = as separator', function () {
+      var argv = parser([ '-n=123' ])
+      argv.should.have.property('n', 123)
+    })
+
+    it('should set n to the numeric value 123, with n at the end of a group and = as separator', function () {
+      var argv = parser([ '-ab5n=123' ])
+      argv.should.have.property('a', true)
+      argv.should.have.property('b', true)
+      argv.should.have.property('5', true)
+      argv.should.have.property('n', 123)
+      argv.should.have.property('_').with.length(0)
+    })
+  })
+
+  describe('whitespace', function () {
+    it('should be whitespace', function () {
+      var argv = parser([ '-x', '\t' ])
+      argv.should.have.property('x', '\t')
+    })
+  })
+
+  describe('boolean modifier function', function () {
+    it('should prevent yargs from sucking in the next option as the value of the first option', function () {
+      // Arrange & Act
+      var result = parser(['-b', '123'], {
+        boolean: ['b']
+      })
+      // Assert
+      result.should.have.property('b').that.is.a('boolean').and.is.true
+      result.should.have.property('_').and.deep.equal([123])
+    })
+  })
+
+  describe('defaults', function () {
+    function checkNoArgs (opts, hasAlias) {
+      it('should set defaults if no args', function () {
+        var result = parser([], opts)
+        result.should.have.property('flag', true)
+        if (hasAlias) {
+          result.should.have.property('f', true)
+        }
+      })
+    }
+
+    function checkExtraArg (opts, hasAlias) {
+      it('should set defaults if one extra arg', function () {
+        var result = parser(['extra'], opts)
+        result.should.have.property('flag', true)
+        result.should.have.property('_').and.deep.equal(['extra'])
+        if (hasAlias) {
+          result.should.have.property('f', true)
+        }
+      })
+    }
+
+    function checkStringArg (opts, hasAlias) {
+      it('should set defaults even if arg looks like a string', function () {
+        var result = parser([ '--flag', 'extra' ], opts)
+        result.should.have.property('flag', true)
+        result.should.have.property('_').and.deep.equal(['extra'])
+        if (hasAlias) {
+          result.should.have.property('f', true)
+        }
+      })
+    }
+
+    describe('for options with aliases', function () {
+      var opts = {
+        alias: {
+          flag: ['f']
+        },
+        default: {
+          flag: true
+        }
+      }
+
+      checkNoArgs(opts, true)
+      checkExtraArg(opts, true)
+    })
+
+    describe('for typed options without aliases', function () {
+      var opts = {
+        boolean: ['flag'],
+        default: {
+          flag: true
+        }
+      }
+
+      checkNoArgs(opts)
+      checkExtraArg(opts)
+      checkStringArg(opts)
+    })
+
+    describe('for typed options with aliases', function () {
+      var opts = {
+        alias: {
+          flag: ['f']
+        },
+        boolean: ['flag'],
+        default: {
+          flag: true
+        }
+      }
+
+      checkNoArgs(opts, true)
+      checkExtraArg(opts, true)
+      checkStringArg(opts, true)
+    })
+
+    describe('for boolean options', function () {
+      [true, false, undefined, null].forEach(function (def) {
+        describe('with explicit ' + def + ' default', function () {
+          var opts = {
+            default: {
+              flag: def
+            },
+            boolean: ['flag']
+          }
+
+          it('should set true if --flag in arg', function () {
+            parser(['--flag'], opts).flag.should.be.true
+          })
+
+          it('should set false if --no-flag in arg', function () {
+            parser(['--no-flag'], opts).flag.should.be.false
+          })
+
+          it('should set ' + def + ' if no flag in arg', function () {
+            expect(parser([], opts).flag).to.equal(def)
+          })
+        })
+      })
+
+      describe('with implied false default', function () {
+        var opts = null
+
+        beforeEach(function () {
+          opts = {
+            boolean: ['flag']
+          }
+        })
+
+        it('should set true if --flag in arg', function () {
+          parser(['--flag'], opts).flag.should.be.true
+        })
+
+        it('should set false if --no-flag in arg', function () {
+          parser(['--no-flag'], opts).flag.should.be.false
+        })
+
+        it('should set false if no flag in arg', function () {
+          parser([], opts).flag.should.be.false
+        })
+      })
+
+      // Fixes: https://github.com/bcoe/yargs/issues/341
+      it('should apply defaults to camel-case form of argument', function () {
+        var argv = parser([], {
+          default: {
+            'foo-bar': 99
+          }
+        })
+
+        argv.fooBar.should.equal(99)
+      })
+    })
+
+    it('should define option as boolean and set default to true', function () {
+      var argv = parser([], {
+        boolean: ['sometrue'],
+        default: {
+          sometrue: true
+        }
+      })
+      argv.should.have.property('sometrue', true)
+    })
+
+    it('should define option as boolean and set default to false', function () {
+      var argv = parser([], {
+        default: {
+          somefalse: false
+        },
+        boolean: ['somefalse']
+      })
+      argv.should.have.property('somefalse', false)
+    })
+
+    it('should set boolean options to false by default', function () {
+      var parse = parser(['moo'], {
+        boolean: ['t', 'verbose'],
+        default: {
+          verbose: false,
+          t: false
+        }
+      })
+      parse.should.have.property('verbose', false).and.be.a('boolean')
+      parse.should.have.property('t', false).and.be.a('boolean')
+      parse.should.have.property('_').and.deep.equal(['moo'])
+    })
+  })
+
+  describe('camelCase', function () {
+    function runTests (strict) {
+      if (!strict) {
+        // Skip this test in strict mode because this option is not specified
+        it('should provide options with dashes as camelCase properties', function () {
+          var result = parser(['--some-option'])
+
+          result.should.have.property('some-option').that.is.a('boolean').and.is.true
+          result.should.have.property('someOption').that.is.a('boolean').and.is.true
+        })
+      }
+
+      it('should provide count options with dashes as camelCase properties', function () {
+        var result = parser([ '--some-option', '--some-option', '--some-option' ], {
+          count: ['some-option']
+        })
+
+        result.should.have.property('some-option', 3)
+        result.should.have.property('someOption', 3)
+      })
+
+      it('should provide options with dashes and aliases as camelCase properties', function () {
+        var result = parser(['--some-option'], {
+          alias: {
+            'some-horse': 'o'
+          }
+        })
+
+        result.should.have.property('some-option').that.is.a('boolean').and.is.true
+        result.should.have.property('someOption').that.is.a('boolean').and.is.true
+      })
+
+      it('should provide defaults of options with dashes as camelCase properties', function () {
+        var result = parser([], {
+          default: {
+            'some-option': 'asdf'
+          }
+        })
+
+        result.should.have.property('some-option', 'asdf')
+        result.should.have.property('someOption', 'asdf')
+      })
+
+      it('should provide aliases of options with dashes as camelCase properties', function () {
+        var result = parser([], {
+          default: {
+            'some-option': 'asdf'
+          },
+          alias: {
+            'some-option': ['o']
+          }
+        })
+
+        result.should.have.property('o', 'asdf')
+        result.should.have.property('some-option', 'asdf')
+        result.should.have.property('someOption', 'asdf')
+      })
+
+      it('should provide aliases of options with dashes as camelCase properties', function () {
+        var result = parser([], {
+          alias: {
+            o: ['some-option']
+          },
+          default: {
+            o: 'asdf'
+          }
+        })
+
+        result.should.have.property('o', 'asdf')
+        result.should.have.property('some-option', 'asdf')
+        result.should.have.property('someOption', 'asdf')
+      })
+
+      it('should provide aliases with dashes as camelCase properties', function () {
+        var result = parser(['--some-option', 'val'], {
+          alias: {
+            o: 'some-option'
+          }
+        })
+
+        result.should.have.property('o').that.is.a('string').and.equals('val')
+        result.should.have.property('some-option').that.is.a('string').and.equals('val')
+        result.should.have.property('someOption').that.is.a('string').and.equals('val')
+      })
+    }
+
+    describe('dashes and camelCase', function () {
+      runTests()
+    })
+
+    describe('dashes and camelCase (strict)', function () {
+      runTests(true)
+    })
+  })
+
+  describe('-', function () {
+    it('should set - as value of n', function () {
+      var argv = parser(['-n', '-'])
+      argv.should.have.property('n', '-')
+      argv.should.have.property('_').with.length(0)
+    })
+
+    it('should set - as a non-hyphenated value', function () {
+      var argv = parser(['-'])
+      argv.should.have.property('_').and.deep.equal(['-'])
+    })
+
+    it('should set - as a value of f', function () {
+      var argv = parser(['-f-'])
+      argv.should.have.property('f', '-')
+      argv.should.have.property('_').with.length(0)
+    })
+
+    it('should set b to true and set - as a non-hyphenated value when b is set as a boolean', function () {
+      var argv = parser(['-b', '-'], {
+        boolean: ['b']
+      })
+
+      argv.should.have.property('b', true)
+      argv.should.have.property('_').and.deep.equal(['-'])
+    })
+
+    it('should set - as the value of s when s is set as a string', function () {
+      var argv = parser([ '-s', '-' ], {
+        string: ['s']
+      })
+
+      argv.should.have.property('s', '-')
+      argv.should.have.property('_').with.length(0)
+    })
+  })
+
+  describe('count', function () {
+    it('should count the number of times a boolean is present', function () {
+      var parsed
+
+      parsed = parser(['-x'], {
+        count: ['verbose']
+      })
+      parsed.verbose.should.equal(0)
+
+      parsed = parser(['--verbose'], {
+        count: ['verbose']
+      })
+      parsed.verbose.should.equal(1)
+
+      parsed = parser(['--verbose', '--verbose'], {
+        count: ['verbose']
+      })
+      parsed.verbose.should.equal(2)
+
+      parsed = parser(['-vvv'], {
+        alias: {
+          v: ['verbose']
+        },
+        count: ['verbose']
+      })
+      parsed.verbose.should.equal(3)
+
+      parsed = parser(['--verbose', '--verbose', '-v', '--verbose'], {
+        count: ['verbose'],
+        alias: {
+          v: ['verbose']
+        }
+      })
+      parsed.verbose.should.equal(4)
+
+      parsed = parser(['--verbose', '--verbose', '-v', '-vv'], {
+        count: ['verbose'],
+        alias: {
+          v: ['verbose']
+        }
+      })
+      parsed.verbose.should.equal(5)
+    })
+
+    it('should not consume the next argument', function () {
+      var parsed = parser([ '-v', 'moo' ], {
+        count: 'v'
+      })
+      parsed.v.should.equal(1)
+      parsed.should.have.property('_').and.deep.equal(['moo'])
+
+      parsed = parser([ '--verbose', 'moomoo', '--verbose' ], {
+        count: 'verbose'
+      })
+      parsed.verbose.should.equal(2)
+      parsed.should.have.property('_').and.deep.equal(['moomoo'])
+    })
+
+    it('should use a default value as is when no arg given', function () {
+      var parsed = parser([], {
+        count: 'v',
+        default: { v: 3 }
+      })
+      parsed.v.should.equal(3)
+
+      parsed = parser([], {
+        count: 'v',
+        default: { v: undefined }
+      })
+      expect(parsed.v).to.be.undefined
+
+      parsed = parser([], {
+        count: 'v',
+        default: { v: null }
+      })
+      expect(parsed.v).to.be.null
+
+      parsed = parser([], {
+        count: 'v',
+        default: { v: false }
+      })
+      parsed.v.should.equal(false)
+
+      parsed = parser([], {
+        count: 'v',
+        default: { v: 'hello' }
+      })
+      parsed.v.should.equal('hello')
+    })
+
+    it('should ignore a default value when arg given', function () {
+      var parsed = parser(['-vv', '-v', '-v'], {
+        count: 'v',
+        default: { v: 1 }
+      })
+      parsed.v.should.equal(4)
+    })
+
+    it('should increment regardless of arg value', function () {
+      var parsed = parser([
+        '-v',
+        '-v=true',
+        '-v', 'true',
+        '-v=false',
+        '-v', 'false',
+        '--no-v',
+        '-v=999',
+        '-v=foobar'
+      ], { count: 'v' })
+      parsed.v.should.equal(8)
+    })
+  })
+
+  describe('array', function () {
+    it('should group values into an array if the same option is specified multiple times', function () {
+      var parse = parser(['-v', 'a', '-v', 'b', '-v', 'c'])
+      parse.should.have.property('v').and.deep.equal(['a', 'b', 'c'])
+      parse.should.have.property('_').with.length(0)
+    })
+
+    it('should default an array to an empty array if passed as first option followed by another', function () {
+      var result = parser(['-a', '-b'], {
+        array: 'a'
+      })
+      result.should.have.property('a').and.deep.equal([])
+    })
+
+    it('should not attempt to default array if an element has already been populated', function () {
+      var result = parser(['-a', 'foo', 'bar', '-b'], {
+        array: 'a'
+      })
+      result.should.have.property('a').and.deep.equal(['foo', 'bar'])
+    })
+
+    it('should default argument to empty array if no value given', function () {
+      var result = parser(['-b'], {
+        array: 'b'
+      })
+      result.should.have.property('b').and.deep.equal([])
+    })
+
+    it('should place value of argument in array, when one argument provided', function () {
+      var result = parser(['-b', '33'], {
+        array: ['b']
+      })
+      Array.isArray(result.b).should.equal(true)
+      result.b[0].should.equal(33)
+    })
+
+    it('should add multiple argument values to the array', function () {
+      var result = parser(['-b', '33', '-b', 'hello'], {
+        array: 'b'
+      })
+      Array.isArray(result.b).should.equal(true)
+      result.b.should.include(33)
+      result.b.should.include('hello')
+    })
+
+    it('should allow array: true, to be set inside an option block', function () {
+      var result = parser(['-b', '33'], {
+        array: 'b'
+      })
+      Array.isArray(result.b).should.equal(true)
+      result.b.should.include(33)
+    })
+
+    // issue #103
+    it('should default camel-case alias to array type', function () {
+      var result = parser(['--ca-path', 'http://www.example.com'], {
+        array: ['ca-path']
+      })
+
+      Array.isArray(result['ca-path']).should.equal(true)
+      Array.isArray(result.caPath).should.equal(true)
+    })
+
+    it('should default alias to array type', function () {
+      var result = parser(['--ca-path', 'http://www.example.com'], {
+        array: 'ca-path',
+        alias: {
+          'ca-path': 'c'
+        }
+      })
+
+      Array.isArray(result['ca-path']).should.equal(true)
+      Array.isArray(result.caPath).should.equal(true)
+      Array.isArray(result.c).should.equal(true)
+    })
+
+    // see: https://github.com/bcoe/yargs/issues/162
+    it('should eat non-hyphenated arguments until hyphenated option is hit', function () {
+      var result = parser(['-a=hello', 'world', '-b',
+        '33', '22', '--foo', 'red', 'green',
+        '--bar=cat', 'dog'], {
+          array: ['a', 'b', 'foo', 'bar']
+        })
+
+      Array.isArray(result.a).should.equal(true)
+      result.a.should.include('hello')
+      result.a.should.include('world')
+
+      Array.isArray(result.b).should.equal(true)
+      result.b.should.include(33)
+      result.b.should.include(22)
+
+      Array.isArray(result.foo).should.equal(true)
+      result.foo.should.include('red')
+      result.foo.should.include('green')
+
+      Array.isArray(result.bar).should.equal(true)
+      result.bar.should.include('cat')
+      result.bar.should.include('dog')
+    })
+
+    // see: https://github.com/yargs/yargs-parser/pull/13
+    it('should support array for --foo= format when the key is a number', function () {
+      var result = parser(['--1=a', 'b'], {
+        array: ['1']
+      })
+
+      Array.isArray(result['1']).should.equal(true)
+      result['1'][0].should.equal('a')
+      result['1'][1].should.equal('b')
+    })
+  })
+
+  describe('nargs', function () {
+    it('should allow the number of arguments following a key to be specified', function () {
+      var result = parser([ '--foo', 'apple', 'bar' ], {
+        narg: {
+          foo: 2
+        }
+      })
+
+      Array.isArray(result.foo).should.equal(true)
+      result.foo[0].should.equal('apple')
+      result.foo[1].should.equal('bar')
+    })
+
+    it('should raise an exception if there are not enough arguments following key', function () {
+      var argv = parser.detailed('--foo apple', {
+        narg: {
+          foo: 2
+        }
+      })
+      argv.error.message.should.equal('Not enough arguments following: foo')
+    })
+
+    it('nargs is applied to aliases', function () {
+      var result = parser(['--bar', 'apple', 'bar'], {
+        narg: {
+          foo: 2
+        },
+        alias: {
+          foo: 'bar'
+        }
+      })
+      Array.isArray(result.foo).should.equal(true)
+      result.foo[0].should.equal('apple')
+      result.foo[1].should.equal('bar')
+    })
+
+    it('should apply nargs to flag arguments', function () {
+      var result = parser([ '-f', 'apple', 'bar', 'blerg' ], {
+        narg: {
+          f: 2
+        }
+      })
+
+      result.f[0].should.equal('apple')
+      result.f[1].should.equal('bar')
+      result._[0].should.equal('blerg')
+    })
+
+    it('should support nargs for -f= and --bar= format arguments', function () {
+      var result = parser(['-f=apple', 'bar', 'blerg', '--bar=monkey', 'washing', 'cat'], {
+        narg: {
+          f: 2,
+          bar: 2
+        }
+      })
+
+      result.f[0].should.equal('apple')
+      result.f[1].should.equal('bar')
+      result._[0].should.equal('blerg')
+
+      result.bar[0].should.equal('monkey')
+      result.bar[1].should.equal('washing')
+      result._[1].should.equal('cat')
+    })
+
+    it('should not modify the input args if an = was used', function () {
+      var expected = ['-f=apple', 'bar', 'blerg', '--bar=monkey', 'washing', 'cat']
+      var args = expected.slice()
+      parser(args, {
+        narg: {
+          f: 2,
+          bar: 2
+        }
+      })
+      args.should.deep.equal(expected)
+
+      parser.detailed(args, {
+        narg: {
+          f: 2,
+          bar: 2
+        }
+      })
+      args.should.deep.equal(expected)
+    })
+
+    it('allows multiple nargs to be set at the same time', function () {
+      var result = parser([ '--foo', 'apple', 'bar', '--bar', 'banana', '-f' ], {
+        narg: {
+          foo: 2,
+          bar: 1
+        }
+      })
+
+      Array.isArray(result.foo).should.equal(true)
+      result.foo[0].should.equal('apple')
+      result.foo[1].should.equal('bar')
+      result.bar.should.equal('banana')
+      result.f.should.equal(true)
+    })
+
+    // see: https://github.com/yargs/yargs-parser/pull/13
+    it('should support nargs for --foo= format when the key is a number', function () {
+      var result = parser(['--1=a', 'b'], {
+        narg: {
+          1: 2
+        }
+      })
+
+      Array.isArray(result['1']).should.equal(true)
+      result['1'][0].should.equal('a')
+      result['1'][1].should.equal('b')
+    })
+  })
+
+  describe('env vars', function () {
+    it('should apply all env vars if prefix is empty', function () {
+      process.env.ONE_FISH = 'twofish'
+      process.env.RED_FISH = 'bluefish'
+      var result = parser([], {
+        envPrefix: ''
+      })
+
+      result.oneFish.should.equal('twofish')
+      result.redFish.should.equal('bluefish')
+    })
+
+    it('should apply only env vars matching prefix if prefix is valid string', function () {
+      process.env.ONE_FISH = 'twofish'
+      process.env.RED_FISH = 'bluefish'
+      process.env.GREEN_EGGS = 'sam'
+      process.env.GREEN_HAM = 'iam'
+      var result = parser([], {
+        envPrefix: 'GREEN'
+      })
+
+      result.eggs.should.equal('sam')
+      result.ham.should.equal('iam')
+      expect(result.oneFish).to.be.undefined
+      expect(result.redFish).to.be.undefined
+    })
+
+    it('should set aliases for options defined by env var', function () {
+      process.env.AIRFORCE_ONE = 'two'
+      var result = parser([], {
+        envPrefix: 'AIRFORCE',
+        alias: {
+          '1': ['one', 'uno']
+        }
+      })
+
+      result['1'].should.equal('two')
+      result.one.should.equal('two')
+      result.uno.should.equal('two')
+    })
+
+    it('should prefer command line value over env var', function () {
+      process.env.FOO_BAR = 'ignore'
+      var result = parser(['--foo-bar', 'baz'], {
+        envPrefix: ''
+      })
+
+      result.fooBar.should.equal('baz')
+    })
+
+    it('should respect type for args defined by env var', function () {
+      process.env.MY_TEST_STRING = '1'
+      process.env.MY_TEST_NUMBER = '2'
+      var result = parser([], {
+        string: 'string',
+        envPrefix: 'MY_TEST_'
+      })
+
+      result.string.should.equal('1')
+      result.number.should.equal(2)
+    })
+
+    it('should set option from aliased env var', function () {
+      process.env.SPACE_X = 'awesome'
+      var result = parser([], {
+        alias: {
+          xactly: 'x'
+        },
+        envPrefix: 'SPACE'
+      })
+
+      result.xactly.should.equal('awesome')
+    })
+
+    it('should prefer env var value over configured default', function () {
+      process.env.FOO_BALL = 'wut'
+      process.env.FOO_BOOL = 'true'
+      var result = parser([], {
+        envPrefix: 'FOO',
+        default: {
+          ball: 'baz',
+          bool: false
+        },
+        boolean: 'bool',
+        string: 'ball'
+      })
+
+      result.ball.should.equal('wut')
+      result.bool.should.equal(true)
+    })
+
+    var jsonPath = path.resolve(__dirname, './fixtures/config.json')
+    it('should prefer config file value over env var', function () {
+      process.env.CFG_HERP = 'zerp'
+      var result = parser(['--cfg', jsonPath], {
+        envPrefix: 'CFG',
+        config: 'cfg',
+        string: 'herp',
+        default: {
+          herp: 'nerp'
+        }
+      })
+
+      result.herp.should.equal('derp')
+    })
+
+    it('should support an env var value as config file option', function () {
+      process.env.TUX_CFG = jsonPath
+      var result = parser([], {
+        envPrefix: 'TUX',
+        config: ['cfg'],
+        default: {
+          z: 44
+        }
+      })
+
+      result.should.have.property('herp')
+      result.should.have.property('foo')
+      result.should.have.property('version')
+      result.should.have.property('truthy')
+      result.z.should.equal(55)
+    })
+
+    it('should prefer cli config file option over env var config file option', function () {
+      process.env.MUX_CFG = path.resolve(__dirname, '../package.json')
+      var result = parser(['--cfg', jsonPath], {
+        envPrefix: 'MUX',
+        config: 'cfg'
+      })
+
+      result.should.have.property('herp')
+      result.should.have.property('foo')
+      result.should.have.property('version')
+      result.should.have.property('truthy')
+      result.z.should.equal(55)
+    })
+
+    it('should apply all nested env vars', function () {
+      process.env.TEST_A = 'a'
+      process.env.TEST_NESTED_OPTION__FOO = 'baz'
+      process.env.TEST_NESTED_OPTION__BAR = 'bar'
+      var result = parser(['--nestedOption.foo', 'bar'], {
+        envPrefix: 'TEST'
+      })
+
+      result.should.have.property('a', 'a')
+      result.should.have.property('nestedOption').and.deep.equal({
+        foo: 'bar',
+        bar: 'bar'
+      })
+    })
+
+    it('should apply nested env var if argv value is using default value', function () {
+      process.env.TEST_A = 'a'
+      process.env.TEST_NESTED_OPTION__FOO = 'baz'
+      process.env.TEST_NESTED_OPTION__BAR = 'bar'
+      var result = parser([], {
+        envPrefix: 'TEST',
+        default: {
+          'nestedOption.foo': 'banana'
+        }
+      })
+
+      result.should.have.property('a', 'a')
+      result.should.have.property('nestedOption').and.deep.equal({
+        foo: 'baz',
+        bar: 'bar'
+      })
+    })
+  })
+
+  describe('configuration', function () {
+    describe('short option groups', function () {
+      it('allows short-option-groups to be disabled', function () {
+        var parse = parser(['-cats=meow'], {
+          configuration: {
+            'short-option-groups': false
+          }
+        })
+        parse.cats.should.equal('meow')
+        parse = parser(['-cats', 'meow'], {
+          configuration: {
+            'short-option-groups': false
+          }
+        })
+        parse.cats.should.equal('meow')
+      })
+    })
+
+    describe('camel-case expansion', function () {
+      it('does not expand camel-case aliases', function () {
+        var parsed = parser.detailed([], {
+          alias: {
+            'foo-bar': ['x']
+          },
+          configuration: {
+            'camel-case-expansion': false
+          }
+        })
+
+        expect(parsed.newAliases.fooBar).to.equal(undefined)
+        expect(parsed.aliases.fooBar).to.equal(undefined)
+      })
+
+      it('does not expand camel-case keys', function () {
+        var parsed = parser.detailed(['--foo-bar=apple'], {
+          configuration: {
+            'camel-case-expansion': false
+          }
+        })
+
+        expect(parsed.argv.fooBar).to.equal(undefined)
+        expect(parsed.argv['foo-bar']).to.equal('apple')
+      })
+    })
+
+    describe('dot notation', function () {
+      it('does not expand dot notation defaults', function () {
+        var parsed = parser([], {
+          default: {
+            'foo.bar': 'x'
+          },
+          configuration: {
+            'dot-notation': false
+          }
+        })
+
+        expect(parsed['foo.bar']).to.equal('x')
+      })
+
+      it('does not expand dot notation arguments', function () {
+        var parsed = parser(['--foo.bar', 'banana'], {
+          configuration: {
+            'dot-notation': false
+          }
+        })
+        expect(parsed['foo.bar']).to.equal('banana')
+        parsed = parser(['--foo.bar=banana'], {
+          configuration: {
+            'dot-notation': false
+          }
+        })
+        expect(parsed['foo.bar']).to.equal('banana')
+      })
+
+      it('should use value from cli, if cli overrides dot notation default', function () {
+        var parsed = parser(['--foo.bar', 'abc'], {
+          default: {
+            'foo.bar': 'default'
+          },
+          configuration: {
+            'dot-notation': false
+          }
+        })
+
+        expect(parsed['foo.bar']).to.equal('abc')
+      })
+
+      it('should also override dot notation alias', function () {
+        var parsed = parser(['--foo.bar', 'abc'], {
+          alias: {
+            'foo.bar': ['alias.bar']
+          },
+          default: {
+            'foo.bar': 'default'
+          },
+          configuration: {
+            'dot-notation': false
+          }
+        })
+
+        expect(parsed['alias.bar']).to.equal('abc')
+      })
+
+      it('does not expand alias of first element of dot notation arguments', function () {
+        var parsed = parser(['--foo.bar', 'banana'], {
+          alias: {
+            'foo': ['f']
+          },
+          configuration: {
+            'dot-notation': false
+          }
+        })
+        expect(parsed['foo.bar']).to.equal('banana')
+        expect(parsed).not.to.include.keys('f.bar')
+      })
+    })
+
+    describe('parse numbers', function () {
+      it('does not coerce defaults into numbers', function () {
+        var parsed = parser([], {
+          default: {
+            'foo': '5'
+          },
+          configuration: {
+            'parse-numbers': false
+          }
+        })
+
+        expect(parsed['foo']).to.equal('5')
+      })
+
+      it('does not coerce arguments into numbers', function () {
+        var parsed = parser(['--foo', '5'], {
+          configuration: {
+            'parse-numbers': false
+          }
+        })
+        expect(parsed['foo']).to.equal('5')
+      })
+
+      it('does not coerce positional arguments into numbers', function () {
+        var parsed = parser(['5'], {
+          configuration: {
+            'parse-numbers': false
+          }
+        })
+        expect(parsed._[0]).to.equal('5')
+      })
+    })
+
+    describe('boolean negation', function () {
+      it('does not negate arguments prefixed with --no-', function () {
+        var parsed = parser(['--no-dice'], {
+          configuration: {
+            'boolean-negation': false
+          }
+        })
+
+        parsed['no-dice'].should.equal(true)
+        expect(parsed.dice).to.equal(undefined)
+      })
+    })
+  })
+
+  // addresses: https://github.com/yargs/yargs-parser/issues/41
+  it('defaults to empty array if array option is provided no values', function () {
+    var parsed = parser(['-f'], {
+      'alias': {
+        'f': 'files'
+      },
+      'array': ['files']
+    })
+    parsed.f.should.deep.equal([])
+    parsed.files.should.deep.equal([])
+
+    parsed = parser(['--files'], {
+      'alias': {
+        'f': 'files'
+      },
+      'array': ['files']
+    })
+    parsed.f.should.deep.equal([])
+    parsed.files.should.deep.equal([])
+
+    parsed = parser(['-f', '-y'], {
+      'alias': {
+        'f': 'files'
+      },
+      'array': ['files']
+    })
+    parsed.f.should.deep.equal([])
+    parsed.files.should.deep.equal([])
+  })
+
+  describe('coerce', function () {
+    it('applies coercion function to simple arguments', function () {
+      var parsed = parser(['--foo', '99'], {
+        coerce: {
+          foo: function (arg) {
+            return arg * -1
+          }
+        }
+      })
+      parsed.foo.should.equal(-99)
+    })
+
+    it('applies coercion function to aliases', function () {
+      var parsed = parser(['--foo', '99'], {
+        coerce: {
+          f: function (arg) {
+            return arg * -1
+          }
+        },
+        alias: {
+          f: ['foo']
+        }
+      })
+      parsed.foo.should.equal(-99)
+      parsed.f.should.equal(-99)
+    })
+
+    it('applies coercion function to all dot options', function () {
+      var parsed = parser(['--foo.bar', 'nananana'], {
+        coerce: {
+          foo: function (val) {
+            val.bar += ', batman!'
+            return val
+          }
+        }
+      })
+      parsed.foo.bar.should.equal('nananana, batman!')
+    })
+
+    it('applies coercion function to an implicit array', function () {
+      var parsed = parser(['--foo', '99', '-f', '33'], {
+        coerce: {
+          f: function (arg) {
+            return arg.map(function (a) {
+              return a * -1
+            })
+          }
+        },
+        alias: {
+          f: ['foo']
+        }
+      })
+      parsed.f.should.deep.equal([-99, -33])
+      parsed.foo.should.deep.equal([-99, -33])
+    })
+
+    it('applies coercion function to an explicit array', function () {
+      var parsed = parser(['--foo', '99', '-f', '33'], {
+        coerce: {
+          f: function (arg) {
+            return arg.map(function (a) {
+              return a * -1
+            })
+          }
+        },
+        array: ['foo'],
+        alias: {
+          f: ['foo']
+        }
+      })
+      parsed.f.should.deep.equal([-99, -33])
+      parsed.foo.should.deep.equal([-99, -33])
+    })
+
+    it('applies coercion function to _', function () {
+      var parsed = parser(['99', '33'], {
+        coerce: {
+          _: function (arg) {
+            return arg.map(function (a) {
+              return a * -1
+            })
+          }
+        }
+      })
+      parsed._.should.deep.equal([-99, -33])
+    })
+
+    // see: https://github.com/yargs/yargs/issues/550
+    it('coercion function can be used to parse large #s', function () {
+      var fancyNumberParser = function (arg) {
+        if (arg.length > 10) return arg
+        else return parseInt(arg)
+      }
+      var parsed = parser(['--foo', '88888889999990000998989898989898', '--bar', '998'], {
+        coerce: {
+          foo: fancyNumberParser,
+          bar: fancyNumberParser
+        }
+      })
+      ;(typeof parsed.foo).should.equal('string')
+      parsed.foo.should.equal('88888889999990000998989898989898')
+      ;(typeof parsed.bar).should.equal('number')
+      parsed.bar.should.equal(998)
+    })
+
+    it('populates argv.error, if an error is thrown', function () {
+      var parsed = parser.detailed(['--foo', '99'], {
+        coerce: {
+          foo: function (arg) {
+            throw Error('banana')
+          }
+        }
+      })
+      parsed.error.message.should.equal('banana')
+    })
+
+    it('populates argv.error, if an error is thrown for an explicit array', function () {
+      var parsed = parser.detailed(['--foo', '99'], {
+        array: ['foo'],
+        coerce: {
+          foo: function (arg) {
+            throw Error('foo is array: ' + Array.isArray(arg))
+          }
+        }
+      })
+      parsed.error.message.should.equal('foo is array: true')
+    })
+  })
+
+  // see: https://github.com/yargs/yargs-parser/issues/37
+  it('normalizes all paths in array when provided via config object', function () {
+    var argv = parser([ '--foo', 'bar' ], {
+      array: ['a'],
+      normalize: ['a'],
+      configObjects: [{'a': ['bin/../a.txt', 'bin/../b.txt']}]
+    })
+    argv.a.should.deep.equal(['a.txt', 'b.txt'])
+  })
+})
diff --git a/yargs-logo.png b/yargs-logo.png
new file mode 100644
index 0000000..0032774
Binary files /dev/null and b/yargs-logo.png differ

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-yargs-parser.git



More information about the Pkg-javascript-commits mailing list