My Logo

PUBLISHED MAY 11, 2024

Teghen Donald Ticha
Lastly Updated: 3 months ago
Reading time 16 mins

Implementing Basic functionalities

In this guide, we'll implement the basic functionalities of our app which will cover initial welcome and action prompts.
Implementing Basic functionalities

Prerequisite

It's recommended that you start with part one ( ) of this chapter.

In this part, we'll continue with the basic implementation of our interactive file explorer application.

With these basic functionalities, users to create new directories, provide existing directories, and interact with the contents of directories through a command-line interface (CLI).

We'll cover the project structure, key components, and how they work together to provide a basic yet intuitive user experience.

Project Structure

Our project structure is organized as follows:

interactive-file-explorer (root folder)
├── src
│   ├── index.js
│   └── helpers
│       ├── constants.js
│       ├── directoryHandlers.js
│       ├── directoryNavigation.js
│       ├── index.js
│       └── prompts.js
├── index.js
├── storage

The storage folder is where all created directories will be stored for reference and manipulation.

Components Overview
  1. 1.src/index.js: Entry point of our application. It imports and calls functions to display the welcome message and handle the initial prompt.
  2. 2.src/helpers/constants.js: Defines constants and utility functions, such as the path to the root directory of the application.
  3. 3.src/helpers/directoryHandlers.js: Contains functions to handle directory-related operations, such as creating a new directory, providing an existing directory, listing directory contents recursively, and storing directories in the storage folder.
  4. 4.src/helpers/directoryNavigation.js: Placeholder for future functionality related to navigating directories and interacting with their contents.
  5. 5.src/helpers/prompts.js: Provides functions to display welcome messages and handle user prompts for creating a new directory or providing an existing one.

Implementation Details

Let's dive into some key implementation details of our interactive file explorer app:

Creating a New Directory

Users are prompted to enter the name of the new directory, and it's created within the root directory of the application using the fs-extra library.

// src/helpers/directoryHandlers.js


const fse = require('fs-extra');
const inquirer = require('inquirer');
const chalk = require('chalk');
const { continueWithDirectoryInteraction } = require('./directoryNavigation');
const { pathToRootDirectory } = require('./constants');

// Function to create a new directory
function createNewDirectory() {
    inquirer
        .prompt([
            {
                type: 'input',
                name: 'directoryName',
                message: 'Enter the name of the new directory: '
            }
        ])
        .then((answers) => {
            const fullDirectoryPath =
                pathToRootDirectory() + answers.directoryName;
            console.log('fullDirectoryPath: ', fullDirectoryPath);
            // Create new directory
            fse.ensureDir(fullDirectoryPath)
                .then(() => {
                    console.log(
                        `New directory "${answers.directoryName}" created successfully.`
                    );
                    // Continue with directory interaction
                    continueWithDirectoryInteraction(answers.directoryName);
                })
                .catch((err) => {
                    console.error('Error creating directory:', err);
                });
        });
}

Breakdown:

  • We use the inquirer library to prompt the user to enter the name of the new directory.
  • Once the user provides the directory name, we construct the full path of the directory using the pathToRootDirectory() function.
  • We then use the fse.ensureDir() function from the fs-extra library to create the new directory asynchronously. If the directory already exists, it will be updated with the new contents.
  • After creating the directory, we store it in the storage folder for reference. We use the fse.writeFile() function to create an empty text file with the same name as the directory.
  • Finally, we display a success message and continue with the directory interaction.
Providing an Existing Directory

Users can specify the path of an existing directory. The application checks if the directory exists and loads its contents for exploration.

// src/helpers/directoryHandlers.js

// Function to provide an existing directory
function useExistingDirectory() {
    inquirer
        .prompt([
            {
                type: 'input',
                name: 'directoryPath',
                message: 'Enter the path of the existing directory: '
            }
        ])
        .then((answers) => {
            const fullDirectoryPath =
                pathToRootDirectory() + answers.directoryPath;
            // Check if directory exists
            fse.pathExists(fullDirectoryPath)
                .then((exists) => {
                    if (exists) {
                        console.log(
                            chalk.green(`Existing directory "${chalk.bold(answers.directoryPath)}" loaded successfully.`)
                        );
                        // list content
                        listDirectoryContents(fullDirectoryPath)
                        .then(result => {
                            if (!result.ok) {
                                console.error(chalk.red(result.error?.message??'Error occurred while reading directory content'));
                                throw result.error
                            }
                            else {
                                // Continue with directory interaction
                                continueWithDirectoryInteraction(answers.directoryPath);
                            }                          
                            
                        });
                        
                        
                    } else {
                        console.error(
                            chalk.yellow('Directory does not exist:'),
                            chalk.underline.bgRed(answers.directoryPath)
                        );
                        useExistingDirectory(); // Prompt user again
                    }
                })
                .catch((err) => {
                    console.error(
                        chalk.red('Error checking directory existence: '),
                        err
                    );
                });
        });
}

