shargs

1.1.1 • Public • Published

🦈 shargs (shell args) is a library for building command-line argument parsers.

node version npm version license PRs Welcome linux unit tests status macos unit tests status windows unit tests status

Features

Installation

Install as a bundle (recommended):

npm install --save shargs

Install as modules:

npm install --save shargs-core   # core functions like parserSync (in bundle: shargs/core or shargs)
npm install --save shargs-opts   # a DSL for command-line options (in bundle: shargs/opts)
npm install --save shargs-parser # collection of parser functions (in bundle: shargs/parser)
npm install --save shargs-usage  # collection of usage functions  (in bundle: shargs/usage)
npm install --save shargs-repl   # build REPLs powered by shargs  (not in bundle)

The documentation assumes the bundle is installed, but the only difference between the bundle and modules installation is how functions are imported: The bundle uses require('shargs/opts'), while require('shargs-opts') is used by modules (note the use of / vs. -). Read installing as bundle or modules for more details.

Getting Started

Describe your command and its options:

const opts = [
  stringPos('question', {desc: 'Ask a question.', required: true}),
  number('answer', ['-a', '--answer'], {desc: 'The answer.', defaultValues: [42]}),
  flag('help', ['-h', '--help'], {desc: 'Print this help message and exit.'})
]

const deepThought = command('deepThought', opts, {desc: 'Ask the Ultimate Question.'})

The deepThought command has three command-line options:

  1. A required string positional argument named question.
  2. An answer number option specified with -a or --answer that should default to 42 if not given.
  3. A help command-line flag given by -h or --help.

You may use the shargs-opts module to get a nice DSL for describing our options. However, you could have also written them out as objects yourself or could have used a different DSL.

Read up on the details in the command-line options section.

Declare your own command-line parser:

const parser = parserSync({
  argv: [splitShortOpts],
  opts: [setDefaultValues, requireOpts, cast],
  args: [flagsAsBools]
})

Shargs gives you fine-grained control over how the options are parsed. By using the shargs-core and shargs-parser modules, we have build the following parser:

  1. splitShortOpts: Short option groups like -cvzf are transformed to -c -v -z -f.
  2. setDefaultValues: Options with default values that were not provided are set.
  3. requireOpts: It is verified that all required options have been given.
  4. cast: Strings are cast to other types, like numbers or booleans.
  5. flagsAsBools: Command-line flags are transformed to booleans.

Note that you did not tell parser how exactly to do those things. Everything is nice and declarative, and the details are hidden away in the parser stages.

The parserSync function and command-line parsers sections have all the details.

Layout a usage documentation:

const docs = usage([synopsis, space, optsList, space, desc])

const style = {
  line: [{width: 80}],
  cols: [{width: 25}, {width: 55}]
}

You may use shargs-usage to automatically generate a usage documentation based on a command definition (e.g. deepThought from before). The module provides all components generally found in usage documentations, like:

  1. A synopsis, summarizing available options: e.g. deepThought (<question>) [-a|--answer] [-h|--help].
  2. An options list (optsList), describing option details in a tabular format.

Note that shargs-usage is declarative: You only specify what components our usage documentation should have. The details on how exactly those components transform command-line options into text is hidden away.

See the automatic usage documentation generation and style sections.

Use the parser and the usage documentation in your program:

const argv = process.argv.slice(2)
const {errs, args} = parser(deepThought)(argv)

errs.forEach(err => console.log(err.msg))

const help = docs(deepThought)(style)
if (args.help) console.log(help)

The command-line option DSL, the parser DSL, and the usage documentation DSL combined give you a very flexible way to write command-line programs.

Find out more in the building command-line parsers with shargs section.

Run your command with node ./deepThought --help:

deepThought (<question>) [-a|--answer] [-h|--help]                              
                                                                                
<question>               Ask a question. [required]                             
-a, --answer=<number>    The answer. [default: 42]                              
-h, --help               Print this help message and exit.                      
                                                                                
Ask the Ultimate Question.                                                      

The automatic usage documentation generation and building command-line parsers with shargs sections have more.

Tutorials

Examples

Documentation

This documentation encompasses the following shargs modules:

  1. shargs-opts is documented in command-line options.
  2. shargs-core is documented in the parserSync function.
  3. shargs-parser is documented in command-line parsers.
  4. shargs-usage is documented in automatic usage documentation generation.
  5. shargs-repl is documented in building REPLs with shargs.

Command-line Options

Command-line options are the most important concept in shargs. They are the basis for its two main features: Command-line parsers and automatic usage documentation generation.

Shargs defines many different types of command-line options represented by objects with the following interfaces:

                          Type                                                       Interface                             Description
Flag Option {key, args, types: []} A present or absent value.
Primitive Option {key, args, types: [_]} A unary value given by argument.
Array Option {key, args, types: [_, _, ...]} An array of length n given by argument.
Variadic Option {key, args} A variable length array given by argument.
Subcommand Option {key, args, opts} An option group given by argument.
Primitive Positional Argument {key, types: [_]} A unary value given by position.
Array Positional Argument {key, types: [_, _, ...]} An array of length n given by position.
Variadic Positional Argument {key} A variable length array given by position.
Command Positional Argument {key, opts} An option group given by position.
Rest {values} An argument value of unknown type.

Since writing objects following these interfaces by hand can be tedious, shargs-opts gives you a simple type-based DSL for defining valid command-line options:

const {command, flag, number, subcommand} = require('shargs/opts')

const opts = [
  subcommand(askOpts)('ask', ['ask'], {required: true, desc: 'Ask a question.'}),
  number('answer', ['-a', '--answer'], {defaultValues: [42], desc: 'The answer.'}),
  flag('help', ['-h', '--help'], {desc: 'Print this help message and exit.'})
]

const deepThought = command('deepThought', opts, {
  desc: 'Deep Thought was created to come up with the Answer to ' +
        'The Ultimate Question of Life, the Universe, and Everything.'
})

In the example, using the type functions subcommand, number, flag, and command guarantees the generation of valid objects.

Type Functions

The following type functions are available:

                            Type Function                             Description
array(types)(key, args, fields)
arrayPos(types)(key, fields)
array generates an array option, while arrayPos generates an array positional argument, representing arrays whose length is known in advance.

The closely related variadic and variadicPos represent arrays with unknown lengths.


array returns the following object:

const array = types => (key, args, fields) => ({
  key, args, types, ...fields
})

arrayPos returns the following object:

const arrayPos = types => (key, fields) => ({
  key, types, ...fields
})
bool(key, args, fields)
boolPos(key, fields)
bool generates a primitive option, while boolPos generates a primitive positional argument, representing the boolean values 'true' and 'false'.

Note that the values are represented as strings and you may want to cast them. If you need more values representing 'true' (e.g. 't', 'yes') or 'false' (e.g. 'F', 'no'), have a look at broadenBools. If you want to treat a value as its reverse, see reverseBools. If you need flags instead of bools, have a look at the boolAsFlag and boolsAsFlags parser stages.


bool returns the following object:

const bool = (key, args, fields) => ({
  key, args, types: ['bool'], ...fields
})

boolPos returns the following object:

const boolPos = (key, fields) => ({
  key, types: ['bool'], ...fields
})
subcommand(opts)(key, args, fields)
command(key, opts, fields)
subcommand generates a subcommand option, while command generates a command positional argument. Combined, they enable commands to do multiple things like git init, git commit, and git push.

subcommand's and command's opts fields are arrays of command-line options used to parse their values. Subcommands may have their own command-specific parsers or are parsed by command's parser. command or subcommand values are either terminated by the end of the input or by --.


subcommand returns the following object:

const subcommand = opts => (key, args, fields) => ({
  key, args, opts, ...fields
})

command returns the following object:

const command = (key, opts, fields) => ({
  key, opts, ...fields
})
flag(key, args, fields)
flag generates a flag option, representing command-line options that take no value.

Shargs counts the number of times a flag occurs, so a flag may be amplified by repeating it. If you don't need counts and prefer numbers or boolean values, have a look at the flagAsBool, flagAsNumber, flagsAsBools and flagsAsNumbers parser stages. If you need the presence of a flag to imply negativity (e.g. --no-fun), see complement, reverse and reverseFlags.


flag returns the following object:

const flag = (key, args, fields) => ({
  key, args, types: [], ...fields
})
number(key, args, fields)
numberPos(key, fields)
number generates a primitive option, while numberPos generates a primitive positional argument, representing JavaScript numbers.

Numbers are represented as strings and you may want to cast them. If you need flags instead of numbers, have a look at the numberAsFlag and numbersAsFlags parser stages.


number returns the following object:

const number = (key, args, fields) => ({
  key, args, types: ['number'], ...fields
})

numberPos returns the following object:

const numberPos = (key, fields) => ({
  key, types: ['number'], ...fields
})
string(key, args, fields)
stringPos(key, fields)
string generates a primitive option, while stringPos generates a primitive positional argument, representing strings.

string returns the following object:

const string = (key, args, fields) => ({
  key, args, types: ['string'], ...fields
})

stringPos returns the following object:

const stringPos = (key, fields) => ({
  key, types: ['string'], ...fields
})
variadic(key, args, fields)
variadicPos(key, fields)
variadic generates a variadic option, while variadicPos generates a variadic positional argument. These types represent arrays whose length is not known in advance.

An opts array can have at most one variadic positional argument and no other positional arguments (*Pos) may be defined after it. The closely related array and arrayPos represent arrays with known lengths, while command and subcommand are variadicPos and variadic with opts fields. A variadic's or variadicPos' values are either terminated by the end of the input or by --.


variadic returns the following object:

const variadic = (key, args, fields) => ({
  key, args, ...fields
})

variadicPos returns the following object:

const variadicPos = (key, fields) => ({
  key, ...fields
})

You may write out command-line options by hand, or write your own DSLs for creating them, they are just JavaScript objects:

const askOpts = [
  {key: 'format', args: ['--format'], types: ['string'], only: ['json', 'xml'], defaultValues: ['json'],
   desc: 'Respond either with json or xml.'},
  {key: 'html', args: ['--no-html'], types: [], reverse: true, desc: 'Remove HTML tags.'},
  {key: 'help', args: ['-h', '--help'], types: [], desc: 'Print this help message and exit.'},
  {key: 'question', types: ['string'], required: true, desc: 'State your question.'}
]

Apart from key, args, types, opts, and values that we have already seen and that determine an option's type, command-line option objects may be given any other fields, that may be used to provide information to parser stages (e.g. defaultValues, only), or to provide descriptions for usage documentation generation (e.g. desc, descArg). If you write your own parser stages, you may also define your own fields.

Option Fields

The following fields are used by shargs-core, shargs-parser stages or shargs-usage functions:

Field      Type      Description
args string[]
args defines argument names for command-line options (e.g. ['-h', '--help']).

Argument names have no restrictions and can be any string. E.g. ['-h', '--help'] could be used for a help flag or ['ask'] could be used for a command. Positional arguments must not have an args field, as they are not given by argument, but by their position.

contradicts key[]
contradicts defines what keys an option is incompatible with.

This information is used by the contradictOpts parser stage to report errors if incompatible options are used together. Note that contradicts is unidirectional and not transitive (e.g. if a contradicts b and b contradicts c, a does not contradict c, and thus a and c are compatible). Only two keys that each contradict the other key are mutually exclusive.

defaultValues *
defaultValues defines default values for command-line options.

They are used by the setDefaultValues parser stage that sets the values field if no values are supplied. The defaultValues' type depends on the command-line option type: Subcommands takes the same array of options as opts. Flag options' values have to be a number. All other options take an array of values, that must have the same length as their types field.

desc string
desc defines an option description used by various usage functions.

More specifically, desc is used by desc, optsList, optsLists, optsDef, and optsDefs and their *With versions.

descArg string
descArg defines a description for an argument value (e.g. {descArg: 'format'} would print --format=<format> instead of --format=<string>).

It is used by the optsList, optsLists, optsDef, and optsDefs usage functions and their *With versions. only, types, and key are other fields that change the argument value description. These fields are applied in the following order (highest priority first): descArg, only, types, and key. If descArg is an empty string, no argument value description is displayed.

descDefault string
descDefault overrides the default shield (e.g. [default: 42]) displayed in several usage commands.

It is used by the optsList, optsLists, optsDef, and optsDefs usage functions and their *With versions. If descDefault is an empty string, the default shield is hidden.

implies key[]
implies defines what keys an option must be defined with.

This information is used by the implyOpts parser stage to report errors if mandatory options are missing. Note that implies is unidirectional (e.g. if a implies b and a is present, b must be present as well, but if b is present, a does not have to be present) and transitive (e.g. if a implies b and b implies c, a also implies c, and thus if a is present, c must also be present). Only two keys that each imply the other key are mutually inclusive.

key string
key defines the name of a command-line option.

It is used by the parser function as a field name for the parsed values in the resulting args object. Most command-line options should have a unique key to avoid collisions with other options. However, if two different options describe the same result field, it may make sense to give them a shared key. See complement for an example. A key must not be named _. It is also used by the optsList, optsLists, optsDef, optsDefs, synopses, and synopsis usage functions and their *With versions to describe argument values (e.g. --format=<format>). descArg, only, and types are other fields that change the argument value description. These fields are applied in the following order (highest priority first): descArg, only, types, and key.

only any[]
only defines valid values of an option.

It is used by the restrictToOnly parser stage to validate user input. only may be used to implement enumerations. It is also used by the optsList, optsLists, optsDef, and optsDefs usage functions and their *With versions to describe argument values (e.g. --format=<json|xml>). descArg, types, and key are other fields that change the argument value description. These fields are applied in the following order (highest priority first): descArg, only, types, and key.

