├── .npmignore ├── .travis.yml ├── CHANGES ├── LICENSE ├── README.md ├── examples ├── abbreviations.js ├── aliases.js ├── arguments.js ├── commands.js ├── custom-usages.js ├── events.js ├── fully-descriptive-help.js ├── help-usage-version.js ├── internal-data.js ├── mkdir.js ├── modifying-builtin-options.js ├── no-configuration.js ├── npm │ ├── config.js │ ├── install.js │ ├── npm.js │ └── whoami.js ├── options.js ├── read-package.js └── to-upper-case.js ├── lib ├── argp.js ├── body.js ├── command.js ├── index.js └── wrap.js ├── package.json └── test └── index.js /.npmignore: -------------------------------------------------------------------------------- 1 | CHANGES 2 | examples 3 | test 4 | .npmignore 5 | .travis.yml -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.11" 4 | - "0.10" -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | v1.0.4 (31 Mar 2014) 2 | Fixed "text()" function with an empty string. 3 | 4 | v1.0.3 (19 Feb 2014) 5 | Bump version. 6 | 7 | v1.0.2 (17 Feb 2014) 8 | Added an "options" paramter to "readPackage()". The email, description and 9 | version found in the package.json can be ignored individually. 10 | 11 | v1.0.1 (21 Dec 2013) 12 | "printHelp()", "printUsage()" and "printVersion()" now exits correctly by 13 | default with code 0. 14 | When "argv()" is called with an input array, "printHelp()", "printUsage()" and 15 | "printVersion()" don't terminate the process. 16 | 17 | v1.0.0 (02 Dec 2013) 18 | Added support for multiple parsers. Now the parser is created using 19 | "createParser()". 20 | In previous versions, passing an array to "argv()" didn't uncache the module 21 | in order to reuse the parser. Now if you don't need to reuse it, pass an 22 | object { once: true } to "createParser()". 23 | Added an "error" event. 24 | Added "footer()". Now you can write text between the --version and email text 25 | lines when using the "readPackage()" function. 26 | When "argv()" was called with an input array from inside a Body or Command 27 | instance, the input array was not read. 28 | Removed the second parameter from the "end" event. Now the functions 29 | "printHelp()", "printUsage()" and "printVersion()" are accessible from the 30 | Argp instance. 31 | Minor bugfixes and improvements. 32 | 33 | v0.2.1 (25 Nov 2013) 34 | The "fail()" function from the "end" event now prints the string message 35 | correctly. 36 | 37 | v0.2.0 (25 Nov 2013) 38 | The "end" event now receives a second parameter with an object with the 39 | previous functions "printHelp()", "printUsage()", "printVersion()" and 40 | "fail()". 41 | Improved README. 42 | Added Travis integration. 43 | Some bugfixes. 44 | 45 | v0.1.3 (25 Oct 2013) 46 | Added a fifth parameter ("fail") to the "end" event. 47 | Minor improvements and bugfixes. 48 | 49 | v0.1.2 (04 Oct 2013) 50 | Minor speed improvements and bugfixes. 51 | 52 | v0.1.1 (30 Sep 2013) 53 | An array with options can be passed to "argv()". 54 | 55 | v0.1.0 (29 Sep 2013) 56 | Bump version. 57 | 58 | v0.0.16 (28 Sep 2013) 59 | Added a new parameter to "help()" and "version()" to disable the short option. 60 | Added "exitStatus()". 61 | 62 | v0.0.15 (27 Sep 2013) 63 | Renamed "help" to "synopsis", property of "argument()". 64 | Renamed "argument" to "metavar", property of "option()". 65 | Minor improvements. 66 | 67 | v0.0.14 (26 Sep 2013) 68 | Added "command()", "main()" and "argv()" to the Body instance. 69 | Removed "end()". 70 | 71 | v0.0.13 (26 Sep 2013) 72 | Removed "line()", "paragraph()", "group()". 73 | Added "text()". 74 | 75 | v0.0.12 (26 Sep 2013) 76 | Minor bugfixes. 77 | 78 | v0.0.11 (25 Sep 2013) 79 | Added commands ("trailing" and "help" properties to "argument()"). 80 | The "end" event now receives 3 new parameters: "printHelp()", "printUsage()" 81 | and "printVersion()". 82 | Removed "_debug" and "_filename" properties from the final object. 83 | Minor improvements. 84 | 85 | v0.0.10 (23 Sep 2013) 86 | The default value of an option is now set with "default" instead of "value". 87 | Code inside the "end" event was preventing the parser from being gc'ed. 88 | Allowed negated flags with a short name. 89 | Added aliases. 90 | Added choices. 91 | Improved --usage message. 92 | Minor improvements. 93 | 94 | v0.0.9 (20 Sep 2013) 95 | Added "columns()". 96 | Minor bugfixes. 97 | 98 | v0.0.8 (19 Sep 2013) 99 | Fixed "readPackage()" with a missing default file. 100 | Added "prefix" parameter to the "text()" function. 101 | "usages()" now replaces the whole "usage" string. 102 | Added "line()" function. It differs from "text()" in that it isn't a new 103 | paragraph. 104 | Renamed "text()" to "paragraph()". 105 | Added "filter" parameter to "options()". 106 | Minor improvements. 107 | 108 | v0.0.7 (18 Sep 2013) 109 | The api has been refactored to be more fluent. 110 | Some bugfixes. 111 | 112 | v0.0.6 (16 Sep 2013) 113 | Options with a negative Number value are parsed correctly. 114 | The "argument()" function has been moved from the Argp to the Body and now 115 | accepts a second configuration parameter. 116 | 117 | v0.0.5 (15 Sep 2013) 118 | Added a "type" setting to the option configuration. 119 | 120 | v0.0.4 (15 Sep 2013) 121 | Added "footer()". 122 | The "fail()" function now prints the "try" message. 123 | 124 | v0.0.3 (15 Sep 2013) 125 | An 80 columns length was hardcoded. 126 | 127 | v0.0.2 (14 Sep 2013) 128 | Added automatic string conversion. 129 | Added "hidden" option configuration. 130 | When the input is parsed the first time "argv()" frees any resource; only 131 | the final object is needed. 132 | Minor bugfixes. 133 | 134 | v0.0.1 (13 Sep 2013) 135 | First release. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Gabriel Llamas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | argp 2 | ==== 3 | 4 | #### Command-line option parser #### 5 | 6 | [![NPM version](https://badge.fury.io/js/argp.png)](http://badge.fury.io/js/argp "Fury Version Badge") 7 | [![Build Status](https://secure.travis-ci.org/gagle/node-argp.png)](http://travis-ci.org/gagle/node-argp "Travis CI Badge") 8 | 9 | [![NPM installation](https://nodei.co/npm/argp.png?mini=true)](https://nodei.co/npm/argp "NodeICO Badge") 10 | 11 | Inspired by the extremly well-known [argp C library](http://www.gnu.org/software/libc/manual/html_node/Argp.html), this module parses GNU-style command-line options. Help, usage and version messages are automatically generated and line-wrapped at 80 columns. The module checks for errors, can be easily adapted to your needs thanks to its evented system and it also works when Node.js is in debug mode. The module is uncached and each property is deleted once all the input parameters have been parsed, so there's no memory footprint. 12 | 13 | This module it's made for you if you want: 14 | 15 | - Robust solution that reads GNU-style options. 16 | - Command configuration. 17 | - Basic error checking. 18 | - Nice help messages without caring about indentation, multilines, etc. 19 | - Zero memory footprint. 20 | 21 | A common configuration looks like this: 22 | 23 | ```javascript 24 | //If you're not going to use multiple parser instances or you don't need to 25 | //reuse a parser, don't cache the module, this will guarantee a zero memory 26 | //footprint 27 | var argv = require ("argp").createParser ({ once: true }) 28 | .description ("Sample app.") 29 | .email ("a@b.c") 30 | .body () 31 | //The object and argument definitions and the text of the --help message 32 | //are configured at the same time 33 | .text (" Arguments:") 34 | .argument ("arg", { description: "Sample argument" }) 35 | .text ("\n Options:") 36 | .option ({ short: "o", long: "opt", description: "Sample option" }) 37 | .help () 38 | .version ("v1.2.3") 39 | .argv (); 40 | 41 | console.log (argv); 42 | 43 | /* 44 | $ node script.js 45 | 46 | { 47 | opt: false, 48 | help: false, 49 | version: false, 50 | arg: false 51 | } 52 | 53 | $ node script.js --help 54 | 55 | Usage: script [options] [arguments] 56 | 57 | Sample app. 58 | 59 | Arguments: 60 | arg Sample argument 61 | 62 | Options: 63 | -o, --opt Sample option 64 | -h, --help Display this help message and exit 65 | -v, --version Output version information and exit 66 | 67 | Report bugs to . 68 | */ 69 | ``` 70 | 71 | If you have a `package.json` file you can take from it the description, email and version using the `readPackage()` function. Take into account that this function calls a synchronous `fs` operation. Doesn't really matter because this module is one of the first things you're going to execute in your program. 72 | 73 | ```javascript 74 | var argv = require ("argp") 75 | //If no path is provided, it tries to read the "./package.json" file 76 | .readPackage ("path/to/package.json") 77 | .body () 78 | .text (" Arguments:") 79 | .argument ("arg", { description: "Sample argument" }) 80 | .text ("\n Options:") 81 | .option ({ short: "o", long: "opt", description: "Sample option" }) 82 | .help () 83 | .argv (); 84 | ``` 85 | 86 | #### Documentation #### 87 | 88 | - [What's new in v1?](#new) 89 | - [Quick examples with no configuration](#quick) 90 | - [Configuring options](#options) 91 | - [Configuring arguments](#arguments) 92 | - [Configuring commands](#commands) 93 | - [Real examples](#examples) 94 | 95 | #### Functions #### 96 | 97 | - [_module_.createParser([options]) : Argp](#createparser) 98 | 99 | #### Objects #### 100 | 101 | - [Argp](#argp_object) 102 | 103 | --- 104 | 105 | 106 | __What's new in v1?__ 107 | 108 | Two things will break your code: 109 | 110 | - Parser instances are introduced. To create one you need to call to [createParser()](#createparser). 111 | In most cases you only need to append `.createParser ({ once: true })`, for example: 112 | 113 | ```javascript 114 | var argv = require ("argp").createParser ({ once: true }) 115 | ... 116 | argv (); 117 | ``` 118 | 119 | The `once` option will uncache the module when [argv()](#argp_argv) is called. 120 | 121 | - The second argument from the [end](#event_end) event is removed. 122 | 123 | Before: 124 | 125 | ```javascript 126 | .on ("end", function (argv, fns){ 127 | /* 128 | fns.printHelp (); 129 | fns.printUsage (); 130 | fns.printVersion (); 131 | fns.fail (); 132 | */ 133 | }) 134 | ``` 135 | 136 | After: 137 | 138 | ```javascript 139 | .on ("end", function (argv){ 140 | /* 141 | this.printHelp (); 142 | this.printUsage (); 143 | this.printVersion (); 144 | this.fail (); 145 | */ 146 | }) 147 | ``` 148 | 149 | --- 150 | 151 | 152 | __Quick examples with no configuration__ 153 | 154 | If an option has not been defined the type of the value is converted automatically from a string to a number, boolean, null or undefined. 155 | 156 | By default the parser doesn't allow undefined arguments and options because you typically want to have an absolute control over the calls to your program in order to avoid unexpected behaviours. Allowing undefined arguments and options is as simple as this: 157 | 158 | ```javascript 159 | var argv = require ("argp").createParser ({ once: true }) 160 | .allowUndefinedArguments () 161 | .allowUndefinedOptions () 162 | .argv (); 163 | ``` 164 | 165 | ```bash 166 | $ node script.js -a -b -c 167 | { a: true, b: true, c: true } 168 | 169 | $ node script.js a b c 170 | { a: true, b: true, c: true } 171 | 172 | $ node script.js -abc null 173 | { a: true, b: true, c: null } 174 | 175 | $ node script.js --a --b 1 --d=e 176 | { a: true, b: 1, d: "e" } 177 | 178 | $ node script.js --no-a b 179 | { a: false, b: true } 180 | 181 | $ node script.js --a -- -b --c d 182 | { a: true, "-b": true, "--c": true, d: true } 183 | ``` 184 | 185 | --- 186 | 187 | 188 | __Configuring options__ 189 | 190 | Example: [options.js](https://github.com/gagle/node-argp/blob/master/examples/options.js). 191 | 192 | Considerations: 193 | 194 | 1. By default the options are flags. If the option requires a value, the `metavar` property must be defined. This property is a string and can be seen when the --help and --usage messages are printed. 195 | 196 | ```bash 197 | $ node script.js --help 198 | ... 199 | o, --opt=STR Sample option 200 | ... 201 | ``` 202 | 203 | Where `STR` is the `metavar` property. 204 | 205 | 2. By default, the value of the options is a string. Configure the `type` property if the value is a number, boolean (rarely used, use a flag instead) or array (comma-separated values and multiple assignments). 206 | 3. Each option has an id which is used to store the value in the final object. This id is the long name. If the long name has not been defined then the id is the short name. 207 | 208 | ```javascript 209 | .option ({ short: "a", long: "aa" }) 210 | //{ aa: false } 211 | .option ({ long: "aa" }) 212 | //{ aa: false } 213 | .option ({ short: "a" }) 214 | //{ a: false } 215 | ``` 216 | 4. Mandatory options (aka `required`) are not implemented because options are _optional_. Use a [command](#commands) if you need mandatory parameters. 217 | 218 | Common properties between flags and options with a value: 219 | 220 | - __description__ - _String_ 221 | The description. 222 | - __hidden__ - _Boolean_ 223 | If true, the option is not displayed in the --help and --usage messages. Default is false. 224 | - __long__ - _String_ 225 | The long name. Cannot contain white spaces. 226 | - __short__ - _String_ 227 | The short name. It must be an alphanumeric character. 228 | 229 | Flags: 230 | 231 | - __negate__ - _Boolean_ 232 | If true, the flag is negated. The default value is true and it becomes false when the short name or the negated long name (eg. --no-flag) is present. 233 | 234 | ```javascript 235 | .option ({ short: "a", long: "aaa" }) 236 | .option ({ short: "b", long: "bbb", negate: true }) 237 | ``` 238 | ```bash 239 | $ node script.js 240 | { aaa: false, bbb: true } 241 | 242 | $ node script.js -a -b 243 | { aaa: true, bbb: false } 244 | 245 | $ node script.js --aaa --bbb 246 | { aaa: true, bbb: true } 247 | 248 | $ node script.js --no-aaa --no-bbb 249 | { aaa: false, bbb: false } 250 | ``` 251 | 252 | Options with a value: 253 | 254 | - __aliases__ - _Array_ 255 | An alias it's a long-name option that points to another option. 256 | 257 | ```javascript 258 | .body () 259 | .option ({ long: "name", aliases: ["foo", "bar"] }) 260 | .help () 261 | .usage () 262 | ``` 263 | ```bash 264 | $ node script.js --foo 265 | { name: true } 266 | 267 | $ node script.js --usage 268 | Usage: script [--name|--foo|--bar] [-h|--help] [--usage] 269 | 270 | $ node script.js --help 271 | Usage: script [options] 272 | 273 | --name, --foo, --bar 274 | -h, --help Display this help message and exit 275 | --usage Display a short usage message and exit 276 | ``` 277 | 278 | The `options()` function returns an object with all the configured options: 279 | 280 | ```javascript 281 | { 282 | name: { ... }, 283 | foo: { ... }, 284 | bar: { ... }, 285 | help: { ... }, 286 | usage: { ... } 287 | } 288 | ``` 289 | Where `name`, `foo` and `bar` point to the same object: 290 | 291 | ```javascript 292 | .on ("start", function (){ 293 | var options = this.options (); 294 | assert.ok (options.name === options.foo && options.name === options.bar); 295 | }) 296 | ``` 297 | - __choices__ - _Array_ 298 | The input value must be one of these choices. If the option is `optional`, the `choices` property is ignored. 299 | 300 | ```javascript 301 | .option ({ long: "opt", metavar: "NUM", type: Number, choices: [1, 2, 3] }) 302 | ``` 303 | ```bash 304 | $ node script.js --opt=1 305 | { opt: 1 } 306 | 307 | $ node script.js --opt=7 # Error! 308 | ``` 309 | 310 | When `default` and `choices` are defined in the same option the default value doesn't need to match any choice: 311 | 312 | ```javascript 313 | .option ({ long: "opt", metavar: "STR", default: "d", choices: ["a", "b", "c"] }) 314 | ``` 315 | ```bash 316 | $ node script.js 317 | { opt: "d" } 318 | ``` 319 | - __default__ - _Object_ 320 | The default value. 321 | 322 | ```javascript 323 | .option ({ long: "name", metavar: "STR", default: "bar", optional: true }) 324 | ``` 325 | ```bash 326 | $ node script.js 327 | { name: "bar" } 328 | 329 | $ node script.js --name 330 | { name: "bar" } 331 | 332 | $ node script.js --name foo 333 | { name: "foo" } 334 | ``` 335 | - __metavar__ - _String_ 336 | Must be defined if the option requires a value. If `metavar` is not defined, the option is a flag. The string is used when the --help and --usage messages are printed. 337 | 338 | ```javascript 339 | .option ({ long: "name", metavar: "STR" }) 340 | ``` 341 | ```bash 342 | $ node script.js --help 343 | ... 344 | --name=STR 345 | ... 346 | ``` 347 | - __optional__ - _Boolean_ 348 | If true, the value is optional. Default is false. If the option doesn't receive any value the default value is set and it depends on the `default` and `type` properties. 349 | 350 | Types and default values: 351 | - String: `null` 352 | - Number: `0` 353 | - Array: `[]` 354 | - Boolean: `false` 355 | 356 | ```javascript 357 | .option ({ long: "name1", metavar: "STR", optional: true }) 358 | .option ({ long: "name2", metavar: "STR", optional: true, type: String }) 359 | .option ({ long: "name3", metavar: "NUM", optional: true, type: Number }) 360 | .option ({ long: "name4", metavar: "ARR", optional: true, type: Array }) 361 | //Boolean type is rarely used, use a flag instead 362 | .option ({ long: "name5", metavar: "BOOL", optional: true, type: Boolean }) 363 | ``` 364 | ```bash 365 | $ node script.js --name1 --name2 --name3 --name4 --name5 366 | { name1: null, name2: null, name3: 0, name4: [], name5: false } 367 | ``` 368 | ```bash 369 | $ node script.js --name1 foo --name2 bar --name3 12 --name4 -12.34,foo,true --name4 false --name5 true 370 | { name1: "foo", ame2: "bar", name3: 12, name4: [-12.34, "foo", true, false], name5: true } 371 | ``` 372 | - __reviver__ - _Function_ 373 | The function is executed when the option is parsed. It is similar to the reviver parameter of the `JSON.parse()` function. This is the right place where you can validate the input data and `fail()` if it's not valid. For example, if the option requires a number you can validate the range here. 374 | 375 | ```javascript 376 | .option ({ long: "name", metavar: "STR", reviver: function (value){ 377 | return value + "bar"; 378 | }}) 379 | ``` 380 | ```bash 381 | $ node script.js --name foo 382 | { name: "foobar" } 383 | ``` 384 | ```javascript 385 | .option ({ long: "opt", metavar: "NUM", type: Number, 386 | reviver: function (value){ 387 | //The "value" parameter is already a number 388 | if (value < 1 || value > 3){ 389 | this.fail ("Option 'opt': Invalid range."); 390 | } 391 | return value; 392 | }}) 393 | ``` 394 | - __type__ - _String | Number | Boolean | Array_ 395 | The type of the value. Default is String. 396 | 397 | If the type is an Array, comma-separated values are automatically stored in an array and each element is converted to the type it represents. Multiple assignments are also supported. 398 | 399 | ```javascript 400 | .option ({ long: "name", metavar: "ARR", type: Array }) 401 | ``` 402 | ```bash 403 | $ node script.js --name 1,true,foo 404 | { name: [1, true, "foo"] } 405 | 406 | $ node script.js --name 1 --name true --name foo 407 | { name: [1, true, "foo"] } 408 | 409 | $ node script.js --name 1,2 --name true,false --name foo,bar 410 | { name: [1, 2, true, false, "foo", "bar"] } 411 | ``` 412 | 413 | --- 414 | 415 | 416 | __Configuring arguments__ 417 | 418 | Example: [arguments.js](https://github.com/gagle/node-argp/blob/master/examples/arguments.js). 419 | 420 | An argument is an individual name like `login`, `reset`, `build`, etc. They are basically flags. 421 | 422 | Properties: 423 | 424 | - __description__ - _String_ 425 | The description. 426 | - __hidden__ - _Boolean_ 427 | If true, the option is not displayed in the --help and --usage messages. Default is false. 428 | 429 | Note: `synopsis` and `trailing` properties can be also configured but they have meaning only with [commands](#commands). 430 | 431 | ```javascript 432 | .argument ("arg1") 433 | .argument ("arg2", { description: "foo" }) 434 | .argument ("arg3", { description: "bar", hidden: true }) 435 | ``` 436 | ```bash 437 | $ node script.js arg1 438 | { arg1: true, arg2: false, arg3: false } 439 | 440 | $ node script.js --help 441 | ... 442 | arg1 foo 443 | arg2 bar 444 | ... 445 | ``` 446 | 447 | Note that an argument is just a flag but it can be present without any prefixed hyphen. It is a flag with more weight, it is used to denote important actions. 448 | 449 | As you can see, the arguments are also stored in a hash like regular options, undefined arguments inclusive. For example: 450 | 451 | ```javascript 452 | var argv = require ("argp").createParser ({ once: true }) 453 | .allowUndefinedArguments () 454 | .allowUndefinedOptions () 455 | .argv (); 456 | 457 | console.log (argv); 458 | ``` 459 | 460 | ```bash 461 | $ node script.js a b c 462 | { a: true, b: true, c: true } 463 | ``` 464 | 465 | This feature is different from other cli parsers that store the arguments in an array. If you need to read undefined arguments and save them in an array you can use the events. For more details: [to-upper-case.js](https://github.com/gagle/node-argp/blob/master/examples/to-upper-case.js) 466 | 467 | --- 468 | 469 | 470 | __Configuring commands__ 471 | 472 | A command is an argument followed by other arguments and options. NPM is an example: 473 | 474 | ``` 475 | npm config set [] 476 | npm install [...] -g 477 | ``` 478 | 479 | `config` is a command and `set` an argument with 2 trailing arguments: minimum 1, maximum 2. 480 | `install` is a command with infinite trailing arguments: minimum 0, maximum Infinity. `-g` is an option which only applies to the `install` command. 481 | 482 | If you have a very few commands you can configure them in the same file ([commands.js](https://github.com/gagle/node-argp/blob/master/examples/commands.js) example), but you typically want to modularize them, one command per file. Then you should check the [npm.js](https://github.com/gagle/node-argp/blob/master/examples/npm/npm.js) example. 483 | 484 | The commands are configured exactly the same way as the `Argp` instance with only one difference: `argument()` accepts 2 new properties: 485 | 486 | - __synopsis__ - _String_ 487 | The string replaces the argument name in the --help and --usage messages. 488 | 489 | ```javascript 490 | .argument ("set", { description: "Sample argument" }); 491 | /* 492 | ... 493 | set Sample argument 494 | ... 495 | */ 496 | 497 | .argument ("set", { synopsis: "set []", description: "Sample argument" }); 498 | /* 499 | ... 500 | set [] Sample argument 501 | ... 502 | */ 503 | ``` 504 | - __trailing__ - _Object_ 505 | Configures how many trailing arguments must follow this argument. 506 | 507 | There are 3 properties: `eq`, `min` and `max`. `eq` cannot be used with `min` or `max`. If `min` and `max` are used, by default `min` is 0 and `max` is Infinity. A `trailing` object without any of these 3 properties defaults to `min` 0 and `max` Infinity. 508 | 509 | Some examples: 510 | 511 | - 2 trailing arguments required: `cmd arg `. 512 | 513 | ```javascript 514 | .argument ("arg", { trailing: { eq: 2 } }) 515 | ``` 516 | - 1 required, 1 optional: `cmd arg []`. 517 | 518 | ```javascript 519 | .argument ("arg", { trailing: { min 1, max: 2 } }) 520 | ``` 521 | - 1 optional: `cmd arg []`. 522 | 523 | ```javascript 524 | .argument ("arg", { trailing: { max: 1 } }) 525 | ``` 526 | - 1 required, infinite optional: `cmd arg [...]`. 527 | 528 | ```javascript 529 | .argument ("arg", { trailing: { min: 1 } }) 530 | ``` 531 | - Infinite: `cmd arg [...]`. 532 | 533 | ```javascript 534 | .argument ("arg", { trailing: {} }) 535 | //Same as trailing: { min: 0, max: Infinity } 536 | ``` 537 | - No trailing arguments: `cmd arg`. 538 | 539 | ```javascript 540 | .argument ("arg") 541 | ``` 542 | - Multiple arguments with trailing in the same line. Argument `arg1` with 1 required, and argument `arg2` with infinite trailing arguments: `cmd arg1 arg2 [...]`. Note that writing `cmd arg1 arg2 [...]` is not the same as `cmd arg2 [...] arg1 `. In the latter case, `arg1 ` will be eaten by the trailing arguments of `arg2`. 543 | 544 | ```javascript 545 | .argument ("arg1", { trailing: { eq: 1 } }) 546 | .argument ("arg2", { trailing: {} }) 547 | ``` 548 | 549 | --- 550 | 551 | 552 | __Real examples__ 553 | 554 | - [brainfuck](https://github.com/gagle/node-brainfuck/blob/master/bin/brainfuck.js): Interpreter for the Brainfuck esoteric language. 555 | - [ntftp](https://github.com/gagle/node-ntftp/blob/master/bin/ntftp.js): Streaming TFTP client and server. 556 | 557 | --- 558 | 559 | 560 | ___module_.createParser([options]) : Argp__ 561 | 562 | Returns a new [Argp](#argp_object) instance. 563 | 564 | Options: 565 | 566 | - __once__ - _Boolean_ 567 | Set it to true if you want to uncache the whole module when [argv()](#argp_argv) finishes. This will guarantee a zero memory footprint. Default is false. 568 | 569 | --- 570 | 571 | 572 | __Argp__ 573 | 574 | The module returns an instance of `Argp`. It inherits from an EventEmitter. 575 | 576 | The parser follows the GNU-style rules: `-a`, `-abc`, `--a`, `--no-a`, `--a=b`, `--`, etc. Long-option abbreviation is also supported. 577 | 578 | If you don't want to configure anything simply require the module, allow undefined arguments and options and call to `argv()`. 579 | 580 | ```javascript 581 | var argv = require ("argp").createParser ({ once: true }) 582 | .allowUndefinedArguments () 583 | .allowUndefinedOptions () 584 | .argv (); 585 | ``` 586 | 587 | Note: If no configuration is provided you cannot join a short name with its value in the same token, eg: `-Dvalue`, all the characters following a hyhen are interpreted as individual flags. 588 | 589 | __Events__ 590 | 591 | With the event system you can fully adapt this module to yours needs. Examples: [to-upper-case.js](https://github.com/gagle/node-argp/blob/master/examples/to-upper-case.js), [mkdir.js](https://github.com/gagle/node-argp/blob/master/examples/mkdir.js). 592 | 593 | - [argument](#event_argument) 594 | - [end](#event_end) 595 | - [error](#event_error) 596 | - [option](#event_option) 597 | - [start](#event_start) 598 | 599 | __Methods__ 600 | 601 | - [Argp#allowUndefinedArguments() : Argp](#argp_allowundefinedarguments) 602 | - [Argp#allowUndefinedOptions() : Argp](#argp_allowundefinedoptions) 603 | - [Argp#arguments() : Object](#argp_arguments) 604 | - [Argp#argv([input]) : Object](#argp_argv) 605 | - [Argp#body() : Body](#argp_body) 606 | - [Argp#columns(columns) : Argp](#argp_columns) 607 | - [Argp#command(name[, configuration]) : Command](#argp_command) 608 | - [Argp#commands() : Argp](#argp_commands) 609 | - [Argp#description(str) : Argp](#argp_description) 610 | - [Argp#email(str) : Argp](#argp_email) 611 | - [Argp#exitStatus(code) : Argp](#argp_exitstatus) 612 | - [Argp#fail(str[, code]) : undefined](#argp_fail) 613 | - [Argp#main() : Argp](#argp_main) 614 | - [Argp#options([filter]) : Object](#argp_options) 615 | - [Argp#printHelp([code]) : undefined](#argp_printhelp) 616 | - [Argp#printUsage([code]) : undefined](#argp_printusage) 617 | - [Argp#printVersion([code]) : undefined](#argp_printversion) 618 | - [Argp#readPackage([path]) : Argp](#argp_readpackage) 619 | - [Argp#sort() : Argp](#argp_sort) 620 | - [Argp#usages(usages) : Argp](#argp_usage) 621 | 622 | __Objects__ 623 | 624 | - [Body](#body) 625 | 626 | --- 627 | 628 | 629 | __argument__ 630 | 631 | Emitted when an argument is found. 632 | 633 | Parameters: 634 | 635 | - __argv__ - _Object_ 636 | The final object. 637 | - __argument__ - _String_ 638 | The name of the argument. 639 | - __ignore__ - _Function_ 640 | When the function is called the parser ignores the argument, hence it isn't stored in the final object. 641 | 642 | 643 | __end__ 644 | 645 | Emitted when all the options and arguments have been parsed. 646 | 647 | Parameters: 648 | 649 | - __argv__ - _Object_ 650 | The final object. 651 | 652 | 653 | __error__ 654 | 655 | Emitted when an error occurs. If you don't listen for `error` events, the message will be printed to stderr and the process will exit. If you attach an error handler and an error occurs, [argv()](#argp_argv) returns null. 656 | 657 | You typically want to listen for `error` events when you need to do something with the error and then quit the process, or simply because you want to continue executing the process (maybe because you are executing a shell prompt) and display the error in the console. 658 | 659 | ```javascript 660 | .on ("error", function (error){ 661 | doSomethingWith (error); 662 | //This will end the process 663 | this.fail (error); 664 | }) 665 | ``` 666 | 667 | For example, the [ntftp](https://github.com/gagle/node-ntftp/blob/master/bin/ntftp.js) module uses two parsers. One is the main parser. If something is not correct, it prints the error to stderr and finishes. The second parser is used when the program is executing a shell prompt. It is being reused and the errors are simply printed to console. 668 | 669 | 670 | __option__ 671 | 672 | Emitted when an option is found. 673 | 674 | Parameters: 675 | 676 | - __argv__ - _Object_ 677 | The final object. 678 | - __option__ - _String_ 679 | The name of the option. 680 | - __value__ - _String_ 681 | The value of the option after calling the reviver, if any. 682 | - __long__ - _Boolean_ 683 | True if the option is a long name, otherwise false. 684 | - __ignore__ - _Function_ 685 | When the function is called the parser ignores the argument, hence it isn't stored in the final object. 686 | 687 | 688 | __start__ 689 | 690 | Emitted just before the parser begins to read the cli parameters. 691 | 692 | Parameters: 693 | 694 | - __argv__ - _Object_ 695 | The final object. The default values are already set. 696 | 697 | --- 698 | 699 | 700 | __Argp#allowUndefinedArguments() : Argp__ 701 | 702 | Allows undefined arguments. 703 | 704 | 705 | __Argp#allowUndefinedOptions() : Argp__ 706 | 707 | Allows undefined options. 708 | 709 | 710 | __Argp#arguments() : Object__ 711 | 712 | Returns the configured arguments. Look at the [internal-data.js](https://github.com/gagle/node-argp/blob/master/examples/internal-data.js) example for further details. 713 | 714 | 715 | __Argp#argv([input]) : Object | null__ 716 | 717 | Parses the `process.argv` array or the given input array. 718 | 719 | If you don't need to reuse the parser and want a zero memory footprint, you shouldn't cache the module and the parser instance. Remember to also set `once` to true. 720 | 721 | ```javascript 722 | var argv = require ("argp").createParser ({ once: true }) 723 | ... 724 | argv (); 725 | ``` 726 | 727 | If you need to reuse a parser, you probably want to listen for [error](#event_error) events. If an error occurs, [argv()](#arg_argv) returns null. 728 | 729 | ```javascript 730 | var argp = require ("argp"); 731 | 732 | //Configuration 733 | var parser = argp.createParser () 734 | .on ("error", ...) 735 | ...; 736 | 737 | var argv; 738 | argv = parser.argv (["-a", "--b", ...]); 739 | argv = parser.argv (["c", "d", ...]); 740 | ``` 741 | 742 | If you pass an input array, then the functions [printHelp()](#argp_printhelp), [printUsage()](#argp_printusage) and [printVersion()](#argp_printversion) will print the message but won't terminate the process. 743 | 744 | 745 | __Argp#body() : Argp__ 746 | 747 | Returns a `Body` instance. 748 | 749 | 750 | __Argp#columns(columns) : Argp__ 751 | 752 | Sets the maximum line length. By default lines are wrapped at 80 columns. 753 | 754 | 755 | __Argp#command(name[, configuration]) : Command__ 756 | 757 | Configures a command. A command it's like a new fresh cli program. It behaves exactly like an `Argp`. See [Configuring commands](#commands). 758 | 759 | 760 | __Argp#commands() : Object__ 761 | 762 | Returns the configured commands. 763 | 764 | Look at the [internal-data.js](https://github.com/gagle/node-argp/blob/master/examples/internal-data.js) example for further details. 765 | 766 | 767 | __Argp#description(str) : Argp__ 768 | 769 | Sets a description. The description is printed at the start of the --help message, after the "Usage" lines. 770 | 771 | 772 | __Argp#email(str) : Argp__ 773 | 774 | Sets a contact email. The email is printed at the end of the --help message. 775 | 776 | 777 | __Argp#exitStatus(code) : Argp__ 778 | 779 | Sets the exit code that will be used is some methods. Default is 1. 780 | 781 | 782 | __Argp#fail(str[, code]) : undefined__ 783 | 784 | Prints a message to the stderr and exits with the given code number or if not given, uses the code configured with [exitStatus()](#argp_exitstatus) or if not configured, exits with code 1. 785 | 786 | 787 | __Argp#main() : Argp__ 788 | 789 | Returns de main `Argp` instance. It's a no-op function, just for a better visual organization when configuring commands. 790 | 791 | Look at the [npm.js](https://github.com/gagle/node-argp/blob/master/examples/npm/npm.js) example for further details. 792 | 793 | 794 | __Argp#options([filter]) : Object__ 795 | 796 | Returns the configured options. `filter` is an object which can be used to return the options that have a short name or a long name. 797 | 798 | ```javascript 799 | .options () 800 | .options ({ short: true }) 801 | .options ({ long: true }) 802 | ``` 803 | 804 | Look at the [internal-data.js](https://github.com/gagle/node-argp/blob/master/examples/internal-data.js) example for further details. 805 | 806 | 807 | __Argp#printHelp([code]) : undefined__ 808 | 809 | Prints the help message and exits with the given code number or if not given, uses the code configured with [exitStatus()](#argp_exitstatus) or if not configured, exits with code 0. 810 | 811 | If [argv()](#argp_argv) is called with an input array, the process doesn't exit. 812 | 813 | 814 | __Argp#printUsage([code]) : undefined__ 815 | 816 | Prints the usage message and exits with the given code number or if not given, uses the code configured with [exitStatus()](#argp_exitstatus) or if not configured, exits with code 0. 817 | 818 | If [argv()](#argp_argv) is called with an input array, the process doesn't exit. 819 | 820 | 821 | __Argp#printVersion([code]) : undefined__ 822 | 823 | Prints the version message (if it was configured) and exits with the given code number or if not given, uses the code configured with [exitStatus()](#argp_exitstatus) or if not configured, exits with code 0. 824 | 825 | If [argv()](#argp_argv) is called with an input array, the process doesn't exit. 826 | 827 | 828 | __Argp#readPackage([path][, options]) : Argp__ 829 | 830 | Reads a `package.json` file and configures the parser with the description, email and version. If no path is provided it tries to read the `./package.json` path. The description, email and version labels can be ignored individually with the `options` parameter. For example, if you only want to ignore the email and read the description and version: 831 | 832 | ```javascript 833 | .readPackage ("path/to/package.json", { email: false }) 834 | ``` 835 | 836 | Options are: `description`, `version`, `email`. By default they are true. Set them to false to ignore them. 837 | 838 | 839 | __Argp#usages(usages) : Argp__ 840 | 841 | Changes the "Usage" line from the --help and --usage messages. `usages` is an array of strings. 842 | 843 | Look at the [custom-usages.js](https://github.com/gagle/node-argp/blob/master/examples/custom-usages.js) example for further details. 844 | 845 | 846 | __Argp#sort() : Argp__ 847 | 848 | If `sort()` is enabled, the options are parsed before the arguments, if not, the options and arguments are parsed in the same order they come. 849 | 850 | --- 851 | 852 | 853 | __Body__ 854 | 855 | The `Body` instance is returned by calling [Argp#body()](#argp_body). All the following functions (except `argv()`, `command()` and `main()`) print a message in the same order they are configured, this allows you to fully customize the --help message very easily. 856 | 857 | Look at [fully-descriptive-help.js](https://github.com/gagle/node-argp/blob/master/examples/fully-descriptive-help.js) for further details. 858 | 859 | __Methods__ 860 | 861 | - [Body#argument(name[, configuration]) : Body](#body_argument) 862 | - [Body#argv([input]) : Object](#body_argv) 863 | - [Body#columns(column1, column2) : Body](#body_columns) 864 | - [Body#command(name[, configuration]) : Command](#body_command) 865 | - [Body#help([options]) : Body](#body_help) 866 | - [Body#main() : Argp](#body_main) 867 | - [Body#option(o) : Body](#body_option) 868 | - [Body#text(str[, prefix]) : Body](#body_text) 869 | - [Body#usage() : Body](#body_usage) 870 | - [Body#version(str[, options]) : Body](#body_version) 871 | 872 | 873 | __Body#argument(name[, configuration]) : Body__ 874 | 875 | Defines an argument. See [Configuring arguments](#arguments). 876 | 877 | 878 | __Body#argv([input]) : Object__ 879 | 880 | Same as [Argp#argv()](#argp_argv). 881 | 882 | 883 | __Body#columns(column1, column2) : Body__ 884 | 885 | Prints a line with 2 columns. The first column shouldn't contain line breaks (`\n`). This functionality is used to print the options and arguments. 886 | 887 | 888 | __Body#command(name[, configuration]) : Command__ 889 | 890 | Same as [Argp#command()](#argp_command). 891 | 892 | 893 | __Body#help([options]) : Body__ 894 | 895 | Enables the `-h, --help` option. The short option can be disabled using the `options` parameter. 896 | 897 | ```javascript 898 | .help ({ short: false }) 899 | ``` 900 | ```bash 901 | $ node script.js --help 902 | ... 903 | --help Display this help message and exit 904 | ... 905 | ``` 906 | 907 | 908 | __Body#main() : Argp__ 909 | 910 | Same as [Argp#main()](#argp_main). 911 | 912 | 913 | __Body#option(o) : Body__ 914 | 915 | Defines an option. See [Configuring options](#options). 916 | 917 | 918 | __Body#text(str[, prefix]) : Body__ 919 | 920 | Prints a text message. By default it's line-wrapped at 80 columns and supports multilines (line breaks, `\n`). The `prefix` is a string that is printed before each line. It's mainly used to indent the text with some spaces. 921 | 922 | 923 | __Body#usage() : Body__ 924 | 925 | Enables the `--usage` option. 926 | 927 | 928 | __Body#version(str[, options]) : Body__ 929 | 930 | Enables the `-v, --version` option. `str` is the text to print when the option is called. The short option can be disabled using the `options` parameter. 931 | 932 | ```javascript 933 | .version ("v1.2.3", { short: false }) 934 | ``` 935 | ```bash 936 | $ node script.js --help 937 | ... 938 | --version Output version information and exit 939 | ... 940 | ``` -------------------------------------------------------------------------------- /examples/abbreviations.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | require ("../lib").createParser ({ once: true }) 4 | .description ("Sample app.") 5 | .body () 6 | .help () 7 | .usage () 8 | .version ("v1.2.3") 9 | .argv (); 10 | 11 | /* 12 | $ node abbreviations.js --he 13 | 14 | Usage: abbreviations [options] 15 | 16 | Sample app. 17 | 18 | -h, --help Display this help message and exit 19 | --usage Display a short usage message and exit 20 | -v, --version Output version information and exit 21 | 22 | -------------------------------------------------------------------------------- 23 | 24 | $ node abbreviations.js --u 25 | 26 | Usage: abbreviations [-h|--help] [--usage] [-v|--version] 27 | 28 | -------------------------------------------------------------------------------- 29 | 30 | $ node abbreviations.js --ver 31 | 32 | v1.2.3 33 | */ -------------------------------------------------------------------------------- /examples/aliases.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* 4 | This example shows 2 types of aliases: 5 | - Pure aliases: They are just a different name which points to the same option. 6 | - Defined aliases: They have their own option definition but they are related 7 | with other options. 8 | 9 | Say we have a --dot option. We want to also use the --point name to refer to the 10 | same option. By default it prints one dot. If we want to print an ellipsis we 11 | can pass the value of 3 or we can define an --ellipsis flag. When it is enabled 12 | it prints 3 dots. 13 | 14 | --point is a pure alias and --ellipsis is a defined alias. 15 | */ 16 | 17 | var argv = require ("../lib").createParser ({ once: true }) 18 | .on ("end", function (argv){ 19 | if (argv.ellipsis) argv.dot = 3; 20 | }) 21 | .body () 22 | .option ({ 23 | short: "d", 24 | long: "dot", 25 | aliases: ["point"], 26 | metavar: "N", 27 | optional: true, 28 | default: 1, 29 | type: Number, 30 | description: "Print N dots, default is 1" 31 | }) 32 | .option ({ 33 | long: "ellipsis", 34 | description: "Print 3 dots, same as --dots=3" 35 | }) 36 | .argv (); 37 | 38 | console.log (argv); 39 | 40 | /* 41 | $ node aliases.js --po 2 # The aliases can be also abbreviated 42 | 43 | { 44 | dot: 2, 45 | ellipisis: false 46 | } 47 | 48 | -------------------------------------------------------------------------------- 49 | 50 | $ node aliases.js --ellipsis 51 | 52 | { 53 | dot: 3, 54 | ellipisis: true 55 | } 56 | */ -------------------------------------------------------------------------------- /examples/arguments.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var argv = require ("../lib").createParser ({ once: true }) 4 | .body () 5 | //Argument 6 | .argument ("arg1") 7 | 8 | //Argument with a description 9 | .argument ("arg2", { description: "foo" }) 10 | 11 | //Hidden argument 12 | .argument ("arg3", { hidden: true }) 13 | 14 | .help () 15 | .usage () 16 | .argv (); 17 | 18 | console.log (argv); 19 | 20 | /* 21 | $ node options.js 22 | 23 | { 24 | help: false, 25 | usage: false, 26 | arg1: false, 27 | arg2: false, 28 | arg3: false 29 | } 30 | 31 | -------------------------------------------------------------------------------- 32 | 33 | $ node options.js --help 34 | 35 | Usage: options [options] [arguments] 36 | 37 | arg1 38 | arg2 foo 39 | -h, --help Display this help message and exit 40 | --usage Display a short usage message and exit 41 | 42 | -------------------------------------------------------------------------------- 43 | 44 | $ node options.js --usage 45 | 46 | Usage: options [-h|--help] [--usage] [arg1] [arg2] 47 | */ -------------------------------------------------------------------------------- /examples/commands.js: -------------------------------------------------------------------------------- 1 | "use script"; 2 | 3 | var argv = require ("../lib").createParser ({ once: true }) 4 | .main () 5 | .description ("Main menu.") 6 | .body () 7 | .help () 8 | .usage () 9 | .command ("config") 10 | .body () 11 | .argument ("set", { 12 | synopsis: "set []", 13 | trailing: { min: 1, max: 2 } 14 | }) 15 | .help () 16 | .command ("install", { trailing: {} }) 17 | .body () 18 | .option ({ short: "g", long: "global" }) 19 | .usage () 20 | .argv (); 21 | 22 | console.log (argv); 23 | 24 | /* 25 | $ node commands.js -h 26 | 27 | Usage: commands [options] 28 | 29 | Main menu. 30 | 31 | -h, --help Display this help message and exit 32 | --usage Display a short usage message and exit 33 | 34 | -------------------------------------------------------------------------------- 35 | 36 | $ node commands.js config -h 37 | 38 | Usage: commands config [options] [arguments] 39 | 40 | set [] 41 | -h, --help Display this help message and exit 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | $ node commands.js config set 1 2 46 | 47 | { config: [], set: [ 1, 2 ] } 48 | 49 | -------------------------------------------------------------------------------- 50 | 51 | $ node commands.js install --usage 52 | 53 | Usage: commands install [-g|--global] [--usage] 54 | 55 | -------------------------------------------------------------------------------- 56 | 57 | $ node commands.js install 1 2 3 -g 58 | 59 | { install: [ 1, 2, 3 ], global: true } 60 | */ -------------------------------------------------------------------------------- /examples/custom-usages.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* 4 | By default when the --help and --usage messages are printed there is only one 5 | "usage" line. This line can be changed and multiple lines can be added with the 6 | usages() function. 7 | */ 8 | 9 | require ("../lib").createParser ({ once: true }) 10 | .usages ([ 11 | "custom-usages ", 12 | "custom-usages [word [word [word]]]" 13 | ]) 14 | .body () 15 | .help () 16 | .usage () 17 | .argv (); 18 | 19 | /* 20 | $ node custom-usages.js --help 21 | 22 | Usage: custom-usages 23 | custom-usages [word [word [word]]] 24 | 25 | -h, --help Display this help message and exit 26 | --usage Display a short usage message and exit 27 | 28 | -------------------------------------------------------------------------------- 29 | 30 | $ custom-usages.js --usage 31 | 32 | Usage: custom-usages 33 | custom-usages [word [word [word]]] 34 | */ -------------------------------------------------------------------------------- /examples/events.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | process.argv = ["node", __filename, "-a", "b", "arg1", "--c=d", "arg2"]; 4 | 5 | /* 6 | The events allow you to fully adapt the parser to your needs. 7 | See to-upper-case.js example. 8 | */ 9 | 10 | require ("../lib").createParser ({ once: true }) 11 | .on ("error", function (error){ 12 | //Emitted when an error occurs 13 | //"argv()" returns null 14 | 15 | console.log (error); 16 | }) 17 | .on ("start", function (argv){ 18 | //Emitted after the default values of the configured options and arguments 19 | //have been set and before starting the read. 20 | 21 | //"argv" is the final object 22 | 23 | console.log ("START"); 24 | }) 25 | .on ("argument", function (argv, argument, ignore){ 26 | //Emitted when an argument is found 27 | 28 | //"argv" is the final object 29 | //"argument" is the argument found 30 | //"ignore" is a function that when called ignores the argument, hence it 31 | //it isn't stored in the final object 32 | 33 | console.log ("ARGUMENT:", argument); 34 | }) 35 | .on ("option", function (argv, option, value, long, ignore){ 36 | //Emitted when an option is found 37 | 38 | //"argv" is the final object 39 | //"option" is the name of the option found 40 | //"value" is the value of the option after calling the reviver, if any 41 | //"long" is a boolean; true if the option is a long name, otherwise false 42 | //"ignore" is a function that when called ignores the argument, hence it 43 | //it isn't stored in the final object 44 | 45 | console.log ("OPTION:", option, value, long); 46 | }) 47 | .on ("end", function (argv){ 48 | //Emitted when all the options and arguments have been read 49 | 50 | //"argv" is the final object 51 | 52 | console.log ("END"); 53 | }) 54 | //.sort () 55 | .allowUndefinedOptions () 56 | .allowUndefinedArguments () 57 | .argv (); 58 | 59 | /* 60 | START 61 | OPTION: a b false 62 | ARGUMENT: arg1 63 | OPTION: c d true 64 | ARGUMENT: arg2 65 | END 66 | 67 | If the "sort()" function is uncommented: 68 | 69 | START 70 | OPTION: a b false 71 | OPTION: c d true 72 | ARGUMENT: arg1 73 | ARGUMENT: arg2 74 | END 75 | */ -------------------------------------------------------------------------------- /examples/fully-descriptive-help.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | require ("../lib").createParser ({ once: true }) 4 | .description ("Sample app.") 5 | .footer ("The program exits with a status code of 0 if no error, " + 6 | "otherwise 99.") 7 | .email ("a@b.c") 8 | .exitStatus (99) 9 | .body () 10 | .text (" Group 1:") 11 | .argument ("arg1", { description: "aaaa" }) 12 | .argument ("arg2", { description: "bbbb" }) 13 | .text ("\n Group 2:") 14 | .option ({ short: "a", long: "aa", description: "aaaa" }) 15 | .option ({ short: "b", long: "bb", description: "bbbb" }) 16 | .text ("\nThis is a multiline text.\nRemember that all the messages " + 17 | "are line-wrapped at 80 columns and you can use \\n to split " + 18 | "them in multiple lines.\n") 19 | .text ("You can prefix the lines with any string. This is useful " + 20 | "when you need to indent the lines or quote messages.", "> ") 21 | .text ("\nList: (column 1 cannot contain \\n)") 22 | .columns (" this is column 1", "This is a multiline in\ncolumn 2") 23 | .text ("\n Informational options:") 24 | .help () 25 | .version ("v1.2.3") 26 | .argv (); 27 | 28 | /* 29 | $ node fully-descriptive-help.js --help 30 | 31 | Usage: fully-descriptive-help [options] [arguments] 32 | 33 | Sample app. 34 | 35 | Group 1: 36 | arg1 aaaa 37 | arg2 bbbb 38 | 39 | Group 2: 40 | -a, --aa aaaa 41 | -b, --bb bbbb 42 | 43 | This is a multiline text. 44 | Remember that all the messages are line-wrapped at 80 columns and you can use \n 45 | to split them in multiple lines. 46 | 47 | > You can prefix the lines with any string. This is useful when you need to 48 | > indent the lines or quote messages. 49 | 50 | List: (column 1 cannot contain \n) 51 | this is column 1 This is a multiline in 52 | column 2 53 | 54 | Informational options: 55 | -h, --help Display this help message and exit 56 | -v, --version Output version information and exit 57 | 58 | The program exits with a status code of 0 if no error, otherwise 1. 59 | 60 | Report bugs to . 61 | */ -------------------------------------------------------------------------------- /examples/help-usage-version.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | require ("../lib").createParser ({ once: true }) 4 | .description ("Sample app.") 5 | .body () 6 | .argument ("arg1") 7 | .argument ("arg2") 8 | .option ({ short: "a", long: "aaaa" }) 9 | .option ({ long: "b", negate: true }) 10 | .option ({ short: "c", metavar: "C" }) 11 | .option ({ long: "d", metavar: "D", default: "dddd" }) 12 | .option ({ short: "e", metavar: "E", optional: true }) 13 | .option ({ long: "f", metavar: "F", default: "ffff", 14 | optional: true }) 15 | .option ({ short: "g", metavar: "G", aliases: ["foo", "bar"]}) 16 | .help () 17 | .usage () 18 | .version ("v1.2.3") 19 | .argv (); 20 | 21 | /* 22 | $ node help-usage-version.js --help 23 | 24 | Usage: help-usage-version [options] [arguments] 25 | 26 | Sample app. 27 | 28 | arg1 29 | arg2 30 | -a, --aaaa 31 | --no-b 32 | -c C 33 | --d=D 34 | -e[E] 35 | --f[=F] 36 | -g, --foo, --bar=G 37 | -h, --help Display this help message and exit 38 | --usage Display a short usage message and exit 39 | -v, --version Output version information and exit 40 | 41 | -------------------------------------------------------------------------------- 42 | 43 | $ node help-usage-version.js --usage 44 | 45 | Usage: help-usage-version [-c C] [-e[E]] [-a|--aaaa] [--b] [--d=D] [--f[=F]] 46 | [-g|--foo|--bar=G] [-h|--help] [--usage] [-v|--version] [arg1] [arg2] 47 | 48 | -------------------------------------------------------------------------------- 49 | 50 | $ node help-usage-version.js -v 51 | 52 | v1.2.3 53 | */ -------------------------------------------------------------------------------- /examples/internal-data.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var util = require ("util"); 4 | 5 | var parser = require ("../lib").createParser ({ once: true }); 6 | parser 7 | .main () 8 | .body () 9 | .argument ("arg1") 10 | .argument ("arg2") 11 | .option ({ short: "a", long: "aa", description: "aaaa" }) 12 | .option ({ long: "bb", description: "bbbb" }) 13 | .option ({ short: "c", description: "cccc", metavar: "cc", 14 | aliases: ["dd"], optional: true, default: 5, type: Number }) 15 | .help () 16 | .usage () 17 | .version ("v1.2.3") 18 | .command ("a", { trailing: {} }) 19 | .body () 20 | .help () 21 | .command ("b") 22 | .body () 23 | .argument ("c", { trailing: {} }) 24 | .usage (); 25 | 26 | console.log (parser.arguments ()); 27 | 28 | /* 29 | { 30 | arg1: { 31 | hidden: false, 32 | synopsis: null, 33 | trailing: null, 34 | description: null 35 | }, 36 | arg2: { 37 | hidden: false, 38 | synopsis: null, 39 | trailing: null, 40 | description: null 41 | } 42 | } 43 | */ 44 | 45 | console.log (parser.options ()); 46 | 47 | /* 48 | { 49 | aa: { 50 | short: "a", 51 | long: "aa", 52 | description: "aaaa", 53 | flag: true, 54 | id: "aa", 55 | hidden: false, 56 | aliases: [], 57 | negate: false, 58 | default: false 59 | }, 60 | bb: { 61 | long: "bb", 62 | description: "bbbb", 63 | flag: true, 64 | id: "bb", 65 | hidden: false, 66 | aliases: [], 67 | negate: false, 68 | default: false 69 | }, 70 | c: { 71 | short: "c", 72 | description: "cccc", 73 | metavar: "cc", 74 | aliases: ["dd"], 75 | optional: true, 76 | default: 5, 77 | type: [Function: Number], 78 | flag: false, 79 | id: "c", 80 | hidden: false, 81 | reviver: null, 82 | choices: null 83 | }, 84 | dd: { 85 | short: "c", 86 | description: "cccc", 87 | metavar: "cc", 88 | aliases: ["dd"], 89 | optional: true, 90 | default: 5, 91 | type: [Function: Number], 92 | flag: false, 93 | id: "c", 94 | hidden: false, 95 | reviver: null, 96 | choices: null 97 | }, 98 | help: { 99 | short: "h", 100 | long: "help", 101 | description: "Display this help message and exit", 102 | flag: true, 103 | id: "help", 104 | hidden: false, 105 | aliases: [], 106 | negate: false, 107 | default: false 108 | }, 109 | usage: { 110 | long: "usage", 111 | description: "Display a short usage message and exit", 112 | flag: true, 113 | id: "usage", 114 | hidden: false, 115 | aliases: [], 116 | negate: false, 117 | default: false 118 | }, 119 | version: { 120 | short: "v", 121 | long: "version", 122 | description: "Output version information and exit", 123 | flag: true, 124 | id: "version", 125 | hidden: false, 126 | aliases: [], 127 | negate: false, 128 | default: false 129 | } 130 | } 131 | */ 132 | 133 | console.log (parser.options ({ short: true })); 134 | 135 | /* 136 | { 137 | a: { 138 | ... 139 | }, 140 | c: { 141 | ... 142 | }, 143 | h: { 144 | ... 145 | }, 146 | v: { 147 | ... 148 | } 149 | */ 150 | 151 | console.log (parser.options ({ long: true })); 152 | 153 | /* 154 | { 155 | aa: { 156 | ... 157 | }, 158 | bb: { 159 | ... 160 | }, 161 | dd: { 162 | ... 163 | }, 164 | help: { 165 | ... 166 | }, 167 | version: { 168 | ... 169 | }, 170 | usage: { 171 | ... 172 | } 173 | } 174 | */ 175 | 176 | console.log (util.inspect (parser.commands (), { depth: null })); 177 | 178 | /* 179 | { 180 | a: { 181 | arguments: {}, 182 | options: { 183 | help: { 184 | short: "h", 185 | long: "help", 186 | description: "Display this help message and exit", 187 | flag: true, 188 | id: "help", 189 | hidden: false, 190 | aliases: [], 191 | negate: false, 192 | default: false 193 | } 194 | } 195 | }, 196 | b: { 197 | arguments: { 198 | c: { 199 | trailing: { 200 | min: 0, 201 | max: Infinity 202 | }, 203 | hidden: false, 204 | synopsis: null, 205 | description: null 206 | } 207 | }, 208 | options: { 209 | usage: { 210 | long: "usage", 211 | description: "Display a short usage message and exit", 212 | flag: true, 213 | id: "usage", 214 | hidden: false, 215 | aliases: [], 216 | negate: false, 217 | default: false 218 | } 219 | } 220 | } 221 | } 222 | */ 223 | 224 | //Note: In this example "argv()" is not called, so the module is never uncached 225 | parser = null; -------------------------------------------------------------------------------- /examples/mkdir.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var argv = require ("../lib").createParser ({ once: true }) 4 | .description ("Create the DIRECTORY(ies), if they do not already exist.") 5 | .usages (["mkdir [OPTION]... DIRECTORY..."]) 6 | .allowUndefinedArguments () 7 | .on ("start", function (argv){ 8 | argv.dirs = []; 9 | }) 10 | .on ("argument", function (argv, argument, ignore){ 11 | argv.dirs.push (argument); 12 | ignore (); 13 | }) 14 | .body () 15 | .text ("Mandatory arguments to long options are mandatory for short " + 16 | "options too.") 17 | .option ({ short: "m", long: "mode", metavar: "MODE", 18 | description: "Set file mode (as in chmod), not a=rwx - umask" }) 19 | .option ({ short: "p", long: "parents", description: "No error if " + 20 | "existing, make parent directories as needed" }) 21 | .option ({ short: "v", long: "verbose", 22 | description: "Print a message for each created directory" }) 23 | .option ({ short: "Z", long: "context", metavar: "CTX", 24 | description: "Set the SELinux security cntext of each created " + 25 | "directory to CTX" }) 26 | .help ({ short: false }) 27 | .version ("v1.2.3", { short: false }) 28 | .argv (); 29 | 30 | console.log (argv); 31 | 32 | /* 33 | $ node mkdir.js --help 34 | 35 | Usage: mkdir [OPTION]... DIRECTORY... 36 | 37 | Create the DIRECTORY(ies), if they do not already exist. 38 | 39 | Mandatory arguments to long options are mandatory for short options too. 40 | -m, --mode=MODE Set file mode (as in chmod), not a=rwx - umask 41 | -p, --parents No error if existing, make parent directories as 42 | needed 43 | -v, --verbose Print a message for each created directory 44 | -Z, --context=CTX Set the SELinux security cntext of each created 45 | directory to CTX 46 | --help Display this help message and exit 47 | --version Output version information and exit 48 | 49 | -------------------------------------------------------------------------------- 50 | 51 | $ node mkdir.js -p a b c 52 | 53 | { 54 | mode: null, 55 | parents: true, 56 | verbose: false, 57 | context: null, 58 | help: false, 59 | version: false, 60 | dirs: ["a", "b", "c" ] 61 | } 62 | 63 | -------------------------------------------------------------------------------- 64 | 65 | $ node mkdir.js -- --help 66 | 67 | { 68 | mode: null, 69 | parents: false, 70 | verbose: false, 71 | context: null, 72 | help: false, 73 | version: false, 74 | dirs: ["--help" ] 75 | } 76 | */ -------------------------------------------------------------------------------- /examples/modifying-builtin-options.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var parser = require ("../lib").createParser ({ once: true }); 4 | parser 5 | .body () 6 | .option ({ short: "v", long: "verbose" }) 7 | .help () 8 | .usage () 9 | //Disable -v option 10 | .version ("v1.2.3", { short: false }); 11 | 12 | parser.options ().help.description = "???"; 13 | 14 | var argv = parser.argv (); 15 | 16 | //Zero memory footprint! 17 | parser = null; 18 | 19 | console.log (argv); 20 | 21 | /* 22 | $ node modifying-builtin-options.js --help 23 | 24 | Usage: modifying-builtin-options [options] 25 | 26 | -v, --verbose 27 | -h, --help ??? 28 | --usage Display a short usage message and exit 29 | --version Output version information and exit 30 | */ -------------------------------------------------------------------------------- /examples/no-configuration.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var argv = require ("../lib").createParser ({ once: true }) 4 | .allowUndefinedOptions () 5 | .allowUndefinedArguments () 6 | .argv (["-abc", "d", "--e=f", "g", "-i", "j", "--", "--k", "l"]); 7 | 8 | console.log (argv); 9 | 10 | /* 11 | { 12 | a: true, 13 | b: true, 14 | c: "d", 15 | e: "f", 16 | g: true, 17 | i: "j", 18 | "--k": true, 19 | l: true 20 | } 21 | */ -------------------------------------------------------------------------------- /examples/npm/config.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function (parser){ 4 | parser 5 | .command ("config") 6 | .on ("end", config) 7 | .description ("Manages the npm configuration files.") 8 | .body () 9 | .text (" Commands:") 10 | .argument ("set", { trailing: { min: 1, max: 2 } , 11 | synopsis: "set []", 12 | description: "Sets the config key to the value. If value " + 13 | "is omitted, then it sets it to \"true\"." }) 14 | .argument ("get", { trailing: { max: 1 }, 15 | synopsis: "get []", 16 | description: "Echo the config value to stdout." }) 17 | .argument ("list", { description: "Show all the config " + 18 | "settings." }) 19 | .text ("\n Options:") 20 | .help (); 21 | }; 22 | 23 | //Note: The parser doesn't need to be explicitly nulled because when the 24 | //"config" function is executed, at this point the parser object is unreferenced 25 | //automatically (it was nulled in the main module, npm.js) 26 | 27 | function config (argv){ 28 | //Code... 29 | console.log (argv); 30 | }; -------------------------------------------------------------------------------- /examples/npm/install.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function (parser){ 4 | parser 5 | //"trailing: {}" is equivalent to "trailing: { min: 0, max: Infinity }" 6 | .command ("install", { trailing: {} }) 7 | .on ("end", install) 8 | .description ("Installs packages.") 9 | .body () 10 | .text ("npm install\n" + 11 | "npm install \n" + 12 | "npm install @\n" + 13 | "npm install @\n" + 14 | "npm install @\n" + 15 | "npm install \n" + 16 | "npm install \n" + 17 | "npm install \n" + 18 | "npm install \n" + 19 | "npm install /\n\n" + 20 | " Options:") 21 | .help (); 22 | }; 23 | 24 | //Note: The parser doesn't need to be explicitly nulled because when the 25 | //"install" function is executed, at this point the parser object is 26 | //unreferenced automatically (it was nulled in the main module, npm.js) 27 | 28 | function install (argv){ 29 | //Code... 30 | console.log (argv); 31 | }; -------------------------------------------------------------------------------- /examples/npm/npm.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | //Configure the main menu 4 | var parser = require ("../../lib").createParser ({ once: true }); 5 | 6 | parser 7 | //main() is optional, no-op, just for a better visual organization 8 | .main () 9 | .on ("end", function (argv){ 10 | if (argv.l){ 11 | fullInfo (); 12 | }else{ 13 | this.printHelp (); 14 | } 15 | }) 16 | .usages (["npm "]) 17 | .body () 18 | .text ("Where command is one of:") 19 | .text ("config, install, whoami\n", " ") 20 | .columns ("npm --help", "Quick help on ") 21 | .text ("\n Options:") 22 | .option ({ short: "l", description: "Display full usage info" }) 23 | .help () 24 | .version ("v1.2.3"); 25 | 26 | //Configure comands 27 | require ("./config")(parser); 28 | require ("./install")(parser); 29 | require ("./whoami")(parser); 30 | 31 | //Start the parser 32 | parser.argv (); 33 | 34 | //Free the parser! 35 | parser = null; 36 | 37 | function fullInfo (){ 38 | //Code... 39 | console.log ("full usage info"); 40 | process.exit (0); 41 | }; -------------------------------------------------------------------------------- /examples/npm/whoami.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = function (parser){ 4 | parser 5 | .command ("whoami") 6 | .on ("end", whoami) 7 | .description ("Display npm username. Just prints the 'username' " + 8 | "config.") 9 | .body () 10 | .help (); 11 | }; 12 | 13 | //Note: The parser doesn't need to be explicitly nulled because when the 14 | //"whoami" function is executed, at this point the parser object is 15 | //unreferenced automatically (it was nulled in the main module, npm.js) 16 | 17 | function whoami (){ 18 | //Code... 19 | console.log ("gagle"); 20 | }; -------------------------------------------------------------------------------- /examples/options.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var argv = require ("../lib").createParser ({ once: true }) 4 | .body () 5 | //Positive flag because it doesn't define the "argument" property 6 | .option ({ short: "a", long: "aaaa" }) 7 | 8 | //Negative flag because it doesn't define the "argument" property 9 | .option ({ long: "b", negate: true }) 10 | 11 | //Option with a mandatory value and null as default value 12 | .option ({ short: "c", metavar: "C" }) 13 | 14 | //Option with a Number type and 0 as default value 15 | //By default the options are strings 16 | .option ({ short: "d", metavar: "D", type: Number }) 17 | 18 | //Option with an Array type and [] as default value 19 | //Array-type values must be comma-separated values, eg: --a 1,a,true 20 | //Each element is converted automatically to the type it represents, 21 | //the previous example is converted to { a: [1, "a", true] } 22 | .option ({ short: "e", metavar: "E", type: Array }) 23 | 24 | //Option with a Boolean type and false as default value 25 | //This type is not very useful because you can just use a flag, eg: 26 | //--a true is converted to { a: true } 27 | .option ({ short: "f", metavar: "F", type: Boolean }) 28 | 29 | //Option with a mandatory value and "gggg" as default value 30 | .option ({ long: "g", metavar: "G", default: "gggg" }) 31 | 32 | //Option with an optional value and null as default value 33 | .option ({ short: "i", metavar: "I", optional: true }) 34 | 35 | //Option with an optional value and "jjjj" as default value 36 | .option ({ long: "j", metavar: "J", default: "jjjj", 37 | optional: true }) 38 | 39 | //Option with a description and reviver 40 | //The reviver receives the string value and returns the new value, 41 | //it's like the json reviver function 42 | .option ({ short: "k", long: "kkkk", metavar: "K", description: "kkkk", 43 | reviver: function (value){ 44 | return value + "foo"; 45 | }}) 46 | 47 | //Hidden option, it isn't printed in the --help and --usage messages 48 | .option ({ short: "l", hidden: true }) 49 | 50 | //Option with an alias 51 | .option ({ short: "m", long: "mm", aliases: ["x"] }) 52 | 53 | //Option with choices 54 | .option ({ short: "n", metavar: "NUM", type: Number, 55 | choices: [1, 10, 100] }) 56 | 57 | .help () 58 | .usage () 59 | .argv (); 60 | 61 | console.log (argv); 62 | 63 | /* 64 | $ node options.js 65 | 66 | { 67 | aaaa: false, 68 | b: true, 69 | c: null, 70 | d: 0, 71 | e: [], 72 | f: false, 73 | g: "gggg", 74 | i: null, 75 | j: "jjjj", 76 | kkkk: null, 77 | l: false, 78 | mm: false, 79 | n: 0, 80 | help: false, 81 | usage: false 82 | } 83 | 84 | -------------------------------------------------------------------------------- 85 | 86 | $ node options.js --help 87 | 88 | Usage: options [options] 89 | 90 | -a, --aaaa 91 | --no-b 92 | -c C 93 | -d D 94 | -e E 95 | -f F 96 | --g=G 97 | -i[I] 98 | --j[=J] 99 | -k, --kkkk=K kkkk 100 | -m, --mm, --x 101 | -n NUM 102 | -h, --help Display this help message and exit 103 | --usage Display a short usage message and exit 104 | 105 | -------------------------------------------------------------------------------- 106 | 107 | $ node options.js --usage 108 | 109 | Usage: options [-c C] [-d D] [-e E] [-f F] [-i[I]] [-n NUM] [-a|--aaaa] [--b] 110 | [--g=G] [--j[=J]] [-k|--kkkk=K] [-m|--mm|--x] [-h|--help] [--usage] 111 | */ -------------------------------------------------------------------------------- /examples/read-package.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | require ("../lib").createParser ({ once: true }) 4 | .readPackage ("../package.json") 5 | //If you use readPackage(), you can write text lines between the ---version 6 | //and the email using the footer() function 7 | .footer ("Sample footer") 8 | .body () 9 | .help () 10 | .usage () 11 | .argv (); 12 | 13 | /* 14 | $ node read-package.js --help 15 | 16 | Usage: read-package [options] 17 | 18 | Command-line option parser 19 | 20 | -h, --help Display this help message and exit 21 | --usage Display a short usage message and exit 22 | -v, --version Output version information and exit 23 | 24 | Report bugs to . 25 | */ -------------------------------------------------------------------------------- /examples/to-upper-case.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* 4 | Converts to upper case any phrase if the -u option is passed. 5 | */ 6 | 7 | require ("../lib").createParser ({ once: true }) 8 | .on ("start", function (argv){ 9 | argv.phrase = []; 10 | }) 11 | .on ("argument", function (argv, argument, ignore){ 12 | argv.phrase.push (argv.u ? argument.toUpperCase () : argument); 13 | 14 | //We don't want to store the words into the final object 15 | ignore (); 16 | }) 17 | .on ("option", function (argv, option, value, long, ignore){ 18 | //We only need the "-u" option, ignore the rest, if any 19 | if (option !== "u") ignore (); 20 | }) 21 | .on ("end", function (argv){ 22 | argv.phrase = argv.phrase.join (" "); 23 | console.log (argv); 24 | }) 25 | .allowUndefinedArguments () 26 | //If "sort" is enabled, the options are parsed before the arguments 27 | .sort () 28 | .body () 29 | .option ({ short: "u" }) 30 | .argv (); 31 | 32 | /* 33 | $ node to-upper-case.js this is a sample text with the -u option 34 | 35 | { 36 | u: true, 37 | phrase: "THIS IS A SAMPLE TEXT WITH THE OPTION" 38 | } 39 | */ -------------------------------------------------------------------------------- /lib/argp.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var events = require ("events"); 4 | var util = require ("util"); 5 | var path = require ("path"); 6 | var fs = require ("fs"); 7 | var wrap = require ("./wrap"); 8 | 9 | var debug = process.argv[1] === "debug"; 10 | var script = path.basename (process.argv[debug ? 2 : 1], ".js"); 11 | var mainScript = script; 12 | 13 | var cast = function (value){ 14 | if (value === "undefined") return undefined; 15 | if (value === "null") return null; 16 | if (value === "true") return true; 17 | if (value === "false") return false; 18 | var v = Number (value); 19 | return isNaN (v) ? value : v; 20 | }; 21 | 22 | var Argp = module.exports = function (options){ 23 | events.EventEmitter.call (this); 24 | 25 | options = options || {}; 26 | 27 | this._once = options.once; 28 | this._exitStatus = 0; 29 | 30 | this._argv = null; 31 | this._argp = null; 32 | this._usages = []; 33 | this._description = null; 34 | this._version = null; 35 | this._email = null; 36 | 37 | this._rePackageEmail = /<(.+)>/; 38 | this._packageVersion = false; 39 | 40 | this._allowUndefinedOptions = false; 41 | this._allowUndefinedArguments = false; 42 | this._sort = false; 43 | this._columns = 80; 44 | this._showHelp = false; 45 | this._showUsage = false; 46 | 47 | this._emitArguments = false; 48 | 49 | this._command = false; 50 | this._commandInstances = {}; 51 | //Shortcuts to the arguments and options of each command 52 | this._commands = {}; 53 | 54 | this._lines = []; 55 | 56 | this._arguments = {}; 57 | this._argumentsArray = []; 58 | 59 | this._options = {}; 60 | this._optionsShort = {}; 61 | this._optionsLong = {}; 62 | 63 | var me = this; 64 | 65 | this._ignore = false; 66 | this._ignoreFn = function (){ 67 | me._ignore = true; 68 | }; 69 | 70 | this._inputError = false; 71 | }; 72 | 73 | util.inherits (Argp, events.EventEmitter); 74 | 75 | Argp.prototype._error = function (str){ 76 | //If an input array is used, don't exit 77 | if (this.listeners ("error").length){ 78 | this._inputError = true; 79 | return this.emit ("error", new Error (str)); 80 | } 81 | 82 | console.error (script + ": " + str); 83 | var error = this._errorTry (); 84 | if (error) console.error (error); 85 | process.exit (this._exitStatus || 1); 86 | }; 87 | 88 | Argp.prototype._errorTry = function (){ 89 | var s = this._command ? script : mainScript; 90 | 91 | var str; 92 | if (this._showHelp && this._showUsage){ 93 | str = "'" + s + " --help' or '" + s + " --usage'"; 94 | }else if (this._showHelp && !this._showUsage){ 95 | str = "'" + s + " --help'"; 96 | }else if (!this._showHelp && this._showUsage){ 97 | str = "'" + s + " --usage'"; 98 | }else if (this._command){ 99 | //If the command doesn't have a help or usage message, show the main help 100 | //and usage 101 | return this._argp._errorTry (); 102 | }else{ 103 | return; 104 | } 105 | 106 | return "Try " + str + " for more information"; 107 | }; 108 | 109 | Argp.prototype._errorChoice = function (value){ 110 | this._error ("Unrecognized choice '" + value + "'"); 111 | }; 112 | 113 | Argp.prototype._errorConvert = function (name, type){ 114 | this._error ("Option '" + name + "' is not a " + type); 115 | }; 116 | 117 | Argp.prototype._errorAbbreviation = function (name){ 118 | this._error ("Option '" + name + "' is ambiguous"); 119 | }; 120 | 121 | Argp.prototype._errorNotExpectedValue = function (name){ 122 | this._errorExpectedValue (name, "not"); 123 | }; 124 | 125 | Argp.prototype._errorExpectedValue = function (name, negate){ 126 | this._error ("Option '" + name + "' " + 127 | (negate ? "does not require" : "requires") + " an argument"); 128 | }; 129 | 130 | Argp.prototype._errorUnrecognizedOption = function (name){ 131 | this._error ("Unrecognized option '" + name + "'"); 132 | }; 133 | 134 | Argp.prototype._errorUnrecognizedArgument = function (name){ 135 | this._error ("Unrecognized argument '" + name + "'"); 136 | }; 137 | 138 | Argp.prototype._errorExpectedCommand = function (name, num, min){ 139 | this._error ("Command '" + name + "' expects " + (min ? min + " " : "") + 140 | num + " argument/s"); 141 | }; 142 | 143 | Argp.prototype._errorEmptyNegatedFlag = function (){ 144 | this._error ("A negated flag must contain a long name, eg. '--no-' is " + 145 | "invalid, '--no-flag' is valid"); 146 | }; 147 | 148 | Argp.prototype._columnize = function (col1, col2){ 149 | var blank = " "; 150 | 151 | var spaces = 30 - col1.length; 152 | if (spaces < 0 && col2){ 153 | col1 += "\n" + blank; 154 | }else{ 155 | for (var i=0; i 1){ 504 | //Assumption: if an undefined option follows the first defined 505 | //no-flag option, the next undefined characters to the first 506 | //defined option are the value of this option 507 | if (!me._optionsShort[str[i + 1]]){ 508 | me._newOption ({ 509 | opt: o, 510 | short: name, 511 | value: str.substring (1) 512 | }); 513 | return; 514 | }else if (o.optional){ 515 | me._newOption ({ 516 | opt: o, 517 | short: name, 518 | value: null 519 | }); 520 | }else{ 521 | //The option requires a value 522 | return me._errorExpectedValue ("-" + name); 523 | } 524 | }else{ 525 | //Wait for the value 526 | option = { 527 | opt: o, 528 | short: name 529 | }; 530 | } 531 | }else if (i < str.length - 1){ 532 | //Options between the first and the last 533 | if (o.optional){ 534 | //No value 535 | me._newOption ({ 536 | opt: o, 537 | short: name 538 | }); 539 | }else{ 540 | //The option requires a value 541 | return me._errorExpectedValue ("-" + name); 542 | } 543 | }else{ 544 | //Last option 545 | //Wait for the value 546 | option = { 547 | opt: o, 548 | short: name 549 | }; 550 | } 551 | } 552 | }else{ 553 | if (!me._allowUndefinedOptions){ 554 | //Undefined option and no undefined allowed 555 | return me._errorUnrecognizedOption ("-" + name); 556 | } 557 | 558 | //Wait for the value 559 | option = { 560 | opt: null, 561 | short: name 562 | }; 563 | } 564 | } 565 | }; 566 | 567 | var argument = function (str){ 568 | //Check for the trailing arguments if this is a command 569 | var curr = me._currentArgument; 570 | 571 | //The arguments of a command have a higher priority than the defined 572 | //arguments, eg: foo 1 bar, where "foo" is a command that expects 2 573 | //arguments and "bar" is a defined argument. In this case, "bar" belongs to 574 | //the "foo"'s arguments: { foo: [1, "bar"], bar: false } 575 | if (me._command && curr){ 576 | me._argv[curr.name].push (cast (str)); 577 | var length = me._argv[curr.name].length; 578 | if (length === curr.trailing.eq || length === curr.trailing.max){ 579 | //Limit reached 580 | me._currentArgument = null; 581 | } 582 | return; 583 | } 584 | 585 | var arg = me._arguments[str]; 586 | 587 | if (!me._allowUndefinedArguments && !arg){ 588 | //Undefined argument and no undefined allowed 589 | return me._errorUnrecognizedArgument (str); 590 | } 591 | 592 | if (me._command && arg && arg.trailing){ 593 | //Store the new argument 594 | me._currentArgument = { 595 | name: str, 596 | trailing: arg.trailing 597 | }; 598 | return; 599 | } 600 | 601 | me._newArgument (str); 602 | }; 603 | 604 | var validateCommand = function (){ 605 | if (!me._command) return; 606 | 607 | var curr = me._currentArgument; 608 | if (curr){ 609 | if (curr.trailing.eq !== undefined){ 610 | return me._errorExpectedCommand (curr.name, curr.trailing.eq); 611 | } 612 | if (me._argv[curr.name].length < curr.trailing.min){ 613 | return me._errorExpectedCommand (curr.name, curr.trailing.min, 614 | "minimum"); 615 | } 616 | } 617 | }; 618 | 619 | var str; 620 | 621 | for (var i=0; i.", 778 | this._columns); 779 | 780 | console.log (h); 781 | //Only exit if the are no error listeners 782 | if (this.listeners ("error").length){ 783 | //Simulate an error to stop parsing the remaining options 784 | this._inputError = true; 785 | }else{ 786 | process.exit (arguments.length === 1 ? code : this._exitStatus); 787 | } 788 | }; 789 | 790 | Argp.prototype.printUsage = function (code){ 791 | var usage = ""; 792 | var prefix = " "; 793 | 794 | //Arguments 795 | if (this._usages.length){ 796 | var s = ""; 797 | for (var i=0; i 1){ 77 | throw new Error ("The short name must be a single character"); 78 | } 79 | //Short names must be alphanumeric characters 80 | var code = o.short.charCodeAt (0); 81 | if (!((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || 82 | (code >= 97 && code <= 122))){ 83 | throw new Error ("The short name must be an alphanumeric character"); 84 | } 85 | //Cannot be already defined 86 | for (var p in this._instance._optionsShort){ 87 | if (p === o.short){ 88 | throw new Error ("The short name \"" + o.short + "\" is already " + 89 | "defined"); 90 | } 91 | } 92 | } 93 | 94 | if (o.aliases){ 95 | var me = this; 96 | o.aliases.forEach (function (alias){ 97 | //Cannot be already defined 98 | if (alias === o.long) throw new Error ("The alias name \"" + alias + 99 | "\" is already defined"); 100 | 101 | for (var p in me._instance._optionsLong){ 102 | if (p === alias){ 103 | throw new Error ("The alias name \"" + alias + "\" is already " + 104 | "defined"); 105 | } 106 | } 107 | }); 108 | } 109 | 110 | this._instance._option (o); 111 | 112 | return this; 113 | }; 114 | 115 | Body.prototype.text = function (str, prefix){ 116 | this._instance._option ({ 117 | text: str, 118 | prefix: prefix 119 | }); 120 | return this; 121 | }; 122 | 123 | Body.prototype.usage = function (){ 124 | this._instance._showUsage = true; 125 | var opt = { 126 | long: "usage", 127 | description: "Display a short usage message" 128 | }; 129 | if (!this._instance.listeners ("error").length){ 130 | opt.description += " and exit"; 131 | } 132 | this._instance._option (opt); 133 | return this; 134 | }; 135 | 136 | Body.prototype.version = function (str, o){ 137 | this._instance._packageVersion = false; 138 | this._instance._version = str + ""; 139 | var short = !(o && o.short === false); 140 | var opt = {}; 141 | if (short) opt.short = "v"; 142 | opt.long = "version"; 143 | opt.description = "Output version information"; 144 | if (!this._instance.listeners ("error").length){ 145 | opt.description += " and exit"; 146 | } 147 | this._instance._option (opt); 148 | return this; 149 | }; -------------------------------------------------------------------------------- /lib/command.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var util = require ("util"); 4 | var Argp = require ("./argp"); 5 | 6 | var Command = module.exports = function (argp, name, o){ 7 | Argp.call (this); 8 | 9 | o = o || {}; 10 | Command._validateTrailing (o.trailing); 11 | 12 | this._command = true; 13 | this._argp = argp; 14 | this._name = name; 15 | this._trailing = o.trailing; 16 | }; 17 | 18 | util.inherits (Command, Argp); 19 | 20 | Command._validateTrailing = function (trailing){ 21 | if (!trailing) return; 22 | 23 | var eq = trailing.eq !== undefined; 24 | var min = trailing.min !== undefined; 25 | var max = trailing.max !== undefined; 26 | 27 | if (eq && (min || max)){ 28 | throw new Error ("Cannot configure \"trailing.eq\" along with " + 29 | "\"trailing.min\" or \"trailing.max\""); 30 | } 31 | 32 | if (eq && trailing.eq < 1){ 33 | throw new Error ("\"trailing.eq\" must be greater than 1"); 34 | } 35 | if (min && trailing.min < 0){ 36 | throw new Error ("\"trailing.min\" must be greater than 1"); 37 | } 38 | if (max && trailing.max < 1){ 39 | throw new Error ("\"trailing.max\" must be greater than 1", 2); 40 | } 41 | 42 | if (min && max){ 43 | if (trailing.min === trailing.max){ 44 | trailing.eq = min; 45 | delete trailing.min; 46 | delete trailing.max; 47 | }else if (trailing.min > trailing.max){ 48 | throw new Error ("\"trailing.max\" must be greater or equal than " + 49 | "\"trailing.min\""); 50 | } 51 | } 52 | if (!min){ 53 | trailing.min = 0; 54 | } 55 | if (!max){ 56 | trailing.max = Infinity; 57 | } 58 | }; 59 | 60 | //Forward to the main Argp instance 61 | Command.prototype.argv = function (input){ 62 | return this._argp.argv.call (this._argp, input); 63 | }; 64 | 65 | //Forward to the main Argp instance 66 | Command.prototype.command = function (){ 67 | return this._argp.command.apply (this._argp, arguments); 68 | }; 69 | 70 | //Forward to the main Argp instance 71 | Command.prototype.commands = function (){ 72 | return this._argp.commands.apply (this._argp, arguments); 73 | }; 74 | 75 | Command.prototype.main = function (){ 76 | return this._argp; 77 | }; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var Argp = require ("./argp"); 4 | 5 | module.exports.createParser = function (options){ 6 | return new Argp (options); 7 | }; -------------------------------------------------------------------------------- /lib/wrap.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | //Based on Apache Commons WordUtils's wrap() function 4 | 5 | module.exports = function (str, columns, prefix, prefixAlways){ 6 | prefix = prefix || ""; 7 | var lines = ""; 8 | var first = true; 9 | var newColumns = columns - prefix.length; 10 | if (prefixAlways){ 11 | columns = newColumns; 12 | } 13 | 14 | str.split (/\r\n|\n/).forEach (function (line){ 15 | var lineLength = line.length; 16 | var offset = 0; 17 | var wrapOffset; 18 | 19 | while (lineLength - offset > columns){ 20 | if (prefixAlways || !first) lines += prefix; 21 | 22 | if (line[offset] === " "){ 23 | offset++; 24 | continue; 25 | } 26 | 27 | wrapOffset = line.lastIndexOf (" ", columns + offset); 28 | if (wrapOffset >= offset){ 29 | lines += line.substring (offset, wrapOffset) + "\n"; 30 | offset = wrapOffset + 1; 31 | }else{ 32 | wrapOffset = line.indexOf (" ", columns + offset); 33 | if (wrapOffset >= 0){ 34 | lines += line.substring (offset, wrapOffset) + "\n"; 35 | offset = wrapOffset + 1; 36 | }else{ 37 | lines += line.substring (offset); 38 | offset = lineLength; 39 | } 40 | } 41 | 42 | if (!prefixAlways && first){ 43 | columns = newColumns; 44 | first = false; 45 | } 46 | } 47 | 48 | lines += (!prefixAlways && first ? "" : prefix) + 49 | line.substring (offset) + "\n"; 50 | first = false; 51 | }); 52 | 53 | return lines.substring (0, lines.length - 1); 54 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "argp", 3 | "version": "1.0.4", 4 | "description": "Command-line option parser", 5 | "keywords": ["cli", "options", "parser", "commands", "arguments", "getopt", 6 | "argparse"], 7 | "author": "Gabriel Llamas ", 8 | "repository": "git://github.com/gagle/node-argp.git", 9 | "engines": { 10 | "node": ">=0.10" 11 | }, 12 | "scripts": { 13 | "test": "node test/index" 14 | }, 15 | "license": "MIT", 16 | "main": "lib" 17 | } -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var assert = require ("assert"); 4 | var argp = require ("../lib"); 5 | 6 | var debug = process.argv[1] === "debug"; 7 | 8 | var argv = function (arr){ 9 | process.argv = ["node", __filename].concat (arr); 10 | }; 11 | 12 | var n = function (){ 13 | return argp.createParser (); 14 | }; 15 | 16 | var a = function (){ 17 | return argp.createParser ().allowUndefinedArguments () 18 | .allowUndefinedOptions (); 19 | }; 20 | 21 | console.error = function (){}; 22 | 23 | process.exit = function (){ 24 | throw new Error (); 25 | }; 26 | 27 | var opts; 28 | 29 | var tests = { 30 | "empty required value": function (){ 31 | assert.doesNotThrow (function (){ 32 | argv (["--a="]); 33 | opts = a ().argv (); 34 | assert.strictEqual (opts.a, null); 35 | }); 36 | }, 37 | "type conversion, no configuration": function (){ 38 | assert.doesNotThrow (function (){ 39 | argv (["--a=undefined", "--b=null", "--c=true", "--d=false", "--e=12", 40 | "--f=12.34", "--g=asd"]); 41 | opts = a ().argv (); 42 | assert.strictEqual (opts.a, undefined); 43 | assert.strictEqual (opts.b, null); 44 | assert.strictEqual (opts.c, true); 45 | assert.strictEqual (opts.d, false); 46 | assert.strictEqual (opts.e, 12); 47 | assert.strictEqual (opts.f, 12.34); 48 | assert.strictEqual (opts.g, "asd"); 49 | }); 50 | }, 51 | "type conversion, configuration": function (){ 52 | assert.doesNotThrow (function (){ 53 | argv (["--a=b", "--b=", "--c=12.34", "--d=", "--e=true", "--f=", 54 | "--g=1,true,a", "--h=", "--i", "-12.34", "--j", "-1.2,foo", "--k", 55 | "1", "--k", "true,foo"]); 56 | opts = n ().body () 57 | .option ({ long: "a", metavar: true }) 58 | .option ({ long: "b", metavar: true }) 59 | .option ({ long: "c", metavar: true, type: Number }) 60 | .option ({ long: "d", metavar: true, type: Number }) 61 | .option ({ long: "e", metavar: true, type: Boolean }) 62 | .option ({ long: "f", metavar: true, type: Boolean }) 63 | .option ({ long: "g", metavar: true, type: Array }) 64 | .option ({ long: "h", metavar: true, type: Array }) 65 | .option ({ long: "i", metavar: true, type: Number }) 66 | .option ({ long: "j", metavar: true, type: Array }) 67 | .option ({ long: "k", metavar: true, type: Array }) 68 | .argv (); 69 | assert.strictEqual (opts.a, "b"); 70 | assert.strictEqual (opts.b, null); 71 | assert.strictEqual (opts.c, 12.34); 72 | assert.strictEqual (opts.d, 0); 73 | assert.strictEqual (opts.e, true); 74 | assert.strictEqual (opts.f, false); 75 | assert.strictEqual (opts.g[0], 1); 76 | assert.strictEqual (opts.g[1], true); 77 | assert.strictEqual (opts.g[2], "a"); 78 | assert.deepEqual (opts.h, []); 79 | assert.strictEqual (opts.i, -12.34); 80 | assert.strictEqual (opts.j[0], -1.2); 81 | assert.strictEqual (opts.j[1], "foo"); 82 | assert.strictEqual (opts.k[0], 1); 83 | assert.strictEqual (opts.k[1], true); 84 | assert.strictEqual (opts.k[2], "foo"); 85 | }); 86 | 87 | assert.throws (function (){ 88 | argv (["--a=b"]); 89 | n ().body () 90 | .option ({ long: "a", metavar: true, type: Number }) 91 | .argv (); 92 | }); 93 | 94 | assert.throws (function (){ 95 | argv (["--a=b"]); 96 | n ().body () 97 | .option ({ long: "a", metavar: true, type: Boolean }) 98 | .argv (); 99 | }); 100 | }, 101 | "abbreviations": function (){ 102 | assert.doesNotThrow (function (){ 103 | argv (["--a"]); 104 | opts = n ().body () 105 | .option ({ long: "aa" }) 106 | .argv (); 107 | assert.deepEqual (opts, { 108 | aa: true 109 | }); 110 | 111 | argv (["--a", "b"]); 112 | opts = n ().body () 113 | .option ({ long: "abc", metavar: true }) 114 | .argv (); 115 | assert.deepEqual (opts, { 116 | abc: "b" 117 | }); 118 | }); 119 | 120 | assert.throws (function (){ 121 | argv (["--a"]); 122 | n ().body () 123 | .option ({ long: "a1" }) 124 | .option ({ long: "a2" }) 125 | .argv (); 126 | }); 127 | }, 128 | "no configuration, nothing": function (){ 129 | assert.doesNotThrow (function (){ 130 | argv ([]); 131 | 132 | opts = a ().argv (); 133 | assert.deepEqual (opts, {}); 134 | 135 | opts = a ().body () 136 | .help () 137 | .usage () 138 | .argv (); 139 | assert.deepEqual (opts, { 140 | help: false, 141 | usage: false 142 | }); 143 | }); 144 | }, 145 | "no configuration, long": function (){ 146 | assert.doesNotThrow (function (){ 147 | argv (["--a"]); 148 | opts = a ().argv (); 149 | assert.deepEqual (opts, { 150 | a: true 151 | }); 152 | 153 | argv (["--a", "--b"]); 154 | opts = a ().argv (); 155 | assert.deepEqual (opts, { 156 | a: true, 157 | b: true 158 | }); 159 | 160 | argv (["--a", "--b", "--c"]); 161 | opts = a ().argv (); 162 | assert.deepEqual (opts, { 163 | a: true, 164 | b: true, 165 | c: true 166 | }); 167 | 168 | argv (["--a", "b", "--c", "d"]); 169 | opts = a ().argv (); 170 | assert.deepEqual (opts, { 171 | a: "b", 172 | c: "d" 173 | }); 174 | 175 | argv (["--a", "--b-c", "--1", "2"]); 176 | opts = a ().argv (); 177 | assert.deepEqual (opts, { 178 | a: true, 179 | "b-c": true, 180 | "1": 2 181 | }); 182 | assert.strictEqual (opts["1"], 2); 183 | 184 | argv (["--a=--b", "--b=c", "--1"]); 185 | opts = a ().argv (); 186 | assert.deepEqual (opts, { 187 | a: "--b", 188 | b: "c", 189 | "1": true 190 | }); 191 | 192 | argv (["--no-a", "--b", "1"]); 193 | opts = a ().argv (); 194 | assert.deepEqual (opts, { 195 | a: false, 196 | b: 1 197 | }); 198 | assert.strictEqual (opts.b, 1); 199 | }); 200 | }, 201 | "no configuration, short": function (){ 202 | assert.doesNotThrow (function (){ 203 | argv (["-a"]); 204 | opts = a ().argv (); 205 | assert.deepEqual (opts, { 206 | a: true 207 | }); 208 | 209 | argv (["-a", "-b"]); 210 | opts = a ().argv (); 211 | assert.deepEqual (opts, { 212 | a: true, 213 | b: true 214 | }); 215 | 216 | argv (["-a", "-b", "-c"]); 217 | opts = a ().argv (); 218 | assert.deepEqual (opts, { 219 | a: true, 220 | b: true, 221 | c: true 222 | }); 223 | 224 | argv (["-a", "b", "-c", "d"]); 225 | opts = a ().argv (); 226 | assert.deepEqual (opts, { 227 | a: "b", 228 | c: "d" 229 | }); 230 | 231 | argv (["-a", "-b-c", "-1", "2"]); 232 | opts = a ().argv (); 233 | assert.deepEqual (opts, { 234 | a: true, 235 | "b": true, 236 | "-": true, 237 | "c": true, 238 | "1": 2 239 | }); 240 | assert.strictEqual (opts["1"], 2); 241 | 242 | argv (["-abc", "d", "-ef"]); 243 | opts = a ().argv (); 244 | assert.deepEqual (opts, { 245 | a: true, 246 | b: true, 247 | c: "d", 248 | e: true, 249 | f: true 250 | }); 251 | }); 252 | }, 253 | "no configuration, arguments": function (){ 254 | assert.doesNotThrow (function (){ 255 | argv (["a"]); 256 | opts = a ().argv (); 257 | assert.deepEqual (opts, { 258 | a: true 259 | }); 260 | 261 | argv (["a", "b"]); 262 | opts = a ().argv (); 263 | assert.deepEqual (opts, { 264 | a: true, 265 | b: true 266 | }); 267 | 268 | argv (["-a", "b", "c"]); 269 | opts = a ().argv (); 270 | assert.deepEqual (opts, { 271 | a: "b", 272 | c: true 273 | }); 274 | 275 | argv (["a", "-b", "c"]); 276 | opts = a ().argv (); 277 | assert.deepEqual (opts, { 278 | a: true, 279 | b: "c" 280 | }); 281 | 282 | argv (["-a", "--", "b", "c"]); 283 | opts = a ().argv (); 284 | assert.deepEqual (opts, { 285 | a: true, 286 | b: true, 287 | c: true 288 | }); 289 | }); 290 | }, 291 | "no configuration, miscellaneous": function (){ 292 | assert.doesNotThrow (function (){ 293 | argv (["--a", "-", "-b", "-", "-", "-1"]); 294 | opts = a ().argv (); 295 | assert.deepEqual (opts, { 296 | a: "-", 297 | b: "-", 298 | "-": true, 299 | "1": true 300 | }); 301 | 302 | argv (["-"]); 303 | opts = a ().argv (); 304 | assert.deepEqual (opts, { 305 | "-": true 306 | }); 307 | 308 | argv (["--"]); 309 | opts = a ().argv (); 310 | assert.deepEqual (opts, {}); 311 | 312 | argv (["--", "-", "--"]); 313 | opts = a ().argv (); 314 | assert.deepEqual (opts, { 315 | "-": true, 316 | "--": true 317 | }); 318 | 319 | argv (["--a", "--", "--b"]); 320 | opts = a ().argv (); 321 | assert.deepEqual (opts, { 322 | a: true, 323 | "--b": true 324 | }); 325 | 326 | argv (["-a", "--", "-b"]); 327 | opts = a ().argv (); 328 | assert.deepEqual (opts, { 329 | a: true, 330 | "-b": true 331 | }); 332 | }); 333 | }, 334 | "configuration, no undefined": function (){ 335 | assert.throws (function (){ 336 | argv (["-a"]); 337 | n ().argv (); 338 | }); 339 | 340 | assert.throws (function (){ 341 | argv (["--a"]); 342 | n ().argv (); 343 | }); 344 | 345 | assert.throws (function (){ 346 | argv (["--no-a"]); 347 | n ().argv (); 348 | }); 349 | 350 | assert.throws (function (){ 351 | argv (["a"]); 352 | n ().argv (); 353 | }); 354 | }, 355 | "configuration, default values": function (){ 356 | assert.doesNotThrow (function (){ 357 | argv ([]); 358 | opts = n ().body () 359 | .argument ("a") 360 | .option ({ long: "b", short: "x" }) 361 | .option ({ long: "c", negate: true }) 362 | .option ({ short: "d", metavar: true, default: "a" }) 363 | .option ({ short: "e", metavar: true, optional: true }) 364 | .argv (); 365 | assert.deepEqual (opts, { 366 | a: false, 367 | b: false, 368 | c: true, 369 | d: "a", 370 | e: null 371 | }); 372 | }); 373 | }, 374 | "configuration, long": function (){ 375 | assert.doesNotThrow (function (){ 376 | argv (["--a"]); 377 | opts = n ().body () 378 | .option ({ long: "a" }) 379 | .argv (); 380 | assert.deepEqual (opts, { 381 | a: true 382 | }); 383 | 384 | argv (["--a"]); 385 | opts = n ().body () 386 | .option ({ long: "a", negate: true }) 387 | .argv (); 388 | assert.deepEqual (opts, { 389 | a: true 390 | }); 391 | 392 | argv (["--no-a"]); 393 | opts = n ().body () 394 | .option ({ long: "a", negate: true }) 395 | .argv (); 396 | assert.deepEqual (opts, { 397 | a: false 398 | }); 399 | 400 | argv (["--no-no-"]); 401 | opts = n ().body () 402 | .option ({ long: "no-" }) 403 | .argv (); 404 | assert.deepEqual (opts, { 405 | "no-": false 406 | }); 407 | 408 | argv (["-a"]); 409 | opts = n ().body () 410 | .option ({ short: "a", long: "abc", negate: true }) 411 | .argv (); 412 | assert.deepEqual (opts, { 413 | abc: false 414 | }); 415 | 416 | argv (["--no-a"]); 417 | opts = n ().body () 418 | .option ({ long: "a" }) 419 | .argv (); 420 | assert.deepEqual (opts, { 421 | a: false 422 | }); 423 | 424 | argv (["--a", "b"]); 425 | opts = n ().body () 426 | .argument ("b") 427 | .option ({ long: "a" }) 428 | .argv (); 429 | assert.deepEqual (opts, { 430 | a: true, 431 | b: true 432 | }); 433 | 434 | argv (["--a", "b"]); 435 | opts = n ().body () 436 | .option ({ long: "a", metavar: true }) 437 | .argv (); 438 | assert.deepEqual (opts, { 439 | a: "b" 440 | }); 441 | 442 | argv (["--a"]); 443 | opts = n ().body () 444 | .option ({ long: "a", metavar: true, optional: true }) 445 | .argv (); 446 | assert.deepEqual (opts, { 447 | a: null 448 | }); 449 | 450 | argv (["--a=b", "--b"]); 451 | opts = n ().body () 452 | .option ({ long: "a", metavar: true }) 453 | .option ({ long: "b" }) 454 | .argv (); 455 | assert.deepEqual (opts, { 456 | a: "b", 457 | b: true 458 | }); 459 | 460 | argv (["--no-a"]); 461 | opts = n ().body () 462 | .option ({ long: "abc", negate: true }) 463 | .argv (); 464 | assert.deepEqual (opts, { 465 | abc: false 466 | }); 467 | 468 | argv (["--a", "--b", "--c", "--d"]); 469 | opts = n ().body () 470 | .option ({ long: "a", metavar: true, optional: true }) 471 | .option ({ long: "b", metavar: true, optional: true, 472 | type: Number }) 473 | .option ({ long: "c", metavar: true, optional: true, 474 | type: Array }) 475 | .option ({ long: "d", metavar: true, optional: true, 476 | type: Boolean }) 477 | .argv (); 478 | assert.strictEqual (opts.a, null); 479 | assert.strictEqual (opts.b, 0); 480 | assert.deepEqual (opts.c, []); 481 | assert.strictEqual (opts.d, false); 482 | 483 | argv (["--b"]); 484 | opts = n ().body () 485 | .option ({ long: "a", aliases: ["b"] }) 486 | .argv (); 487 | assert.deepEqual (opts, { 488 | a: true 489 | }); 490 | 491 | argv (["--a", "b"]); 492 | opts = n ().body () 493 | .option ({ long: "a", metavar: true, choices: ["b"] }) 494 | .argv (); 495 | assert.deepEqual (opts, { 496 | a: "b" 497 | }); 498 | 499 | argv (["--a", "1"]); 500 | opts = n ().body () 501 | .option ({ long: "a", metavar: true, type: Number, choices: [1] }) 502 | .argv (); 503 | assert.strictEqual (opts.a, 1); 504 | 505 | argv (["--a"]); 506 | opts = n ().body () 507 | .option ({ long: "a", metavar: true, type: Number, optional: true, 508 | choices: [1] }) 509 | .argv (); 510 | assert.strictEqual (opts.a, 0); 511 | }); 512 | 513 | assert.throws (function (){ 514 | argv (["--no-"]); 515 | n ().body ().argv (); 516 | }); 517 | 518 | assert.throws (function (){ 519 | argv (["--a=b"]); 520 | n ().body () 521 | .option ({ long: "a" }) 522 | .argv (); 523 | }); 524 | 525 | assert.throws (function (){ 526 | argv (["--a"]); 527 | n ().body () 528 | .option ({ long: "a", metavar: true }) 529 | .argv (); 530 | }); 531 | 532 | assert.throws (function (){ 533 | argv (["--a", "--b"]); 534 | n ().body () 535 | .option ({ long: "a", metavar: true }) 536 | .argv (); 537 | }); 538 | 539 | assert.throws (function (){ 540 | argv (["--a"]); 541 | n ().body () 542 | .option ({ long: "a12" }) 543 | .option ({ long: "a34" }) 544 | .argv (); 545 | }); 546 | 547 | assert.throws (function (){ 548 | argv (["--a=2"]); 549 | n ().body () 550 | .option ({ long: "a", metavar: true, type: Number, choices: [1] }) 551 | .argv (); 552 | }); 553 | }, 554 | "configuration, short": function (){ 555 | assert.doesNotThrow (function (){ 556 | argv (["-a"]); 557 | opts = n ().body () 558 | .option ({ short: "a" }) 559 | .argv (); 560 | assert.deepEqual (opts, { 561 | a: true 562 | }); 563 | 564 | argv (["-a", "b"]); 565 | opts = n ().body () 566 | .argument ("b") 567 | .option ({ short: "a" }) 568 | .argv (); 569 | assert.deepEqual (opts, { 570 | a: true, 571 | b: true 572 | }); 573 | 574 | argv (["-a", "b"]); 575 | opts = n ().body () 576 | .option ({ short: "a", metavar: true }) 577 | .argv (); 578 | assert.deepEqual (opts, { 579 | a: "b" 580 | }); 581 | 582 | argv (["-a"]); 583 | opts = n ().body () 584 | .option ({ short: "a", metavar: true, optional: true }) 585 | .argv (); 586 | assert.deepEqual (opts, { 587 | a: null 588 | }); 589 | 590 | argv (["-ab", "-c"]); 591 | opts = n ().body () 592 | .option ({ short: "a", metavar: true }) 593 | .option ({ short: "c" }) 594 | .argv (); 595 | assert.deepEqual (opts, { 596 | a: "b", 597 | c: true 598 | }); 599 | 600 | argv (["-abc", "-d"]); 601 | opts = n ().body () 602 | .option ({ short: "a", metavar: true }) 603 | .option ({ short: "d" }) 604 | .argv (); 605 | assert.deepEqual (opts, { 606 | a: "bc", 607 | d: true 608 | }); 609 | 610 | argv (["-abc", "d"]); 611 | opts = n ().allowUndefinedOptions ().body () 612 | .option ({ short: "a" }) 613 | .option ({ short: "b" }) 614 | .argv (); 615 | assert.deepEqual (opts, { 616 | a: true, 617 | b: true, 618 | c: "d" 619 | }); 620 | 621 | argv (["-abcd", "e"]); 622 | opts = n ().allowUndefinedOptions ().body () 623 | .option ({ short: "a" }) 624 | .option ({ short: "b" }) 625 | .argv (); 626 | assert.deepEqual (opts, { 627 | a: true, 628 | b: true, 629 | c: true, 630 | d: "e" 631 | }); 632 | 633 | argv (["-abc", "b"]); 634 | opts = n ().body () 635 | .option ({ short: "a" }) 636 | .option ({ short: "b" }) 637 | .option ({ short: "c", metavar: true }) 638 | .argv (); 639 | assert.deepEqual (opts, { 640 | a: true, 641 | b: true, 642 | c: "b" 643 | }); 644 | 645 | argv (["-abc", "d"]); 646 | opts = n ().allowUndefinedArguments ().body () 647 | .option ({ short: "a" }) 648 | .option ({ short: "b" }) 649 | .option ({ short: "c" }) 650 | .argv (); 651 | assert.deepEqual (opts, { 652 | a: true, 653 | b: true, 654 | c: true, 655 | d: true 656 | }); 657 | 658 | argv (["-abc", "b"]); 659 | opts = n ().body () 660 | .option ({ short: "a", metavar: true, optional: true }) 661 | .option ({ short: "b", metavar: true, optional: true }) 662 | .option ({ short: "c", metavar: true }) 663 | .argv (); 664 | assert.deepEqual (opts, { 665 | a: null, 666 | b: null, 667 | c: "b" 668 | }); 669 | 670 | argv (["-ab"]); 671 | opts = n ().body () 672 | .option ({ short: "a", metavar: true, optional: true }) 673 | .option ({ short: "b" }) 674 | .argv (); 675 | assert.deepEqual (opts, { 676 | a: null, 677 | b: true 678 | }); 679 | }); 680 | 681 | assert.throws (function (){ 682 | argv (["-a"]); 683 | opts = n ().body () 684 | .option ({ short: "a", negate: true }) 685 | .argv (); 686 | assert.deepEqual (opts, { 687 | a: true 688 | }); 689 | }); 690 | 691 | assert.throws (function (){ 692 | argv (["-ab"]); 693 | n ().body () 694 | .option ({ short: "a", metavar: "a" }) 695 | .option ({ short: "b" }) 696 | .argv (); 697 | }); 698 | 699 | assert.throws (function (){ 700 | argv (["-ab"]); 701 | n ().body () 702 | .option ({ short: "a", metavar: "a" }) 703 | .option ({ short: "b", metavar: "a" }) 704 | .argv (); 705 | }); 706 | 707 | assert.throws (function (){ 708 | argv (["-ab", "--c"]); 709 | n ().body () 710 | .option ({ short: "a", metavar: "a" }) 711 | .option ({ short: "b", metavar: "a" }) 712 | end ().argv (); 713 | }); 714 | 715 | assert.throws (function (){ 716 | argv (["-abc"]); 717 | n ().body () 718 | .option ({ short: "a" }) 719 | .option ({ short: "b", metavar: "a" }) 720 | end ().argv (); 721 | }); 722 | }, 723 | "configuration, arguments": function (){ 724 | assert.doesNotThrow (function (){ 725 | argv (["--c", "a", "c"]); 726 | opts = n ().allowUndefinedOptions ().body () 727 | .argument ("a") 728 | .argv (); 729 | assert.deepEqual (opts, { 730 | c: "c", 731 | a: true 732 | }); 733 | }); 734 | }, 735 | "command, trailing error check": function (){ 736 | assert.throws (function (){ 737 | n ().command ("a", { trailing: { eq: 1, min: 2 } }); 738 | }); 739 | 740 | assert.throws (function (){ 741 | n ().command ("a", { trailing: { eq: 1, max: 2 } }); 742 | }); 743 | 744 | assert.throws (function (){ 745 | n ().command ("a", { trailing: { eq: 0 } }); 746 | }); 747 | 748 | assert.throws (function (){ 749 | n ().command ("a", { trailing: { min: -1 } }); 750 | }); 751 | 752 | assert.throws (function (){ 753 | n ().command ("a", { trailing: { max: 0 } }); 754 | }); 755 | 756 | assert.throws (function (){ 757 | n ().command ("a", { trailing: { min: 2, max: 1 } }); 758 | }); 759 | 760 | assert.throws (function (){ 761 | argv (["a"]); 762 | n ().command ("a", { trailing: { eq: 1 } }).argv (); 763 | }); 764 | 765 | assert.throws (function (){ 766 | argv (["a"]); 767 | n ().command ("a", { trailing: { min: 1 } }).argv (); 768 | }); 769 | }, 770 | "command": function (){ 771 | assert.doesNotThrow (function (){ 772 | argv (["a", "1"]); 773 | opts = n ().command ("a", { trailing: { eq: 1 } }).body () 774 | .argument ("b", { trailing: { eq: 1 } }) 775 | .argument ("c") 776 | .argv (); 777 | assert.deepEqual (opts, { 778 | a: [1], 779 | b: [], 780 | c: false 781 | }); 782 | }); 783 | 784 | assert.doesNotThrow (function (){ 785 | argv (["a", "1", "b", "2", "c"]); 786 | opts = n ().command ("a", { trailing: { eq: 1 } }).body () 787 | .argument ("b", { trailing: { eq: 1 } }) 788 | .argument ("c") 789 | .argv (); 790 | assert.deepEqual (opts, { 791 | a: [1], 792 | b: [2], 793 | c: true 794 | }); 795 | }); 796 | 797 | assert.doesNotThrow (function (){ 798 | argv (["a", "1"]); 799 | opts = n ().command ("a", { trailing: { max: 2 } }).argv (); 800 | assert.deepEqual (opts, { 801 | a: [1], 802 | }); 803 | }); 804 | 805 | assert.doesNotThrow (function (){ 806 | argv (["a", "1", "2", "b", "1", "2", "3"]); 807 | opts = n ().command ("a", { trailing: { max: 2 } }).body () 808 | .argument ("b", { trailing: {} }) 809 | .argv (); 810 | assert.deepEqual (opts, { 811 | a: [1, 2], 812 | b: [1, 2, 3] 813 | }); 814 | }); 815 | 816 | assert.doesNotThrow (function (){ 817 | argv (["b", "1", "c"]); 818 | opts = n () 819 | .command ("a", { trailing: { max: 2 } }).body () 820 | .argument ("b", { trailing: {} }) 821 | 822 | .command ("b", { trailing: { eq: 1 } }).body () 823 | .argument ("c", { trailing: {} }) 824 | 825 | .argv (); 826 | assert.deepEqual (opts, { 827 | b: [1], 828 | c: [] 829 | }); 830 | }); 831 | 832 | assert.doesNotThrow (function (){ 833 | argv (["a", "b", "c"]); 834 | opts = n () 835 | .command ("a").body () 836 | .argument ("b", { trailing: {} }) 837 | 838 | .argv (); 839 | assert.deepEqual (opts, { 840 | a: [], 841 | b: ["c"] 842 | }); 843 | }); 844 | 845 | assert.doesNotThrow (function (){ 846 | argv (["a", "1", "b", "2"]); 847 | opts = n () 848 | .command ("a", { trailing: { eq: 1 } }).body () 849 | .argument ("b", { trailing: { eq: 1 } }) 850 | 851 | .argv (); 852 | assert.deepEqual (opts, { 853 | a: [1], 854 | b: [2] 855 | }); 856 | }); 857 | }, 858 | "input array": function (){ 859 | assert.doesNotThrow (function (){ 860 | opts = a ().argv (["--a", "b", "--c", "d"]); 861 | assert.deepEqual (opts, { 862 | a: "b", 863 | c: "d" 864 | }); 865 | 866 | opts = a ().body ().argv (["--a", "b", "--c", "d"]); 867 | assert.deepEqual (opts, { 868 | a: "b", 869 | c: "d" 870 | }); 871 | 872 | opts = a ().command ("a").argv (["--a", "b", "--c", "d"]); 873 | assert.deepEqual (opts, { 874 | a: "b", 875 | c: "d" 876 | }); 877 | }); 878 | } 879 | }; 880 | 881 | for (var test in tests){ 882 | tests[test] (); 883 | } --------------------------------------------------------------------------------