Let’s make this CLI program from the scratch
4. CLI Program to create a HTML , JS template
- There are libraries to make CLI tool in npm communities (i.e, yargs, commander, meow)
- In this example, we are going to use libraries called commander chalk & inquirer to build a CLI program
commander
- The complete solution for node.js command-line interfaces
chalk
- Terminal string styling
- chalk libraries give a color to CLI command instead of plain black & white
inquirer
- A collection of common interactive command line user interfaces
> First, install npm packages
// console
$ npm i commander inquirer chalk
>> Check the output
+ chalk@3.0.0
+ inquirer@7.1.0
+ commander@5.0.0
added 37 packages from 31 contributors and audited 46 packages in 4.058s
found 0 vulnerabilities
- and node_modules folder installed in your current directory because you install npm libraries
> Second, Create command.js (executable file)
>> Command.js
#! /usr/bin/env node
const program = require("commander");
program
.version("0.0.1", "-v, --version")
.usage("[options]");
program
.command("template <type>")
.usage("--name <name> --path [path]")
.description("make a template")
.alias("tmpl")
.option("-n --name <name>", "enter filename", "index")
.option("-n --directory <path>", "make the creation path")
.action((type, options) => {
console.log(type, options.name, options.directory);
});
program
.command("*", { noHelp: true })
.action(() => {
console.log("Cannot find the following command")
program.help();
});
program
.parse(process.argv);
- You get program object from commander package
There are many methods in program object
- version : sets up program version. Usage using --version or -v
- usage : tells how to use the command line. Usage using -h or --help
- option : specifies the additional options. For example, we can get file name — name and directory -- directory options
- command : sets up command line. program.command('template <type>') or program.command('*') . Currently, you can run the command using either cli template html (<type> is html) or all other command * ( using wildcard )
- action : defines executable function and method. can get the parameters from the command line (i.e, <type>)
- parse : method that appends to the end of the program object. It helps parsing command and option from process.argv parameters
>> Package.js
Let’s configure in package.js to run the command.js
// package.json
{
...
"bin":
{ "cli": "./command.js"
},
...
}
>> Check the output
$ npm i -g
/usr/local/bin/cli -> /usr/local/lib/node_modules/node-cli/command.js
+ node-cli@0.0.1
updated 1 package in 0.246s
>> Console using options -v & -h
$ cli -v
0.0.1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
$cli -h
Options:
-v, --versioon output the version number
-h, --help display help for command
Commands:
template|tmpl [options] make a template
help [command] display help for command
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
$cli template
error: missing required argument "type"
- <type> is a required field; therefore, cli template results ERROR for missing the required <type> parameter
>> Command.js
- Add HTML & JS template in command.js
- User prompt using inquirer
- coloring the console output , error using chalk
#!/usr/bin/env node
const program = require("commander");
const fs = require("fs");
const path = require("path");
const inquirer = require("inquirer");
const chalk = require("chalk");
const htmlTemplate = `<!DOCTYPE html>
<html>
<head>
<meta chart="utf-8" />
<title>Template</title>
</head>
<body>
<h1>Hello</h1>
<p>CLI</p>
</body>
</html>`;
const routerTemplate = `const express = require("express");
const router = express.Router();
router.get("/", (req, res, next) => {
try {
res.send("ok");
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;`;
const exist = (dir) => {
try {
fs.accessSync(dir, fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK);
return true;
} catch (e) {
return false;
}
};
const mkdirp = (dir) => {
const dirname = path
.relative(".", path.normalize(dir))
.split(path.sep)
.filter(p => !!p);
dirname.forEach((d, idx) => {
const pathBuilder = dirname.slice(0, idx + 1).join(path.sep);
if (!exist(pathBuilder)) {
fs.mkdirSync(pathBuilder);
}
});
};
const makeTemplate = (type, name, directory) => {
mkdirp(directory);
if (type === "html") {
const pathToFile = path.join(directory, `${name}.html`);
if (exist(pathToFile)) {
console.error(chalk.bold.red("File Exists"));
} else {
fs.writeFileSync(pathToFile, htmlTemplate);
console.log(chalk.green(pathToFile, "Creation Successfully"));
}
} else if (type === "express-router") {
const pathToFile = path.join(directory, `${name}.js`);
if (exist(pathToFile)) {
console.error(chalk.bold.red("File Exists"));
} else {
fs.writeFileSync(pathToFile, routerTemplate);
console.log(chalk.green(pathToFile, "Creation Successfully"));
}
} else {
console.error(chalk.bold.red("Choose either 1) html or 2) express-router"));
}
};
let triggered = false;
program
.version("0.0.1", "-v, --version")
.usage("[options]");
program
.command("template <type>")
.usage("--name <name> --path [path]")
.description("Create Template")
.alias("tmpl")
.option("-n, --name <name>", "Enter file Name", "index")
.option("-d, --directory [path]", "Enter file Path", ".")
.action((type, options) => {
makeTemplate(type, options.name, options.directory);
triggered = true;
});
program
.command("*", { noHelp: true })
.action(() => {
console.log("Cannot find the command");
program.help();
triggered = true;
});
program
.parse(process.argv);
if (!triggered) {
inquirer.prompt([{
type: "list",
name: "type",
message: "Choose the template Types",
choices: ["html", "express-router"],
}, {
type: "input",
name: "name",
message: "Type File Name",
default: "index",
}, {
type: "input",
name: "directory",
message: "Type File Directory",
default: ".",
}, {
type: "confirm",
name: "confirm",
message: "Creation? ",
}])
.then((answers) => {
if (answers.confirm) {
makeTemplate(answers.type, answers.name, answers.directory);
console.log(chalk.rgb(128, 128, 128)("Terminal Closed"));
}
});
}
>> Package.json
check package.js to see if dependencies (chalk, commander, inquirer) are installed correctly
{
"name": "node-cli",
"version": "0.0.1",
"description": "nodejs cli program",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "GPLEE",
"license": "ISC",
"bin": {
"cli": "./command.js"
},
"dependencies": {
"chalk": "^2.4.1",
"commander": "^2.15.1",
"inquirer": "^5.2.0"
}
}
>> RUN
Simply cli on the terminal
$ cli