• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..21-May-2021-

etc/H21-May-2021-389226

lib/H03-May-2022-

CHANGES.mdH A D21-May-202110.7 KiB365238

README.mdH A D21-May-202117.7 KiB575446

package.jsonH A D21-May-2021703 2726

README.md

1A 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
4too loosey goosey (not explicit), too big/too many deps, or ill specified.
5YMMV.
6
7Follow <a href="https://twitter.com/intent/user?screen_name=trentmick" target="_blank">@trentmick</a>
8for updates to node-dashdash.
9
10# Install
11
12    npm install dashdash
13
14
15# Usage
16
17```javascript
18var dashdash = require('dashdash');
19
20// Specify the options. Minimally `name` (or `names`) and `type`
21// must be given for each.
22var 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.
34var opts = dashdash.parse({options: options});
35
36console.log("opts:", opts);
37console.log("args:", opts._args);
38```
39
40
41# Longer Example
42
43A more realistic [starter script "foo.js"](./examples/foo.js) is as follows.
44This also shows using `parser.help()` for formatted option help.
45
46```javascript
47var dashdash = require('./lib/dashdash');
48
49var 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
73var parser = dashdash.createParser({options: options});
74try {
75    var opts = parser.parse(process.argv);
76} catch (e) {
77    console.error('foo: error: %s', e.message);
78    process.exit(1);
79}
80
81console.log("# opts:", opts);
82console.log("# args:", opts._args);
83
84// Use `parser.help()` for formatted options help.
85if (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
97Some 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: []
105usage: node foo.js [OPTIONS]
106options:
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
143See the ["examples"](examples/) dir for a number of starter examples using
144some of dashdash's features.
145
146
147# Environment variable integration
148
149If you want to allow environment variables to specify options to your tool,
150dashdash makes this easy. We can change the 'verbose' option in the example
151above 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
162then the **"FOO_VERBOSE" environment variable** can be used to set this
163option:
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
173Boolean options will interpret the empty string as unset, '0' as false
174and 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
200Non-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
210Numbers:
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
220foo: error: arg for "FOO_TIMEOUT" is not a positive integer: "blarg"
221```
222
223With the `includeEnv: true` config to `parser.help()` the environment
224variable 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
237Dashdash provides a simple way to create a Bash completion file that you
238can 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
250Dashdash 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
255or directly from a `options` array of options specs:
256
257    var code = dashdash.bashCompletionFromOptions({
258        name: 'mycli',
259        options: OPTIONS
260    });
261
262Write that content to "/usr/local/etc/bash_completion.d/mycli" and you will
263have Bash completions for `mycli`. Alternatively you can write it to
264any file (e.g. "~/.bashrc") and source it.
265
266You could add a `--completion` hidden option to your tool that emits the
267completion content and document for your users to call that to install
268Bash completions.
269
270See [examples/ddcompletion.js](examples/ddcompletion.js) for a complete
271example, including how one can define bash functions for completion of custom
272option types. Also see [node-cmdln](https://github.com/trentm/node-cmdln) for
273how 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
283Parser construction (i.e. `dashdash.createParser(CONFIG)`) takes the
284following 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
328Example 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
343Each 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
419You can add headings between option specs in the `options` array.  To do so,
420simply add an object with only a `group` property -- the string to print as
421the heading for the subsequent options in the array.  For example:
422
423```javascript
424var 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
443Note: You can use an empty string, `{group: ''}`, to get a blank line in help
444output between groups of options.
445
446
447# Help config
448
449The `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
487Dashdash includes a good starter set of option types that it will parse for
488you. 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
504For example, a simple option type that accepts 'yes', 'y', 'no' or 'n' as
505a 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
534See "examples/custom-option-\*.js" for other examples.
535See the `addOptionType` block comment in "lib/dashdash.js" for more details.
536Please let me know [with an
537issue](https://github.com/trentm/node-dashdash/issues/new) if you write a
538generally useful one.
539
540
541
542# Why
543
544Why 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
574MIT. See LICENSE.txt.
575