UNPKG

@five-vm/cli

Version:

High-performance CLI for Five VM development with WebAssembly integration

455 lines (450 loc) 17.8 kB
/** * Five CLI Analyze Command * * Advanced bytecode analysis with security scanning, performance profiling, * and optimization recommendations. */ import chalk from 'chalk'; import ora from 'ora'; import { FiveCompilerWasm } from '../wasm/compiler.js'; import { FiveFileManager } from '../utils/FiveFileManager.js'; /** * Five analyze command implementation */ export const analyzeCommand = { name: 'analyze', description: 'Analyze Five VM bytecode for optimization and security', aliases: ['analysis', 'inspect'], options: [ { flags: '--security', description: 'Perform security analysis', defaultValue: false }, { flags: '--performance', description: 'Analyze performance characteristics', defaultValue: false }, { flags: '--optimization', description: 'Show optimization opportunities', defaultValue: false }, { flags: '--all', description: 'Perform all types of analysis', defaultValue: false }, { flags: '--format <format>', description: 'Output format', choices: ['text', 'json', 'html'], defaultValue: 'text' }, { flags: '--output <file>', description: 'Save analysis report to file', required: false }, { flags: '--verbose', description: 'Show detailed analysis information', defaultValue: false } ], arguments: [ { name: 'bytecode', description: 'Five VM bytecode file (.bin)', required: true } ], examples: [ { command: 'five analyze program.bin', description: 'Basic bytecode analysis' }, { command: 'five analyze program.bin --all --format json', description: 'Complete analysis with JSON output' }, { command: 'five analyze program.bin --security --output report.html', description: 'Security analysis with HTML report' }, { command: 'five analyze program.bin --performance --verbose', description: 'Detailed performance analysis' } ], handler: async (args, options, context) => { const { logger, wasmManager } = context; try { // Initialize WASM compiler for analysis const spinner = ora('Initializing Five analyzer...').start(); const compiler = new FiveCompilerWasm(logger); await compiler.initialize(); spinner.succeed('Five analyzer initialized'); // Load bytecode const bytecodeFile = args[0]; // Load file using centralized manager const fileManager = FiveFileManager.getInstance(); const loadedFile = await fileManager.loadFile(bytecodeFile, { validateFormat: true }); logger.info(`Analyzing ${loadedFile.format.toUpperCase()} file: ${loadedFile.bytecode.length} bytes from ${bytecodeFile}`); // Show ABI info if available if (loadedFile.abi) { const functionCount = Object.keys(loadedFile.abi.functions || {}).length; logger.info(`📋 Functions to analyze: ${functionCount}`); } // Perform analysis spinner.start('Analyzing bytecode...'); const analysis = await compiler.analyzeBytecode(loadedFile.bytecode); spinner.succeed('Analysis completed'); // Display results await displayAnalysisResults(analysis, options, logger); } catch (error) { logger.error('Analysis failed:', error); throw error; } } }; /** * Display analysis results in specified format */ async function displayAnalysisResults(analysis, options, logger) { if (options.format === 'json') { const output = JSON.stringify(analysis, null, 2); if (options.output) { const { writeFile } = await import('fs/promises'); await writeFile(options.output, output); logger.info(`Analysis saved to ${options.output}`); } else { console.log(output); } return; } if (options.format === 'html') { const htmlReport = generateHtmlReport(analysis); if (options.output) { const { writeFile } = await import('fs/promises'); await writeFile(options.output, htmlReport); logger.info(`HTML report saved to ${options.output}`); } else { console.log(htmlReport); } return; } // Text format output displayTextAnalysis(analysis, options); } /** * Display analysis in text format */ function displayTextAnalysis(analysis, options) { console.log('\n' + chalk.bold('Five VM Bytecode Analysis')); console.log('='.repeat(50)); // Basic Information console.log('\n' + chalk.bold('Basic Information:')); console.log(` Instructions: ${analysis.instructionCount}`); console.log(` Functions: ${analysis.functionCount}`); console.log(` Jump Targets: ${analysis.jumpTargets.length}`); // Complexity Metrics if (analysis.complexity) { console.log('\n' + chalk.bold('Complexity Metrics:')); console.log(` Cyclomatic Complexity: ${analysis.complexity.cyclomaticComplexity}`); console.log(` Nesting Depth: ${analysis.complexity.nestingDepth}`); console.log(` Halstead Complexity: ${analysis.complexity.halsteadComplexity}`); console.log(` Maintainability Index: ${analysis.complexity.maintainabilityIndex}`); } // Call Graph if (options.verbose && analysis.callGraph.length > 0) { console.log('\n' + chalk.bold('Call Graph:')); for (const node of analysis.callGraph.slice(0, 10)) { console.log(` ${node.functionName}:`); console.log(` Calls: ${node.callsTo.join(', ') || 'none'}`); console.log(` Called by: ${node.calledBy.join(', ') || 'none'}`); console.log(` Instructions: ${node.instructionCount}`); console.log(` Complexity: ${node.complexity}`); } if (analysis.callGraph.length > 10) { console.log(` ... and ${analysis.callGraph.length - 10} more functions`); } } // Optimization Opportunities if ((options.optimization || options.all) && analysis.optimizationOpportunities.length > 0) { console.log('\n' + chalk.bold('Optimization Opportunities:')); const grouped = groupBy(analysis.optimizationOpportunities, 'priority'); for (const priority of ['high', 'medium', 'low']) { const opportunities = grouped[priority] || []; if (opportunities.length > 0) { console.log(`\n ${chalk.yellow(priority.toUpperCase())} Priority:`); for (const opp of opportunities.slice(0, 5)) { console.log(` • ${opp.description}`); console.log(` Location: ${opp.location}`); console.log(` Estimated improvement: ${opp.estimatedImprovement}`); if (options.verbose) { console.log(` Type: ${opp.type}`); } } if (opportunities.length > 5) { console.log(` ... and ${opportunities.length - 5} more`); } } } } // Security Issues if ((options.security || options.all) && analysis.securityIssues.length > 0) { console.log('\n' + chalk.bold('Security Analysis:')); const grouped = groupBy(analysis.securityIssues, 'severity'); for (const severity of ['critical', 'high', 'medium', 'low']) { const issues = grouped[severity] || []; if (issues.length > 0) { const color = getSecurityColor(severity); console.log(`\n ${color(severity.toUpperCase())} Severity:`); for (const issue of issues) { console.log(` ${getSecurityIcon(severity)} ${issue.description}`); console.log(` Location: ${issue.location}`); console.log(` Category: ${issue.category}`); if (options.verbose) { console.log(` Recommendation: ${issue.recommendation}`); } } } } } // Performance Analysis if ((options.performance || options.all)) { console.log('\n' + chalk.bold('Performance Analysis:')); // Estimate compute units const estimatedCU = estimateComputeUnits(analysis); console.log(` Estimated Compute Units: ${estimatedCU}`); // Memory usage estimation const memoryEstimate = estimateMemoryUsage(analysis); console.log(` Estimated Memory Usage: ${memoryEstimate} bytes`); // Performance characteristics const characteristics = analyzePerformanceCharacteristics(analysis); console.log(` Performance Profile: ${characteristics.profile}`); console.log(` Bottlenecks: ${characteristics.bottlenecks.join(', ') || 'none detected'}`); if (options.verbose && characteristics.hotspots.length > 0) { console.log('\n Performance Hotspots:'); for (const hotspot of characteristics.hotspots.slice(0, 5)) { console.log(` • ${hotspot.location}: ${hotspot.impact}`); } } } // Summary console.log('\n' + chalk.bold('Summary:')); const score = calculateOverallScore(analysis); const scoreColor = score >= 80 ? chalk.green : score >= 60 ? chalk.yellow : chalk.red; console.log(` Overall Score: ${scoreColor(score)}/100`); const recommendations = generateRecommendations(analysis); if (recommendations.length > 0) { console.log('\n' + chalk.bold('Recommendations:')); for (const rec of recommendations.slice(0, 3)) { console.log(` • ${rec}`); } } } /** * Generate HTML report */ function generateHtmlReport(analysis) { return `<!DOCTYPE html> <html> <head> <title>Five VM Bytecode Analysis Report</title> <style> body { font-family: Arial, sans-serif; margin: 40px; } .header { background: #f4f4f4; padding: 20px; border-radius: 5px; } .section { margin: 20px 0; } .metric { display: inline-block; margin: 10px; padding: 10px; background: #e9e9e9; border-radius: 3px; } .high { color: #d32f2f; } .medium { color: #f57f17; } .low { color: #388e3c; } .critical { color: #b71c1c; font-weight: bold; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } </style> </head> <body> <div class="header"> <h1>Five VM Bytecode Analysis Report</h1> <p>Generated on ${new Date().toISOString()}</p> </div> <div class="section"> <h2>Basic Information</h2> <div class="metric">Instructions: ${analysis.instructionCount}</div> <div class="metric">Functions: ${analysis.functionCount}</div> <div class="metric">Jump Targets: ${analysis.jumpTargets.length}</div> </div> ${analysis.complexity ? ` <div class="section"> <h2>Complexity Metrics</h2> <div class="metric">Cyclomatic: ${analysis.complexity.cyclomaticComplexity}</div> <div class="metric">Nesting Depth: ${analysis.complexity.nestingDepth}</div> <div class="metric">Halstead: ${analysis.complexity.halsteadComplexity}</div> <div class="metric">Maintainability: ${analysis.complexity.maintainabilityIndex}</div> </div> ` : ''} ${analysis.optimizationOpportunities.length > 0 ? ` <div class="section"> <h2>Optimization Opportunities</h2> <table> <tr><th>Priority</th><th>Type</th><th>Description</th><th>Location</th><th>Improvement</th></tr> ${analysis.optimizationOpportunities.map(opp => ` <tr> <td class="${opp.priority}">${opp.priority}</td> <td>${opp.type}</td> <td>${opp.description}</td> <td>${opp.location}</td> <td>${opp.estimatedImprovement}</td> </tr> `).join('')} </table> </div> ` : ''} ${analysis.securityIssues.length > 0 ? ` <div class="section"> <h2>Security Issues</h2> <table> <tr><th>Severity</th><th>Category</th><th>Description</th><th>Location</th></tr> ${analysis.securityIssues.map(issue => ` <tr> <td class="${issue.severity}">${issue.severity}</td> <td>${issue.category}</td> <td>${issue.description}</td> <td>${issue.location}</td> </tr> `).join('')} </table> </div> ` : ''} </body> </html>`; } /** * Utility functions */ function groupBy(array, key) { return array.reduce((groups, item) => { const group = (groups[item[key]] = groups[item[key]] || []); group.push(item); return groups; }, {}); } function getSecurityColor(severity) { switch (severity) { case 'critical': return chalk.red.bold; case 'high': return chalk.red; case 'medium': return chalk.yellow; case 'low': return chalk.green; default: return chalk.gray; } } function getSecurityIcon(severity) { switch (severity) { case 'critical': return '🚨'; case 'high': return '⚠️'; case 'medium': return '⚡'; case 'low': return 'ℹ️'; default: return '•'; } } function estimateComputeUnits(analysis) { // Simple estimation based on instruction count and complexity const baseUnits = analysis.instructionCount * 2; const complexityMultiplier = analysis.complexity ? 1 + (analysis.complexity.cyclomaticComplexity * 0.1) : 1; return Math.round(baseUnits * complexityMultiplier); } function estimateMemoryUsage(analysis) { // Estimate based on instruction count and function count const instructionMemory = analysis.instructionCount * 4; // 4 bytes per instruction const functionMemory = analysis.functionCount * 32; // 32 bytes per function header const stackMemory = 1024; // Base stack allocation return instructionMemory + functionMemory + stackMemory; } function analyzePerformanceCharacteristics(analysis) { const profile = analysis.complexity?.cyclomaticComplexity > 10 ? 'Complex' : analysis.instructionCount > 1000 ? 'Large' : 'Simple'; const bottlenecks = []; const hotspots = []; // Analyze call graph for bottlenecks for (const node of analysis.callGraph) { if (node.complexity > 5) { bottlenecks.push(`Complex function: ${node.functionName}`); hotspots.push({ location: node.functionName, impact: `High complexity (${node.complexity})` }); } if (node.instructionCount > 100) { bottlenecks.push(`Large function: ${node.functionName}`); hotspots.push({ location: node.functionName, impact: `Many instructions (${node.instructionCount})` }); } } return { profile, bottlenecks, hotspots }; } function calculateOverallScore(analysis) { let score = 100; // Deduct for complexity if (analysis.complexity) { if (analysis.complexity.cyclomaticComplexity > 10) score -= 20; if (analysis.complexity.nestingDepth > 5) score -= 15; if (analysis.complexity.maintainabilityIndex < 50) score -= 25; } // Deduct for security issues for (const issue of analysis.securityIssues) { switch (issue.severity) { case 'critical': score -= 30; break; case 'high': score -= 20; break; case 'medium': score -= 10; break; case 'low': score -= 5; break; } } // Deduct for optimization opportunities const highPriorityOptimizations = analysis.optimizationOpportunities .filter(opp => opp.priority === 'high').length; score -= highPriorityOptimizations * 5; return Math.max(0, score); } function generateRecommendations(analysis) { const recommendations = []; if (analysis.complexity?.cyclomaticComplexity > 10) { recommendations.push('Consider refactoring complex functions to reduce cyclomatic complexity'); } const criticalSecurity = analysis.securityIssues.filter(issue => issue.severity === 'critical'); if (criticalSecurity.length > 0) { recommendations.push('Address critical security issues immediately'); } const highPriorityOpts = analysis.optimizationOpportunities.filter(opp => opp.priority === 'high'); if (highPriorityOpts.length > 0) { recommendations.push('Implement high-priority optimizations for better performance'); } if (analysis.instructionCount > 1000) { recommendations.push('Consider code splitting for large programs'); } return recommendations; } //# sourceMappingURL=analyze.js.map