Build an interactive CLI with Node.js ======  Node.js can be very useful when it comes to building command-line interfaces (CLIs). In this post, I'll teach you how to use [Node.js][1] to build a CLI that asks some questions and creates a file based on the answers. ### Get started Let's start by creating a brand new [npm][2] package. (Npm is the JavaScript package manager.) ``` mkdir my-script cd my-script npm init ``` Npm will ask some questions. After that, we need to install some packages. ``` npm install --save chalk figlet inquirer shelljs ``` Here's what these packages do: * **Chalk:** Terminal string styling done right * **Figlet:** A program for making large letters out of ordinary text * **Inquirer:** A collection of common interactive command-line user interfaces * **ShellJS:** Portable Unix shell commands for Node.js ### Make an index.js file Now we'll create an `index.js` file with the following content: ``` #!/usr/bin/env node const inquirer = require("inquirer"); const chalk = require("chalk"); const figlet = require("figlet"); const shell = require("shelljs"); ``` ### Plan the CLI It's always good to plan what a CLI needs to do before writing any code. This CLI will do just one thing: **create a file**. The CLI will ask two questions—what is the filename and what is the extension?—then create the file, and show a success message with the created file path. ``` // index.js const run = async () => { // show script introduction // ask questions // create the file // show success message }; run(); ``` The first function is the script introduction. Let's use `chalk` and `figlet` to get the job done. ``` const init = () => { console.log( chalk.green( figlet.textSync("Node JS CLI", { font: "Ghost", horizontalLayout: "default", verticalLayout: "default" }) ) ); } const run = async () => { // show script introduction init(); // ask questions // create the file // show success message }; run(); ``` Second, we'll write a function that asks the questions. ``` const askQuestions = () => { const questions = [ { name: "FILENAME", type: "input", message: "What is the name of the file without extension?" }, { type: "list", name: "EXTENSION", message: "What is the file extension?", choices: [".rb", ".js", ".php", ".css"], filter: function(val) { return val.split(".")[1]; } } ]; return inquirer.prompt(questions); }; // ... const run = async () => { // show script introduction init(); // ask questions const answers = await askQuestions(); const { FILENAME, EXTENSION } = answers; // create the file // show success message }; ``` Notice the constants FILENAME and EXTENSIONS that came from `inquirer`. The next step will create the file. ``` const createFile = (filename, extension) => { const filePath = `${process.cwd()}/${filename}.${extension}` shell.touch(filePath); return filePath; }; // ... const run = async () => { // show script introduction init(); // ask questions const answers = await askQuestions(); const { FILENAME, EXTENSION } = answers; // create the file const filePath = createFile(FILENAME, EXTENSION); // show success message }; ``` And last but not least, we'll show the success message along with the file path. ``` const success = (filepath) => { console.log( chalk.white.bgGreen.bold(`Done! File created at ${filepath}`) ); }; // ... const run = async () => { // show script introduction init(); // ask questions const answers = await askQuestions(); const { FILENAME, EXTENSION } = answers; // create the file const filePath = createFile(FILENAME, EXTENSION); // show success message success(filePath); }; ``` Let's test the script by running `node index.js`. Here's what we get: ### The full code Here is the final code: ``` #!/usr/bin/env node const inquirer = require("inquirer"); const chalk = require("chalk"); const figlet = require("figlet"); const shell = require("shelljs"); const init = () => { console.log( chalk.green( figlet.textSync("Node JS CLI", { font: "Ghost", horizontalLayout: "default", verticalLayout: "default" }) ) ); }; const askQuestions = () => { const questions = [ { name: "FILENAME", type: "input", message: "What is the name of the file without extension?" }, { type: "list", name: "EXTENSION", message: "What is the file extension?", choices: [".rb", ".js", ".php", ".css"], filter: function(val) { return val.split(".")[1]; } } ]; return inquirer.prompt(questions); }; const createFile = (filename, extension) => { const filePath = `${process.cwd()}/${filename}.${extension}` shell.touch(filePath); return filePath; }; const success = filepath => { console.log( chalk.white.bgGreen.bold(`Done! File created at ${filepath}`) ); }; const run = async () => { // show script introduction init(); // ask questions const answers = await askQuestions(); const { FILENAME, EXTENSION } = answers; // create the file const filePath = createFile(FILENAME, EXTENSION); // show success message success(filePath); }; run(); ``` ### Use the script anywhere To execute this script anywhere, add a `bin` section in your `package.json` file and run `npm link`. ``` { "name": "creator", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node index.js" }, "author": "", "license": "ISC", "dependencies": { "chalk": "^2.4.1", "figlet": "^1.2.0", "inquirer": "^6.0.0", "shelljs": "^0.8.2" }, "bin": { "creator": "./index.js" } } ``` Running `npm link` makes this script available anywhere. That's what happens when you run this command: ``` /usr/bin/creator -> /usr/lib/node_modules/creator/index.js /usr/lib/node_modules/creator -> /home/hugo/code/creator ``` It links the `index.js` file as an executable. This is only possible because of the first line of the CLI script: `#!/usr/bin/env node`. Now we can run this script by calling: ``` $ creator ``` ### Wrapping up As you can see, Node.js makes it very easy to build nice command-line tools! If you want to go even further, check this other packages: * [meow][3] – a simple command-line helper * [yargs][4] – a command-line opt-string parser * [pkg][5] – package your Node.js project into an executable Tell us about your experience building a CLI in the comments. -------------------------------------------------------------------------------- via: https://opensource.com/article/18/7/node-js-interactive-cli 作者:[Hugo Dias][a] 选题:[lujun9972](https://github.com/lujun9972) 译者:[译者ID](https://github.com/译者ID) 校对:[校对者ID](https://github.com/校对者ID) 本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 [a]:https://opensource.com/users/hugodias [1]:https://nodejs.org/en/ [2]:https://www.npmjs.com/ [3]:https://github.com/sindresorhus/meow [4]:https://github.com/yargs/yargs [5]:https://github.com/zeit/pkg