# argv.js Simple argv parser ## Motivation I needed a new argv parser for a quick and dirty project I was working on and evaluating and selecting the proper existing parser and then learning its API, quirks and adapting the architecture to it seemed to be more complicated, require more effort and far less fun than putting together a trivial parser myself in a couple of hours. This code is an evolution of that parser. ## Features - Simple - Supports both the _option_ (a-la `ls`) and _command_ (a-la `git`) paradigms - Nestable parsers can be nested as option/command handlers defining independent nested contexts - Option expansion `-abc` expands to `-a -b -c` if `-abc` is not defined - Option/command value passing implicit `-a 123` (requires definition or manual handling) or explicit `-a=123` - Environment variable option/command value defaults - Option/command value conversion - Option/command value collection - Multiple option prefix support - Reasonable defaults: - Metadata defaults to `package.json` - `-help` – generate and print help - `-version` – print version - `-quiet` – suppress printing - `-` – stop argument processing - Extensible: - Hooks for dynamic option/command handling - Customizable error and stop condition handling ### Planned - Run `-` scripts - Option doc grouping (???) ## Contents - [argv.js](#argvjs) - [Motivation](#motivation) - [Features](#features) - [Planned](#planned) - [Contents](#contents) - [Architecture](#architecture) - [Installation](#installation) - [Basics](#basics) - [Options in more detail](#options-in-more-detail) - [Help and metadata](#help-and-metadata) - [Basic options](#basic-options) - [Commands](#commands) - [Active options/commands](#active-optionscommands) - [Nested parsers](#nested-parsers) - [Stopping](#stopping) - [Error reporting](#error-reporting) - [Handling the result](#handling-the-result) - [Calling the script](#calling-the-script) - [Advanced docs](#advanced-docs) - [License](#license) ## Architecture This module provides the following workflow: ``` Parser(..) -> (..) -> ``` - define/declare a parser (parse grammar) ``` Parser() -> ``` - define post-parse callbacks (optional) ``` .then() .stop() .error() ``` - parse ``` (...) -> ``` - option handlers (defined in ``) are called while parsing, - then/stop/error ``'s are called after the `` is done, - everything is run in the _context_ of the `` object so any data set on it is accessible after parsing is done for further reference. Note that the `` is fully reusable and on each call will produce a new `` object. The `` object has the `` as its `.__proto__`. ## Installation ```shell_session $ npm install ig-argv ``` ## Basics Create a [bare.js](./examples/bare.js) script and make it runnable ```shell_session $ touch bare.js $ chmod +x bare.js ``` Now for the code ```javascript #!/usr/bin/env node // compatible with both node's and RequireJS' require(..) var argv = require('ig-argv') var parser = exports.parser = argv.Parser({ // option definitions... // ... }) .then(function(){ // things to do after the options are handled... // ... }) // run the parser... __filename == (require.main || {}).filename && parser() ``` This script already knows how to respond to `-help` and friends. ```shell_session $ ./bare.js --help Usage: bare.js [OPTIONS] Options: -h, --help - print this message and exit -v, --version - show bare.js verion and exit -q, --quiet - quiet mode - - stop processing arguments after this point Written by John Smith Varsion: 0.0.1 / License: BSD-3-Clause ``` ## Options in more detail Start by creating an [`options.js`](./examples/options.js) script... ```shell_session $ touch options.js $ chmod +x options.js ``` ...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 ```javascript doc: 'Example script options', ``` Metadata: ```javascript // to make things consistent we'll take the version from package.json version: require('./package.json').version, author: 'John Smith ', license: 'BSD-3-Clause', ``` If not set, `.version`, `.author` and `.license` are acquired from `package.json` located at the same path as the main script. To explicitly set the path of the JSON file from which metadata is read set [`.packageJson`](./ADVANCED.md#parserpackagejson). These basic bits of metadata can be referenced in other `-help` sections, for example: ```javascript footer: 'Written by: $AUTHOR\nVersion: $VERSION / License: $LICENSE', ``` ### Basic options These, if encountered, simply assign a value to an attribute on the parsed object. Any option/command can be passed a value, either explicitly (e.g. `-opt=123`) or implicitly by first setting `.arg` (see examples below) and and then passing `-opt 123`. If no value is given `true` is assigned to option attribute on the parsed object to indicate that the option/command is present in the command-line. Note that repeating a basic option/command will overwrite the previous value unless `.collect` is set (see `-push` example below). Note that in general case option order in the command-line is not critical, but option context can matter (see: [Active options/commands](#active-optionscommands) and [Nested parsers](#nested-parsers)) ```javascript '-bool': { doc: 'if given, set .bool to true' }, // option with a value... '-value': { doc: 'set .x to X', // 'X' (i.e. VALUE) is used to indicate the option value in -help // while 'x' (key) is the attribute where the value will be written... // // NOTE: if no .arg is set option attribute name is used. // // See the first example in "Calling the script" section below for output. arg: 'X | x', // the value is optional by default but we can make it required... valueRequired: true, }, // setup an alias -r -> -required // // NOTE: aliases are used only for referencing, all naming is done via the // actual option/command name. '-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, }, '-i': { 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: 'PATH | home_path', // 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', }, ``` For more info on available `.type` and `.collect` handlers see: [`