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

cli-max

v6.0.0

Published

An opinionated solution for building CLI programs.

Downloads

24

Readme

cli-max

An opinionated solution for building CLI applications using Node.js.


Contents


Understanding CLI Application Categories

CLI Applications can be categorized into two types

  • Single Command Apps
  • Multi Command Apps

Single Command Apps

Single Command Apps usually have just one main action.

Examples: mkdir, touch, ls, etc.,

Multi Command Apps

Multi Command Apps are usually a collection of actions.

They have sub-commands that perform different operations.

Examples: git, npm, etc.,


Understanding CLI Command invocation

Structure

$ command sub-command <...[--options]> <...parameters>

Examples

$ mkdir "New Folder"
  • mkdir is the command
  • the value New Folder is called a parameter or an argument.
$ git pull --quiet origin master
  • git is the command
  • pull is the sub-command
  • --quiet is an option
  • origin and master are the parameters

Introduction to cli-max

cli-max is a library that tries to make the experience of building a CLI app easy and pleasant.

The API of cli-max consciously tries to make your code more declarative and thus be easier to build, understand and maintain.

Features

  • Single and Multi Command CLI Apps, both can be implemented using cli-max
  • A Command can be configured as a default. and this will be executed when no valid command name is passed at runtime
  • Sub-Commands can have aliases, making it easy for end-users to pass alternative command names
  • Options can have aliases too (supports both short flags and long alternatives)
  • Options can be configured with default values
  • "help" details for every command is auto-generated using the details provided in the configuration

Getting Started

The approach to building CLI apps using cli-max, can broadly be described as a two-step process:

  1. Configure
  2. Execute

Step 1 - Configure

You can configure and implement the functionality of your CLI app using the API createCLI().

function createCLI(command: Command, config: CLIConfig): ExecuteFn

The createCLI() API takes two parameters of types Command and CLIConfig respectively.

You can build a Single Command CLI App by implementing all its functionality in the action property of the command argument passed to createCLI().

For building Multi Command CLI App, you can configure sub-commands and implement their functionality in corresponding action property of each sub-command.

If invoked with proper configuration as mentioned above createCLI() API returns a function.

This function is what is used in the next step.

Step 2 - Execute

The function returned by the createCLI() API is what invokes the actual functionality.

One can call the function returned by createCLI() as cli or execute or run or parse or compute or anything similar.

This function encapsulates the idea of processing and evaluating the actual arguments and flags passed at runtime and hence any of the above names.

The type for the function returned by createCLI() is ExecuteFn

Note: To explain easily, this document will from now on refer this function as executeFn. But, remember it can be named anything per your convenience.

const executeFn = createCLI(someCommand, someConfig); // step-1

const result = executeFn(process.argv); // step-2

The executeFn expects the arguments received by the Node.js process at runtime.

One can access these arguments passed to a Node.js process from the global property process.argv. (read more about process.argv)

Invoking executeFn with runtime arguments properly will parse the arguments and execute the corresponding command configured in the 1st step.

executeFn also returns the output value of the command executed from the configured commands.

Some insight on process.argv

process.argv is an array of the command line arguments received by the Node.js process

Launching a Node.js process as

$ node process-args.js one two=three four

would generate the process.argv with the following values

[
    "/path/to/the/node/executable",
    "/path/to/the/file/process-args.js",
    "one",
    "two=three",
    "four"
]

cli-max in Action

const execute = createCLI({
    name: 'give',
    description: 'Greetings made easy!',
    subCommands: [
        {
            name: 'greetings',
            action: ({ flags: { to } }) => {
                console.log(`Hello ${to}! How are you?`);
            },
            options:[
                {
                    name: 'to',
                    aliases: ['t'],
                    description: 'this option specifies whom to greet',
                    required: false,
                    defaultValue: 'there',
                },
            ],
            isDefault: true,
        },
        {
            name: 'compliment',
            action: ({ flags: { to } }) => {
                console.log(`Hey ${to}, You look good! :)`);
            },
            options:[
                {
                    name: 'to',
                    aliases: ['t'],
                    description: 'this option specifies whom to complient',
                    required: false,
                    defaultValue: 'there',
                },
            ],
        }
    ],
});

execute(process.argv);

/*
Output:

$ give greetings
Hello there! How are you?

$ give greetings --to John
Hello John! How are you?

$ give compliment
Hey there, You look good! :)

$ give greetings --to John
Hey John, You look good! :)
*/

API in detail

API:

Types:

Interfaces:


createCLI()

This API is used to configure the command, sub-commands, options and actions

function createCLI(command: Command, config: CLIConfig): ExecuteFn

params

Expects two arguments

return value:

returns a function of type ExecuteFn


ExecuteFn

This is the type for the function returned by createCLI() API

type ExecuteFn = function (processArgs: string[]): any

params

Expects one argument

  • processArgs - an array of strings

processArgs is supposed to be process.argv i.e, the list of arguments received by the process

return value

returns the output of the command executed from the list of sub-commands configured


Action

This is the type for the callback function that is configured in a Command or a SubCommand to implement its functionality.

An action callback configured in a Command or a SubCommand gets invoked automatically when executeFn receives the command-name in the processArgs.

type Action = function (params: ActionParams): any;

params

Receives one argument


GetHelpFn

This is the type for the function that generates "help" details for a command or a sub-command.

This function getHelp can be accessed as a property in the ActionParams received by the action.

If you want to display "help" for a command, you can just invoke this function (available as a property in the object received by the action configured for the command) and it would return the "help" details generated specifically for the command in context.

type GetHelpFn = function (): string;

Command

This type encapsulates the details needed to configure a command

{
    name: string;
    description: string;
    usage: string;
    action?: Action;
    options?: Option[];
    subCommands?: SubCommand[];
}

Note: To auto-generate proper "help" details for a command, it is assumed that at the least the name, description and usage properties are assigned non-empty values.

To create a Single Command CLI App one can just implement the action property in the Command object being passed to createCLI() API.

To create a Multi Command CLI App one has to configure subCommands property in the command object that is passed to createCLI() API. For these Apps the main action property is optional but it can be used to handle cases where end-user invokes just the main command.


SubCommand

This type encapsulates the details needed to configure a sub-command

{
    name: string;
    description: string;
    usage: string;
    action: Action;
    aliases?: string[];
    options?: Option[];
    isDefault?: boolean;
}

Note: To auto-generate proper "help" details for a sub-command, it is assumed that at the least the name, description and usage properties are assigned non-empty values.


Option

This type encapsulates the details needed to configure an option for either a command or a sub-command

{
    name: string;
    aliases: string[];
    description: string;
    defaultValue: any;
    required: boolean;
}

Note: To auto-generate proper "help" details for options in a command or a sub-command, it is assumed that at the least the name and description for individual options are assigned non-empty values.


ActionParams

This type represents the object passed to an action of a command or a sub-command

{
    parameters: string[];
    flags: RuntimeFlags;
    getHelp: GetHelpFn;
}

RuntimeFlags

This type represents the collection of flags received at runtime.

each flag and its value received at runtime is assigned as a property and the corresponding value in this object

{
    [key: string]: any;
}

CLIConfig

This type encapsulates the customization options that can be passed to the createCLI() API

{
    generateHelp?: boolean;
    prettyHelp?: boolean;
    paddingInDetails?: number;
}