project-line-counter
Version:
A simple CLI tool to count lines of code by language.
142 lines (141 loc) • 5.17 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import fs from "fs";
import path from "path";
import chalk from "chalk";
import { select } from "@inquirer/prompts";
const langToExt = {
All: null,
TypeScript: [".ts", ".tsx"],
JavaScript: [".js", ".jsx"],
Python: [".py"],
Java: [".java"],
};
// Parse CLI flags (e.g. --typescript, --javascript, etc.)
export function parseFlags() {
const args = process.argv.slice(2);
for (const arg of args) {
if (arg.startsWith("--")) {
const key = arg.slice(2).toLowerCase();
switch (key) {
case "typescript":
return "TypeScript";
case "javascript":
return "JavaScript";
case "python":
return "Python";
case "java":
return "Java";
case "all":
return "All";
default:
console.warn(chalk.red(`Unknown flag: ${arg}`));
process.exit(1);
}
}
}
return null;
}
// Recursively gather files, ignoring node_modules and hidden folders
export function getAllFiles(dir, files = []) {
const entries = fs.readdirSync(dir);
for (const entry of entries) {
if (entry === "node_modules" || entry.startsWith("."))
continue;
const fullPath = path.join(dir, entry);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
getAllFiles(fullPath, files);
}
else {
files.push(fullPath);
}
}
return files;
}
// Count lines in a single file, ignoring comment lines based on extension
export function countLines(file, ext) {
let content = fs.readFileSync(file, "utf8");
// JavaScript/TypeScript/Java: remove block comments and filter out single-line comments
if ([".js", ".jsx", ".ts", ".tsx", ".java"].includes(ext)) {
// strip multiline comments
content = content.replace(/\/\*[\s\S]*?\*\//g, "");
const lines = content.split("\n");
return lines.filter((line) => {
const trimmed = line.trim();
return trimmed && !trimmed.startsWith("//");
}).length;
}
// Python: filter out lines starting with '#'
if (ext === ".py") {
content = content.replace(/(^\s*(?!.*=\s*)('{3}|"{3})[\s\S]*?\2)/gm, "");
const lines = content.split("\n");
return lines.filter((line) => {
const trimmed = line.trim();
return trimmed && !trimmed.startsWith("#");
}).length;
}
// Default: count all lines
return content.split("\n").length;
}
// Perform the line counting based on selected extensions
export function performCount(exts) {
const startDir = process.cwd();
const files = getAllFiles(startDir);
let total = 0;
let scanned = 0;
for (const file of files) {
const ext = path.extname(file);
if (!exts || exts.includes(ext)) {
try {
total += countLines(file, ext);
scanned++;
}
catch (_a) {
// skip unreadable files
}
}
}
console.log(chalk.blue("\nResults:"));
console.log(chalk.green(`• Files scanned: ${scanned}`));
console.log(chalk.yellow(`• Total lines of code: ${total}\n`));
}
// Interactive prompt flow using @inquirer/prompts
export function interactiveFlow() {
return __awaiter(this, void 0, void 0, function* () {
console.log(chalk.cyan.bold("Welcome to Count-Lines!"));
console.log(chalk.gray("Let's count your lines of code interactively.\n"));
const language = (yield select({
message: "Select a language to count (or All):",
choices: Object.keys(langToExt),
default: Object.keys(langToExt).indexOf("All"),
}));
console.log(chalk.magenta(`\nCounting ${language} files...`));
performCount(langToExt[language]);
});
}
// Main entry
export function main() {
return __awaiter(this, void 0, void 0, function* () {
const flagLang = parseFlags();
if (flagLang) {
console.log(chalk.magenta(`\nCounting ${flagLang} files...`));
performCount(langToExt[flagLang]);
}
else {
yield interactiveFlow();
}
});
}
main().catch((err) => {
console.error(chalk.red("Error:"), err);
process.exit(1);
});