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.src/index.js: Entry point of our application. It imports and calls functions to display the welcome message and handle the initial prompt.
- 2.src/helpers/constants.js: Defines constants and utility functions, such as the path to the root directory of the application.
- 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.src/helpers/directoryNavigation.js: Placeholder for future functionality related to navigating directories and interacting with their contents.
- 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 thefs-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 thefse.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 thelistDirectoryContents()
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 functionlistDirectory()
to perform the actual listing. - ➢The
listDirectory()
function reads the contents of the specified directory usingfse.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.
PAGE CONTENT
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.
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.
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.
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.
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
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.
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.
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.
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.
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!
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.
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.
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
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
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
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.
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.
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.
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.
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.
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.
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.
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.