Skip to content

Commit 4f5f3e6

Browse files
committed
feat(wc): refactor to use commander for CLI argument parsing
- Migrate from manual argv parsing to commander.js for robust flag handling - Add support for -l (lines), -w (words), -c (bytes) flags - Refactor calculateFileStats to return object with descriptive properties - Rename printFormattedLine to printReport for clarity - Improve flag detection: default to all columns when no flags provided - Maintain totals row for multiple files - Update error messages to match standard wc format - Clean up JSDoc comments and code structure
1 parent 175c44f commit 4f5f3e6

1 file changed

Lines changed: 52 additions & 53 deletions

File tree

  • implement-shell-tools/wc

implement-shell-tools/wc/wc.js

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,66 @@
11
import process from "node:process";
22
import { promises as fs } from "node:fs";
3+
import { Command } from "commander";
34

4-
/**
5-
* Calculates the lines, words, and bytes for a given file.
6-
*/
7-
async function calculateFileStats(filePath) {
8-
const fileBuffer = await fs.readFile(filePath);
9-
const fileContent = fileBuffer.toString();
10-
11-
// Standard 'wc' counts newline characters (\n)
12-
const lineCount = fileContent.split("\n").length - 1;
5+
const program = new Command();
136

14-
// Split by any whitespace and filter out empty strings to get actual words
15-
const wordCount = fileContent
16-
.split(/\s+/)
17-
.filter((word) => word.length > 0).length;
18-
19-
// Buffer.length provides the exact byte count on disk
20-
const byteCount = fileBuffer.length;
21-
22-
return { lineCount, wordCount, byteCount, filePath };
23-
}
7+
program
8+
.name("wc")
9+
.description("A simple node implementation of the word count utility")
10+
.argument("[files...]", "Files to process")
11+
.option("-l, --lines", "print the newline counts")
12+
.option("-w, --words", "print the word counts")
13+
.option("-c, --bytes", "print the byte counts")
14+
.action(async (files, options) => {
15+
// If no specific flags are provided, default to showing all
16+
const noFlagsProvided = !options.lines && !options.words && !options.bytes;
17+
const showAll = noFlagsProvided;
2418

25-
/**
26-
* Main execution function
27-
*/
28-
async function runWordCount() {
29-
const filePaths = process.argv.slice(2);
30-
const results = [];
19+
const results = [];
3120

32-
for (const filePath of filePaths) {
33-
try {
34-
const stats = await calculateFileStats(filePath);
35-
results.push(stats);
21+
for (const filePath of files) {
22+
try {
23+
const stats = await calculateFileStats(filePath);
24+
results.push(stats);
25+
printReport(stats, options, showAll);
26+
} catch (error) {
27+
console.error(`wc: ${filePath}: No such file or directory`);
28+
process.exitCode = 1;
29+
}
30+
}
3631

37-
printFormattedLine(
38-
stats.lineCount,
39-
stats.wordCount,
40-
stats.byteCount,
41-
stats.filePath,
42-
);
43-
} catch (error) {
44-
console.error(`wc: ${filePath}: No such file or directory`);
45-
process.exitCode = 1;
32+
if (results.length > 1) {
33+
const totals = {
34+
lineCount: results.reduce((sum, s) => sum + s.lineCount, 0),
35+
wordCount: results.reduce((sum, s) => sum + s.wordCount, 0),
36+
byteCount: results.reduce((sum, s) => sum + s.byteCount, 0),
37+
label: "total"
38+
};
39+
printReport(totals, options, showAll);
4640
}
47-
}
41+
});
4842

49-
// If multiple files were processed, show the total
50-
if (results.length > 1) {
51-
const totalLines = results.reduce((sum, item) => sum + item.lineCount, 0);
52-
const totalWords = results.reduce((sum, item) => sum + item.wordCount, 0);
53-
const totalBytes = results.reduce((sum, item) => sum + item.byteCount, 0);
43+
async function calculateFileStats(filePath) {
44+
const fileBuffer = await fs.readFile(filePath);
45+
const fileContent = fileBuffer.toString();
5446

55-
printFormattedLine(totalLines, totalWords, totalBytes, "total");
56-
}
47+
return {
48+
lineCount: fileContent.split("\n").length - 1,
49+
wordCount: fileContent.split(/\s+/).filter(w => w.length > 0).length,
50+
byteCount: fileBuffer.length,
51+
label: filePath
52+
};
5753
}
5854

59-
/**
60-
* Formats the output into columns to match the standard 'wc' utility
61-
*/
62-
function printFormattedLine(lines, words, bytes, label) {
63-
const format = (number) => String(number).padStart(8);
64-
console.log(`${format(lines)}${format(words)}${format(bytes)} ${label}`);
55+
function printReport(stats, options, showAll) {
56+
const output = [];
57+
const format = (num) => String(num).padStart(4);
58+
59+
if (showAll || options.lines) output.push(format(stats.lineCount));
60+
if (showAll || options.words) output.push(format(stats.wordCount));
61+
if (showAll || options.bytes) output.push(format(stats.byteCount));
62+
63+
console.log(`${output.join("")} ${stats.label}`);
6564
}
6665

67-
runWordCount();
66+
program.parse(process.argv);

0 commit comments

Comments
 (0)