opts option[] opts defines the command-line options of commands and subcommands.
required boolean
required defines whether a command-line option has to be present or not.

It is used by the requireOpts stage that reports an error if a required option does not have values. A positional argument (*Pos) can only be required, if all previously defined positional arguments are required as well. The synopsis, synopses, optsList, optsLists, optsDef, and optsDefs usage functions and their *With versions mark required options.

reverse boolean reverse defines whether the values of a given option should be reversed by the reverseBools or reverseFlags parser stages.
types string[]
types defines what user input a command-line option takes.

Flag options' types must be []. Primitive options' and primitive positional arguments' types must be [_], and array options' and array positional arguments' types must be [_, _, ...], where _ is the name of a type given as a string. Variadic options, variadic positional arguments, subcommand options, and command positional arguments must not have a types field. types is also used by the optsList, optsLists, optsDef, and optsDefs usage functions and their *With versions to describe argument values (e.g. --format=<bool> for a bool option). descArg, only, and key are other fields that change the argument value description. These fields are applied in the following order (highest priority first): descArg, only, types, and key.

values any[]
This field should only be set by parser stages and never manually. values are assigned by the parser. You may want to use defaultValues.

The length of a values' array depends on the command-line option type: Flag options, primitive options, primitive positional arguments, and rest must each have values of length 1. Array options' and array positional arguments' values field must match their types in length. subcommand option's, command positional argument's, variadic option's, and variadic positional argument's values may have any number of entries.

Option Decorators

Certain changes to options are so frequent, that shargs-opts provides decorators for them. You may think of decorators as recurring patterns that are provided as functions.

shargs-opts provides the following decorators:

                  Decorator                   Description
complement(prefix)(opt)
complement transforms a bool or flag option into a complementary option prefixed with a given string (e.g. --no-html if used on --html).

The complementary option has the same key as the original option, but reverses its value. If complement is used, you most probably want to also use the reverseBools or reverseFlags parser stage.


Example:

const {flag, complement} = require('shargs/opts')

const no = complement('--no-')

const html = flag('html', ['-H', '--html'], {defaultValues: ['false']})
const noHtml = no(html)

Is the same as:

const {flag} = require('shargs/opts')

const html = flag('html', ['-H', '--html'], {defaultValues: ['false']})
const noHtml = flag('html', ['--no-H', '--no-html'], {reverse: true})

Note the differences in defaultValues and reverse.

posArgToOpt(args)(opt)
posArgToOpt transforms a positional argument into an option by adding args.

Example:

const {command, stringPos} = require('shargs/opts')

const opts = [stringPos('question')]
const deepThought = command('deepThought', opts)

const args = ['deepThought', 'D']
posArgToOpt(args)(deepThought)

Is the same as:

const {subcommand} = require('shargs/opts')

subcommand(opts)('deepThought', args)

Verify Commands

Shargs provides a function for verifying that commands have the correct structure:

const {verifyCommand} = require('shargs')

const {errs, opt} = verifyCommand(deepThought)

In the example, it would return a list of errs if deepThought was invalid. If the command is valid, the errs list is empty. verifyCommand is used internally by parserSync and parser, but may be used independently.

The parserSync Function

The parserSync function is shargs' core abstraction. It generates a command-line parser from a collection of parser stages and is usually used alongside shargs-parser:

const {parserSync} = require('shargs')
const {cast, flagsAsBools, requireOpts, restrictToOnly} = require('shargs/parser')
const {reverseFlags, setDefaultValues, splitShortOpts} = require('shargs/parser')

const stages = {
  argv: [splitShortOpts],
  opts: [setDefaultValues, requireOpts, reverseFlags, cast],
  args: [flagsAsBools]
}

const substages = {
  ask: [...stages.opts, restrictToOnly]
}

const parser = parserSync(stages, substages)

parserSync takes two parameters:

  1. A stages object that takes parser stages and defines what transformations should be applied in which order.
  2. An optional substages object that defines subcommand-specific opts parser stages.

parserSync has a twin function called parser that does the same, but works asynchronously.

stages

Shargs has seven different processing steps called stages that are applied in a predefined order and transform argument values (process.argv) via command-line options (opts) to arguments (args):

Stage Field Type
1 toArgv
                    any => {errs, argv} 

Transforms a value into command-line argument values syntax, e.g.

"-p commit -am 'First commit'"

could be transformed to

['-p', 'commit', '-am', 'First commit']
2 argv
     Array {errs, argv}>

Several stages that modify command-line argument values, e.g.

['-p', 'commit', '-am', 'First commit']

could be transformed to

['-p', 'commit', '-a', '-m', 'First commit']
3 toOpts
command => {errs, argv} => {errs, opts} 

Transforms argument values into command-line options, e.g.

['-p', 'commit', '-a', '-m', 'First commit']

could be transformed to

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: [], values: [1]},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]
4 opts
     Array {errs, opts}>

Several stages that modify command-line options, e.g.

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: [], values: [1]},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]

could be transformed to

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: ['bool'], values: ['true']},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]
5 toArgs
           {errs, opts} => {errs, args} 

Transforms command-line options into arguments object arrays, e.g.

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: ['bool'], values: ['true']},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]

could be transformed to

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: [
    {_: [], all: 'true', message: 'First commit'}
  ]}
]
6 args
     Array {errs, args}>

Several stages that modify arguments object arrays, e.g.

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: [
    {_: [], all: 'true', message: 'First commit'}
  ]}
]

could be transformed to

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: {
    {_: [], all: true, message: 'First commit'}
  }}
]
7 fromArgs
           {errs, args} => any          

Transforms argument object arrays into any result value:

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: [
    {_: [], all: true, message: 'First commit'}
  ]}
]

could be transformed to

{
  _: [],
  paginate: {type: 'flag', count: 1},
  commit: {
    _: [],
    all: true,
    message: 'First commit'
  }
}

The argv, opts, and args stages are the user-facing API to declare a parser's behavior.

The toOps and toArgs stages define the core behavior of parserSync (and parser) and shargs defines sensible defaults that should not have to be changed in most use cases. However, if you do have a use case that needs adjustments to those stages, you may carefully swap them out.

If you read the types from top to bottom, you get a good impression of how parserSync works.

substages

substages define custom opts stages for subcommands. That means, while most subcommands are parsed using the opts defined in stages, those whose key matches a key in the substages object are parsed using the opts defined under that key.

Keys may be deeply nested to account for subcommands of subcommands: E.g. if ask had a subcommand with the question key, {ask: {question: [...stages.opts, restrictToOnly]}} would assign custom opts to question.

The _ key is special in substages: It is a wildcard that is used by any subcommand that is not given explicitly by key. E.g. {ask: {_: [...stages.opts, restrictToOnly]}} and {_: {_: [...stages.opts, restrictToOnly]}} both work for question.

Async Parsers

The parserSync function has an asynchronous alternative called parser. It is used exactly like parserSync, but also works with stages returning JavaScript Promises and returns a Promise itself:

// stages, substages, deepThought, argv are taken from the Getting Started section

const {parser} = require('shargs')

const asyncParser = parser(stages, substages)
const parse = asyncParser(deepThought)
const {errs, args} = await parse(argv)

In addition to parserSync's parameters, parser's stages and substages parameters also take parser stages that return Promises:

Stage Field Type
1 toArgv
                    any =>         {errs, argv}  
                       any => Promise 

Transforms a value into command-line argument values syntax, e.g.

"-p commit -am 'First commit'"

could be transformed to

['-p', 'commit', '-am', 'First commit']
2 argv
     Array         {errs, argv}> 
        Array Promise>

Several stages that modify command-line argument values, e.g.

['-p', 'commit', '-am', 'First commit']

could be transformed to

['-p', 'commit', '-a', '-m', 'First commit']
3 toOpts
command => {errs, argv} =>         {errs, opts}  
   command => {errs, argv} => Promise 

Transforms argument values into command-line options, e.g.

['-p', 'commit', '-a', '-m', 'First commit']

could be transformed to

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: [], values: [1]},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]
4 opts
     Array         {errs, opts}> 
        Array Promise>

Several stages that modify command-line options, e.g.

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: [], values: [1]},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]

could be transformed to

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: ['bool'], values: ['true']},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]
5 toArgs
           {errs, opts} =>         {errs, args}  
              {errs, opts} => Promise 

Transforms command-line options into arguments object arrays, e.g.

[
  {key: 'paginate', args: ['-p'], types: [], values: [1]},
  {key: 'commit', args: ['commit'], opts: [...], values: [
    {key: 'all', args: ['-a'], types: ['bool'], values: ['true']},
    {key: 'message', args: ['-m'], types: ['string'], values: ['First commit']},
    ...
  ]},
  ...
]

could be transformed to

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: [
    {_: [], all: 'true', message: 'First commit'}
  ]}
]
6 args
     Array         {errs, args}> 
        Array Promise>

Several stages that modify arguments object arrays, e.g.

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: [
    {_: [], all: 'true', message: 'First commit'}
  ]}
]

could be transformed to

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: {
    {_: [], all: true, message: 'First commit'}
  }}
]
7 fromArgs
           {errs, args} =>         any           
              {errs, args} => Promise<any>          

Transforms argument object arrays into any result value:

[
  {_: [], paginate: {type: 'flag', count: 1}},
  {commit: [
    {_: [], all: true, message: 'First commit'}
  ]}
]

could be transformed to

{
  _: [],
  paginate: {type: 'flag', count: 1},
  commit: {
    _: [],
    all: true,
    message: 'First commit'
  }
}

If you read the stages' field types from top to bottom, you get a good impression of what an asynchronous parser does. Internally, an asynchronous shargs parser really differs only in one major way from a synchronous parser: Instead of using function composition, it uses Promise.prototype.then to chain parser stages.

Advanced Parsers

Command-line Parsers

You do not have to write all parser stages yourself. The shargs-parser library offers a large collection of common parser stages, you can use.

The parser stages presented here are split into checks and stages. While checks only report errors, stages also transform their argv, opts, or args. Usually, it makes sense to declare checks before stages.

argv Checks

                                             Description
verifyArgv(rules)
Reports a FalseArgvRules error if the passed rules predicate returns false for an argument value.

If rules is not a function, reports a WrongArgvRulesType error.


Example:

const {verifyArgv} = require('shargs/parser')

const rules = argv => (
  argv.some(_ => _ === '--question') &&
  argv.some(_ => _ === '--answer')
)

const argv = ['--answer', '42']

verifyArgv(rules)({argv})

Result:

{
  errs: [
    {
      code: 'FalseArgvRules',
      msg:  'Your argv rules returned false...',
      info: {...}
    }
  ]
}

argv Stages

                                             Description
equalsSignAsSpace
Allows arguments of the form --answer=42 to be interpreted like --answer 42.

It only removes the first =, so ['--question=1+2=3?'] is transformed into ['--question', '1+2=3?'].


Example:

const {equalsSignAsSpace} = require('shargs/parser')

const argv = ['--answer=42']

equalsSignAsSpace({argv})

Result:

{
  argv: ['--answer', '42']
}
shortOptsNoSpace
Allows to omit whitespaces between short arguments and their values. Passing -a42 would be the same as passing -a 42. Cannot be used together with splitShortOpts.

Example:

const {shortOptsNoSpace} = require('shargs/parser')

const argv = ['-a42']

shortOptsNoSpace({argv})

Result:

{
  argv: ['-a', '42']
}
splitShortOpts
Allows using short option groups. The group -xvzf would be interpreted as -x -v -z -f. Cannot be used together with shortOptsNoSpace.

Example:

const {splitShortOpts} = require('shargs/parser')

const argv = ['-ha', '42']

splitShortOpts({argv})

Result:

{
  argv: ['-h', '-a', '42']
}
traverseArgv(p)(f)
Transforms arguments by applying a function f to each argument satisfying a predicate p.

While p's signature is arg => true|false, f's signature must be (arg, index, argv) => ({errs = [], argv = []}). Many other argv checks and stages are defined in terms of traverseArgv and it is of great help for writing custom argv stages.


Example:

const {traverseArgv} = require('shargs/parser')

const argv = [
  '--answer=42',
  '--help'
]

const hasEqualsSign = arg => arg.indexOf('=') > -1

const replaceFirstEqualsSign = arg => ({
  argv: [
    arg.slice(0, arg.indexOf('=')),
    arg.slice(arg.indexOf('=') + 1)
  ]
})

traverseArgv(hasEqualsSign)(replaceFirstEqualsSign)({argv})

Result:

{
  argv: [
    '--answer', '42',
    '--help'
  ]
}

opts Checks

                                             Description
contradictOpts
Reports a ContradictionDetected error if options with a contradicts list violate their constraints.

This is the case, if both, the option and an option from its contradicts list, have values. If contradicts is not a list, it reports a WrongContradictsType error.


Example:

const {contradictOpts} = require('shargs/parser')
const {number, string} = require('shargs/opts')

const opts = [
  number('age', ['-a'], {
    values: ['27']
  }),
  string('birthday', ['-b'], {
    contradicts: ['age'],
    values: ['27.7.1927']
  })
]

contradictOpts({opts})

Result:

{
  errs: [
    {
      code: 'ContradictionDetected',
      msg:  'Some given keys contradict each other.',
      info: {...}
    }
  ]
}
demandASubcommand
Reports a SubcommandRequired unless at least one subcommand has values.

Example:

