Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
df4ff07
create cat.js file to implement cat logic in it
HassanOHOsman Nov 21, 2025
2ee4991
import 2 built in NodeJS modules
HassanOHOsman Nov 21, 2025
0931aea
checks if our program receieves 1 argument otherwise throw an error m…
HassanOHOsman Nov 21, 2025
f8392fa
storing the one argument in our program into a a variable called path
HassanOHOsman Nov 21, 2025
23b18aa
Read file at the path passed as argument in the programme
HassanOHOsman Nov 21, 2025
136af7b
rename content var in a more meaningful way
HassanOHOsman Nov 21, 2025
0f50542
log out/display a file content without adding a new line
HassanOHOsman Nov 21, 2025
2289a8d
installed commander library and updated the type property in JSON file
HassanOHOsman Nov 21, 2025
b236e17
improting commander library into js file
HassanOHOsman Nov 21, 2025
4f65e6c
setting up basic info about our program and most importantly a flag/o…
HassanOHOsman Nov 21, 2025
72dab99
update the program info to include argument
HassanOHOsman Nov 21, 2025
b6de478
commader to interpret the command line arguments based on -n option
HassanOHOsman Nov 21, 2025
68982c6
read all the flags/options provided.
HassanOHOsman Nov 21, 2025
eaf8d3b
cleaning code and getting rid of useless bits
HassanOHOsman Nov 21, 2025
815dd88
splitting the contnet of a file by newline and storing it in a var na…
HassanOHOsman Nov 21, 2025
73f9e36
build logic for number of lines options
HassanOHOsman Nov 21, 2025
bff2e3b
adding a condition as to when the -n option used
HassanOHOsman Nov 21, 2025
ee72ac4
getting rid of numbered trailing empty lines
HassanOHOsman Nov 21, 2025
2ba43de
define -b option in the porgram info
HassanOHOsman Nov 21, 2025
583c011
update logic for -n & -b options
HassanOHOsman Nov 21, 2025
13d12fe
update & correct logic for -n & -b options
HassanOHOsman Nov 21, 2025
8ba6202
join the array elements by new line and output the formed text to end…
HassanOHOsman Nov 21, 2025
64ff212
add a scenario as to when the program doesn't contain any -n or -b flags
HassanOHOsman Nov 21, 2025
bbe5b0c
reworking on code so that it handles outputting content from multiple…
HassanOHOsman Nov 21, 2025
ddf594b
work on logic to hadle multiple files
HassanOHOsman Nov 21, 2025
ee0d711
update the argument in the program info to handle multiple paths
HassanOHOsman Nov 21, 2025
d123b19
create ls file to store all the js program logic
HassanOHOsman Nov 21, 2025
cd93e63
run teminal commands to add package.json since i'll be using import t…
HassanOHOsman Nov 21, 2025
584666e
import built in and third part modules/libraries into the ls.js file
HassanOHOsman Nov 21, 2025
ae56d9b
uodate the type value to "module" so that i could use "import" keyword
HassanOHOsman Nov 21, 2025
49b4e4b
Initialize program with basic info (name, description, argument & opt…
HassanOHOsman Nov 21, 2025
8f7a7e1
Add argument parsing for file path
HassanOHOsman Nov 21, 2025
a67234a
sotre program.opts in meaningful var options
HassanOHOsman Nov 21, 2025
385b875
path expect one argument /file path
HassanOHOsman Nov 21, 2025
d5ea768
directoryContent stores a value that reads the content (files & folde…
HassanOHOsman Nov 21, 2025
5adee43
adding a for loop for when -1 option is added to an ls program
HassanOHOsman Nov 21, 2025
d84dd4d
update the -1 flag description in the program info part
HassanOHOsman Nov 21, 2025
bd01e5c
add spacing for when ls is used without the -1/--one option
HassanOHOsman Nov 21, 2025
83940e0
add option f-a for handling all files - including hidden ones - in th…
HassanOHOsman Nov 21, 2025
6943c01
logic to filter out hidden files form LS output if -a is not added to it
HassanOHOsman Nov 21, 2025
0ec7440
update logic for when option -a not selected
HassanOHOsman Nov 21, 2025
9a639b6
create "wc.js" file to house my programme
HassanOHOsman Nov 24, 2025
1b2e8ec
initialised npm and installed "Commander" library
HassanOHOsman Nov 24, 2025
bebba1c
update the type property value to "module" in the JSON file
HassanOHOsman Nov 24, 2025
e2ee819
import built-in & third party dependancies into the wc.js file
HassanOHOsman Nov 24, 2025
b87db26
set the program basic info and the first option: -l
HassanOHOsman Nov 24, 2025
b291f4f
interpert the command line argument based on option and ensure that t…
HassanOHOsman Nov 24, 2025
0e8d2b9
ensuring that excactly one argument passed onto our porgramme
HassanOHOsman Nov 24, 2025
f827bfd
the first (and only) user argument sotred in a variable path
HassanOHOsman Nov 24, 2025
8139354
Add options parsing and directory reading
HassanOHOsman Nov 24, 2025
ee0f23e
improt "stat" function from the fs module
HassanOHOsman Nov 24, 2025
eb7c00b
use stat function to grap info about the file or directory and store …
HassanOHOsman Nov 24, 2025
ee3b4eb
add if condition to handle 2 cases: 1) path is file or path is dir
HassanOHOsman Nov 24, 2025
62a1c7d
build a path for each file in a dir and process the file depending on…
HassanOHOsman Nov 24, 2025
d4644e1
create a function to count lines
HassanOHOsman Nov 24, 2025
b51271e
include word counting functionality in the function counter
HassanOHOsman Nov 24, 2025
e9dc04e
make the function counter characters too
HassanOHOsman Nov 24, 2025
fbb3e4e
add return values inside the function
HassanOHOsman Nov 24, 2025
2af4968
add the function counter the inside if condition for the case of deal…
HassanOHOsman Nov 24, 2025
87768a1
update if block to handle when -l option logic for when it's added to…
HassanOHOsman Nov 24, 2025
4196751
remove the buggy line
HassanOHOsman Nov 24, 2025
5cbefa1
update the function so that it returns the numebr of lines rather tha…
HassanOHOsman Nov 24, 2025
03d9fb6
adding .trim() method to get rid of the spaces (not counting blank li…
HassanOHOsman Nov 24, 2025
091692c
add a function for the logic for when the case of the path is "dir"
HassanOHOsman Nov 24, 2025
c6aa7ae
for dir case: create logic to handdle when -l option is added to the …
HassanOHOsman Nov 24, 2025
524af1d
update the error in the else for dir
HassanOHOsman Nov 24, 2025
46c5df5
update bugy lines of code
HassanOHOsman Nov 24, 2025
c58db9c
remove the validation for if we have multiple arguments as this clash…
HassanOHOsman Nov 24, 2025
eb67a84
update logic to handl having mutple paths (files) when dealing with a…
HassanOHOsman Nov 24, 2025
8a546e1
add counters for total lines, words & characters for when the path is…
HassanOHOsman Nov 24, 2025
ec4de6a
for the case of a dire print the total coutner
HassanOHOsman Nov 24, 2025
009c40b
add -w option in the program basic info
HassanOHOsman Nov 24, 2025
c32410a
flesh out logic to include the -w & -c options
HassanOHOsman Nov 24, 2025
3cc8aaf
code now handles no flag cases for all scenarios (file or dir)
HassanOHOsman Nov 24, 2025
397d4e0
update logic to match the wc command line in the way it displays output
HassanOHOsman Nov 24, 2025
e155672
house keeping
HassanOHOsman Nov 24, 2025
d2daa0e
remove redantant and repetitive code
HassanOHOsman Nov 24, 2025
4fdb357
validating the path first
HassanOHOsman Jan 9, 2026
b2563c1
add try-catch code block
HassanOHOsman Jan 9, 2026
b5866c5
change
HassanOHOsman Jan 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions implement-shell-tools/cat/cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import process from "node:process";
import {promises as fs} from "node:fs";
import {program} from "commander";

program
.name("display-file-content")
.description("Output the content of a file to the terminal")
.argument("<path...>", "The file path to process")
.option("-n", "Number the output lines")
.option("-b","Number the non-blank output lines")

program.parse();

const paths = program.args;

const options = program.opts();

let lineNumber = 1;

for (const path of paths) {
const filesContent = await fs.readFile(path, "utf-8");

const lines = filesContent.split("\n");

if (lines[lines.length - 1] === "") {
lines.pop();
}

for (let line of lines) {
if (options.n) {
process.stdout.write(`${lineNumber} ${line}\n`);
lineNumber++;
} else if (options.b) {
if (line != "") {
process.stdout.write(`${lineNumber} ${line}\n`);
lineNumber++;
} else {
process.stdout.write("\n");
}
} else {
process.stdout.write(line + "\n");
}
}
}









25 changes: 25 additions & 0 deletions implement-shell-tools/cat/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions implement-shell-tools/cat/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "cat",
"version": "1.0.0",
"description": "You should already be familiar with the `cat` command line tool.",
"main": "cat.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"commander": "^14.0.2"
}
}
48 changes: 48 additions & 0 deletions implement-shell-tools/ls/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import process from "node:process";
import { promises as fs } from "node:fs";
import { program } from "commander";

