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

climp

v1.0.4

Published

A tool for building Node CLIs

Downloads

38

Readme

🐒 climp

npm version ci

climp is a simple tool to help build Node CLIs.

Installation

yarn add climp

Usage

climp's default export is a function called climp, which takes in a config object that describes what you want your CLI to do and look like.

It returns another function that you can then pass arguments to. Your generated CLI function will handle parsing and validating options, and will call the function mapped to each command in your config object.

// my-script.js

const {default: climp} = require('climp');

// Import functions from your own code
const {doSomething, doAnotherThing} = require('./my-code');

const cli = climp({
  commands: {
    'do-something': {
      func: doSomething,
      args: {
        'arg-name': {
          type: 'string',
        },
      },
    },
    'do-another-thing': {
      func: doAnotherThing,
    },
  },
});

// ['node', 'my-script.js', 'do-something', '--arg-name', 'arg-value']
const args = process.argv.slice(2);

cli(args); // doSomething({'arg-name': 'arg-value'})

Note that it's up to you to trim off any unwanted arguments (i.e. node, my-script.js) before passing it to climp's CLI. You might get an error otherwise.

Check out the tests (tests/climp.test.ts) for some more examples on usage.

Config

climp is fully typed, and thus it may be helpful to explore its type declarations

Below is a more detailed explanation/example of climp's config object:

interface Config {
  commands: Commands;
  global?: {
    args?: Args;
    positionalArgs?: PositionalArgs;
  };
}

commmands

commands is an object you can use to map command names to their Command configs.

interface Command {
  func: CommandFunction;
  args?: Args;
  positionalArgs?: PositionalArgs;
}

func is the function that will ultimately be called with the parsed argument body. You can specify parsing behaviour with your args and positionalArgs configs.

Command.args

Command.args refers to your named args, that is, the args that are prefixed with -- and may optionally be followed by associated values.

Named args may be assigned a type, and also a range of number of values that may be accepted alongside it.

For instance, a BoolArg needs only a type specification, since the inclusion/exclusion of a boolean flag is meaningful on its own (include it to set it to true, exclude it to set it to false).

interface BoolArg extends BasicArg {
  type: 'boolean';
  required?: false;
}

A SingularArg accepts in a single value after the argument name itself. Thus passing in the arg-value pair --arg-name arg-value to your command will set arg-name in your final arg body to have the value arg-value.

interface SingularArg extends BasicArg {
  type: Exclude<Type, 'boolean'>;
}

FiniteArg and InfiniteArg are similar, in that you may specify a finite list of types to assert upon your values, or accept a range from min to max values of a given type.

interface FiniteArg extends BasicArg {
  types: Type[];
}

interface InfiniteArg extends BasicArg {
  types: Type;
  min?: number;
  max?: number;
}

Command.positionalArgs

Command.positionalArgs refers to your positional args, that is, the args that are imbued meaning via their indexed position within the command string.

Positional args may be either required or optional, and may be expressed as a list of PositionalArgs or a InfinitePositionalArgs config object. The latter works similarly to the InfiniteArg option in that it accepts a range of value counts.

type Type = 'boolean' | 'string' | 'number' | 'cast';

interface PositionalArgs {
  required?: PositionalArgsDescriptor;
  optional?: PositionalArgsDescriptor;
}

type PositionalArgsDescriptor = PositionalArg[] | InfinitePositionalArgs;

type PositionalArg = NamedPositionalArg | Type;

// You may choose to label your positional args in the final arg body; otherwise they are given numeric keys
interface NamedPositionalArg {
  name?: string;
  type: Type;
}

interface InfinitePositionalArgs {
  types: Type;
  min?: number;
  max?: number;
}

global

global is where you can define your CLI's top-level arguments (i.e. the arguments that apply to all your commands). args and positionalArgs refer to your global named and positional args respectively.

Some notes on parsing behaviour:

  • If a global and command named arg share the same name, the command named arg will take precedence
  • The parsing will prioritize global positional args before command positional args. Furthermore, required positional args will be considered first

Errors

climp also exports ClimpError as a named export. It throws ClimpErrors when it runs into parsing/validating issues, both on climp calls and on calls to the returned function returned by climp. The intended use case is that the consumer wrap these calls in try-catch blocks so they may define their own error-handling behaviour.

try {
  cli = climp(config);
} catch (e) {
  if (e instanceof ClimpError) {
    // handle climp error (e.g. log, etc.)
  } else {
    // handle other errors
  }
}

try {
  cli(args);
} catch (e) {
  if (e instanceof ClimpError) {
    // handle climp error (e.g. log, etc.)
  } else {
    // handle other errors
  }
}