Documentation
Parser

Parser

The ArgumentParser class is the main library component. It can be instantiated with a set of option definitions and provides methods to parse command-line arguments into option values.

Option values

The result of argument parsing is an object that contains the option values corresponding to the option definitions given in the parser constructor. There are different ways to obtain these values, as explained below.

Using a newly-created object

This is the easiest, most common method: you just call parse and await the returned promise. This method accepts two optional parameters:

  • cmdLine - the raw command line (string) or the command-line arguments (string[])
  • flags - a ParsingFlags object with the parsing flags

Normally you should not need to pass these parameters, as they have sensible default values. The command line defaults to the value of either the COMP_LINE or BUFFER environment variables (whichever is present) or the process arguments:

process.env['COMP_LINE'] ?? process.env['BUFFER'] ?? process.argv.slice(2);

If you feel the need to configure the parsing procedure, make sure to first understand how word completion works.

This method is asynchronous, so you must use await in order to resolve the returned promise.

Using your own object

This is a more flexible method that allows you to pass an existing object or class instance, which will be filled with the parsed values. It is named parseInto and accepts the same parameters as the previous one, except for an additional (first) parameter:

  • values - the option values to parse into

Existing values are preserved until they get overridden by values parsed either from the command line or from environment variables.

When using TypeScript, this parameter will be type-checked against the expected type of the option values for a given set of option definitions.

💡

Using IntelliSense, you can peak at the resulting type of the parse method, or declare a temporary type alias for OptionValues<typeof _your_options_>, to see how the object is structured.

This method returns a promise that resolves to a ParsingResult object containing the following properties:

Parsing flags

The parsing procedure can be configured with a ParsingFlags object that has some optional properties, as described below.

Program name

The progName property is a custom name for the main command, which is used to update the process title and is rendered in the help message's usage section. It defaults to the basename of the executing script:

process.argv[1].split(/[\\/]/).at(-1);
💡
You can set it to an empty string to suppress its appearance.
This flag is ignored when word completion is in effect.

Completion index

The compIndex property is the cursor position in a command line for which the user pressed Tab. It defaults to the value of either the COMP_POINT or CURSOR environment variables, or to the length of the BUFFER variable (whichever is present, otherwise undefined):

Number(process.env['COMP_POINT'] ?? process.env['CURSOR']) || process.env['BUFFER']?.length;

When invoking the parsing methods with a raw command line, and this flag is set, the parser will know to perform word completion for the argument ending at this position.

Cluster prefix

The clusterPrefix property specifies the prefix for cluster arguments. If set, then eligible arguments with this prefix may be considered a cluster. This must be used in conjunction with the cluster letters option attribute.

Option names have precedence over the cluster prefix. For example, if the prefix is a single dash and there's an option named '-flag', then an argument with this name will not be considered a cluster argument.

Parsing features

The parser supports a set of features that should fulfill most use cases. They are listed below.

Custom callbacks

Custom parsing operations are supported through the following kinds of callbacks:

All of these can be asynchronous, in which case the parser awaits their resolution, either because it needs their result or to avoid data races when reading and modifying the option values.

Note that there is no synchronous version of the parsing procedure. This is a design choice: in order to support a fully synchronous parse method using the same code base, the parser would have to deal with returned promises in a way that would make it hard to maintain (remember the classic callback hell (opens in a new tab)).

Besides, the asynchronous version has the benefit of allowing us to perform some operations, such as requirements checking, concurrently. This should not be a drawback for most applications, since argument parsing is usually done at the top-level of a module or script, where the await directive is available.

Argument sequence

An argument sequence is the occurrence of an option in the command line with possible parameters. The parser looks for option names or positional arguments once it finishes parsing the previous option, or if the latter is variadic.

For example, if the option initiating a sequence is a string option with a fallback value, the parser starts looking for new options as soon as it advances to the next argument, since that may be either the option's parameter or the start of a new sequence. Supposing that it is a parameter, once the parser advances past this argument, it knows that the next one must be the start of a sequence.

The same algorithm works for function options with a variable parameter count. For example, if the option expects between 1 and 3 parameters, the parser treats the next argument as a parameter to the option, regardless of whether it is an option name or not. Once the first parameter is saved, the parser resumes searching until 3 parameters are accumulated, at which point it must find an option specification (even if it is a new occurrence of the same option).

Sequence information

The information gathered by the parser is saved in a ParseInfo object that is passed as parameter to some of the custom callbacks. It contains details about the current argument sequence in the parsing loop:

  • values - The previously parsed values. It has an opaque type that should be cast to OptionValues<typeof your_options>.
  • index - The index of the occurrence of the option name, or of the first option parameter. It will be NaN if the sequence comes from an environment variable.
  • name - The option name as specified on the command-line, or the environment variable name. It will be the option's preferred name if the sequence comes from positional arguments.
  • param - The option parameter(s), or the parameters preceding the word being completed, if any.
  • comp - True if performing word completion, or the word being completed. Not available for the command callback.

