Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

London| Elhadj Abdoul Diallo| Module-Tools | WEEK3 - Implement-shell-tools #25

Open
wants to merge 46 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
f5382f7
Add implementation for cat shell tool
Mar 3, 2025
cfa60fe
Refactor cat implementation to support reading multiple files asynchr…
Mar 3, 2025
48355e1
Implement display function to output contents of the files
Mar 3, 2025
16944c0
Fix variable name for file paths in cat implementation
Mar 3, 2025
677386b
Add package.json and package-lock.json for dependency management
Mar 3, 2025
2fc1242
Enhance cat implementation with command-line options for line numberi…
Mar 3, 2025
6c5e0c7
Refactor readFiles and displayFileContents functions to flatten outpu…
Mar 3, 2025
fe03c76
Fix readFiles function to remove trailing empty lines from file contents
Mar 3, 2025
9fb84ad
Refactor readFiles function to use extractLinesFromContent for improv…
Mar 3, 2025
2150905
Add option to number non-empty lines in cat implementation
Mar 3, 2025
2376e64
Update readFiles function to use object syntax for fs.readFile encodi…
Mar 3, 2025
24ceb1c
Implement ls command with options for single line output
Mar 3, 2025
d823cbe
Enhance ls command to accept multiple paths as arguments
Mar 3, 2025
97647ec
Add option to include hidden files in ls command
Mar 3, 2025
5cc3cac
Add option to display current and parent directories when including h…
Mar 3, 2025
6fe4d34
Remove unnecessary await from displayFileContents function call
Mar 3, 2025
80b1b24
Fix comment wording in extractLinesFromContent function for clarity
Mar 3, 2025
aee2490
Enhance documentation for implementLs function to clarify parameters …
Mar 3, 2025
cf568a4
Add wc command implementation to count lines, words, and characters i…
Mar 4, 2025
bad7699
Refactor wc command to handle multiple files and return line, word, a…
Mar 4, 2025
d8f858b
Refactor wc command to handle empty lines correctly and improve word …
Mar 4, 2025
1239f5f
Fix line count calculation in createLineWordsCharCountForFile function
Mar 4, 2025
0021d1e
Add aggregation of line, word, and character counts for multiple file…
Mar 4, 2025
5b3d5c9
Improve aggregation logic in wc command to handle single file cases
Mar 4, 2025
2b16d73
Refactor wc command to use commander for argument parsing
Mar 4, 2025
9ddebf4
Add line count option to wc command
Mar 4, 2025
e5ccf82
Add character count option to wc command
Mar 4, 2025
da2ec96
Add word count option to wc command
Mar 4, 2025
ea33cfd
Fix output logic in wc command to display total count when line optio…
Mar 4, 2025
cd2a6de
Update wc command to conditionally display total count for word option
Mar 4, 2025
3ffac88
Refactor wc command output logic to handle character option and displ…
Mar 4, 2025
8b23d95
Refactor output logic in wc command to use a helper function for form…
Mar 4, 2025
0e6ac90
Refactor output logic in wc command to inline option formatting
Mar 4, 2025
22fda0d
Rename function to count lines, words, and characters in file for cla…
Mar 4, 2025
f0b5293
Rename variables for clarity in line, word, and character counts in w…
Mar 4, 2025
8444b86
Rename function to improve clarity in file processing and output display
Mar 4, 2025
3d9756b
Refactor processFilesAndDisplayCounts to improve variable naming for …
Mar 4, 2025
c5e2b07
Add JSDoc comments to aggregateFileData function for improved documen…
Mar 4, 2025
faece38
rename file name to cat.js
Mar 4, 2025
b8fc18f
rename file name to ls.js
Mar 4, 2025
522e254
Refactor cat.js to streamline file reading and line display logic
Mar 5, 2025
e53d221
Rename variables for clarity and update function to print file conten…
Mar 5, 2025
19ed271
Refactor printFileWithLineNumbers function to improve line number han…
Mar 5, 2025
1517657
Rename options for line number handling in printFileWithLineNumbers f…
Mar 5, 2025
6aea96c
Refactor cat.js to rename and separate file reading and line printing…
Mar 5, 2025
7c4ca2a
Refactor ls.js to encapsulate directory listing logic in a dedicated …
Mar 5, 2025
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
55 changes: 55 additions & 0 deletions implement-shell-tools/cat/cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { promises as fs, read } from "node:fs";
import process from "node:process";
import { program } from "commander";

program
.name("Implement cat")
.description("Implement a version of the cat program")
.option("-n, --number", "Number the output lines, starting at 1")
.option("-b, --number2", "Number the nonempty lines, starting at 1")
.argument("<paths...>", "The file paths to process")
.parse(process.argv);

let args = program.args;

const nOption = program.opts().number;
const bOption = program.opts().number2;
let lineNumber = 1;

async function readAndPrintFileContent(path) {
try {
const content = await fs.readFile(path, { encoding: "utf-8" });
const lines = extractLinesFromContent(content);
printLinesWithOptions(lines);
} catch (err) {
console.error(err.message);
}
}

