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.