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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@maartennnn/cli-builder

v2.3.0

Published

A cli builder tool

Readme

CLI-Builder

API Docs

Trying out an example

This example can be found in bin/example-cli.js

git clone https://github.com/maarteNNNN/cli-builder.git
npm install
npm link
cli-builder help
npm unlink # to delete the cli-builder bin

Installing

npm install cli-builder

Be sure to take a look at bin/example-cli.js

Instantiate a new CLI with new REPLClient({ ...options }) REPL stands for Read Eval Print Loop

defining an commands Object as shown below in below

cli.run(commands);

Commands example

// DO NOT ADD HELP TO THE ROOT OBJECT. THIS IS DYNAMICALLY MOUNTED
const commands = {
  test: {
    execute: () => console.log('this is the test run'),
    help: 'help of test',
    testing: {
      execute: ({ argument, options }) =>
        console.log('ARGUMENT: ', argument, '\nOPTIONS: ', options),
      help: 'testing help',
      input: '<arg-to-pass-to-execute-function>', // argument and options are passed as an object passed to execute function
      // cmd test testing IAMPASSEDTOFUNCTION -f
      options: [{ option: 'f', help: 'Follow the logs' }],
    },
    testing2: {
      execute: () => console.log('executing testing2'),
      help: 'testing2 help',
    },
  },
  test2: {
    execute: () => console.log('this is the test2 run'),
    help: 'help of test2',
  },
  deep: {
    nesting: {
      works: {
        as: {
          // Without help
          command: () =>
            console.log('to run this type `deep nesting works as command`'),
          // Or with help
          // command: {
          //   // this get executed as `deep nesting works as command`
          //   execute: () => console.log('to run this type `deep nesting works as command`'),
          //   // this get executed as `deep nesting works as command help`
          //   help: 'help of command'
          // }
        },
      },
    },
  },
  runSomeFunction: async () => {
    // DO SOME INSANE LOGIC HERE
  },
  // A more comprehensive example below titled: Defining help with only one execute function
  exampleWithOneExecute: {
    knownCommand: {
      help: 'Help for this known command',
    },
    // Show the user there are other commands available
    'any-yet-unknown-property': {
      help: 'Help for ANY UNKOWN PROPERTY',
    },
    async execute({ argument, options }) {
      console.log(this); // Mounts the REPLClient dynamically
      console.log(param); // Passes the last given argument/param dynamically
      console.log(options); // Passes the last given options/flags dynamically
    },
  },
};

WARNING

Help is dynamically mounted to the commands object. It generates a function which will mount all child help properties.



NOTE

Running is going through the object and should be written as arguments the following way: deep nesting works as command for the example above (It executes the function or the execute child function in case help wants to be added). deep nesting works as command --help (executes --help or -h child function in case it's available)



WARNING

functions are added as camelCase but are transformed to kebab-case: run-some-function will call result in runSomeFunction.



ADVANCED EXAMPLE

actions can be used to integrate imported files. You can check out the example of a full-fledged cli implementation in ldpos-commander or SocketCluster.

The CLI (REPLCient) object is passed to the actions functions by Function.prototype.bind

The bindActionArgs are passed via Function.prototype.bind as well. Except if an argument is passed in the commands object function Eg.


someFunctionCmd: {
  // CLI as this will be available but bindActionArgs won't be as argument replaces them
  execute: (argument) => cli.actions.someFunction(argument),
}

A more apprehensive example

const actions = {
  getUserData = async (id, someFunction, aString, aNumber) => {
    try {
      const data = await axios.get(`user/${id}`)

      console.log(this.argv) // logs all passed arguments with - and --

      // this references to the cli object as it's bound
      this.successLog(data)

      someFunction()

      console.log(aString, aNumber)
    } catch (e) {
      throw new Error(e)
    }
  }
}

// Binding below array to `options.bindActionArgs` in `new REPLClient({ ...options })`
const options = {
  bindActionArgs = [123, () => console.log('function executed'), 'a string', 23123]
}

const cli = new REPLClient(options)

const commands = {
  // No arguments are passed here, they are mounted dynamically
  anActionTest: async () => await cli.actions.getUserData()
}

cli.run(commands)

using cli-builder an-action-test will execute the getUserData function with the bindActionArgs parameters bound to it.

Defining help with only one execute function

When you want to dynamically output to the console Eg. get a JSON Object from an API with undefined structure but you want to be able to log any of those properties to the console it can be done via:

const commands = {
  entrypoint: {
    any: {
      help: 'Help for any',
    },
    extra: {
      help: 'Help for extra',
    },
    helping: {
      help: 'Help for helping',
    },
    commands: {
      help: 'Help for commands',
    },
    'any-unknown-property': {
      help: 'Help for ANY UNKOWN PROPERTY',
    },
    async execute(param) {
      param = cli.kebabCaseToCamel(param);

      // We don't want the paging info in this case
      const {
        data: { data },
      } = axios.get('https://reqres.in/api/users?page=2');

      // If null it could be accessible, if undefined we know for sure it isn't
      if (!data[param] === undefined)
        throw new Error('Custom property not found.');

      // The `REPLCient` is object is dynamically mounted
      this.successLog(data[param], `${param}:`);
    },
  },
};