From 83c381cd9bd294a745ff7af0bde35436a8ac7736 Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Fri, 21 Nov 2025 12:03:49 +0000 Subject: [PATCH 01/10] Implement 'cat' command alternative with line numbering options --- implement-shell-tools/cat/cat.js | 64 ++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) 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..827ab94f --- /dev/null +++ b/implement-shell-tools/cat/cat.js @@ -0,0 +1,64 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; +import process from "node:process"; + +// configure the CLI program with its name, description, arguments, options, and actions (the help instructions) +program + .name("cat") + .description("An alternative to the 'cat' command") + .argument("", "The file(s) to process") + .option("-n, --number", "Number all output lines") + .option("-b, --number-nonblank", "Number non-blank output lines") + // actions to process the provided files with the specified options (-n, -b) + .action(async (files, options) => { + try { + // call newCat for all files + await newCat(files, options.number, options.numberNonblank) + } catch (err) { + console.error(`Error: ${err.message}`); + } + }); + +// parse command-line file arguments using the process.argv array +program.parse(process.argv); + + +async function newCat(files, numberLines, numberNonBlank) { + let lineNumber = 1; + + for (const file of files) { + // read each file into a single text string + try { + const data = await fs.readFile(file, "utf8"); + // split that string into an array at \n where each element is a line from the file + // e.g. lines = ["Line 1", "Line 2", "Line 3"] + const lines = data.split("\n") + + // remove trailing blank line caused by a trailing newline + if (lines[lines.length - 1] === "") { + lines.pop(); + } + + for (const line of lines) { + if (numberNonBlank) { + // check what is left on the line after trimming (truthy = text, falsy = blank) + if (line.trim()) { + console.log(`${lineNumber.toString().padStart(6, ' ')} ${line}`); + lineNumber++ + } else { + console.log(line) + } + } else if (numberLines) { + // number all lines + console.log(`${lineNumber.toString().padStart(6, ' ')} ${line}`); + lineNumber++ + } else { + // if neither flag print normally + console.log(line) + } + } + } catch (err) { + console.error(`Error reading file ${file}: ${err.message}`); + } + } +} \ No newline at end of file From 37077633ee1aaca7d7bb34f4e0e4bd1040a2a57c Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Fri, 21 Nov 2025 21:07:56 +0000 Subject: [PATCH 02/10] Implement 'ls' command alternative with directory listing options --- implement-shell-tools/ls/ls.js | 83 ++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) 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..bf89d6e2 --- /dev/null +++ b/implement-shell-tools/ls/ls.js @@ -0,0 +1,83 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; +import process from "node:process"; + +// configure the CLI program with its name, description, arguments, options, and actions (the help instructions) +program + .name("ls") + .description("An alternative to the 'ls' command") + .argument("[directory]", "The directory to list") + // Commander stores -1 as a string key that is accessed using options['1'] + .option("-1", "List all files, one per line") + .option("-a, --all", "Include hidden files (those starting with .) in the listing") + .action(async (directory, options) => { + if (program.args.length > 1) { + console.error(`Expected no more than 1 argument (sample-files) but got ${program.args.length}.`); + process.exit(1); + } + + // default directory to current folder + directory = directory || "."; + + await newLs(directory, options['1'], options.all); + }); + +program.parse(process.argv); + + +async function newLs(directory, oneFlag, allFlag) { + try { + // check if the path exists + const stats = await fs.stat(directory); + + // if it’s a file, just print its name + if (stats.isFile()) { + console.log(directory); + return; + } + + // read directory contents + let entries = await fs.readdir(directory); + + let finalEntries; + + // organize -a output ('.' and '..' first, then visible files, then hidden (starts with a .) files) + if (allFlag) { + const dotEntries = ['.', '..']; + const visibleFiles = entries.filter(name => !name.startsWith('.')); + const hiddenFiles = entries.filter(name => name.startsWith('.') && name !== '.' && name !== '..'); + + // localeCompare = take into account rules of system language/region for ordering + // undefined = uses the system default, numeric = regular number sorting, base = ignore case & accents + visibleFiles.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })); + hiddenFiles.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })); + + // combine to a single new array + finalEntries = dotEntries.concat(visibleFiles, hiddenFiles); + } else { + // sort just visible files + finalEntries = entries + .filter(name => !name.startsWith('.')) + .sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })); + } + + // organize -1 output + if (oneFlag) { + for (const entry of finalEntries) { + console.log(entry); + } + } else { + //no flags (separated by 2 spaces) + console.log(finalEntries.join(' ')); + } + + } catch (err) { + console.error(`ls: cannot access '${directory}': No such file or directory`); + } +} + + + + + + From a7bdd7a62e702ab2ff0529aac82a220db626af52 Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Fri, 21 Nov 2025 21:21:44 +0000 Subject: [PATCH 03/10] Refactor line numbering logic in 'cat' command implementation for improved readability --- implement-shell-tools/cat/cat.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 827ab94f..7c6fada6 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -22,6 +22,10 @@ program // parse command-line file arguments using the process.argv array program.parse(process.argv); +function printNumberedLine(line, lineNumber) { + console.log(`${lineNumber.toString().padStart(6, ' ')} ${line}`); + return lineNumber + 1; +} async function newCat(files, numberLines, numberNonBlank) { let lineNumber = 1; @@ -43,15 +47,13 @@ async function newCat(files, numberLines, numberNonBlank) { if (numberNonBlank) { // check what is left on the line after trimming (truthy = text, falsy = blank) if (line.trim()) { - console.log(`${lineNumber.toString().padStart(6, ' ')} ${line}`); - lineNumber++ + lineNumber = printNumberedLine(line, lineNumber); } else { console.log(line) } } else if (numberLines) { // number all lines - console.log(`${lineNumber.toString().padStart(6, ' ')} ${line}`); - lineNumber++ + lineNumber = printNumberedLine(line, lineNumber); } else { // if neither flag print normally console.log(line) From 4b1a8cd333e50bcdf59e84852018a4e0ccd0e1cc Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Fri, 21 Nov 2025 22:11:32 +0000 Subject: [PATCH 04/10] Refactor sorting logic in 'ls' command to improve code clarity and organization --- implement-shell-tools/ls/ls.js | 38 +++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index bf89d6e2..9a7356f2 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -25,6 +25,16 @@ program program.parse(process.argv); + +function sortEntries(entries) { + // localeCompare = take into account rules of system language/region for ordering + // undefined = uses the system default, numeric = regular number sorting, base = ignore case & accents + return entries.sort((a, b) => + a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) + ); +} + + async function newLs(directory, oneFlag, allFlag) { try { // check if the path exists @@ -37,28 +47,22 @@ async function newLs(directory, oneFlag, allFlag) { } // read directory contents - let entries = await fs.readdir(directory); + const entries = await fs.readdir(directory); let finalEntries; + + // organize -a output (visible files (doesn't start with a .) and hidden files (starts with a .)) + const visibleFiles = entries.filter(name => !name.startsWith('.')); + const hiddenFiles = entries.filter(name => name.startsWith('.') && name !== '.' && name !== '..'); - // organize -a output ('.' and '..' first, then visible files, then hidden (starts with a .) files) if (allFlag) { - const dotEntries = ['.', '..']; - const visibleFiles = entries.filter(name => !name.startsWith('.')); - const hiddenFiles = entries.filter(name => name.startsWith('.') && name !== '.' && name !== '..'); - - // localeCompare = take into account rules of system language/region for ordering - // undefined = uses the system default, numeric = regular number sorting, base = ignore case & accents - visibleFiles.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })); - hiddenFiles.sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })); - - // combine to a single new array - finalEntries = dotEntries.concat(visibleFiles, hiddenFiles); + // add visible and hidden files to the new ['.', '..'] array literal + finalEntries = ['.', '..'] + .concat(sortEntries(visibleFiles)) + .concat(sortEntries(hiddenFiles)); } else { - // sort just visible files - finalEntries = entries - .filter(name => !name.startsWith('.')) - .sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' })); + // return sorted array with visible files + finalEntries = sortEntries(visibleFiles); } // organize -1 output From eace0f9adc1091d9c42379f38aa50ab5cbbb339a Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Sat, 22 Nov 2025 00:41:53 +0000 Subject: [PATCH 05/10] Implement 'wc' command to count lines, words, and bytes in files --- implement-shell-tools/wc/wc.js | 85 ++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) 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..753bed8d --- /dev/null +++ b/implement-shell-tools/wc/wc.js @@ -0,0 +1,85 @@ +import { program } from "commander"; +import { promises as fs } from "node:fs"; +import process from "node:process"; + +// configure the CLI program with its name, description, arguments, options, and actions (the help instructions) +program + .name("wc") + .description("An alternative to the 'wc' command") + .argument("", "The file(s) to count lines/words/bytes") + .option("-l", "Count lines") + .option("-w", "Count words") + .option("-c", "Count bytes") + .action(async (files, options) => { + try { + // call newWc for all files + await newWc(files, options) + } catch (err) { + console.error(`Error: ${err.message}`); + } + }); + + program.parse(process.argv); + +//helper function to format string for output +function formatCount(count) { + return count.toString().padStart(3); +} + + +// helper function to print the wc outputs per case +function printWcOutput(lineCount, wordCount, byteCount, file, options, noFlags) { + const parts = []; + + if (noFlags || options.l) parts.push(formatCount(lineCount)); + if (noFlags || options.w) parts.push(formatCount(wordCount)); + if (noFlags || options.c) parts.push(formatCount(byteCount)); + + parts.push(file); + console.log(parts.join(" ")); +} + +async function newWc(files, options) { + + const noFlags = + !options.l && + !options.w && + !options.c; + + // set the counts variables + let totalLines = 0; + let totalWords = 0; + let totalBytes = 0; + + for (const file of files) { + + try { + // read each file into a single text string + const content = await fs.readFile(file, "utf8"); + + // count lines by splitting on '\n' and subtracting 1 because + // each newline creates an extra array element, so length-1 equals the number of newline characters + const lineCount = content.split("\n").length - 1; + + // .filter(Boolean) ensures that falsy values like "" (empty string), null, undefined, 0, false are removed + const wordCount = content.split(/\s+/).filter(Boolean).length; + + // calculates the number of bytes the file uses when encoded as UTF-8. + // different than just counting chars as some chars (like emojis, accented letters, etc) take more than 1 byte + const byteCount = Buffer.byteLength(content, "utf8"); + + // update the count + totalLines += lineCount; + totalWords += wordCount; + totalBytes += byteCount; + + printWcOutput(lineCount, wordCount, byteCount, file, options, noFlags); + } catch (err) { + console.error(`Error reading file ${file}: ${err.message}`); + } + } + if (files.length > 1) { + // print the totals as wc does + printWcOutput(totalLines, totalWords, totalBytes, "total", options, noFlags); +} +} From 13fab23d4c73c339d653e8b7e7358cdcf83594e3 Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Sat, 22 Nov 2025 23:19:51 +0000 Subject: [PATCH 06/10] Refactor 'cat', 'ls', and 'wc' commands for improved readability and functionality --- implement-shell-tools/cat/cat.js | 48 ++++++++-------- implement-shell-tools/ls/ls.js | 99 ++++++++++++++++---------------- implement-shell-tools/wc/wc.js | 4 +- 3 files changed, 77 insertions(+), 74 deletions(-) diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 7c6fada6..9b7de1dd 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -2,6 +2,7 @@ import { program } from "commander"; import { promises as fs } from "node:fs"; import process from "node:process"; +// configure the CLI program with its name, description, arguments, options, and actions (the help instructions) // configure the CLI program with its name, description, arguments, options, and actions (the help instructions) program .name("cat") @@ -9,26 +10,28 @@ program .argument("", "The file(s) to process") .option("-n, --number", "Number all output lines") .option("-b, --number-nonblank", "Number non-blank output lines") - // actions to process the provided files with the specified options (-n, -b) .action(async (files, options) => { try { - // call newCat for all files - await newCat(files, options.number, options.numberNonblank) + await newCat(files, options); } catch (err) { - console.error(`Error: ${err.message}`); + console.error(`Error: ${err.message}`); } - }); + }); -// parse command-line file arguments using the process.argv array program.parse(process.argv); -function printNumberedLine(line, lineNumber) { - console.log(`${lineNumber.toString().padStart(6, ' ')} ${line}`); - return lineNumber + 1; +//helper function to format output +function printLine(line, lineNumber, padWidth) { + if (lineNumber !== null) { + console.log(`${lineNumber.toString().padStart(padWidth, ' ')} ${line}`); + } else { + console.log(line); + } } -async function newCat(files, numberLines, numberNonBlank) { +async function newCat(files, options) { let lineNumber = 1; + const padWidth = 6; for (const file of files) { // read each file into a single text string @@ -43,24 +46,21 @@ async function newCat(files, numberLines, numberNonBlank) { lines.pop(); } - for (const line of lines) { - if (numberNonBlank) { - // check what is left on the line after trimming (truthy = text, falsy = blank) - if (line.trim()) { - lineNumber = printNumberedLine(line, lineNumber); - } else { - console.log(line) - } - } else if (numberLines) { + lines.forEach(line => { + //line trim: truthy = text, falsy = blank + if (options.numberNonblank && line.trim()) { + // number non-blank lines only + printLine(line, lineNumber++, padWidth); + } else if (options.number){ // number all lines - lineNumber = printNumberedLine(line, lineNumber); + printLine(line, lineNumber++, padWidth); } else { - // if neither flag print normally - console.log(line) + // neither flag, print normally + printLine(line, null, padWidth) } - } + }); } catch (err) { - console.error(`Error reading file ${file}: ${err.message}`); + console.error(`Error reading file ${file}: ${err.message}`); } } } \ No newline at end of file diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index 9a7356f2..df7d6070 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -11,77 +11,80 @@ program .option("-1", "List all files, one per line") .option("-a, --all", "Include hidden files (those starting with .) in the listing") .action(async (directory, options) => { - if (program.args.length > 1) { - console.error(`Expected no more than 1 argument (sample-files) but got ${program.args.length}.`); - process.exit(1); - } + try { + // default to current directory if none is specified + const dir = directory || "."; - // default directory to current folder - directory = directory || "."; - - await newLs(directory, options['1'], options.all); + await newLs(dir, options['1'], options.all); + } catch (err) { + console.error(`Error: ${err.message}`); + } }); program.parse(process.argv); +// filter files based on visibility (includeHidden = true includes all files) +function filterFiles(entries, includeHidden) { + return entries.filter(name => + includeHidden ? true : !name.startsWith(".") + ); +} +// sort entries: directories first, then files, function sortEntries(entries) { + const dirs = entries.filter(entry => { + try { + return fs.statSync(entry).isDirectory(); + } catch (err) { + return false; + } + }); + + const files = entries.filter(entry => { + try { + return fs.statSync(entry).isFile(); + } catch (err) { + return false; + } + }); // localeCompare = take into account rules of system language/region for ordering // undefined = uses the system default, numeric = regular number sorting, base = ignore case & accents - return entries.sort((a, b) => - a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) + return entries.sort((a, b) => + a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }) ); } +// print entries either one per line (-1 flag) +function printEntries(entries) { + entries.forEach(entry => console.log(entry)); +} + + async function newLs(directory, oneFlag, allFlag) { try { - // check if the path exists + // check if path exists and determine if file or directory const stats = await fs.stat(directory); - - // if it’s a file, just print its name + + // if a file, just print the name if (stats.isFile()) { console.log(directory); return; - } + } - // read directory contents + // reads directory contents const entries = await fs.readdir(directory); - let finalEntries; - - // organize -a output (visible files (doesn't start with a .) and hidden files (starts with a .)) - const visibleFiles = entries.filter(name => !name.startsWith('.')); - const hiddenFiles = entries.filter(name => name.startsWith('.') && name !== '.' && name !== '..'); - - if (allFlag) { - // add visible and hidden files to the new ['.', '..'] array literal - finalEntries = ['.', '..'] - .concat(sortEntries(visibleFiles)) - .concat(sortEntries(hiddenFiles)); - } else { - // return sorted array with visible files - finalEntries = sortEntries(visibleFiles); - } - - // organize -1 output - if (oneFlag) { - for (const entry of finalEntries) { - console.log(entry); - } - } else { - //no flags (separated by 2 spaces) - console.log(finalEntries.join(' ')); - } + // Filter out hidden files if no -a flag + const filteredEntries = filterFiles(entries, allFlag); + // Sort the entries using the sortEntries helper + const sortedEntries = sortEntries(filteredEntries); + + // print entries for -1 flag (one per line) + printEntries(sortedEntries); } catch (err) { - console.error(`ls: cannot access '${directory}': No such file or directory`); + console.error(`ls: cannot access '${directory}': ${err.message}`); } -} - - - - - - +} \ No newline at end of file diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 753bed8d..78111ccc 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -23,7 +23,8 @@ program //helper function to format string for output function formatCount(count) { - return count.toString().padStart(3); + const paddingStart = 3 + return count.toString().padStart(paddingStart); } @@ -52,7 +53,6 @@ async function newWc(files, options) { let totalBytes = 0; for (const file of files) { - try { // read each file into a single text string const content = await fs.readFile(file, "utf8"); From adf7c2b089a4db6e1eaef33f1f1db1a8a5252991 Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Thu, 27 Nov 2025 17:19:53 +0000 Subject: [PATCH 07/10] Refactor options in 'wc' command for clarity and consistency. Add package.json and package-lock.json for dependency management --- implement-shell-tools/cat/cat.js | 1 - implement-shell-tools/package-lock.json | 25 +++++++++++++++++++++++++ implement-shell-tools/package.json | 8 ++++++++ implement-shell-tools/wc/wc.js | 6 +++--- 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 implement-shell-tools/package-lock.json create mode 100644 implement-shell-tools/package.json diff --git a/implement-shell-tools/cat/cat.js b/implement-shell-tools/cat/cat.js index 9b7de1dd..ae33600c 100644 --- a/implement-shell-tools/cat/cat.js +++ b/implement-shell-tools/cat/cat.js @@ -2,7 +2,6 @@ import { program } from "commander"; import { promises as fs } from "node:fs"; import process from "node:process"; -// configure the CLI program with its name, description, arguments, options, and actions (the help instructions) // configure the CLI program with its name, description, arguments, options, and actions (the help instructions) program .name("cat") diff --git a/implement-shell-tools/package-lock.json b/implement-shell-tools/package-lock.json new file mode 100644 index 00000000..38a22987 --- /dev/null +++ b/implement-shell-tools/package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "implement-shell-tools", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "implement-shell-tools", + "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 new file mode 100644 index 00000000..32d31991 --- /dev/null +++ b/implement-shell-tools/package.json @@ -0,0 +1,8 @@ +{ + "name": "implement-shell-tools", + "version": "1.0.0", + "type": "module", + "dependencies": { + "commander": "^14.0.2" + } +} diff --git a/implement-shell-tools/wc/wc.js b/implement-shell-tools/wc/wc.js index 78111ccc..40e6b3ed 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -7,9 +7,9 @@ program .name("wc") .description("An alternative to the 'wc' command") .argument("", "The file(s) to count lines/words/bytes") - .option("-l", "Count lines") - .option("-w", "Count words") - .option("-c", "Count bytes") + .option("-l", "--lines", "Print the newline counts") + .option("-w", "--words", "Print the word counts") + .option("-c", "--bytes", "Print the byte counts") .action(async (files, options) => { try { // call newWc for all files From 7b1d67dd97d31a0f11ef068c0ba1d9f07be21473 Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Thu, 27 Nov 2025 17:28:03 +0000 Subject: [PATCH 08/10] Add .gitignore file to exclude node_modules, log files, and environment variables --- implement-shell-tools/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 implement-shell-tools/.gitignore diff --git a/implement-shell-tools/.gitignore b/implement-shell-tools/.gitignore new file mode 100644 index 00000000..c3c80962 --- /dev/null +++ b/implement-shell-tools/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +*.log +.DS_Store +.env \ No newline at end of file From fafae173bd8fddfa9825362776428baf2f24c451 Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Wed, 31 Dec 2025 13:54:38 +0000 Subject: [PATCH 09/10] Improve comments and enhance output formatting in 'ls' command --- implement-shell-tools/ls/ls.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/implement-shell-tools/ls/ls.js b/implement-shell-tools/ls/ls.js index df7d6070..6c6f40f4 100644 --- a/implement-shell-tools/ls/ls.js +++ b/implement-shell-tools/ls/ls.js @@ -56,7 +56,7 @@ function sortEntries(entries) { } -// print entries either one per line (-1 flag) +// print each entry on its own line (used for -1 flag) function printEntries(entries) { entries.forEach(entry => console.log(entry)); } @@ -76,14 +76,18 @@ async function newLs(directory, oneFlag, allFlag) { // reads directory contents const entries = await fs.readdir(directory); - // Filter out hidden files if no -a flag + // filter out hidden files if no -a flag const filteredEntries = filterFiles(entries, allFlag); - // Sort the entries using the sortEntries helper + // sort the entries using the sortEntries helper const sortedEntries = sortEntries(filteredEntries); - // print entries for -1 flag (one per line) - printEntries(sortedEntries); + // print entries based on -1 flag + if (oneFlag) { + printEntries(sortedEntries); // one per line + } else { + console.log(sortedEntries.join(" ")); // all on one line, separated by spaces + } } catch (err) { console.error(`ls: cannot access '${directory}': ${err.message}`); } From 4902edc9cc7b01a58b61aef523ddcbe7f4b32be9 Mon Sep 17 00:00:00 2001 From: Geraldine-Edwards Date: Fri, 2 Jan 2026 15:03:00 +0000 Subject: [PATCH 10/10] Refactor command options in program args for clarity and update options names in printWcOutput function accordingly --- 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 40e6b3ed..7b977617 100644 --- a/implement-shell-tools/wc/wc.js +++ b/implement-shell-tools/wc/wc.js @@ -7,9 +7,9 @@ program .name("wc") .description("An alternative to the 'wc' command") .argument("", "The file(s) to count lines/words/bytes") - .option("-l", "--lines", "Print the newline counts") - .option("-w", "--words", "Print the word counts") - .option("-c", "--bytes", "Print the byte counts") + .option("-l, --lines", "Print the newline counts") + .option("-w, --words", "Print the word counts") + .option("-c, --bytes", "Print the byte counts") .action(async (files, options) => { try { // call newWc for all files @@ -32,10 +32,10 @@ function formatCount(count) { function printWcOutput(lineCount, wordCount, byteCount, file, options, noFlags) { const parts = []; - if (noFlags || options.l) parts.push(formatCount(lineCount)); - if (noFlags || options.w) parts.push(formatCount(wordCount)); - if (noFlags || options.c) parts.push(formatCount(byteCount)); - + if (noFlags || options.lines) parts.push(formatCount(lineCount)); + if (noFlags || options.words) parts.push(formatCount(wordCount)); + if (noFlags || options.bytes) parts.push(formatCount(byteCount)); + parts.push(file); console.log(parts.join(" ")); } @@ -43,9 +43,9 @@ function printWcOutput(lineCount, wordCount, byteCount, file, options, noFlags) async function newWc(files, options) { const noFlags = - !options.l && - !options.w && - !options.c; + !options.lines && + !options.words && + !options.bytes; // set the counts variables let totalLines = 0;