npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@twilcynder/arguments-parser

v1.17.0

Published

Sometimes I need to make functions that might be useful for other developers. This is where i put them. No dependencies.

Downloads

9

Readme

NodeJS Arguments Parser(s)

This module provides various ways of easily parsing arguments given to a program (or any array of strings actually).

Install


npm add @twilcynder/arguments-parser

Quick Start

You can parse arguments either by passing instances or various Parsers to the parseArguments() function, but the simplest solution is to use a single ArgumentsManager and its methods.

import { ArgumentsManager } from "@twilcynder/arguments-parser";

let {parameter, switch, switch2, option, number, files, props} = new ArgumentsManager()
    .addParameter("parameter", {description: "A parameter"})
    .addSwitch("-s", {dest: "switch", description: "A Switch (mandatory)"})
    .addSwitch(["-S", "--switch2"], {dest: "switch", description: "Another switch (optional)"}, false)
    .addOption(["-o", "--option"], {description: "An Option"})
    .addOption(["-n", "--number"], {description: "Needs a number", type: "number"})
    .addMultiParameter("files")
    .setAbstract("A test program")
    .setMissingArgumentBehavior("Missing mandatory argument", null, false)
    .enableHelpParameter()
    .enablePropertyArguments("props")

    .parseProcessArguments()
    node test.js -s --option ye -n 12 prop=value file1 file2 * 

Basically, you add named parameters called "parsers", that will each take a value according to different behaviors (take any argument, check if a switch is present, etc).

Explanations for everything in these snippets below.

Usage

ArgumentsManager

The most basic way to use this library. An instance of ArgumentsManager can :

  • be configured with parsers, that will each handle different arguments
  • parse a set of arguments with those parser

Each parser has a destination, which is a name that will be used to identify the result of that parser (whether a certain witch was found, the value of a certain parameter, etc). Parsing will always return an object / dictionnary, associating each destination name to its value. This means that using JavaScript's destructuring assigment, you can place them in variables like this

let {param1, param2} = new ArgumentsManager()
    .addParameter("param1")
    .addParameter("param2")
    //and then you parse, we'll see how in a minute

Configure

All these methods return the ArgumentsManager instance, which means you can chain them (new ArgumentsManager().addOption().addParameter()...)

Universal options

All the "add" methods take an "option" parameter, used to fine-tune the behavior of the added parser. There are some options that work on all parsers; only the options that are specific to each parser will be listed below.

  • "default" : specifies the default value retrurned by the parser is it did not catch anything (and was optional)
  • "description" (string) : gives a description to the parser, used by the manual feature (see the --help/-h parameter)

An additional common (as in, compatible with multiple parsers but not all) option is "transform" : this option allows you to convert the value saved by a parser before it is returned.

  • If its value is "number", the value will be converted to an integer (using parseInt)
.addParameter(dest, options = {}, optional = true)

Adds a parameter parser, that will simply take the value of an basic argument. A "basic argument" is defined as any argument that did not match any option or switch parser (see below) and is not a property (also see below) The first argument is the destination name.

Options can be :

  • "last" (boolean) : if false, this parser will take the first basic argument and then stop parsing anything. If true, this parser will take every argument and save the last. This means that any parameter parser added after this one will be unable to read anything, as a single argument cannot be saved by multiple parsers.
  • type (string) :
    • "number" : value will be converted to a number (NaN if not convertible).

If "optional" is false, parsing methods will raise an error if this parser did not have anything to save.

This method supports the "transform" option (see Universal Options)

.addMultiParameter(dest, options = {})

Works like the parameter parser, except instead of saving a single argument it will save all basic arguments that aren't a switch, option or property.

As a single argument cannot be saved by multiple parsers, any parameter parsers added after this method is called will be unable to parse anything.

This parser does not take a "default" option, and simply returns an empty array if no arguments matched the conditions.

This method supports the "transform" option (see Universal Options) ; keep in mind that it will work in a slightly special way, as the conversion will not be applied to the value of this parser directly (which is an array), but to all of its elements.

.addSwitch(triggers, options = {}, optional = true)

Adds a switch parser. This parser takes one or many "triggers", and ignores anything that is not exactly one of these triggers. Is one of the triggers is ever encountered, the value returned by this parser will be true ; if not, it will be false.
The "triggers" parameter can either be a string or an array of strings.

The destination name for this parser can be specified in the options (as "dest"), but if any of the triggers starts with "--", the rest of the trigger (i.e. the trigger without the initial "--" will be used as the destination name).

If "optional" is false, parsing methods will raise an error if none of the triggers were seen. Note that making a switch mandatory is very rarely relevant.

