import { execFileSync } from "node:child_process" ;
import { existsSync } from "node:fs" ;
import { readFile } from "node:fs/promises" ;
function writeStdoutLine(message: string): void {
process.stdout.write(`${message}\n`);
}
type ParsedArgs = {
maxLines: number;
};
function parseArgs(argv: string[]): ParsedArgs {
let maxLines = 500 ;
for (let index = 0 ; index < argv.length; index++) {
const arg = argv[index];
if (arg === "--max" ) {
const next = argv[index + 1 ];
if (!next || Number.isNaN(Number(next))) {
throw new Error("Missing/invalid --max value" );
}
maxLines = Number(next);
index++;
continue ;
}
}
return { maxLines };
}
function gitLsFilesAll(): string[] {
// Include untracked files too so local refactors don’t “pass” by accident.
const stdout = execFileSync("git" , ["ls-files" , "--cached" , "--others" , "--exclude-standard" ], {
encoding: "utf8" ,
});
return stdout
.split("\n" )
.map((line) => line.trim())
.filter(Boolean );
}
async function countLines(filePath: string): Promise<number> {
const content = await readFile(filePath, "utf8" );
// Count physical lines. Keeps the rule simple + predictable.
return content.split("\n" ).length;
}
async function main() {
// Makes `... | head` safe.
process.stdout.on("error" , (error: NodeJS.ErrnoException) => {
if (error.code === "EPIPE" ) {
process.exit(0 );
}
throw error;
});
const { maxLines } = parseArgs(process.argv.slice(2 ));
const files = gitLsFilesAll()
.filter((filePath) => existsSync(filePath))
.filter((filePath) => filePath.endsWith(".ts" ) || filePath.endsWith(".tsx" ));
const results = await Promise.all(
files.map(async (filePath) => ({ filePath, lines: await countLines(filePath) })),
);
const offenders = results
.filter((result) => result.lines > maxLines)
.toSorted((a, b) => b.lines - a.lines);
if (!offenders.length) {
return ;
}
// Minimal, grep-friendly output.
for (const offender of offenders) {
writeStdoutLine(`${offender.lines}\t${offender.filePath}`);
}
process.exitCode = 1 ;
}
await main();
Messung V0.5 in Prozent C=98 H=97 G=97
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland