mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
370 lines • 16 kB
JavaScript
/**
* Cross-Platform Analyzer Orchestrator
* Coordinates all cross-platform compatibility analysis modules
*/
import { FileSystemAnalyzer } from './FileSystemAnalyzer.js';
import { ShellCommandAnalyzer } from './ShellCommandAnalyzer.js';
import { EnvironmentAnalyzer } from './EnvironmentAnalyzer.js';
export class CrossPlatformAnalyzer {
projectRoot;
fileSystemAnalyzer;
shellCommandAnalyzer;
environmentAnalyzer;
constructor(projectRoot) {
this.projectRoot = projectRoot;
this.fileSystemAnalyzer = new FileSystemAnalyzer(projectRoot);
this.shellCommandAnalyzer = new ShellCommandAnalyzer(projectRoot);
this.environmentAnalyzer = new EnvironmentAnalyzer(projectRoot);
}
async analyze() {
const issues = [];
// Run all analyzers in parallel
const [fileSystemAnalysis, shellAnalysis, environmentAnalysis] = await Promise.all([
this.fileSystemAnalyzer.analyze(issues),
this.shellCommandAnalyzer.analyze(issues),
this.environmentAnalyzer.analyze(issues)
]);
// Merge shell analysis into environment analysis
environmentAnalysis.shellCompatibility = shellAnalysis;
environmentAnalysis.fileSystemRequirements = fileSystemAnalysis;
// Analyze platform compatibility
const platformCompatibility = this.calculatePlatformCompatibility(issues);
// Calculate platform-specific issues
const platformSpecificIssues = this.categorizePlatformIssues(issues);
// Calculate overall score and risk
const { overallScore, riskLevel } = this.calculateOverallScore(issues, platformCompatibility);
// Generate recommendations
const recommendations = this.generateRecommendations(issues, platformCompatibility, environmentAnalysis);
return {
issues,
platformCompatibility,
overallScore,
riskLevel,
recommendations,
platformSpecificIssues,
environmentAnalysis
};
}
calculatePlatformCompatibility(issues) {
const platforms = ['windows', 'macOS', 'linux', 'unix'];
const compatibility = this.initializePlatformCompatibility();
// Count issues per platform
this.countIssuesPerPlatform(issues, compatibility, platforms);
// Calculate scores for each platform
platforms.forEach(platform => {
this.calculatePlatformScore(compatibility[platform]);
});
// Calculate overall compatibility
this.calculateOverallCompatibility(issues, compatibility);
return compatibility;
}
initializePlatformCompatibility() {
const createCompatLevel = () => ({
score: 100, issues: 0, critical: 0, status: 'excellent'
});
return {
windows: createCompatLevel(),
macOS: createCompatLevel(),
linux: createCompatLevel(),
unix: createCompatLevel(),
overall: createCompatLevel()
};
}
countIssuesPerPlatform(issues, compatibility, platforms) {
issues.forEach(issue => {
issue.affectedPlatforms.forEach(platform => {
if (platform === 'all') {
this.incrementAllPlatforms(compatibility, platforms, issue);
}
else if (platform in compatibility) {
this.incrementPlatform(compatibility[platform], issue);
}
});
});
}
incrementAllPlatforms(compatibility, platforms, issue) {
platforms.forEach(p => this.incrementPlatform(compatibility[p], issue));
}
incrementPlatform(platComp, issue) {
platComp.issues++;
if (issue.severity === 'critical') {
platComp.critical++;
}
}
calculatePlatformScore(comp) {
const criticalPenalty = comp.critical * 15;
const issuePenalty = comp.issues > 0 ? Math.log10(comp.issues + 1) * 10 : 0;
const penalty = criticalPenalty + issuePenalty;
comp.score = Math.max(0, Math.round(100 - penalty));
comp.status = this.getStatusFromScore(comp.score);
}
calculateOverallCompatibility(issues, compatibility) {
const severityCounts = this.countIssueBySeverity(issues);
compatibility.overall.issues = issues.length;
compatibility.overall.critical = severityCounts.critical;
const penalty = this.calculateOverallPenalty(severityCounts, issues.length);
compatibility.overall.score = Math.max(0, Math.round(100 - penalty));
compatibility.overall.status = this.getStatusFromScore(compatibility.overall.score);
}
countIssueBySeverity(issues) {
return issues.reduce((counts, issue) => {
if (issue.severity === 'critical')
counts.critical++;
else if (issue.severity === 'high')
counts.high++;
return counts;
}, { critical: 0, high: 0 });
}
calculateOverallPenalty(severityCounts, totalIssues) {
const criticalPenalty = severityCounts.critical * 15;
const highPenalty = severityCounts.high * 5;
const otherPenalty = totalIssues > 0 ? Math.log10(totalIssues + 1) * 15 : 0;
return criticalPenalty + highPenalty + otherPenalty;
}
getStatusFromScore(score) {
if (score >= 90)
return 'excellent';
if (score >= 75)
return 'good';
if (score >= 50)
return 'fair';
if (score >= 25)
return 'poor';
return 'incompatible';
}
categorizePlatformIssues(issues) {
const categorized = {
windows: [],
macOS: [],
linux: [],
unix: []
};
const typeMap = new Map();
for (const issue of issues) {
for (const platform of issue.affectedPlatforms) {
if (platform === 'all') {
// Add to all platforms
for (const p of ['windows', 'macOS', 'linux', 'unix']) {
this.addToPlatformIssues(p, issue, typeMap);
}
}
else if (platform in categorized) {
this.addToPlatformIssues(platform, issue, typeMap);
}
}
}
// Convert map to arrays
for (const [platform, types] of typeMap.entries()) {
const platKey = platform;
categorized[platKey] = Array.from(types.values())
.sort((a, b) => {
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
return severityOrder[a.severity] - severityOrder[b.severity];
});
}
return categorized;
}
addToPlatformIssues(platform, issue, typeMap) {
if (!typeMap.has(platform)) {
typeMap.set(platform, new Map());
}
const platformMap = typeMap.get(platform);
if (!platformMap.has(issue.type)) {
platformMap.set(issue.type, {
type: issue.type,
message: issue.message,
files: [],
severity: issue.severity
});
}
const platformIssue = platformMap.get(issue.type);
platformIssue.files.push(issue.file + (issue.line ? `:${issue.line}` : ''));
// Update severity to highest
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
if (severityOrder[issue.severity] < severityOrder[platformIssue.severity]) {
platformIssue.severity = issue.severity;
}
}
calculateOverallScore(issues, compatibility) {
const overallScore = compatibility.overall.score;
let riskLevel;
const criticalCount = issues.filter(i => i.severity === 'critical').length;
const highCount = issues.filter(i => i.severity === 'high').length;
if (criticalCount > 0 || overallScore < 30) {
riskLevel = 'critical';
}
else if (highCount >= 5 || overallScore < 50) {
riskLevel = 'high';
}
else if (highCount >= 1 || overallScore < 70) {
riskLevel = 'medium';
}
else {
riskLevel = 'low';
}
return { overallScore, riskLevel };
}
// Recommendation generators configuration
RECOMMENDATION_CONFIGS = [
{
filter: (issues) => issues.filter(i => i.severity === 'critical'),
condition: (filtered) => filtered.length > 0,
generator: (filtered) => ({
priority: 'critical',
category: 'Critical Compatibility Issues',
title: 'Address Critical Cross-Platform Issues',
description: `${filtered.length} critical issues prevent cross-platform compatibility`,
platforms: ['all'],
actionItems: [
'Fix all critical issues immediately',
'Test on all target platforms',
'Use cross-platform alternatives for platform-specific code'
]
})
},
{
filter: (issues) => issues.filter(i => i.type.includes('path')),
condition: (filtered) => filtered.length > 0,
generator: (filtered) => ({
priority: 'high',
category: 'Path Handling',
title: 'Use Cross-Platform Path Handling',
description: `${filtered.length} path-related issues found`,
platforms: ['all'],
actionItems: [
'Always use path.join() instead of string concatenation',
'Use path.sep instead of hardcoded separators',
'Avoid hardcoded absolute paths',
'Use path.resolve() for absolute paths'
],
codeExamples: {
bad: `const file = __dirname + '/config/' + name + '.json';`,
good: `const file = path.join(__dirname, 'config', name + '.json');`
}
})
},
{
filter: (issues) => issues.filter(i => i.type.includes('command') || i.type.includes('shell')),
condition: (filtered) => filtered.length > 0,
generator: (filtered) => ({
priority: 'high',
category: 'Shell Commands',
title: 'Avoid Platform-Specific Shell Commands',
description: `${filtered.length} shell command compatibility issues`,
platforms: ['all'],
actionItems: [
'Use Node.js APIs instead of shell commands',
'If shell commands are necessary, check platform first',
'Use cross-platform npm packages for common operations',
'Test shell scripts on all target platforms'
]
})
},
{
filter: (issues) => issues.filter(i => i.type.includes('env')),
condition: (filtered) => filtered.length > 0,
generator: (filtered) => ({
priority: 'medium',
category: 'Environment Variables',
title: 'Handle Platform-Specific Environment Variables',
description: `${filtered.length} environment variable issues`,
platforms: ['all'],
actionItems: [
'Use os.homedir() instead of HOME/USERPROFILE',
'Use os.tmpdir() instead of TEMP/TMPDIR',
'Check for variable existence before use',
'Provide fallback values for missing variables'
],
codeExamples: {
bad: `const home = process.env.HOME;`,
good: `const home = os.homedir();`
}
})
}
];
generateRecommendations(issues, compatibility, environmentAnalysis) {
const recommendations = [];
// Generate issue-based recommendations
this.RECOMMENDATION_CONFIGS.forEach(config => {
const filtered = config.filter(issues);
if (config.condition(filtered)) {
recommendations.push(config.generator(filtered));
}
});
// Platform-specific recommendations
this.addPlatformSpecificRecommendations(compatibility, issues, recommendations);
// Native module recommendations
if (environmentAnalysis.dependencies.some((d) => d.nativeModules)) {
recommendations.push({
priority: 'medium',
category: 'Dependencies',
title: 'Native Module Compatibility',
description: 'Project uses native modules requiring compilation',
platforms: ['all'],
actionItems: [
'Document build requirements for each platform',
'Consider using prebuilt binaries',
'Provide fallback pure JavaScript alternatives',
'Test native module installation on all platforms'
]
});
}
// General best practices
recommendations.push({
priority: 'low',
category: 'Best Practices',
title: 'Cross-Platform Development Guidelines',
description: 'Follow these practices for better compatibility',
platforms: ['all'],
actionItems: [
'Always test on Windows, macOS, and Linux',
'Use CI/CD to test on multiple platforms',
'Prefer Node.js built-in modules over shell commands',
'Document any platform-specific requirements',
'Use ESLint with platform-specific rules',
'Configure Git for consistent line endings'
]
});
return recommendations;
}
getPlatformSpecificActions(platform, issues) {
const platformIssues = issues.filter(i => i.affectedPlatforms.includes(platform));
const actions = [];
const issueTypes = new Set(platformIssues.map(i => i.type));
if (platform === 'windows') {
if (issueTypes.has('unix_command')) {
actions.push('Replace Unix commands with Node.js APIs or cross-platform tools');
}
if (issueTypes.has('unix_path')) {
actions.push('Use path module for all file paths');
}
if (issueTypes.has('file_permissions')) {
actions.push('Handle file permissions gracefully on Windows');
}
}
else {
if (issueTypes.has('windows_command')) {
actions.push('Replace Windows commands with cross-platform alternatives');
}
if (issueTypes.has('windows_path')) {
actions.push('Avoid Windows-style paths');
}
}
return actions.length > 0 ? actions : ['Review and fix platform-specific issues'];
}
addPlatformSpecificRecommendations(compatibility, issues, recommendations) {
Object.entries(compatibility).forEach(([platform, compat]) => {
if (platform !== 'overall' && compat.score < 70) {
recommendations.push({
priority: compat.score < 50 ? 'high' : 'medium',
category: 'Platform Compatibility',
title: `Improve ${platform} Compatibility`,
description: `${platform} compatibility score: ${compat.score}/100`,
platforms: [platform],
actionItems: this.getPlatformSpecificActions(platform, issues)
});
}
});
}
}
//# sourceMappingURL=CrossPlatformAnalyzer.js.map