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

tauris

v1.8.2

Published

A simple Node.JS argument parser with subcommand support and a beautiful UI

Downloads

34

Readme

Tauris demonstrated in a terminal


Table of contents

⚡️ Quickstart

import { Command } from "tauris";

const mycommand = new Command("mycommand")
  .option("v", {
    alias: "version",
    description: "Display the version number",
    type: "boolean",
  })
  .demandArgument();

const options = mycommand.parse(process.argv.slice(2));

if (options?.v) console.log("versin 1.0.0");

🎨 Features

  • 🍃 Lightweight: Weighs in just under 7.5kb
  • ⚡️ Typescript Compatible: Provides typings out of the box
  • ✨ Clean User Interface: Render friendly, scannable help menus

🚀 Installation

$ npm i tauris # or: yarn add tauris

🧑‍💻 API Reference

new Command(name: string)

Creates a new command or subcommand:

import { Command } from "tauris";

const mycommand = new Command("mycommand");

Configuring Commands

A command can be configured with its "configuration methods" (.usage, .describe, .option, etc.). These methods will apply a configuration change to the command and then return the command they were called on to allow chaining them together. For example:

mycommand.describe("Description").usage("mycommand <subcommand>");

will first add a description, then set the usage string, and then return the command.

Basic Configuration

  • You can override the usage string using .usage(usage: string).
  • You can give your command a description using .description(description: string) (This description will be displayed in the help menu of the parent command, so if your command is not a subcommand, this option isn't useful.).
  • .header(header: string) adds a string that displays above the help message.

Options

You can add an option to a command using .option(nams: string[, options: CLIOptionOptions]):

mycommand.option(
  // Option name. If you want your option to have a short and long name, like
  // "-v" and "--version", use the short one here and make the longer one an
  // alias.
  "v",
  {
    // A single alias or list of alias names for the option
    alias: "version",
    // A short description to display in the help menu
    description: "Display version number",
    // Data type of the option (defaults to 'text')
    type: "boolean",
  }
);

The optional type option allows you to set one of three data types for your option: boolean, number or text (default is text). These will treat the given value differently:

  • Boolean will treat the option as a flag which is true if the option is present and false if it isn't, therefore

Root Options

If you need a command to pass options down to its subcommands, use .rootOption. This method takes the same arguments as .option. By using .clearRoot([names: string | string[]]), you can remove root options from a subcommand and its subcommands:

// Now, `mysubcommand` no longer has the `-s` root option, but other
// subcommands still do:
mysubcommand.clearRoot("s");

Subcommands

You can add any command as a subcommand by running parentCommand.command(subcommand) (This adds subcommand as a subcommand of parentCommand).

Note: Setting a command as a subcommand mutates said subcommand. Therefore, the same subcommand instance cannot be added as a subcommand to multiple different commands. Use command.copy() to create a copy of the command in order to set multiple subcommands.

You can get any command's parent command using command.parent or the root command using .root() (In git remote add origin, add is the deepest subcommand, its parent is remote and the root command is git. Note that the root command is always the same no matter what command we start at (git.root() === remote.root() === add.root() === git)).

Every subcommand needs a handler: The handler is the code that runs when the subcommand is invoked. You can add the handler using .handler(async function handler(args) {}):

mysubcommand.handler(async function (args) {
  console.log("You ran `mysubcommand`!");
});

Inside the handler function, this is the command the handler was applied to (remember: this doesn't work in arrow functions!) and args are all the options passed to the subcommand. Note that tauris only invokes the handler of the deepest subcommand, i.e. if the command rootcommand has a subcommand foo that has a sub-subcommand bar and the user runs rootcommand foo bar, only the handler for bar will be invoked.

Note that handlers may be asynchronous, but they don't have to.

Exiting from subcommands

When writing CLIs, it's often useful to be able to exit prematurely from a program or control the exit code it returns. For this, the process.exit() function is commonly used. However, this approach has its issues: We can only call .parse() once, then the handler may force the program to exit, but there's no way to know for sure.

Instead, when you need to exit, simply return the desired exit code from your handler. Usually, this will immediately cause your program to exit, but it can also be surpressed by passing noExit: true to .parse (see parsing arguments).

The Help Menu

  • .demandArgument() – Show the help menu if the command is called without arguments
  • .noHelp() – Disable the help menu entirely

Internationalisation

The help menu (see screenshot at top) contains some template text like "Usage:" and "Options:", which is in english by default. If your tool is intended for users more familiar with another language, you can use the .language() method:

// Apply german translation
mycommand.language({
  "Usage:": "Nutzung:",
  "Commands:": "Befehle:",
  "Root Options:": "Root-Optionen:",
  "Options:": "Optionen:",
  "Display this help message": "Diese Hilfsinformationen anzeigen",
});

For a different language, simply replace the strings on the right with the correct translation for the desired language. The language is passed down to all subcommands.

Parsing arguments

Once you've used the above methods to describe your command, run .parse() to parse command line arguments:

const command = new Command("command")
	.option('v', {alias: 'version', type: 'boolean', description: ''});
	.option('o', {alias: 'output', type: 'text', description: ''});

command.parse([]);
command.parse(['-v']); 											// { v: true }
command.parse(['--version']); 							// { v: true }
command.parse(['-o']); 											// { o: undefined }
command.parse(['-o', 'output.txt']); 				// { o: 'output.txt' }
command.parse(['--output', 'output.txt']); 	// { o: 'output.txt' }

// Parse arguments from `argv`
command.parse(process.argv.slice(2));

To parse the arguments given to the script when it was run, use .parse(process.argv.slice(2)) rather than .parse(process.argv). This is because process argv always begins with the path to the nodejs binary running the script, then the path to the script, and only after that the actual arguments.

If, while parsing the arguments, tauris detects that a subcommand is being invoked, it will automatically invoke the subcommand's handler and return a promise that resolves to the subcommand's exit code once the handler is done. If tauris detects invalid input, it will return false.

The .parse method additionally takes an options argument:

command.parse([], {
	noExit: true,
	noPromise: true
})

Set noExit to make the exit method a no-op (see exiting from subcommands) and instead return the exit code (if a subcommand is invoked).

Set noPromise to return false and let the handler run in the background rather than returning a promise (if a subcommand is invoked)

🛸 Contributing

You can contribute to tauris in many ways like creating new features, fixing buges and improving documentation or examples. Find more information in CONTRIBUTING.md

⚖️ License