const {demandASubcommand} = require('shargs/parser')
const {flag, number, subcommand} = require('shargs/opts')

const opts = [
  subcommand([])('ask', ['ask'], {desc: 'Ask a question.'}),
  number('answer', ['-a', '--answer'], {
    values: ['42'],
    desc: 'The answer.'
  }),
  flag('help', ['-h', '--help'], {
    desc: 'Print this help message and exit.'
  })
]

demandASubcommand({opts})

Result:

{
  errs: [
    {
      code: 'SubcommandRequired',
      msg:  'No subcommand found. Please use at least one subcommand!',
      info: {...}
    }
  ]
}
implyOpts
Reports an ImplicationViolated error if options with an implies list violate their constraints.

This is the case, if the option has values, but an option from its implies list has not. If implies is not a list, it reports a WrongImpliesType error.


Example:

const {implyOpts} = require('shargs/parser')
const {number, string} = require('shargs/opts')

const opts = [
  number('answer', ['-a']),
  string('question', ['-q'], {
    implies: ['answer'],
    values: ['How much is the fish?']
  })
]

implyOpts({opts})

Result:

{
  errs: [
    {
      code: 'ImplicationViolated',
      msg:  'Some given keys that imply...',
      info: {...}
    }
  ]
}
requireOpts
Reports a RequiredOptionMissing error if an option whose required field is true is missing.

If values is not an array, it reports a WrongFormatForRequiredOption error.


Example:

const {requireOpts} = require('shargs/parser')
const {string} = require('shargs/opts')

const opts = [
  string('question', ['--question'], {required: true})
]

requireOpts({opts})

Result:

{
  errs: [
    {
      code: 'RequiredOptionIsMissing',
      msg:  'A required option has not been provided.',
      info: {...}
    }
  ]
}
suggestOpts
Corrects spelling mistakes by suggesting existing command-line arguments for all unknown provided arguments. E.g. if --asnwer was provided, the --answer argument would be suggested.

It checks all rest values, assuming they are in the rest category because of spelling mistakes. It collects all command-line options' args and computes a distance metric (currently Levenshtein distance) between each arg and each rest. It reports the results in a DidYouMean error, suggesting probable args replacements for spelling mistakes.


Example:

const {suggestOpts} = require('shargs/parser')
const {number} = require('shargs/opts')

const opts = [
  number('answer', ['-a', '--ans']),
  {values: ['--asn']}
]

suggestOpts({opts})

Result:

{
  errs: [
    {
      code: 'DidYouMean',
      msg:  'An unknown command-line argument...',
      info: {
        argv: '--asn',
        options: [
          [],
          [],
          [{'--ans': number('answer', ['-a', '--ans'])}],
          [{'-a': number('answer', ['-a', '--ans'])}]
        ]
      }
    }
  ]
}

The options array looks a little bit strange, so an explanation is in order. The array's index is the cost necessary to transform the unknown option in the arguments, represented as keys. Because of this, you can conveniently work with the results, e.g. by only using the most probable ones:

'Did you mean: ' + (
  options
  .slice(0, 3)
  .reduce((a, b) => a.concat(b))
  .flatMap(Object.keys)
  .join(', ')
)

Results in:

Did you mean: --age
validatePosArgs
Reports an InvalidRequiredPositionalArgument error if defined positional arguments (*Pos) violate their rules for the required field or the position of variadicPos.

If a positional argument is required, all previously defined positional arguments must be required, as well, and no other positional arguments can be defined after a variadicPos. In case of a violation of the second rule, validatePosArgs reports an InvalidVariadicPositionalArgument error.


Example:

const {validatePosArgs} = require('shargs/parser')
const {stringPos, variadicPos} = require('shargs/opts')

const opts = [
  stringPos('name1', {required: true, values: ['Arthur']}),
  stringPos('name2', {required: false, values: ['Ford']}),
  stringPos('name3', {required: true, values: ['Trillian']}),
  variadicPos('names', {values: ['Zaphod', 'Marvin']}),
  stringPos('name4', {values: ['Douglas']})
]

validatePosArgs({opts})

Result:

{
  errs: [
    {
      code: 'InvalidRequiredPositionalArgument',
      msg:  'If a positional argument is required, all prev...',
      info: {...}
    },
    {
      code: 'InvalidVariadicPositionalArgument',
      msg:  'Only the last positional argument may be variadic.',
      info: {...}
    }
  ]
}
verifyOpts(rules)
Reports a FalseOptsRules error if the opts array does not adhere to the rules predicate. rules must have the following function signature: opt => true|false.

If rules is not a function, verifyOpts reports a WrongOptsRulesType error.


Example:

const {verifyOpts} = require('shargs/parser')
const {string} = require('shargs/opts')

const implies = (p, q) => !p || q

const rules = opts => implies(
  opts.some(_ => _.key === 'question' && _.values),
  opts.some(_ => _.key === 'answer' && _.values)
)

const opts = [
  string('question', ['--question'], {
    values: ['How much is the fish?']
  }),
  number('answer', ['-a'])
]

verifyOpts(rules)({opts})

Result:

{
  errs: [
    {
      code: 'FalseOptsRules',
      msg:  'Your opts rules returned false...',
      info: {...}
    }
  ]
}
verifyValuesArity
Reports an error if an option's values do not fit its types.

See the values documentations for the exact rules. If the lengths of values and types do not match, an InvalidArity error is reported. If the types field has an invalid value, an InvalidTypes error is reported and verifyValuesArity reports an InvalidValues error in case of invalid values.


Example:

const {verifyValuesArity} = require('shargs/parser')
const {number} = require('shargs/opts')

const opts = [
  number('answer', ['--answer'], {values: ['42', '23']})
]

verifyValuesArity({opts})

Result:

{
  errs: [
    {
      code: 'InvalidArity',
      msg:  "An option's types arity does not match...",
      info: {...}
    }
  ]
}

opts Stages

                                             Description
arrayOnRepeat
Collects all repeated keys in an array, instead of keeping only the first mention of a key.

Example:

const {arrayOnRepeat} = require('shargs/parser')
const {number, string} = require('shargs/opts')

const opts = [
  string('answer', ['-a'], {values: ['42']}),
  number('answer', ['-a'], {values: [42]})
]

arrayOnRepeat({opts})

Result:

{
  opts: [
    array(['string', 'number'])('answer', ['-a'], {
      values: ['42', 42]
    })
  ]
}
bestGuessOpts
Takes a best guess approach to transform rest values that did not match a command-line option into new command-line options. E.g. {values: ['--version']} becomes {key: 'version', types: [], values: [1]} and [{values: ['--not']}, {values: ['panic']}] becomes {key: 'not', types: ['string'], args: ['--not'], values: ['panic']}.

Single rest options are interpreted as flags while two consecutive rest options are interpreted as strings if the first rest is in short option format (one minus with a single character, e.g. -n, -a) or in long option format (two minuses with any more characters, e.g. --name, --answer). bestGuessArgs is very similar to bestGuessOpts, but also considers non-consecutive rest values.


Example:

const {bestGuessOpts} = require('shargs/parser')
const {flag, string} = require('shargs/opts')

const opts = [
  string('age', ['--age'], {values: ['unknown']}),
  {values: ['--paranoid']},
  {values: ['--name']},
  {values: ['Marvin']},
  {values: ['foo']}
]

bestGuessOpts({opts})

Result:

{
  opts: [
    string('age', ['--age'], {values: ['unknown']}),
    flag('paranoid', [], {values: [1]}),
    string('name', [], {values: ['Marvin']}),
    {values: ['foo']}
  ]
}
broadenBools(alt)
Transforms bools with values like 'yes' or 'no' into bools with 'true' or 'false' values based on an alt mapping (e.g. {true: ['yes'], false: ['no']}).

Example:

const {broadenBools} = require('shargs/parser')
const {bool, number} = require('shargs/opts')

const opts = [
  number('answer', ['-a', '--answer'], {values: ['42']}),
  bool('verbose', ['--verbose'], {values: ['no']})
]

const alt = {
  true: ['yes'],
  false: ['no', 'f']
}

broadenBools(alt)({opts})

Result:

{
  opts: [
    number('answer', ['-a', '--answer'], {values: ['42']}),
    bool('verbose', ['--verbose'], {values: ['false']})
  ]
}
cast
Casts string values into other JavaScript types (e.g. numbers, booleans) according to the command-line options' types (e.g. {key: 'answer', types: ['number'], values: ['42']} is transformed to {key: 'answer', types: ['number'], values: [42]}).

If types contains 'number', but values cannot be cast into a number, an ArgumentIsNotANumber error is reported. If types contains 'bool', but values is not ['true'] or ['false'], an ArgumentIsNotABool error is reported.


Example:

const {cast} = require('shargs/parser')
const {bool, number} = require('shargs/opts')

const opts = [
  number('answer', ['-a', '--answer'], {values: ['42']}),
  bool('verbose', ['--verbose'], {defaultValues: ['false']})
]

cast({opts})

Result:

{
  opts: [
    number('answer', ['-a', '--answer'], {values: [42]}),
    bool('verbose', ['--verbose'], {defaultValues: [false]})
  ]
}
restrictToOnly
Validates all command-line options with both, only and values fields, by making sure that all values in values are also contained in only.

If values are not found in only, a ValueRestrictionsViolated error is reported for each value.


Example:

const {restrictToOnly} = require('shargs/parser')
const {number} = require('shargs/opts')

const opts = [
  number('answer', ['--answer'], {only: ['42'], values: ['23']})
]

restrictToOnly({opts})

Result:

{
  errs: [
    {
      code: 'ValueRestrictionViolated',
      msg:  'A value lies outside the allowed values...',
      info: {...}
    }
  ],
  opts
}
reverseBools
Transforms values of primitive options and array options whose types contain 'bool' and whose reverse field is true by replacing 'true'/true with 'false'/false and vice versa.

Example:

const {reverseBools} = require('shargs/parser')
const {bool} = require('shargs/opts')

const opts = [
  bool('verbose', ['-v'], {reverse: true, values: [true]}),
  bool('verbose', ['-v'], {reverse: true, values: ['true']})
]

reverseBools({opts})

Result:

{
  opts: [
    bool('verbose', ['-v'], {reverse: true, values: [false]}),
    bool('verbose', ['-v'], {reverse: true, values: ['false']})
  ]
}
reverseFlags
Transforms values of flag options whose reverse field is true by inverting the flag's value (e.g. 1 becomes -1).

Example:

const {reverseFlags} = require('shargs/parser')
const {flag} = require('shargs/opts')

const opts = [
  flag('help', ['-h'], {reverse: true, values: [1]})
]

reverseFlags({opts})

Result:

{
  opts: [
    flag('help', ['-h'], {reverse: true, values: [-1]})
  ]
}
setDefaultValues
Transforms all options that have no values, but defaultValues, by setting the values field to the defaultValues' value.

Example:

const opts = [
  flag(['-f'], {defaultValues: [1]}),
  bool(['-b'], {defaultValues: ['true']})
]

setDefaultValues({opts})

Result:

{
  opts: [
    flag(['-f'], {values: [1]}),
    bool(['-b'], {values: ['true']})
  ]
}
traverseOpts(p)(f)
Transforms opts by applying a function f to each option satisfying a predicate p.

While p's signature is opt => true|false, f's signature must be (opt, index, opts) => ({errs = [], opts = []}). Many other opts checks and stages are defined in terms of traverseOpts and it is of great help for writing custom opts stages.


Example:

const {traverseOpts} = require('shargs/parser')
const {flag, number} = require('shargs/opts')

const opts = [
  number('answer', ['-a'], {values: ['42']}),
  flag('verbose', ['-v'], {values: [1]}),
  flag('help', ['-h'], {values: [1]})
]

const isFlag = _ => Array.isArray(_.types) && _.types.length === 0

const reverseFlags = opt => ({
  opts: [
    {...opt, values: [-opt.values[0]]}
  ]
})

traverseOpts(isFlag)(reverseFlags)({opts})

Result:

{
  opts: [
    number('answer', ['-a'], {values: ['42']}),
    flag('verbose', ['-v'], {values: [-1]}),
    flag('help', ['-h'], {values: [-1]})
  ]
}

args Checks

                                             Description
failRest
Reports an UnexpectedArgument error for each value in the rest field _.

Example:

const {failRest} = require('shargs/parser')

const args = {
  _: ['--help']
}

failRest({args})

Result:

{
  errs: [
    {
      code: 'UnexpectedArgument',
      msg:  'An unexpected argument was used...',
      info: {...}
    }
  ]
}
verifyArgs(rules)
Reports a FalseArgsRules error for each args object that does not adhere to the rules predicate (with the signature arg => true|false).

Reports a WrongArgsRulesType error if rules is not a function.


Example:

const {verifyArgs} = require('shargs/parser')

const rules = args => (
  typeof args.question !== 'undefined' &&
  typeof args.answer   !== 'undefined'
)

const args = {
  question: 'How much is the fish?'
}

verifyArgs(rules)({args})

Result:

{
  errs: [
    {
      code: 'FalseArgsRules',
      msg:  'Your args rules returned false...',
      info: {...}
    }
  ]
}

args Stages

                                             Description
bestGuessArgs
Introduces new arguments by best guess based on rest field values (e.g. {_: ['--version']} becomes {version: {type: 'flag', count: 1}} and {_: ['--not', 'panic']} becomes {not: 'panic'}).

