|
1 | 1 | import { program } from "commander"; |
2 | 2 | import { promises as fs } from "node:fs"; |
3 | 3 |
|
4 | | -const argv = process.argv.slice(2); |
| 4 | +program |
| 5 | + .name("check-for-wc") |
| 6 | + .description("Implement my own version of wc") |
| 7 | + .argument("<paths...>", "The file paths to process") |
| 8 | + .option("-l", "Counts the total number of lines") |
| 9 | + .option("-c", "Counts the total number of characters") |
| 10 | + .option("-w", "Counts the total number of words"); |
5 | 11 |
|
6 | | -const flags = argv.filter((arg) => arg.startsWith("-")); |
7 | | -const paths = argv.filter((arg) => !arg.startsWith("-")); |
| 12 | +program.parse(); |
8 | 13 |
|
9 | | -const showLines = flags.includes("-l"); |
10 | | -const showWords = flags.includes("-w"); |
11 | | -const showBytes = flags.includes("-c"); |
| 14 | +/// |
12 | 15 |
|
13 | | -const noFlagsGiven = !showLines && !showWords && !showBytes; |
| 16 | +const paths = program.args; |
| 17 | +const showLines = program.opts().l; |
| 18 | +const showWords = program.opts().w; |
| 19 | +const showChar = program.opts().c; |
| 20 | + |
| 21 | +const noFlagsGiven = !showLines && !showWords && !showChar; |
14 | 22 |
|
15 | 23 | const columns = []; |
16 | | -if (noFlagsGiven || showLines) columns.push("lines"); |
17 | | -if (noFlagsGiven || showWords) columns.push("words"); |
18 | | -if (noFlagsGiven || showBytes) columns.push("bytes"); |
19 | | - |
20 | | -function countStats(content) { |
21 | | - const lines = (content.match(/\n/g) || []).length; |
22 | | - const words = content.split(/\s+/).filter((w) => w.length > 0).length; |
23 | | - const bytes = Buffer.byteLength(content, "utf-8"); |
24 | | - return { lines, words, bytes }; |
25 | | -} |
26 | 24 |
|
27 | | -// Read every file and collect its stats |
28 | | -const rows = []; |
29 | 25 | for (const path of paths) { |
30 | 26 | const content = await fs.readFile(path, "utf-8"); |
31 | | - rows.push({ path, stats: countStats(content) }); |
32 | | -} |
33 | 27 |
|
34 | | -// If there's more than one file, we also need a "total" row at the end |
35 | | -if (rows.length > 1) { |
36 | | - const total = { lines: 0, words: 0, bytes: 0 }; |
37 | | - for (const { stats } of rows) { |
38 | | - total.lines += stats.lines; |
39 | | - total.words += stats.words; |
40 | | - total.bytes += stats.bytes; |
41 | | - } |
42 | | - rows.push({ path: "total", stats: total }); |
43 | | -} |
| 28 | + const lineCount = content.split("\n").length - 1; |
44 | 29 |
|
45 | | -const needsAlignment = columns.length > 1 || rows.length > 1; |
| 30 | + const wordCount = content |
| 31 | + .split(/\s+/) |
| 32 | + .filter((word) => word.length > 0).length; |
46 | 33 |
|
47 | | -let width = 0; |
48 | | -if (needsAlignment) { |
49 | | - for (const { stats } of rows) { |
50 | | - for (const col of columns) { |
51 | | - width = Math.max(width, String(stats[col]).length); |
52 | | - } |
53 | | - } |
| 34 | + const charCount = Buffer.byteLength(content, "utf-8"); |
54 | 35 |
|
55 | | - width = Math.max(width, 3); |
| 36 | + columns.push({ |
| 37 | + path: path, |
| 38 | + lines: lineCount, |
| 39 | + words: wordCount, |
| 40 | + char: charCount, |
| 41 | + }); |
56 | 42 | } |
| 43 | +if (columns.length > 1) { |
| 44 | + let totalLines = 0; |
| 45 | + let totalWords = 0; |
| 46 | + let totalChar = 0; |
57 | 47 |
|
58 | | -for (const { path, stats } of rows) { |
59 | | - const parts = columns.map((col, index) => { |
60 | | - const text = String(stats[col]); |
61 | | - if (!needsAlignment) { |
62 | | - return text; |
63 | | - } |
64 | | - const padded = text.padStart(width, " "); |
| 48 | + for (const result of columns) { |
| 49 | + totalLines += result.lines; |
| 50 | + totalWords += result.words; |
| 51 | + totalChar += result.char; |
| 52 | + } |
65 | 53 |
|
66 | | - return index === 0 ? padded : " " + padded; |
| 54 | + columns.push({ |
| 55 | + path: "total", |
| 56 | + lines: totalLines, |
| 57 | + words: totalWords, |
| 58 | + char: totalChar, |
67 | 59 | }); |
| 60 | +} |
| 61 | + |
| 62 | +for (const result of columns) { |
| 63 | + let line = ""; |
| 64 | + |
| 65 | + if (noFlagsGiven || showLines) { |
| 66 | + line += String(result.lines).padStart(6, " "); |
| 67 | + } |
| 68 | + if (noFlagsGiven || showWords) { |
| 69 | + line += String(result.words).padStart(6, " "); |
| 70 | + } |
| 71 | + if (noFlagsGiven || showChar) { |
| 72 | + line += String(result.char).padStart(6, " "); |
| 73 | + } |
| 74 | + |
| 75 | + line += " " + result.path; |
68 | 76 |
|
69 | | - console.log(`${parts.join("")} ${path}`); |
| 77 | + console.log(line); |
70 | 78 | } |
0 commit comments