Skip to content

Commit f82bbb0

Browse files
Implement 'wc' command to count lines, words, and bytes in files
1 parent 309fe1c commit f82bbb0

File tree

1 file changed

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

1 file changed

+85
-0
lines changed

implement-shell-tools/wc/wc.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { program } from "commander";
2+
import { promises as fs } from "node:fs";
3+
import process from "node:process";
4+
5+
// configure the CLI program with its name, description, arguments, options, and actions (the help instructions)
6+
program
7+
.name("wc")
8+
.description("An alternative to the 'wc' command")
9+
.argument("<files...>", "The file(s) to count lines/words/bytes")
10+
.option("-l", "Count lines")
11+
.option("-w", "Count words")
12+
.option("-c", "Count bytes")
13+
.action(async (files, options) => {
14+
try {
15+
// call newWc for all files
16+
await newWc(files, options)
17+
} catch (err) {
18+
console.error(`Error: ${err.message}`);
19+
}
20+
});
21+
22+
program.parse(process.argv);
23+
24+
//helper function to format string for output
25+
function formatCount(count) {
26+
return count.toString().padStart(3);
27+
}
28+
29+
30+
// helper function to print the wc outputs per case
31+
function printWcOutput(lineCount, wordCount, byteCount, file, options, noFlags) {
32+
const parts = [];
33+
34+
if (noFlags || options.l) parts.push(formatCount(lineCount));
35+
if (noFlags || options.w) parts.push(formatCount(wordCount));
36+
if (noFlags || options.c) parts.push(formatCount(byteCount));
37+
38+
parts.push(file);
39+
console.log(parts.join(" "));
40+
}
41+
42+
async function newWc(files, options) {
43+
44+
const noFlags =
45+
!options.l &&
46+
!options.w &&
47+
!options.c;
48+
49+
// set the counts variables
50+
let totalLines = 0;
51+
let totalWords = 0;
52+
let totalBytes = 0;
53+
54+
for (const file of files) {
55+
56+
try {
57+
// read each file into a single text string
58+
const content = await fs.readFile(file, "utf8");
59+
60+
// count lines by splitting on '\n' and subtracting 1 because
61+
// each newline creates an extra array element, so length-1 equals the number of newline characters
62+
const lineCount = content.split("\n").length - 1;
63+
64+
// .filter(Boolean) ensures that falsy values like "" (empty string), null, undefined, 0, false are removed
65+
const wordCount = content.split(/\s+/).filter(Boolean).length;
66+
67+
// calculates the number of bytes the file uses when encoded as UTF-8.
68+
// different than just counting chars as some chars (like emojis, accented letters, etc) take more than 1 byte
69+
const byteCount = Buffer.byteLength(content, "utf8");
70+
71+
// update the count
72+
totalLines += lineCount;
73+
totalWords += wordCount;
74+
totalBytes += byteCount;
75+
76+
printWcOutput(lineCount, wordCount, byteCount, file, options, noFlags);
77+
} catch (err) {
78+
console.error(`Error reading file ${file}: ${err.message}`);
79+
}
80+
}
81+
if (files.length > 1) {
82+
// print the totals as wc does
83+
printWcOutput(totalLines, totalWords, totalBytes, "total", options, noFlags);
84+
}
85+
}

0 commit comments

Comments
 (0)