Transforms single rest field values into a flag and two consecutive rest options into a string. It only assumes rest field values to be strings if the first rest is in short option format (one minus with a single character, e.g. -h, -v) or in long option format (two minuses with any more characters, e.g. --help, --verbose). bestGuessArgs is very similar to bestGuessOpts, but also considers rest fields that originally did not directly follow each other. E.g. assuming --help to be a known argument, --not --help panic would produce {not: 'panic'}, although its components were not in tandem.


Example:

const {bestGuessArgs} = require('shargs/parser')

const obj = {
  args: {
    _: ['--answer', '42', 'foo', '-h'],
    command: {
      _: ['bar', '-v', '--question', 'What is answer?', '-v']
    }
  }
}

bestGuessArgs(obj)

Result:

{
  args: {
    _: ['foo'],
    answer: '42',
    h: {type: 'flag', count: 1},
    command: {
      _: ['bar'],
      v: {type: 'flag', count: 2},
      question: 'What is answer?'
    }
  }
}
bestGuessCast
Casts string args into other JavaScript types using a best guess approach based on their values (e.g. {answer: '42'} becomes {answer: 42} and {all: 'true'} becomes {all: true}).

It supports numbers and booleans (e.g. {help: 'true'} becomes {help: true}).


Example:

const {bestGuessCast} = require('shargs/parser')

const args = {
  _: ['--name', 'Marvin'],
  str1: 'yay',
  num1: '42.3',
  num2: '123e-1',
  num3: '0x11',
  num4: '0b11',
  bool1: 'true',
  arr1: ['-42', 'true', 'yay'],
  obj: {
    num5: '0o11',
    num6: '-Infinity',
    num7: '',
    num8: null,
    bool2: 'false',
    bool3: undefined
  }
}

bestGuessCast({args})

Result:

{
  args: {
    _: ['--name', 'Marvin'],
    str1: 'yay',
    num1: 42.3,
    num2: 12.3,
    num3: 17,
    num4: 3,
    bool1: true,
    arr1: [-42, true, 'yay'],
    obj: {
      num5: 9,
      num6: -Infinity,
      num7: '',
      num8: null,
      bool2: false,
      bool3: undefined
    }
  }
}
boolAsFlag(key)
Transforms bool arguments with key in args to a flag object. E.g., assuming the all key, {all: true} is transformed to {all: {type: 'flag', count: 1}} and {all: false} to {all: {type: 'flag', count: -1}}.

Example:

const args = {
  _: [],
  version: true
}

boolAsFlag('version')({args})

Result:

{
  _: [],
  version: {type: 'flag', count: 1}
}
boolsAsFlags
Transforms all bool arguments in args to flag objects using boolAsFlag.

Example:

const args = {
  _: [],
  html: false,
  version: true
}

boolsAsFlags({args})

Result:

{
  _: [],
  html: {type: 'flag', count: -1},
  version: {type: 'flag', count: 1}
}
clearRest
Sets rest values to an empty array (i.e. {_: []}).

Example:

const {clearRest} = require('shargs/parser')

const args = {_: ['--verbose']}

clearRest({args})

Result:

{
  args: {_: []}
}
flagAsBool(key)
Transforms flags with key in args to a bool value. E.g., assuming the all key, {all: {type: 'flag', count: 1}} is transformed to {all: true} and {all: {type: 'flag', count: -1}} to {all: false}.

If its count is greater than 0 it is considered true, otherwise it is considered false.


Example:

const {flagAsBool} = require('shargs/parser')

const args = {
  verbose: {type: 'flag', count: 1}
}

flagAsBool('verbose')({args})

Result:

{
  args: {
    verbose: true
  }
}
flagAsNumber(key)
Transforms flags with key in args to a number using its count. E.g., assuming the verbose key, {verbose: {type: 'flag', count: 3}} becomes {verbose: 3}.

Example:

const {flagAsNumber} = require('shargs/parser')

const args = {
  verbose: {type: 'flag', count: 2}
}

flagAsNumber('version')({args})

Result:

{
  args: {
    verbose: 2
  }
}
flagsAsBools
Transforms all flag arguments in args to bool values using flagAsBool.

Example:

const {flagsAsBools} = require('shargs/parser')

const args = {
  verbose: {type: 'flag', count: 1}
}

flagsAsBools({args})

Result:

{
  args: {
    verbose: true
  }
}
flagsAsNumbers
Transforms all flag arguments in args to numbers using their count like flagAsNumber.

Example:

const {flagsAsNumbers} = require('shargs/parser')

const args = {
  verbose: {type: 'flag', count: 2}
}

flagsAsNumbers({args})

Result:

{
  args: {
    verbose: 2
  }
}
mergeArgs(merge)
Transforms args by flattening them by recursively merging nested objects into their parent object (e.g. {ask: {question: '42?'}, answer: 42} becomes {question: '42?', answer: 42}).

A custom merge function may be passed with the following function signature: (obj1 = {}, obj2 = {}) => {}. The default merge function (if merge is undefined) prefers keys from the parent object over keys from nested objects, but concatenates rest values (_) from both objects (e.g. {_: ['foo'], answer: 42, ask: {_: ['bar'], answer: 23}} becomes {_: ['foo', 'bar'], answer: 42}).


Example:

const {mergeArgs} = require('shargs/parser')

const args = {
  _: ['--help'],
  version: {type: 'flag', count: 2},
  name: 'Arthur',
  command: {
    _: ['-v'],
    version: {type: 'flag', count: 1},
    name: 'Trillian',
    help: true
  },
  verbose: true
}

const mergeLeft = (outer, inner) => ({
  ...inner,
  ...outer,
  _: [
    ...(outer._ || []),
    ...(inner._ || [])
  ]
})

mergeArgs(mergeLeft)({args})

Result:

{
  args: {
    _: ['--help', '-v'],
    version: {type: 'flag', count: 2},
    name: 'Arthur',
    help: true,
    verbose: true
  }
}
numberAsFlag(key)
Transforms numbers with key in args to flag objects. The number becomes the flag's count. E.g. {answer: 42} becomes {answer: {type: 'flag', count: 42}}.

Example:

const args = {
  _: [],
  answer: 42
}

numberAsFlag('answer')({args})

Result:

{
  _: [],
  answer: {type: 'flag', count: 42}
}
numbersAsFlags
Transforms all numbers in args to flag objects using numberAsFlag.

Example:

const args = {
  _: [],
  answer: 42
}

numbersAsFlags({args})

Result:

{
  _: [],
  answer: {type: 'flag', count: 42}
}
traverseArgs(fs)
Transforms args by applying functions fs to each key/value pair based on the value's type.

fs supports the following types: array, boolean, flag, function, null, number, object, string, undefined, and otherwise. The default behavior for most types is to not change the value, with three notable exceptions: functions and otherwises key/value pairs are removed from args, while object's default function applies fs to nested objects. {flag: ({key, val, errs, args}) => ({errs, args})} is the signature for fs with fields for each type. Many other args checks and stages are defined in terms of traverseArgs and it is of great help for writing custom args stages.


Example:

const {traverseArgs} = require('shargs/parser')

const args = {
  verbose: {type: 'flag', count: 2},
  answer: 23
}

const fs = {
  flag:   ({key, val, errs, args}) => ({
    errs,
    args: {...args, [key]: val.count}
  }),
  number: ({key, val, errs, args}) => ({
    errs,
    args: {...args, [key]: val + 19}
  })
}

traverseArgs(fs)({args})

Result:

{
  args: {
    verbose: 2,
    answer: 42
  }
}

Allowed fs fields:

const fs = {
  array:     ({key, val, errs, args}) => ({errs, args}),
  boolean:   ({key, val, errs, args}) => ({errs, args}),
  flag:      ({key, val, errs, args}) => ({errs, args}),
  function:  ({key, val, errs, args}) => ({errs, args}),
  null:      ({key, val, errs, args}) => ({errs, args}),
  number:    ({key, val, errs, args}) => ({errs, args}),
  otherwise: ({key, val, errs, args}) => ({errs, args}),
  object:    ({key, val, errs, args}) => ({errs, args}),
  string:    ({key, val, errs, args}) => ({errs, args}),
  undefined: ({key, val, errs, args}) => ({errs, args})
}

Advanced Parser Stages

Automatic Usage Documentation Generation

Shargs strictly separates the concerns of parsing command-line arguments and generating usage documentation. The shargs-usage module specializes on generating terminal-based usage documentation for --help flags from command-line options:

const {desc, optsLists, space, synopses, usage} = require('shargs/usage')

const docs = usage([
  synopses,
  space,
  optsLists,
  space,
  desc
])

shargs-usage lets you define how your usage documentation should look like in a declarative way. In the example, we tell our docs to start with synopses, have optsLists in the body, and close with a description. We separate these three parts with spaces and enclose everything in a usage function.

Note that we did not mention any command-line options, yet:

const {command, flag, number, stringPos} = require('shargs/opts')

const opts = [
  stringPos('question', {desc: 'Ask a question.', required: true}),
  number('answer', ['-a', '--answer'], {desc: 'The answer.', defaultValues: [42]}),
  flag('help', ['-h', '--help'], {desc: 'Print this help message and exit.'})
]

const deepThought = command('deepThought', opts, {
  desc: 'Deep Thought was created to come up with the Answer to ' +
        'The Ultimate Question of Life, the Universe, and Everything.'
})

const optsDocs = docs(deepThought)

optsDocs now knows what to layout (deepThought), and how to layout it (docs). Finally, we style the different parts (lines and columns) of the documentation:

const style = {
  line: [{width: 60}],
  cols: [{width: 25}, {width: 35}]
}

const text = optsDocs(style)

Now, if we console.log(text), the following text is printed to the console:

deepThought (<question>) [-a|--answer] [-h|--help]          
                                                            
<question>               Ask a question. [required]         
-a, --answer=<number>    The answer. [default: 42]          
-h, --help               Print this help message and exit.  
                                                            
Deep Thought was created to come up with the Answer to The  
Ultimate Question of Life, the Universe, and Everything.    

deepThought, docs, and style are the moving parts of automatic usage documentation generation and are defined independently. We have already talked about command-line options before and will talk about style in an upcoming section.

Usage Functions

shargs-usage provides the following usage functions to declare layouts:

             Usage Function               Description
desc
descWith({id})
desc takes a command-line option's desc field and formats it according to a style.

If the description is too long to fit one line, it is split and spread over several lines. desc is defined as descWith({id: 'line'}).


Example:

Deep Thought should answer the Ultimate 
Question                                

Code:

const {desc, usage} = require('shargs/usage')

const opt = {
  opts: [],
  desc: 'Deep Thought should answer the Ultimate Question'
}

const style = {
  line: [{width: 40}]
}

usage([
  desc
])(opt)(style)
note(string)
noteWith({id})(string)
note takes a string and formats it according to a style, ignoring its second parameter.

If the string is too long to fit one line, it is split and spread over several lines. note is defined as noteWith({id: 'line'}).


Example:

Deep Thought was created to come up with
the Answer                              

Code:

const {note, usage} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

usage([
  note('Deep Thought was created to come up with the Answer')
])()(style)
notes(strings)
notesWith({id})(strings)
notes takes a list of strings and formats it according to a style, ignoring its second parameter.

If a string is too long to fit one line, it is split and spread over several lines. notes is defined as notesWith({id: 'line'}).


Example:

Deep Thought was created to come up with
the Answer                              
to The Ultimate Question.               

Code:

const {notes, usage} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

usage([
  notes([
    'Deep Thought was created to come up with the Answer',
    'to The Ultimate Question.'
  ])
])()(style)
optsDef
optsDefWith({id, pad})
optsDef layouts its opts as a definition list and formats it according to its style.

The term part comprises of an opt's args, descArg, only, types, and key fields, followed by the contradicts, defaultValues, implies, and required fields. The desc field is given in the definition part. optsDef is defined as optsDefWith({id: 'line', pad: 4}).


Example:

-a, --answer=<number> [default: 42]     
    The answer.                         
-h, --help                              
    Prints help.                        
--version                               
    The version.                        

Code:

const {optsDef, usage} = require('shargs/usage')
const {flag, number} = require('shargs/opts')

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer.', defaultValues: ['42']
    }),
    flag('help', ['-h', '--help'], {desc: 'Prints help.'}),
    flag('version', ['--version'], {desc: 'The version.'})
  ]
}

const style = {
  line: [{width: 40}]
}

usage([
  optsDef
])(opt)(style)
optsDefs
optsDefsWith({id, pad})
optsDefs first layouts its opts and then the opts of all its subcommands recursively, using optsDefs, indenting each optsDef layer by pad spaces.

optsDefs is defined as optsDefsWith({id: 'line', pad: 4}).


Example:

-a, --answer=<number> [default: 42]     
    The answer.                         
-h, --help                              
    Show the usage docs.                
ask [required]                          
    Ask questions.                      
    -h                                  
        Usage docs.                     
    <questions>... [required]           
        Questions.                      

Code:

const {optsDefs, usage} = require('shargs/usage')
const {flag, subcommand} = require('shargs/opts')
const {number, variadicPos} = require('shargs/opts')

const required = true

const askOpts = [
  flag('help', ['-h'], {desc: 'Show the usage docs.'}),
  variadicPos('questions', {required, desc: 'Questions.'})
]

const ask = subcommand(askOpts)

const opt = {
  opts: [
    ask('ask', ['ask'], {desc: 'Ask questions.', required}),
    number('answer', ['-a', '--answer'], {
      desc: 'The answer.', defaultValues: ['42']
    }),
    flag('help', ['-h', '--help'], {desc: 'Usage docs.'})
  ]
}

const style = {
  line: [{width: 40}]
}

