@diullei/codeguardian
Version:
Open-source developer tool to validate and enforce architectural rules, especially for AI-generated code
269 lines • 9.49 kB
JavaScript
"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