program
.name("list-files-in-directory")
.description("List all files and directories in a directory")
.argument("<path>", "The file path to process")
.option("-1, --one", "Output one entry per line")
.option("-a", "List all files & directories, including hidden ones");

program.parse();

const path = program.args[0];

const options = program.opts();

if (!path) {
console.error("Error: No directory path was provided.");
process.exit(1);
}

let directoryContent;

try {
directoryContent = await fs.readdir(path);
} catch (err) {
console.error(`Error reading directory: ${err.message}`);
process.exit(1);
}

let allContent = directoryContent;

if (!options.a) {
allContent = directoryContent.filter(name => !name.startsWith("."));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen if a directory was not provided - are we able to handle this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Matt, apologies for the very delayed response!
Thanks for bringing this to my attention.
I've just added validation to handle such a case.
Please review and let me know.

}

for (const item of allContent) {
if (options.one) {
process.stdout.write(item + "\n");
} else {
process.stdout.write(item + " ");
}
}




25 changes: 25 additions & 0 deletions implement-shell-tools/ls/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions implement-shell-tools/ls/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "ls",
"version": "1.0.0",
"description": "You should already be familiar with the `ls` command line tool.",
"main": "ls.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"commander": "^14.0.2"
}
}
25 changes: 25 additions & 0 deletions implement-shell-tools/wc/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions implement-shell-tools/wc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "wc",
"version": "1.0.0",
"description": "You should already be familiar with the `wc` command line tool.",
"main": "wc.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"commander": "^14.0.2"
}
}
90 changes: 90 additions & 0 deletions implement-shell-tools/wc/wc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { program } from "commander";
import { promises as fs } from "node:fs";
import process from "node:process";
import { stat } from "node:fs/promises";

