diff options
author | LinuxWizard42 <computerwizard@linuxmail.org> | 2022-10-12 22:54:37 +0300 |
---|---|---|
committer | LinuxWizard42 <computerwizard@linuxmail.org> | 2022-10-12 22:54:37 +0300 |
commit | 703e03aba33f234712206769f57717ba7d92d23d (patch) | |
tree | 0041f04ccb75bd5379c764e9fe42249fffe75fc3 /node_modules/dashdash | |
parent | ab6e257e6e9d9a483d7e86f220d8b209a2cd7753 (diff) | |
download | FlashRunner-703e03aba33f234712206769f57717ba7d92d23d.tar.gz FlashRunner-703e03aba33f234712206769f57717ba7d92d23d.tar.zst |
Added export_allowed file to make repository visible in cgit
Diffstat (limited to 'node_modules/dashdash')
-rw-r--r-- | node_modules/dashdash/CHANGES.md | 364 | ||||
-rw-r--r-- | node_modules/dashdash/LICENSE.txt | 24 | ||||
-rw-r--r-- | node_modules/dashdash/README.md | 574 | ||||
-rw-r--r-- | node_modules/dashdash/etc/dashdash.bash_completion.in | 389 | ||||
-rw-r--r-- | node_modules/dashdash/lib/dashdash.js | 1055 | ||||
-rw-r--r-- | node_modules/dashdash/package.json | 26 |
6 files changed, 2432 insertions, 0 deletions
diff --git a/node_modules/dashdash/CHANGES.md b/node_modules/dashdash/CHANGES.md new file mode 100644 index 0000000..d7c8f4e --- /dev/null +++ b/node_modules/dashdash/CHANGES.md @@ -0,0 +1,364 @@ +# node-dashdash changelog + +## not yet released + +(nothing yet) + +## 1.14.1 + +- [issue #30] Change the output used by dashdash's Bash completion support to + indicate "there are no completions for this argument" to cope with different + sorting rules on different Bash/platforms. For example: + + $ triton -v -p test2 package get <TAB> # before + ##-no -tritonpackage- completions-## + + $ triton -v -p test2 package get <TAB> # after + ##-no-completion- -results-## + +## 1.14.0 + +- New `synopsisFromOpt(<option spec>)` function. This will be used by + [node-cmdln](https://github.com/trentm/node-cmdln) to put together a synopsis + of options for a command. Some examples: + + > synopsisFromOpt({names: ['help', 'h'], type: 'bool'}); + '[ --help | -h ]' + > synopsisFromOpt({name: 'file', type: 'string', helpArg: 'FILE'}); + '[ --file=FILE ]' + + +## 1.13.1 + +- [issue #20] `bashCompletionSpecFromOptions` breaks on an options array with + an empty-string group. + + +## 1.13.0 + +- Update assert-plus dep to 1.x to get recent fixes (particularly for + `assert.optional*`). + +- Drop testing (and official support in packages.json#engines) for node 0.8.x. + Add testing against node 5.x and 4.x with `make testall`. + +- [pull #16] Change the `positiveInteger` type to NOT accept zero (0). + For those who might need the old behaviour, see + "examples/custom-option-intGteZero.js". (By Dave Pacheco.) + + +## 1.12.2 + +- Bash completion: Add `argtypes` to specify the types of positional args. + E.g. this would allow you to have an `ssh` command with `argtypes = ['host', + 'cmd']` for bash completion. You then have to provide Bash functions to + handle completing those types via the `specExtra` arg. See + "[examples/ddcompletion.js](examples/ddcompletion.js)" for an example. + +- Bash completion: Tweak so that options or only offered as completions when + there is a leading '-'. E.g. `mytool <TAB>` does NOT offer options, `mytool + -<TAB>` *does*. Without this, a tool with options would never be able to + fallback to Bash's "default" completion. For example `ls <TAB>` wouldn't + result in filename completion. Now it will. + +- Bash completion: A workaround for not being able to explicitly have *no* + completion results. Because dashdash's completion uses `complete -o default`, + we fallback to Bash's "default" completion (typically for filename + completion). Before this change, an attempt to explicitly say "there are + no completions that match" would unintentionally trigger filename completion. + Instead as a workaround we return: + + $ ddcompletion --none <TAB> # the 'none' argtype + ##-no completions-## + + $ ddcompletion # a custom 'fruit' argtype + apple banana orange + $ ddcompletion z + ##-no -fruit- completions-## + + This is a bit of a hack, but IMO a better experience than the surprise + of matching a local filename beginning with 'z', which isn't, in this + case, a "fruit". + +## 1.12.1 + +- Bash completion: Document `<option spec>.completionType`. Add `includeHidden` + option to `bashCompletionSpecFromOptions()`. Add support for dealing with + hidden subcmds. + + +## 1.12.0 + +- Support for generating Bash completion files. See the "Bash completion" + section of the README.md and "examples/ddcompletion.js" for an example. + + +## 1.11.0 + +- Add the `arrayFlatten` boolean option to `dashdash.addOptionType` used for + custom option types. This allows one to create an `arrayOf...` option type + where each usage of the option can return multiple results. For example: + + node mytool.js --foo a,b --foo c + + We could define an option type for `--foo` such that + `opts.foo = ['a', 'b', 'c']`. See + "[examples/custom-option-arrayOfCommaSepString.js](examples/custom-option-arrayOfCommaSepString.js)" + for an example. + + +## 1.10.1 + +- Trim the published package to the minimal bits. Before: 24K tarball, 144K unpacked. + After: 12K tarball, 48K unpacked. `npm` won't let me drop the README.md. :) + + +## 1.10.0 + +- [issue #9] Support `includeDefault` in help config (similar to `includeEnv`) to have a + note of an option's default value, if any, in help output. +- [issue #11] Fix option group breakage introduced in v1.9.0. + + +## 1.9.0 + +- [issue #10] Custom option types added with `addOptionType` can specify a + "default" value. See "examples/custom-option-fruit.js". + + +## 1.8.0 + +- Support `hidden: true` in an option spec to have help output exclude this + option. + + +## 1.7.3 + +- [issue #8] Fix parsing of a short option group when one of the + option takes an argument. For example, consider `tail` with + a `-f` boolean option and a `-n` option that takes a number + argument. This should parse: + + tail -fn5 + + Before this change, that would not parse correctly. + It is suspected that this was introduced in version 1.4.0 + (with commit 656fa8bc71c372ebddad0a7026bd71611e2ec99a). + + +## 1.7.2 + +- Known issues: #8 + +- Exclude 'tools/' dir in packages published to npm. + + +## 1.7.1 + +- Known issues: #8 + +- Support an option group *empty string* value: + + ... + { group: '' }, + ... + + to render as a blank line in option help. This can help separate loosely + related sets of options without resorting to a title for option groups. + + +## 1.7.0 + +- Known issues: #8 + +- [pull #7] Support for `<parser>.help({helpWrap: false, ...})` option to be able + to fully control the formatting for option help (by Patrick Mooney) `helpWrap: + false` can also be set on individual options in the option objects, e.g.: + + var options = [ + { + names: ['foo'], + type: 'string', + helpWrap: false, + help: 'long help with\n newlines' + + '\n spaces\n and such\nwill render correctly' + }, + ... + ]; + + +## 1.6.0 + +- Known issues: #8 + +- [pull #6] Support headings between groups of options (by Joshua M. Clulow) + so that this code: + + var options = [ + { group: 'Armament Options' }, + { names: [ 'weapon', 'w' ], type: 'string' }, + { group: 'General Options' }, + { names: [ 'help', 'h' ], type: 'bool' } + ]; + ... + + will give you this help output: + + ... + Armament Options: + -w, --weapon + + General Options: + -h, --help + ... + + +## 1.5.0 + +- Known issues: #8 + +- Add support for adding custom option types. "examples/custom-option-duration.js" + shows an example adding a "duration" option type. + + $ node custom-option-duration.js -t 1h + duration: 3600000 ms + $ node custom-option-duration.js -t 1s + duration: 1000 ms + $ node custom-option-duration.js -t 5d + duration: 432000000 ms + $ node custom-option-duration.js -t bogus + custom-option-duration.js: error: arg for "-t" is not a valid duration: "bogus" + + A custom option type is added via: + + var dashdash = require('dashdash'); + dashdash.addOptionType({ + name: '...', + takesArg: true, + helpArg: '...', + parseArg: function (option, optstr, arg) { + ... + } + }); + +- [issue #4] Add `date` and `arrayOfDate` option types. They accept these date + formats: epoch second times (e.g. 1396031701) and ISO 8601 format: + `YYYY-MM-DD[THH:MM:SS[.sss][Z]]` (e.g. "2014-03-28", + "2014-03-28T18:35:01.489Z"). See "examples/date.js" for an example usage. + + $ node examples/date.js -s 2014-01-01 -e $(date +%s) + start at 2014-01-01T00:00:00.000Z + end at 2014-03-29T04:26:18.000Z + + +## 1.4.0 + +- Known issues: #8 + +- [pull #2, pull #3] Add a `allowUnknown: true` option on `createParser` to + allow unknown options to be passed through as `opts._args` instead of parsing + throwing an exception (by https://github.com/isaacs). + + See 'allowUnknown' in the README for a subtle caveat. + + +## 1.3.2 + +- Fix a subtlety where a *bool* option using both `env` and `default` didn't + work exactly correctly. If `default: false` then all was fine (by luck). + However, if you had an option like this: + + options: [ { + names: ['verbose', 'v'], + env: 'FOO_VERBOSE', + 'default': true, // <--- this + type: 'bool' + } ], + + wanted `FOO_VERBOSE=0` to make the option false, then you need the fix + in this version of dashdash. + + +## 1.3.1 + +- [issue #1] Fix an envvar not winning over an option 'default'. Previously + an option with both `default` and `env` would never take a value from the + environment variable. E.g. `FOO_FILE` would never work here: + + options: [ { + names: ['file', 'f'], + env: 'FOO_FILE', + 'default': 'default.file', + type: 'string' + } ], + + +## 1.3.0 + +- [Backward incompatible change for boolean envvars] Change the + interpretation of environment variables for boolean options to consider '0' + to be false. Previous to this *any* value to the envvar was considered + true -- which was quite misleading. Example: + + $ FOO_VERBOSE=0 node examples/foo.js + # opts: { verbose: [ false ], + _order: [ { key: 'verbose', value: false, from: 'env' } ], + _args: [] } + # args: [] + + +## 1.2.1 + +- Fix for `parse.help({includeEnv: true, ...})` handling to ensure that an + option with an `env` **but no `help`** still has the "Environment: ..." + output. E.g.: + + { names: ['foo'], type: 'string', env: 'FOO' } + + ... + + --foo=ARG Environment: FOO=ARG + + +## 1.2.0 + +- Transform the option key on the `opts` object returned from + `<parser>.parse()` for convenience. Currently this is just + `s/-/_/g`, e.g. '--dry-run' -> `opts.dry_run`. This allow one to use hyphen + in option names (common) but not have to do silly things like + `opt["dry-run"]` to access the parsed results. + + +## 1.1.0 + +- Environment variable integration. Envvars can be associated with an option, + then option processing will fallback to using that envvar if defined and + if the option isn't specified in argv. See the "Environment variable + integration" section in the README. + +- Change the `<parser>.parse()` signature to take a single object with keys + for arguments. The old signature is still supported. + +- `dashdash.createParser(CONFIG)` alternative to `new dashdash.Parser(CONFIG)` + a la many node-land APIs. + + +## 1.0.2 + +- Add "positiveInteger" and "arrayOfPositiveInteger" option types that only + accept positive integers. + +- Add "integer" and "arrayOfInteger" option types that accepts only integers. + Note that, for better or worse, these do NOT accept: "0x42" (hex), "1e2" + (with exponent) or "1.", "3.0" (floats). + + +## 1.0.1 + +- Fix not modifying the given option spec objects (which breaks creating + a Parser with them more than once). + + +## 1.0.0 + +First release. diff --git a/node_modules/dashdash/LICENSE.txt b/node_modules/dashdash/LICENSE.txt new file mode 100644 index 0000000..54706c6 --- /dev/null +++ b/node_modules/dashdash/LICENSE.txt @@ -0,0 +1,24 @@ +# This is the MIT license + +Copyright (c) 2013 Trent Mick. All rights reserved. +Copyright (c) 2013 Joyent Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/node_modules/dashdash/README.md b/node_modules/dashdash/README.md new file mode 100644 index 0000000..e47b106 --- /dev/null +++ b/node_modules/dashdash/README.md @@ -0,0 +1,574 @@ +A light, featureful and explicit option parsing library for node.js. + +[Why another one? See below](#why). tl;dr: The others I've tried are one of +too loosey goosey (not explicit), too big/too many deps, or ill specified. +YMMV. + +Follow <a href="https://twitter.com/intent/user?screen_name=trentmick" target="_blank">@trentmick</a> +for updates to node-dashdash. + +# Install + + npm install dashdash + + +# Usage + +```javascript +var dashdash = require('dashdash'); + +// Specify the options. Minimally `name` (or `names`) and `type` +// must be given for each. +var options = [ + { + // `names` or a single `name`. First element is the `opts.KEY`. + names: ['help', 'h'], + // See "Option specs" below for types. + type: 'bool', + help: 'Print this help and exit.' + } +]; + +// Shortcut form. As called it infers `process.argv`. See below for +// the longer form to use methods like `.help()` on the Parser object. +var opts = dashdash.parse({options: options}); + +console.log("opts:", opts); +console.log("args:", opts._args); +``` + + +# Longer Example + +A more realistic [starter script "foo.js"](./examples/foo.js) is as follows. +This also shows using `parser.help()` for formatted option help. + +```javascript +var dashdash = require('./lib/dashdash'); + +var options = [ + { + name: 'version', + type: 'bool', + help: 'Print tool version and exit.' + }, + { + names: ['help', 'h'], + type: 'bool', + help: 'Print this help and exit.' + }, + { + names: ['verbose', 'v'], + type: 'arrayOfBool', + help: 'Verbose output. Use multiple times for more verbose.' + }, + { + names: ['file', 'f'], + type: 'string', + help: 'File to process', + helpArg: 'FILE' + } +]; + +var parser = dashdash.createParser({options: options}); +try { + var opts = parser.parse(process.argv); +} catch (e) { + console.error('foo: error: %s', e.message); + process.exit(1); +} + +console.log("# opts:", opts); +console.log("# args:", opts._args); + +// Use `parser.help()` for formatted options help. +if (opts.help) { + var help = parser.help({includeEnv: true}).trimRight(); + console.log('usage: node foo.js [OPTIONS]\n' + + 'options:\n' + + help); + process.exit(0); +} + +// ... +``` + + +Some example output from this script (foo.js): + +``` +$ node foo.js -h +# opts: { help: true, + _order: [ { name: 'help', value: true, from: 'argv' } ], + _args: [] } +# args: [] +usage: node foo.js [OPTIONS] +options: + --version Print tool version and exit. + -h, --help Print this help and exit. + -v, --verbose Verbose output. Use multiple times for more verbose. + -f FILE, --file=FILE File to process + +$ node foo.js -v +# opts: { verbose: [ true ], + _order: [ { name: 'verbose', value: true, from: 'argv' } ], + _args: [] } +# args: [] + +$ node foo.js --version arg1 +# opts: { version: true, + _order: [ { name: 'version', value: true, from: 'argv' } ], + _args: [ 'arg1' ] } +# args: [ 'arg1' ] + +$ node foo.js -f bar.txt +# opts: { file: 'bar.txt', + _order: [ { name: 'file', value: 'bar.txt', from: 'argv' } ], + _args: [] } +# args: [] + +$ node foo.js -vvv --file=blah +# opts: { verbose: [ true, true, true ], + file: 'blah', + _order: + [ { name: 'verbose', value: true, from: 'argv' }, + { name: 'verbose', value: true, from: 'argv' }, + { name: 'verbose', value: true, from: 'argv' }, + { name: 'file', value: 'blah', from: 'argv' } ], + _args: [] } +# args: [] +``` + + +See the ["examples"](examples/) dir for a number of starter examples using +some of dashdash's features. + + +# Environment variable integration + +If you want to allow environment variables to specify options to your tool, +dashdash makes this easy. We can change the 'verbose' option in the example +above to include an 'env' field: + +```javascript + { + names: ['verbose', 'v'], + type: 'arrayOfBool', + env: 'FOO_VERBOSE', // <--- add this line + help: 'Verbose output. Use multiple times for more verbose.' + }, +``` + +then the **"FOO_VERBOSE" environment variable** can be used to set this +option: + +```shell +$ FOO_VERBOSE=1 node foo.js +# opts: { verbose: [ true ], + _order: [ { name: 'verbose', value: true, from: 'env' } ], + _args: [] } +# args: [] +``` + +Boolean options will interpret the empty string as unset, '0' as false +and anything else as true. + +```shell +$ FOO_VERBOSE= node examples/foo.js # not set +# opts: { _order: [], _args: [] } +# args: [] + +$ FOO_VERBOSE=0 node examples/foo.js # '0' is false +# opts: { verbose: [ false ], + _order: [ { key: 'verbose', value: false, from: 'env' } ], + _args: [] } +# args: [] + +$ FOO_VERBOSE=1 node examples/foo.js # true +# opts: { verbose: [ true ], + _order: [ { key: 'verbose', value: true, from: 'env' } ], + _args: [] } +# args: [] + +$ FOO_VERBOSE=boogabooga node examples/foo.js # true +# opts: { verbose: [ true ], + _order: [ { key: 'verbose', value: true, from: 'env' } ], + _args: [] } +# args: [] +``` + +Non-booleans can be used as well. Strings: + +```shell +$ FOO_FILE=data.txt node examples/foo.js +# opts: { file: 'data.txt', + _order: [ { key: 'file', value: 'data.txt', from: 'env' } ], + _args: [] } +# args: [] +``` + +Numbers: + +```shell +$ FOO_TIMEOUT=5000 node examples/foo.js +# opts: { timeout: 5000, + _order: [ { key: 'timeout', value: 5000, from: 'env' } ], + _args: [] } +# args: [] + +$ FOO_TIMEOUT=blarg node examples/foo.js +foo: error: arg for "FOO_TIMEOUT" is not a positive integer: "blarg" +``` + +With the `includeEnv: true` config to `parser.help()` the environment +variable can also be included in **help output**: + + usage: node foo.js [OPTIONS] + options: + --version Print tool version and exit. + -h, --help Print this help and exit. + -v, --verbose Verbose output. Use multiple times for more verbose. + Environment: FOO_VERBOSE=1 + -f FILE, --file=FILE File to process + + +# Bash completion + +Dashdash provides a simple way to create a Bash completion file that you +can place in your "bash_completion.d" directory -- sometimes that is +"/usr/local/etc/bash_completion.d/"). Features: + +- Support for short and long opts +- Support for knowing which options take arguments +- Support for subcommands (e.g. 'git log <TAB>' to show just options for the + log subcommand). See + [node-cmdln](https://github.com/trentm/node-cmdln#bash-completion) for + how to integrate that. +- Does the right thing with "--" to stop options. +- Custom optarg and arg types for custom completions. + +Dashdash will return bash completion file content given a parser instance: + + var parser = dashdash.createParser({options: options}); + console.log( parser.bashCompletion({name: 'mycli'}) ); + +or directly from a `options` array of options specs: + + var code = dashdash.bashCompletionFromOptions({ + name: 'mycli', + options: OPTIONS + }); + +Write that content to "/usr/local/etc/bash_completion.d/mycli" and you will +have Bash completions for `mycli`. Alternatively you can write it to +any file (e.g. "~/.bashrc") and source it. + +You could add a `--completion` hidden option to your tool that emits the +completion content and document for your users to call that to install +Bash completions. + +See [examples/ddcompletion.js](examples/ddcompletion.js) for a complete +example, including how one can define bash functions for completion of custom +option types. Also see [node-cmdln](https://github.com/trentm/node-cmdln) for +how it uses this for Bash completion for full multi-subcommand tools. + +- TODO: document specExtra +- TODO: document includeHidden +- TODO: document custom types, `function complete\_FOO` guide, completionType +- TODO: document argtypes + + +# Parser config + +Parser construction (i.e. `dashdash.createParser(CONFIG)`) takes the +following fields: + +- `options` (Array of option specs). Required. See the + [Option specs](#option-specs) section below. + +- `interspersed` (Boolean). Optional. Default is true. If true this allows + interspersed arguments and options. I.e.: + + node ./tool.js -v arg1 arg2 -h # '-h' is after interspersed args + + Set it to false to have '-h' **not** get parsed as an option in the above + example. + +- `allowUnknown` (Boolean). Optional. Default is false. If false, this causes + unknown arguments to throw an error. I.e.: + + node ./tool.js -v arg1 --afe8asefksjefhas + + Set it to true to treat the unknown option as a positional + argument. + + **Caveat**: When a shortopt group, such as `-xaz` contains a mix of + known and unknown options, the *entire* group is passed through + unmolested as a positional argument. + + Consider if you have a known short option `-a`, and parse the + following command line: + + node ./tool.js -xaz + + where `-x` and `-z` are unknown. There are multiple ways to + interpret this: + + 1. `-x` takes a value: `{x: 'az'}` + 2. `-x` and `-z` are both booleans: `{x:true,a:true,z:true}` + + Since dashdash does not know what `-x` and `-z` are, it can't know + if you'd prefer to receive `{a:true,_args:['-x','-z']}` or + `{x:'az'}`, or `{_args:['-xaz']}`. Leaving the positional arg unprocessed + is the easiest mistake for the user to recover from. + + +# Option specs + +Example using all fields (required fields are noted): + +```javascript +{ + names: ['file', 'f'], // Required (one of `names` or `name`). + type: 'string', // Required. + completionType: 'filename', + env: 'MYTOOL_FILE', + help: 'Config file to load before running "mytool"', + helpArg: 'PATH', + helpWrap: false, + default: path.resolve(process.env.HOME, '.mytoolrc') +} +``` + +Each option spec in the `options` array must/can have the following fields: + +- `name` (String) or `names` (Array). Required. These give the option name + and aliases. The first name (if more than one given) is the key for the + parsed `opts` object. + +- `type` (String). Required. One of: + + - bool + - string + - number + - integer + - positiveInteger + - date (epoch seconds, e.g. 1396031701, or ISO 8601 format + `YYYY-MM-DD[THH:MM:SS[.sss][Z]]`, e.g. "2014-03-28T18:35:01.489Z") + - arrayOfBool + - arrayOfString + - arrayOfNumber + - arrayOfInteger + - arrayOfPositiveInteger + - arrayOfDate + + FWIW, these names attempt to match with asserts on + [assert-plus](https://github.com/mcavage/node-assert-plus). + You can add your own custom option types with `dashdash.addOptionType`. + See below. + +- `completionType` (String). Optional. This is used for [Bash + completion](#bash-completion) for an option argument. If not specified, + then the value of `type` is used. Any string may be specified, but only the + following values have meaning: + + - `none`: Provide no completions. + - `file`: Bash's default completion (i.e. `complete -o default`), which + includes filenames. + - *Any string FOO for which a `function complete_FOO` Bash function is + defined.* This is for custom completions for a given tool. Typically + these custom functions are provided in the `specExtra` argument to + `dashdash.bashCompletionFromOptions()`. See + ["examples/ddcompletion.js"](examples/ddcompletion.js) for an example. + +- `env` (String or Array of String). Optional. An environment variable name + (or names) that can be used as a fallback for this option. For example, + given a "foo.js" like this: + + var options = [{names: ['dry-run', 'n'], env: 'FOO_DRY_RUN'}]; + var opts = dashdash.parse({options: options}); + + Both `node foo.js --dry-run` and `FOO_DRY_RUN=1 node foo.js` would result + in `opts.dry_run = true`. + + An environment variable is only used as a fallback, i.e. it is ignored if + the associated option is given in `argv`. + +- `help` (String). Optional. Used for `parser.help()` output. + +- `helpArg` (String). Optional. Used in help output as the placeholder for + the option argument, e.g. the "PATH" in: + + ... + -f PATH, --file=PATH File to process + ... + +- `helpWrap` (Boolean). Optional, default true. Set this to `false` to have + that option's `help` *not* be text wrapped in `<parser>.help()` output. + +- `default`. Optional. A default value used for this option, if the + option isn't specified in argv. + +- `hidden` (Boolean). Optional, default false. If true, help output will not + include this option. See also the `includeHidden` option to + `bashCompletionFromOptions()` for [Bash completion](#bash-completion). + + +# Option group headings + +You can add headings between option specs in the `options` array. To do so, +simply add an object with only a `group` property -- the string to print as +the heading for the subsequent options in the array. For example: + +```javascript +var options = [ + { + group: 'Armament Options' + }, + { + names: [ 'weapon', 'w' ], + type: 'string' + }, + { + group: 'General Options' + }, + { + names: [ 'help', 'h' ], + type: 'bool' + } +]; +... +``` + +Note: You can use an empty string, `{group: ''}`, to get a blank line in help +output between groups of options. + + +# Help config + +The `parser.help(...)` function is configurable as follows: + + Options: + Armament Options: + ^^ -w WEAPON, --weapon=WEAPON Weapon with which to crush. One of: | + / sword, spear, maul | + / General Options: | + / -h, --help Print this help and exit. | + / ^^^^ ^ | + \ `-- indent `-- helpCol maxCol ---' + `-- headingIndent + +- `indent` (Number or String). Default 4. Set to a number (for that many + spaces) or a string for the literal indent. +- `headingIndent` (Number or String). Default half length of `indent`. Set to + a number (for that many spaces) or a string for the literal indent. This + indent applies to group heading lines, between normal option lines. +- `nameSort` (String). Default is 'length'. By default the names are + sorted to put the short opts first (i.e. '-h, --help' preferred + to '--help, -h'). Set to 'none' to not do this sorting. +- `maxCol` (Number). Default 80. Note that reflow is just done on whitespace + so a long token in the option help can overflow maxCol. +- `helpCol` (Number). If not set a reasonable value will be determined + between `minHelpCol` and `maxHelpCol`. +- `minHelpCol` (Number). Default 20. +- `maxHelpCol` (Number). Default 40. +- `helpWrap` (Boolean). Default true. Set to `false` to have option `help` + strings *not* be textwrapped to the helpCol..maxCol range. +- `includeEnv` (Boolean). Default false. If the option has associated + environment variables (via the `env` option spec attribute), then + append mentioned of those envvars to the help string. +- `includeDefault` (Boolean). Default false. If the option has a default value + (via the `default` option spec attribute, or a default on the option's type), + then a "Default: VALUE" string will be appended to the help string. + + +# Custom option types + +Dashdash includes a good starter set of option types that it will parse for +you. However, you can add your own via: + + var dashdash = require('dashdash'); + dashdash.addOptionType({ + name: '...', + takesArg: true, + helpArg: '...', + parseArg: function (option, optstr, arg) { + ... + }, + array: false, // optional + arrayFlatten: false, // optional + default: ..., // optional + completionType: ... // optional + }); + +For example, a simple option type that accepts 'yes', 'y', 'no' or 'n' as +a boolean argument would look like: + + var dashdash = require('dashdash'); + + function parseYesNo(option, optstr, arg) { + var argLower = arg.toLowerCase() + if (~['yes', 'y'].indexOf(argLower)) { + return true; + } else if (~['no', 'n'].indexOf(argLower)) { + return false; + } else { + throw new Error(format( + 'arg for "%s" is not "yes" or "no": "%s"', + optstr, arg)); + } + } + + dashdash.addOptionType({ + name: 'yesno' + takesArg: true, + helpArg: '<yes|no>', + parseArg: parseYesNo + }); + + var options = { + {names: ['answer', 'a'], type: 'yesno'} + }; + var opts = dashdash.parse({options: options}); + +See "examples/custom-option-\*.js" for other examples. +See the `addOptionType` block comment in "lib/dashdash.js" for more details. +Please let me know [with an +issue](https://github.com/trentm/node-dashdash/issues/new) if you write a +generally useful one. + + + +# Why + +Why another node.js option parsing lib? + +- `nopt` really is just for "tools like npm". Implicit opts (e.g. '--no-foo' + works for every '--foo'). Can't disable abbreviated opts. Can't do multiple + usages of same opt, e.g. '-vvv' (I think). Can't do grouped short opts. + +- `optimist` has surprise interpretation of options (at least to me). + Implicit opts mean ambiguities and poor error handling for fat-fingering. + `process.exit` calls makes it hard to use as a libary. + +- `optparse` Incomplete docs. Is this an attempted clone of Python's `optparse`. + Not clear. Some divergence. `parser.on("name", ...)` API is weird. + +- `argparse` Dep on underscore. No thanks just for option processing. + `find lib | wc -l` -> `26`. Overkill. + Argparse is a bit different anyway. Not sure I want that. + +- `posix-getopt` No type validation. Though that isn't a killer. AFAIK can't + have a long opt without a short alias. I.e. no `getopt_long` semantics. + Also, no whizbang features like generated help output. + +- ["commander.js"](https://github.com/visionmedia/commander.js): I wrote + [a critique](http://trentm.com/2014/01/a-critique-of-commander-for-nodejs.html) + a while back. It seems fine, but last I checked had + [an outstanding bug](https://github.com/visionmedia/commander.js/pull/121) + that would prevent me from using it. + + +# License + +MIT. See LICENSE.txt. diff --git a/node_modules/dashdash/etc/dashdash.bash_completion.in b/node_modules/dashdash/etc/dashdash.bash_completion.in new file mode 100644 index 0000000..dc33309 --- /dev/null +++ b/node_modules/dashdash/etc/dashdash.bash_completion.in @@ -0,0 +1,389 @@ +#!/bin/bash +# +# Bash completion generated for '{{name}}' at {{date}}. +# +# The original template lives here: +# https://github.com/trentm/node-dashdash/blob/master/etc/dashdash.bash_completion.in +# + +# +# Copyright 2016 Trent Mick +# Copyright 2016 Joyent, Inc. +# +# +# A generic Bash completion driver script. +# +# This is meant to provide a re-usable chunk of Bash to use for +# "etc/bash_completion.d/" files for individual tools. Only the "Configuration" +# section with tool-specific info need differ. Features: +# +# - support for short and long opts +# - support for knowing which options take arguments +# - support for subcommands (e.g. 'git log <TAB>' to show just options for the +# log subcommand) +# - does the right thing with "--" to stop options +# - custom optarg and arg types for custom completions +# - (TODO) support for shells other than Bash (tcsh, zsh, fish?, etc.) +# +# +# Examples/design: +# +# 1. Bash "default" completion. By default Bash's 'complete -o default' is +# enabled. That means when there are no completions (e.g. if no opts match +# the current word), then you'll get Bash's default completion. Most notably +# that means you get filename completion. E.g.: +# $ tool ./<TAB> +# $ tool READ<TAB> +# +# 2. all opts and subcmds: +# $ tool <TAB> +# $ tool -v <TAB> # assuming '-v' doesn't take an arg +# $ tool -<TAB> # matching opts +# $ git lo<TAB> # matching subcmds +# +# Long opt completions are given *without* the '=', i.e. we prefer space +# separated because that's easier for good completions. +# +# 3. long opt arg with '=' +# $ tool --file=<TAB> +# $ tool --file=./d<TAB> +# We maintain the "--file=" prefix. Limitation: With the attached prefix +# the 'complete -o filenames' doesn't know to do dirname '/' suffixing. Meh. +# +# 4. envvars: +# $ tool $<TAB> +# $ tool $P<TAB> +# Limitation: Currently only getting exported vars, so we miss "PS1" and +# others. +# +# 5. Defer to other completion in a subshell: +# $ tool --file $(cat ./<TAB> +# We get this from 'complete -o default ...'. +# +# 6. Custom completion types from a provided bash function. +# $ tool --profile <TAB> # complete available "profiles" +# +# +# Dev Notes: +# - compgen notes, from http://unix.stackexchange.com/questions/151118/understand-compgen-builtin-command +# - https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html +# + + +# Debugging this completion: +# 1. Uncomment the "_{{name}}_log_file=..." line. +# 2. 'tail -f /var/tmp/dashdash-completion.log' in one terminal. +# 3. Re-source this bash completion file. +#_{{name}}_log=/var/tmp/dashdash-completion.log + +function _{{name}}_completer { + + # ---- cmd definition + + {{spec}} + + + # ---- locals + + declare -a argv + + + # ---- support functions + + function trace { + [[ -n "$_{{name}}_log" ]] && echo "$*" >&2 + } + + function _dashdash_complete { + local idx context + idx=$1 + context=$2 + + local shortopts longopts optargs subcmds allsubcmds argtypes + shortopts="$(eval "echo \${cmd${context}_shortopts}")" + longopts="$(eval "echo \${cmd${context}_longopts}")" + optargs="$(eval "echo \${cmd${context}_optargs}")" + subcmds="$(eval "echo \${cmd${context}_subcmds}")" + allsubcmds="$(eval "echo \${cmd${context}_allsubcmds}")" + IFS=', ' read -r -a argtypes <<< "$(eval "echo \${cmd${context}_argtypes}")" + + trace "" + trace "_dashdash_complete(idx=$idx, context=$context)" + trace " shortopts: $shortopts" + trace " longopts: $longopts" + trace " optargs: $optargs" + trace " subcmds: $subcmds" + trace " allsubcmds: $allsubcmds" + + # Get 'state' of option parsing at this COMP_POINT. + # Copying "dashdash.js#parse()" behaviour here. + local state= + local nargs=0 + local i=$idx + local argtype + local optname + local prefix + local word + local dashdashseen= + while [[ $i -lt $len && $i -le $COMP_CWORD ]]; do + argtype= + optname= + prefix= + word= + + arg=${argv[$i]} + trace " consider argv[$i]: '$arg'" + + if [[ "$arg" == "--" && $i -lt $COMP_CWORD ]]; then + trace " dashdash seen" + dashdashseen=yes + state=arg + word=$arg + elif [[ -z "$dashdashseen" && "${arg:0:2}" == "--" ]]; then + arg=${arg:2} + if [[ "$arg" == *"="* ]]; then + optname=${arg%%=*} + val=${arg##*=} + trace " long opt: optname='$optname' val='$val'" + state=arg + argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1) + word=$val + prefix="--$optname=" + else + optname=$arg + val= + trace " long opt: optname='$optname'" + state=longopt + word=--$optname + + if [[ "$optargs" == *"-$optname="* && $i -lt $COMP_CWORD ]]; then + i=$(( $i + 1 )) + state=arg + argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1) + word=${argv[$i]} + trace " takes arg (consume argv[$i], word='$word')" + fi + fi + elif [[ -z "$dashdashseen" && "${arg:0:1}" == "-" ]]; then + trace " short opt group" + state=shortopt + word=$arg + + local j=1 + while [[ $j -lt ${#arg} ]]; do + optname=${arg:$j:1} + trace " consider index $j: optname '$optname'" + + if [[ "$optargs" == *"-$optname="* ]]; then + argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1) + if [[ $(( $j + 1 )) -lt ${#arg} ]]; then + state=arg + word=${arg:$(( $j + 1 ))} + trace " takes arg (rest of this arg, word='$word', argtype='$argtype')" + elif [[ $i -lt $COMP_CWORD ]]; then + state=arg + i=$(( $i + 1 )) + word=${argv[$i]} + trace " takes arg (word='$word', argtype='$argtype')" + fi + break + fi + + j=$(( $j + 1 )) + done + elif [[ $i -lt $COMP_CWORD && -n "$arg" ]] && $(echo "$allsubcmds" | grep -w "$arg" >/dev/null); then + trace " complete subcmd: recurse _dashdash_complete" + _dashdash_complete $(( $i + 1 )) "${context}__${arg/-/_}" + return + else + trace " not an opt or a complete subcmd" + state=arg + word=$arg + nargs=$(( $nargs + 1 )) + if [[ ${#argtypes[@]} -gt 0 ]]; then + argtype="${argtypes[$(( $nargs - 1 ))]}" + if [[ -z "$argtype" ]]; then + # If we have more args than argtypes, we use the + # last type. + argtype="${argtypes[@]: -1:1}" + fi + fi + fi + + trace " state=$state prefix='$prefix' word='$word'" + i=$(( $i + 1 )) + done + + trace " parsed: state=$state optname='$optname' argtype='$argtype' prefix='$prefix' word='$word' dashdashseen=$dashdashseen" + local compgen_opts= + if [[ -n "$prefix" ]]; then + compgen_opts="$compgen_opts -P $prefix" + fi + + case $state in + shortopt) + compgen $compgen_opts -W "$shortopts $longopts" -- "$word" + ;; + longopt) + compgen $compgen_opts -W "$longopts" -- "$word" + ;; + arg) + # If we don't know what completion to do, then emit nothing. We + # expect that we are running with: + # complete -o default ... + # where "default" means: "Use Readline's default completion if + # the compspec generates no matches." This gives us the good filename + # completion, completion in subshells/backticks. + # + # We cannot support an argtype="directory" because + # compgen -S '/' -A directory -- "$word" + # doesn't give a satisfying result. It doesn't stop at the trailing '/' + # so you cannot descend into dirs. + if [[ "${word:0:1}" == '$' ]]; then + # By default, Bash will complete '$<TAB>' to all envvars. Apparently + # 'complete -o default' does *not* give us that. The following + # gets *close* to the same completions: '-A export' misses envvars + # like "PS1". + trace " completing envvars" + compgen $compgen_opts -P '$' -A export -- "${word:1}" + elif [[ -z "$argtype" ]]; then + # Only include opts in completions if $word is not empty. + # This is to avoid completing the leading '-', which foils + # using 'default' completion. + if [[ -n "$dashdashseen" ]]; then + trace " completing subcmds, if any (no argtype, dashdash seen)" + compgen $compgen_opts -W "$subcmds" -- "$word" + elif [[ -z "$word" ]]; then + trace " completing subcmds, if any (no argtype, empty word)" + compgen $compgen_opts -W "$subcmds" -- "$word" + else + trace " completing opts & subcmds (no argtype)" + compgen $compgen_opts -W "$shortopts $longopts $subcmds" -- "$word" + fi + elif [[ $argtype == "none" ]]; then + # We want *no* completions, i.e. some way to get the active + # 'complete -o default' to not do filename completion. + trace " completing 'none' (hack to imply no completions)" + echo "##-no-completion- -results-##" + elif [[ $argtype == "file" ]]; then + # 'complete -o default' gives the best filename completion, at least + # on Mac. + trace " completing 'file' (let 'complete -o default' handle it)" + echo "" + elif ! type complete_$argtype 2>/dev/null >/dev/null; then + trace " completing '$argtype' (fallback to default b/c complete_$argtype is unknown)" + echo "" + else + trace " completing custom '$argtype'" + completions=$(complete_$argtype "$word") + if [[ -z "$completions" ]]; then + trace " no custom '$argtype' completions" + # These are in ascii and "dictionary" order so they sort + # correctly. + echo "##-no-completion- -results-##" + else + echo $completions + fi + fi + ;; + *) + trace " unknown state: $state" + ;; + esac + } + + + trace "" + trace "-- $(date)" + #trace "\$IFS: '$IFS'" + #trace "\$@: '$@'" + #trace "COMP_WORDBREAKS: '$COMP_WORDBREAKS'" + trace "COMP_CWORD: '$COMP_CWORD'" + trace "COMP_LINE: '$COMP_LINE'" + trace "COMP_POINT: $COMP_POINT" + + # Guard against negative COMP_CWORD. This is a Bash bug at least on + # Mac 10.10.4's bash. See + # <https://lists.gnu.org/archive/html/bug-bash/2009-07/msg00125.html>. + if [[ $COMP_CWORD -lt 0 ]]; then + trace "abort on negative COMP_CWORD" + exit 1; + fi + + # I don't know how to do array manip on argv vars, + # so copy over to argv array to work on them. + shift # the leading '--' + i=0 + len=$# + while [[ $# -gt 0 ]]; do + argv[$i]=$1 + shift; + i=$(( $i + 1 )) + done + trace "argv: '${argv[@]}'" + trace "argv[COMP_CWORD-1]: '${argv[$(( $COMP_CWORD - 1 ))]}'" + trace "argv[COMP_CWORD]: '${argv[$COMP_CWORD]}'" + trace "argv len: '$len'" + + _dashdash_complete 1 "" +} + + +# ---- mainline + +# Note: This if-block to help work with 'compdef' and 'compctl' is +# adapted from 'npm completion'. +if type complete &>/dev/null; then + function _{{name}}_completion { + local _log_file=/dev/null + [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log" + COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \ + COMP_LINE="$COMP_LINE" \ + COMP_POINT="$COMP_POINT" \ + _{{name}}_completer -- "${COMP_WORDS[@]}" \ + 2>$_log_file)) || return $? + } + complete -o default -F _{{name}}_completion {{name}} +elif type compdef &>/dev/null; then + function _{{name}}_completion { + local _log_file=/dev/null + [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log" + compadd -- $(COMP_CWORD=$((CURRENT-1)) \ + COMP_LINE=$BUFFER \ + COMP_POINT=0 \ + _{{name}}_completer -- "${words[@]}" \ + 2>$_log_file) + } + compdef _{{name}}_completion {{name}} +elif type compctl &>/dev/null; then + function _{{name}}_completion { + local cword line point words si + read -Ac words + read -cn cword + let cword-=1 + read -l line + read -ln point + local _log_file=/dev/null + [[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log" + reply=($(COMP_CWORD="$cword" \ + COMP_LINE="$line" \ + COMP_POINT="$point" \ + _{{name}}_completer -- "${words[@]}" \ + 2>$_log_file)) || return $? + } + compctl -K _{{name}}_completion {{name}} +fi + + +## +## This is a Bash completion file for the '{{name}}' command. You can install +## with either: +## +## cp FILE /usr/local/etc/bash_completion.d/{{name}} # Mac +## cp FILE /etc/bash_completion.d/{{name}} # Linux +## +## or: +## +## cp FILE > ~/.{{name}}.completion +## echo "source ~/.{{name}}.completion" >> ~/.bashrc +##
\ No newline at end of file diff --git a/node_modules/dashdash/lib/dashdash.js b/node_modules/dashdash/lib/dashdash.js new file mode 100644 index 0000000..adb6f13 --- /dev/null +++ b/node_modules/dashdash/lib/dashdash.js @@ -0,0 +1,1055 @@ +/** + * dashdash - A light, featureful and explicit option parsing library for + * node.js. + */ +// vim: set ts=4 sts=4 sw=4 et: + +var assert = require('assert-plus'); +var format = require('util').format; +var fs = require('fs'); +var path = require('path'); + + +var DEBUG = true; +if (DEBUG) { + var debug = console.warn; +} else { + var debug = function () {}; +} + + + +// ---- internal support stuff + +// Replace {{variable}} in `s` with the template data in `d`. +function renderTemplate(s, d) { + return s.replace(/{{([a-zA-Z]+)}}/g, function (match, key) { + return d.hasOwnProperty(key) ? d[key] : match; + }); +} + +/** + * Return a shallow copy of the given object; + */ +function shallowCopy(obj) { + if (!obj) { + return (obj); + } + var copy = {}; + Object.keys(obj).forEach(function (k) { + copy[k] = obj[k]; + }); + return (copy); +} + + +function space(n) { + var s = ''; + for (var i = 0; i < n; i++) { + s += ' '; + } + return s; +} + + +function makeIndent(arg, deflen, name) { + if (arg === null || arg === undefined) + return space(deflen); + else if (typeof (arg) === 'number') + return space(arg); + else if (typeof (arg) === 'string') + return arg; + else + assert.fail('invalid "' + name + '": not a string or number: ' + arg); +} + + +/** + * Return an array of lines wrapping the given text to the given width. + * This splits on whitespace. Single tokens longer than `width` are not + * broken up. + */ +function textwrap(s, width) { + var words = s.trim().split(/\s+/); + var lines = []; + var line = ''; + words.forEach(function (w) { + var newLength = line.length + w.length; + if (line.length > 0) + newLength += 1; + if (newLength > width) { + lines.push(line); + line = ''; + } + if (line.length > 0) + line += ' '; + line += w; + }); + lines.push(line); + return lines; +} + + +/** + * Transform an option name to a "key" that is used as the field + * on the `opts` object returned from `<parser>.parse()`. + * + * Transformations: + * - '-' -> '_': This allow one to use hyphen in option names (common) + * but not have to do silly things like `opt["dry-run"]` to access the + * parsed results. + */ +function optionKeyFromName(name) { + return name.replace(/-/g, '_'); +} + + + +// ---- Option types + +function parseBool(option, optstr, arg) { + return Boolean(arg); +} + +function parseString(option, optstr, arg) { + assert.string(arg, 'arg'); + return arg; +} + +function parseNumber(option, optstr, arg) { + assert.string(arg, 'arg'); + var num = Number(arg); + if (isNaN(num)) { + throw new Error(format('arg for "%s" is not a number: "%s"', + optstr, arg)); + } + return num; +} + +function parseInteger(option, optstr, arg) { + assert.string(arg, 'arg'); + var num = Number(arg); + if (!/^[0-9-]+$/.test(arg) || isNaN(num)) { + throw new Error(format('arg for "%s" is not an integer: "%s"', + optstr, arg)); + } + return num; +} + +function parsePositiveInteger(option, optstr, arg) { + assert.string(arg, 'arg'); + var num = Number(arg); + if (!/^[0-9]+$/.test(arg) || isNaN(num) || num === 0) { + throw new Error(format('arg for "%s" is not a positive integer: "%s"', + optstr, arg)); + } + return num; +} + +/** + * Supported date args: + * - epoch second times (e.g. 1396031701) + * - ISO 8601 format: YYYY-MM-DD[THH:MM:SS[.sss][Z]] + * 2014-03-28T18:35:01.489Z + * 2014-03-28T18:35:01.489 + * 2014-03-28T18:35:01Z + * 2014-03-28T18:35:01 + * 2014-03-28 + */ +function parseDate(option, optstr, arg) { + assert.string(arg, 'arg'); + var date; + if (/^\d+$/.test(arg)) { + // epoch seconds + date = new Date(Number(arg) * 1000); + /* JSSTYLED */ + } else if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?Z?)?$/i.test(arg)) { + // ISO 8601 format + date = new Date(arg); + } else { + throw new Error(format('arg for "%s" is not a valid date format: "%s"', + optstr, arg)); + } + if (date.toString() === 'Invalid Date') { + throw new Error(format('arg for "%s" is an invalid date: "%s"', + optstr, arg)); + } + return date; +} + +var optionTypes = { + bool: { + takesArg: false, + parseArg: parseBool + }, + string: { + takesArg: true, + helpArg: 'ARG', + parseArg: parseString + }, + number: { + takesArg: true, + helpArg: 'NUM', + parseArg: parseNumber + }, + integer: { + takesArg: true, + helpArg: 'INT', + parseArg: parseInteger + }, + positiveInteger: { + takesArg: true, + helpArg: 'INT', + parseArg: parsePositiveInteger + }, + date: { + takesArg: true, + helpArg: 'DATE', + parseArg: parseDate + }, + arrayOfBool: { + takesArg: false, + array: true, + parseArg: parseBool + }, + arrayOfString: { + takesArg: true, + helpArg: 'ARG', + array: true, + parseArg: parseString + }, + arrayOfNumber: { + takesArg: true, + helpArg: 'NUM', + array: true, + parseArg: parseNumber + }, + arrayOfInteger: { + takesArg: true, + helpArg: 'INT', + array: true, + parseArg: parseInteger + }, + arrayOfPositiveInteger: { + takesArg: true, + helpArg: 'INT', + array: true, + parseArg: parsePositiveInteger + }, + arrayOfDate: { + takesArg: true, + helpArg: 'INT', + array: true, + parseArg: parseDate + }, +}; + + + +// ---- Parser + +/** + * Parser constructor. + * + * @param config {Object} The parser configuration + * - options {Array} Array of option specs. See the README for how to + * specify each option spec. + * - allowUnknown {Boolean} Default false. Whether to throw on unknown + * options. If false, then unknown args are included in the _args array. + * - interspersed {Boolean} Default true. Whether to allow interspersed + * arguments (non-options) and options. E.g.: + * node tool.js arg1 arg2 -v + * '-v' is after some args here. If `interspersed: false` then '-v' + * would not be parsed out. Note that regardless of `interspersed` + * the presence of '--' will stop option parsing, as all good + * option parsers should. + */ +function Parser(config) { + assert.object(config, 'config'); + assert.arrayOfObject(config.options, 'config.options'); + assert.optionalBool(config.interspersed, 'config.interspersed'); + var self = this; + + // Allow interspersed arguments (true by default). + this.interspersed = (config.interspersed !== undefined + ? config.interspersed : true); + + // Don't allow unknown flags (true by default). + this.allowUnknown = (config.allowUnknown !== undefined + ? config.allowUnknown : false); + + this.options = config.options.map(function (o) { return shallowCopy(o); }); + this.optionFromName = {}; + this.optionFromEnv = {}; + for (var i = 0; i < this.options.length; i++) { + var o = this.options[i]; + if (o.group !== undefined && o.group !== null) { + assert.optionalString(o.group, + format('config.options.%d.group', i)); + continue; + } + assert.ok(optionTypes[o.type], + format('invalid config.options.%d.type: "%s" in %j', + i, o.type, o)); + assert.optionalString(o.name, format('config.options.%d.name', i)); + assert.optionalArrayOfString(o.names, + format('config.options.%d.names', i)); + assert.ok((o.name || o.names) && !(o.name && o.names), + format('exactly one of "name" or "names" required: %j', o)); + assert.optionalString(o.help, format('config.options.%d.help', i)); + var env = o.env || []; + if (typeof (env) === 'string') { + env = [env]; + } + assert.optionalArrayOfString(env, format('config.options.%d.env', i)); + assert.optionalString(o.helpGroup, + format('config.options.%d.helpGroup', i)); + assert.optionalBool(o.helpWrap, + format('config.options.%d.helpWrap', i)); + assert.optionalBool(o.hidden, format('config.options.%d.hidden', i)); + + if (o.name) { + o.names = [o.name]; + } else { + assert.string(o.names[0], + format('config.options.%d.names is empty', i)); + } + o.key = optionKeyFromName(o.names[0]); + o.names.forEach(function (n) { + if (self.optionFromName[n]) { + throw new Error(format( + 'option name collision: "%s" used in %j and %j', + n, self.optionFromName[n], o)); + } + self.optionFromName[n] = o; + }); + env.forEach(function (n) { + if (self.optionFromEnv[n]) { + throw new Error(format( + 'option env collision: "%s" used in %j and %j', + n, self.optionFromEnv[n], o)); + } + self.optionFromEnv[n] = o; + }); + } +} + +Parser.prototype.optionTakesArg = function optionTakesArg(option) { + return optionTypes[option.type].takesArg; +}; + +/** + * Parse options from the given argv. + * + * @param inputs {Object} Optional. + * - argv {Array} Optional. The argv to parse. Defaults to + * `process.argv`. + * - slice {Number} The index into argv at which options/args begin. + * Default is 2, as appropriate for `process.argv`. + * - env {Object} Optional. The env to use for 'env' entries in the + * option specs. Defaults to `process.env`. + * @returns {Object} Parsed `opts`. It has special keys `_args` (the + * remaining args from `argv`) and `_order` (gives the order that + * options were specified). + */ +Parser.prototype.parse = function parse(inputs) { + var self = this; + + // Old API was `parse([argv, [slice]])` + if (Array.isArray(arguments[0])) { + inputs = {argv: arguments[0], slice: arguments[1]}; + } + + assert.optionalObject(inputs, 'inputs'); + if (!inputs) { + inputs = {}; + } + assert.optionalArrayOfString(inputs.argv, 'inputs.argv'); + //assert.optionalNumber(slice, 'slice'); + var argv = inputs.argv || process.argv; + var slice = inputs.slice !== undefined ? inputs.slice : 2; + var args = argv.slice(slice); + var env = inputs.env || process.env; + var opts = {}; + var _order = []; + + function addOpt(option, optstr, key, val, from) { + var type = optionTypes[option.type]; + var parsedVal = type.parseArg(option, optstr, val); + if (type.array) { + if (!opts[key]) { + opts[key] = []; + } + if (type.arrayFlatten && Array.isArray(parsedVal)) { + for (var i = 0; i < parsedVal.length; i++) { + opts[key].push(parsedVal[i]); + } + } else { + opts[key].push(parsedVal); + } + } else { + opts[key] = parsedVal; + } + var item = { key: key, value: parsedVal, from: from }; + _order.push(item); + } + + // Parse args. + var _args = []; + var i = 0; + outer: while (i < args.length) { + var arg = args[i]; + + // End of options marker. + if (arg === '--') { + i++; + break; + + // Long option + } else if (arg.slice(0, 2) === '--') { + var name = arg.slice(2); + var val = null; + var idx = name.indexOf('='); + if (idx !== -1) { + val = name.slice(idx + 1); + name = name.slice(0, idx); + } + var option = this.optionFromName[name]; + if (!option) { + if (!this.allowUnknown) + throw new Error(format('unknown option: "--%s"', name)); + else if (this.interspersed) + _args.push(arg); + else + break outer; + } else { + var takesArg = this.optionTakesArg(option); + if (val !== null && !takesArg) { + throw new Error(format('argument given to "--%s" option ' + + 'that does not take one: "%s"', name, arg)); + } + if (!takesArg) { + addOpt(option, '--'+name, option.key, true, 'argv'); + } else if (val !== null) { + addOpt(option, '--'+name, option.key, val, 'argv'); + } else if (i + 1 >= args.length) { + throw new Error(format('do not have enough args for "--%s" ' + + 'option', name)); + } else { + addOpt(option, '--'+name, option.key, args[i + 1], 'argv'); + i++; + } + } + + // Short option + } else if (arg[0] === '-' && arg.length > 1) { + var j = 1; + var allFound = true; + while (j < arg.length) { + var name = arg[j]; + var option = this.optionFromName[name]; + if (!option) { + allFound = false; + if (this.allowUnknown) { + if (this.interspersed) { + _args.push(arg); + break; + } else + break outer; + } else if (arg.length > 2) { + throw new Error(format( + 'unknown option: "-%s" in "%s" group', + name, arg)); + } else { + throw new Error(format('unknown option: "-%s"', name)); + } + } else if (this.optionTakesArg(option)) { + break; + } + j++; + } + + j = 1; + while (allFound && j < arg.length) { + var name = arg[j]; + var val = arg.slice(j + 1); // option val if it takes an arg + var option = this.optionFromName[name]; + var takesArg = this.optionTakesArg(option); + if (!takesArg) { + addOpt(option, '-'+name, option.key, true, 'argv'); + } else if (val) { + addOpt(option, '-'+name, option.key, val, 'argv'); + break; + } else { + if (i + 1 >= args.length) { + throw new Error(format('do not have enough args ' + + 'for "-%s" option', name)); + } + addOpt(option, '-'+name, option.key, args[i + 1], 'argv'); + i++; + break; + } + j++; + } + + // An interspersed arg + } else if (this.interspersed) { + _args.push(arg); + + // An arg and interspersed args are not allowed, so done options. + } else { + break outer; + } + i++; + } + _args = _args.concat(args.slice(i)); + + // Parse environment. + Object.keys(this.optionFromEnv).forEach(function (envname) { + var val = env[envname]; + if (val === undefined) + return; + var option = self.optionFromEnv[envname]; + if (opts[option.key] !== undefined) + return; + var takesArg = self.optionTakesArg(option); + if (takesArg) { + addOpt(option, envname, option.key, val, 'env'); + } else if (val !== '') { + // Boolean envvar handling: + // - VAR=<empty-string> not set (as if the VAR was not set) + // - VAR=0 false + // - anything else true + addOpt(option, envname, option.key, (val !== '0'), 'env'); + } + }); + + // Apply default values. + this.options.forEach(function (o) { + if (opts[o.key] === undefined) { + if (o.default !== undefined) { + opts[o.key] = o.default; + } else if (o.type && optionTypes[o.type].default !== undefined) { + opts[o.key] = optionTypes[o.type].default; + } + } + }); + + opts._order = _order; + opts._args = _args; + return opts; +}; + + +/** + * Return help output for the current options. + * + * E.g.: if the current options are: + * [{names: ['help', 'h'], type: 'bool', help: 'Show help and exit.'}] + * then this would return: + * ' -h, --help Show help and exit.\n' + * + * @param config {Object} Config for controlling the option help output. + * - indent {Number|String} Default 4. An indent/prefix to use for + * each option line. + * - nameSort {String} Default is 'length'. By default the names are + * sorted to put the short opts first (i.e. '-h, --help' preferred + * to '--help, -h'). Set to 'none' to not do this sorting. + * - maxCol {Number} Default 80. Note that long tokens in a help string + * can go past this. + * - helpCol {Number} Set to specify a specific column at which + * option help will be aligned. By default this is determined + * automatically. + * - minHelpCol {Number} Default 20. + * - maxHelpCol {Number} Default 40. + * - includeEnv {Boolean} Default false. If true, a note stating the `env` + * envvar (if specified for this option) will be appended to the help + * output. + * - includeDefault {Boolean} Default false. If true, a note stating + * the `default` for this option, if any, will be appended to the help + * output. + * - helpWrap {Boolean} Default true. Wrap help text in helpCol..maxCol + * bounds. + * @returns {String} + */ +Parser.prototype.help = function help(config) { + config = config || {}; + assert.object(config, 'config'); + + var indent = makeIndent(config.indent, 4, 'config.indent'); + var headingIndent = makeIndent(config.headingIndent, + Math.round(indent.length / 2), 'config.headingIndent'); + + assert.optionalString(config.nameSort, 'config.nameSort'); + var nameSort = config.nameSort || 'length'; + assert.ok(~['length', 'none'].indexOf(nameSort), + 'invalid "config.nameSort"'); + assert.optionalNumber(config.maxCol, 'config.maxCol'); + assert.optionalNumber(config.maxHelpCol, 'config.maxHelpCol'); + assert.optionalNumber(config.minHelpCol, 'config.minHelpCol'); + assert.optionalNumber(config.helpCol, 'config.helpCol'); + assert.optionalBool(config.includeEnv, 'config.includeEnv'); + assert.optionalBool(config.includeDefault, 'config.includeDefault'); + assert.optionalBool(config.helpWrap, 'config.helpWrap'); + var maxCol = config.maxCol || 80; + var minHelpCol = config.minHelpCol || 20; + var maxHelpCol = config.maxHelpCol || 40; + + var lines = []; + var maxWidth = 0; + this.options.forEach(function (o) { + if (o.hidden) { + return; + } + if (o.group !== undefined && o.group !== null) { + // We deal with groups in the next pass + lines.push(null); + return; + } + var type = optionTypes[o.type]; + var arg = o.helpArg || type.helpArg || 'ARG'; + var line = ''; + var names = o.names.slice(); + if (nameSort === 'length') { + names.sort(function (a, b) { + if (a.length < b.length) + return -1; + else if (b.length < a.length) + return 1; + else + return 0; + }) + } + names.forEach(function (name, i) { + if (i > 0) + line += ', '; + if (name.length === 1) { + line += '-' + name + if (type.takesArg) + line += ' ' + arg; + } else { + line += '--' + name + if (type.takesArg) + line += '=' + arg; + } + }); + maxWidth = Math.max(maxWidth, line.length); + lines.push(line); + }); + + // Add help strings. + var helpCol = config.helpCol; + if (!helpCol) { + helpCol = maxWidth + indent.length + 2; + helpCol = Math.min(Math.max(helpCol, minHelpCol), maxHelpCol); + } + var i = -1; + this.options.forEach(function (o) { + if (o.hidden) { + return; + } + i++; + + if (o.group !== undefined && o.group !== null) { + if (o.group === '') { + // Support a empty string "group" to have a blank line between + // sets of options. + lines[i] = ''; + } else { + // Render the group heading with the heading-specific indent. + lines[i] = (i === 0 ? '' : '\n') + headingIndent + + o.group + ':'; + } + return; + } + + var helpDefault; + if (config.includeDefault) { + if (o.default !== undefined) { + helpDefault = format('Default: %j', o.default); + } else if (o.type && optionTypes[o.type].default !== undefined) { + helpDefault = format('Default: %j', + optionTypes[o.type].default); + } + } + + var line = lines[i] = indent + lines[i]; + if (!o.help && !(config.includeEnv && o.env) && !helpDefault) { + return; + } + var n = helpCol - line.length; + if (n >= 0) { + line += space(n); + } else { + line += '\n' + space(helpCol); + } + + var helpEnv = ''; + if (o.env && o.env.length && config.includeEnv) { + helpEnv += 'Environment: '; + var type = optionTypes[o.type]; + var arg = o.helpArg || type.helpArg || 'ARG'; + var envs = (Array.isArray(o.env) ? o.env : [o.env]).map( + function (e) { + if (type.takesArg) { + return e + '=' + arg; + } else { + return e + '=1'; + } + } + ); + helpEnv += envs.join(', '); + } + var help = (o.help || '').trim(); + if (o.helpWrap !== false && config.helpWrap !== false) { + // Wrap help description normally. + if (help.length && !~'.!?"\''.indexOf(help.slice(-1))) { + help += '.'; + } + if (help.length) { + help += ' '; + } + help += helpEnv; + if (helpDefault) { + if (helpEnv) { + help += '. '; + } + help += helpDefault; + } + line += textwrap(help, maxCol - helpCol).join( + '\n' + space(helpCol)); + } else { + // Do not wrap help description, but indent newlines appropriately. + var helpLines = help.split('\n').filter( + function (ln) { return ln.length }); + if (helpEnv !== '') { + helpLines.push(helpEnv); + } + if (helpDefault) { + helpLines.push(helpDefault); + } + line += helpLines.join('\n' + space(helpCol)); + } + + lines[i] = line; + }); + + var rv = ''; + if (lines.length > 0) { + rv = lines.join('\n') + '\n'; + } + return rv; +}; + + +/** + * Return a string suitable for a Bash completion file for this tool. + * + * @param args.name {String} The tool name. + * @param args.specExtra {String} Optional. Extra Bash code content to add + * to the end of the "spec". Typically this is used to append Bash + * "complete_TYPE" functions for custom option types. See + * "examples/ddcompletion.js" for an example. + * @param args.argtypes {Array} Optional. Array of completion types for + * positional args (i.e. non-options). E.g. + * argtypes = ['fruit', 'veggie', 'file'] + * will result in completion of fruits for the first arg, veggies for the + * second, and filenames for the third and subsequent positional args. + * If not given, positional args will use Bash's 'default' completion. + * See `specExtra` for providing Bash `complete_TYPE` functions, e.g. + * `complete_fruit` and `complete_veggie` in this example. + */ +Parser.prototype.bashCompletion = function bashCompletion(args) { + assert.object(args, 'args'); + assert.string(args.name, 'args.name'); + assert.optionalString(args.specExtra, 'args.specExtra'); + assert.optionalArrayOfString(args.argtypes, 'args.argtypes'); + + return bashCompletionFromOptions({ + name: args.name, + specExtra: args.specExtra, + argtypes: args.argtypes, + options: this.options + }); +}; + + +// ---- Bash completion + +const BASH_COMPLETION_TEMPLATE_PATH = path.join( + __dirname, '../etc/dashdash.bash_completion.in'); + +/** + * Return the Bash completion "spec" (the string value for the "{{spec}}" + * var in the "dashdash.bash_completion.in" template) for this tool. + * + * The "spec" is Bash code that defines the CLI options and subcmds for + * the template's completion code. It looks something like this: + * + * local cmd_shortopts="-J ..." + * local cmd_longopts="--help ..." + * local cmd_optargs="-p=tritonprofile ..." + * + * @param args.options {Array} The array of dashdash option specs. + * @param args.context {String} Optional. A context string for the "local cmd*" + * vars in the spec. By default it is the empty string. When used to + * scope for completion on a *sub-command* (e.g. for "git log" on a "git" + * tool), then it would have a value (e.g. "__log"). See + * <http://github.com/trentm/node-cmdln> Bash completion for details. + * @param opts.includeHidden {Boolean} Optional. Default false. By default + * hidden options and subcmds are "excluded". Here excluded means they + * won't be offered as a completion, but if used, their argument type + * will be completed. "Hidden" options and subcmds are ones with the + * `hidden: true` attribute to exclude them from default help output. + * @param args.argtypes {Array} Optional. Array of completion types for + * positional args (i.e. non-options). E.g. + * argtypes = ['fruit', 'veggie', 'file'] + * will result in completion of fruits for the first arg, veggies for the + * second, and filenames for the third and subsequent positional args. + * If not given, positional args will use Bash's 'default' completion. + * See `specExtra` for providing Bash `complete_TYPE` functions, e.g. + * `complete_fruit` and `complete_veggie` in this example. + */ +function bashCompletionSpecFromOptions(args) { + assert.object(args, 'args'); + assert.object(args.options, 'args.options'); + assert.optionalString(args.context, 'args.context'); + assert.optionalBool(args.includeHidden, 'args.includeHidden'); + assert.optionalArrayOfString(args.argtypes, 'args.argtypes'); + + var context = args.context || ''; + var includeHidden = (args.includeHidden === undefined + ? false : args.includeHidden); + + var spec = []; + var shortopts = []; + var longopts = []; + var optargs = []; + (args.options || []).forEach(function (o) { + if (o.group !== undefined && o.group !== null) { + // Skip group headers. + return; + } + + var optNames = o.names || [o.name]; + var optType = getOptionType(o.type); + if (optType.takesArg) { + var completionType = o.completionType || + optType.completionType || o.type; + optNames.forEach(function (optName) { + if (optName.length === 1) { + if (includeHidden || !o.hidden) { + shortopts.push('-' + optName); + } + // Include even hidden options in `optargs` so that bash + // completion of its arg still works. + optargs.push('-' + optName + '=' + completionType); + } else { + if (includeHidden || !o.hidden) { + longopts.push('--' + optName); + } + optargs.push('--' + optName + '=' + completionType); + } + }); + } else { + optNames.forEach(function (optName) { + if (includeHidden || !o.hidden) { + if (optName.length === 1) { + shortopts.push('-' + optName); + } else { + longopts.push('--' + optName); + } + } + }); + } + }); + + spec.push(format('local cmd%s_shortopts="%s"', + context, shortopts.sort().join(' '))); + spec.push(format('local cmd%s_longopts="%s"', + context, longopts.sort().join(' '))); + spec.push(format('local cmd%s_optargs="%s"', + context, optargs.sort().join(' '))); + if (args.argtypes) { + spec.push(format('local cmd%s_argtypes="%s"', + context, args.argtypes.join(' '))); + } + return spec.join('\n'); +} + + +/** + * Return a string suitable for a Bash completion file for this tool. + * + * @param args.name {String} The tool name. + * @param args.options {Array} The array of dashdash option specs. + * @param args.specExtra {String} Optional. Extra Bash code content to add + * to the end of the "spec". Typically this is used to append Bash + * "complete_TYPE" functions for custom option types. See + * "examples/ddcompletion.js" for an example. + * @param args.argtypes {Array} Optional. Array of completion types for + * positional args (i.e. non-options). E.g. + * argtypes = ['fruit', 'veggie', 'file'] + * will result in completion of fruits for the first arg, veggies for the + * second, and filenames for the third and subsequent positional args. + * If not given, positional args will use Bash's 'default' completion. + * See `specExtra` for providing Bash `complete_TYPE` functions, e.g. + * `complete_fruit` and `complete_veggie` in this example. + */ +function bashCompletionFromOptions(args) { + assert.object(args, 'args'); + assert.object(args.options, 'args.options'); + assert.string(args.name, 'args.name'); + assert.optionalString(args.specExtra, 'args.specExtra'); + assert.optionalArrayOfString(args.argtypes, 'args.argtypes'); + + // Gather template data. + var data = { + name: args.name, + date: new Date(), + spec: bashCompletionSpecFromOptions({ + options: args.options, + argtypes: args.argtypes + }), + }; + if (args.specExtra) { + data.spec += '\n\n' + args.specExtra; + } + + // Render template. + var template = fs.readFileSync(BASH_COMPLETION_TEMPLATE_PATH, 'utf8'); + return renderTemplate(template, data); +} + + + +// ---- exports + +function createParser(config) { + return new Parser(config); +} + +/** + * Parse argv with the given options. + * + * @param config {Object} A merge of all the available fields from + * `dashdash.Parser` and `dashdash.Parser.parse`: options, interspersed, + * argv, env, slice. + */ +function parse(config) { + assert.object(config, 'config'); + assert.optionalArrayOfString(config.argv, 'config.argv'); + assert.optionalObject(config.env, 'config.env'); + var config = shallowCopy(config); + var argv = config.argv; + delete config.argv; + var env = config.env; + delete config.env; + + var parser = new Parser(config); + return parser.parse({argv: argv, env: env}); +} + + +/** + * Add a new option type. + * + * @params optionType {Object}: + * - name {String} Required. + * - takesArg {Boolean} Required. Whether this type of option takes an + * argument on process.argv. Typically this is true for all but the + * "bool" type. + * - helpArg {String} Required iff `takesArg === true`. The string to + * show in generated help for options of this type. + * - parseArg {Function} Require. `function (option, optstr, arg)` parser + * that takes a string argument and returns an instance of the + * appropriate type, or throws an error if the arg is invalid. + * - array {Boolean} Optional. Set to true if this is an 'arrayOf' type + * that collects multiple usages of the option in process.argv and + * puts results in an array. + * - arrayFlatten {Boolean} Optional. XXX + * - default Optional. Default value for options of this type, if no + * default is specified in the option type usage. + */ +function addOptionType(optionType) { + assert.object(optionType, 'optionType'); + assert.string(optionType.name, 'optionType.name'); + assert.bool(optionType.takesArg, 'optionType.takesArg'); + if (optionType.takesArg) { + assert.string(optionType.helpArg, 'optionType.helpArg'); + } + assert.func(optionType.parseArg, 'optionType.parseArg'); + assert.optionalBool(optionType.array, 'optionType.array'); + assert.optionalBool(optionType.arrayFlatten, 'optionType.arrayFlatten'); + + optionTypes[optionType.name] = { + takesArg: optionType.takesArg, + helpArg: optionType.helpArg, + parseArg: optionType.parseArg, + array: optionType.array, + arrayFlatten: optionType.arrayFlatten, + default: optionType.default + } +} + + +function getOptionType(name) { + assert.string(name, 'name'); + return optionTypes[name]; +} + + +/** + * Return a synopsis string for the given option spec. + * + * Examples: + * > synopsisFromOpt({names: ['help', 'h'], type: 'bool'}); + * '[ --help | -h ]' + * > synopsisFromOpt({name: 'file', type: 'string', helpArg: 'FILE'}); + * '[ --file=FILE ]' + */ +function synopsisFromOpt(o) { + assert.object(o, 'o'); + + if (o.hasOwnProperty('group')) { + return null; + } + var names = o.names || [o.name]; + // `type` here could be undefined if, for example, the command has a + // dashdash option spec with a bogus 'type'. + var type = getOptionType(o.type); + var helpArg = o.helpArg || (type && type.helpArg) || 'ARG'; + var parts = []; + names.forEach(function (name) { + var part = (name.length === 1 ? '-' : '--') + name; + if (type && type.takesArg) { + part += (name.length === 1 ? ' ' + helpArg : '=' + helpArg); + } + parts.push(part); + }); + return ('[ ' + parts.join(' | ') + ' ]'); +}; + + +module.exports = { + createParser: createParser, + Parser: Parser, + parse: parse, + addOptionType: addOptionType, + getOptionType: getOptionType, + synopsisFromOpt: synopsisFromOpt, + + // Bash completion-related exports + BASH_COMPLETION_TEMPLATE_PATH: BASH_COMPLETION_TEMPLATE_PATH, + bashCompletionFromOptions: bashCompletionFromOptions, + bashCompletionSpecFromOptions: bashCompletionSpecFromOptions, + + // Export the parseFoo parsers because they might be useful as primitives + // for custom option types. + parseBool: parseBool, + parseString: parseString, + parseNumber: parseNumber, + parseInteger: parseInteger, + parsePositiveInteger: parsePositiveInteger, + parseDate: parseDate +}; diff --git a/node_modules/dashdash/package.json b/node_modules/dashdash/package.json new file mode 100644 index 0000000..a11e1f5 --- /dev/null +++ b/node_modules/dashdash/package.json @@ -0,0 +1,26 @@ +{ + "name": "dashdash", + "description": "A light, featureful and explicit option parsing library.", + "version": "1.14.1", + "author": "Trent Mick <trentm@gmail.com> (http://trentm.com)", + "keywords": ["option", "parser", "parsing", "cli", "command", "args", + "bash", "completion"], + "repository": { + "type": "git", + "url": "git://github.com/trentm/node-dashdash.git" + }, + "main": "./lib/dashdash.js", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "devDependencies": { + "nodeunit": "0.9.x" + }, + "engines": { + "node": ">=0.10" + }, + "scripts": { + "test": "nodeunit test/*.test.js" + }, + "license": "MIT" +} |