Build Your Own WC Tool in NodeJS 💻

RoopaRoopa
7 min read

Introduction

In this blog, we will see how to create your own Linux WC tool in NodeJs. This project is a part of the Coding Challenge (here).

What is the WC tool?

The wc (word count) tool is a command-line utility in Unix and Linux systems that displays the number of lines, words, and bytes in a file or input.

The traditional wc tool is written in C language.

Here, 9 lines, 20 words, and 128 characters present in the test.txt .

How to build a WC tool in NodeJS?

Step 1: Set up the environment

Ensure you have Node.js installed on your system. You can download it from Node.js official website.

Step 2: Install npm and Import modules

  1. Initialize a new Node.js project:

     npm init -y
    
  2. Install the necessary modules:

     npm install commander fs
    
  3. Create a new file index.js inside a bin folder and import the required modules:

     const { readFileSync } = require('fs'); // To handle files
     const { program } = require('commander'); // To create a cli command
    

Step 3: Create cawc command and Parse the input

Provide your own cli command name and its description using program.command(), program.description(). This will create a cli command for you.

To define flag options in your cli command, use program.option() to define the different flag options for your command. Here, I defined four flag options for my cawc command.

  1. The -l or --line flag will take the file name as an input and returns the number of lines in the given file.

  2. The -w or --word flag will take the file name as an input and returns the number of words in the given file.

  3. The -m or --chars flag will take the file name as an input and return the number of characters in the given file.

  4. The -c or --bytes flag will take the file name as an input and return the number of bytes in the given file.

The program.parse() is used to parse the args in cli command, and using program.opts() we can separate the options (i.e., flag) from the command statement.

// Command is defined
program
    .command('cawc')
    .description('Return the number of lines, words, character present in the file.');

// Command options are defined
program
    .option('-l, --line <FILENAME>', 'Returns the number of lines in a file')
    .option('-w, --word <FILENAME>', 'Returns the number of words in a file')
    .option('-m, --chars <FILENAME>', 'Returns the number of characters in a file')
    .option('-c, --bytes <FILENAME>', 'Returns the number of bytes in a file');
    // .args('<FILENAME>');

// Input
program.parse(process.argv);
const options = program.opts();

Step 4: Define function for -l or --line flag

When the -l or --line flag is used, then the command should return the number of lines present in the given file. The below function is used to return the number of lines present in the file.

Here, options.line stores the file name and sends it to the noOfLines() function to read it. readFileSync() is used to read the file.

// If flag is -l call the noOfLines function
if (options.line) console.log(noOfLines(options.line)+" "+options.line) ;

// Option -l is chosen
function noOfLines(file_name){

    // ReadFileSync function is used to read the file and convert it 
    // into string using toString() method
    var text = readFileSync(file_name).toString();

    // The text is splitted by new line and the length is found using length
    var lineCount = text.split('\n').length;

    // Formatted output
    return lineCount;
}

Step 5: Define function for -w or --word flag

When the -w or --word flag is used, then the command should return the number of words present in the given file. The below function is used to return the number of words present in the file.

// If flag is -w call the noOfWords function
if (options.word) console.log(noOfWords(options.word)+" "+options.word);

// Option -w is chosen
function noOfWords(file_name){
    var wordCount = 0;

    // Read the contents of file and separate it line by line
    var text = readFileSync(file_name).toString().split('\n');

    // Iterate through each line to find the number of words in each line
    for(const line of text){

        // Add it to the wordCount
        wordCount += line.split(' ').length;
    }

    // Format the output
    return wordCount;
}

Step 6: Define function for -m or --chars flag

When the -m or --chars flag is used, then the command should return the number of characters present in the given file. The below function is used to return the number of characters present in the file.

// If flag is -m call the noOfChars function
if (options.chars) console.log(noOfChars(options.chars)+" "+options.chars);

// Option -m is chosen
function noOfChars(file_name){

    // Find the number of characters in the file
    var charCount = readFileSync(file_name).toString().length;

    // Format the output
    return charCount;
}

Step 7: Define function for -c or --bytes flag

When the -c or --bytes flag is used, then the command should return the number of bytes present in the given file. The below function is used to return the number of bytes present in the file.

