UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

217 lines (194 loc) • 9.1 kB
#!/usr/bin/env node /** * @file Command-line interface for performance analysis and optimization opportunity detection * @description Single responsibility: Provide interactive CLI for identifying performance bottlenecks * * This CLI tool serves as the performance analysis interface for the AgentSqripts platform, * detecting algorithmic inefficiencies, I/O bottlenecks, memory issues, and concurrency * optimization opportunities. It implements severity filtering, category-based analysis, * and effort-based prioritization to support performance optimization workflows. * * Design rationale: * - Performance-focused CLI design enables systematic optimization workflows * - Category filtering allows targeted optimization efforts (Algorithm, I/O, Memory, etc.) * - Effort-level filtering helps prioritize quick wins vs complex refactoring * - Quantified impact metrics enable ROI-based optimization decisions * - Multiple output formats support both human analysis and automated tooling */ const fs = require('fs'); const path = require('path'); const { analyzeProjectPerformance, analyzeFilePerformance } = require('../lib/performance/analyzePerformance'); const { formatResults, getGradeEmoji, formatSeverity } = require('./lib/commonFormatters'); const { createHelpFunction } = require('./lib/helpFormatter'); const { parseArgs: sharedParseArgs } = require('./lib/argumentParser'); const { handleAnalysisError, exitOnSeverityThreshold } = require('./lib/errorHandler'); const { createSummaryFormatter, createRecommendationsSection, createTopIssuesSection } = require('./lib/summaryFormatter'); const { createDetailedFormatter, formatIssueWithIcons } = require('./lib/detailedFormatter'); /** * Display help information */ const showHelp = createHelpFunction({ command: 'analyze-performance.js', description: 'Analyzes code for performance bottlenecks including O(n²) algorithmic patterns, blocking sync I/O,\nJSON operations in loops, serial awaits, large inline objects, and other optimization opportunities.', options: [ { flag: '--extensions <exts>', description: 'Comma-separated list of file extensions (default: .js,.ts,.jsx,.tsx)' }, { flag: '--output-format <fmt>', description: 'Output format: json, summary, detailed (default: summary)' }, { flag: '--severity <level>', description: 'Minimum severity to report: LOW, MEDIUM, HIGH (default: LOW)' }, { flag: '--category <cat>', description: 'Filter by category: Algorithm, I/O, CPU, Memory, Concurrency (default: all)' }, { flag: '--effort <level>', description: 'Filter by effort level: 1, 2, 3 (default: all)' }, { flag: '--help', description: 'Show this help message' } ], modes: ' file Analyze a single file\n project Analyze entire project (default)', examples: [ 'node analyze-performance.js .', 'node analyze-performance.js --severity HIGH src/', 'node analyze-performance.js --output-format json --extensions .js,.ts .', 'node analyze-performance.js --category Algorithm --effort 1 src/' ], output: ' The tool identifies performance bottlenecks by checking:\n - O(n²) algorithmic patterns (nested loops, inefficient array methods)\n - Blocking synchronous I/O operations (fs.readFileSync, execSync)\n - JSON operations in hot paths (stringify/parse in loops)\n - Serial await chains that could be parallelized\n - Large inline objects and strings (memory optimization)\n - Unbounded array growth patterns\n - Inefficient regex compilation in loops', sections: { 'ISSUE TYPES': ' šŸ”„ HIGH: Major bottlenecks with significant performance impact\n ⚔ MEDIUM: Moderate optimization opportunities\n šŸ’” LOW: Minor performance improvements', 'CATEGORIES': ' 🧮 Algorithm: Computational complexity issues\n šŸ’¾ I/O: Input/output bottlenecks\n šŸ”§ CPU: CPU-intensive operations\n 🧠 Memory: Memory usage optimization\n ⚔ Concurrency: Parallelization opportunities', 'EFFORT LEVELS': ' 1: Quick wins (easy fixes)\n 2: Moderate effort required\n 3: Complex refactoring needed' } }); // Removed duplicate formatResults - now using shared version from commonFormatters // Create custom summary formatter using shared utility const formatSummary = createSummaryFormatter({ title: 'šŸš€ Performance Analysis Results', scoreField: 'performanceScore', gradeField: 'performanceGrade', filesField: 'filesAnalyzed', issuesField: 'totalIssues', showEffort: true, effortField: 'totalEffort', customMetrics: [ { field: 'filesWithIssues', icon: 'āš ļø', label: 'Files with Issues' } ], breakdowns: [ { field: 'severityBreakdown', type: 'severity', icon: 'šŸ“ˆ', title: 'Issue Breakdown' }, { field: 'categoryBreakdown', type: 'category', icon: 'šŸ·ļø', title: 'Category Breakdown', icons: { 'Algorithm': '🧮', 'I/O': 'šŸ’¾', 'CPU': 'šŸ”§', 'Memory': '🧠', 'Concurrency': '⚔' } } ], customSections: [ createRecommendationsSection(), createTopIssuesSection({ field: 'topIssues', title: 'Top Performance Issues', limit: 20, formatItem: (issue, i) => { const severityIcon = issue.severity === 'HIGH' ? 'šŸ”„' : issue.severity === 'MEDIUM' ? '⚔' : 'šŸ’”'; const categoryIcon = issue.category === 'Algorithm' ? '🧮' : issue.category === 'I/O' ? 'šŸ’¾' : issue.category === 'CPU' ? 'šŸ”§' : issue.category === 'Memory' ? '🧠' : '⚔'; return ` ${i + 1}. ${severityIcon} ${categoryIcon} ${issue.type}\n šŸ“ ${issue.summary}\n šŸ’” ${issue.recommendation}\n ā±ļø Effort: ${issue.effort}/3 | šŸŽÆ Impact: ${issue.impact}`; } }) ] }); // Old formatSummary implementation fully removed - using shared formatter // Old formatDetailed removed - using shared detailed formatter // Replace with shared detailed formatter const formatDetailedNew = createDetailedFormatter({ title: 'šŸ” Detailed Performance Analysis', formatSummary: formatSummary, filesField: 'files', issuesField: 'issues', formatFile: (fileData) => { return `šŸ“„ ${path.relative('.', fileData.file)} (Score: ${fileData.performanceScore}/100, Effort: ${fileData.metrics.totalEffort})\n`; }, formatIssue: (issue) => { const icons = { severity: { 'HIGH': 'šŸ”„', 'MEDIUM': '⚔', 'LOW': 'šŸ’”' }, category: { 'Algorithm': '🧮', 'I/O': 'šŸ’¾', 'CPU': 'šŸ”§', 'Memory': '🧠', 'Concurrency': '⚔' } }; const lines = formatIssueWithIcons(issue, icons); // Add code snippet if available if (issue.code) { lines.splice(1, 0, ` šŸ“‹ Code: ${issue.code}`); } return lines; } }); /** * Main function */ async function main() { const { getProcessArgs } = require('../lib/utils/processHelpers'); const args = getProcessArgs(); const { shouldShowHelp } = require('../lib/utils/cliHelpers'); if (shouldShowHelp(args)) { showHelp(); return; } // Parse arguments using shared parser const { options: parsedOptions, targetPath: parsedPath, error } = sharedParseArgs(args, { defaults: { extensions: ['.js', '.ts', '.jsx', '.tsx'], outputFormat: 'summary', severity: 'LOW', category: null, effort: null }, flags: { extensions: { type: 'list' }, outputFormat: { type: 'string' }, severity: { type: 'string', transform: (v) => v.toUpperCase() }, category: { type: 'string' }, effort: { type: 'string' } } }); if (error) { const { logAnalysisError } = require('../lib/utils/errorMessages'); logAnalysisError('performance', error); process.exit(1); } const { extensions, outputFormat, severity, category, effort } = parsedOptions; const targetPath = parsedPath; try { // Check if target is a file or directory const stat = await fs.promises.stat(targetPath); let results; if (stat.isFile()) { // Analyze single file results = await analyzeFilePerformance(targetPath); } else { // Analyze project results = await analyzeProjectPerformance(targetPath, { extensions, excludePatterns: ['node_modules', '.git', 'dist', 'build', 'coverage'], maxFiles: Infinity // Enable unlimited file processing }); } // Output results const formatted = formatResults(results, outputFormat, { severity, category, effort }, formatSummary, formatDetailedNew); console.log(formatted); // Exit with error code if high-impact issues found exitOnSeverityThreshold(results); } catch (error) { handleAnalysisError(error, 'performance'); } } // Export main function for testing module.exports = { main }; if (require.main === module) { main().catch(error => { console.error("Fatal error:", error); process.exit(1); }); }