program
.name("count-containing-lines-words-characters")
.description("Counts lines, words or characters in a file (or all files) inside a directory")
.option("-l, --line", "The number of lines in each file")
.option("-w, --word", "The number of words in each file")
.option("-c, --character", "The number of characters in each file")
.argument("<path...>", "The file path to process");

program.parse();

const argv = program.args;

const options = program.opts();


function counter(item) {
const lines = item.trim().split("\n").length;
const words = item.split(/\s+/).filter(Boolean).length;
const characters = item.length;
return { lines, words, characters };
}

let totalLines = 0;
let totalWords = 0;
let totalCharacters = 0;
let fileCount = 0;

for (const path of argv) {
const pathInfo = await stat(path);

if (pathInfo.isFile()) {
const content = await fs.readFile(path, "utf-8");
const stats = counter(content);
if (options.line) {
console.log(`${stats.lines} ${path}`);
} else if (options.word) {
console.log(`${stats.words} ${path}`);
} else if (options.character) {
console.log(`${stats.characters} ${path}`);
} else {
console.log(`${stats.lines} ${stats.words} ${stats.characters} ${path}`);
}

totalLines += stats.lines;
totalWords += stats.words;
totalCharacters += stats.characters;
fileCount++;

} else if (pathInfo.isDirectory()) {
const files = await fs.readdir(path);
for (const file of files) {
const filePath = `${path}/${file}`;
const fileContent = await fs.readFile(filePath, "utf-8");
const stats = counter(fileContent);

if (options.line) {
console.log(`${stats.lines} ${filePath}`);
} else if (options.word) {
console.log(`${stats.words} ${filePath}`);
} else if (options.character) {
console.log(`${stats.characters} ${filePath}`);
} else {
console.log(`${stats.lines} ${stats.words} ${stats.characters} ${filePath}`);
}

totalLines += stats.lines;
totalWords += stats.words;
totalCharacters += stats.characters;
fileCount++;
}
}

}

if (fileCount > 1) {
if (options.line) {
console.log(`${totalLines} total`);
} else if (options.word) {
console.log(`${totalWords} total`);
} else if (options.character) {
console.log(`${totalCharacters} total`);
} else {
console.log(`${totalLines} ${totalWords} ${totalCharacters} total`);
}
}