@paulohenriquevn/m2js
Version:
Transform TypeScript/JavaScript code into LLM-friendly Markdown summaries + Smart Dead Code Detection + Graph-Deep Diff Analysis. Extract exported functions, classes, and JSDoc comments for better AI context with 60%+ token reduction. Intelligent dead cod
364 lines • 12.3 kB
JavaScript
;
/**
* Git Integration for Graph-Deep Diff Analysis
* Handles git operations for baseline comparisons
*/
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;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitIntegrator = void 0;
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os_1 = require("os");
/**
* Git integration class for handling repository operations
*/
class GitIntegrator {
constructor(repoPath) {
this.repoPath = repoPath;
this.validateGitRepo();
}
/**
* Validate that the path is a git repository
*/
validateGitRepo() {
try {
(0, child_process_1.execSync)('git rev-parse --git-dir', {
cwd: this.repoPath,
stdio: 'pipe',
});
}
catch {
throw new Error(`Not a git repository: ${this.repoPath}`);
}
}
/**
* Get the current git reference (branch or commit)
*/
getCurrentRef() {
try {
const result = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result.trim();
}
catch {
// Fallback to commit hash
try {
const result = (0, child_process_1.execSync)('git rev-parse HEAD', {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result.trim().substring(0, 8);
}
catch {
return 'unknown';
}
}
}
/**
* Check if a git reference exists
*/
refExists(ref) {
try {
(0, child_process_1.execSync)(`git rev-parse --verify ${ref}`, {
cwd: this.repoPath,
stdio: 'pipe',
});
return true;
}
catch {
return false;
}
}
/**
* Get list of files at a specific git reference
*/
getFilesAtRef(ref, patterns) {
try {
// Get list of files at the reference
let cmd = `git ls-tree -r --name-only ${ref}`;
const result = (0, child_process_1.execSync)(cmd, {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
let files = result
.trim()
.split('\n')
.filter(f => f.length > 0);
// Filter by TypeScript/JavaScript files
files = files.filter(file => /\.(ts|tsx|js|jsx)$/.test(file) &&
!file.includes('node_modules') &&
!file.includes('.d.ts'));
// Apply additional patterns if provided
if (patterns && patterns.length > 0) {
const includePatterns = patterns.filter(p => !p.startsWith('!'));
const excludePatterns = patterns
.filter(p => p.startsWith('!'))
.map(p => p.slice(1));
if (includePatterns.length > 0) {
files = files.filter(file => includePatterns.some(pattern => this.matchPattern(file, pattern)));
}
if (excludePatterns.length > 0) {
files = files.filter(file => !excludePatterns.some(pattern => this.matchPattern(file, pattern)));
}
}
return files.map(file => path.join(this.repoPath, file));
}
catch (error) {
throw new Error(`Failed to get files at ref ${ref}: ${error.message}`);
}
}
/**
* Get file content at a specific git reference
*/
getFileContentAtRef(filePath, ref) {
try {
const relativePath = path.relative(this.repoPath, filePath);
const result = (0, child_process_1.execSync)(`git show ${ref}:${relativePath}`, {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result;
}
catch {
// File might not exist at this ref
return '';
}
}
/**
* Create temporary directory with files from a git reference
*/
async createTempWorkspace(ref, patterns) {
const tempDir = path.join((0, os_1.tmpdir)(), `m2js-workspace-${ref}-${Date.now()}`);
try {
// Create temp directory
fs.mkdirSync(tempDir, { recursive: true });
// Get files at the reference
const files = this.getFilesAtRef(ref, patterns);
// Copy files to temp directory maintaining structure
for (const filePath of files) {
const relativePath = path.relative(this.repoPath, filePath);
const tempFilePath = path.join(tempDir, relativePath);
const tempFileDir = path.dirname(tempFilePath);
// Create directory structure
fs.mkdirSync(tempFileDir, { recursive: true });
// Get file content at ref and write to temp location
const content = this.getFileContentAtRef(filePath, ref);
if (content) {
fs.writeFileSync(tempFilePath, content, 'utf8');
}
}
return tempDir;
}
catch (error) {
// Cleanup on error
if (fs.existsSync(tempDir)) {
fs.rmSync(tempDir, { recursive: true, force: true });
}
throw new Error(`Failed to create workspace for ${ref}: ${error.message}`);
}
}
/**
* Get changes between two references
*/
getChangesBetween(baseRef, currentRef = 'HEAD') {
try {
const cmd = `git diff --name-status --numstat ${baseRef}...${currentRef}`;
const result = (0, child_process_1.execSync)(cmd, {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
if (!result.trim()) {
return [];
}
const changes = [];
const lines = result.trim().split('\n');
for (const line of lines) {
const parts = line.split('\t');
if (parts.length >= 3) {
const [linesAdded, linesDeleted, filePath] = parts;
// Skip non-JS/TS files
if (!/\.(ts|tsx|js|jsx)$/.test(filePath)) {
continue;
}
let changeType = 'modified';
if (linesAdded === '-' && linesDeleted === '-') {
changeType = 'renamed';
}
else if (linesDeleted === '0') {
changeType = 'added';
}
else if (linesAdded === '0') {
changeType = 'deleted';
}
changes.push({
path: filePath,
changeType,
linesAdded: linesAdded === '-' ? 0 : parseInt(linesAdded, 10),
linesDeleted: linesDeleted === '-' ? 0 : parseInt(linesDeleted, 10),
});
}
}
return changes;
}
catch (error) {
throw new Error(`Failed to get changes between ${baseRef} and ${currentRef}: ${error.message}`);
}
}
/**
* Get list of recent commits
*/
getRecentCommits(count = 10) {
try {
const result = (0, child_process_1.execSync)(`git log --oneline -${count} --pretty=format:"%H|%s|%ai"`, {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result
.trim()
.split('\n')
.map(line => {
const [hash, message, date] = line.split('|');
return { hash: hash.substring(0, 8), message, date };
});
}
catch {
return [];
}
}
/**
* Resolve reference to actual commit hash
*/
resolveRef(ref) {
try {
// Handle special references
if (ref === 'previous') {
return this.getPreviousCommit();
}
const result = (0, child_process_1.execSync)(`git rev-parse ${ref}`, {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result.trim();
}
catch {
throw new Error(`Invalid git reference: ${ref}`);
}
}
/**
* Get the previous commit hash
*/
getPreviousCommit() {
try {
const result = (0, child_process_1.execSync)('git rev-parse HEAD~1', {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result.trim();
}
catch {
throw new Error('No previous commit found');
}
}
/**
* Simple pattern matching for file paths
*/
matchPattern(filePath, pattern) {
// Convert glob pattern to regex
const regexPattern = pattern
.replace(/\*\*/g, '.*')
.replace(/\*/g, '[^/]*')
.replace(/\?/g, '[^/]');
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(filePath);
}
/**
* Cleanup temporary workspace
*/
cleanupWorkspace(workspacePath) {
try {
if (fs.existsSync(workspacePath)) {
fs.rmSync(workspacePath, { recursive: true, force: true });
}
}
catch {
// Ignore cleanup errors
}
}
/**
* Check if working directory is clean
*/
isWorkingDirectoryClean() {
try {
const result = (0, child_process_1.execSync)('git status --porcelain', {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result.trim() === '';
}
catch {
return false;
}
}
/**
* Get current branch name
*/
getCurrentBranch() {
try {
const result = (0, child_process_1.execSync)('git branch --show-current', {
cwd: this.repoPath,
encoding: 'utf8',
stdio: 'pipe',
});
return result.trim();
}
catch {
return 'unknown';
}
}
}
exports.GitIntegrator = GitIntegrator;
//# sourceMappingURL=git-integrator.js.map