// If flag is -c call the noOfBytes function
if (options.bytes) console.log(noOfBytes(options.bytes)+" "+options.bytes);

// Option -c is chosen
function noOfBytes(file_name){

    // Find the number of bytes in the file
    var byteCount = readFileSync(file_name).length;

    // Format the output
    return byteCount;
}

Step 8: Define function without flag

When no flag is used, then the command should return the number of lines, words and characters present in the given file.

// console.log(program.args);
if (process.argv.length < 5) defaultCall(process.argv[3]);

// File name only provided
function defaultCall(file_name){
    // Get number of lines
    var lines = noOfLines(file_name);

    // Get number of words
    var words = noOfWords(file_name);

    // Get number of characters
    var characters = noOfChars(file_name);

    // Format output
    console.log(lines+" "+words+" "+characters+" "+file_name);

}

Final index.js file

The final index.js file should look like this.

#! /usr/bin/env node

// Module import
const { program } = require('commander');
const { readFileSync } = require('fs');

// Command is defined
program
    .command('cawc')
    .description('Return the number of lines, words, character present in the file.');

// Command options are defined
program
    .option('-l, --line <FILENAME>', 'Returns the number of lines in a file')
    .option('-w, --word <FILENAME>', 'Returns the number of words in a file')
    .option('-m, --chars <FILENAME>', 'Returns the number of characters in a file')
    .option('-c, --bytes <FILENAME>', 'Returns the number of bytes in a file');
    // .args('<FILENAME>');

// Input
program.parse(process.argv);
const options = program.opts();

// If flag is -l call the noOfLines function
if (options.line) console.log(noOfLines(options.line)+" "+options.line) ;

// If flag is -w call the noOfWords function
if (options.word) console.log(noOfWords(options.word)+" "+options.word);

// If flag is -m call the noOfChars function
if (options.chars) console.log(noOfChars(options.chars)+" "+options.chars);

// If flag is -c call the noOfBytes function
if (options.bytes) console.log(noOfBytes(options.bytes)+" "+options.bytes);

// console.log(program.args);
if (process.argv.length < 5) defaultCall(process.argv[3]);
// else {}

// Option -l is chosen
function noOfLines(file_name){

    // ReadFileSync function is used to read the file and convert it 
    // into string using toString() method
    var text = readFileSync(file_name).toString();

    // The text is splitted by new line and the length is found using length
    var lineCount = text.split('\n').length;

    // Formatted output
    return lineCount;
}

// Option -w is chosen
function noOfWords(file_name){
    var wordCount = 0;

    // Read the contents of file and separate it line by line
    var text = readFileSync(file_name).toString().split('\n');

    // Iterate through each line to find the number of words in each line
    for(const line of text){

        // Add it to the wordCount
        wordCount += line.split(' ').length;
    }

    // Format the output
    return wordCount;
}

// Option -m is chosen
function noOfChars(file_name){

    // Find the number of characters in the file
    var charCount = readFileSync(file_name).toString().length;

    // Format the output
    return charCount;
}

// Option -c is chosen
function noOfBytes(file_name){

    // Find the number of bytes in the file
    var byteCount = readFileSync(file_name).length;

    // Format the output
    return byteCount;
}

// File name only provided
function defaultCall(file_name){
    // Get number of lines
    var lines = noOfLines(file_name);

    // Get number of words
    var words = noOfWords(file_name);

    // Get number of characters
    var characters = noOfChars(file_name);

    // Format output
    console.log(lines+" "+words+" "+characters+" "+file_name);

}

Example Usage

To run the command, navigate to the bin folder and run the below command. Where, test.txt is a test file present in the bin folder.

node index.js cawc test.txt

You can also use custom file to run this command.

node index.js cawc file_path

Screenshots

Output using test file present in bin folder

Output using custom file location

Conclusion

Hurray! Your cli command was created successfully. Comment on this blog to clarify your doubts.

Resources

GitHub

To read more on commander.js

0
Subscribe to my newsletter

Read articles from Roopa directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Roopa
Roopa

I'm a pre-final year computer science student at SRM with a strong academic background and technical skills. I am actively contributing to the beginner-friendly open-source repositories to showcase my skills in web development. I love to share my knowledge of technical skills and am a pro at debugging errors.