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

grarg

v1.0.1

Published

A minimal, bring-your-own-logic command-line-argument parser

Downloads

8

Readme

grarg

“Grr. Argh.”Mutant Enemy

grarg is a minimal bring-your-own-logic parser for command-line arguments.

Why? What makes you think Node.js needs another argument parsing library?

Because every existing argument parser in the npm.com registry (or at least, all the ones I could find) follows the same flawed model. Not all command line arguments are map keys, and not all "bare" arguments are sequential. Many applications are better suited to a sort of state-machine argument parsing model, where options transform a state that determines how successive non-options are parsed.

For example, say you have a command like chug package --verbose --env production --images foo.png bar.png --rescale=50% huge.png --scripts --minify index.js helper.js update-and-push. It's pretty clear how this command would interpret these arguments, but there's no clean way to express it in a model like the one used by minimist (or its successors like yargs/getopts/caproal/mri).

With grarg, you can write your own option-by-option parsing logic with an iterative callback that takes options and values as a series of (sometimes partial) pairs.

API: grarg([argv,] [params,] cb)

The grarg function returned by require('grarg') takes an array of arguments (argv), an object of parameters (params - not yet implemented), and a function to call back with option/value pairs (cb).

argv defaults to process.argv.slice(2) by default. For most scripts, this is what you want. (If running in a binary-is-the-script environment like Electron, where there's no script name to chop off the argv array, you'll want to explicitly use process.argv.slice(1) instead.)

params effectively defaults to {"end": "--"} (though each parameter's default is considered individually if unspecified).

Callback signature

If an option begins with two hyphens, it will be passed to the callback as the first parameter (with those double-hyphens stripped).

If an option is followed by a value (either as a pair like --foo bar or with an equals sign like --foo=bar), the option and its accompanyng value are passed to the callback as its first and second parameters, respectively.

Note that this means --foo=bar is indistinguishable from --foo bar. If you support the first form, you ought to support the second form as an alternative syntax for the same specification: any kind of cleverness with differing behavior between the forms is user-hostile and unsupported.

Also note that this means you may get an option that is unrelated to the argument following it: for example, shred --quickly buster.dat lindsay.dat would be parsed as cb(null, "shred"), cb("quickly","buster.dat"), and cb(null, "lindsay.dat"). It's up to your callback to interpret and handle values that may be attached this kind of "unrelated" argument: always remember to check if a "standalone value" has been provided alongside any "standalone option".

If an option is followed by another option, the "standalone" option is passed to the callback with null as its second parameter.

If multiple successive non-hyphen-prefixed options are encountered, they will be passed to the callback with null as the first parameter.

For example, the command in the "Why?" section above, if passed to grarg((k,v)=>console.log(JSON.stringify([k,v]))), would look like:

[null, "chug"]
[null, "package"]
["verbose", null]
["env", "production"]
["images", "foo.png"]
[null, "bar.png"]
["rescale", "50%"]
[null, "huge.png"]
["scripts", null]
["minify", "index.js"]
[null,"helper.js"]
[null,"update-and-push"]

The end parameter

Not yet implemented.

If end is "--", the first standalone -- argument encountered in the input array will be passed to the callback as cb(null, "--"), and then all successive arguments will be passed to the callback with null as the first parameter, even if they appear to represent an option. (For example, -- --foo=bar would pass the second option as cb(null, "--foo=bar") and not cb("foo", "bar"))).

This is generally used to define a list of arguments for a subprocess, like in the case of ssh, where -- separates arguments to the SSH client SSH from arguments to a command to run on the host.

If end is a number, the first non-option argument after end number of non-options have been parsed will end argument parsing. A value of 1 will work like minimist's stopEarly (stopping parsing after the first non-option argument), and values of 2 and higher can be used to permit a number of positional arguments (such as commands or subcommands) before ceasing to parse options. (The value of 0 is reserved as a possible way to disable argument parsing altogether in certain circumstances.)

If end is false, any standalone -- argument will be passed to the callback as cb(null, "--"), and paired parsing will continue. (To reuse an earlier example, the second argument of -- --foo=bar would be passed as cb("foo", "bar") when end is false.).

Note that this means a standalone -- will always be interpreted as a standalone value, even when end is false. If you need to define "--" as the value of an option, you need to specify it using the = syntax, ie. --foo=-- is the only way to get a parse result of cb("foo", "--"). (Of course, this rule applies for any option-value that may begin with --, as longer strings would be interpreted as the beginning of a new option.)

The short parameter

Not yet implemented.

If params.short is true, items starting with a single hyphen will be treated as options (ie. they will cause a prior option to be passed as cb('--that-option',null)), and passed to the callback with '-' as the first argument, and the rest of the item as the second argument (for example, -xzf would be passed to the callback as cb('-','xzf')).

This can interfere with negative numbers as values, so if params.short is 'nan' (case-insensitive), this will only be applied if the argument does not evaluate to a number.

If params.short is false or undefined, arguments beginning with - are treated just like any other non-double-prefixed argument.

Note that the single hyphen - is always treated as an ordinary argument.

Note that, technically speaking, the call signature of short options with this parameter overlaps that of a triple-hyphen option, ie. --- foo is indistinguishable from -foo. If that's a problem for your use case, then don't use short.

Example usage

Here's some code that uses grargs to implement minimist's core default behavior in seven lines:

const args = {_:[]};
require('grarg')((key, value) => {
  key = key || '_';
  if (value === null) value = true;
  if (Array.isArray(args[key]) args[key].push(value);
  else if (args[key] !== undefined) args[key] = [args[key], value];
  else args[key] = value; });