UNPKG

incize

Version:

AI Commit Copilot for Power Developers

217 lines (216 loc) 6.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DiffParser = void 0; const simple_git_1 = require("simple-git"); const types_1 = require("../../types"); class DiffParser { git; constructor(repoPath) { this.git = (0, simple_git_1.simpleGit)(repoPath || process.cwd()); } /** * Parse diff for staged changes */ async parseStagedDiff() { try { const diff = await this.git.diff(['--cached', '--unified=3']); return this.parseDiffString(diff); } catch (error) { throw new types_1.GitError('Failed to parse staged diff', { originalError: error instanceof Error ? error.message : String(error) }); } } /** * Parse diff for working directory changes */ async parseWorkingDiff() { try { const diff = await this.git.diff(['--unified=3']); return this.parseDiffString(diff); } catch (error) { throw new types_1.GitError('Failed to parse working diff', { originalError: error instanceof Error ? error.message : String(error) }); } } /** * Parse diff string into structured format */ parseDiffString(diffString) { if (!diffString.trim()) { return { files: [], summary: { additions: 0, deletions: 0, totalChanges: 0 } }; } const fileDiffs = this.splitDiffIntoFiles(diffString); const files = []; let totalAdditions = 0; let totalDeletions = 0; for (const fileDiff of fileDiffs) { const parsedFile = this.parseFileDiff(fileDiff); if (parsedFile) { files.push(parsedFile); totalAdditions += parsedFile.additions; totalDeletions += parsedFile.deletions; } } return { files, summary: { additions: totalAdditions, deletions: totalDeletions, totalChanges: totalAdditions + totalDeletions } }; } /** * Split diff string into individual file diffs */ splitDiffIntoFiles(diffString) { const fileDiffs = []; const lines = diffString.split('\n'); let currentFileDiff = []; for (const line of lines) { if (line.startsWith('diff --git')) { if (currentFileDiff.length > 0) { fileDiffs.push(currentFileDiff.join('\n')); } currentFileDiff = [line]; } else { currentFileDiff.push(line); } } if (currentFileDiff.length > 0) { fileDiffs.push(currentFileDiff.join('\n')); } return fileDiffs; } /** * Parse individual file diff */ parseFileDiff(fileDiff) { const lines = fileDiff.split('\n'); if (lines.length < 2) return null; // Extract file path and status const diffHeader = lines[0]; if (!diffHeader) return null; const pathMatch = diffHeader.match(/diff --git a\/(.+) b\/(.+)/); if (!pathMatch) return null; const oldPath = pathMatch[1]; const newPath = pathMatch[2]; const path = newPath !== '/dev/null' ? newPath : oldPath; // Determine file status const status = this.determineFileStatus(lines); // Count additions and deletions const { additions, deletions } = this.countChanges(lines); // Detect language const language = this.detectLanguage(path || ''); return { path: path || '', status, additions, deletions, diff: fileDiff, language }; } /** * Determine file status from diff */ determineFileStatus(lines) { for (const line of lines) { if (line.startsWith('new file mode')) return 'added'; if (line.startsWith('deleted file mode')) return 'deleted'; if (line.startsWith('rename from') || line.startsWith('rename to')) return 'renamed'; } return 'modified'; } /** * Count additions and deletions in diff */ countChanges(lines) { let additions = 0; let deletions = 0; for (const line of lines) { if (line.startsWith('+') && !line.startsWith('+++')) { additions++; } else if (line.startsWith('-') && !line.startsWith('---')) { deletions++; } } return { additions, deletions }; } /** * Detect programming language from file extension */ detectLanguage(path) { const extension = path.split('.').pop()?.toLowerCase(); const languageMap = { // Web 'js': 'JavaScript', 'ts': 'TypeScript', 'jsx': 'React JSX', 'tsx': 'React TSX', 'html': 'HTML', 'css': 'CSS', 'scss': 'SCSS', 'sass': 'Sass', 'vue': 'Vue', // Backend 'py': 'Python', 'java': 'Java', 'kt': 'Kotlin', 'go': 'Go', 'rs': 'Rust', 'php': 'PHP', 'rb': 'Ruby', 'cs': 'C#', 'cpp': 'C++', 'c': 'C', 'swift': 'Swift', // Data 'json': 'JSON', 'xml': 'XML', 'yaml': 'YAML', 'yml': 'YAML', 'toml': 'TOML', 'sql': 'SQL', // Config 'md': 'Markdown', 'txt': 'Text', 'sh': 'Shell', 'bash': 'Bash', 'zsh': 'Shell', 'fish': 'Shell', 'ps1': 'PowerShell', // Build 'dockerfile': 'Dockerfile', 'docker': 'Dockerfile', 'makefile': 'Makefile', 'mk': 'Makefile' }; return languageMap[extension || ''] || extension; } /** * Get summary statistics for diff */ async getDiffSummary() { const diff = await this.parseStagedDiff(); const languages = [...new Set(diff.files.map(f => f.language).filter(Boolean))]; return { fileCount: diff.files.length, additions: diff.summary.additions, deletions: diff.summary.deletions, languages }; } } exports.DiffParser = DiffParser;