Word completion

Quoting the Bash docs (opens in a new tab):

When word completion is attempted for an argument to a command for which a completion specification (a compspec) has been defined using the complete builtin (see Programmable Completion Builtins), the programmable completion facilities are invoked.

The parser does not use the completion facilities, because it relies on the raw command line and the cursor position into that line, which can be retrieved from the following environment variables:

  • COMP_LINE or BUFFER - the current command line
  • COMP_POINT or CURSOR - the index of the cursor position relative to the beginning of the command line

When these variables are available, the parser enters into completion mode: it truncates the command line at the cursor position and performs completion of the last argument.

The result of completion is a list of words separated by line breaks, which should be printed on the terminal so that the completion builtins can perform the final completion step.

The parser ignores any errors thrown by callbacks during completion. If an error is thrown by a completion callback, the default completion message (an empty list) will be thrown instead.

Completion algorithm

The completion algorithm implemented by the library is explained below. In what follows, comp is the word being completed, i.e., the command-line argument ending at the completion index (it may be an empty string):

  1. If comp is expected to be an option name:
    • If comp is a known option name, that name is returned; else
    • If there is no positional option, the available option names are filtered by the prefix comp and returned; else
    • comp is treated as a parameter of the positional option; go to step 2
  2. comp is the parameter of a non-niladic option, then either of the following is executed and its result is combined with that of step 3:
    • If the option has a complete callback, it is called with comp; else
    • If it is a boolean option, the option's truth and falsity names (if any) are filtered by the prefix comp; else
    • If the option has enumerated values, those values are converted to string and filtered by the prefix comp; else
    • An empty list is returned
  3. If the option was not specified with a positional marker, then, if either of the following holds true, the available option names are filtered by the prefix comp and returned:
    • It is the first argument in a sequence of positional arguments; or
    • It is not the first argument in a sequence, and is not short of the minimum expected parameter count of an option

If all of the above results in an empty list, the default completion (usually file completion, if enabled in the builtin's configuration) will be attempted. Note that the conditions of the third step exclude the possibility of it being an inline parameter, when considering option names.

Altered parsing behavior

Since the completion builtins always expect a list of words as a result, the library must suppress all errors that occur during parsing, and it does not make sense to perform some operations that might throw. Therefore, when word completion is in effect, parsing behavior will change in the following important ways:

  • parsing errors, such as unknown option names, are suppressed
  • unknown-valued options (help and version) are skipped
  • the command callback does not get executed
  • option requirements are not verified
  • cluster arguments are completed with the default completion (an empty list)
💡

Other arguments are processed as usual, which means that a completion callback can inspect the values parsed before it, in order to make better suggestions based on those values.

Requirements checking

When the parser evaluates option requirements, it compares an option's value against any value required by other options. Generally, this analysis is performed after all arguments have been parsed, but it may also be performed in two more situations:

As has been mentioned, requirements are not checked when word completion is in effect.

Name suggestions

When the parser expects an option name and the current argument is not a valid one (and there is no positional option), it may select option names that are similar to the current argument using the Gestalt algorithm (opens in a new tab), and include them in the error message.

Error messages

Error messages generated by the parser can be customized via the validator configuration, which can be provided as an additional parameter to the parser constructor.

Inline parameters

Option parameters may be passed on the command-line using the syntax <name>=<param>. This syntax is only valid for monadic or delimited options and cannot be used with the positional marker.

As is the case with standalone parameters, inline parameters may contain any number of equal signs, and even start with one (e.g., -opt==val would be parsed as '=val').

Cluster arguments may also have inline parameters, but their syntax is different. A cluster argument is considered to have an inline parameter if it contains an unknown letter that is not the first one in the cluster. In this case, the first letter must be an option and the rest is its parameter. See cluster inline parameters for details about this syntax.

Process title

The process title will be updated to reflect the current command being executed. This includes the main script and any nested commands. For example, if the command-line is:

path/to/main/script.js -flag0 cmd1 -flag1 cmd2 args...

The process title would be updated in the following way:

  1. node - this the starting title, before any updates
  2. node script.js - the title at the beginning of the parsing loop
  3. node script.js cmd1 - the title at the start of the cmd1 command
  4. node script.js cmd1 cmd2 - the title at the start of the cmd2 command

The title will remain unchanged after the parser returns. Other option names are not used, because they would pollute the output of process management utilities such as ps.