twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

README.md (18164B)


      1 A light, featureful and explicit option parsing library for node.js.
      2 
      3 [Why another one? See below](#why). tl;dr: The others I've tried are one of
      4 too loosey goosey (not explicit), too big/too many deps, or ill specified.
      5 YMMV.
      6 
      7 Follow <a href="https://twitter.com/intent/user?screen_name=trentmick" target="_blank">@trentmick</a>
      8 for updates to node-dashdash.
      9 
     10 # Install
     11 
     12     npm install dashdash
     13 
     14 
     15 # Usage
     16 
     17 ```javascript
     18 var dashdash = require('dashdash');
     19 
     20 // Specify the options. Minimally `name` (or `names`) and `type`
     21 // must be given for each.
     22 var options = [
     23     {
     24         // `names` or a single `name`. First element is the `opts.KEY`.
     25         names: ['help', 'h'],
     26         // See "Option specs" below for types.
     27         type: 'bool',
     28         help: 'Print this help and exit.'
     29     }
     30 ];
     31 
     32 // Shortcut form. As called it infers `process.argv`. See below for
     33 // the longer form to use methods like `.help()` on the Parser object.
     34 var opts = dashdash.parse({options: options});
     35 
     36 console.log("opts:", opts);
     37 console.log("args:", opts._args);
     38 ```
     39 
     40 
     41 # Longer Example
     42 
     43 A more realistic [starter script "foo.js"](./examples/foo.js) is as follows.
     44 This also shows using `parser.help()` for formatted option help.
     45 
     46 ```javascript
     47 var dashdash = require('./lib/dashdash');
     48 
     49 var options = [
     50     {
     51         name: 'version',
     52         type: 'bool',
     53         help: 'Print tool version and exit.'
     54     },
     55     {
     56         names: ['help', 'h'],
     57         type: 'bool',
     58         help: 'Print this help and exit.'
     59     },
     60     {
     61         names: ['verbose', 'v'],
     62         type: 'arrayOfBool',
     63         help: 'Verbose output. Use multiple times for more verbose.'
     64     },
     65     {
     66         names: ['file', 'f'],
     67         type: 'string',
     68         help: 'File to process',
     69         helpArg: 'FILE'
     70     }
     71 ];
     72 
     73 var parser = dashdash.createParser({options: options});
     74 try {
     75     var opts = parser.parse(process.argv);
     76 } catch (e) {
     77     console.error('foo: error: %s', e.message);
     78     process.exit(1);
     79 }
     80 
     81 console.log("# opts:", opts);
     82 console.log("# args:", opts._args);
     83 
     84 // Use `parser.help()` for formatted options help.
     85 if (opts.help) {
     86     var help = parser.help({includeEnv: true}).trimRight();
     87     console.log('usage: node foo.js [OPTIONS]\n'
     88                 + 'options:\n'
     89                 + help);
     90     process.exit(0);
     91 }
     92 
     93 // ...
     94 ```
     95 
     96 
     97 Some example output from this script (foo.js):
     98 
     99 ```
    100 $ node foo.js -h
    101 # opts: { help: true,
    102   _order: [ { name: 'help', value: true, from: 'argv' } ],
    103   _args: [] }
    104 # args: []
    105 usage: node foo.js [OPTIONS]
    106 options:
    107     --version             Print tool version and exit.
    108     -h, --help            Print this help and exit.
    109     -v, --verbose         Verbose output. Use multiple times for more verbose.
    110     -f FILE, --file=FILE  File to process
    111 
    112 $ node foo.js -v
    113 # opts: { verbose: [ true ],
    114   _order: [ { name: 'verbose', value: true, from: 'argv' } ],
    115   _args: [] }
    116 # args: []
    117 
    118 $ node foo.js --version arg1
    119 # opts: { version: true,
    120   _order: [ { name: 'version', value: true, from: 'argv' } ],
    121   _args: [ 'arg1' ] }
    122 # args: [ 'arg1' ]
    123 
    124 $ node foo.js -f bar.txt
    125 # opts: { file: 'bar.txt',
    126   _order: [ { name: 'file', value: 'bar.txt', from: 'argv' } ],
    127   _args: [] }
    128 # args: []
    129 
    130 $ node foo.js -vvv --file=blah
    131 # opts: { verbose: [ true, true, true ],
    132   file: 'blah',
    133   _order:
    134    [ { name: 'verbose', value: true, from: 'argv' },
    135      { name: 'verbose', value: true, from: 'argv' },
    136      { name: 'verbose', value: true, from: 'argv' },
    137      { name: 'file', value: 'blah', from: 'argv' } ],
    138   _args: [] }
    139 # args: []
    140 ```
    141 
    142 
    143 See the ["examples"](examples/) dir for a number of starter examples using
    144 some of dashdash's features.
    145 
    146 
    147 # Environment variable integration
    148 
    149 If you want to allow environment variables to specify options to your tool,
    150 dashdash makes this easy. We can change the 'verbose' option in the example
    151 above to include an 'env' field:
    152 
    153 ```javascript
    154     {
    155         names: ['verbose', 'v'],
    156         type: 'arrayOfBool',
    157         env: 'FOO_VERBOSE',         // <--- add this line
    158         help: 'Verbose output. Use multiple times for more verbose.'
    159     },
    160 ```
    161 
    162 then the **"FOO_VERBOSE" environment variable** can be used to set this
    163 option:
    164 
    165 ```shell
    166 $ FOO_VERBOSE=1 node foo.js
    167 # opts: { verbose: [ true ],
    168   _order: [ { name: 'verbose', value: true, from: 'env' } ],
    169   _args: [] }
    170 # args: []
    171 ```
    172 
    173 Boolean options will interpret the empty string as unset, '0' as false
    174 and anything else as true.
    175 
    176 ```shell
    177 $ FOO_VERBOSE= node examples/foo.js                 # not set
    178 # opts: { _order: [], _args: [] }
    179 # args: []
    180 
    181 $ FOO_VERBOSE=0 node examples/foo.js                # '0' is false
    182 # opts: { verbose: [ false ],
    183   _order: [ { key: 'verbose', value: false, from: 'env' } ],
    184   _args: [] }
    185 # args: []
    186 
    187 $ FOO_VERBOSE=1 node examples/foo.js                # true
    188 # opts: { verbose: [ true ],
    189   _order: [ { key: 'verbose', value: true, from: 'env' } ],
    190   _args: [] }
    191 # args: []
    192 
    193 $ FOO_VERBOSE=boogabooga node examples/foo.js       # true
    194 # opts: { verbose: [ true ],
    195   _order: [ { key: 'verbose', value: true, from: 'env' } ],
    196   _args: [] }
    197 # args: []
    198 ```
    199 
    200 Non-booleans can be used as well. Strings:
    201 
    202 ```shell
    203 $ FOO_FILE=data.txt node examples/foo.js
    204 # opts: { file: 'data.txt',
    205   _order: [ { key: 'file', value: 'data.txt', from: 'env' } ],
    206   _args: [] }
    207 # args: []
    208 ```
    209 
    210 Numbers:
    211 
    212 ```shell
    213 $ FOO_TIMEOUT=5000 node examples/foo.js
    214 # opts: { timeout: 5000,
    215   _order: [ { key: 'timeout', value: 5000, from: 'env' } ],
    216   _args: [] }
    217 # args: []
    218 
    219 $ FOO_TIMEOUT=blarg node examples/foo.js
    220 foo: error: arg for "FOO_TIMEOUT" is not a positive integer: "blarg"
    221 ```
    222 
    223 With the `includeEnv: true` config to `parser.help()` the environment
    224 variable can also be included in **help output**:
    225 
    226     usage: node foo.js [OPTIONS]
    227     options:
    228         --version             Print tool version and exit.
    229         -h, --help            Print this help and exit.
    230         -v, --verbose         Verbose output. Use multiple times for more verbose.
    231                               Environment: FOO_VERBOSE=1
    232         -f FILE, --file=FILE  File to process
    233 
    234 
    235 # Bash completion
    236 
    237 Dashdash provides a simple way to create a Bash completion file that you
    238 can place in your "bash_completion.d" directory -- sometimes that is
    239 "/usr/local/etc/bash_completion.d/"). Features:
    240 
    241 - Support for short and long opts
    242 - Support for knowing which options take arguments
    243 - Support for subcommands (e.g. 'git log <TAB>' to show just options for the
    244   log subcommand). See
    245   [node-cmdln](https://github.com/trentm/node-cmdln#bash-completion) for
    246   how to integrate that.
    247 - Does the right thing with "--" to stop options.
    248 - Custom optarg and arg types for custom completions.
    249 
    250 Dashdash will return bash completion file content given a parser instance:
    251 
    252     var parser = dashdash.createParser({options: options});
    253     console.log( parser.bashCompletion({name: 'mycli'}) );
    254 
    255 or directly from a `options` array of options specs:
    256 
    257     var code = dashdash.bashCompletionFromOptions({
    258         name: 'mycli',
    259         options: OPTIONS
    260     });
    261 
    262 Write that content to "/usr/local/etc/bash_completion.d/mycli" and you will
    263 have Bash completions for `mycli`. Alternatively you can write it to
    264 any file (e.g. "~/.bashrc") and source it.
    265 
    266 You could add a `--completion` hidden option to your tool that emits the
    267 completion content and document for your users to call that to install
    268 Bash completions.
    269 
    270 See [examples/ddcompletion.js](examples/ddcompletion.js) for a complete
    271 example, including how one can define bash functions for completion of custom
    272 option types. Also see [node-cmdln](https://github.com/trentm/node-cmdln) for
    273 how it uses this for Bash completion for full multi-subcommand tools.
    274 
    275 - TODO: document specExtra
    276 - TODO: document includeHidden
    277 - TODO: document custom types, `function complete\_FOO` guide, completionType
    278 - TODO: document argtypes
    279 
    280 
    281 # Parser config
    282 
    283 Parser construction (i.e. `dashdash.createParser(CONFIG)`) takes the
    284 following fields:
    285 
    286 - `options` (Array of option specs). Required. See the
    287   [Option specs](#option-specs) section below.
    288 
    289 - `interspersed` (Boolean). Optional. Default is true. If true this allows
    290   interspersed arguments and options. I.e.:
    291 
    292         node ./tool.js -v arg1 arg2 -h   # '-h' is after interspersed args
    293 
    294   Set it to false to have '-h' **not** get parsed as an option in the above
    295   example.
    296 
    297 - `allowUnknown` (Boolean).  Optional.  Default is false.  If false, this causes
    298   unknown arguments to throw an error.  I.e.:
    299 
    300         node ./tool.js -v arg1 --afe8asefksjefhas
    301 
    302   Set it to true to treat the unknown option as a positional
    303   argument.
    304 
    305   **Caveat**: When a shortopt group, such as `-xaz` contains a mix of
    306   known and unknown options, the *entire* group is passed through
    307   unmolested as a positional argument.
    308 
    309   Consider if you have a known short option `-a`, and parse the
    310   following command line:
    311 
    312         node ./tool.js -xaz
    313 
    314   where `-x` and `-z` are unknown.  There are multiple ways to
    315   interpret this:
    316 
    317     1. `-x` takes a value: `{x: 'az'}`
    318     2. `-x` and `-z` are both booleans: `{x:true,a:true,z:true}`
    319 
    320   Since dashdash does not know what `-x` and `-z` are, it can't know
    321   if you'd prefer to receive `{a:true,_args:['-x','-z']}` or
    322   `{x:'az'}`, or `{_args:['-xaz']}`. Leaving the positional arg unprocessed
    323   is the easiest mistake for the user to recover from.
    324 
    325 
    326 # Option specs
    327 
    328 Example using all fields (required fields are noted):
    329 
    330 ```javascript
    331 {
    332     names: ['file', 'f'],       // Required (one of `names` or `name`).
    333     type: 'string',             // Required.
    334     completionType: 'filename',
    335     env: 'MYTOOL_FILE',
    336     help: 'Config file to load before running "mytool"',
    337     helpArg: 'PATH',
    338     helpWrap: false,
    339     default: path.resolve(process.env.HOME, '.mytoolrc')
    340 }
    341 ```
    342 
    343 Each option spec in the `options` array must/can have the following fields:
    344 
    345 - `name` (String) or `names` (Array). Required. These give the option name
    346   and aliases. The first name (if more than one given) is the key for the
    347   parsed `opts` object.
    348 
    349 - `type` (String). Required. One of:
    350 
    351     - bool
    352     - string
    353     - number
    354     - integer
    355     - positiveInteger
    356     - date (epoch seconds, e.g. 1396031701, or ISO 8601 format
    357       `YYYY-MM-DD[THH:MM:SS[.sss][Z]]`, e.g. "2014-03-28T18:35:01.489Z")
    358     - arrayOfBool
    359     - arrayOfString
    360     - arrayOfNumber
    361     - arrayOfInteger
    362     - arrayOfPositiveInteger
    363     - arrayOfDate
    364 
    365   FWIW, these names attempt to match with asserts on
    366   [assert-plus](https://github.com/mcavage/node-assert-plus).
    367   You can add your own custom option types with `dashdash.addOptionType`.
    368   See below.
    369 
    370 - `completionType` (String). Optional. This is used for [Bash
    371   completion](#bash-completion) for an option argument. If not specified,
    372   then the value of `type` is used. Any string may be specified, but only the
    373   following values have meaning:
    374 
    375     - `none`: Provide no completions.
    376     - `file`: Bash's default completion (i.e. `complete -o default`), which
    377       includes filenames.
    378     - *Any string FOO for which a `function complete_FOO` Bash function is
    379       defined.* This is for custom completions for a given tool. Typically
    380       these custom functions are provided in the `specExtra` argument to
    381       `dashdash.bashCompletionFromOptions()`. See
    382       ["examples/ddcompletion.js"](examples/ddcompletion.js) for an example.
    383 
    384 - `env` (String or Array of String). Optional. An environment variable name
    385   (or names) that can be used as a fallback for this option. For example,
    386   given a "foo.js" like this:
    387 
    388         var options = [{names: ['dry-run', 'n'], env: 'FOO_DRY_RUN'}];
    389         var opts = dashdash.parse({options: options});
    390 
    391   Both `node foo.js --dry-run` and `FOO_DRY_RUN=1 node foo.js` would result
    392   in `opts.dry_run = true`.
    393 
    394   An environment variable is only used as a fallback, i.e. it is ignored if
    395   the associated option is given in `argv`.
    396 
    397 - `help` (String). Optional. Used for `parser.help()` output.
    398 
    399 - `helpArg` (String). Optional. Used in help output as the placeholder for
    400   the option argument, e.g. the "PATH" in:
    401 
    402         ...
    403         -f PATH, --file=PATH    File to process
    404         ...
    405 
    406 - `helpWrap` (Boolean). Optional, default true. Set this to `false` to have
    407   that option's `help` *not* be text wrapped in `<parser>.help()` output.
    408 
    409 - `default`. Optional. A default value used for this option, if the
    410   option isn't specified in argv.
    411 
    412 - `hidden` (Boolean). Optional, default false. If true, help output will not
    413   include this option. See also the `includeHidden` option to
    414   `bashCompletionFromOptions()` for [Bash completion](#bash-completion).
    415 
    416 
    417 # Option group headings
    418 
    419 You can add headings between option specs in the `options` array.  To do so,
    420 simply add an object with only a `group` property -- the string to print as
    421 the heading for the subsequent options in the array.  For example:
    422 
    423 ```javascript
    424 var options = [
    425     {
    426         group: 'Armament Options'
    427     },
    428     {
    429         names: [ 'weapon', 'w' ],
    430         type: 'string'
    431     },
    432     {
    433         group: 'General Options'
    434     },
    435     {
    436         names: [ 'help', 'h' ],
    437         type: 'bool'
    438     }
    439 ];
    440 ...
    441 ```
    442 
    443 Note: You can use an empty string, `{group: ''}`, to get a blank line in help
    444 output between groups of options.
    445 
    446 
    447 # Help config
    448 
    449 The `parser.help(...)` function is configurable as follows:
    450 
    451         Options:
    452           Armament Options:
    453         ^^  -w WEAPON, --weapon=WEAPON  Weapon with which to crush. One of: |
    454        /                                sword, spear, maul                  |
    455       /   General Options:                                                  |
    456      /      -h, --help                  Print this help and exit.           |
    457     /   ^^^^                            ^                                   |
    458     \       `-- indent                   `-- helpCol              maxCol ---'
    459      `-- headingIndent
    460 
    461 - `indent` (Number or String). Default 4. Set to a number (for that many
    462   spaces) or a string for the literal indent.
    463 - `headingIndent` (Number or String). Default half length of `indent`. Set to
    464   a number (for that many spaces) or a string for the literal indent. This
    465   indent applies to group heading lines, between normal option lines.
    466 - `nameSort` (String). Default is 'length'. By default the names are
    467   sorted to put the short opts first (i.e. '-h, --help' preferred
    468   to '--help, -h'). Set to 'none' to not do this sorting.
    469 - `maxCol` (Number). Default 80. Note that reflow is just done on whitespace
    470   so a long token in the option help can overflow maxCol.
    471 - `helpCol` (Number). If not set a reasonable value will be determined
    472   between `minHelpCol` and `maxHelpCol`.
    473 - `minHelpCol` (Number). Default 20.
    474 - `maxHelpCol` (Number). Default 40.
    475 - `helpWrap` (Boolean). Default true. Set to `false` to have option `help`
    476   strings *not* be textwrapped to the helpCol..maxCol range.
    477 - `includeEnv` (Boolean). Default false. If the option has associated
    478   environment variables (via the `env` option spec attribute), then
    479   append mentioned of those envvars to the help string.
    480 - `includeDefault` (Boolean). Default false. If the option has a default value
    481   (via the `default` option spec attribute, or a default on the option's type),
    482   then a "Default: VALUE" string will be appended to the help string.
    483 
    484 
    485 # Custom option types
    486 
    487 Dashdash includes a good starter set of option types that it will parse for
    488 you. However, you can add your own via:
    489 
    490     var dashdash = require('dashdash');
    491     dashdash.addOptionType({
    492         name: '...',
    493         takesArg: true,
    494         helpArg: '...',
    495         parseArg: function (option, optstr, arg) {
    496             ...
    497         },
    498         array: false,  // optional
    499         arrayFlatten: false,  // optional
    500         default: ...,   // optional
    501         completionType: ...  // optional
    502     });
    503 
    504 For example, a simple option type that accepts 'yes', 'y', 'no' or 'n' as
    505 a boolean argument would look like:
    506 
    507     var dashdash = require('dashdash');
    508 
    509     function parseYesNo(option, optstr, arg) {
    510         var argLower = arg.toLowerCase()
    511         if (~['yes', 'y'].indexOf(argLower)) {
    512             return true;
    513         } else if (~['no', 'n'].indexOf(argLower)) {
    514             return false;
    515         } else {
    516             throw new Error(format(
    517                 'arg for "%s" is not "yes" or "no": "%s"',
    518                 optstr, arg));
    519         }
    520     }
    521 
    522     dashdash.addOptionType({
    523         name: 'yesno'
    524         takesArg: true,
    525         helpArg: '<yes|no>',
    526         parseArg: parseYesNo
    527     });
    528 
    529     var options = {
    530         {names: ['answer', 'a'], type: 'yesno'}
    531     };
    532     var opts = dashdash.parse({options: options});
    533 
    534 See "examples/custom-option-\*.js" for other examples.
    535 See the `addOptionType` block comment in "lib/dashdash.js" for more details.
    536 Please let me know [with an
    537 issue](https://github.com/trentm/node-dashdash/issues/new) if you write a
    538 generally useful one.
    539 
    540 
    541 
    542 # Why
    543 
    544 Why another node.js option parsing lib?
    545 
    546 - `nopt` really is just for "tools like npm". Implicit opts (e.g. '--no-foo'
    547   works for every '--foo'). Can't disable abbreviated opts. Can't do multiple
    548   usages of same opt, e.g. '-vvv' (I think). Can't do grouped short opts.
    549 
    550 - `optimist` has surprise interpretation of options (at least to me).
    551   Implicit opts mean ambiguities and poor error handling for fat-fingering.
    552   `process.exit` calls makes it hard to use as a libary.
    553 
    554 - `optparse` Incomplete docs. Is this an attempted clone of Python's `optparse`.
    555   Not clear. Some divergence. `parser.on("name", ...)` API is weird.
    556 
    557 - `argparse` Dep on underscore. No thanks just for option processing.
    558   `find lib | wc -l` -> `26`. Overkill.
    559   Argparse is a bit different anyway. Not sure I want that.
    560 
    561 - `posix-getopt` No type validation. Though that isn't a killer. AFAIK can't
    562   have a long opt without a short alias. I.e. no `getopt_long` semantics.
    563   Also, no whizbang features like generated help output.
    564 
    565 - ["commander.js"](https://github.com/visionmedia/commander.js): I wrote
    566   [a critique](http://trentm.com/2014/01/a-critique-of-commander-for-nodejs.html)
    567   a while back. It seems fine, but last I checked had
    568   [an outstanding bug](https://github.com/visionmedia/commander.js/pull/121)
    569   that would prevent me from using it.
    570 
    571 
    572 # License
    573 
    574 MIT. See LICENSE.txt.