mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
331 lines ⢠15.9 kB
JavaScript
import { Command } from 'commander';
import chalk from 'chalk';
import ora from 'ora';
import * as path from 'path';
import { AnalyzerConfigLoader } from '../config/analyzer-config.js';
import { SecurityAnalyzer } from '../analyzers/SecurityAnalyzer.js';
import { PerformanceAnalyzer } from '../analyzers/PerformanceAnalyzer.js';
import { DocumentationAnalyzer } from '../analyzers/DocumentationAnalyzer.js';
import { CodeQualityAnalyzer } from '../analyzers/CodeQualityAnalyzer.js';
import { CrossPlatformAnalyzer } from '../analyzers/CrossPlatformAnalyzer.js';
import { UnusedCodeAnalyzer } from '../analyzers/UnusedCodeAnalyzer.js';
import { DetailedReportGenerator } from '../reporting/DetailedReportGenerator.js';
export function createAnalyzeConfigurableCommand() {
return new Command('analyze-config')
.alias('ac')
.description('Run code analysis with configurable rules and thresholds')
.option('-s, --security', 'Run security analysis only')
.option('-p, --performance', 'Run performance analysis only')
.option('-d, --documentation', 'Run documentation analysis only')
.option('-q, --quality', 'Run code quality analysis only')
.option('-x, --cross-platform', 'Run cross-platform analysis only')
.option('-u, --unused', 'Run unused code analysis only')
.option('--config <path>', 'Path to custom analyzer configuration file')
.option('--save-config <path>', 'Save current configuration to file')
.option('--show-config', 'Display current configuration')
.option('--disable <analyzers>', 'Disable specific analyzers (comma-separated)')
.option('--threshold <name=value>', 'Override specific threshold', collectThresholds, {})
.option('--format <format>', 'Report format: console, markdown, html, json', 'console')
.option('--output <path>', 'Output report to file')
.option('--no-details', 'Skip detailed recommendations')
.option('--no-examples', 'Skip code examples in report')
.action(async (options) => {
const projectRoot = process.cwd();
// Load configuration
let configLoader;
if (options.config) {
configLoader = await AnalyzerConfigLoader.loadFromFile(options.config);
console.log(chalk.gray(`Using custom configuration from: ${options.config}`));
}
else {
const defaultConfigPath = path.join(projectRoot, '.mira-analyzer-config.json');
configLoader = await AnalyzerConfigLoader.loadFromFile(defaultConfigPath);
}
const config = configLoader.getConfig();
// Handle --show-config
if (options.showConfig) {
console.log(chalk.cyan('\nš Current Analyzer Configuration:\n'));
console.log(JSON.stringify(config, null, 2));
return;
}
// Handle --save-config
if (options.saveConfig) {
await configLoader.saveToFile(options.saveConfig);
console.log(chalk.green(`ā
Configuration saved to: ${options.saveConfig}`));
return;
}
// Handle --disable
if (options.disable) {
const disabledAnalyzers = options.disable.split(',').map((a) => a.trim());
disabledAnalyzers.forEach((analyzer) => {
if (config[analyzer]) {
config[analyzer].enabled = false;
}
});
}
// Handle --threshold overrides
if (options.threshold && Object.keys(options.threshold).length > 0) {
applyThresholdOverrides(config, options.threshold);
}
console.log(chalk.cyan('\nš Running Configurable Code Analysis\n'));
const results = {};
const errors = [];
// Determine which analyzers to run
const runAll = !options.security && !options.performance && !options.documentation &&
!options.quality && !options.crossPlatform && !options.unused;
// Security Analysis
if ((runAll || options.security) && config.security?.enabled) {
const spinner = ora('Running security analysis...').start();
try {
const analyzer = new SecurityAnalyzer(projectRoot);
results.security = await analyzer.fullAnalysis();
// Apply configuration-based scoring
const securityConfig = config.security;
if (results.security.criticalIssues > securityConfig.thresholds.criticalIssuesMax) {
results.security.configViolation = 'Exceeded critical issues threshold';
}
spinner.succeed('Security analysis complete');
}
catch (error) {
spinner.fail('Security analysis failed');
errors.push(`Security: ${error}`);
}
}
// Performance Analysis
if ((runAll || options.performance) && config.performance?.enabled) {
const spinner = ora('Running performance analysis...').start();
try {
const analyzer = new PerformanceAnalyzer(projectRoot);
results.performance = await analyzer.analyze();
spinner.succeed('Performance analysis complete');
}
catch (error) {
spinner.fail('Performance analysis failed');
errors.push(`Performance: ${error}`);
}
}
// Documentation Analysis
if ((runAll || options.documentation) && config.documentation?.enabled) {
const spinner = ora('Running documentation analysis...').start();
try {
const analyzer = new DocumentationAnalyzer(projectRoot);
results.documentation = await analyzer.analyze();
spinner.succeed('Documentation analysis complete');
}
catch (error) {
spinner.fail('Documentation analysis failed');
errors.push(`Documentation: ${error}`);
}
}
// Code Quality Analysis
if ((runAll || options.quality) && config.codeQuality?.enabled) {
const spinner = ora('Running code quality analysis...').start();
try {
const analyzer = new CodeQualityAnalyzer(projectRoot);
results.codeQuality = await analyzer.fullAnalysis();
spinner.succeed('Code quality analysis complete');
}
catch (error) {
spinner.fail('Code quality analysis failed');
errors.push(`Code Quality: ${error}`);
}
}
// Cross-Platform Analysis
if ((runAll || options.crossPlatform) && config.crossPlatform?.enabled) {
const spinner = ora('Running cross-platform analysis...').start();
try {
const analyzer = new CrossPlatformAnalyzer(projectRoot);
results.crossPlatform = await analyzer.analyze();
spinner.succeed('Cross-platform analysis complete');
}
catch (error) {
spinner.fail('Cross-platform analysis failed');
errors.push(`Cross-Platform: ${error}`);
}
}
// Unused Code Analysis
if ((runAll || options.unused) && config.unusedCode?.enabled) {
const spinner = ora('Running unused code analysis...').start();
try {
const analyzer = new UnusedCodeAnalyzer(projectRoot);
results.unusedCode = await analyzer.analyze();
spinner.succeed('Unused code analysis complete');
}
catch (error) {
spinner.fail('Unused code analysis failed');
errors.push(`Unused Code: ${error}`);
}
}
// Generate detailed report
const reportOptions = {
format: options.format,
outputPath: options.output,
includeDetails: options.details !== false,
includeExamples: options.examples !== false,
includeTrends: false,
maxIssuesPerCategory: 10
};
const reportGenerator = new DetailedReportGenerator(reportOptions);
await reportGenerator.generateReport(results, projectRoot);
// If not console output, still show summary
if (options.format !== 'console' && !options.output) {
displayResults(results, config, errors);
}
});
}
function collectThresholds(value, previous) {
const [key, val] = value.split('=');
previous[key] = isNaN(Number(val)) ? val : Number(val);
return previous;
}
function applyThresholdOverrides(config, overrides) {
for (const [key, value] of Object.entries(overrides)) {
const parts = key.split('.');
let target = config;
for (let i = 0; i < parts.length - 1; i++) {
if (target[parts[i]]) {
target = target[parts[i]];
}
}
const lastPart = parts[parts.length - 1];
if (target.thresholds && lastPart in target.thresholds) {
target.thresholds[lastPart] = value;
}
}
}
function displayResults(results, config, errors) {
console.log(chalk.cyan('\nš Analysis Results Summary\n'));
// Overall score calculation
let totalScore = 0;
let analyzersRun = 0;
// Security Results
if (results.security) {
analyzersRun++;
const score = results.security.securityScore || 0;
totalScore += score;
console.log(chalk.yellow('š Security Analysis:'));
console.log(` Score: ${getScoreColor(score)}${score}/100${chalk.reset()}`);
console.log(` Risk Level: ${getRiskColor(results.security.riskLevel)}${results.security.riskLevel}${chalk.reset()}`);
console.log(` Critical Issues: ${results.security.criticalIssues}`);
console.log(` Total Issues: ${results.security.issues}`);
if (results.security.configViolation) {
console.log(chalk.red(` ā ļø Config Violation: ${results.security.configViolation}`));
}
if (config.security?.thresholds.minSecurityScore && score < config.security.thresholds.minSecurityScore) {
console.log(chalk.red(` ā Below minimum score threshold (${config.security.thresholds.minSecurityScore})`));
}
console.log();
}
// Performance Results
if (results.performance) {
analyzersRun++;
const score = results.performance.score || 0;
totalScore += score;
console.log(chalk.blue('ā” Performance Analysis:'));
console.log(` Score: ${getScoreColor(score)}${score}/100${chalk.reset()}`);
console.log(` Issues: ${results.performance.issues}`);
if (results.performance.bundleSizeKB && config.performance?.rules.bundleSize.enabled) {
const maxSize = config.performance.rules.bundleSize.maxSizeKB;
const bundleSize = results.performance.bundleSizeKB;
if (bundleSize > maxSize) {
console.log(chalk.red(` ā Bundle size (${bundleSize}KB) exceeds limit (${maxSize}KB)`));
}
}
console.log();
}
// Documentation Results
if (results.documentation) {
analyzersRun++;
const score = results.documentation.score || 0;
totalScore += score;
console.log(chalk.green('š Documentation Analysis:'));
console.log(` Score: ${getScoreColor(score)}${score}/100${chalk.reset()}`);
console.log(` Coverage: ${results.documentation.coverage}%`);
console.log(` Issues: ${results.documentation.issues}`);
if (config.documentation?.thresholds.minDocumentationScore && score < config.documentation.thresholds.minDocumentationScore) {
console.log(chalk.red(` ā Below minimum score threshold (${config.documentation.thresholds.minDocumentationScore})`));
}
console.log();
}
// Code Quality Results
if (results.codeQuality) {
analyzersRun++;
const score = results.codeQuality.score || 0;
totalScore += score;
console.log(chalk.magenta('⨠Code Quality Analysis:'));
console.log(` Score: ${getScoreColor(score)}${score}/100${chalk.reset()}`);
console.log(` Issues: ${results.codeQuality.issues}`);
console.log(` Duplicates: ${results.codeQuality.duplicates || 0}`);
console.log(` Complexity Issues: ${results.codeQuality.complexityIssues || 0}`);
console.log();
}
// Cross-Platform Results
if (results.crossPlatform) {
analyzersRun++;
const score = results.crossPlatform.overallScore || 0;
totalScore += score;
console.log(chalk.cyan('š„ļø Cross-Platform Analysis:'));
console.log(` Score: ${getScoreColor(score)}${score}/100${chalk.reset()}`);
console.log(` Risk Level: ${getRiskColor(results.crossPlatform.riskLevel)}${results.crossPlatform.riskLevel}${chalk.reset()}`);
console.log(` Issues: ${results.crossPlatform.issues.length}`);
// Platform-specific scores
if (results.crossPlatform.platformCompatibility) {
console.log(' Platform Compatibility:');
for (const [platform, compat] of Object.entries(results.crossPlatform.platformCompatibility)) {
if (platform !== 'overall' && typeof compat === 'object') {
const platCompat = compat;
console.log(` ${platform}: ${getScoreColor(platCompat.score)}${platCompat.score}/100${chalk.reset()} (${platCompat.status})`);
}
}
}
console.log();
}
// Unused Code Results
if (results.unusedCode) {
analyzersRun++;
const score = results.unusedCode.score || 0;
totalScore += score;
console.log(chalk.gray('šļø Unused Code Analysis:'));
console.log(` Score: ${getScoreColor(score)}${score}/100${chalk.reset()}`);
console.log(` Unused Functions: ${results.unusedCode.unusedFunctions?.length || 0}`);
console.log(` Unused Files: ${results.unusedCode.unusedFiles?.length || 0}`);
console.log(` Dead Code Blocks: ${results.unusedCode.deadCode?.length || 0}`);
console.log();
}
// Overall Summary
if (analyzersRun > 0) {
const overallScore = Math.round(totalScore / analyzersRun);
console.log(chalk.bold.cyan('š Overall Project Health:'));
console.log(` Average Score: ${getScoreColor(overallScore)}${overallScore}/100${chalk.reset()}`);
console.log(` Analyzers Run: ${analyzersRun}`);
if (errors.length > 0) {
console.log(chalk.red(`\nā Errors encountered:`));
errors.forEach(error => console.log(` - ${error}`));
}
// Configuration summary
console.log(chalk.gray('\nš Configuration Summary:'));
console.log(chalk.gray(` Severity Penalties: Critical=${config.severity.critical}, High=${config.severity.high}, Medium=${config.severity.medium}, Low=${config.severity.low}`));
}
else {
console.log(chalk.yellow('No analyzers were run. Check your configuration.'));
}
}
function getScoreColor(score) {
if (score >= 90)
return chalk.green('');
if (score >= 70)
return chalk.yellow('');
if (score >= 50)
return chalk.rgb(255, 165, 0)(''); // orange
return chalk.red('');
}
function getRiskColor(risk) {
switch (risk) {
case 'low': return chalk.green('');
case 'medium': return chalk.yellow('');
case 'high': return chalk.rgb(255, 165, 0)(''); // orange
case 'critical': return chalk.red('');
default: return chalk.gray('');
}
}
//# sourceMappingURL=analyze-configurable.js.map