.addOption(triggers, options = {}, optional = true)

Adds an option parser. This parser takes one or many "triggers", and ignores anything that is not exactly one of these triggers. Is one of the triggers is ever encountered, the value of the next argument will be saved.
The "triggers" parameter can either be a string or an array of strings.

The destination name for this parser can be specified in the options (as "dest"), but if any of the triggers starts with "--", the rest of the trigger (i.e. the trigger without the initial "--" will be used as the destination name).

Options can be :

  • length : if above 1, this parser will save this amount of arguments after the trigger, and return them as an array

If "optional" is false, parsing methods will raise an error if none of the triggers were seen.

This method supports the "transform" option (see Universal Options)

.addMultiOption(triggers, options = {}, optional = true)

Adds an repeatable option parser, which works just like the option parser, except it returns an array, saving a new element each time the trigger is found.

To clarify : this is a parser that always returns an array. Each time the parsed argument is one of the triggers you specified as the first argument (either a string or an array of strings), the next argument is added to the array.

This parser does not take a "default" option, and simply returns an empty array if the trigger was never seen.

Options can be :

  • length : if above 1, this parser will save this amount of arguments after each occurence of the trigger, and return an array of arrays

This method supports the "transform" option (see Universal Options) ; keep in mind that it will work in a slightly special way, as the conversion will not be applied to the value of this parser directly (which is an array), but to all of its elements.

.enablePropertyArguments(dest = "properties", description)

Enables property arguments parsing. This means that all "property arguments", which are all the arguments of form name=value will be collected in a single object / dictionnary.

Example :

let {props} = new ArgumentsManager()
    .enablePropertyArguments(props)
    .parseProcessArguments() //see below

console.log(props)

Running this propgram like this

node test.js prop1=foo prop2=bar

will produce the following result (content of the props variable)

{"prop1": "foo", "prop2": "bar"}

Note that if you do not call this method, "property arguments" will just be treated as basic arguments

.enableHelpParameter(noEffect) and .setAbstract(abstract)

Adds a special switch parser that detects either -h or --help.

  • If "noEffect" is false, when -h or --help are parsed it will display a help message ; the program will then exit with code 0.
  • If it is true, the parser will simply behave like a normal switch parser, with "help" as the destination, allowing you to control more accurately what happens when the user requested help.

This help message is composed of

  • A summary of all the parameters in the form of a "usage" string ("Usage : node program.js ...")
  • Optionnaly, a short text configured with setAbstract
  • A list of the parsers, with their description.
.enableRecursiveResult(dest = "all")

If this method is called with a string parameter, the result object of the parsing will contain a property pointing to itself (with the name specified by "dest").
This means that after running

let {param1, param2, all} = new ArgumentsManager()
    //...
    .enableRecursiveResult()
    .parseProcessArguments()

the "all" variable will contain the whole result of .parseProcessArguments(), including itself.
This is useful when you want to use the destructuring argument to assign the results to variables, but also keep the whole result object somewhere.

.setMissingArgumentBehavior(message, errorCode, throw_ = true)

Configures the behavior of the parsing methods in case a mandatory argument is missing.

  • "message" (string) will set the text message displayed or raised, depending on the next arguments. Note that this message will be followed by " : " and the destination name of the parameter that's missing.
  • "errorCode" (number), if specified, will make the program exit with the given error code.
  • "throw" (boolean) sets whether an exception is raised if an argument is missing. Pointless if "errorCode" is specified, as the program will exit before anything can be raised.
  • "log" (boolean) sets whether the "message" is logged to stderr on if an argument is missing

.apply(func)

Calls "func" on the ArgumentsManager and returns it. The main purpose of this is that if you want to reuse the same parameters across different distances, you can write a function taking an ArgumentsManager and calling the above methods on it, and then use .apply to call this function as part of the methods chain.

function config(am){
    am.addOption(    .addOption(["-o", "--output"], {
        description: "A file to save the output to. If not specified, the output will be sent to the std output."
    })
    .addSwitch(["-l", "--log"], {
        description: "Use to log the processed data (in a nice and pretty format) to the std output, the actual output is emitted"
    }))
}

//Without .apply

let manager = new ArgumentsManager();

config(manager)

manager
    .addParameter(...)
    .parseProgramArguments();

//with .apply

new ArgumentsManager()
    .apply(config)
    .addParameter(...)
    .parseProgramArguments();

Parse

After calling all the relevant configuration methods, and settings up what arguments you want to save in which destination, you can call on of these methods to parse arguments following your configuration.

.parseArguments(args)

Parses any array of arguments ("args").

.parseProcessArguments()

Parses the arguments of the current process.