@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
399 lines (383 loc) ⢠16.5 kB
JavaScript
;
/**
* CLI interface for Graph-Deep Diff Analysis
* LLM-friendly reporting with rich context and impact scoring
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getGraphDiffHelpText = getGraphDiffHelpText;
exports.executeGraphDiffAnalysis = executeGraphDiffAnalysis;
const chalk_1 = __importDefault(require("chalk"));
const graph_diff_analyzer_1 = require("./graph-diff-analyzer");
/**
* Get detailed help text for graph diff analysis
*/
function getGraphDiffHelpText() {
return `
${chalk_1.default.bold.blue('š M2JS Graph-Deep Diff Analysis')}
${chalk_1.default.bold('PURPOSE:')}
Compare architectural states between git references to detect problematic changes
and track technical debt evolution over time.
${chalk_1.default.bold('BASIC USAGE:')}
m2js <path> --graph-diff --baseline <ref>
m2js <path> --graph-diff --baseline main --current feature-branch
m2js <path> --graph-diff --baseline HEAD~1 --format json
${chalk_1.default.bold('OPTIONS:')}
--baseline <ref> Baseline git reference (required)
Examples: main, HEAD~1, v1.0.0, commit-hash
--current <ref> Current reference (default: working directory)
Examples: feature-branch, HEAD, working files
--format <type> Output format: table (default), json
--min-severity <level> Filter by severity: low, medium, high, critical
--include-details Include detailed change analysis (default: true)
--include-impact Include impact scoring (default: true)
--include-suggestions Include improvement suggestions (default: true)
${chalk_1.default.bold('DETECTION CAPABILITIES:')}
š Circular Dependencies - New/resolved circular imports
š Coupling Changes - Average dependencies per module
š¦ External Dependencies - NPM package additions/removals
šļø Layer Violations - Architecture boundary violations
š§© Complexity Hotspots - High-coupling modules
š Architecture Layers - New/removed structural layers
${chalk_1.default.bold('OUTPUT INFORMATION:')}
⢠Severity Distribution - Critical, High, Medium, Low changes
⢠Category Breakdown - Dependencies, Architecture, Coupling, etc.
⢠Health Score Tracking - 0-100 architectural health metric
⢠Impact Analysis - Maintainability, Performance, Testability
⢠Actionable Recommendations - Prioritized improvement steps
${chalk_1.default.bold('EXAMPLES:')}
# Compare current branch to main
m2js src/ --graph-diff --baseline main
# Compare two specific commits
m2js . --graph-diff --baseline v1.0.0 --current v1.1.0
# Focus on critical issues only
m2js src/ --graph-diff --baseline HEAD~5 --min-severity high
# JSON output for CI/CD integration
m2js . --graph-diff --baseline main --format json > architecture-report.json
${chalk_1.default.bold('CI/CD INTEGRATION:')}
# Use in PR checks to prevent architectural regression
m2js src/ --graph-diff --baseline origin/main --format json | jq '.impact.healthChange.delta'
${chalk_1.default.bold('COMMON WORKFLOWS:')}
1. Pre-merge validation - Compare feature branch to main
2. Release preparation - Compare current to last stable version
3. Refactoring tracking - Monitor architectural improvements
4. Technical debt audit - Analyze historical architectural changes
${chalk_1.default.green('š” Pro Tip:')} Use --baseline HEAD~1 for commit-by-commit analysis
${chalk_1.default.green('š” Pro Tip:')} Set up git hooks to track architectural health automatically
`;
}
/**
* Execute graph diff analysis with LLM-friendly output
*/
async function executeGraphDiffAnalysis(projectPath, options) {
const startTime = Date.now();
try {
console.log(chalk_1.default.blue('š Starting Graph-Deep Diff Analysis...'));
console.log(chalk_1.default.gray(`Comparing ${options.baseline} ā ${options.current || 'current'}`));
// Perform analysis
const report = await (0, graph_diff_analyzer_1.analyzeGraphDiff)(projectPath, options);
// Output results based on format
if (options.format === 'json') {
console.log(JSON.stringify(report, null, 2));
}
else {
await displayTableReport(report, options);
}
const duration = Date.now() - startTime;
console.log(chalk_1.default.gray(`\nā±ļø Analysis completed in ${duration}ms`));
}
catch (error) {
console.error(chalk_1.default.red(`ā Graph diff analysis failed: ${error.message}`));
process.exit(1);
}
}
/**
* Display analysis results in table format (LLM-friendly)
*/
async function displayTableReport(report, options) {
console.log('\n' + chalk_1.default.bold.blue('š GRAPH-DEEP DIFF ANALYSIS REPORT'));
console.log(chalk_1.default.blue('='.repeat(60)));
// Comparison overview
displayComparisonOverview(report);
// Impact summary
displayImpactSummary(report.impact);
// Key metrics changes
displayMetricsChanges(report);
// Architectural changes
if (options.includeDetails !== false) {
displayArchitecturalChanges(report.changes, options);
}
// Recommendations
if (options.includeSuggestions !== false) {
displayRecommendations(report.recommendations);
}
// Health score analysis
displayHealthScoreAnalysis(report.impact);
}
/**
* Display comparison overview
*/
function displayComparisonOverview(report) {
console.log('\n' + chalk_1.default.bold.yellow('š COMPARISON OVERVIEW'));
console.log(chalk_1.default.yellow('-'.repeat(40)));
console.log(`${chalk_1.default.cyan('Project:')} ${report.projectPath}`);
console.log(`${chalk_1.default.cyan('Baseline:')} ${report.comparison.baseline}`);
console.log(`${chalk_1.default.cyan('Current:')} ${report.comparison.current}`);
console.log(`${chalk_1.default.cyan('Analyzed:')} ${report.comparison.timestamp.toISOString()}`);
console.log(`${chalk_1.default.cyan('Total Changes:')} ${report.changes.length}`);
}
/**
* Display impact summary with severity distribution
*/
function displayImpactSummary(impact) {
console.log('\n' + chalk_1.default.bold.red('šÆ IMPACT SUMMARY'));
console.log(chalk_1.default.red('-'.repeat(40)));
// Severity breakdown
console.log(chalk_1.default.bold('Severity Distribution:'));
const severities = ['critical', 'high', 'medium', 'low'];
severities.forEach(severity => {
const count = impact.bySeverity[severity] || 0;
const color = getSeverityColor(severity);
const icon = getSeverityIcon(severity);
console.log(` ${icon} ${color(severity.toUpperCase())}: ${count} changes`);
});
// Category breakdown
console.log(chalk_1.default.bold('\nCategory Distribution:'));
Object.entries(impact.byCategory).forEach(([category, count]) => {
const icon = getCategoryIcon(category);
console.log(` ${icon} ${chalk_1.default.cyan(category)}: ${count} changes`);
});
// Health score change
const healthDelta = impact.healthChange.delta;
const healthColor = healthDelta >= 0 ? chalk_1.default.green : chalk_1.default.red;
const healthIcon = healthDelta >= 0 ? 'š' : 'š';
console.log(`\n${healthIcon} ${chalk_1.default.bold('Health Score:')} ${impact.healthChange.before} ā ${impact.healthChange.after} (${healthColor(healthDelta > 0 ? '+' : '')}${healthDelta.toFixed(1)})`);
}
/**
* Display key metrics changes
*/
function displayMetricsChanges(report) {
console.log('\n' + chalk_1.default.bold.green('š KEY METRICS CHANGES'));
console.log(chalk_1.default.green('-'.repeat(40)));
const metrics = report.impact.keyMetrics;
displayMetricChange('Circular Dependencies', metrics.circularDependencies.before, metrics.circularDependencies.after, metrics.circularDependencies.delta, 'š');
displayMetricChange('Average Coupling', metrics.averageCoupling.before, metrics.averageCoupling.after, metrics.averageCoupling.delta, 'š', 1);
displayMetricChange('External Dependencies', metrics.externalDependencies.before, metrics.externalDependencies.after, metrics.externalDependencies.delta, 'š¦');
displayMetricChange('Module Count', metrics.moduleCount.before, metrics.moduleCount.after, metrics.moduleCount.delta, 'š');
}
/**
* Display individual metric change
*/
function displayMetricChange(name, before, after, delta, icon, decimals = 0) {
const deltaColor = delta > 0 ? chalk_1.default.red : delta < 0 ? chalk_1.default.green : chalk_1.default.gray;
const deltaSign = delta > 0 ? '+' : '';
const beforeStr = decimals > 0 ? before.toFixed(decimals) : before.toString();
const afterStr = decimals > 0 ? after.toFixed(decimals) : after.toString();
const deltaStr = decimals > 0 ? delta.toFixed(decimals) : delta.toString();
console.log(`${icon} ${chalk_1.default.cyan(name)}: ${beforeStr} ā ${afterStr} (${deltaColor(deltaSign)}${deltaColor(deltaStr)})`);
}
/**
* Display architectural changes with filtering
*/
function displayArchitecturalChanges(changes, options) {
if (changes.length === 0) {
console.log('\n' + chalk_1.default.bold.green('ā
NO ARCHITECTURAL CHANGES DETECTED'));
return;
}
console.log('\n' + chalk_1.default.bold.magenta('šļø ARCHITECTURAL CHANGES'));
console.log(chalk_1.default.magenta('-'.repeat(40)));
// Filter by minimum severity if specified
let filteredChanges = changes;
if (options.minSeverity) {
const severityOrder = ['low', 'medium', 'high', 'critical'];
const minIndex = severityOrder.indexOf(options.minSeverity);
filteredChanges = changes.filter(change => severityOrder.indexOf(change.severity) >= minIndex);
}
// Sort by severity (critical first)
const severityOrder = ['critical', 'high', 'medium', 'low'];
filteredChanges.sort((a, b) => severityOrder.indexOf(a.severity) - severityOrder.indexOf(b.severity));
filteredChanges.forEach((change, index) => {
displayArchitecturalChange(change, index + 1, options);
});
if (filteredChanges.length < changes.length) {
const hiddenCount = changes.length - filteredChanges.length;
console.log(chalk_1.default.gray(`\n... and ${hiddenCount} more lower-severity changes`));
}
}
/**
* Display individual architectural change
*/
function displayArchitecturalChange(change, index, options) {
const severityColor = getSeverityColor(change.severity);
const severityIcon = getSeverityIcon(change.severity);
const categoryIcon = getCategoryIcon(change.category);
console.log(`\n${index}. ${severityIcon} ${severityColor(change.severity.toUpperCase())} - ${categoryIcon} ${change.category}`);
console.log(` ${chalk_1.default.bold(change.description)}`);
if (options?.includeImpact !== false) {
const impact = change.impact;
console.log(` ${chalk_1.default.cyan('Risk:')} ${impact.riskLevel} | ${chalk_1.default.cyan('Overall Score:')} ${impact.overallScore > 0 ? '+' : ''}${impact.overallScore}`);
console.log(` ${chalk_1.default.cyan('Reasoning:')} ${impact.reasoning}`);
if (impact.affectedAreas.length > 0) {
console.log(` ${chalk_1.default.cyan('Affected Areas:')} ${impact.affectedAreas.join(', ')}`);
}
}
if (change.affected.length > 0) {
console.log(` ${chalk_1.default.cyan('Affected Modules:')} ${change.affected.slice(0, 3).join(', ')}${change.affected.length > 3 ? '...' : ''}`);
}
}
/**
* Display recommendations
*/
function displayRecommendations(recommendations) {
if (recommendations.length === 0) {
return;
}
console.log('\n' + chalk_1.default.bold.blue('š” RECOMMENDATIONS'));
console.log(chalk_1.default.blue('-'.repeat(40)));
// Sort by priority
const priorityOrder = ['critical', 'high', 'medium', 'low'];
const sortedRecs = recommendations.sort((a, b) => priorityOrder.indexOf(a.priority) - priorityOrder.indexOf(b.priority));
sortedRecs.forEach((rec, index) => {
displayRecommendation(rec, index + 1);
});
}
/**
* Display individual recommendation
*/
function displayRecommendation(rec, index) {
const priorityColor = getSeverityColor(rec.priority);
const typeIcon = getRecommendationTypeIcon(rec.type);
const effortIcon = getEffortIcon(rec.effort);
console.log(`\n${index}. ${typeIcon} ${priorityColor(rec.priority.toUpperCase())} - ${rec.title}`);
console.log(` ${chalk_1.default.gray(rec.description)}`);
console.log(` ${effortIcon} ${chalk_1.default.cyan('Effort:')} ${rec.effort} | ${chalk_1.default.cyan('Impact:')} ${rec.expectedImpact}`);
if (rec.actions.length > 0) {
console.log(` ${chalk_1.default.cyan('Actions:')}`);
rec.actions.forEach(action => {
console.log(` ⢠${action}`);
});
}
}
/**
* Display health score analysis
*/
function displayHealthScoreAnalysis(impact) {
console.log('\n' + chalk_1.default.bold.cyan('š„ ARCHITECTURAL HEALTH ANALYSIS'));
console.log(chalk_1.default.cyan('-'.repeat(40)));
const healthDelta = impact.healthChange.delta;
const currentHealth = impact.healthChange.after;
let healthStatus = '';
let recommendations = '';
if (currentHealth >= 80) {
healthStatus = chalk_1.default.green('EXCELLENT');
recommendations = 'Continue following good practices';
}
else if (currentHealth >= 60) {
healthStatus = chalk_1.default.yellow('GOOD');
recommendations = 'Minor improvements recommended';
}
else if (currentHealth >= 40) {
healthStatus = chalk_1.default.yellow('FAIR');
recommendations = 'Significant refactoring needed';
}
else {
healthStatus = chalk_1.default.red('POOR');
recommendations =
'Critical architectural issues require immediate attention';
}
console.log(`${chalk_1.default.cyan('Current Health:')} ${currentHealth.toFixed(1)}/100 (${healthStatus})`);
console.log(`${chalk_1.default.cyan('Health Trend:')} ${healthDelta >= 0 ? 'š Improving' : 'š Declining'} (${healthDelta > 0 ? '+' : ''}${healthDelta.toFixed(1)})`);
console.log(`${chalk_1.default.cyan('Recommendation:')} ${recommendations}`);
}
/**
* Get color for severity level
*/
function getSeverityColor(severity) {
switch (severity) {
case 'critical':
return chalk_1.default.red.bold;
case 'high':
return chalk_1.default.red;
case 'medium':
return chalk_1.default.yellow;
case 'low':
return chalk_1.default.green;
default:
return chalk_1.default.gray;
}
}
/**
* Get icon for severity level
*/
function getSeverityIcon(severity) {
switch (severity) {
case 'critical':
return 'šØ';
case 'high':
return 'ā ļø';
case 'medium':
return 'ā”';
case 'low':
return 'š”';
default:
return 'š';
}
}
/**
* Get icon for category
*/
function getCategoryIcon(category) {
switch (category) {
case 'dependencies':
return 'š';
case 'architecture':
return 'šļø';
case 'coupling':
return 'š';
case 'complexity':
return 'š§©';
case 'external':
return 'š¦';
case 'performance':
return 'ā”';
case 'maintainability':
return 'š§';
default:
return 'š';
}
}
/**
* Get icon for recommendation type
*/
function getRecommendationTypeIcon(type) {
switch (type) {
case 'fix-issue':
return 'š§';
case 'improve-architecture':
return 'šļø';
case 'refactor':
return 'ā»ļø';
case 'monitor':
return 'š';
default:
return 'š”';
}
}
/**
* Get icon for effort level
*/
function getEffortIcon(effort) {
switch (effort) {
case 'low':
return 'š¢';
case 'medium':
return 'š”';
case 'high':
return 'š“';
default:
return 'āŖ';
}
}
//# sourceMappingURL=graph-diff-cli.js.map