UNPKG

mira-consciousness

Version:

Memory & Intelligence Retention Archive - Preserving The Spark

215 lines 8.57 kB
/** * File System Performance Analyzer * Checks for file system related performance issues */ import fs from 'fs-extra'; import * as path from 'path'; import { glob } from 'glob'; export class FileSystemAnalyzer { projectRoot; constructor(projectRoot) { this.projectRoot = projectRoot; } async analyze() { const issues = []; await Promise.all([ this.checkPackageJsonSize(issues), this.checkNodeModulesSize(issues), this.checkFileCount(issues), this.checkLargeFiles(issues), this.checkSyncOperations(issues) ]); return issues; } async checkPackageJsonSize(issues) { const packageJsonPath = path.join(this.projectRoot, 'package.json'); if (await fs.pathExists(packageJsonPath)) { try { const packageJson = await fs.readJson(packageJsonPath); const deps = Object.keys(packageJson.dependencies || {}); const devDeps = Object.keys(packageJson.devDependencies || {}); const totalDeps = deps.length + devDeps.length; if (totalDeps > 100) { issues.push({ file: 'package.json', type: 'dependency_bloat', message: `High number of dependencies (${totalDeps}). Consider reducing to improve install time.`, impact: 'medium' }); } if (totalDeps > 200) { issues.push({ file: 'package.json', type: 'excessive_dependencies', message: `Excessive dependencies (${totalDeps}). This will significantly slow down npm install.`, impact: 'high' }); } } catch (error) { // Ignore JSON parsing errors } } } async checkNodeModulesSize(issues) { const nodeModulesPath = path.join(this.projectRoot, 'node_modules'); if (await fs.pathExists(nodeModulesPath)) { try { const size = await this.getDirectorySize(nodeModulesPath); const sizeMB = size / (1024 * 1024); if (sizeMB > 500) { issues.push({ file: 'node_modules', type: 'large_node_modules', message: `node_modules is very large (${sizeMB.toFixed(0)}MB). Consider using npm ci in production.`, impact: 'medium' }); } if (sizeMB > 1000) { issues.push({ file: 'node_modules', type: 'huge_node_modules', message: `node_modules is extremely large (${sizeMB.toFixed(0)}MB). Review dependencies.`, impact: 'high' }); } } catch (error) { // Skip if can't calculate size } } } async checkFileCount(issues) { try { const files = await glob('**/*', { cwd: this.projectRoot, ignore: ['node_modules/**', '.git/**', 'dist/**', 'build/**'] }); if (files.length > 1000) { issues.push({ file: 'project', type: 'high_file_count', message: `Project has many files (${files.length}). Consider organizing or cleaning up.`, impact: 'low' }); } if (files.length > 5000) { issues.push({ file: 'project', type: 'excessive_file_count', message: `Project has excessive files (${files.length}). This may slow down tools and IDEs.`, impact: 'medium' }); } } catch (error) { // Skip if glob fails } } async checkLargeFiles(issues) { try { const files = await glob('**/*', { cwd: this.projectRoot, ignore: ['node_modules/**', '.git/**', 'dist/**', 'build/**'] }); for (const file of files) { const filePath = path.join(this.projectRoot, file); try { const stats = await fs.stat(filePath); if (stats.isFile()) { const sizeMB = stats.size / (1024 * 1024); if (sizeMB > 10) { issues.push({ file, type: 'large_file', message: `File is large (${sizeMB.toFixed(1)}MB). Consider compression or chunking.`, impact: 'medium' }); } if (sizeMB > 50) { issues.push({ file, type: 'huge_file', message: `File is extremely large (${sizeMB.toFixed(1)}MB). This will impact performance.`, impact: 'high' }); } } } catch (error) { // Skip files that can't be read } } } catch (error) { // Skip if glob fails } } async checkSyncOperations(issues) { // Check for synchronous operations in JS/TS files const syncPatterns = [ { pattern: /\.readFileSync\(/, type: 'sync_file_read', message: 'Use async readFile instead of readFileSync' }, { pattern: /\.writeFileSync\(/, type: 'sync_file_write', message: 'Use async writeFile instead of writeFileSync' }, { pattern: /\.execSync\(/, type: 'sync_exec', message: 'Use async exec instead of execSync' }, { pattern: /JSON\.parse.*readFileSync/, type: 'sync_json_read', message: 'Use async JSON file reading' } ]; try { const files = await glob('**/*.{ts,js}', { cwd: this.projectRoot, ignore: ['node_modules/**', '.git/**', 'dist/**'] }); for (const file of files) { const filePath = path.join(this.projectRoot, file); try { const content = await fs.readFile(filePath, 'utf-8'); const lines = content.split('\n'); lines.forEach((line, index) => { for (const syncPattern of syncPatterns) { if (syncPattern.pattern.test(line)) { issues.push({ file: `${file}:${index + 1}`, type: syncPattern.type, message: syncPattern.message, impact: 'medium' }); } } }); } catch (error) { // Skip files that can't be read } } } catch (error) { // Skip if glob fails } } async getDirectorySize(dirPath, depth = 0) { let totalSize = 0; // Limit recursion depth to prevent hanging if (depth > 3) { return 0; } try { const items = await fs.readdir(dirPath); // Limit items processed to prevent hanging on large directories const itemsToProcess = items.slice(0, 100); for (const item of itemsToProcess) { const itemPath = path.join(dirPath, item); const stats = await fs.stat(itemPath); if (stats.isDirectory()) { totalSize += await this.getDirectorySize(itemPath, depth + 1); } else { totalSize += stats.size; } } } catch (error) { // Return what we have so far } return totalSize; } } //# sourceMappingURL=FileSystemAnalyzer.js.map