agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
220 lines (196 loc) • 8.97 kB
JavaScript
#!/usr/bin/env node
/**
* @file Command-line interface for scalability analysis and bottleneck detection
* @description Single responsibility: Provide interactive CLI for identifying scalability concerns
*
* This CLI tool serves as the scalability analysis interface for the AgentSqripts platform,
* detecting blocking operations, N+1 query patterns, unbounded memory growth, and other
* performance bottlenecks that impact application scalability under load. It implements
* severity-based filtering, category analysis, and comprehensive reporting to support
* systematic scalability optimization workflows.
*
* Design rationale:
* - Scalability-focused analysis enables proactive performance planning
* - Category filtering (API, Database, Infrastructure) enables targeted optimization
* - Severity thresholds help prioritize critical scalability threats
* - Multiple output formats support both development analysis and CI/CD integration
* - Comprehensive detection coverage from database patterns to system resource usage
*/
const fs = require('fs');
const { promises: fsPromises } = require('fs');
const path = require('path');
const { analyzeProjectScalability, analyzeFileScalability } = require('../lib/scalability/analyzeScalability');
const { formatResults, getGradeEmoji, formatSeverity } = require('./lib/commonFormatters');
const { createSummaryFormatter, createRecommendationsSection, createTopIssuesSection } = require('./lib/summaryFormatter');
const { createDetailedFormatter, formatIssueWithIcons } = require('./lib/detailedFormatter');
/**
* Display help information
*/
const { createHelpFunction } = require('./lib/helpFormatter');
const { parseArgs: sharedParseArgs } = require('./lib/argumentParser');
const { handleAnalysisError } = require('./lib/errorHandler');
const showHelp = createHelpFunction({
command: 'analyze-scalability.js',
description: 'Analyzes code for scalability bottlenecks including blocking sync operations, N+1 queries,\nunbounded memory growth, and other performance issues that can hurt application scalability.',
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, CRITICAL (default: LOW)' },
{ flag: '--category <cat>', description: 'Filter by category: API, Database, Infrastructure (default: all)' },
{ flag: '--max-files <num>', description: 'Maximum number of files to analyze (default: all files)' },
{ flag: '--help', description: 'Show this help message' }
],
modes: ' file Analyze a single file\n project Analyze entire project (default)',
examples: [
'node analyze-scalability.js .',
'node analyze-scalability.js --severity HIGH src/',
'node analyze-scalability.js --output-format json --extensions .js,.ts .',
'node analyze-scalability.js --category Database --output-format detailed src/'
],
output: ' The tool identifies scalability bottlenecks by checking:\n - Blocking synchronous operations (fs.readFileSync, execSync)\n - N+1 query patterns (database calls in loops)\n - Per-request file I/O operations\n - Unbounded memory growth patterns\n - CPU-intensive operations in request paths\n - Inefficient string operations',
sections: {
'ISSUE TYPES': ' 🚨 CRITICAL: Immediate scalability threats\n ⚠️ HIGH: Major bottlenecks affecting performance\n 📊 MEDIUM: Moderate scalability concerns\n 📝 LOW: Minor optimizations',
'CATEGORIES': ' 📡 API: Request/response path issues\n 🗄️ Database: Data access bottlenecks\n 🏗️ Infrastructure: System resource issues'
}
});
// Removed duplicate formatResults - now using shared version from commonFormatters
// Create custom summary formatter using shared utility
const formatSummary = createSummaryFormatter({
title: '🚨 Scalability Analysis Results',
scoreField: 'scalabilityScore',
gradeField: 'scalabilityGrade',
filesField: 'totalFiles',
issuesField: 'totalIssues',
customMetrics: [
{ field: 'filesWithIssues', icon: '⚠️', label: 'Files with Issues' }
],
breakdowns: [
{
field: 'severityBreakdown',
type: 'severity',
icon: '📈',
title: 'Issue Breakdown',
levels: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
},
{
field: 'categoryBreakdown',
type: 'category',
icon: '🏷️',
title: 'Category Breakdown',
icons: {
'API': '📡',
'Database': '🗄️',
'Infrastructure': '🏗️'
}
}
],
customSections: [
createRecommendationsSection(),
createTopIssuesSection({
field: 'issues',
title: 'Top Scalability Issues',
limit: 10,
formatItem: (issue, i) => {
const severityIcon = issue.severity === 'CRITICAL' ? '🚨' :
issue.severity === 'HIGH' ? '⚠️' :
issue.severity === 'MEDIUM' ? '📊' : '📝';
const categoryIcon = issue.category === 'API' ? '📡' :
issue.category === 'Database' ? '🗄️' : '🏗️';
const fileInfo = issue.file ? `\n 📁 File: ${path.relative('.', issue.file)}` : '';
const lineInfo = issue.line ? `:${issue.line}` : '';
return ` ${i + 1}. ${severityIcon} ${categoryIcon} ${issue.type}${fileInfo}${lineInfo}\n 📍 ${issue.summary}\n 💡 ${issue.recommendation}\n 🎯 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 Scalability Analysis',
formatSummary: formatSummary,
filesField: 'files',
issuesField: 'issues',
formatFile: (fileData) => {
return `📄 ${path.relative('.', fileData.file)} (Score: ${fileData.scalabilityScore}/100)\n`;
},
formatIssue: (issue) => {
const icons = {
severity: { 'CRITICAL': '🚨', 'HIGH': '⚠️', 'MEDIUM': '📊', 'LOW': '📝' },
category: { 'API': '📡', 'Database': '🗄️', 'Infrastructure': '🏗️' }
};
const lines = formatIssueWithIcons(issue, icons);
// Add pattern info if available
if (issue.pattern) {
lines.splice(1, 0, ` 📊 Pattern: ${issue.pattern}`);
}
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,
maxFiles: Infinity
},
flags: {
extensions: { type: 'list' },
outputFormat: { type: 'string' },
severity: { type: 'string', transform: (v) => v.toUpperCase() },
category: { type: 'string' },
maxFiles: { type: 'number' }
}
});
if (error) {
const { logAnalysisError } = require('../lib/utils/errorMessages');
logAnalysisError('scalability', error);
process.exit(1);
}
const { extensions, outputFormat, severity, category, maxFiles } = parsedOptions;
const targetPath = parsedPath;
try {
// Check if target is a file or directory
const stat = await fsPromises.stat(targetPath);
let results;
if (stat.isFile()) {
// Analyze single file
results = await analyzeFileScalability(targetPath);
} else {
// Analyze project
results = await analyzeProjectScalability(targetPath, {
extensions,
excludePatterns: ['node_modules', '.git', 'dist', 'build', 'coverage'],
maxFiles // Use CLI option or default to all files
});
}
// Output results
const formatted = formatResults(results, outputFormat, { severity, category }, formatSummary, formatDetailedNew);
console.log(formatted);
// Exit with error code if critical issues found
const hasCritical = results.summary ?
results.summary.severityBreakdown.CRITICAL > 0 :
results.issues.some(i => i.severity === 'CRITICAL');
if (hasCritical) {
process.exit(1);
}
} catch (error) {
handleAnalysisError(error, 'scalability');
}
}
if (require.main === module) {
main().catch(error => { console.error("Fatal error:", error); process.exit(1); });
}