usage([
  optsDefs
])(opt)(style)
optsList
optsListWith({id})
optsList layouts its opts as a table with two columns and formats it according to its style.

The first column comprises of an opt's args, descArg, only, types, and key fields. The desc field is given in the second column, followed by the contradicts, defaultValues, implies, and required fields. optsList is defined as optsListWith({id: 'cols'}).


Example:

-a, --answer=<number>    The answer. [default: 42]
-h, --help               Prints help.             
--version                The version.             

Code:

const {optsList, usage} = require('shargs/usage')
const {flag, number} = require('shargs/opts')

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer.', defaultValues: ['42']
    }),
    flag('help', ['-h', '--help'], {desc: 'Prints help.'}),
    flag('version', ['--version'], {desc: 'The version.'})
  ]
}

const style = {
  cols: [{width: 25}, {width: 25}]
}

usage([
  optsList
])(opt)(style)
optsLists
optsListsWith({id, pad})
optsLists first layouts its opts and then the opts of all its subcommands recursively, using optsLists, indenting the first column of each optsList layer by four spaces.

optsLists is defined as optsListsWith({id: 'cols', pad: 4}).


Example:

-a, --answer=<number>    The answer. [default: 42]
-h, --help               Usage docs.              
ask                      Ask questions. [required]
    -h                   Show the usage docs.     
    <questions>...       Questions. [required]    

Code:

const {optsLists, usage} = require('shargs/usage')
const {flag, subcommand} = require('shargs/opts')
const {number, variadicPos} = require('shargs/opts')

const required = true

const askOpts = [
  flag('help', ['-h'], {desc: 'Show the usage docs.'}),
  variadicPos('questions', {required, desc: 'Questions.'})
]

const ask = subcommand(askOpts)

const opt = {
  opts: [
    ask('ask', ['ask'], {desc: 'Ask questions.', required}),
    number('answer', ['-a', '--answer'], {
      desc: 'The answer.', defaultValues: ['42']
    }),
    flag('help', ['-h', '--help'], {desc: 'Usage docs.'})
  ]
}

const style = {
  cols: [{width: 25}, {width: 25}]
}

usage([
  optsLists
])(opt)(style)
space
spaceWith({id, lines})
space ignores its first argument and returns a line consisting entirely of spaces, with a width according to style.

space is defined as spaceWith({id: 'line', lines: 1}).


Example:

Deep Thought was created to come up with
                                        
the Answer to The Ultimate Question.    

Code:

const {note, space, usage} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

usage([
  note('Deep Thought was created to come up with'),
  space,
  note('the Answer to The Ultimate Question.')
])()(style)
synopses
synopsesWith({id})
synopses first layouts its opts and then the opts of all its subcommands, using a synopsis each.

synopses is defined as synopsesWith({id: 'line'}).


Example:

deepThought (-a|--answer) [-h|--help]   
deepThought (ask) [-h] (<questions>...)   

Code:

const {synopses, usage} = require('shargs/usage')
const {command, flag, number} = require('shargs/opts')
const {subcommand, variadicPos} = require('shargs/opts')

const required = true

const askOpts = [
  flag('help', ['-h']),
  variadicPos('questions', {required})
]

const ask = subcommand(askOpts)

const opts = [
  ask('ask', ['ask'], {required}),
  number('answer', ['-a', '--answer'], {required}),
  flag('help', ['-h', '--help'])
]

const deepThought = command('deepThought', opts)

const style = {
  line: [{width: 40}]
}

usage([
  synopses
])(deepThought)(style)
synopsis
synopsisWith({id})
synopsis layouts the program's name in the first and its opts in the second column of a table and formats it according to its style.

For each opt, the args, descArg, only, required, types, and key fields are used for a brief overview. synopsis is defined as synopsisWith({id: 'line'}).


Example:

deepThought (-a|--answer) [-h|--help]   
            [--version] <questions>...  

Code:

const {synopsis, usage} = require('shargs/usage')
const {command, flag} = require('shargs/opts')
const {number, variadicPos} = require('shargs/opts')

const opts = [
  number('answer', ['-a', '--answer'], {
    desc: 'The answer.', required: true
  }),
  flag('help', ['-h', '--help'], {desc: 'Prints help.'}),
  flag('version', ['--version'], {desc: 'The version.'}),
  variadicPos('questions')
]

const deepThought = command('deepThought', opts)

const style = {
  line: [{width: 40}]
}

usage([
  synopsis
])(deepThought)(style)

Usage Combinators

While usage functions taken for themselves are useful, they really begin to shine if they are combined by usage combinators. Usage combinators are higher-order usage functions that take other usage functions as parameters, combine them in various ways, and return a new usage function.

Let's see how usage combinators may be used to implement synopses:

const {decorate, noSubcommands, onlySubcommands} = require('shargs/usage')
const {optsMap, synopsis, usage, usageMap} = require('shargs/usage')

const prefixKey = prefix => optsMap(opts => ({...opts, key: prefix + ' ' + opts.key}))

function synopses (opt) {
  return usage([
    noSubcommands(synopsis),
    decorate(prefixKey(opt.key), onlySubcommands)(
      usageMap(synopses)
    )
  ])(opt)
}

This example uses usage decorators, that are only introduced in the next section. The implementation of synopses uses two usage combinators: usage and usageMap.

usage is used to combine two usage functions: A synopsis of all opts, but subcommands, and the usage function returned by usageMap. usageMap iterates over all subcommands and recursively calls synopses on each subcommand's opts. The recursion stops, if opt's opts has no more subcommands, since usage functions with empty opts return an empty string.

Combinators are a powerful feature, as they let you build more complex things from smaller parts. shargs-usage provides the following usage combinators:

                  Usage Combinator                   Description
usage(functions)(opt)(style)
usage takes a list of usage functions that each take an opt, a style and return a string. It then applies its own opt and style to each function, and concatenates the resulting strings.

Example:

deepThought [-a|--answer] [-h|--help] [--version] 
                                                  
-a, --answer=<number>    The answer.              
-h, --help               Prints help.             
--version                Prints version.          
                                                  
Deep Thought was created to come up with the      
Answer.                                           

Code:

const {note, optsList, space} = require('shargs/usage')
const {synopsis, usage} = require('shargs/usage')
const {command, flag, number} = require('shargs/opts')

const opts = [
  number('answer', ['-a', '--answer'], {desc: 'The answer.'}),
  flag('help', ['-h', '--help'], {desc: 'Prints help.'}),
  flag('version', ['--version'], {desc: 'Prints version.'})
]

const deepThought = command('deepThought', opts, {
  desc: 'Deep Thought was created to come up with the Answer.'
})

const style = {
  line: [{width: 50}],
  cols: [{width: 25}, {width: 25}]
}

usage([synopsis, space, optsList, space, desc])(deepThought)(style)
usageMap(f)({opts})(style)
usageMap takes a function f that takes an option and returns a layout function. It maps f over the option's opts and applies its style to each resulting layout function. Finally, it concatenates the resulting strings and returns the result.

Example:

-a, --answer                            
    The answer.                         
-h, --help                              
    Prints help.                        
--version                               
    Prints version.                     

Code:

const {text, textWith, usageMap} = require('shargs/usage')
const {flag, number} = require('shargs/opts')

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {desc: 'The answer.'}),
    flag('help', ['-h', '--help'], {desc: 'Prints help.'}),
    flag('version', ['--version'], {desc: 'Prints version.'})
  ]
}

const style = {
  line: [{width: 40}]
}

usageMap(({args, desc}) => layout([
  text(args.join(', ')),
  textWith({id: 'desc'})(desc)
]))(opt)(style)

Usage Decorators

When defining layouts, we may want to feature some opts in one place, and the remaining in a different place of our documentation. Maybe the subcommands should be presented in a definition list, while the other options are layed out as a table.

Usage decorators enable these use cases by modifying inputs of usage functions:

const {desc, optsDef, optsList, space, synopsis, usage} = require('shargs/usage')
const {decorate, noSubcommands, onlyFirstArg, onlySubcommands} = require('shargs/usage')

const decoratedDocs = usage([
  noSubcommands(onlyFirstArg(synopsis)),
  space,
  onlySubcommands(optsDef),
  space,
  noSubcommands(optsList),
  space,
  desc
])

The example uses three different decorators: noSubcommands, onlySubcommands, and onlyFirstArg. Each of these decorators modifies the opts array in some way, before passing it on to their wrapped usage function. The first two focus on filtering opts: noSubcommands removes all subcommands, while onlySubcommands keeps only subcommands. onlyFirstArg goes one step further and modifies each option in opts, removing all but the first argument in their args fields.

shargs-usage has the following usage decorators:

     Usage Decorator      Description
justArgs(args)(usageFunction)
justArgs modifies its opt by removing all opts that have no args field or whose args do not contain any argument given in the args list.

Example:

const {justArgs, usage} = require('shargs/usage')
const {flag, number, subcommand} = require('shargs/opts')

const style = {
  cols: [{width: 25}, {width: 25}]
}

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer'
    }),
    subcommand([])('ask', ['ask'], {desc: 'Asks a question'}),
    flag('version', ['--version'], {desc: 'Prints version'})
  ]
}

usage([
  justArgs(['-a'])(optsList)
])(opt)(style)

Result:

-a, --answer=<number>    The answer               
noSubcommands(usageFunction)
noSubcommands modifies its opt by removing all subcommands from its opts.

Example:

const {noSubcommands, usage} = require('shargs/usage')
const {flag, number, subcommand} = require('shargs/opts')

const style = {
  cols: [{width: 25}, {width: 25}]
}

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer'
    }),
    subcommand([])('ask', ['ask'], {desc: 'Asks a question'}),
    flag('version', ['--version'], {desc: 'Prints version'})
  ]
}

usage([
  noSubcommands(optsList)
])(opt)(style)

Result:

-a, --answer=<number>    The answer               
--version                Prints version           
onlySubcommands(usageFunction)
onlySubcommands modifies its opt by keeping only subcommands in its opts.

Example:

const {onlySubcommands, usage} = require('shargs/usage')
const {flag, number, subcommand} = require('shargs/opts')

const style = {
  cols: [{width: 25}, {width: 25}]
}

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer'
    }),
    subcommand([])('ask', ['ask'], {desc: 'Asks a question'}),
    flag('version', ['--version'], {desc: 'Prints version'})
  ]
}

usage([
  onlySubcommands(optsList)
])(opt)(style)

Result:

ask                      Asks a question          
onlyFirstArg(usageFunction)
onlyFirstArg modifies its opt by first keeping only opts that have args and by then removing all args but the first.

Example:

const {onlyFirstArg, usage} = require('shargs/usage')
const {flag, number, subcommand} = require('shargs/opts')

const style = {
  cols: [{width: 25}, {width: 25}]
}

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer'
    }),
    subcommand([])('ask', ['ask'], {desc: 'Asks a question'}),
    flag('version', ['--version'], {desc: 'Prints version'})
  ]
}

usage([
  onlyFirstArg(optsList)
])(opt)(style)

Result:

-a <number>              The answer               
ask                      Asks a question          
--version                Prints version           
optsFilter(p)(usageFunction)
optsFilter modifies its opt by applying a filter with the predicate p, whose function signature must be opt => true|false to its opts. Many other usage decorators are defined in terms of optsFilter and it is of great help for writing custom ones.

Example:

const {optsFilter, usage} = require('shargs/usage')
const {flag, number, subcommand} = require('shargs/opts')

const style = {
  cols: [{width: 25}, {width: 25}]
}

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer'
    }),
    subcommand([])('ask', ['ask'], {desc: 'Asks a question'}),
    flag('version', ['--version'], {desc: 'Prints version'})
  ]
}

usage([
  optsFilter(({types}) => types !== null)(optsList)
])(opt)(style)

Result:

-a, --answer=<number>    The answer               
ask                      Asks a question          
--version                Prints version           
optsMap(f)(usageFunction)
optsMap modifies its opt by applying a function f to each option in opts, whose function signature must be opt => opt. Many other usage decorators are defined in terms of optsMap and it is of great help for writing custom ones.

Example:

const {optsMap, usage} = require('shargs/usage')
const {flag, number, subcommand} = require('shargs/opts')

const style = {
  cols: [{width: 25}, {width: 25}]
}

const opt = {
  opts: [
    number('answer', ['-a', '--answer'], {
      desc: 'The answer'
    }),
    subcommand([])('ask', ['ask'], {desc: 'Asks a question'}),
    flag('version', ['--version'], {desc: 'Prints version'})
  ]
}

usage([
  optsMap(opt => ({...opt, args: opt.args.slice(0, 1)}))(optsList)
])(opt)(style)

Result:

-a <number>              The answer               
ask                      Asks a question          
--version                Prints version           

Usage Decorator Combinators

If many usage decorators are applied to a usage function, things get unwieldy, fast:

const {justArgs, noSubcommands, onlyFirstArg, synopsis} = require('shargs/usage')

const briefSynopsis = noSubcommands(onlyFirstArg(justArgs(['--help'])(synopsis)))

In the example, briefSynopsis is decorated three times and the code is not very readable. Usage decorator combinators facilitate a cleaner code layout:

const {decorate, justArgs, noSubcommands, onlyFirstArg, synopsis} = require('shargs/usage')

const decorated = decorate(noSubcommands, onlyFirstArg, justArgs(['--help']))

const briefSynopsis = decorated(synopsis)

This version of briefSynopsis is much more readable. Note, that decorate applies its usage decorators from right to left. As is apparent from the example, usage decorator combinators are usage decorators, themselves.

