diff --git a/README.md b/README.md index 46b1c27..0134bdd 100644 --- a/README.md +++ b/README.md @@ -120,10 +120,10 @@ $ npm install ig-argv ## Basics -Create a script and make it runnable +Create a [bare.js](./examples/bare.js) script and make it runnable ```shell -$ touch script.js -$ chmod +x script.js +$ touch bare.js +$ chmod +x bare.js ``` Now for the code @@ -150,25 +150,37 @@ __filename == require.main.filename This will already create a script that can respond to `-help` and freinds. ```shell -$ ./script.js --help -Usage: script.js [OPTIONS] +$ ./bare.js --help +Usage: bare.js [OPTIONS] Options: -h, --help - print this message and exit - -v, --version - show script.js verion and exit + -v, --version - show bare.js verion and exit -q, --quiet - quiet mode - - stop processing arguments after this point ``` ## Options in more detail -Let us populate the option definitions splitting the job into sections. +Start by creating an [`options.js`](./examples/options.js) script... +```shell +$ touch options.js +$ chmod +x options.js +``` -Start by creating a parser... +...and a parser: ```javascript +#!/usr/bin/env node + +// compatible with both node's and RequireJS' require(..) +var argv = require('ig-argv') + var parser = argv.Parser({ ``` +Now let us populate the option definitions splitting the job into sections. + + ### Help and metadata Basic script description @@ -222,7 +234,7 @@ present in the command-line. // a required option... '-required': { - doc: 'set .required_option_given to true' + doc: 'set .required_option_given to true', // NOTE: we can omit the VALUE part to not require a value... // NOTE: of no attr is specified in arg option name is used. @@ -409,21 +421,22 @@ The `` will call different sets of callbacks on different stop condition - [`.then(..)`](./ADVANCED.md#parserthen) for normal exit ```javascript .then(function(unhandled, root_value, rest){ - console.log('finished normally.') + console.log('### finished normally.') + console.log(this) }) ``` - [`.stop(..)`](./ADVANCED.md#parserstop) when parser is stopped ```javascript .stop(function(arg, rest){ - console.log(`stopped at ${arg}.`) + console.log(`### stopped at ${arg}.`) }) ``` - [`.stop(..)`](./ADVANCED.md#parserstop) when an error is detected ```javascript .error(function(reason, arg, rest){ - console.log(`something went wrong when parsing ${arg}.`) + console.log(`### something went wrong when parsing ${arg}.`) }) ``` @@ -432,18 +445,110 @@ The `` will call different sets of callbacks on different stop condition This will create a parser that supports the following: ```shell -$ ./script.js --help +$ ./options.js --help +Usage: options.js [OPTIONS] -$ ./script.js --value 321 +Example script options -$ ./script.js --value=321 +Options: + -h, --help - print this message and exit + -v, --version - show options.js verion and exit + -q, --quiet - quiet mode + -r, --required - set .required_option_given to true + (Required) + --default=VALUE - option with default value + (Default: some value) + --bool - if given set .bool to true + --value=X - set .x to X + --int=INT - pass an integer value + --home=HOME - set home path + (Env: $HOME) + -p, --push=ELEM - push elements to a .list + -c - command + --active - basic active option + -s, --shorthand-active - shorthand-active + --then - then + --stop - stop + --error - error + --silent-error - silent-error + --critical-error - critical-error + - - stop processing arguments after this point -$ ./script.js command +Commands: + command - command + nested - nested -$ ./script.js nested -h +Written by John Smith (2.8.1 / BSD-3-Clause). +### stopped at --help. +``` -$ ./script.js -fb +Required argument handling +```shell +$ ./options.js +options.js: ParserError: required but missing: -required +### something went wrong when parsing -required. +``` +```shell +$ ./options.js -r +### finished normally. +Parser { + ... + required_option_given: true, + default: 'some value', + home: true +} +``` + +Passing values implicitly +```shell +$ ./script.js -r --value 321 +### finished normally. +Parser { + ... + required_option_given: true, + x: '321', + default: 'some value', + home: true +} +``` + +Passing values explicitly +```shell +$ ./script.js -r --value=321 +### finished normally. +Parser { + ... + required_option_given: true, + x: '321', + default: 'some value', + home: true +} +``` + +```shell +$ ./script.js -r command + +``` + +```shell +$ ./script.js -r nested + +$ ./script.js -r nested -h + +``` + +Split options +```shell +$ ./script.js -rsc +### finished normally. +Parser { + ... + required_option_given: true, + command: true, + default: 'some value', + home: true +} ``` ## Advanced docs diff --git a/argv.js b/argv.js index 8d2895e..d04615b 100644 --- a/argv.js +++ b/argv.js @@ -904,10 +904,9 @@ object.Constructor('Parser', { && parsed.handleErrorExit(arg, reason) } var reportError = function(message, arg, rest){ message = message - .replace(/$ARG/g, arg) - handleError(message, arg, rest) - return parsed.printError( - module.ParserError(message)) } + .replace(/\$ARG/g, arg) + parsed.printError(module.ParserError(message)) + return handleError(message, arg, rest) } var runHandler = function(handler, arg, rest){ var [arg, value] = arg instanceof Array ? arg diff --git a/examples/options.js b/examples/options.js new file mode 100644 index 0000000..90f643b --- /dev/null +++ b/examples/options.js @@ -0,0 +1,151 @@ +#!/usr/bin/env node + +var argv = require('../argv') + +var parser = argv.Parser({ + doc: 'Example script options', + + // to make things consistent we'll take the version from package.json + version: require('../package.json').version, + + author: 'John Smith ', + license: 'BSD-3-Clause', + + footer: 'Written by $AUTHOR ($VERSION / $LICENSE).', + + '-bool': { + doc: 'if given set .bool to true' }, + + + // option with a value... + '-value': { + doc: 'set .x to X', + + // 'X' (VALUE) is used for -help while 'x' (key) is where the + // value will be written... + arg: 'X | x', + + // the value is optional by default but we can make it required... + valueRequired: true, + }, + + + // setup an alias -r -> -required + '-r': '-required', + + // a required option... + '-required': { + doc: 'set .required_option_given to true', + + // NOTE: we can omit the VALUE part to not require a value... + // NOTE: of no attr is specified in arg option name is used. + arg: '| required_option_given', + + // NOTE: by default required options/commands are sorted above normal + // options but bellow -help/-version/-quiet/... + // (by default at priority 80) + required: true, + }, + + + '-int': { + doc: 'pass an integer value', + + // NOTE: if not key is given the VALUE name is used as a key, so the + // value here is assigned to .INT... + arg: 'INT', + + // convert the input value to int... + type: 'int', + }, + + + '-default': { + doc: 'option with default value', + arg: 'VALUE | default', + + default: 'some value', + + // keep this near the top of the options list in -help... + priority: 80, + }, + + + '-home': { + doc: 'set home path', + arg: 'HOME | home', + + // get the default value from the environment variable $HOME... + env: 'HOME', + }, + + + // collecting values... + '-p': '-push', + '-push': { + doc: 'push elements to a .list', + arg: 'ELEM | list', + + // this will add each argument to a -push option to a list... + collect: 'list', + }, + + '@command': { + // ... + }, + + // Since options and commands are identical, aliases from one to the + // other work as expected... + '-c': '@command', + + '-active': { + doc: 'basic active option', + handler: function(args, key, value){ + // ... + } }, + + '-s': '-shorthand-active', + '-shorthand-active': function(args, key, value){ + // ... + }, + + '@nested': argv.Parser({ + // ... + }).then(function(){ + // ... + }), + + '-then': { + handler: function(){ + return argv.THEN } }, + '-stop': { + handler: function(){ + return argv.STOP } }, + + '-error': { + handler: function(){ + throw argv.ParserError('something went wrong.') } }, + '-silent-error': { + handler: function(){ + return argv.ParserError('something went wrong.') } }, + '-critical-error': { + handler: function(){ + throw 'something went really wrong.' } }, +}) +.then(function(unhandled, root_value, rest){ + console.log('### finished normally.') + console.log(this) +}) +.stop(function(arg, rest){ + console.log(`### stopped at ${arg}.`) +}) +.error(function(reason, arg, rest){ + console.log(`### something went wrong when parsing ${arg}.`) +}) + + +// run the parser... +__filename == require.main.filename + && parser() + +// vim:set ts=4 sw=4 spell :