Chapter 12 of 12
Build a CLI tool that analyses a directory of files: counts lines, words, and characters per file, and outputs a formatted summary report. Pure Node.js β no npm packages needed.
#!/usr/bin/env node
// Usage: node analyser.js ./src
const fs = require("fs/promises");
const path = require("path");
async function analyseFile(filePath) {
const content = await fs.readFile(filePath, "utf8");
const lines = content.split("
");
const words = content.split(/s+/).filter(Boolean);
return {
file: path.basename(filePath),
lines: lines.length,
words: words.length,
chars: content.length,
size: (await fs.stat(filePath)).size,
};
}
async function analyseDirectory(dirPath) {
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const files = entries
.filter(e => e.isFile() && !e.name.startsWith("."))
.map(e => path.join(dirPath, e.name));
const results = await Promise.all(files.map(analyseFile));
return results;
}
function printReport(results) {
const totals = results.reduce((acc, r) => ({
lines: acc.lines + r.lines,
words: acc.words + r.words,
chars: acc.chars + r.chars,
}), { lines: 0, words: 0, chars: 0 });
console.log("
ββ File Analysis Report βββββββββββββββββββββββββ
");
console.log("File".padEnd(30) + "Lines".padStart(8) + "Words".padStart(8) + "Chars".padStart(8));
console.log("β".repeat(54));
for (const r of results.sort((a, b) => b.lines - a.lines)) {
console.log(
r.file.padEnd(30) +
String(r.lines).padStart(8) +
String(r.words).padStart(8) +
String(r.chars).padStart(8)
);
}
console.log("β".repeat(54));
console.log(
"TOTAL".padEnd(30) +
String(totals.lines).padStart(8) +
String(totals.words).padStart(8) +
String(totals.chars).padStart(8)
);
console.log(`
${results.length} files analysed.
`);
}
async function main() {
const targetDir = process.argv[2] || ".";
const absPath = path.resolve(targetDir);
try {
await fs.access(absPath);
} catch {
console.error(`Error: Directory not found: ${absPath}`);
process.exit(1);
}
console.log(`Analysing: ${absPath}`);
const results = await analyseDirectory(absPath);
if (results.length === 0) {
console.log("No files found.");
return;
}
printReport(results);
}
main().catch(err => {
console.error("Unexpected error:", err.message);
process.exit(1);
});