[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