|
1 | 1 | import { program } from "commander"; |
2 | 2 | import process from "node:process"; |
3 | 3 | import { promises as fs } from "node:fs"; |
| 4 | +import glob from "glob"; |
4 | 5 |
|
5 | 6 | program |
6 | | - .name("cat") |
7 | | - .description("print the content of file") |
8 | | - .option("-n, --line-numbers","Number the output lines, starting at 1") |
9 | | - .option("-b, --number-nonblank", "Number non-empty output lines, overrides -n") |
10 | | - .argument("<paths...>", "The file path(s) to process"); // to support multiple file |
| 7 | + .name("cat") |
| 8 | + .description("print the content of file") |
| 9 | + .option("-n, --line-numbers", "Number the output lines, starting at 1") |
| 10 | + .option( |
| 11 | + "-b, --number-nonblank", |
| 12 | + "Number non-empty output lines, overrides -n" |
| 13 | + ) |
| 14 | + .argument("<paths...>", "The file path(s) to process"); // to support multiple file |
11 | 15 | program.parse(); |
12 | 16 |
|
13 | | -const argv = program.args; |
| 17 | +const argv = program.args.flatMap((path) => glob.sync(path)); |
| 18 | + |
14 | 19 | const options = program.opts(); |
15 | 20 | if (argv.length === 0) { |
16 | | - console.error(`No file paths provided`);// to support more files |
17 | | - process.exit(1); |
| 21 | + console.error(`No file paths provided`); // to support more files |
| 22 | + process.exit(1); |
18 | 23 | } |
19 | 24 |
|
20 | 25 | let lineCounter = 1; |
21 | | - |
22 | | -for (const path of argv) { |
23 | | - try { |
24 | | -const content = await fs.readFile(path, "utf-8"); |
25 | | -const lines= content.split(/\r?\n/); |
26 | | -if (lines.length && lines[lines.length - 1] === '') {//// Remove trailing empty line if it's just from the final newline |
27 | | - lines.pop(); |
| 26 | +function printLine(line, number = false) { |
| 27 | + if (number && line.trim() !== "") { |
| 28 | + const lineNumber = String(lineCounter++).padStart(6, " "); |
| 29 | + console.log(`${lineNumber}\t${line}`); |
| 30 | + } else { |
| 31 | + console.log(line); |
| 32 | + } |
28 | 33 | } |
29 | | - |
30 | | -if (options.numberNonblank) { |
31 | | - lines.forEach((line) => { |
32 | | - if (line.trim() === "") { |
33 | | - console.log(""); // Blank line, no number |
34 | | - } else { |
35 | | - const lineNumber = String(lineCounter++).padStart(6, " "); |
36 | | - console.log(`${lineNumber}\t${line}`); |
37 | | - } |
38 | | - }); |
39 | | - |
40 | | -}else if (options.lineNumbers) { |
41 | | - lines.forEach((line) => { |
42 | | - const lineNumber = String(lineCounter++).padStart(6, ' '); |
43 | | - console.log(`${lineNumber}\t${line}`) |
44 | | - }); |
45 | | - |
46 | | -} else { |
47 | | - process.stdout.write(content); |
48 | | - if (!content.endsWith('\n')) process.stdout.write('\n'); |
49 | | - } |
50 | | - } catch (err) { |
51 | | - console.error(`cat: ${path}: ${err.message}`); |
| 34 | +// Helper function to print totals for multiple files |
| 35 | +function printTotal(total, label = "total") { |
| 36 | + console.log(`${total} ${label}`); |
| 37 | +} |
| 38 | +for (const path of argv) { |
| 39 | + try { |
| 40 | + const content = await fs.readFile(path, "utf-8"); |
| 41 | + const lines = content.split(/\r?\n/); |
| 42 | + if (lines.length && lines[lines.length - 1] === "") { |
| 43 | + // Remove trailing empty line if it's just from the final newline |
| 44 | + lines.pop(); |
52 | 45 | } |
| 46 | + // Determine if we need to number lines |
| 47 | + const numberLines = options.numberNonblank || options.lineNumbers; |
| 48 | + |
| 49 | + lines.forEach((line) => printLine(line, numberLines)); |
| 50 | + |
| 51 | + // Add a newline if the file didn't end with one |
| 52 | + if (!content.endsWith("\n")) process.stdout.write("\n"); |
| 53 | + } catch (err) { |
| 54 | + console.error(`cat: ${path}: ${err.message}`); |
| 55 | + } |
53 | 56 | } |
0 commit comments