UNPKG

@diullei/codeguardian

Version:

Open-source developer tool to validate and enforce architectural rules, especially for AI-generated code

269 lines 9.49 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GitRepository = void 0; const simple_git_1 = __importDefault(require("simple-git")); const fs_1 = require("fs"); const path = __importStar(require("path")); class GitRepository { repoPath; git; constructor(repoPath) { this.repoPath = repoPath; this.git = (0, simple_git_1.default)(repoPath); } async getDefaultBranch() { try { const remoteHead = await this.git.raw(['symbolic-ref', 'refs/remotes/origin/HEAD']); if (remoteHead) { const match = remoteHead.match(/refs\/remotes\/origin\/(.+)/); if (match && match[1]) { return match[1].trim(); } } } catch { } try { await this.git.raw(['rev-parse', '--verify', 'refs/heads/main']); return 'main'; } catch { try { await this.git.raw(['rev-parse', '--verify', 'refs/heads/master']); return 'master'; } catch { return 'main'; } } } async getFiles(diff, mode = 'diff') { switch (mode) { case 'diff': return diff.files; case 'all': return this.getAllWorkingFiles(); case 'staged': return this.getStagedFiles(); default: return diff.files; } } async getAllFiles() { const lsFiles = await this.git.raw(['ls-files']); const trackedFiles = lsFiles .trim() .split('\n') .filter(f => f); const status = await this.git.status(); const allFilePaths = new Set([ ...trackedFiles, ...status.not_added, ...status.created, ...status.modified, ...status.renamed.map(r => r.to), ]); const files = await Promise.all(Array.from(allFilePaths).map(async (filePath) => { const fileInfo = { path: filePath, status: 'modified', insertions: 0, deletions: 0, }; try { fileInfo.content = await this.getFileContent(filePath); } catch (error) { } return fileInfo; })); return files; } async getFileContent(filePath) { const fullPath = path.join(this.repoPath, filePath); return fs_1.promises.readFile(fullPath, 'utf-8'); } async getDiff(baseBranch, headBranch) { if (headBranch === 'HEAD') { const committedDiff = await this.git.diffSummary([`${baseBranch}...HEAD`]); const workingDiff = await this.git.diffSummary(['HEAD']); const allFiles = new Map(); committedDiff.files.forEach(file => { allFiles.set(file.file, file); }); workingDiff.files.forEach(file => { allFiles.set(file.file, file); }); const files = await Promise.all(Array.from(allFiles.values()).map(async (file) => { const status = this.mapGitStatus(file); const fileInfo = { path: file.file, status, insertions: file.insertions || 0, deletions: file.deletions || 0, }; if (file.binary === false && (status === 'added' || status === 'modified')) { try { fileInfo.content = await this.getFileContent(file.file); } catch (error) { } } if (status === 'renamed' && 'from' in file && file.from) { fileInfo.oldPath = file.from; } return fileInfo; })); return { files, baseBranch, headBranch, }; } else { const diffSummary = await this.git.diffSummary([`${baseBranch}...${headBranch}`]); const files = await Promise.all(diffSummary.files.map(async (file) => { const status = this.mapGitStatus(file); const fileInfo = { path: file.file, status, insertions: file.insertions || 0, deletions: file.deletions || 0, }; if (file.binary === false && (status === 'added' || status === 'modified')) { try { fileInfo.content = await this.getFileContent(file.file); } catch (error) { } } if (status === 'renamed' && 'from' in file && file.from) { fileInfo.oldPath = file.from; } return fileInfo; })); return { files, baseBranch, headBranch, }; } } mapGitStatus(file) { if (file.deletions === 0 && file.insertions > 0 && !file.from) { return 'added'; } else if (file.deletions > 0 && file.insertions === 0) { return 'deleted'; } else if (file.from && file.file !== file.from) { return 'renamed'; } else { return 'modified'; } } async getAllWorkingFiles() { const lsFiles = await this.git.raw(['ls-files']); const trackedFiles = lsFiles .trim() .split('\n') .filter(f => f); const status = await this.git.status(); const fileStatusMap = new Map(); trackedFiles.forEach(file => { fileStatusMap.set(file, 'modified'); }); [...status.not_added, ...status.created].forEach(file => { fileStatusMap.set(file, 'added'); }); status.modified.forEach(file => { fileStatusMap.set(file, 'modified'); }); status.deleted.forEach(file => { fileStatusMap.set(file, 'deleted'); }); status.renamed.forEach((rename) => { fileStatusMap.set(rename.to, 'renamed'); }); const files = await Promise.all(Array.from(fileStatusMap.entries()).map(async ([filePath, status]) => { const fileInfo = { path: filePath, status, insertions: 0, deletions: 0, }; if (status !== 'deleted') { try { fileInfo.content = await this.getFileContent(filePath); } catch (error) { } } return fileInfo; })); return files; } async getStagedFiles() { const stagedDiff = await this.git.diffSummary(['--cached']); const files = await Promise.all(stagedDiff.files.map(async (file) => { const status = this.mapGitStatus(file); const fileInfo = { path: file.file, status, insertions: file.insertions || 0, deletions: file.deletions || 0, }; if (file.binary === false && status !== 'deleted') { try { fileInfo.content = await this.getFileContent(file.file); } catch (error) { } } if (status === 'renamed' && 'from' in file && file.from) { fileInfo.oldPath = file.from; } return fileInfo; })); return files; } } exports.GitRepository = GitRepository; //# sourceMappingURL=GitRepository.js.map