Breakdown:

  • Similar to creating a new directory, we prompt the user to enter the path of an existing directory using the inquirer library.
  • We construct the full path of the directory and check if it exists asynchronously using the fse.pathExists() function.
  • If the directory exists, we display a success message, store it in the storage folder, and list its contents recursively using the listDirectoryContents() function.
  • If the directory does not exist, we display an error message and prompt the user again.
Listing Directory Contents

Directories and files within the specified directory are recursively listed in a concise and descriptive manner.

// src/helpers/directoryHandler.js

// Function to list directory's content
async function listDirectoryContents(directory) {
    console.log(`\n *** ${directory.split('/').pop()} ***`);
    let error = null;

    if (!directory) {
        //error = new Error('directory not found!')
        return {ok: false, error};
    }

    const result = await listDirectory(directory)
    
    return result ;
}

async function listDirectory(directoryPath, indent = '') {
    let result = {ok: true, error: null};

    fse.readdir(directoryPath, (err, files) => {
        if (err) {   
            result.error = err ;  
            result.ok = false  ; 
            return;
        }

        files.forEach((file) => {
            const filePath = `${directoryPath}/${file}`;
            fse.stat(filePath, (err, stats) => {
                if (err) {
                    result.error = err;
                    result.ok = false;
                    return;
                }

                if (stats.isDirectory()) {
                    console.log(`${indent}📁 ${file}`);
                    listDirectory(filePath, `${indent}  `); // Recursively list subdirectory
                } else {
                    console.log(`${indent}📄 ${file}`);
                }
            });
        });
        
    });
    return result;
}

Breakdown:

  • The listDirectoryContents() function is responsible for initiating the listing of directory contents. It logs the name of the directory being listed and calls the helper function listDirectory() to perform the actual listing.
  • The listDirectory() function reads the contents of the specified directory using fse.readdir() and iterates over each file or subdirectory.
  • For each item in the directory, it determines whether it's a file or a directory using fse.stat() and logs the appropriate symbol (📁 for directories, 📄 for files).
  • If the item is a directory, the function recursively calls itself to list its contents.
Continuing with Directory Interaction

Placeholder function to continue interacting with directories. This could include features like navigating directories, adding/deleting files, etc.

// src/helpers/directoryNavigation.js

const chalk = require('chalk');

// Function to continue with directory interaction
function continueWithDirectoryInteraction(directoryPath) {
    // TODO: Implement directory navigation and interaction
    setTimeout(() => {
        console.log(`Continue interacting with : ${chalk.blue(directoryPath)}`);
    }, 200)

}

module.exports = {
    continueWithDirectoryInteraction
};


App Entry

The entry point of our application.

// src/index.js

const { displayWelcomeMessage, handleInitialPrompt } = require('./helpers');

// Call functions to display welcome message and initial prompt
displayWelcomeMessage();
handleInitialPrompt();


Testing

To test these basic features, add a folder to the storage folder name `nameer`.

In this folder add another folder name `player` and in that add a file name `play.js` with a single line of code like : console.log('I\'m just playing around');

Then, in your terminal run the command npm run format to format your code according to our prettier config and then, run npm run dev.

  • select 1, then enter any name for a new folder to be created. you shloud get some like :
fullDirectoryPath:  /Users/donaldteghen/Desktop/no-linear-path/interactive-file-explorer-app/storage/new-dir
New directory "new-dir" created successfully.
Continue interacting with directory: new-dir


  • Restart the app, this time select 2 and enter nameer. You get a stats of the directory ie all its folders aand subfolders and their file contents if any.
> node src/index.js

Welcome to the Interactive File Explorer!
-----------------------------------------
Do you want to:
1. Create a new directory
2. Provide an existing directory
Enter your choice (1 or 2): 2
2
? Enter the path of the existing directory:  nameer
? Enter the path of the existing directory:  nameer
? Enter the path of the existing directory:  nameer
Existing directory "nameer" loaded successfully.

 *** nameer ***
📄 name.txt
📁 player
  📄 play.js
Continue interacting with directory: nameer


So far, we've covered the implementation of basic functionalities in an interactive file explorer application.

Our application provides a simple yet powerful interface for managing directories and files through the command line.
Now, it's time to add more advanced features and capabilities.