shargs-usage has the following usage decorator combinators:

           Usage Decorator Combinator               Description
decorate(decorators)(usageFunction) decorate takes many usage function decorators and applies them to its usageFunction from right to left.

Style

Layout functions are transformed to strings by applying styles:

const style = {
  line: [{width: 80}],
  cols: [{width: 25}, {width: 55}]
}

In the example, style provides the details for how many columns a usage documentation text should be wide, and whether it should have padding. A style is an object whose values are arrays of style objects, that must have a width key, and may have padEnd and padStart keys:

Parameter Type Description
padEnd number padEnd defines a padding to the right. It is filled with spaces.
padStart number padStart defines a padding to the left. It is filled with spaces.
width number width defines the length of text. The full length of the string is the width plus padEnd and padStart.

Advanced Usage Documentation

Building Command-line Parsers with Shargs

This section reuses code snippets from earlier sections:

                                                                                                                 Snippets                                                                                                                 
askOpts from the type functions section.
const askOpts = [
  {key: 'format', args: ['--format'], types: ['string'], only: ['json', 'xml'],
   defaultValues: ['json'], desc: 'Respond either with json or xml.'},
  {key: 'html', args: ['--no-html'], types: [], reverse: true, desc: 'Remove HTML tags.'},
  {key: 'help', args: ['-h', '--help'], types: [], desc: 'Print this help message and exit.'},
  {key: 'question', types: ['string'], required: true, desc: 'State your question.'}
]
deepThought from the command-line options section.
const {command, flag, number, subcommand} = require('shargs/opts')

const opts = [
  subcommand(askOpts)('ask', ['ask'], {required: true, desc: 'Ask a question.'}),
  number('answer', ['-a', '--answer'], {defaultValues: [42], desc: 'The answer.'}),
  flag('help', ['-h', '--help'], {desc: 'Print this help message and exit.'})
]

const deepThought = command('deepThought', opts, {
  desc: 'Deep Thought was created to come up with the Answer to ' +
        'The Ultimate Question of Life, the Universe, and Everything.'
})
parser from the parserSync function section.
const {parserSync} = require('shargs')
const {cast, flagsAsBools, requireOpts, restrictToOnly} = require('shargs/parser')
const {reverseFlags, setDefaultValues, splitShortOpts} = require('shargs/parser')

const stages = {
  argv: [splitShortOpts],
  opts: [setDefaultValues, requireOpts, reverseFlags, cast],
  args: [flagsAsBools]
}

const substages = {
  ask: [...stages.opts, restrictToOnly]
}

const parser = parserSync(stages, substages)
docs from the automatic usage documentation generation section.
const {desc, optsLists, space, synopses, usage} = require('shargs/usage')

const docs = usage([
  synopses,
  space,
  optsLists,
  space,
  desc
])
style from the style section.
const style = {
  line: [{width: 80}],
  cols: [{width: 25}, {width: 55}]
}
Imagine these snippets were located in their own modules and were imported earlier. Then, a sample command-line program written with shargs could be:

const argv = process.argv.slice(2)
const {errs, args} = parser(deepThought)(argv)

if (args.help) {
  const help = docs(deepThought)(style)
  console.log(help)
  process.exit(0)
}

if (errs.length > 0) {
  errs.forEach(({code, msg}) => console.log(`${code}: ${msg}`))
  process.exit(1)
}

console.log(`The answer is: ${args.answer}`)
process.exit(0)

First, we skip the first two values of process.argv. They are node and the file name and can be ignored.

We then parse the remaining argv with our deepThought parser and get two results: A list of errs, and an args object with parsed argument values. Based on those two results, we build our program.

If the args.help field is set, we print a help text generated from docs by applying deepThought and style. Then, we exit with exit code 0.

If we run the program with node ./deepThought --help, the following text is printed:

deepThought [-a|--answer] [-h|--help]                                           
deepThought (ask) [--format] [--no-html] [-h|--help] (<question>)                 
                                                                                
-a, --answer=<number>    The answer. [default: 42]                              
-h, --help               Print this help message and exit.                      
ask                      Ask a question. [required]                             
    --format=<json|xml>  Respond either with json or xml. [default: json]       
    --no-html            Remove HTML tags.                                      
    -h, --help           Print this help message and exit.                      
    <question>           State your question. [required]                        
                                                                                
Deep Thought was created to come up with the Answer to The Ultimate Question of 
Life, the Universe, and Everything.                                             

If the errs array has errors, we print all errors and exit with exit code 1. E.g. if we execute node ./deepThought --answer 5, without specifying the required ask subcommand, the following text appears:

Required option is missing: An option that is marked as required has not been provided.

Otherwise, we print the args.answer. E.g. if we run it with node ./deepThought ask "What is the meaning of Life, the Universe, and Everything?", it prints:

The answer is: 42

More In-depth Documentation

Feel free to skip this section if you are new to Shargs. It introduces more advanced topics:

Installing as Bundle or Modules

Since version 0.26.0, shargs may be installed in two different ways: Either as a bundle (recommended), or individually as modules.

npm install --save shargs        # bundle installation (core, opts, parser, and usage)

npm install --save shargs-core   # module (in bundle: shargs/core or shargs)
npm install --save shargs-opts   # module (in bundle: shargs/opts)
npm install --save shargs-parser # module (in bundle: shargs/parser)
npm install --save shargs-usage  # module (in bundle: shargs/usage)
npm install --save shargs-repl   # module (not in bundle)

The shargs bundle combines several modules in one distribution with its own version number. The advantage for the user is that the module versions are guaranteed to be compatible and updates are simpler.

Installing individual modules is more flexible, e.g. if you want to use a specific set of module versions, if one module of the bundle is not needed or if one of the modules is replaced with a different implementation.

It is recommended to start with the bundle installation and import modules like require('shargs/opts') or import 'shargs/core'. If you want to switch to a module installation later, you may simply replace your imports with module imports: E.g. require('shargs-opts') and import 'shargs-core'.

If you are using modules and need to know which versions are compatible, you may refer to the module versions used by the shargs bundle.

Multiple Subcommands

Shargs supports specifying multiple subcommands. E.g. you could use both, the ask and design subcommands in the same command in the following version of deepThought:

const {command, flag, number, stringPos, subcommand} = require('shargs/opts')

const ask = subcommand([stringPos('question')])
const design = subcommand([stringPos('name')])

const opts = [
  ask('ask', ['ask'], {desc: 'Ask a question.'}),
  design('design', ['design'], {desc: 'Design a more powerful computer.'}),
  flag('help', ['-h', '--help'], {desc: 'Print this help message and exit.'})
]

const deepThought = command('deepThought', opts, {desc: 'Ask the Ultimate Question.'})

If you provide both subcommands in your argv, both are parsed:

const argv = ['design', 'Earth', 'ask', 'What is the answer to the Ultimate Question?']

const parse = parserSync()(deepThought)

const {argv, errs} = parse(argv)

console.log(argv)
/*
{
  _: [],
  ask: {
    _: [],
    question: 'What is the answer to the Ultimate Question?'
  },
  design: {
    _: [],
    name: 'Earth'
  }
}
*/

Note that the subcommand order is not preserved. This is due to the default behavior of fromArgs, that keeps only the first mention of a subcommand and merges all subcommands into an (unordered) object.

The input to fromArgs is still ordered and has duplicates, so if your program needs the subcommand order or duplicates, just write a custom fromArgs stage:

const merge = (obj1, obj2) => ({
  ...obj1,
  subcommands: [
    ...(obj1.subcommands || []),
    obj2
  ]
})

const fromArgs = ({errs, args}) => ({
  errs,
  args: args.slice(1).reduce(merge, args[0])
})

This demonstration implementation of fromArgs is very simple and lacks some features like e.g. subcommands of subcommands. Please improve it before using it in your production programs.

Building REPLs with Shargs

🚧 Work in progress: This feature is currently worked on and its API is not yet stable.

Shargs-repl lets you build REPLs with actions defined by shargs commands.

Custom Checks and Stages

Shargs makes writing and using custom checks and stages very simple. The only thing you have to do is to follow the correct function signatures for your check or stage, as given in the stages and substages sections. The following code snippets showcase very simple examples with the correct signatures.

Regardless of whether you implement a check or a stage, the most important thing to remember is: Always pass on errors!

Custom argv stage example:

function splitShortOpts ({errs = [], argv = []} = {}) {
  const argv2 = argv.flatMap(arg =>
    arg.length > 2 && arg[0] === '-' && arg[1] !== '-'
      ? arg.slice(1).split('').map(c => '-' + c)
      : arg
  )

  return {errs, argv: argv2}
}

If you write a custom argv stage, have a look at traverseArgv!

Custom opts stage example:

function demandACommand ({errs = [], opts = []} = {}) {
  const errs2 = []

  const aCommand = opts.some(
    ({key, args, types, opts}) => (
      typeof key !== 'undefined' &&
      typeof types === 'undefined' &&
      Array.isArray(args) && Array.isArray(opts)
    )
  )

  if (!aCommand) {
    errs2.push({
      code: 'CommandRequired',
      msg:  'No command found. Please use at least one command!',
      info: {options: opts}
    })
  }

  return {errs: errs.concat(errs2), opts}
}

If you write a custom opts stage, have a look at traverseOpts!

Custom args stage example:

const {traverseArgs} = require('shargs/parser')

function flagsAsBools ({errs = [], args = {}} = {}) {
  const fs = {
    flag: ({key, val, errs, args}) => ({
      errs,
      args: {...args, [key]: val.count > 0}
    })
  }

  const {errs: errs2, args: args2} = traverseArgs(fs)({args})

  return {errs: errs.concat(errs2), args: args2}
}

If you write a custom args stage, have a look at traverseArgs!

Layout Functions

Usage functions that are applied to an opt yield so called layout functions. If we take a closer look at the signatures of usage and layout functions, the connection between the two becomes apparent:

Type Function Signature Description
Layout Function style => string Layout functions take a style and return a string.
Usage Function opt => style => string Usage functions take an opt and return a layout function.

In shargs-usage, an opt's purpose is to provide the textual contents of layout functions and the usage functions' only job is to specify how this textual content is extracted from the opt. The layout functions do the actual work of formatting strings.

Let's have a look at an example:

const {br, defs, layout, table, text} = require('shargs/usage')

const askDocs = layout([
  table([
    ['deepThought (ask)', '[--format] [--no-html] [-h|--help] (<question>)']
  ]),
  br,
  defs([
    ['--format=<json|xml> [default: json]', 'Respond either with json or xml.'],
    ['--no-html', 'Remove HTML tags.'],
    ['-h, --help', 'Print this help message and exit.'],
    ['<question> [required]', 'State your question.']
  ]),
  br,
  text(
    'Deep Thought was created to come up with the Answer to ' +
    'The Ultimate Question of Life, the Universe, and Everything.'
  )
])

In the example, askDocs is a layout that comprises four different layout functions: table, br, defs, and text. Depending on how we style the layout, we get different strings:

const style = {
  line: [{width: 80}],
  cols: [{width: 16}, {width: 64}]
}

const string = askDocs(style)

If we console.log(string), the following text is printed to the console:

deepThought (ask) [--format] [--no-html] [-h|--help] (<question>)                 
                                                                                
--format=<json|xml> [default: json]                                             
    Respond either with json or xml.                                            
--no-html                                                                       
    Remove HTML tags.                                                           
-h, --help                                                                      
    Print this help message and exit.                                           
<question> [required]                                                           
    State your question.                                                        
                                                                                
Deep Thought was created to come up with the Answer to The Ultimate Question of 
Life, the Universe, and Everything.                                             

Experiment with style to get different layouts!

shargs-usage gives you the following layout functions:

              Layout Function                     Description
br
brWith({id, lines})
br returns a line filled with spaces, with a width according to style.

br is defined as brWith({id: 'line', lines: 1}).


Example:

Deep Thought was created to come up with
the Answer                              
                                        
to The Ultimate Question.               

Code:

const {br, layout, text} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

layout([
  text('Deep Thought was created to come up with the Answer'),
  br,
  text('to The Ultimate Question.')
])(style)
cols(columns)
colsWith({id})(columns)
cols takes a list of columns, where each column is a list of strings corresponding to lines.

It formats the columns according to their widths and cuts off strings that are too long. cols is defined as colsWith({id: 'cols'}).


Example:

-a, --answer=<number>    The answer. [default: 42]
-h, --help               Prints help.             
--version                Prints version.          

Code:

const {cols, layout} = require('shargs/usage')

const style = {
  cols: [{width: 25}, {width: 25}]
}

layout([
  cols([
    [
      '-a, --answer=<number>',
      '-h, --help',
      '--version'
    ],
    [
      'The answer. [default: 42]',
      'Prints help.',
      'Prints version.'
    ]
  ])
])(style)
defs(tuples)
defsWith({id, pad})(tuples)
defs takes a list of tuples, where each entry is a tuple of strings, with a term at the first and a definition at the second position.

It formats its tuples as a definition list over two lines, with the term in the first, and the definition in the second line. If a term or definition extends its line, it is continued in another line. defs is defined as defsWith({id: 'line', pad: 4}).


Example:

-a, --answer=<number> [default: 42]     
    The answer.                         
-h, --help                              
    Prints help.                        
--version                               
    Prints version.                     

Code:

const {defs, layout} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

layout([
  defs([
    ['-a, --answer=<number> [default: 42]', 'The answer.'],
    ['-h, --help', 'Prints help.'],
    ['--version', 'Prints version.']
  ])
])(style)
line(string)
lineWith({id})(string)
line takes a string and formats it according to a style's width.

