UNPKG

@zubenelakrab/gitstats

Version:

Powerful Git repository analyzer with comprehensive statistics and insights

142 lines 6.39 kB
import { createGitParser } from '../parsers/git-parser.js'; import { createAuthorAnalyzer } from '../analyzers/author-analyzer.js'; import { createTimelineAnalyzer } from '../analyzers/timeline-analyzer.js'; import { createHotspotAnalyzer } from '../analyzers/hotspot-analyzer.js'; import { createBusFactorAnalyzer } from '../analyzers/busfactor-analyzer.js'; import { createVelocityAnalyzer } from '../analyzers/velocity-analyzer.js'; import { createComplexityAnalyzer } from '../analyzers/complexity-analyzer.js'; import { createWorkPatternsAnalyzer } from '../analyzers/workpatterns-analyzer.js'; import { createCommitQualityAnalyzer } from '../analyzers/commits-analyzer.js'; import { createCollaborationAnalyzer } from '../analyzers/collaboration-analyzer.js'; import { createCouplingAnalyzer } from '../analyzers/coupling-analyzer.js'; import { createHealthAnalyzer } from '../analyzers/health-analyzer.js'; import { createBranchesAnalyzer } from '../analyzers/branches-analyzer.js'; import { daysDifference } from '../utils/date.js'; /** * Main analyzer that orchestrates all sub-analyzers */ export class GitStatsAnalyzer { config; onProgress; constructor(config, onProgress) { this.config = config; this.onProgress = onProgress; } reportProgress(phase, current, total) { if (this.onProgress) { this.onProgress({ phase, current, total }); } } async analyze() { const parser = createGitParser(this.config.repoPath); const totalPhases = 8; // Phase 1: Get repository info this.reportProgress('Fetching repository info', 1, totalPhases); const repository = await parser.getRepositoryInfo(); // Phase 2: Get commits this.reportProgress('Fetching commits', 2, totalPhases); const commits = await parser.getCommits(this.config); if (commits.length === 0) { throw new Error('No commits found in repository'); } // Phase 3: Get branches and tags this.reportProgress('Fetching branches and tags', 3, totalPhases); const [branches, tags] = await Promise.all([ parser.getBranches(), parser.getTags(), ]); // Phase 4: Run core analyzers in parallel this.reportProgress('Analyzing commits (core)', 4, totalPhases); const [authors, timeline, hotspots, busFactor] = await Promise.all([ createAuthorAnalyzer().analyze(commits, this.config), createTimelineAnalyzer().analyze(commits, this.config), createHotspotAnalyzer().analyze(commits, this.config), createBusFactorAnalyzer().analyze(commits, this.config), ]); // Phase 5: Run velocity and patterns analyzers this.reportProgress('Analyzing velocity and patterns', 5, totalPhases); const [velocity, workPatterns, commitQuality] = await Promise.all([ createVelocityAnalyzer().analyze(commits, this.config), createWorkPatternsAnalyzer().analyze(commits, this.config), createCommitQualityAnalyzer().analyze(commits, this.config), ]); // Phase 6: Run collaboration and coupling analyzers this.reportProgress('Analyzing collaboration and coupling', 6, totalPhases); const [collaboration, coupling, complexity] = await Promise.all([ createCollaborationAnalyzer().analyze(commits, this.config), createCouplingAnalyzer().analyze(commits, this.config), createComplexityAnalyzer().analyze(commits, this.config), ]); // Phase 7: Run health and branch analyzers this.reportProgress('Analyzing health and branches', 7, totalPhases); const [health, branchAnalysis] = await Promise.all([ createHealthAnalyzer().analyze(commits, this.config), createBranchesAnalyzer().analyze(commits, this.config, branches), ]); // Phase 8: Generate summary and compile report this.reportProgress('Compiling report', 8, totalPhases); const summary = this.generateSummary(commits, authors, hotspots, repository); return { repository, generatedAt: new Date(), config: this.config, summary, authors, timeline, hotspots, busFactor, branches, tags, // Extended analytics velocity, complexity, workPatterns, commitQuality, collaboration, coupling, health, branchAnalysis, }; } generateSummary(commits, authors, hotspots, _repository) { let totalAdditions = 0; let totalDeletions = 0; const filesChanged = new Set(); for (const commit of commits) { for (const file of commit.files) { totalAdditions += file.additions; totalDeletions += file.deletions; filesChanged.add(file.path); } } // Calculate age from actual commits analyzed const sortedCommits = commits .map(c => c.date.getTime()) .sort((a, b) => a - b); const firstCommitDate = sortedCommits.length > 0 ? new Date(sortedCommits[0]) : new Date(); const lastCommitDate = sortedCommits.length > 0 ? new Date(sortedCommits[sortedCommits.length - 1]) : new Date(); const repositoryAge = daysDifference(firstCommitDate, lastCommitDate) || 1; const mostActiveAuthor = authors[0]?.author || { name: 'Unknown', email: '' }; const mostChangedFile = hotspots.files[0]?.path || ''; return { totalCommits: commits.length, totalAuthors: authors.length, totalFiles: filesChanged.size, totalAdditions, totalDeletions, averageCommitsPerDay: commits.length / repositoryAge, averageCommitsPerAuthor: authors.length > 0 ? commits.length / authors.length : 0, mostActiveAuthor, mostChangedFile, repositoryAge, }; } } /** * Create and run analyzer */ export async function analyzeRepository(config, onProgress) { const analyzer = new GitStatsAnalyzer(config, onProgress); return analyzer.analyze(); } //# sourceMappingURL=analyzer.js.map