UNPKG

arela

Version:

AI-powered CTO with multi-agent orchestration, code summarization, visual testing (web + mobile) for blazing fast development.

310 lines 13.2 kB
/** * Flow Analyzer Module * Main orchestration for flow analysis: * - Discovers entry points * - Traces execution paths * - Checks standards * - Generates refactor proposals */ import fs from 'fs-extra'; import path from 'path'; import { glob } from 'glob'; import { discoverEntryPoints } from './discovery.js'; import { traceExecutionPaths } from './tracer.js'; import { checkStandards } from './standards.js'; /** * Analyze a code flow from entry points through the codebase */ export async function analyzeFlow(config) { const startTime = Date.now(); // Step 1: Discover entry points const discoveryResult = await discoverEntryPoints(config.cwd); const entryPoints = discoveryResult.entryPoints; // Step 2: Trace execution paths const executionPaths = []; const allNodes = []; for (const entryPoint of entryPoints) { try { const traceResult = await traceExecutionPaths(config.cwd, entryPoint.name); executionPaths.push(...traceResult.executionPaths); allNodes.push(...traceResult.nodes); } catch (error) { if (config.verbose) { console.error(`Failed to trace ${entryPoint.name}:`, error); } } } // Step 3: Check standards across all files const standardViolations = []; const allFiles = await glob('**/*.{ts,tsx,js,jsx}', { cwd: config.cwd, ignore: ['node_modules/**', 'dist/**', '**/*.test.*', '**/*.spec.*'], }); for (const file of allFiles) { const filePath = path.join(config.cwd, file); try { const content = await fs.readFile(filePath, 'utf-8'); const result = checkStandards(content, file); standardViolations.push(...result.violations); } catch (error) { // Skip files that can't be read } } // Step 4: Calculate scores const scores = calculateScores(standardViolations); // Step 5: Generate refactor proposals const refactorProposals = generateRefactorProposals(entryPoints, executionPaths, standardViolations, allFiles); // Step 6: Generate recommendations const recommendations = generateRecommendations(standardViolations, refactorProposals, scores); // Step 7: Calculate average path depth const avgPathDepth = executionPaths.length > 0 ? executionPaths.reduce((sum, p) => sum + p.depth, 0) / executionPaths.length : 0; return { flowName: config.flowName, timestamp: new Date().toISOString(), entryPoints, executionPaths, standardViolations, refactorProposals, analysis: { totalEntryPoints: entryPoints.length, totalPaths: executionPaths.length, totalViolations: standardViolations.length, averagePathDepth: Math.round(avgPathDepth * 10) / 10, scores, recommendations, }, }; } /** * Calculate quality scores based on standard violations */ function calculateScores(violations) { const categories = ['security', 'ux', 'architecture', 'performance']; const scores = {}; for (const category of categories) { const categoryViolations = violations.filter(v => v.category === category); const criticalCount = categoryViolations.filter(v => v.severity === 'critical').length; const warningCount = categoryViolations.filter(v => v.severity === 'warning').length; // Calculate score: 100 - (critical * 20 + warning * 5) let score = 100 - (criticalCount * 20 + warningCount * 5); score = Math.max(0, Math.min(100, score)); scores[category] = score; } scores.overall = Math.round((scores.security + scores.ux + scores.architecture + scores.performance) / 4); return scores; } /** * Generate actionable refactor proposals */ function generateRefactorProposals(entryPoints, executionPaths, violations, files) { const proposals = []; let proposalId = 1; // Group violations by affected files const violationsByFile = new Map(); for (const violation of violations) { if (!violationsByFile.has(violation.location)) { violationsByFile.set(violation.location, []); } violationsByFile.get(violation.location).push(violation); } // Create proposals for groups of violations for (const [filePath, fileViolations] of violationsByFile) { const criticalViolations = fileViolations.filter((v) => v.severity === 'critical'); const warningViolations = fileViolations.filter((v) => v.severity === 'warning'); // Security refactor proposal if (criticalViolations.length > 0) { const securityViolations = criticalViolations.filter((v) => v.category === 'security'); if (securityViolations.length > 0) { proposals.push({ id: `refactor_sec_${proposalId++}`, title: `Security Hardening: ${path.basename(filePath)}`, description: `Address ${securityViolations.length} security vulnerabilities`, affectedFiles: [filePath], complexity: 'medium', priority: 10, estimatedEffort: '2-4 hours', impact: { security: `Fix ${securityViolations.length} critical issues`, }, implementationSteps: securityViolations.map((v) => v.refactorProposal), }); } } // Architecture refactor proposal const archViolations = fileViolations.filter((v) => v.category === 'architecture'); if (archViolations.length >= 2) { proposals.push({ id: `refactor_arch_${proposalId++}`, title: `Architecture Improvement: ${path.basename(filePath)}`, description: `Improve module structure and dependencies`, affectedFiles: [filePath], complexity: 'complex', priority: 7, estimatedEffort: '4-8 hours', impact: { architecture: 'Better modularity and testability', performance: 'Reduced coupling', }, implementationSteps: archViolations.map((v) => v.refactorProposal), }); } // Performance optimization proposal const perfViolations = fileViolations.filter((v) => v.category === 'performance'); if (perfViolations.length >= 1) { proposals.push({ id: `refactor_perf_${proposalId++}`, title: `Performance Optimization: ${path.basename(filePath)}`, description: `Optimize runtime performance`, affectedFiles: [filePath], complexity: 'simple', priority: 6, estimatedEffort: '1-2 hours', impact: { performance: 'Improved load times and responsiveness', }, implementationSteps: perfViolations.map((v) => v.refactorProposal), }); } } // Generate holistic proposals based on execution paths if (executionPaths.length > 5) { proposals.push({ id: `refactor_flow_${proposalId++}`, title: 'Simplify Execution Flow', description: `Reduce complexity from ${executionPaths.length} execution paths to fewer, clearer flows`, affectedFiles: Array.from(new Set(executionPaths.flatMap(p => p.path))), complexity: 'complex', priority: 8, estimatedEffort: '8-16 hours', impact: { architecture: 'Simpler, more maintainable code flow', performance: 'Reduced cognitive load', }, implementationSteps: [ 'Map out critical vs. optional execution paths', 'Extract common patterns into reusable functions', 'Consider using a state machine for complex flows', 'Add comprehensive logging for debugging', ], }); } // Entry point consolidation if (entryPoints.length > 10) { proposals.push({ id: `refactor_ep_${proposalId++}`, title: 'Consolidate Entry Points', description: `Consolidate ${entryPoints.length} entry points into unified interfaces`, affectedFiles: entryPoints.map(ep => ep.path), complexity: 'medium', priority: 5, estimatedEffort: '4-6 hours', impact: { architecture: 'Unified API surface', }, implementationSteps: [ 'Identify entry point patterns', 'Create routing/dispatch layer', 'Consolidate handler signatures', 'Update call sites', ], }); } return proposals.sort((a, b) => b.priority - a.priority); } /** * Generate high-level recommendations */ function generateRecommendations(violations, proposals, scores) { const recommendations = []; // Security recommendations if (scores.security < 70) { recommendations.push('🔐 Security audit needed: Add input validation, secrets management, and error handling'); } // Architecture recommendations if (scores.architecture < 70) { recommendations.push('🏗️ Refactor for better architecture: Reduce coupling, improve modularity, and add types'); } // Performance recommendations if (scores.performance < 70) { recommendations.push('⚡ Performance optimizations available: Add memoization, lazy loading, and debouncing'); } // UX recommendations if (scores.ux < 70) { recommendations.push('🎨 Improve user experience: Add loading states, error messages, and accessibility'); } // Overall quality if (scores.overall < 60) { recommendations.push('⚠️ Overall code quality is below target. Start with highest priority refactoring proposals.'); } else if (scores.overall >= 80) { recommendations.push('✨ Good code quality! Focus on top-priority proposals for continuous improvement.'); } // Based on violations if (violations.length > 20) { recommendations.push('📋 High number of violations detected. Consider systematic refactoring approach.'); } // Based on proposals if (proposals.filter(p => p.priority >= 8).length > 0) { recommendations.push('🎯 Critical improvements available. Prioritize high-impact refactoring proposals.'); } return recommendations; } /** * Export analysis result as JSON for further processing */ export function exportAnalysis(result, outputPath) { fs.writeFileSync(outputPath, JSON.stringify(result, null, 2)); } /** * Generate a markdown report */ export function generateMarkdownReport(result) { let report = `# Flow Analysis Report: ${result.flowName}\n\n`; report += `**Generated**: ${new Date(result.timestamp).toLocaleString()}\n\n`; // Summary report += `## Summary\n\n`; report += `| Metric | Value |\n`; report += `|--------|-------|\n`; report += `| Overall Score | ${result.analysis.scores.overall}/100 |\n`; report += `| Security | ${result.analysis.scores.security}/100 |\n`; report += `| UX | ${result.analysis.scores.ux}/100 |\n`; report += `| Architecture | ${result.analysis.scores.architecture}/100 |\n`; report += `| Performance | ${result.analysis.scores.performance}/100 |\n`; report += `| Entry Points | ${result.analysis.totalEntryPoints} |\n`; report += `| Execution Paths | ${result.analysis.totalPaths} |\n`; report += `| Violations Found | ${result.analysis.totalViolations} |\n\n`; // Recommendations report += `## Recommendations\n\n`; for (const rec of result.analysis.recommendations) { report += `- ${rec}\n`; } report += `\n`; // Top Violations report += `## Top Violations\n\n`; const topViolations = result.standardViolations.slice(0, 10); for (const violation of topViolations) { report += `### ${violation.standard} (${violation.severity})\n`; report += `- **File**: ${violation.location}\n`; report += `- **Description**: ${violation.description}\n`; report += `- **Fix**: ${violation.refactorProposal}\n\n`; } // Refactor Proposals report += `## Refactor Proposals\n\n`; for (const proposal of result.refactorProposals.slice(0, 5)) { report += `### ${proposal.title}\n`; report += `- **Complexity**: ${proposal.complexity}\n`; report += `- **Estimated Effort**: ${proposal.estimatedEffort}\n`; report += `- **Priority**: ${proposal.priority}/10\n`; report += `- **Steps**:\n`; for (const step of proposal.implementationSteps.slice(0, 3)) { report += ` 1. ${step}\n`; } report += `\n`; } return report; } //# sourceMappingURL=analyzer.js.map