mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
561 lines • 20.7 kB
JavaScript
/**
* Universal Robust Unused Code Analyzer
*
* Designed for thousands of users across all environments and project types.
* Ultra-conservative approach that works safely with any codebase.
*/
import * as fs from 'fs/promises';
import * as path from 'path';
import { glob } from 'glob';
export class UniversalRobustUnusedCodeAnalyzer {
projectRoot;
environment = null;
safetyConfig;
entryPoints = new Set();
reachableFiles = new Set();
// Universal patterns that should ALWAYS be preserved
UNIVERSAL_PRESERVE_PATTERNS = [
// Entry points and executables
'**/index.*',
'**/main.*',
'**/app.*',
'**/server.*',
'**/start.*',
'**/launch.*',
'**/run.*',
'bin/**',
'scripts/**',
// Configuration files
'**/*.config.*',
'**/config/**',
'**/configs/**',
'**/configuration/**',
// Build and deployment
'**/webpack.*',
'**/babel.*',
'**/tsconfig.*',
'**/jsconfig.*',
'**/package.json',
'**/package-lock.json',
'**/yarn.lock',
'**/pnpm-lock.yaml',
'**/Dockerfile*',
'**/docker-compose.*',
'**/.env*',
// Documentation and metadata
'**/README.*',
'**/CHANGELOG.*',
'**/LICENSE*',
'**/CONTRIBUTING.*',
'docs/**',
// Testing infrastructure
'**/*.test.*',
'**/*.spec.*',
'**/test/**',
'**/tests/**',
'**/spec/**',
'**/jest.*',
'**/karma.*',
'**/cypress.*',
// Source maps and build outputs
'**/*.map',
'dist/**',
'build/**',
'out/**',
'target/**',
// Version control and CI/CD
'.git/**',
'.github/**',
'.gitlab/**',
'**/.gitignore',
'**/.gitattributes',
// IDE and editor files
'.vscode/**',
'.idea/**',
'**/*.iml',
// Language-specific preserves
// Python
'**/__init__.py',
'**/setup.py',
'**/requirements.*',
'**/pyproject.toml',
// Java
'**/pom.xml',
'**/build.gradle',
'**/MainActivity.*',
// C/C++
'**/CMakeLists.txt',
'**/Makefile*',
'**/main.c*',
// Go
'**/go.mod',
'**/go.sum',
'**/main.go',
// Rust
'**/Cargo.toml',
'**/Cargo.lock',
'**/main.rs',
// PHP
'**/composer.json',
'**/composer.lock',
'**/index.php',
// Ruby
'**/Gemfile*',
'**/Rakefile',
// .NET
'**/*.csproj',
'**/*.sln',
'**/Program.cs',
// Mobile development
'**/Info.plist',
'**/AndroidManifest.xml',
'**/pubspec.yaml',
// Static site generators
'**/gatsby-*',
'**/next.config.*',
'**/nuxt.config.*',
'**/vite.config.*',
// Database and data
'**/*.sql',
'**/*.db',
'**/*.sqlite*',
'**/migrations/**',
'**/seeds/**',
// Security and certificates
'**/*.pem',
'**/*.key',
'**/*.crt',
'**/*.cert',
// Any file with "main", "index", "app", "start" in the name
'**/*main*',
'**/*index*',
'**/*app*',
'**/*start*',
'**/*entry*',
'**/*boot*',
'**/*init*',
'**/*setup*',
'**/*config*',
'**/*launch*'
];
constructor(projectRoot, safetyConfig) {
this.projectRoot = projectRoot;
this.safetyConfig = {
maxFilesToAnalyze: 10000,
maxDirectoriesToScan: 1000,
analysisTimeoutMs: 30000, // 30 seconds max
confidenceThreshold: 0.95, // Very high confidence required
enableDeepAnalysis: false, // Disabled by default for safety
preservePatterns: [],
...safetyConfig
};
}
async analyze() {
console.log('🌍 Starting Universal Robust Analysis...');
const startTime = Date.now();
try {
// Set timeout for entire analysis
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Analysis timeout')), this.safetyConfig.analysisTimeoutMs);
});
const analysisPromise = this.performSafeAnalysis();
const result = await Promise.race([analysisPromise, timeoutPromise]);
const duration = Date.now() - startTime;
console.log(`✅ Analysis completed in ${duration}ms`);
return result;
}
catch (error) {
console.error('❌ Analysis failed:', error);
// Return safe default result on any error
return this.createSafeDefaultResult();
}
}
async performSafeAnalysis() {
// Step 1: Detect project environment
await this.detectProjectEnvironment();
// Step 2: Universal entry point detection
await this.detectUniversalEntryPoints();
// Step 3: Conservative file classification
const allFiles = await this.scanProjectFiles();
// Step 4: Ultra-conservative unused detection
const unusedFiles = await this.detectUnusedFilesConservatively(allFiles);
// Convert to expected type structure
const languageInfos = (this.environment?.languages || []).map(lang => ({
name: lang,
percentage: 0,
files: 0,
linesOfCode: 0,
entryPoints: [],
buildFiles: [],
packageFiles: []
}));
const typedEnvironment = {
languages: languageInfos,
frameworks: this.environment?.frameworks || [],
buildSystems: this.environment?.buildSystems || [],
packageManagers: this.environment?.packageManager ? [this.environment.packageManager] : [],
operatingSystem: 'unknown',
architecture: 'unknown',
projectType: this.mapProjectType(this.environment?.type || 'unknown')
};
return {
score: this.calculateSafetyScore(unusedFiles.length, allFiles.length),
environment: typedEnvironment,
summary: {
totalFiles: allFiles.length,
unusedFileCount: unusedFiles.length,
unusedFilePercentage: (unusedFiles.length / allFiles.length) * 100,
totalFunctions: 0,
unusedFunctionCount: 0,
unusedFunctionPercentage: 0,
unusedImportCount: 0,
unusedAssetCount: 0,
unusedStyleCount: 0,
deadCodeBlockCount: 0,
potentialSavings: {
linesOfCode: 0,
fileSize: 0,
estimatedDevelopmentTime: 0
}
},
unusedFiles,
unusedFunctions: [],
unusedImports: [],
unusedAssets: [],
unusedStyles: [],
deadCodeBlocks: [],
languageSpecificResults: [],
recommendations: []
};
}
async detectProjectEnvironment() {
const packageJsonPath = path.join(this.projectRoot, 'package.json');
const frameworks = [];
const languages = [];
const buildSystems = [];
let packageManager = null;
try {
// Detect from package.json
if (await fs.access(packageJsonPath).then(() => true).catch(() => false)) {
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
// Detect frameworks
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
if (deps.react)
frameworks.push('React');
if (deps.vue)
frameworks.push('Vue');
if (deps.angular || deps['@angular/core'])
frameworks.push('Angular');
if (deps.express)
frameworks.push('Express');
if (deps.next)
frameworks.push('Next.js');
if (deps.gatsby)
frameworks.push('Gatsby');
if (deps.nuxt)
frameworks.push('Nuxt.js');
packageManager = 'npm';
}
// Detect languages by file extensions
const sampleFiles = await glob('**/*.{js,ts,jsx,tsx,py,java,go,rs,php,rb,cs,cpp,c}', {
cwd: this.projectRoot,
ignore: ['node_modules/**', '.git/**']
});
// Limit for performance
const limitedFiles = sampleFiles.slice(0, 100);
for (const file of limitedFiles) {
const ext = path.extname(file).toLowerCase();
if (['.js', '.jsx', '.ts', '.tsx'].includes(ext) && !languages.includes('JavaScript/TypeScript')) {
languages.push('JavaScript/TypeScript');
}
if (ext === '.py' && !languages.includes('Python'))
languages.push('Python');
if (ext === '.java' && !languages.includes('Java'))
languages.push('Java');
if (ext === '.go' && !languages.includes('Go'))
languages.push('Go');
if (ext === '.rs' && !languages.includes('Rust'))
languages.push('Rust');
if (ext === '.php' && !languages.includes('PHP'))
languages.push('PHP');
if (ext === '.rb' && !languages.includes('Ruby'))
languages.push('Ruby');
if (ext === '.cs' && !languages.includes('C#'))
languages.push('C#');
if (['.cpp', '.c'].includes(ext) && !languages.includes('C/C++'))
languages.push('C/C++');
}
// Detect other package managers
if (await fs.access(path.join(this.projectRoot, 'yarn.lock')).then(() => true).catch(() => false)) {
packageManager = 'yarn';
}
if (await fs.access(path.join(this.projectRoot, 'pnpm-lock.yaml')).then(() => true).catch(() => false)) {
packageManager = 'pnpm';
}
this.environment = {
type: this.determineProjectType(frameworks, languages),
frameworks,
languages,
buildSystems,
packageManager
};
}
catch (error) {
// Safe fallback
this.environment = {
type: 'unknown',
frameworks: [],
languages: [],
buildSystems: [],
packageManager: null
};
}
}
determineProjectType(frameworks, languages) {
if (frameworks.includes('React') || frameworks.includes('Vue') || frameworks.includes('Angular')) {
return 'web';
}
if (frameworks.includes('Express') || languages.includes('JavaScript/TypeScript')) {
return 'node';
}
if (languages.includes('Java') && (languages.length === 1)) {
return 'mobile'; // Could be Android
}
return 'unknown';
}
mapProjectType(type) {
switch (type) {
case 'web': return 'web';
case 'node': return 'api';
case 'mobile': return 'mobile';
case 'desktop': return 'desktop';
case 'library': return 'library';
default: return 'single';
}
}
async detectUniversalEntryPoints() {
try {
// Look for package.json entry points
const packageJsonPath = path.join(this.projectRoot, 'package.json');
if (await fs.access(packageJsonPath).then(() => true).catch(() => false)) {
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
if (packageJson.main)
this.entryPoints.add(packageJson.main);
if (packageJson.module)
this.entryPoints.add(packageJson.module);
if (packageJson.bin) {
if (typeof packageJson.bin === 'string') {
this.entryPoints.add(packageJson.bin);
}
else {
Object.values(packageJson.bin).forEach(bin => this.entryPoints.add(bin));
}
}
}
// Universal entry point patterns
const entryPatterns = [
'index.*',
'main.*',
'app.*',
'server.*',
'start.*',
'bin/**',
'src/index.*',
'src/main.*',
'src/app.*',
'lib/index.*'
];
for (const pattern of entryPatterns) {
const matches = await glob(pattern, { cwd: this.projectRoot });
matches.slice(0, 10).forEach(match => this.entryPoints.add(match));
}
}
catch (error) {
// Safe fallback - assume common entry points exist
this.entryPoints.add('index.js');
this.entryPoints.add('main.js');
this.entryPoints.add('app.js');
}
}
async scanProjectFiles() {
try {
const files = await glob('**/*', {
cwd: this.projectRoot,
ignore: [
'node_modules/**',
'.git/**',
'dist/**',
'build/**',
'out/**',
'target/**',
'**/*.log',
'**/*.tmp',
'**/tmp/**',
'**/temp/**'
],
dot: false
});
// Limit files for safety
const limitedFiles = files.slice(0, this.safetyConfig.maxFilesToAnalyze);
// Filter to actual files only
const actualFiles = [];
for (const file of limitedFiles) {
try {
const fullPath = path.join(this.projectRoot, file);
const stat = await fs.stat(fullPath);
if (stat.isFile()) {
actualFiles.push(file);
}
}
catch (error) {
// Skip files that can't be accessed
}
}
return actualFiles;
}
catch (error) {
console.warn('File scanning failed, returning empty list for safety');
return [];
}
}
async detectUnusedFilesConservatively(allFiles) {
const unusedFiles = [];
const preservePatterns = [
...this.UNIVERSAL_PRESERVE_PATTERNS,
...this.safetyConfig.preservePatterns
];
for (const file of allFiles) {
// Check if file matches any preserve pattern
const isPreserved = preservePatterns.some(pattern => {
// Convert glob pattern to regex for matching
const regex = new RegExp(pattern
.replace(/\*\*/g, '.*')
.replace(/\*/g, '[^/]*')
.replace(/\?/g, '.'));
return regex.test(file);
});
if (isPreserved) {
continue; // Skip preserved files
}
// Only flag files with VERY high confidence and specific criteria
const confidence = await this.calculateFileUnusedConfidence(file);
if (confidence >= this.safetyConfig.confidenceThreshold) {
try {
const fullPath = path.join(this.projectRoot, file);
const stat = await fs.stat(fullPath);
unusedFiles.push({
path: file,
size: stat.size,
lastModified: stat.mtime,
reason: 'File appears unused based on conservative analysis',
confidence,
potentialEntryPoints: []
});
}
catch (error) {
// Skip files that can't be accessed
}
}
}
return unusedFiles;
}
async calculateFileUnusedConfidence(file) {
// Ultra-conservative: Start with very low confidence
let confidence = 0.1;
try {
const fullPath = path.join(this.projectRoot, file);
const content = await fs.readFile(fullPath, 'utf-8');
// Very strict criteria for considering a file unused
const ext = path.extname(file).toLowerCase();
// Only consider certain file types for potential removal
if (!['.log', '.tmp', '.cache', '.bak', '.old'].includes(ext)) {
return 0.1; // Very low confidence for normal files
}
// Check if it's a temporary or cache file
if (file.includes('/tmp/') || file.includes('/cache/') || file.includes('/temp/')) {
confidence = 0.7;
}
// Check if it's a log file
if (ext === '.log' && content.length > 0) {
const lines = content.split('\n');
const lastLine = lines[lines.length - 1];
if (lastLine && lastLine.trim()) {
// Check if log is very old (basic heuristic)
const dateMatch = lastLine.match(/\d{4}-\d{2}-\d{2}/);
if (dateMatch) {
const logDate = new Date(dateMatch[0]);
const monthsOld = (Date.now() - logDate.getTime()) / (1000 * 60 * 60 * 24 * 30);
if (monthsOld > 6) {
confidence = 0.8;
}
}
}
}
// Even stricter for source files - never suggest removal
if (['.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.go', '.rs', '.php', '.rb', '.cs', '.cpp', '.c'].includes(ext)) {
return 0.05; // Extremely low confidence for source files
}
}
catch (error) {
// If we can't read the file, don't suggest removing it
return 0.1;
}
return Math.min(confidence, 0.9); // Cap at 90% confidence for safety
}
calculateSafetyScore(unusedCount, totalCount) {
// Conservative scoring - lower scores for more flagged files
if (totalCount === 0)
return 100;
const unusedPercentage = (unusedCount / totalCount) * 100;
if (unusedPercentage < 1)
return 95; // Excellent
if (unusedPercentage < 5)
return 85; // Good
if (unusedPercentage < 10)
return 70; // Fair
if (unusedPercentage < 20)
return 50; // Poor
return 25; // Very poor - likely analysis error
}
createSafeDefaultResult() {
const typedEnvironment = {
languages: [],
frameworks: [],
buildSystems: [],
packageManagers: [],
operatingSystem: 'unknown',
architecture: 'unknown',
projectType: 'single'
};
return {
score: 90, // Safe default score
environment: typedEnvironment,
summary: {
totalFiles: 0,
unusedFileCount: 0,
unusedFilePercentage: 0,
totalFunctions: 0,
unusedFunctionCount: 0,
unusedFunctionPercentage: 0,
unusedImportCount: 0,
unusedAssetCount: 0,
unusedStyleCount: 0,
deadCodeBlockCount: 0,
potentialSavings: {
linesOfCode: 0,
fileSize: 0,
estimatedDevelopmentTime: 0
}
},
unusedFiles: [],
unusedFunctions: [],
unusedImports: [],
unusedAssets: [],
unusedStyles: [],
deadCodeBlocks: [],
languageSpecificResults: [],
recommendations: []
};
}
}
//# sourceMappingURL=UniversalRobustUnusedCodeAnalyzer.js.map