Skip to content

London | Ameneh Keshavarz | Implement-shell-tools| WEEK3 #49

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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

Ameneh-Keshavarz
Copy link

Learners, PR Template

Self checklist

  • I have committed my files one by one, on purpose, and for a reason
  • I have titled my PR with COHORT_NAME | FIRST_NAME LAST_NAME | REPO_NAME | WEEK
  • I have tested my changes
  • My changes follow the style guide
  • My changes meet the requirements of this task

Changelist

Briefly explain your PR.

Questions

Ask any questions you have for your reviewer.

@mjpeet mjpeet added the Needs Review Participant to add when requesting review label Mar 20, 2025
Copy link
Collaborator

@blorente blorente left a comment

Choose a reason for hiding this comment

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

Thank you for your PR! I'm Borja, a volunteer, and I'll be reviewing your code.

The implementations of cat, ls and wc are good! I have left a few edge cases that are not covered, as well as a few suggestions, but you're definitely on the right track :)

Besides that, would you mind including the package.json and package-lock.json files you used during development? For a stretch goal, could you tell me why we should or shouldn't commit them to a repository?

Keep up the good work!

Comment on lines 14 to 15
//const nOption = program.opts().number;
//const bOption = program.opts().number2;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to keep these lines around? They seem to be doing the same thing as the next line.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, I removed the unnecessary commnets.

try {
const content = await fs.readFile(path, { encoding: "utf-8" });
const lines = content.split("\n");
if(lines[lines.length - 1] === "") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if(lines[lines.length - 1] === "") {
if (lines[lines.length - 1] === "") {

In other parts of the code, there is a space between the if and the opening parenthesis, so we should be consistent. This is purely a style comment, and doesn't affect the correctness of the program.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I updated the code to be consistent.

if (nOption) {
console.log(`${lineNumber++} ${line}`);
} else if (bOption && line.trim()) {
console.log(`${nonEmptyLineNumber++} ${line}`);
Copy link
Collaborator

Choose a reason for hiding this comment

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

There seems to be something wrong with the output. When I run this code, the lines on multiple files are counted the with the same counter:

$ node cat.js -b sample-files/*.txt
1 Once upon a time...
2 There was a house made of gingerbread.
3 It looked delicious.
4 I was tempted to take a bite of it.
5 But this seemed like a bad idea...

6 There's more to come, though...

However, when we run cat, we can see that every line number is counted individually:

➜ cat -b sample-files/*.txt
     1  Once upon a time...  # From sample-files/1.txt
     1  There was a house made of gingerbread.   # From sample-files/2.txt
     1  It looked delicious.   # From sample-files/3.txt
     2  I was tempted to take a bite of it.
     3  But this seemed like a bad idea...

     4  There's more to come, though...

How can we modify the code so that the lines are counted correctly?

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for the feedback. I checked my code, and the issue was that I expected line numbers to reset for each file. But the real cat -b also keeps numbering across multiple files without resetting. I've updated my script, and it now matches that behavior.

function printLinesWithOptions(lines) {
lines.forEach((line, index) => {
if (nOption) {
console.log(`${lineNumber++} ${line}`);
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens when lineNumber goes into double-digits? In cat, it keeps alignment:

$ cat very_long_file
...
  10    .parse(process.argv);
...

Copy link
Author

Choose a reason for hiding this comment

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

Yes, line numbers were misaligned. Fixed it using padStart() to align them like cat -n.

try {
const content = await fs.readFile(path, { encoding: "utf-8" });
const lines = content.split("\n");
if(lines[lines.length - 1] === "") {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need this special case?

Furthermore, what happens if lines is empty? I know that, because of how split works, you'll always get at least one element, but as the code evolves, this may no longer be true.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks, the special case isn’t strictly necessary, but I included it to be safe in case the input source changes in the future. I’ll also make sure to handle potential empty results from split() to avoid issues as the code evolves.

if (onePerLine) {
files.forEach(file => console.log(file));
} else {
console.log(files.join(' '));
Copy link
Collaborator

Choose a reason for hiding this comment

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

In ls, files are printed with a certain amount of padding, so that if we have many files, they appear to be in a table:

➜ /bin/ls
ls.js                   package-lock.json           README.md
node_modules            package.json                sample-files

This is not part of the assignment brief but, as a streacth goal, would you like to consider how to pad the outputs like that?


program
.description('Count lines, words, and characters in the specified files')
.option('-l, --lines', 'Count the lines')
Copy link
Collaborator

@blorente blorente May 15, 2025

Choose a reason for hiding this comment

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

When counting lines, your program counts one more than wc:

➜  wc -l sample-files/3.txt
       5 sample-files/3.txt

➜ node wc.js -l sample-files/3.txt
6 /Users/blorente/code/github.com/CodeYourFuture/Module-Tools/implement-shell-tools/wc/sample-files/3.txt

Why does this happen? How could we fix it so that we print the right number of lines?

Copy link
Author

Choose a reason for hiding this comment

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

I was using data.split('\n').length, which overcounts lines. To match the behavior of wc -l, I updated it to:
const lines = (data.match(/\n/g) || []).length;

Comment on lines 24 to 25
const lines = data.split('\n').length;
const words = data.split(/\s+/).filter(Boolean).length;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This section of the code is processing data twice: Once to split it into lines, and another one to split it into words. While this is correct, in very large files, this could potentially be quite slow.

Is there a way we could avoid processing the entirety of data twice?

This is a stretch goal, as the current program is already correct.

Comment on lines 61 to 63
if (options.lines !== false) totals.push(totalLines);
if (options.words !== false) totals.push(totalWords);
if (options.characters !== false) totals.push(totalCharacters);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why did you add the !== false clause to these lines? Is there any way we could express the same in a more concise way?

Copy link
Author

Choose a reason for hiding this comment

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

The !== false checks were overly cautious, siince commander sets options to true or undefined, the concise and correct way is simply:
if (options.lines)

.option('-l, --lines', 'Count the lines')
.option('-w, --words', 'Count the words')
.option('-c, --characters', 'Count the characters')
.parse(process.argv);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Your solution prints the full path of each file:

➜ node wc.js -l sample-files/3.txt
6 /Users/blorente/code/github.com/CodeYourFuture/Module-Tools/implement-shell-tools/wc/sample-files/3.txt

Whereas wc only prints the path relative to the directory we run it from:

➜  wc -l sample-files/3.txt
       5 sample-files/3.txt

How would you modify this code to print the relative path?

Copy link
Author

@Ameneh-Keshavarz Ameneh-Keshavarz May 25, 2025

Choose a reason for hiding this comment

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

I was printing the absolute path using path.resolve, which made the output differ from wc. I’ve updated the code to print the original file argument instead, so it now shows the relative path the we type.

@blorente blorente added 👀 Review Requirements Changes requested to meet requirements Reviewed Volunteer to add when completing a review and removed Needs Review Participant to add when requesting review labels May 15, 2025
@Ameneh-Keshavarz
Copy link
Author

Hi Borja,

Thanks for the feedback and for reviewing my code! I looked at the edge cases you mentioned and add the package.json and package-lock.json files.

We should commit both files because: package.json shows what packages the project needs. package-lock.json makes sure everyone installs the exact same versions. Thanks again

@Ameneh-Keshavarz Ameneh-Keshavarz requested a review from blorente May 25, 2025 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
👀 Review Requirements Changes requested to meet requirements Reviewed Volunteer to add when completing a review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants