-
-
Notifications
You must be signed in to change notification settings - Fork 88
London | 26-SDC-Mar | Ebrahim Beiati-Asl | Sprint 3 | implements-shell-tool #376
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
708e4ce
972ae2b
09cde63
643fefa
c01eac6
8c5c05a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| #!/usr/bin/env node | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| //shared line counter across all files(matches cat -n) | ||
| let globalLineCounter = 1; | ||
|
|
||
| function printFile(filePath, options) { | ||
| try { | ||
| const content = fs.readFileSync(filePath, 'utf-8'); | ||
| const lines = content.split('\n'); | ||
|
|
||
| lines.forEach((line) => { | ||
| if(options.numberNonEmpty) { | ||
| //-b option: number non-empty lines | ||
| if(line.trim()) { | ||
| process.stdout.write( | ||
| `${String(globalLineCounter).padStart(6)}\t${line}\n` | ||
| ); | ||
| globalLineCounter++; | ||
| } else { | ||
| process.stdout.write('\n'); | ||
| } | ||
| } else if(options.numberAll) { | ||
| //-n option: number all lines | ||
| process.stdout.write( | ||
| `${String(globalLineCounter).padStart(6)}\t${line}\n` | ||
| ); | ||
| globalLineCounter++; | ||
| } else { | ||
| //default: just print the line | ||
| process.stdout.write(line + '\n'); | ||
| } | ||
| }); | ||
|
|
||
| } catch (error) { | ||
| console.error(`Error reading file ${filePath}: ${error.message}`); | ||
| } | ||
| } | ||
|
|
||
| function main() { | ||
| const args = process.argv.slice(2); | ||
| const options = { | ||
| numberNonEmpty: false, | ||
| numberAll: false, | ||
| }; | ||
| const filePatterns = []; | ||
|
|
||
| args.forEach((arg) => { | ||
| if(arg === '-n') { | ||
| options.numberAll = true; | ||
| } else if(arg === '-b') { | ||
| options.numberNonEmpty = true; | ||
| } else { | ||
| filePatterns.push(arg); | ||
| } | ||
| }); | ||
| // -b takes precedence over -n | ||
| if(options.numberNonEmpty) { | ||
| options.numberAll = false; | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than having two different options which are mutually exclusive, I would probably model this as one option with three possible values: |
||
|
|
||
| if(filePatterns.length === 0) { | ||
| console.log("cat: missing file operand"); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const files = filePatterns; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you call this |
||
|
|
||
| files.forEach((file) => { | ||
| const resolvedPath = path.resolve(process.cwd(), file); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What advantage does |
||
| printFile(resolvedPath, options); | ||
| }); | ||
| } | ||
|
|
||
| main(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #!/usr/bin/env node | ||
| const fs = require('node:fs'); | ||
| const path = require('node:path'); | ||
|
|
||
| function listDirectory(dirPath, showAll, onePerLine) { | ||
| try { | ||
| const entries = fs.readdirSync(dirPath, { withFileTypes: true }); | ||
| const filtered = entries.filter((entry) => showAll || !entry.name.startsWith('.')); | ||
|
|
||
| if(onePerLine) { | ||
| filtered.forEach(entry => console.log(entry.name)); | ||
| } else { | ||
| const names = filtered.map(entry => entry.name); | ||
| console.log(names.join(' ')); | ||
| } | ||
| } catch (error) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This indentation isn't correct - please format all of your code before submitting for review. I'd recommend setting up your IDE to auto-format your code on save to avoid needing to remember to do this. |
||
| console.error(`Error reading directory ${dirPath}: ${error.message}`); | ||
| } | ||
| } | ||
| function main() { | ||
| const args = process.argv.slice(2); | ||
| // Check for options | ||
| const showAll = args.includes('-a'); | ||
| const onePerLine = args.includes('-1'); | ||
| //remove options from args | ||
| const directories = args.filter(arg => arg !== '-a' && arg !== '-1'); | ||
|
|
||
| // If no directory is specified, list the current directory | ||
| if(directories.length === 0) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you think how to fold the "no directories" case into the main loop so you don't have to have two separate calls to |
||
| listDirectory(process.cwd(), showAll, onePerLine); | ||
| return; | ||
| } | ||
| //If a directory is specified, list that directory | ||
| directories.forEach((arg, index) => { | ||
| try { | ||
| const stats = fs.statSync(arg); | ||
| if(stats.isDirectory()) { | ||
| //Print header if multiple directories are listed | ||
| if(directories.length > 1) console.log(`${arg}:`); | ||
|
|
||
| listDirectory(arg, showAll, onePerLine); | ||
| //add a blank line between directory listings if there are multiple directories | ||
| if(directories.length > 1 && index < directories.length - 1) console.log(''); | ||
| } else{ | ||
| console.log(arg);// single file | ||
| } | ||
| } catch (error) { | ||
| console.error(`Error accessing ${arg}: ${error.message}`); | ||
| } | ||
| }); | ||
| } | ||
| main(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| #!/usr/bin/env node | ||
| const fs = require('node:fs'); | ||
| // Function to count lines, words, and bytes in a file | ||
| function countFileContent(content) { | ||
| const lines = content.split('\n').length; // Count lines by splitting on newline characters | ||
| const words = content.trim().split(/\s+/).filter(Boolean).length; // Split by whitespace and filter out empty strings | ||
| const bytes = Buffer.byteLength(content, 'utf8'); | ||
| return { lines, words, bytes }; | ||
| } | ||
|
|
||
| //print counts in the format of wc according to options | ||
| function printCounts(filePath, counts, options) { | ||
| const parts = []; | ||
| if(options.line) parts.push(counts.lines); | ||
| if(options.word) parts.push(counts.words); | ||
| if(options.byte) parts.push(counts.bytes); | ||
| //if no specific count options are provided, print all counts | ||
| if(!options.line && !options.word && !options.byte) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be simpler to do this check when setting up options, rather than when consuming it - i.e. in your options parsing to see "if no options were set, set all to true" - that way the rest of your code doesn't need to think about this special case, they can just handle (This about this as an abstraction boundary - the point of parsing command line flags into an options object is so that the rest of your code doesn't need to worry about the specifics of flags, this is just one more example of a place you can avoid your code needing to know the specifics of flags) |
||
| //default is to print all counts | ||
| parts.push(counts.lines, counts.words, counts.bytes); | ||
| } | ||
| console.log(parts.join('\t'),filePath); | ||
| } | ||
|
|
||
| function main() { | ||
| const args = process.argv.slice(2); | ||
| const options = { | ||
| line: false, | ||
| word: false, | ||
| byte: false, | ||
| }; | ||
|
|
||
| //Separate options from file paths | ||
| const files = []; | ||
| args.forEach((arg) => { | ||
| if(arg === '-l') options.line = true; | ||
| else if(arg === '-w') options.word = true; | ||
| else if(arg === '-c') options.byte = true; | ||
| else files.push(arg); | ||
| }); | ||
|
|
||
| if(files.length === 0) { | ||
| console.error('No files specified'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| let totalCounts = { lines: 0, words: 0, bytes: 0 }; | ||
| const multipleFiles = files.length > 1; | ||
|
|
||
| files.forEach(file => { | ||
| try { | ||
| const content = fs.readFileSync(file, 'utf-8'); | ||
| const counts = countFileContent(content); | ||
|
|
||
| // Sum counts for total if multiple files | ||
| totalCounts.lines += counts.lines; | ||
| totalCounts.words += counts.words; | ||
| totalCounts.bytes += counts.bytes; | ||
|
|
||
| printCounts(file, counts, options); | ||
| } catch (error) { | ||
| console.error(`Error reading file ${file}: ${error.message}`); | ||
| } | ||
| }); | ||
|
|
||
| // If multiple files, print total counts | ||
| if(multipleFiles) { | ||
| printCounts('total', totalCounts, options); | ||
| } | ||
| } | ||
| main(); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The three branches here look quite similar and repetitive. In general, if you have multiple similar branches, it's more clear to extract the differences into variables, and then run the same code, i.e. so you'd only have one call to
process.stdout.writewhich looks more likeprocess.stdout.write(`${prefix}${line}\n`)whereprefixmay be set differently based on options (including potentially an empty string).This way it's easier for someone reading the code to see what's the same / different in each case, and also avoids the hazard that someone updates one of the branches but forgets to update the other ones.