function extractLinesFromContent(content) {
const lines = content.split("\n");
if (lines[lines.length - 1] === "") {
lines.pop(); // excludes last line if empty
}
return lines;
}

function printLinesWithOptions(lines) {
lines.forEach((line) => {
if (nOption) {
console.log(`${lineNumber++} ${line}`);
return;
}

if (bOption) {
if (line !== "") {
console.log(`${lineNumber++} ${line}`);
return;
}
}

console.log(line);
});
}
// display file/s contents with line numbers.
await Promise.all(args.map(readAndPrintFileContent));
47 changes: 47 additions & 0 deletions implement-shell-tools/ls/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Reads the contents of the specified directories and outputs the file names.
* Supports options for displaying hidden files and listing each file on a new line.
*
* @param {string[]} filePaths - The paths to be processed. Defaults to the current directory if no argument is provided.
* @param {boolean} one - If true, outputs each file and directory on a new line.
* @param {boolean} hidden - If true, includes hidden files and directories in the output.
*/
import process from "node:process";
import { promises as fs } from "node:fs";
import { program } from "commander";

program
.name("Implement ls")
.description("Implements a version of the ls command")
.option("-1, --one", "Output all files and directories each in a line")
.option("-a, --hidden", "Output hidden files/directories")
.argument("[paths...]", "the paths to be processed")
.parse(process.argv);

const filePaths = program.args.length ? program.args : ["."];

const one = program.opts().one;
const hidden = program.opts().hidden;

async function listDirectoryContents(filePath) {
try {
const files = await fs.readdir(filePath, { withFileTypes: true }); // is returned as a Dirent
const filteredFiles = files
.filter((file) => hidden || !file.name.startsWith("."))
.map((file) => file.name);

if (hidden) {
filteredFiles.unshift(".", "..");
}

if (one) {
filteredFiles.forEach((file) => console.log(file));
} else {
console.log(filteredFiles.join(" "));
}
} catch (err) {
console.error(`Error reading directory ${filePath}:`, err.message);
}
}

filePaths.map(listDirectoryContents);
103 changes: 103 additions & 0 deletions implement-shell-tools/wc/wc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { program } from "commander";
import process from "node:process";
import { promises as fs } from "node:fs";

program
.name("Implement wc")
.description("Implements a version of the wc command")
.option("-l, --line", "Counts file lines")
.option("-c, --char", "Counts characters in file")
.option("-w, --word", "Counts words in file")
.argument("[paths...]", "The path/s to process")
.parse(process.argv);

const args = program.args;

function removeEndEmptyLine(arr) {
return arr[arr.length - 1] === "" ? arr.slice(0, -1) : arr;
}

const lineOption = program.opts().line;
const charOption = program.opts().char;
const wordOption = program.opts().word;

async function countLinesWordsCharsInFile(path) {
const content = await fs.readFile(path, { encoding: "utf-8" });

const lines = removeEndEmptyLine(content.split("\n"));

const words = lines.flatMap((element) =>
element.split(" ").filter((word) => word !== "")
);

const chars = content.split("");

const numberOfLines = lines.length;
const numberOfWords = words.length;
const numberOFChars = chars.length;

if (lineOption) {
return `${numberOfLines} ${path}`;
}

if (charOption) {
return `${numberOFChars} ${path}`;
}

if (wordOption) {
return `${numberOfWords} ${path}`;
}

return `${numberOfLines} ${numberOfWords} ${numberOFChars} ${path}`;
}

async function processFilesAndDisplayCounts() {
const fileCounts = await Promise.all(args.map(countLinesWordsCharsInFile));
fileCounts.forEach((fileCount) => console.log(fileCount));

const aggregatedFilesData = aggregateFileData(fileCounts);

if (aggregatedFilesData !== 0 && lineOption) {
console.log(`${aggregatedFilesData[0]} total`);
return;
}

if (aggregatedFilesData !== 0 && wordOption) {
console.log(`${aggregatedFilesData[0]} total`);
return;
}

if (aggregatedFilesData !== 0 && charOption) {
console.log(`${aggregatedFilesData[0]} total`);
return;
}

aggregatedFilesData !== 0
? console.log(
`${aggregatedFilesData[0]} ${aggregatedFilesData[1]} ${aggregatedFilesData[2]} total`
)
: null;
}

/**
* Aggregates numerical data from an array of file content strings.
*
* @param {string[]} files - An array of strings, each representing the content of a file.
* Each string should contain space-separated numbers.
* @returns {number[]|number} - An array of sums for each column of numbers if there are multiple files,
* or 0 if there is only one file.
*/
function aggregateFileData(fileCounts) {
const digits = fileCounts.map((element) =>
element.split(" ").slice(0, -1).map(Number)
);
const sums =
digits.length > 1
? digits[0].map((_, colIndex) =>
digits.reduce((sum, row) => sum + row[colIndex], 0)
)
: 0;
return sums;
}

processFilesAndDisplayCounts();
21 changes: 21 additions & 0 deletions package-lock.json

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

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "module",
"dependencies": {
"commander": "^13.1.0"
}
}