From df4ff07b6f3a449fa88982c3dcd6e645fb159c90 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 08:47:22 +0000 Subject: [PATCH 01/83] create cat.js file to implement cat logic in it --- implement-shell-tools/cat/cat.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 implement-shell-tools/cat/cat.js diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js new file mode 100644 index 00000000..e69de29b From 2ee4991c4efd03e28a3976a0101c7c5f7cb159e6 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 08:52:25 +0000 Subject: [PATCH 02/83] import 2 built in NodeJS modules --- implement-shell-tools/cat/cat.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index e69de29b..6d8199df 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,3 @@ +import process from "node:process"; +import {promises as fs} from "node:fs"; + From 0931aea909bf0a6b7a9982694e96deea341ffb77 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:01:05 +0000 Subject: [PATCH 03/83] checks if our program receieves 1 argument otherwise throw an error message and exit the program (unsuccessful). --- implement-shell-tools/cat/cat.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 6d8199df..f7a3e885 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -1,3 +1,8 @@ import process from "node:process"; import {promises as fs} from "node:fs"; +const argv = process.argv.slice(2); +if (argv.length != 1) { + console.error("Expected exactly 1 argument or a path but received ${argv.length."); + process.exit(1); +} \ No newline at end of file From f8392fa9936a05746d5f6c190dc5c02219edd009 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:03:54 +0000 Subject: [PATCH 04/83] storing the one argument in our program into a a variable called path --- implement-shell-tools/cat/cat.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index f7a3e885..94c6fc79 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -5,4 +5,6 @@ const argv = process.argv.slice(2); if (argv.length != 1) { console.error("Expected exactly 1 argument or a path but received ${argv.length."); process.exit(1); -} \ No newline at end of file +} + +const path = argv[0]; \ No newline at end of file From 23b18aa5e3f68f2e5439a0cef0a173bf967e3ebe Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:08:11 +0000 Subject: [PATCH 05/83] Read file at the path passed as argument in the programme --- implement-shell-tools/cat/cat.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 94c6fc79..85e79083 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -7,4 +7,6 @@ if (argv.length != 1) { process.exit(1); } -const path = argv[0]; \ No newline at end of file +const path = argv[0]; + +const content = await fs.readFile(path, "utf-8"); \ No newline at end of file From 136af7b37ead85f1024ccbdfabc2d9ade0aee524 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:15:36 +0000 Subject: [PATCH 06/83] rename content var in a more meaningful way --- implement-shell-tools/cat/cat.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 85e79083..137eee56 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -9,4 +9,7 @@ if (argv.length != 1) { const path = argv[0]; -const content = await fs.readFile(path, "utf-8"); \ No newline at end of file +const displayFileContent = await fs.readFile(path, "utf-8"); + + + From 0f50542a86c5ed658c7c4edd37de4373a1b2ac7e Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:16:30 +0000 Subject: [PATCH 07/83] log out/display a file content without adding a new line --- implement-shell-tools/cat/cat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 137eee56..2839be27 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -11,5 +11,5 @@ const path = argv[0]; const displayFileContent = await fs.readFile(path, "utf-8"); - +process.stdout.write(displayFileContent); From 2289a8dc628a08695f270e7b5bc87e38a1825a2d Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:41:05 +0000 Subject: [PATCH 08/83] installed commander library and updated the type property in JSON file --- implement-shell-tools/cat/package-lock.json | 25 +++++++++++++++++++++ implement-shell-tools/cat/package.json | 16 +++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 implement-shell-tools/cat/package-lock.json create mode 100644 implement-shell-tools/cat/package.json diff --git a/implement-shell-tools/cat/package-lock.json b/implement-shell-tools/cat/package-lock.json new file mode 100644 index 00000000..9ca092a6 --- /dev/null +++ b/implement-shell-tools/cat/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "cat", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cat", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/cat/package.json b/implement-shell-tools/cat/package.json new file mode 100644 index 00000000..a6653b6b --- /dev/null +++ b/implement-shell-tools/cat/package.json @@ -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" + } +} From b236e1722e871caada5e0ec8b29a93ea87f08886 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:44:17 +0000 Subject: [PATCH 09/83] improting commander library into js file --- implement-shell-tools/cat/cat.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 2839be27..ace43531 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -1,5 +1,7 @@ import process from "node:process"; import {promises as fs} from "node:fs"; +import {program} from "commander"; + const argv = process.argv.slice(2); if (argv.length != 1) { From 4f65e6cd243db3b0220b978cbc8435a95ca8f85b Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:50:12 +0000 Subject: [PATCH 10/83] setting up basic info about our program and most importantly a flag/option to handle the number of output lines --- implement-shell-tools/cat/cat.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index ace43531..741923b3 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -2,6 +2,11 @@ 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") + .option("-n", "Number the output lines") + const argv = process.argv.slice(2); if (argv.length != 1) { From 72dab994cc02dc3fb8c165e858b4103a33b477ca Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 09:54:41 +0000 Subject: [PATCH 11/83] update the program info to include argument --- implement-shell-tools/cat/cat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 741923b3..b5c77144 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -5,9 +5,9 @@ import {program} from "commander"; program .name("display-file-content") .description("Output the content of a file to the terminal") + .argument("", "The file path to process") .option("-n", "Number the output lines") - const argv = process.argv.slice(2); if (argv.length != 1) { console.error("Expected exactly 1 argument or a path but received ${argv.length."); From b6de4785b7673b84571704c7ccaee19d97d04998 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 10:02:22 +0000 Subject: [PATCH 12/83] commader to interpret the command line arguments based on -n option --- implement-shell-tools/cat/cat.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index b5c77144..52a8d770 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -8,6 +8,8 @@ program .argument("", "The file path to process") .option("-n", "Number the output lines") +program.parse(); + const argv = process.argv.slice(2); if (argv.length != 1) { console.error("Expected exactly 1 argument or a path but received ${argv.length."); From 68982c64e0730b76b1fc9418374bc105b759d30e Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 10:16:12 +0000 Subject: [PATCH 13/83] read all the flags/options provided. --- implement-shell-tools/cat/cat.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 52a8d770..a0a4a838 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -10,13 +10,15 @@ program program.parse(); -const argv = process.argv.slice(2); +const argv = program.args; if (argv.length != 1) { console.error("Expected exactly 1 argument or a path but received ${argv.length."); process.exit(1); } const path = argv[0]; +const options = program.opts(); + const displayFileContent = await fs.readFile(path, "utf-8"); From eaf8d3b5a4f98d9151be8b0239ae403b37f44fda Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 10:22:40 +0000 Subject: [PATCH 14/83] cleaning code and getting rid of useless bits --- implement-shell-tools/cat/cat.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index a0a4a838..6e030a1b 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -10,15 +10,11 @@ program program.parse(); -const argv = program.args; -if (argv.length != 1) { - console.error("Expected exactly 1 argument or a path but received ${argv.length."); - process.exit(1); -} +const paths = program.args; -const path = argv[0]; const options = program.opts(); +const path = paths[0]; const displayFileContent = await fs.readFile(path, "utf-8"); From 815dd880573ee0d567098f9467f4535b0f0a0059 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 10:27:28 +0000 Subject: [PATCH 15/83] splitting the contnet of a file by newline and storing it in a var named lines --- implement-shell-tools/cat/cat.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 6e030a1b..440fb34b 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -18,5 +18,7 @@ const path = paths[0]; const displayFileContent = await fs.readFile(path, "utf-8"); +const lines = displayFileContent.split("\n"); + process.stdout.write(displayFileContent); From 73f9e368b8fd7bffb81636f595ed9158ab263ff5 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 10:37:02 +0000 Subject: [PATCH 16/83] build logic for number of lines options --- implement-shell-tools/cat/cat.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 440fb34b..cae0fb9f 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -18,7 +18,11 @@ const path = paths[0]; const displayFileContent = await fs.readFile(path, "utf-8"); -const lines = displayFileContent.split("\n"); +const linesArray = displayFileContent.split("\n"); + +const numberedLinesArray = linesArray.map((line, index) => `${index + 1} ${line}`); + +const numberedLines = numberedLinesArray.join("\n") process.stdout.write(displayFileContent); From bff2e3b50cef274648fc48e9ce53b263db7add89 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 10:38:13 +0000 Subject: [PATCH 17/83] adding a condition as to when the -n option used --- implement-shell-tools/cat/cat.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index cae0fb9f..92a057b1 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -24,5 +24,11 @@ const numberedLinesArray = linesArray.map((line, index) => `${index + 1} ${line const numberedLines = numberedLinesArray.join("\n") -process.stdout.write(displayFileContent); +if (options.n) { + process.stdout.write(numberedLines); +} else { + process.stdout.write(displayFileContent); +} + + From ee72ac4c50cc42a31d3699a98b48eb0726407361 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 10:49:52 +0000 Subject: [PATCH 18/83] getting rid of numbered trailing empty lines --- implement-shell-tools/cat/cat.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 92a057b1..e30acdc9 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -20,6 +20,10 @@ const displayFileContent = await fs.readFile(path, "utf-8"); const linesArray = displayFileContent.split("\n"); +if (linesArray[linesArray.length - 1] == "") { + linesArray.pop(); +} + const numberedLinesArray = linesArray.map((line, index) => `${index + 1} ${line}`); const numberedLines = numberedLinesArray.join("\n") From 2ba43dee9c7a3ebd2af0f0df5d30946f481ccccb Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 11:02:03 +0000 Subject: [PATCH 19/83] define -b option in the porgram info --- implement-shell-tools/cat/cat.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index e30acdc9..83883143 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -7,6 +7,7 @@ program .description("Output the content of a file to the terminal") .argument("", "The file path to process") .option("-n", "Number the output lines") + .option("-b","Number the non-blank output lines") program.parse(); From 583c011d6b784b2760fdbc670eef8eb0bd6d0883 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 14:20:09 +0000 Subject: [PATCH 20/83] update logic for -n & -b options --- implement-shell-tools/cat/cat.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 83883143..3b677657 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -25,15 +25,14 @@ if (linesArray[linesArray.length - 1] == "") { linesArray.pop(); } -const numberedLinesArray = linesArray.map((line, index) => `${index + 1} ${line}`); +const outputLines = []; -const numberedLines = numberedLinesArray.join("\n") +let lineNumber = 1; -if (options.n) { - process.stdout.write(numberedLines); -} else { - process.stdout.write(displayFileContent); +for (let line in linesArray) { + if (options.n) { + const numberedLines = "${lineNumber} ${line}"; + lineNumber++; + } } - - From 13d12fe0477a60b0ef9fd41e96514345dd5cc7d9 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 14:28:39 +0000 Subject: [PATCH 21/83] update & correct logic for -n & -b options --- implement-shell-tools/cat/cat.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 3b677657..600c9037 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -31,8 +31,17 @@ let lineNumber = 1; for (let line in linesArray) { if (options.n) { - const numberedLines = "${lineNumber} ${line}"; + const numberedLines = '${lineNumber} ${line}'; + outputLines.push(numberedLines); lineNumber++; + } else if (options.b) { + if (line != "") { + const numberedLines = "${lineNumber} ${line}"; + outputLines.push(numberedLines); + lineNumber++; + } else { + outputLines.push(""); + } } } From 8ba620282a3a01a88b609335a6a5e41bcfc81be6 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 14:31:30 +0000 Subject: [PATCH 22/83] join the array elements by new line and output the formed text to end user --- implement-shell-tools/cat/cat.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 600c9037..b1f05eab 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -45,3 +45,5 @@ for (let line in linesArray) { } } +process.stdout.write(outputLines.join("\n")); + From 64ff2125a459dc709332b40ba08cec22232064ca Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 14:36:30 +0000 Subject: [PATCH 23/83] add a scenario as to when the program doesn't contain any -n or -b flags --- implement-shell-tools/cat/cat.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index b1f05eab..10585bf1 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -29,19 +29,21 @@ const outputLines = []; let lineNumber = 1; -for (let line in linesArray) { +for (let line of linesArray) { if (options.n) { - const numberedLines = '${lineNumber} ${line}'; + const numberedLines = `${lineNumber} ${line}`; outputLines.push(numberedLines); lineNumber++; } else if (options.b) { if (line != "") { - const numberedLines = "${lineNumber} ${line}"; + const numberedLines = `${lineNumber} ${line}`; outputLines.push(numberedLines); lineNumber++; } else { outputLines.push(""); } + } else { + outputLines.push(line) } } From bbe5b0ce706a1b3ab96dd4f7ca03b6791aa8de67 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 15:24:40 +0000 Subject: [PATCH 24/83] reworking on code so that it handles outputting content from multiple files --- implement-shell-tools/cat/cat.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 10585bf1..91c0584a 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -13,11 +13,12 @@ program.parse(); const paths = program.args; -const options = program.opts(); +for (const path of paths) { + const filesContent = await fs.readFile(path, "utf-8"); +} -const path = paths[0]; +const options = program.opts(); -const displayFileContent = await fs.readFile(path, "utf-8"); const linesArray = displayFileContent.split("\n"); From ddf594ba5c0adc47372e9121c95893fc92a3fbc3 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 17:53:46 +0000 Subject: [PATCH 25/83] work on logic to hadle multiple files --- implement-shell-tools/cat/cat.js | 41 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 91c0584a..d1730ba9 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -13,40 +13,41 @@ program.parse(); const paths = program.args; -for (const path of paths) { - const filesContent = await fs.readFile(path, "utf-8"); -} - const options = program.opts(); +let lineNumber = 1; -const linesArray = displayFileContent.split("\n"); - -if (linesArray[linesArray.length - 1] == "") { - linesArray.pop(); -} +for (const path of paths) { + const filesContent = await fs.readFile(path, "utf-8"); -const outputLines = []; + const lines = filesContent.split("\n"); -let lineNumber = 1; + if (lines[lines.length - 1] === "") { + lines.pop(); + } -for (let line of linesArray) { + for (let line of lines) { if (options.n) { - const numberedLines = `${lineNumber} ${line}`; - outputLines.push(numberedLines); + process.stdout.write(`${lineNumber} ${line}\n`); lineNumber++; } else if (options.b) { if (line != "") { - const numberedLines = `${lineNumber} ${line}`; - outputLines.push(numberedLines); - lineNumber++; + process.stdout.write(`${lineNumber} ${line}\n`); + lineNumber++; } else { - outputLines.push(""); + process.stdout.write("\n"); } } else { - outputLines.push(line) + process.stdout.write(line + "\n"); + } } } -process.stdout.write(outputLines.join("\n")); + + + + + + + From ee0d711b463b63ee9a54237b13e3510c8ebd5b4f Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 17:55:18 +0000 Subject: [PATCH 26/83] update the argument in the program info to handle multiple paths --- implement-shell-tools/cat/cat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index d1730ba9..91ec0984 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -5,7 +5,7 @@ import {program} from "commander"; program .name("display-file-content") .description("Output the content of a file to the terminal") - .argument("", "The file path to process") + .argument("", "The file path to process") .option("-n", "Number the output lines") .option("-b","Number the non-blank output lines") From d123b198e5a6da2274cbd27964f1785196bb76d6 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 19:39:09 +0000 Subject: [PATCH 27/83] create ls file to store all the js program logic --- implement-shell-tools/ls/ls.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 implement-shell-tools/ls/ls.js diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js new file mode 100644 index 00000000..e69de29b From cd93e637657e4a1ed9b9a2acedcd53773f305bbe Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 19:43:18 +0000 Subject: [PATCH 28/83] run teminal commands to add package.json since i'll be using import the for commander library --- implement-shell-tools/ls/package-lock.json | 25 ++++++++++++++++++++++ implement-shell-tools/ls/package.json | 16 ++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 implement-shell-tools/ls/package-lock.json create mode 100644 implement-shell-tools/ls/package.json diff --git a/implement-shell-tools/ls/package-lock.json b/implement-shell-tools/ls/package-lock.json new file mode 100644 index 00000000..771b618b --- /dev/null +++ b/implement-shell-tools/ls/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "ls", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ls", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/ls/package.json b/implement-shell-tools/ls/package.json new file mode 100644 index 00000000..4a09815b --- /dev/null +++ b/implement-shell-tools/ls/package.json @@ -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": "commonjs", + "dependencies": { + "commander": "^14.0.2" + } +} From 584666e660189b85ca1f8d0ce9107e8e53670954 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 19:44:38 +0000 Subject: [PATCH 29/83] import built in and third part modules/libraries into the ls.js file --- implement-shell-tools/ls/ls.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index e69de29b..ccb77df6 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,3 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +import { program } from "commander"; From ae56d9b3086477341b92d933b11429e5a30f3d16 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 19:45:52 +0000 Subject: [PATCH 30/83] uodate the type value to "module" so that i could use "import" keyword --- implement-shell-tools/ls/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/package.json b/implement-shell-tools/ls/package.json index 4a09815b..d227aaca 100644 --- a/implement-shell-tools/ls/package.json +++ b/implement-shell-tools/ls/package.json @@ -9,7 +9,7 @@ "keywords": [], "author": "", "license": "ISC", - "type": "commonjs", + "type": "module", "dependencies": { "commander": "^14.0.2" } From 49b4e4be59c3c7b0294a6b830479360e189787ef Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 19:57:28 +0000 Subject: [PATCH 31/83] Initialize program with basic info (name, description, argument & options) --- implement-shell-tools/ls/ls.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index ccb77df6..0da6e43f 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -1,3 +1,10 @@ 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("", "The file path to process") + .option("-1", "Output one entry per line") +// .option("-a", "List all files & directories, including hidden ones"); \ No newline at end of file From 8f7a7e17298a71716d831c5c050a274f82aeed54 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 19:59:14 +0000 Subject: [PATCH 32/83] Add argument parsing for file path --- implement-shell-tools/ls/ls.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 0da6e43f..d7637c70 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -7,4 +7,8 @@ program .description("List all files and directories in a directory") .argument("", "The file path to process") .option("-1", "Output one entry per line") -// .option("-a", "List all files & directories, including hidden ones"); \ No newline at end of file +// .option("-a", "List all files & directories, including hidden ones"); + +program.parse(); + +const path = program.args; \ No newline at end of file From a67234aba64b1f4b486ebdf0c1cca52890965f33 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 20:02:16 +0000 Subject: [PATCH 33/83] sotre program.opts in meaningful var options --- implement-shell-tools/ls/ls.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index d7637c70..4a86fbac 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -11,4 +11,6 @@ program program.parse(); -const path = program.args; \ No newline at end of file +const path = program.args; + +const options = program.opts(); From 385b875c90d9162e65b500d368492ba06a8ff77b Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 20:07:24 +0000 Subject: [PATCH 34/83] path expect one argument /file path --- implement-shell-tools/ls/ls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 4a86fbac..9a9bdff3 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -11,6 +11,6 @@ program program.parse(); -const path = program.args; +const path = program.args[0]; const options = program.opts(); From d5ea768ca49a786c791fa434efda3aff11b581a9 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 20:11:25 +0000 Subject: [PATCH 35/83] directoryContent stores a value that reads the content (files & folder) inside a working direcotry and return the content in an array --- implement-shell-tools/ls/ls.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 9a9bdff3..5fc55e91 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -14,3 +14,7 @@ program.parse(); const path = program.args[0]; const options = program.opts(); + +const directoryContent = await fs.readdir(path); + + From 5adee43738b730f6e9858daa032330f6899a09d2 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 20:25:44 +0000 Subject: [PATCH 36/83] adding a for loop for when -1 option is added to an ls program --- implement-shell-tools/ls/ls.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 5fc55e91..a0855fd6 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -17,4 +17,12 @@ const options = program.opts(); const directoryContent = await fs.readdir(path); +for (const item of directoryContent) { + if (options.one) { + process.stdout.write(item + "\n") + } + } + + + From d84dd4d55c08751190ee00f16e3c212cbed22624 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 20:33:18 +0000 Subject: [PATCH 37/83] update the -1 flag description in the program info part --- implement-shell-tools/ls/ls.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index a0855fd6..36676cd4 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -6,7 +6,7 @@ program .name("list-files-in-directory") .description("List all files and directories in a directory") .argument("", "The file path to process") - .option("-1", "Output one entry per line") + .option("-1, --one", "Output one entry per line") // .option("-a", "List all files & directories, including hidden ones"); program.parse(); @@ -19,8 +19,10 @@ const directoryContent = await fs.readdir(path); for (const item of directoryContent) { if (options.one) { - process.stdout.write(item + "\n") - } + process.stdout.write(item + "\n"); + } else { + process.stdout.write(item); + } } From bd01e5cb6373f201c45ff997eff97cc2c1a55acd Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 20:35:33 +0000 Subject: [PATCH 38/83] add spacing for when ls is used without the -1/--one option --- implement-shell-tools/ls/ls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 36676cd4..5ab156f7 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -21,7 +21,7 @@ for (const item of directoryContent) { if (options.one) { process.stdout.write(item + "\n"); } else { - process.stdout.write(item); + process.stdout.write(item + " "); } } From 83940e04cee2693378b94470461d94e645a4ec2f Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 22:13:57 +0000 Subject: [PATCH 39/83] add option f-a for handling all files - including hidden ones - in the program basic info --- implement-shell-tools/ls/ls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 5ab156f7..65c72192 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -7,7 +7,7 @@ program .description("List all files and directories in a directory") .argument("", "The file path to process") .option("-1, --one", "Output one entry per line") -// .option("-a", "List all files & directories, including hidden ones"); + .option("-a", "List all files & directories, including hidden ones"); program.parse(); From 6943c015652321da36ab29f9cdf6e130498e6bf7 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 22:21:53 +0000 Subject: [PATCH 40/83] logic to filter out hidden files form LS output if -a is not added to it --- implement-shell-tools/ls/ls.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 65c72192..a39115f9 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -17,6 +17,12 @@ const options = program.opts(); const directoryContent = await fs.readdir(path); +let allContent = directoryContent; + +if (!options.a) { + allContent = directoryContent.filter(name => name.startsWith(".")); +} + for (const item of directoryContent) { if (options.one) { process.stdout.write(item + "\n"); From 0ec7440f083515df6789bca031f8d7c71b3d3f63 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 21 Nov 2025 22:27:03 +0000 Subject: [PATCH 41/83] update logic for when option -a not selected --- implement-shell-tools/ls/ls.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index a39115f9..8bb1c496 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -20,10 +20,10 @@ const directoryContent = await fs.readdir(path); let allContent = directoryContent; if (!options.a) { - allContent = directoryContent.filter(name => name.startsWith(".")); + allContent = directoryContent.filter(name => !name.startsWith(".")); } -for (const item of directoryContent) { +for (const item of allContent) { if (options.one) { process.stdout.write(item + "\n"); } else { From 9a639b6491d7af7d026bedc427d5fc8d2319df9a Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 12:28:13 +0000 Subject: [PATCH 42/83] create "wc.js" file to house my programme --- implement-shell-tools/wc/wc.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 implement-shell-tools/wc/wc.js diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js new file mode 100644 index 00000000..e69de29b From 1b2e8ecd7847478f64267454d1b7dd5d0566f6f1 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 12:31:17 +0000 Subject: [PATCH 43/83] initialised npm and installed "Commander" library --- implement-shell-tools/wc/package-lock.json | 25 ++++++++++++++++++++++ implement-shell-tools/wc/package.json | 16 ++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 implement-shell-tools/wc/package-lock.json create mode 100644 implement-shell-tools/wc/package.json diff --git a/implement-shell-tools/wc/package-lock.json b/implement-shell-tools/wc/package-lock.json new file mode 100644 index 00000000..1aff6316 --- /dev/null +++ b/implement-shell-tools/wc/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "wc", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "wc", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +} diff --git a/implement-shell-tools/wc/package.json b/implement-shell-tools/wc/package.json new file mode 100644 index 00000000..070893bc --- /dev/null +++ b/implement-shell-tools/wc/package.json @@ -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": "commonjs", + "dependencies": { + "commander": "^14.0.2" + } +} From bebba1cbd408b77dfa0e5c1bab0e2e08806cb01f Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 12:31:55 +0000 Subject: [PATCH 44/83] update the type property value to "module" in the JSON file --- implement-shell-tools/wc/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/package.json b/implement-shell-tools/wc/package.json index 070893bc..b78a04c9 100644 --- a/implement-shell-tools/wc/package.json +++ b/implement-shell-tools/wc/package.json @@ -9,7 +9,7 @@ "keywords": [], "author": "", "license": "ISC", - "type": "commonjs", + "type": "module", "dependencies": { "commander": "^14.0.2" } From e2ee819984a75afeb40020b72d4e633fccea5ad3 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 12:43:10 +0000 Subject: [PATCH 45/83] import built-in & third party dependancies into the wc.js file --- implement-shell-tools/wc/wc.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index e69de29b..88f6c63c 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,3 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; +import process from "node:process"; From b87db2638bb6a96bd14b949832017b25fcd11ed2 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 12:52:03 +0000 Subject: [PATCH 46/83] set the program basic info and the first option: -l --- implement-shell-tools/wc/wc.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 88f6c63c..1b9d8cb2 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -1,3 +1,9 @@ import { program } from "commander"; import { promises as fs } from "node:fs"; import process from "node:process"; + +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") + .argument("", "The file path to process"); \ No newline at end of file From b291f4ffd2d120fb98478cdfaefaf67926fe21e9 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 12:53:46 +0000 Subject: [PATCH 47/83] interpert the command line argument based on option and ensure that there's an argument in the program --- implement-shell-tools/wc/wc.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 1b9d8cb2..93244fd2 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -6,4 +6,8 @@ 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") - .argument("", "The file path to process"); \ No newline at end of file + .argument("", "The file path to process"); + +program.parse(); + +const argv = program.args; \ No newline at end of file From 0e8d2b979986d32afe9540ed90467deda4b11f20 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 15:12:43 +0000 Subject: [PATCH 48/83] ensuring that excactly one argument passed onto our porgramme --- implement-shell-tools/wc/wc.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 93244fd2..2ad28b9d 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -10,4 +10,11 @@ program program.parse(); -const argv = program.args; \ No newline at end of file +const argv = program.args; + +if (argv.length != 1) { + console.error( + `Expected exactly 1 argument (a path) to be passed but got ${argv.length}.` + ); + process.exit(1); +} \ No newline at end of file From f827bfdc6cae5832adb9bb4060e9679ad9048d93 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 15:15:42 +0000 Subject: [PATCH 49/83] the first (and only) user argument sotred in a variable path --- implement-shell-tools/wc/wc.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 2ad28b9d..8c4ce9a7 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -17,4 +17,6 @@ if (argv.length != 1) { `Expected exactly 1 argument (a path) to be passed but got ${argv.length}.` ); process.exit(1); -} \ No newline at end of file +} + +const path = argv[0]; \ No newline at end of file From 8139354d60b0ddacac490d5867c9eddbe44027e7 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 15:21:46 +0000 Subject: [PATCH 50/83] Add options parsing and directory reading --- implement-shell-tools/wc/wc.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 8c4ce9a7..057a1fb3 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -19,4 +19,8 @@ if (argv.length != 1) { process.exit(1); } -const path = argv[0]; \ No newline at end of file +const path = argv[0]; + +const options = program.opts(); + +const content = await fs.readdir(path); \ No newline at end of file From ee0f23e10ecbaffac06cb7803e1f1561b0539350 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 15:31:36 +0000 Subject: [PATCH 51/83] improt "stat" function from the fs module --- implement-shell-tools/wc/wc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 057a1fb3..87169df2 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -1,6 +1,7 @@ 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") From eb7c00b831fd20571b1bfd72137f481489ed946f Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 15:37:04 +0000 Subject: [PATCH 52/83] use stat function to grap info about the file or directory and store value in a variable called pathInfo --- implement-shell-tools/wc/wc.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 87169df2..ed0a607a 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -24,4 +24,6 @@ const path = argv[0]; const options = program.opts(); -const content = await fs.readdir(path); \ No newline at end of file +const content = await fs.readdir(path); + +const pathInfo = await stat(path); \ No newline at end of file From ee3b4eb58a0573977d77d0de8b6e351149015ab9 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 15:42:30 +0000 Subject: [PATCH 53/83] add if condition to handle 2 cases: 1) path is file or path is dir --- implement-shell-tools/wc/wc.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index ed0a607a..d90f78f7 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -26,4 +26,10 @@ const options = program.opts(); const content = await fs.readdir(path); -const pathInfo = await stat(path); \ No newline at end of file +const pathInfo = await stat(path); + +if (pathInfo.isFile()) { + const fileContent = await fs.readFile(path, "utf-8"); +} else if (pathInfo.isDirectory()) { + const directoryContent = await fs.readdir(path); +} \ No newline at end of file From 62a1c7d7865ebc9f4a6904a2e2786ac3ba4e63c7 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 15:50:01 +0000 Subject: [PATCH 54/83] build a path for each file in a dir and process the file depending on what we want to count: lines, words etc --- implement-shell-tools/wc/wc.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index d90f78f7..766b39f7 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -29,7 +29,11 @@ const content = await fs.readdir(path); const pathInfo = await stat(path); if (pathInfo.isFile()) { - const fileContent = await fs.readFile(path, "utf-8"); + const content = await fs.readFile(path, "utf-8"); } else if (pathInfo.isDirectory()) { - const directoryContent = await fs.readdir(path); + const files = await fs.readdir(path); + for (const file of files) { + const filePath = `${path}/${file}`; + const fileContent = await fs.readFile(filePath, "utf-8"); + } } \ No newline at end of file From d4644e181d11a85233b725156e37a3a64175ebdc Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 16:59:47 +0000 Subject: [PATCH 55/83] create a function to count lines --- implement-shell-tools/wc/wc.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 766b39f7..ce330a53 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -36,4 +36,8 @@ if (pathInfo.isFile()) { const filePath = `${path}/${file}`; const fileContent = await fs.readFile(filePath, "utf-8"); } +} + +function counter(item) { + const lines = item.split("\n"); } \ No newline at end of file From b51271ef0459e5471930a82b4bbffec8d76c96c0 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:01:27 +0000 Subject: [PATCH 56/83] include word counting functionality in the function counter --- implement-shell-tools/wc/wc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index ce330a53..289add4e 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -40,4 +40,5 @@ if (pathInfo.isFile()) { function counter(item) { const lines = item.split("\n"); + const words = item,split(/\s+/).filter(Boolean).length; } \ No newline at end of file From e9dc04ecbb11164d5cadbff71ca0334e33247a54 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:02:52 +0000 Subject: [PATCH 57/83] make the function counter characters too --- implement-shell-tools/wc/wc.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 289add4e..9a2ae76d 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -40,5 +40,6 @@ if (pathInfo.isFile()) { function counter(item) { const lines = item.split("\n"); - const words = item,split(/\s+/).filter(Boolean).length; + const words = item.split(/\s+/).filter(Boolean).length; + const characters = item.length; } \ No newline at end of file From fbb3e4e47977c1e364a4640ecfb2024a149bca5d Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:03:26 +0000 Subject: [PATCH 58/83] add return values inside the function --- implement-shell-tools/wc/wc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 9a2ae76d..a8425979 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -42,4 +42,5 @@ function counter(item) { const lines = item.split("\n"); const words = item.split(/\s+/).filter(Boolean).length; const characters = item.length; + return {lines, words, characters}; } \ No newline at end of file From 2af49681c61c62d4a0deb77d6644d6cfe289a95c Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:05:59 +0000 Subject: [PATCH 59/83] add the function counter the inside if condition for the case of dealing with single file --- implement-shell-tools/wc/wc.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index a8425979..c17482bf 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -28,8 +28,16 @@ const content = await fs.readdir(path); const pathInfo = await stat(path); +function counter(item) { + const lines = item.split("\n"); + const words = item.split(/\s+/).filter(Boolean).length; + const characters = item.length; + return { lines, words, characters }; +} + if (pathInfo.isFile()) { const content = await fs.readFile(path, "utf-8"); + const stats = counter(content); } else if (pathInfo.isDirectory()) { const files = await fs.readdir(path); for (const file of files) { @@ -38,9 +46,3 @@ if (pathInfo.isFile()) { } } -function counter(item) { - const lines = item.split("\n"); - const words = item.split(/\s+/).filter(Boolean).length; - const characters = item.length; - return {lines, words, characters}; -} \ No newline at end of file From 87768a152711e99eb42ca9a1c1945a432ff13ee2 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:10:51 +0000 Subject: [PATCH 60/83] update if block to handle when -l option logic for when it's added to the program by end user --- implement-shell-tools/wc/wc.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index c17482bf..e5622147 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -38,6 +38,11 @@ function counter(item) { if (pathInfo.isFile()) { const content = await fs.readFile(path, "utf-8"); const stats = counter(content); + if (options.line) { + console.log(`${stats.lines} ${path}`); + } else { + console.log(`${stats.lines} ${stats.words} ${stats.chars} ${path}`); + } } else if (pathInfo.isDirectory()) { const files = await fs.readdir(path); for (const file of files) { From 41967514887f58db483a4cc5853094878942b7e0 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:15:01 +0000 Subject: [PATCH 61/83] remove the buggy line --- implement-shell-tools/wc/wc.js | 1 - 1 file changed, 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index e5622147..194d6d22 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -24,7 +24,6 @@ const path = argv[0]; const options = program.opts(); -const content = await fs.readdir(path); const pathInfo = await stat(path); From 5cbefa1599b95a1cebfc455dc48202ce0635d913 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:16:26 +0000 Subject: [PATCH 62/83] update the function so that it returns the numebr of lines rather than a full array with items in it --- implement-shell-tools/wc/wc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 194d6d22..4eb91e0b 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -28,7 +28,7 @@ const options = program.opts(); const pathInfo = await stat(path); function counter(item) { - const lines = item.split("\n"); + const lines = item.split("\n").length; const words = item.split(/\s+/).filter(Boolean).length; const characters = item.length; return { lines, words, characters }; From 03d9fb648de617cfa75c2545c70dbab43aafeec4 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 17:20:11 +0000 Subject: [PATCH 63/83] adding .trim() method to get rid of the spaces (not counting blank lines) and get the exact number of lines --- implement-shell-tools/wc/wc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 4eb91e0b..e6fe58ca 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -28,7 +28,7 @@ const options = program.opts(); const pathInfo = await stat(path); function counter(item) { - const lines = item.split("\n").length; + const lines = item.trim().split("\n").length; const words = item.split(/\s+/).filter(Boolean).length; const characters = item.length; return { lines, words, characters }; From 091692cd6bf42dc79adae718385c3015d264d313 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 18:13:09 +0000 Subject: [PATCH 64/83] add a function for the logic for when the case of the path is "dir" --- implement-shell-tools/wc/wc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index e6fe58ca..9e130b30 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -47,6 +47,7 @@ if (pathInfo.isFile()) { for (const file of files) { const filePath = `${path}/${file}`; const fileContent = await fs.readFile(filePath, "utf-8"); + const stats = counter(fileContent) } } From c6aa7ae34d8ac5a9ae6ab02812eec7a1d70d645d Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 18:15:47 +0000 Subject: [PATCH 65/83] for dir case: create logic to handdle when -l option is added to the prgoram --- implement-shell-tools/wc/wc.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 9e130b30..1d04a05d 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -47,7 +47,13 @@ if (pathInfo.isFile()) { for (const file of files) { const filePath = `${path}/${file}`; const fileContent = await fs.readFile(filePath, "utf-8"); - const stats = counter(fileContent) + const stats = counter(fileContent); + + if (options.line) { + console.log(`${stats.lines} ${filePath}`); + } else { + console.log(`${stats.lines} ${stats.words} ${stats.chars} ${fileContent}`); + } } } From 524af1d88d2e1ef2a7d30772bfcbfef32a82932c Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 18:16:20 +0000 Subject: [PATCH 66/83] update the error in the else for dir --- implement-shell-tools/wc/wc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 1d04a05d..9e593ae4 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -52,7 +52,7 @@ if (pathInfo.isFile()) { if (options.line) { console.log(`${stats.lines} ${filePath}`); } else { - console.log(`${stats.lines} ${stats.words} ${stats.chars} ${fileContent}`); + console.log(`${stats.lines} ${stats.words} ${stats.chars} ${filePath}`); } } } From 46c5df5c518bb0e8b6960dad1f95e4fb9873331a Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 18:20:50 +0000 Subject: [PATCH 67/83] update bugy lines of code --- implement-shell-tools/wc/wc.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 9e593ae4..651f5a23 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -7,7 +7,7 @@ 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") - .argument("", "The file path to process"); + .argument("", "The file path to process"); program.parse(); @@ -40,7 +40,7 @@ if (pathInfo.isFile()) { if (options.line) { console.log(`${stats.lines} ${path}`); } else { - console.log(`${stats.lines} ${stats.words} ${stats.chars} ${path}`); + console.log(`${stats.lines} ${stats.words} ${stats.characters} ${path}`); } } else if (pathInfo.isDirectory()) { const files = await fs.readdir(path); @@ -52,7 +52,7 @@ if (pathInfo.isFile()) { if (options.line) { console.log(`${stats.lines} ${filePath}`); } else { - console.log(`${stats.lines} ${stats.words} ${stats.chars} ${filePath}`); + console.log(`${stats.lines} ${stats.words} ${stats.characters} ${filePath}`); } } } From c58db9c9075cc7aa5e5e45154ea3248655748c20 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 18:23:07 +0000 Subject: [PATCH 68/83] remove the validation for if we have multiple arguments as this clashes when handle wc for a directory with mutiple files --- implement-shell-tools/wc/wc.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 651f5a23..ecf013b6 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -13,12 +13,7 @@ program.parse(); const argv = program.args; -if (argv.length != 1) { - console.error( - `Expected exactly 1 argument (a path) to be passed but got ${argv.length}.` - ); - process.exit(1); -} + const path = argv[0]; From eb67a848e44e0a5a8cece2cbb33cf2bc659460f3 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 18:29:00 +0000 Subject: [PATCH 69/83] update logic to handl having mutple paths (files) when dealing with a dir --- implement-shell-tools/wc/wc.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index ecf013b6..60987921 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -14,13 +14,16 @@ program.parse(); const argv = program.args; - const path = argv[0]; const options = program.opts(); -const pathInfo = await stat(path); + +if (argv.length < 1) { + console.error("You must pass at least one path!"); + process.exit(1); +} function counter(item) { const lines = item.trim().split("\n").length; @@ -29,6 +32,9 @@ function counter(item) { return { lines, words, characters }; } +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); @@ -52,3 +58,4 @@ if (pathInfo.isFile()) { } } +} \ No newline at end of file From 8a546e1fc7978ff73d4eba819d3fd89e1cb813a0 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 22:09:55 +0000 Subject: [PATCH 70/83] add counters for total lines, words & characters for when the path is either a file or a dir --- implement-shell-tools/wc/wc.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 60987921..36982562 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -13,13 +13,11 @@ program.parse(); const argv = program.args; - const path = argv[0]; const options = program.opts(); - if (argv.length < 1) { console.error("You must pass at least one path!"); process.exit(1); @@ -32,6 +30,11 @@ function counter(item) { 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); @@ -43,6 +46,12 @@ if (pathInfo.isFile()) { } 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) { @@ -55,6 +64,11 @@ if (pathInfo.isFile()) { } else { console.log(`${stats.lines} ${stats.words} ${stats.characters} ${filePath}`); } + + totalLines += stats.lines; + totalWords += stats.words; + totalCharacters += stats.characters; + fileCount++; } } From ec4de6a7a3fb7bd54a7a79d8fe4dd83c61b6a29d Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 22:12:00 +0000 Subject: [PATCH 71/83] for the case of a dire print the total coutner --- implement-shell-tools/wc/wc.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 36982562..9c06d0a3 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -72,4 +72,12 @@ if (pathInfo.isFile()) { } } +} + +if (fileCount > 1) { + if (options.line) { + console.log(`${totalLines} total`); + } else { + console.log(`${totalLines} ${totalWords} ${totalCharacters} total`); + } } \ No newline at end of file From 009c40b82d2abf95f16640d6bba200d166028d34 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 22:16:29 +0000 Subject: [PATCH 72/83] add -w option in the program basic info --- implement-shell-tools/wc/wc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 9c06d0a3..6aaba2ec 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -7,6 +7,7 @@ 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") .argument("", "The file path to process"); program.parse(); From c32410a2655cd434ae0e7ba78be9953f36daef6a Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 22:23:10 +0000 Subject: [PATCH 73/83] flesh out logic to include the -w & -c options --- implement-shell-tools/wc/wc.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 6aaba2ec..9d4ed1b1 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -8,6 +8,7 @@ program .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("", "The file path to process"); program.parse(); @@ -44,8 +45,10 @@ if (pathInfo.isFile()) { const stats = counter(content); if (options.line) { console.log(`${stats.lines} ${path}`); + } else if (options.word) { + console.log(`${stats.words} ${path}`); } else { - console.log(`${stats.lines} ${stats.words} ${stats.characters} ${path}`); + console.log(`${stats.characters} ${path}`); } totalLines += stats.lines; @@ -62,8 +65,10 @@ if (pathInfo.isFile()) { if (options.line) { console.log(`${stats.lines} ${filePath}`); + } else if (options.word) { + console.log(`${stats.words} ${filePath}`); } else { - console.log(`${stats.lines} ${stats.words} ${stats.characters} ${filePath}`); + console.log(`${stats.characters} ${filePath}`); } totalLines += stats.lines; @@ -78,7 +83,9 @@ if (pathInfo.isFile()) { if (fileCount > 1) { if (options.line) { console.log(`${totalLines} total`); + } else if (options.word) { + console.log(`${totalWords} total`); } else { - console.log(`${totalLines} ${totalWords} ${totalCharacters} total`); + console.log(`${totalCharacters} total`); } } \ No newline at end of file From 3cc8aaf31a244548f504279920333fbff1984500 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 22:33:56 +0000 Subject: [PATCH 74/83] code now handles no flag cases for all scenarios (file or dir) --- implement-shell-tools/wc/wc.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 9d4ed1b1..19c647f4 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -47,8 +47,10 @@ if (pathInfo.isFile()) { console.log(`${stats.lines} ${path}`); } else if (options.word) { console.log(`${stats.words} ${path}`); - } else { + } else if (options.character) { console.log(`${stats.characters} ${path}`); + } else { + console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); } totalLines += stats.lines; @@ -67,8 +69,10 @@ if (pathInfo.isFile()) { 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.characters} ${filePath}`); + console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); } totalLines += stats.lines; @@ -85,7 +89,9 @@ if (fileCount > 1) { console.log(`${totalLines} total`); } else if (options.word) { console.log(`${totalWords} total`); - } else { + } else if (options.character) { console.log(`${totalCharacters} total`); + } else { + console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); } } \ No newline at end of file From 397d4e060de73ef3003c20577b3c9e6a2df1a190 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 22:52:15 +0000 Subject: [PATCH 75/83] update logic to match the wc command line in the way it displays output --- implement-shell-tools/wc/wc.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 19c647f4..33677815 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -44,11 +44,11 @@ if (pathInfo.isFile()) { const content = await fs.readFile(path, "utf-8"); const stats = counter(content); if (options.line) { - console.log(`${stats.lines} ${path}`); + console.log(` ${stats.lines} ${path}`); } else if (options.word) { - console.log(`${stats.words} ${path}`); + console.log(` ${stats.words} ${path}`); } else if (options.character) { - console.log(`${stats.characters} ${path}`); + console.log(` ${stats.characters} ${path}`); } else { console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); } @@ -66,11 +66,11 @@ if (pathInfo.isFile()) { const stats = counter(fileContent); if (options.line) { - console.log(`${stats.lines} ${filePath}`); + console.log(` ${stats.lines} ${filePath}`); } else if (options.word) { - console.log(`${stats.words} ${filePath}`); + console.log(` ${stats.words} ${filePath}`); } else if (options.character) { - console.log(`${stats.characters} ${filePath}`); + console.log(` ${stats.characters} ${filePath}`); } else { console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); } @@ -86,12 +86,12 @@ if (pathInfo.isFile()) { if (fileCount > 1) { if (options.line) { - console.log(`${totalLines} total`); + console.log(` ${totalLines}`); } else if (options.word) { - console.log(`${totalWords} total`); + console.log(` ${totalWords}`); } else if (options.character) { - console.log(`${totalCharacters} total`); + console.log(` ${totalCharacters}`); } else { - console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); + console.log(` ${totalLines} ${totalWords} ${totalCharacters}`); } } \ No newline at end of file From e15567215172f45940f94e53095f387a106d02a1 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 23:02:17 +0000 Subject: [PATCH 76/83] house keeping --- implement-shell-tools/wc/wc.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 33677815..cbf6e972 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -44,13 +44,13 @@ if (pathInfo.isFile()) { const content = await fs.readFile(path, "utf-8"); const stats = counter(content); if (options.line) { - console.log(` ${stats.lines} ${path}`); + console.log(`${stats.lines} ${path}`); } else if (options.word) { - console.log(` ${stats.words} ${path}`); + console.log(`${stats.words} ${path}`); } else if (options.character) { - console.log(` ${stats.characters} ${path}`); + console.log(`${stats.characters} ${path}`); } else { - console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); + console.log(`${stats.lines} ${stats.words} ${stats.characters} ${path}`); } totalLines += stats.lines; @@ -66,13 +66,13 @@ if (pathInfo.isFile()) { const stats = counter(fileContent); if (options.line) { - console.log(` ${stats.lines} ${filePath}`); + console.log(`${stats.lines} ${filePath}`); } else if (options.word) { - console.log(` ${stats.words} ${filePath}`); + console.log(`${stats.words} ${filePath}`); } else if (options.character) { - console.log(` ${stats.characters} ${filePath}`); + console.log(`${stats.characters} ${filePath}`); } else { - console.log(` ${stats.lines} ${stats.words} ${stats.characters} ${path}`); + console.log(`${stats.lines} ${stats.words} ${stats.characters} ${path}`); } totalLines += stats.lines; @@ -86,12 +86,12 @@ if (pathInfo.isFile()) { if (fileCount > 1) { if (options.line) { - console.log(` ${totalLines}`); + console.log(`${totalLines} total`); } else if (options.word) { - console.log(` ${totalWords}`); + console.log(`${totalWords} total`); } else if (options.character) { - console.log(` ${totalCharacters}`); + console.log(`${totalCharacters} total`); } else { - console.log(` ${totalLines} ${totalWords} ${totalCharacters}`); + console.log(`${totalLines} ${totalWords} ${totalCharacters} total`); } } \ No newline at end of file From d2daa0ecf22d2602e4ebab71095ea420d7a0d7ae Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Mon, 24 Nov 2025 23:09:41 +0000 Subject: [PATCH 77/83] remove redantant and repetitive code --- implement-shell-tools/wc/wc.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index cbf6e972..67dae674 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -15,16 +15,9 @@ program.parse(); const argv = program.args; -const path = argv[0]; - const options = program.opts(); -if (argv.length < 1) { - console.error("You must pass at least one path!"); - process.exit(1); -} - function counter(item) { const lines = item.trim().split("\n").length; const words = item.split(/\s+/).filter(Boolean).length; @@ -72,7 +65,7 @@ if (pathInfo.isFile()) { } else if (options.character) { console.log(`${stats.characters} ${filePath}`); } else { - console.log(`${stats.lines} ${stats.words} ${stats.characters} ${path}`); + console.log(`${stats.lines} ${stats.words} ${stats.characters} ${filePath}`); } totalLines += stats.lines; From 4fdb35714116562ebd5e70f1faa25052d55e4eb3 Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 9 Jan 2026 20:35:49 +0000 Subject: [PATCH 78/83] validating the path first --- implement-shell-tools/ls/ls.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 8bb1c496..2b1e5f55 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -15,6 +15,11 @@ const path = program.args[0]; const options = program.opts(); +if (!path) { + console.error("Error: No directory path was provided."); + process.exit(1); +} + const directoryContent = await fs.readdir(path); let allContent = directoryContent; From b2563c1951fefe1a62b4df17504e54f99528724c Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 9 Jan 2026 20:39:27 +0000 Subject: [PATCH 79/83] add try-catch code block --- implement-shell-tools/ls/ls.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 2b1e5f55..5c717c96 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -20,7 +20,14 @@ if (!path) { process.exit(1); } -const directoryContent = await fs.readdir(path); +const directoryContent; + +try { + directoryContent = await fs.readdir(path); +} catch (err) { + console.error(`Error reading directory: ${err.message}`); + process.exit(1); +} let allContent = directoryContent; From b5866c562661f2f04ba2c32b3c3ff48d053d489a Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 9 Jan 2026 20:40:52 +0000 Subject: [PATCH 80/83] change change variable keryword assignemnt for from cosnt to let --- implement-shell-tools/ls/ls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 5c717c96..d31d971b 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -20,7 +20,7 @@ if (!path) { process.exit(1); } -const directoryContent; +let directoryContent; try { directoryContent = await fs.readdir(path); From 0e4e1c2974ab1536462a3fe96101968d9eee350d Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 23 Jan 2026 18:22:36 +0000 Subject: [PATCH 81/83] being economical by having 1 package.json for all wc, cat and ls to access rather than each one having their own package.json --- implement-shell-tools/ls/package-lock.json | 25 ------------------- implement-shell-tools/ls/package.json | 16 ------------ .../{cat => }/package-lock.json | 0 implement-shell-tools/{cat => }/package.json | 0 implement-shell-tools/wc/package-lock.json | 25 ------------------- implement-shell-tools/wc/package.json | 16 ------------ 6 files changed, 82 deletions(-) delete mode 100644 implement-shell-tools/ls/package-lock.json delete mode 100644 implement-shell-tools/ls/package.json rename implement-shell-tools/{cat => }/package-lock.json (100%) rename implement-shell-tools/{cat => }/package.json (100%) delete mode 100644 implement-shell-tools/wc/package-lock.json delete mode 100644 implement-shell-tools/wc/package.json diff --git a/implement-shell-tools/ls/package-lock.json b/implement-shell-tools/ls/package-lock.json deleted file mode 100644 index 771b618b..00000000 --- a/implement-shell-tools/ls/package-lock.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "ls", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "ls", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "commander": "^14.0.2" - } - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "license": "MIT", - "engines": { - "node": ">=20" - } - } - } -} diff --git a/implement-shell-tools/ls/package.json b/implement-shell-tools/ls/package.json deleted file mode 100644 index d227aaca..00000000 --- a/implement-shell-tools/ls/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "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" - } -} diff --git a/implement-shell-tools/cat/package-lock.json b/implement-shell-tools/package-lock.json similarity index 100% rename from implement-shell-tools/cat/package-lock.json rename to implement-shell-tools/package-lock.json diff --git a/implement-shell-tools/cat/package.json b/implement-shell-tools/package.json similarity index 100% rename from implement-shell-tools/cat/package.json rename to implement-shell-tools/package.json diff --git a/implement-shell-tools/wc/package-lock.json b/implement-shell-tools/wc/package-lock.json deleted file mode 100644 index 1aff6316..00000000 --- a/implement-shell-tools/wc/package-lock.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "wc", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "wc", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "commander": "^14.0.2" - } - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "license": "MIT", - "engines": { - "node": ">=20" - } - } - } -} diff --git a/implement-shell-tools/wc/package.json b/implement-shell-tools/wc/package.json deleted file mode 100644 index b78a04c9..00000000 --- a/implement-shell-tools/wc/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "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" - } -} From 6098ccbbce7af2f2a484d12f013c7dcb85045faf Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 23 Jan 2026 18:31:59 +0000 Subject: [PATCH 82/83] 1.update package.json to acommodate all 3 folders (cat, wc &ls) 2. get rid of package-lock.json since a new one can be generated --- implement-shell-tools/package-lock.json | 25 ------------------------- implement-shell-tools/package.json | 12 ++++++++---- 2 files changed, 8 insertions(+), 29 deletions(-) delete mode 100644 implement-shell-tools/package-lock.json diff --git a/implement-shell-tools/package-lock.json b/implement-shell-tools/package-lock.json deleted file mode 100644 index 9ca092a6..00000000 --- a/implement-shell-tools/package-lock.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "cat", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "cat", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "commander": "^14.0.2" - } - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "license": "MIT", - "engines": { - "node": ">=20" - } - } - } -} diff --git a/implement-shell-tools/package.json b/implement-shell-tools/package.json index a6653b6b..368302bf 100644 --- a/implement-shell-tools/package.json +++ b/implement-shell-tools/package.json @@ -1,13 +1,17 @@ { - "name": "cat", + "name": "shell-command-tools-implementation", "version": "1.0.0", - "description": "You should already be familiar with the `cat` command line tool.", - "main": "cat.js", + "description": "JavaScript implementations of common shell command-line tools including cat, ls, and wc.", + "bin": { + "cat": "./cat/index.js", + "ls": "./ls/index.js", + "wc": "./wc/index.js" + }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], - "author": "", + "author": "Hassan O.", "license": "ISC", "type": "module", "dependencies": { From 4cdc48322b4996be5fb31b5d3d3648918a15f2ec Mon Sep 17 00:00:00 2001 From: HassanOHOsman Date: Fri, 23 Jan 2026 18:33:08 +0000 Subject: [PATCH 83/83] generate a new package-lock.josn based on the updated package.json by running npm install --- implement-shell-tools/package-lock.json | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 implement-shell-tools/package-lock.json diff --git a/implement-shell-tools/package-lock.json b/implement-shell-tools/package-lock.json new file mode 100644 index 00000000..115d541c --- /dev/null +++ b/implement-shell-tools/package-lock.json @@ -0,0 +1,30 @@ +{ + "name": "shell-command-tools-implementation", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "shell-command-tools-implementation", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^14.0.2" + }, + "bin": { + "cat": "cat/index.js", + "ls": "ls/index.js", + "wc": "wc/index.js" + } + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + } + } +}