UNPKG

@nerdo/code-reviewer

Version:

A web-based visual git diff tool for reviewing code changes between commits, branches, and tags

133 lines (132 loc) 5.22 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GitFileRepository = void 0; const simple_git_1 = __importDefault(require("simple-git")); const FileChange_1 = require("../../domain/entities/FileChange"); const DiffService_1 = require("../../domain/services/DiffService"); class GitFileRepository { constructor() { this.diffService = new DiffService_1.DiffService(); } getGit(repoPath) { return (0, simple_git_1.default)(repoPath); } async getFileTree(repoPath, commitHash) { const git = this.getGit(repoPath); const tree = await git.raw(['ls-tree', '-r', '--name-only', commitHash]); const files = tree.trim().split('\n').filter(f => f); return this.buildTreeFromPaths(files); } async getFileChanges(repoPath, fromHash, toHash) { const git = this.getGit(repoPath); const diffSummary = await git.diffSummary([fromHash, toHash]); return diffSummary.files.map(file => { const fileAny = file; // eslint-disable-line @typescript-eslint/no-explicit-any let changeType; let previousPath; if (file.file.includes('=>')) { const [oldPath, newPath] = file.file.split(' => ').map(p => p.trim()); changeType = oldPath !== newPath ? FileChange_1.FileChangeType.Renamed : FileChange_1.FileChangeType.Modified; previousPath = oldPath; } else if (fileAny.insertions > 0 && fileAny.deletions === 0 && fileAny.changes === fileAny.insertions) { changeType = FileChange_1.FileChangeType.Added; } else if (fileAny.deletions > 0 && fileAny.insertions === 0 && fileAny.changes === fileAny.deletions) { changeType = FileChange_1.FileChangeType.Deleted; } else { changeType = FileChange_1.FileChangeType.Modified; } return { path: file.file.includes('=>') ? file.file.split(' => ')[1].trim() : file.file, previousPath, changeType, additions: fileAny.insertions || 0, deletions: fileAny.deletions || 0 }; }); } async getFileDiff(repoPath, fromHash, toHash, filePath) { const [oldContent, newContent] = await Promise.all([ this.getFileContent(repoPath, fromHash, filePath).catch(() => ''), this.getFileContent(repoPath, toHash, filePath).catch(() => '') ]); // If both contents are the same, it's an unchanged file if (oldContent === newContent && oldContent !== '') { return { path: filePath, oldContent, newContent, hunks: [], isBinary: false }; } const isBinary = await this.isFileBinary(repoPath, toHash, filePath); const hunks = isBinary ? [] : this.diffService.generateFullFileDiff(oldContent, newContent); return { path: filePath, oldContent, newContent, hunks, isBinary }; } async getFileContent(repoPath, commitHash, filePath) { const git = this.getGit(repoPath); try { return await git.show([`${commitHash}:${filePath}`]); } catch (error) { throw new Error(`File ${filePath} not found in commit ${commitHash}`); } } async isFileBinary(repoPath, commitHash, filePath) { const git = this.getGit(repoPath); try { const result = await git.raw(['diff', '--numstat', `${commitHash}~1`, commitHash, '--', filePath]); return result.includes('-\t-\t'); } catch { return false; } } buildTreeFromPaths(paths) { const root = { name: '/', path: '/', type: 'directory', children: [] }; for (const filePath of paths) { const parts = filePath.split('/'); let current = root; for (let i = 0; i < parts.length; i++) { const part = parts[i]; const isFile = i === parts.length - 1; const nodePath = parts.slice(0, i + 1).join('/'); let child = current.children?.find(c => c.name === part); if (!child) { child = { name: part, path: nodePath, type: isFile ? 'file' : 'directory', children: isFile ? undefined : [] }; if (!current.children) { current.children = []; } current.children.push(child); } if (!isFile) { current = child; } } } return root; } } exports.GitFileRepository = GitFileRepository;