If a string exceeds its width, it is cut off, otherwise, the width is filled up with spaces. It ends with a line break. line is defined as lineWith({id: 'line'}).


Example:

Deep Thought was created to come up with
the Answer                              

Code:

const {layout, line} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

layout([
  line('Deep Thought was created to come up with'),
  line('the Answer')
])(style)
lines(strings)
linesWith({id})(strings)
lines takes a list of strings and layouts each string with line.

lines is defined as linesWith({id: 'line'}).


Example:

Deep Thought was created to come up with
the Answer                              
to The Ultimate Question.               

Code:

const {layout, lines} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

layout([
  lines([
    'Deep Thought was created to come up with',
    'the Answer',
    'to The Ultimate Question.'
  ])
])(style)
table(rows)
tableWith({id})(rows)
table takes a list of rows, lays it out as a borderless table, and formats it according to a style.

If an entry exceeds the length of a column, it breaks into the next row. table is defined as tableWith({id: 'cols'}).


Example:

-a, --answer=<number>    The answer. [default: 42]
-h, --help               Prints help.             
--version                Prints version.          

Code:

const {layout, table} = require('shargs/usage')

const style = {
  cols: [{width: 25}, {width: 25}]
}

layout([
  table([
    ['-a, --answer=<number>', 'The answer. [default: 42]'],
    ['-h, --help', 'Prints help.'],
    ['--version', 'Prints version.']
  ])
])(style)
text(string)
textWith({id})(string)
text takes a string and formats it according to a style.

If the string exceeds a line, it continues on the next. text is defined as textWith({id: 'line'}).


Example:

Deep Thought was created to come up with
the Answer                              

Code:

const {layout, text} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

layout([
  text('Deep Thought was created to come up with the Answer')
])(style)
texts(strings)
textsWith({id})(strings)
texts takes a list of strings and layouts each string with text.

texts is defined as textsWith({id: 'line'}).


Example:

Deep Thought was created to come up with
the Answer                              
to The Ultimate Question.               

Code:

const {layout, texts} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

layout([
  texts([
    'Deep Thought was created to come up with the Answer',
    'to The Ultimate Question.'
  ])
])(style)

Layout Combinators

Layout combinators are functions that take layout functions as parameters and return new layout functions. They are the primary way of building more complex constructs from simpler components. The following examples demonstrate the use of layout combinators:

const {layout, layoutMap, textWith} = require('shargs/usage')

const defsWith = ({id}) => layoutMap(
  ([term, definition] = []) => layout([
    textWith({id})(term),
    textWith({id})(definition)
  ])
)

defsWith is implemented in terms of layout, layoutMap, and textWith. It maps over a list of term and definition pairs and layouts them as texts.

shargs-usage has the following layout combinators:

            Layout Combinator             Description
layout(functions)(style)
layout takes a list of layout functions that each take a style and return a string. It then applies its own style to each function, and concatenates the resulting strings.

Example:

const {layout, line} = require('shargs/usage')

const style = {
  line: [{width: 40}]
}

layout([
  line('Deep Thought was created to come up with'),
  line('the Answer')
])(style)

Result:

Deep Thought was created to come up with
the Answer                              
layoutMap(f)(list)(style)
layoutMap takes a function f that takes any value and returns a layout function. It maps f over the list and applies its style to each resulting layout function. Finally, it concatenates the resulting strings and returns the result.

Example:

const {layout, layoutMap, textWith} = require('shargs/usage')

const defsWith = ({id}) => layoutMap(
  ([term, definition] = []) => layout([
    textWith({id})(term),
    textWith({id})(definition)
  ])
)

const defs = defsWith({id: 'line'})

const style = {
  line: [{width: 40}]
}

defs([
  ['-a, --answer=<number> [default: 42]', 'The answer.'],
  ['-h, --help', 'Prints help.'],
  ['--version', 'Prints version.']
])(style)

Result:

-a, --answer=<number> [default: 42]     
    The answer.                         
-h, --help                              
    Prints help.                        
--version                               
    Prints version.                     

Layout Decorators

When working with layout functions that take a style as input, you sometimes want to modify this style just before it is passed to the function, and only for this function call. This is what layout decorators are for:

const {layout, layoutMap, pad, text} = require('shargs/usage')

const defs = layoutMap(
  ([term, definition] = []) => layout([
    text(term),
    pad(['line', 0], 4)(text(definition))
  ])
)

The example shows a sample implementation of defs using the pad layout decorator. Here, the term, as well as the definition have the same id, texts default id 'line'. However, we want to add a padding of 4 spaces to the definition. So we use pad to add 4 spaces to the id at the ['line', 0] path of style.

shargs-usage ships with the following layout decorators:

                         Layout Decorator                          Description
pad(path, spaces)(layoutFunction)
pad looks up the style object at the path in its style and modifies it, by adding a number of spaces to its padStart and subtracting the same number from its width. It then passes the modified style to its layoutFunction.

Example:

const {layout, pad, table} = require('shargs/usage')

const style = {
  cols: [{width: 20}, {width: 20}]
}

layout([
  pad(['cols', 0], 4)(table([['--answer', '42']]))
])(style)

Result:

    --answer        42                  
stylePath(path, f)(layoutFunction)
stylePath looks up the style object at the path in its style and modifies it by applying the function f to it. It then passes the modified style to its layoutFunction.
const {layout, stylePath, table} = require('shargs/usage')

const pad4 = obj => ({
  ...obj,
  padStart: (obj.padStart || 0) + 4,
  width: obj.width - 4
})

const style = {
  cols: [{width: 20}, {width: 20}]
}

layout([
  stylePath(['cols', 0], pad4)(table([['--answer', '42']]))
])(style)

Result:

    --answer        42                  

Layout Decorator Combinators

If many decorators are applied to a layout function, the resulting code can get deeply nested:

const {layout, pad, table} = require('shargs/usage')

const style = {
  cols: [{width: 25}, {width: 30}]
}

layout([
  pad(['cols', 0], 4)(
    pad(['cols', 1], 4)(
      table([
        ['-a, --answer=<number>', 'The answer. [default: 42]']
      ])
    )
  )
])(style)

Layout decorator combinators avoid nesting deeply, by first collecting layout decorators and applying them all at once:

const {decorate, layout, pad, table} = require('shargs/usage')

const style = {
  cols: [{width: 25}, {width: 30}]
}

const decorated = decorate(pad(['cols', 0], 4), pad(['cols', 1], 4))

layout([
  decorated(
    table([
      ['-a, --answer=<number>', 'The answer. [default: 42]']
    ])
  )
])(style)

Note, that decorate applies layout decorators from right to left.

shargs-usage contains the following layout decorator combinators:

             Layout Decorator Combinator              Description
decorate(decorators)(layoutFunction) decorate takes many layout function decorators and applies them to its layoutFunction from right to left.

Custom Layout Functions

Using your own layout function is straightforward: Your function only has to have the correct signature and it is ready to be used as a layout function: It must take a style object and return a string.

The following example showcases the custom table2 layout function that takes columns instead of rows as input:

const {table} = require('shargs/usage')

const table2 = (columns = []) => style => {
  const rows = []

  for (let i = 0; i < columns[0].length; i++) {
    const row = []
    for (let j = 0; j < columns.length; j++) {
      row.push(columns[j][i])
    }
    rows.push(row)
  }

  return table(rows)(style)
}

You may use table2 as a layout function if you apply it to a columns array, since that returns a function that takes a style argument and returns a string.

This is of course a very simplified example that makes many assumptions that are often not valid and should not be made in real projects. Your own function would most probably need much more validations and handling of edge cases.

Custom Usage Functions

Writing and using custom usage functions in shargs is very simple: You only have to write a function with the correct signature and it can be used as a usage function. It must take an opt object and a style object and return a string.

The following example shows the custom descs function that displays the options' descriptions:

const {text} = require('shargs/usage')

const desc = ({desc = ''} = {}) => text(desc)

Using usageMap simplifies the process of defining your own functions:

const {table, usageMap} = require('shargs/usage')

const optsTable = usageMap(
  ({key, args, required, desc}) => table([
    [(required ? '*' : '') + key, args.join(', '), desc]
  ])
)

Error Codes

shargs-core and shargs-parser report errors if a command-line option's syntax is invalid, or if checks fail. The following table contains all error codes currently in use and where they are thrown:

Code Message Thrown by
ArgumentIsNotABool The passed command line argument must either be 'true' or 'false'. cast
ArgumentIsNotANumber The passed command line argument must be a number. cast
CommandExpected Expected a command with a string "key" field and an "opts" array. verifyCommand
ContradictionDetected Some given keys contradict each other. contradictOpts
DidYouMean An unknown command-line argument was passed. Did you mean any of the following options? suggestOpts
FalseArgsRules Your args rules returned false. Please abide to the rules defined in verifyArgs. verifyArgs
FalseArgvRules Your argv rules returned false. Please abide to the rules defined in verifyArgv. verifyArgv
FalseOptsRules Your opts rules returned false. Please abide to the rules defined in verifyOpts. verifyOpts
ImplicationViolated Some given keys that imply each other are not all defined. implyOpts
IncompatibleTypes Repeated options must either both be variadic or both not. arrayOnRepeat
InvalidArgs The "args" field has an invalid value: "args" must be a non-empty array of strings. verifyCommand
InvalidArity An option's types arity does not match its values arity. verifyValuesArity
InvalidBoolMapping The mapping provided to broadenBools must only map from 'true' or 'false' to a list of alternatives. broadenBools
InvalidKey The "key" field has an invalid value: "key" must be a string, cannot be "_" or "--", and must not include whitespaces. verifyCommand
InvalidNestedCommand Commands cannot be nested inside commands. Did you forget an "args" field for your subcommand? verifyCommand
InvalidOptionsListInCombine Options list in combine was undefined, null or empty. verifyCommand
InvalidOpts The "opts" field has an invalid value: "opts" must be an array of command-line options and positional arguments. verifyCommand
InvalidRequiredPositionalArgument If a positional argument is required, all previous positional arguments must be required as well. The required field must either be undefined, true or false. validatePosArgs
InvalidTypes Each argument must have a types key that must be null or an array. verifyCommand
verifyValuesArity
InvalidValues An option's values field has an invalid type. verifyValuesArity
InvalidVariadicPositionalArgument Only the last positional argument may be variadic. validatePosArgs
OptionExpected A command-line option was expected, but something else was received. verifyCommand
PosArgExpected A positional argument was expected, but something else was received. verifyCommand
RequiredOptionMissing An option that is marked as required has not been provided. requireOpts
SubcommandExpected A subcommand was expected, but something else was received. verifyCommand
SubcommandRequired No subcommand found. Please use at least one subcommand! demandASubcommand
UnexpectedArgument An unexpected argument was used that has no option defined. failRest
UnknownCommandLineOptionType The command-line option or positional argument given is of an unknown type. verifyCommand
ValueRestrictionsViolated A value lies outside the allowed values of an option. restrictToOnly
WrongArgsRulesType The args rules are of a wrong type, please provide a predicate with the following signature: (args) => boolean. verifyArgs
WrongArgvRulesType The argv rules are of a wrong type, please provide a predicate with the following signature: (argv) => boolean. verifyArgv
WrongContradictsType The contradicts field has the wrong type, please provide an array of command-line option keys. contradictOpts
WrongFormatForRequiredOption A required option has values or defaultValues in the wrong format. Default values are different depending on the command-line option type: Commands take objects, flags take counts, and other options take arrays of the correct length. requireOpts
WrongImpliesType The implies field has the wrong type, please provide an array of command-line option keys. implyOpts
WrongOptsRulesType The opts rules are of a wrong type, please provide a predicate with the following signature: (options) => boolean. verifyCommand

FAQ

                     Question                      Answer
How can I use config objects with shargs?
A config object in this question denotes an object that is used to read in default values from a file or a URI. Shargs does not include reading and merging config objects because there are other specialized libraries for this task that are easy to use alongside shargs. There are several simple ways to combine shargs' args objects with config objects:

If you just want to have default values, you may want to check out the defaultValues options field. If this does not suffice or you have a different problem, read on.

Say we have read in a config object from somewhere:

const config = {
  question: 'How can I use config objects with shargs?',
  answer: 'Read the FAQ section!'
}

And we have run a shargs parser and have obtained the following args object:

const args = {
  _: [],
  question: 'What is the meaning of life, the universe, and everything?'
}

Then using the config object would just mean merging the two objects:

const preferArgs = {
  ...config,
  ...args
}

const preferConfig = {
  ...args,
  ...config
}

Of course these example merges are simple cases, because the objects are flat.

In case of subcommands, the args object would have (deeply) nested objects. Such cases are common and there are specialized libraries for merging deeply nested objects, like ramda or lodash:

const {mergeDeepLeft, mergeDeepRight} = require('ramda')

const preferArgs = mergeDeepLeft(args, config)

const preferConfig = mergeDeepRight(args, config)
Why do command-line options have a key field?
The key field is an apparent difference between shargs and other command-line parsers. So one might ask, why shargs uses it, while other parsers do not need it. But as is mostly the case, shargs has good reasons:

Command-line parsers read arguments and assign them to variables that are passed as inputs to programs. So we are dealing with two different sets of names, here: Names of arguments and names of variables. Those two sets are connected by a unidirectional mapping, where arguments map to variable names.

If a single argument would only ever map to a single variable, the two could just as well have the same name. But for more complex mappings, things start to get complex, too:

