This content originally appeared on DEV Community and was authored by Lokesh_Choudhary
What is a Command Line Interface (CLI) Application?
CLI tools allow you to run certain tasks or operations right from your terminal or command line prompt. As a developer , chances are you spend most of your time in your terminal, typing in commands to help you get around some tasks. A good example of commonly used applications include npm , Create React App , Vue CLI etc.
In this tutorial you will create a CLI todo list application by using Node JS.
Setting up the project
First , create a directory that will hold the CLI application:
mkdir todo-list-cli
cd todo-list-cli
Next, we will initialize our Node.js project
npm init -y
This will create a package.json file with defaults. Once that is done you need to install some packages that will help create our CLI application. These are:
commander:This package makes creating the CLI application easier. It provides functions that will allow you to set the commands, options and more
chalk:This package lets us print colored messages to the console. It will help us make our CLI application look nice and pretty
conf:This package allows us to save persistent information on the user’s machine. We will be using it to save the user’s todo list
To install these packages, run:
npm i commander chalk conf
Once installation is done, you are ready to start the development of the CLI tool.
Creating a CLI Application
Firstly start by creating index.js
in the root of the project. This will be the main entry of the application.
Next, to create the basic configurations, and functionalities, we can use commander
. First, let's require program
from commander
.
const {program} = require('commander')
To declare a command, commander provides the following functions:
-
command
: takes a string that defines the command. -
description
: describes the command for the user. This is helpful when the user uses the --help option. -
option
: the options that this command can take, if any. -
action
: particular action to execute, when command is executed.
If you are wondering what about the commands for the CLI?
You need the following commands:
- todo list: this will list the tasks in the user’s to-do list
- todo add: this will add a new task to the user’s to-do list
- todo mark-done: this will mark specific tasks or all tasks as done in the list
Creating the List Command
The list command will just show the list of tasks that the user has added before. It will not take any options. You should be able to run it by running the following command in your terminal:
todo list
Now in index.js, add the following below the code we added earlier:
program
.command('list)
.description('List all the TODO tasks')
.action(list)
In this the command
function is used to declare the command in CLI application. The argument you pass is a string.The description
function is used to describe this command to the user when they run the application with the --help
option. Finally, the action
is assigned to a function called list
, which you will create shortly.
Now, create a new directory called commands
. And a file list.js
in it, which will hold the function that will run when the user runs todo list
in the terminal.
For storing and reading the tasks, you will use the conf
package. It has the following functions:
-
set
: this sets the information under a specific key -
get
: this gets the information that is set under a specific key
Lets start by requiring conf in commands/list.js
:
const conf = new (require('conf'))()
Next, you need to implement and export the function for use in index.js
:
function list(){
}
module.exports = list
Now, specify the key todo-list
inside the list function under which the data will be set
and get
using the conf package. todo-list
will be an array of objects.
const todoList = conf.get('todo-list')
Next, if todo data is already in the todo-list
, you need to loop over them and display them in the terminal, done tasks will have green color and yellow for the tasks that are not done.
If todo-list
is empty, which means user does not have any tasks, you need to show a message in red indicating that they don't have any tasks.
const todoList = conf.get('todo-list')
if (todoList && todoList.length) {
//user has tasks in todoList
} else {
//user does not have tasks in todoList
}
To show color in our terminal, as mentioned before you will use chalk
. Let's require it in the commands/list.js
.
const conf = new (require('conf'))()
const chalk = require('chalk')
//rest of our code
Next, you will use chalk
in the else part first. You need to show the user that they don't have any tasks in the todo list. To display message in red using chalk
:
else {
//user does not have tasks in todoList
console.log(
chalk.red.bold('You don\'t have any tasks yet.')
)
}
Now, you need to display a message in green if the user does have tasks. First, you need to show a message that details the color meaning of the tasks.
if (todoList && todoList.length) {
console.log(
chalk.blue.bold('Tasks in green are done. Tasks in yellow are still not done.')
)
}
Now, the second step is to loop over the tasks in the todoList
and for each task, check if it's done then display green, if not then yellow.
todoList.forEach((task, index) => {
if (task.done) {
console.log(
chalk.greenBright(`${index}. ${task.text}`)
)
} else {
console.log(
chalk.yellowBright(`${index}. ${task.text}`)
)
}
})
Now the list
function is done and you can use it in index.js
.
The full code till now is:
const conf = new (require('conf'))()
const chalk = require('chalk')
function list () {
const todoList = conf.get('todo-list')
if (todoList && todoList.length) {
console.log(
chalk.blue.bold('Tasks in green are done. Tasks in yellow are still not done.')
)
todoList.forEach((task, index) => {
if (task.done) {
console.log(
chalk.greenBright(`${index}. ${task.text}`)
)
} else {
console.log(
chalk.yellowBright(`${index}. ${task.text}`)
)
}
})
} else {
console.log(
chalk.red.bold('You don\'t have any tasks yet.')
)
}
}
module.exports = list
Now, in the index.js
require the list
function.
const list = require('./commands/list')
Then, at the end of file add the following:
program.parse()
This is important for commander
as the input of the user need to be parsed to figure out which command the user is running and execute it.
Testing the Application
The first step is to add the following in the package.json
file.
"bin":{
"todo":"index.js"
}
todo
will be used in the terminal when running commands from our todo CLI. You can change it to whatever you want. It is pointing at index.js, as this is your main point of entry.
Now, you have to globally install the package on your machine.
npm i -g
Once it is done you can run the application right from your terminal.
todo --help
You will see the following in your terminal:
Usage: todo [options] [command]
Options:
-h, --help display help for command
Commands:
list List all the TODO tasks
help [command] display help for command
If you run the list command:
todo list
It will just show the message that you don't have any task yet.
Let's implement a new command that is add
command.
Add Command
The add
command will take one argument, which will be the text/title of the task.The command will look.
todo add "Make CLI App"
Now, you need to declare add
command in index.js
under the list
command, not after the program.parse()
, add the the following:
program
.command('add <task>')
.description('Add a new TODO task')
.action(add)
The command function has add where is the argument the user need to pass. In commander a required argument is , whereas if it’s optional, you use [ARG_NAME]. Also, the name given to the argument is same as name of the parameter passed to the function in action.
Now, just like the list
command you need to implement the add function. Let’s create the file commands/add.js
with the following :
const conf = new (require('conf'))()
const chalk = require('chalk')
function add (task) {
}
module.exports = add
In the add
function, a task
parameter is passed, which will be passed by the user.
The add
function will store the task in the todo-list
array using conf
. And a success message in green will be displayed using chalk
.
First, you will use the get
function to get the todo-list
and then push a new task to the todo-list
array.
The entire code for the add
function is:
function add (task) {
//get the current todo-list
let todosList = conf.get('todo-list')
if (!todosList) {
//default value for todos-list
todosList = []
}
//push the new task to the todos-list
todosList.push({
text: task,
done: false
})
//set todos-list in conf
conf.set('todo-list', todosList)
//display message to user
console.log(
chalk.green.bold('Task has been added successfully!')
)
}
Now, go back to index.js
and require the add
function:
const add = require('./commands/add')
Let's test this command in the terminal:
todos add "Make CLI App"
You will get a message "Task has been added successfully!" in green. To check that added task, run in your terminal:
todo list
Try adding some more tasks to see the list grow.
Now will add the mark-done
command which will mark a task as done.
mark-done command
The mark-done
command, takes a --tasks
option followed by at least one index of the tasks user want to mark as done it mark those as done, but by default will mark all tasks as done if not index is specified.
Example command:
todo mark-done --tasks 1 2
For the simplicity of the tutorial, the indices of tasks to mark them done are used.But in a real-life use case application, you would probably use unique IDs for the tasks.
Now, declare mark-done
command under the add
command:
program
.command('mark-done')
.description('Mark commands done')
.option('-t, --tasks <tasks...>', 'The tasks to mark done. If not specified, all tasks will be marked done.')
.action(markDone)
In this command the option function. The first parameter is the format of the option -t, --tasks
means that the user can use either -t
or --tasks
to pass this option. means that more than one task can be provided, but as the <> is used which means it is required. The second parameter is the description of the option. This is useful when the user types todo mark-done --help
command.
Now, just like previous commands you need to implement the markDone
function. Let’s create the file commands/markDone.js
with the following :
const conf = new (require('conf'))()
const chalk = require('chalk')
function markDone({tasks}) {
}
module.exports = markDone
You can see that the markDone function takes an object that includes a tasks
property. If the -t
or --tasks
option is passed to the command, tasks
will be an array of the values passed by the user. If not, it will be undefined.
What we need to do inside the markDone
function is to get
the todo-list
array from conf
. If todo-list
is not empty, you need to loop over it. And mark only the tasks of the indices the user enters as done. If tasks
indices is undefined, then mark all tasks as done.
The complete code for markDone
is :
function markDone({tasks}) {
let todosList = conf.get('todo-list')
if (todosList) {
//loop over the todo list tasks
todosList = todosList.map((task, index) => {
//check if the user specified the tasks to mark done
if (tasks) {
//check if this task is one of the tasks the user specified
if (tasks.indexOf(index.toString()) !== -1) {
//mark only specified tasks by user as done
task.done = true
}
} else {
//if the user didn't specify tasks, mark all as done
task.done = true
}
return task
});
//set the new todo-list
conf.set('todo-list', todosList)
}
//show the user a message
console.log(
chalk.green.bold('Tasks have been marked as done successfully')
)
}
First check if the todoList
is empty or not, if not loop over todosList
inside map
function. And then check if tasks
is defined, which means if the user has passed any specific tasks to mark as done.
If tasks
is defined, then you need to check if the current task item is in the tasks by checking if the index is in the tasks array. Note that index.toString()
is used because the tasks array will hold the indices as strings.
If tasks
is not defined, then, as mentioned before, mark all items as done. After loop completion you get the the updated list, you need to set todo-list
using conf.set
to the new array. In the end, show the user a success message.
Finally, go back to index.js
and require markDone
function:
const markDone = require('./commands/markDone')
Now, test it out. By running:
todo mark-done
If everything is correct, you can run todo list
and see that all items are in green now.
Next, try to add a few more tasks then mark those done using their indices, an example command to mark a single task as done:
todo mark-done -t 1
To mark multiple tasks:
todo mark-done -t 1 3 5
You can now play with the commands then check which are marked done and which aren’t using the todos list
command.
Our CLI Application is done! todo-list-cli now allows the user to add tasks, view them, and mark them done.
Conclusion
Congratulations, you learned how to create a CLI Application using Node.JS. The number of possible projects are are endless, so go create something more awesome!
This content originally appeared on DEV Community and was authored by Lokesh_Choudhary
Lokesh_Choudhary | Sciencx (2021-10-14T06:08:47+00:00) How to Build a Command Line Interface (CLI) Application with Node.JS👨‍🎓🤓.. Retrieved from https://www.scien.cx/2021/10/14/how-to-build-a-command-line-interface-cli-application-with-node-js%f0%9f%91%a8%e2%80%8d%f0%9f%8e%93%f0%9f%a4%93/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.