Skip to content

Commit dae3b62

Browse files
added code for the wc exercise
1 parent b945902 commit dae3b62

File tree

1 file changed

+89
-0
lines changed
  • implement-shell-tools/wc

1 file changed

+89
-0
lines changed

implement-shell-tools/wc/wc.mjs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { program } from "commander";
2+
import process from "node:process";
3+
import { readFileSync, existsSync } from "node:fs";
4+
5+
program
6+
.name("wc")
7+
.description("Count lines, words, and characters in files")
8+
.argument("[files...]", "Files to process")
9+
.option("-l, --lines", "Count lines")
10+
.option("-w, --words", "Count words")
11+
.option("-c, --chars", "Count characters (bytes)")
12+
program.parse(process.argv);
13+
14+
const options = program.opts();
15+
const files = program.args.length ? program.args : ["/dev/stdin"];
16+
17+
function countFile(filePath, options) {
18+
let content = "";
19+
try {
20+
if (filePath === "/dev/stdin") {
21+
content = readFileSync(process.stdin.fd, "utf8");
22+
} else {
23+
if (!existsSync(filePath)) {
24+
console.error(`wc: ${filePath}: No such file or directory`);
25+
return null;
26+
}
27+
content = readFileSync(filePath, "utf8");
28+
}
29+
} catch (error) {
30+
console.error(`wc: ${filePath}: ${error.message}`);
31+
return null;
32+
}
33+
34+
if (typeof content !== 'string') {
35+
content = "";
36+
}
37+
38+
const lineCount = (content.match(/\n/g) || []).length;
39+
40+
const wordCount = content.trim().split(/\s+/).filter(Boolean).length;
41+
42+
const charCount = Buffer.byteLength(content, "utf8");
43+
44+
return {
45+
file: filePath,
46+
lines: options.lines || (!options.words && !options.chars) ? lineCount : null,
47+
words: options.words || (!options.lines && !options.chars) ? wordCount : null,
48+
chars: options.chars || (!options.lines && !options.words) ? charCount : null,
49+
};
50+
}
51+
52+
const results = [];
53+
let totalLines = 0;
54+
let totalWords = 0;
55+
let totalChars = 0;
56+
const hasMultipleFiles = files.length > 1;
57+
58+
files.forEach(file => {
59+
const result = countFile(file, options);
60+
if (result) {
61+
results.push(result);
62+
63+
if (result.lines !== null) totalLines += result.lines;
64+
if (result.words !== null) totalWords += result.words;
65+
if (result.chars !== null) totalChars += result.chars;
66+
}
67+
});
68+
69+
results.forEach(result => {
70+
const output = [];
71+
if (result.lines !== null) output.push(result.lines.toString().padStart(8));
72+
if (result.words !== null) output.push(result.words.toString().padStart(8));
73+
if (result.chars !== null) output.push(result.chars.toString().padStart(8));
74+
console.log(output.join(" "), result.file);
75+
});
76+
77+
if (hasMultipleFiles && results.length > 0) {
78+
const totalOutput = [];
79+
if (options.lines || (!options.words && !options.chars)) {
80+
totalOutput.push(totalLines.toString().padStart(8));
81+
}
82+
if (options.words || (!options.lines && !options.chars)) {
83+
totalOutput.push(totalWords.toString().padStart(8));
84+
}
85+
if (options.chars || (!options.lines && !options.words)) {
86+
totalOutput.push(totalChars.toString().padStart(8));
87+
}
88+
console.log(totalOutput.join(" "), "total");
89+
}

0 commit comments

Comments
 (0)