All Chapter Parts for NodeJs In Theory, An absolute Beginner’s Overview
  1. Chapter 1 , Part 1 : Introduction to NodeJS

    In this series part, I introduce nodeJS and some technical concepts associated with it. I also show how easy it is to setup and start a simple nodeJS web server.

  2. Chapter 1 , Part 2 : How to Install and Setup NodeJS

    In this series part, I run you through the various ways to install nodeJS. I also discuss how to install nvm and use it to switch between different node versions.

  3. Chapter 1 , Part 3 : How much JavaScript do you need to learn NodeJS

    In this series part, we explore the nuanced relationship between JavaScript and NodeJS, highlighting some subtle distinctions between the two environments.

  4. Chapter 1 , Part 4 : The v8 Engine and the difference Between NodeJS and the browser

    In this series part, we explore the V8 engine and how it interacts with nodeJS. We also discuss node’s event loop and uncover the mystery behinds node’s ability to handle concurrent operations.

  5. Chapter 1 , Part 5 : NPM, the NodeJS package manager

    Discover the essentials of npm, the powerful package manager for Node.js. Learn installation, management, publishing, and best practices

  6. Chapter 1 , Part 6 : NodeJS in Development Vs Production

    Explore how Node.js behaves differently in development and production environments. Learn key considerations for deploying Node.js applications effectively.

  7. Chapter 2 , Part 1 : Asynchronous Flow Control

    In this series part, we'll explore various aspects of asynchronous flow control in Node.js, from basic concepts to advanced techniques.

  8. Chapter 2 , Part 2 : Blocking vs Non-blocking I/O

    Explore the differences between blocking and non-blocking I/O in Node.js, and learn how to optimize performance and scalability.

  9. Chapter 2 , Part 3 : Understanding NodeJS Event loop

    Exploring the Node.js event loop by understanding its phases, kernel integration, and processes enabling seamless handling of asynchronous operations in your applications.

  10. Chapter 2 , Part 4 : The NodeJS EventEmitter

    Explore the power of Node.js EventEmitter: an essential tool for building scalable and event-driven applications. Learn how to utilize it effectively!

  11. Chapter 3 , Part 1 : Working with files in NodeJS

    Gain comprehensive insights into file management in Node.js, covering file stats, paths, and descriptors, to streamline and enhance file operations in your applications.

  12. Chapter 3 , Part 2 : Reading and Writing Files in NodeJS

    Uncover the fundamentals of reading and writing files in nodeJS with comprehensive examples and use cases for some widely used methods.

  13. Chapter 3 , Part 3 : Working with Folders in NodeJS

    Unlock the secrets of folder manipulation in Node.js! Explore essential techniques and methods for working with directories efficiently

  14. Chapter 4 , Part 1 : Running NodeJS Scripts

    Master the command line interface for executing nodeJS scripts efficiently. Learn common options and best practices for seamless script execution

  15. Chapter 4 , Part 2 : Reading Environment Variables in NodeJS

    Learn how to efficiently manage environment variables in nodeJS applications. Explore various methods and best practices for security and portability

  16. Chapter 4 , Part 3 : Writing Outputs to the Command Line in NodeJS

    Learn essential techniques for writing outputs in nodeJS CLI. From basic logging to formatting and understanding stdout/stderr.

  17. Chapter 4 , Part 4 : Reading Inputs from the Command Line in NodeJS

    Learn the various ways and strategies to efficiently read command line inputs in nodeJS, making your program more interactive and flexible.

  18. Chapter 4 , Part 5 : The NodeJS Read, Evaluate, Print, and Loop (REPL)

    Explore the power of nodeJS's Read, Evaluate, Print, and Loop (REPL). Learn how to use this interactive environment for rapid prototyping, debugging, and experimentation.

  19. Chapter 5 , Part 1 : Introduction to Testing in NodeJS

    Discover the fundamentals of testing in nodeJS! Learn about testing types, frameworks, and best practices for building reliable applications.

  20. Chapter 5 , Part 2 : Debugging Tools and Techniques in NodeJS

    Explore essential debugging tools and techniques in Node.js development. From built-in options to advanced strategies, and best practices for effective debugging.

  21. Chapter 6 , Part 1 : Project Planning and Setup

    Discuss the planning and design process for building our interactive file explorer in Node.js, focusing on core features, UI/UX design, and implementation approach and initial setup.

  22. Chapter 6 , Part 2 : Implementing Basic functionalities

    In this guide, we'll implement the basic functionalities of our app which will cover initial welcome and action prompts.

  23. Chapter 6 , Part 3 : Implementating Core Features and Conclusion

    In this guide, we'll complete the rest of the more advanced functionalities of our app including, create, search, sort, delete, rename and navigate file directories.