How to create a basic npx command-line library
Tags: javascript, npm, webdev, node
Published: 2020-03-22 11:29:54

## Table Of Contents
* [npx](#chapter-npx)
* [Setup](#chapter-setup)
* [Reading arguments](#chapter-args)
* [Colors](#chapter-colors)
* [What's next](#chapter-next)

## npx <a name="chapter-npx" />
[npx](https://www.npmjs.com/package/npx) is a tool shipped with npm@5.2.0 and newer that allows you to execute any command from the npm registry (ex: npx [create-react-app](https://www.npmjs.com/package/create-react-app)) without need to install it locally.

## Setup <a name="chapter-setup" />
An npx executable library is similar to a normal npm library. Create a new project with [npm](https://docs.npmjs.com/cli/init):

```bash
npm init
```

Now, let's create our executable file under **bin** folder and call it **cliTest.js**. All executable files must have a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) (#! /usr/bin/env node) header:

```javascript
#! /usr/bin/env node
console.log("unicorns♥")
```

The next step is to expose our **cliTest.js** as a command. Open [package.json](https://docs.npmjs.com/files/package.json) and add a [bin](https://docs.npmjs.com/files/package.json#bin) property. It's a key-value object where the key is the command and value is the path to the executable .js file. At this point the package.json should look like this:

```json
{
    "name": "cli-npm",
    "version": "1.0.0",
    "bin": {
	    "test-cli-tool": "bin/cliTest.js"
    }
}
```

That's all for a basic setup. Run: npm i -g to install this package locally. Open terminal and run:

```bash
npx test-cli-tool
```

It will output: unicorns♥

This package can also be [published](https://docs.npmjs.com/cli/publish) to npm, but this is a story for another time.

## Reading arguments<a name="chapter-args" />

All command-line arguments are accessible via argv (argument values) property of the process. To print the input add:
```javascript
console.log(process.argv);
```

The first argument is the path to the executor, the second is the path to our executable .js file. So when parsing input you should start from the third argument (the first passed after the command). Here is a simple example:

```javascript
#! /usr/bin/env node
console.log("unicorns♥");

// slice argv as we don't need the forst two elements (in this case)
const args = process.argv.slice(2, process.argv.length);
console.log(args);

const action = args[0];// first argument
const a = args[1];     // second argument
const b = args[2];     // third argument

if(action === "sum"){
    // ex: npx test-cli-tool sum 5 2
    // output: "Sum is: 7"
    console.log("Sum is: " + (Number(a) + Number(b)));
} else if(action === "dif") {
    // ex: npx test-cli-tool dif 5 2
    // output: "Difference is: 3"
    console.log("Difference is: " + (Number(a) - Number(b)));
} else {
    console.error("Unexpected input");
}

process.exit(0);// 0 means there were no errors
```
This is a very primitive way of managing input. For something more sophisticated please check [yargs](https://www.npmjs.com/package/yargs) library.

## Colors<a name="chapter-colors" />
If you want to add some swag to your cli tool you should definitely make it colorful. Check [here](https://gist.github.com/abritinthebay/d80eb99b2726c83feb0d97eab95206c4) different escape codes to change colors. Ex:

```javascript
const RESET = "\x1b[0m";
const GREEN = "\x1b[32m";
const YELLOW = "\x1b[33m";
const WHITE = "\x1b[37m";

const getColoredText = (text, color) => {
    if(color == null){
        color = WHITE;
    }

    // remember to add reset at the end.
    return color + text + RESET;
}

console.log(getColoredText("Hello!", GREEN));
console.log(getColoredText("Hi!", YELLOW));
```

For some advanced colouring you can use [chalk](https://www.npmjs.com/package/chalk) library.

## To be continued...<a name="chapter-next" />
In the next post, we will see how to execute other commands and add some spinners.