Say we have two arguments, -v and --version, that can be used interchangeably. If they would map to two variables, -v and --version, the program would have to have knowledge about the arguments being interchangeable, in order to correctly interpret its inputs. As leaking this knowledge to the program would be undesirable, parsers usually work around this by assigning the value of one argument to both variables. But now we are in a situation where we have two dependant variables that always have the same value. A less verbose solution is just letting both arguments map to the same variable (the key field):

const {string} = require('shargs/opts')

const opts = [
  string('version', ['-v', '--version'])
]

A special situation of two arguments mapping to the same variable is, when the arguments belong to separate options. This frequently occurs for flag and bool options that have a complement:

const {flag} = require('shargs/opts')

const opts = [
  flag('fun', ['--fun']),
  flag('fun', ['--no-fun'], {reverse: true})
]

In the example, --fun adds 1 to the flag count, while --no-fun adds -1 due to reverse (assuming the parser has the reverseFlags stage).

But we have other possible mappings yet to explore: Situations, where one argument maps to two different variable names. Say we have a --birthday argument and the birthday and age variables. birthday is a string in date format, while age is a number holding the current age, transformed by the custom ageAsNumber stage. This kind of mapping is only possible if the parser's arguments are independent of the program's variables.

So, command-line options have a key field, because:

  1. Separating internal variable names from external argument names is a good practice.
  2. Separating argument and variable names enables functionality that would otherwise not be possible.
  3. Separating arguments and variables makes interpreting variables less verbose for programs.

If you really do not need key fields and wish to use just argument names instead, it is straight forward to adjust the type function syntax accordingly:

const array2 = types => (args = [], fields = {}) => ({
  key: args.length > 0 ? args[0] : undefined,
  args,
  types,
  ...fields
})

const number2 = array2(['number'])

// ...
Can I use custom command-line option types like date?
Yes, you can add and use your own option types. Both, the command-line options DSL and the parser functions have been designed with this in mind:

Say you want to add your own custom date type. First, you need to add a command-line option of that type:

const {array} = require('shargs/opts')

const date = array(['date'])

A date is an option that takes exactly one argument, whose type is described as 'date'.

Now we have an option, we may want to write parser stages that work with dates. How about a stage that transforms dates to their millisecond representation:

const {traverseOpts} = require('shargs/parser')

function dateToMillis ({errs = [], opts = []} = {}) {
  const isDate = ({types}) => (
    Array.isArray(types) &&
    types.length === 1 &&
    types[0] === 'date'
  )

  const toMillis = string => new Date(string).getTime()

  const dateToMillis = opt => ({
    opts: [{
      ...opt,
      ...(Array.isArray(opt.values)
          ? {values: opt.values.map(toMillis)}
          : {}
      )
    }]
  })

  return traverseOpts(isDate)(dateToMillis)({errs, opts})
}

This parser stage works alongside the other parser stages. Note, that a real implementation would test much more edge cases, like dates that occur in arrays.

Can I use comma-separated values to define arrays?
shargs-parser does not include a parser stage to split comma-separated values into arrays. But it is easy enough to write a stage yourself:

We are inventing a new option type for this FAQ: commas:

const {array} = require('shargs/opts')

const commas = array(['commas'])

The commas type function is used to mark options we want to split.

We then write a custom opts stage to perform the splitting:

const {traverseOpts} = require('shargs/parser')

const isCommas = ({key, types, values}) => (
  typeof key !== 'undefined' &&
  Array.isArray(types) && types.indexOf('commas') > -1 &&
  Array.isArray(values) && values.length === types.length
)

const transformCommaArray = opt => {
  let values = []
  let types  = []

  for (let i = 0; i < opt.values.length; i++) {
    const value = opt.values[i]
    const type = opt.types[i]

    if (type === 'commas') {
      const elements = value.split(',')
      values = [...values, ...elements]
      types = [...types, ...Array.from({length: elements.length}, () => 'string')]
    } else {
      values.push(value)
      types.push(type)
    }
  }

  return {opts: [{...opt, types, values}]}
}

const splitCommas = traverseOpts(isCommas)(transformCommaArray)

splitCommas may now be used with options of type commas!

So why doesn't shargs-parser support comma-separated values by default? The reason is that using comma-separated values is just not that common. And if you nonetheless need comma-separated values, it is simple enough to implement yourself.

Why are --no-* arguments not reversed by the bestGuess* stages? The reason is because there is no simple way to opt-out of this functionality, once it is employed. You could add an optOutReverse parameter to each bestGuess* stage, I guess, but that would clutter the stages' signatures. So shargs decided to leave interpreting these arguments to the individual programs.
Can I have command-line options with 0..1 values?
An example for such an option would be ternary logics types, like true, false, unknown, that could be represented as a mixture of flags and bools. Shargs does not support such options out of the box, but you can implement them with some gotchas:

We generally recommend against using options with 0..1 cardinalities in programs. This is also why shargs does not support it.

A better approach is using an enumeration, implemented with the only options field and the restrictToOnly parser stage.

If you want to use it anyway, here is how you could do it in shargs:

Flags give you only two cases, the presence of the flag (true if flagsAsBools is used), and its absence (unknown):

const {flag} = require('shargs/opts')

const fun = flag('fun', ['--fun'])

You could add a third case by using only flags by defining a complement:

const {complement} = require('shargs/opts')

const noFun = complement('--no-')(fun)

Which is the same as writing:

const noFun = flag('fun', ['--no-fun'], {reverse: true})

If you provide --fun, the fun variable is set to true, on --no-fun it is set to false, and providing neither --fun, nor --no-fun would mean unknown.

You could implement the same behavior with an option that takes none or one argument, by using a combination of variable length arrays, aka subcommands and a custom command-line options field. The general idea is to mark a subcommand as threeValued with a field, and then transform it to a custom type in the opts stage.

First, let us define an option:

const {stringPos, subcommand} = require('shargs/opts')

const funOpts = [
  stringPos('threeValues')
]

const fun = subcommand(funOpts)('fun', ['--fun'], {threeValued: true})

Now, let us define an opts stage that transforms the subcommand:

const {traverseOpts} = require('shargs/parser')

const isThreeValued = ({threeValued}) => threeValued === true

  const toThreeValued = opt => {
  const types = ['threeValued']

  let values = ['unknown']

  if (Array.isArray(opt.values)) {
    const threeValues = opt.values.find(opt => opt.key === 'threeValues')
    values = threeValues.values || ['true']
  }

  return {
    opts: [
      {...opt, types, values: values.slice(0, 1), opts: undefined}
    ]
  }
}

const subcommandsToThreeValued = traverseOpts(isThreeValued)(toThreeValued)

subcommandsToThreeValued only transforms subcommands that have the threeValued field. For each subcommand, it checks, whether the subcommand is not present (unknown), it is present but has no values (true), or if it is present and has at least one value, (true if the value is true, false if it is false, otherwise unknown).

Note that this sample implementation is very brittle and should not be used as presented in a program.

Can I use enums?
Yes, you can use enums with a combination of string command-line options, the only options field, and the restrictToOnly parser stage:
const {string} = require('shargs/opts')

const answers = string('answers', ['-a'], {only: ['yes', 'no', 'maybe']})
Can I use keys like 'a.b', indicating object fields?
Some command-line parsers allow arguments of the form --a.b 42, whose values are stored in nested objects {a: {b: 42}}. Shargs does not provide this functionality. However, it is very easy to write your own parser stage for it:

First, let us write a helper function for traversing args objects:

function traverseKeys (p) {
  return f => ({errs, args}) => Object.keys(args).reduce(
    ({errs, args: obj}, key) => {
      const val = args[key]
      if (!Array.isArray(val) && typeof val === 'object') {
        obj[key] = traverseKeys(p)(f)(val)
      }
      if (p(key)) {
        const {[key]: _, ...rest} = obj
        obj = {...rest, ...f(key, val)}
      }
      return {errs, args: obj}
    },
    {errs, args}
  )
}

Using traverseKeys, we can implement a nestKeys args stage:

const _ = require('lodash')

const hasDots = key => key.indexOf('.') > -1

const nestValue = (key, val) => {
  const obj = {}
  _.set(obj, key, val)
  return obj
}

const nestKeys = traverseKeys(hasDots)(nestValue)

The nestKeys args stage should now nest the values into an object.

The reason why shargs does not include such a stage by default is, that this is a niche case that can be either implemented after parsing, or is easy enough to implement yourself.

Why do shargs' functions have several parameter lists?
Many functions have an unusual signature, like text(string)(style) and the question arises, why it is not text(string, style), instead. The reason has to do with function composition and tacit programming:

shargs builds command-line parsers and usage documentation by composing parser and usage functions with functions it calls combinators. An exemplary combinator function is layout(functions)(style).

layout takes a list of functions that have a common signature: They take a style, and return a string. Next, it takes its own style parameter and feeds it to each function, getting a list of strings. Then it concatenates all strings together, which results in a string:

const {layout, text} = require('shargs/usage')

const style = {line: [{width: 10}]}

const string = layout([
  text('First.'),
  text('Second.')
])(style)

// string === 'First.    \nSecond.   \n'

What layout basically gives us is a way to provide only one style parameter to a list of functions, instead of one parameter per function. But why does layout have to have such a weird signature?

Let us assume we had the following layout2 and text2 functions, instead:

const {layout, text} = require('shargs/usage')

const layout2 = (functions, style) => layout(functions)(style)

const text2 = (string, style) => text(string)(style)

How could we concatenate strings only using text2?

const style = {line: [{width: 10}]}

const string = text2('First.', style) + text2('Second.', style)

// string === 'First.    \nSecond.   \n'

Do you see how the style parameter is repeated for every function? It gets worse if you have more functions.

Now let us use layout2:

const style = {line: [{width: 10}]}

const string = layout2([
  style => text2('First.', style),
  style => text2('Second.', style)
], style)

// string === 'First.    \nSecond.   \n'

See how style is still repeated and we do not have the advantage of only providing it once? Actually, using layout2 looks worse than using just text2!

But we can do better and rewrite the same example with text and two parameter lists:

const {text} = require('shargs/usage')

const style = {line: [{width: 10}]}

const string = layout2([
  style => text('First.')(style),
  style => text('Second.')(style)
], style)

// string === 'First.    \nSecond.   \n'

And then we can apply an optimization: See how we define a function that takes a style and feed it to a function text('First.') that takes a style? This is redundant, and we can just leave out style altogether:

const {text} = require('shargs/usage')

const style = {line: [{width: 10}]}

const string = layout2([
  text('First.'),
  text('Second.')
], style)

// string === 'First.    \nSecond.   \n'

Now we do not repeat style for every function! The code is much shorter and is easier to read.

And we can do even better by using a signature like layout. Because then layout is also a function that takes a style and returns a string, like text, and can be used inside other layout functions!

const {layout, text} = require('shargs/usage')

const style = {line: [{width: 10}]}

const firstSecond = layout([
  text('First.'),
  text('Second.')
])

const andThird = layout([
  firstSecond,
  text('Third.')
])

const string = andThird(style)

// string === 'First.    \nSecond.   \nThird.    \n'

And although we have five functions that each take a style parameter, we only have to apply it once.

Shargs employs tacit programming techniques to reduce boilerplate in its DSLs. A side-effect is that function signatures are weird (the technical term is curried).

Some JavaScript libraries like Ramda and lodash/fp use a technique called auto-currying. If layout would be auto-curried, it would have the signatures of layout and layout2 at the same time and you could choose which one to use. Shargs decided against auto-currying its functions, since it is simple enough to curry your functions yourself if you wanted:

const {curry} = require('ramda')
const {layout} = require('shargs/usage')

const curriedLayout = curry((fs, style) => layout(fs)(style))

curriedLayout can now be used like layout and like layout2.

Comparison to Related Libraries

  shargs yargs commander.js minimist
Self-description Shargs turns command-line arguments parsing inside out and gives you fine-grained control over parser stages and usage docs. Yargs helps you build interactive command line tools, by parsing arguments and generating an elegant user interface. The complete solution for node.js command-line interfaces, inspired by Ruby's commander. Minimist is the guts of optimist's argument parser without all the fanciful decoration.
Focus A command-line parser library with a focus on enabling developers to easily and quickly build their own parsers of just the right size. A large parser with lots of features with a focus on providing the options out of the box. A medium parser with a strong focus on a textual DSL that makes it easy to define options. A tiny parser, mostly without an options schema, with a strong focus on optimistic parsing.
License MIT MIT MIT MIT
First Commit January 14th 2020 September 10th 2010 August 14th 2011 June 25th 2013
Customize Parsing Pick and choose your parser checks and stages, write and use custom checks and stages, and optionally define command-specific parsers. You can turn on and off some of yargs' parsing features, and use a kind of middleware similar to shargs' args stages. You may specify a function to do custom processing of option values. None that I am aware of.
Customize Usage Docs Use a DSL with many options to build custom usage documentation layouts with fine-grained control over styles. Allows specifying the scriptName, a usage string, an epilogue, examples as strings, and the number of columns after which to wrap. Display extra information by listening to the --help event, customize program name and usage description, and add custom description text. None that I am aware of.

Reporting Issues

Please report issues in the tracker!

Contributing

We are open to, and grateful for, any contributions made by the community. By contributing to shargs, you agree to abide by the code of conduct. Please read the contributing guide.

License

Shargs is MIT licensed.

Logo created by brgfx (www.freepik.com).

Package Sidebar

Install

npm i shargs

Weekly Downloads

5

Version

1.1.1

License

MIT

Unpacked Size

201 kB

Total Files

16

Last publish

Collaborators

  • yordle