obsidian-media-db-sync/automation/stats.ts
2024-04-11 22:30:55 +02:00

160 lines
3.7 KiB
TypeScript

import * as fs from 'fs';
interface Stat {
fileType: string;
count: number;
lines: number;
}
abstract class StatsBase {
parent: StatsBase | undefined;
path: string;
name: string;
stats: Stat[];
constructor(parent: StatsBase | undefined, path: string, name: string, stats: Stat[]) {
this.parent = parent;
this.path = path;
this.name = name;
this.stats = stats;
}
abstract addChild(child: StatsBase): void;
abstract mergeStats(stats: Stat[]): void;
abstract print(depth: number, lastChildArr: boolean[]): void;
abstract sort(): void;
getPrefix(depth: number, lastChildArr: boolean[]): string {
let prefix = '';
for (let i = 0; i < depth; i++) {
prefix += lastChildArr[i] ? ' ' : '│ ';
}
if (lastChildArr.at(-1)) {
prefix += '└─ ';
} else {
prefix += '├─ ';
}
return prefix;
}
}
class FolderStats extends StatsBase {
children: StatsBase[];
constructor(parent: StatsBase | undefined, path: string, name: string) {
super(parent, path, name, []);
this.children = [];
}
addChild(child: StatsBase) {
this.children.push(child);
this.mergeStats(child.stats);
}
mergeStats(stats: Stat[]): void {
// console.log(this, stats);
for (const stat of stats) {
const existingStat = this.stats.find(s => s.fileType === stat.fileType);
if (existingStat) {
existingStat.count += stat.count;
existingStat.lines += stat.lines;
} else {
this.stats.push(structuredClone(stat));
}
}
this.parent?.mergeStats(stats);
}
print(depth: number, lastChildArr: boolean[]): void {
console.log(
`${this.getPrefix(depth, lastChildArr)}${this.name} | ${this.stats.reduce((acc, s) => acc + s.count, 0)} files | ${this.stats.reduce((acc, s) => acc + s.lines, 0)} lines`,
);
for (let i = 0; i < this.children.length; i++) {
const child = this.children[i];
child.print(depth + 1, [...lastChildArr, i === this.children.length - 1]);
}
}
sort(): void {
this.children.sort((a, b) => {
if (a instanceof FolderStats && b instanceof FileStats) {
return 1;
} else if (a instanceof FileStats && b instanceof FolderStats) {
return -1;
} else {
return a.name.localeCompare(b.name);
}
});
this.children.forEach(c => c.sort());
}
}
class FileStats extends StatsBase {
constructor(parent: StatsBase, path: string, name: string, stats: Stat[]) {
super(parent, path, name, stats);
}
addChild(_child: StatsBase): void {
throw new Error('Cannot add child to file');
}
mergeStats(_stats: Stat[]): void {
throw new Error('Cannot merge stats to file');
}
print(depth: number, lastChildArr: boolean[]): void {
console.log(`${this.getPrefix(depth, lastChildArr)}${this.name} | ${this.stats[0].lines} lines`);
}
sort(): void {}
}
function collectStats() {
const root = new FolderStats(undefined, './src', 'src');
const ignore = ['node_modules', 'extraTypes', 'bun.lockb'];
const todo: FolderStats[] = [root];
while (todo.length > 0) {
const current = todo.pop()!;
const children = fs.readdirSync(current.path, { withFileTypes: true });
for (const child of children) {
if (ignore.includes(child.name)) {
continue;
}
if (child.isDirectory()) {
const folder = new FolderStats(current, `${current.path}/${child.name}`, child.name);
current.addChild(folder);
todo.push(folder);
} else {
const content = fs.readFileSync(`${current.path}/${child.name}`, 'utf-8');
const file = new FileStats(current, `${current.path}/${child.name}`, child.name, [
{
fileType: child.name.split('.').splice(1).join('.'),
count: 1,
lines: content.split('\n').length,
},
]);
current.addChild(file);
}
}
}
root.sort();
root.print(0, [true]);
}
collectStats();