UNPKG

@paulohenriquevn/m2js

Version:

Transform TypeScript/JavaScript code into LLM-friendly Markdown summaries + Smart Dead Code Detection + Graph-Deep Diff Analysis. Extract exported functions, classes, and JSDoc comments for better AI context with 60%+ token reduction. Intelligent dead cod

291 lines 9.84 kB
"use strict"; /** * Performance Optimizer for M2JS Dead Code Analysis * Provides caching, parallelization, and memory optimization */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProgressIndicator = exports.OptimizedDataStructures = exports.OptimizedFileProcessor = void 0; const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); /** * File parsing cache manager */ class FileParsingCache { constructor(maxSize = 1000) { this.cache = new Map(); this.accessOrder = []; this.maxSize = maxSize; } /** * Check if file is cached and still valid */ isValid(filePath) { const cached = this.cache.get(filePath); if (!cached) return false; try { const stats = (0, fs_1.statSync)(filePath); return cached.mtime === stats.mtimeMs && cached.size === stats.size; } catch { // File no longer exists this.cache.delete(filePath); return false; } } /** * Get cached parsing results */ get(filePath) { if (!this.isValid(filePath)) return null; const cached = this.cache.get(filePath); // Update access order (LRU) this.updateAccessOrder(filePath); return { exports: [...cached.exports], // Return copies to prevent mutation imports: [...cached.imports], }; } /** * Cache parsing results */ set(filePath, content, exports, imports) { try { const stats = (0, fs_1.statSync)(filePath); // Evict old entries if cache is full while (this.cache.size >= this.maxSize && this.accessOrder.length > 0) { const oldest = this.accessOrder.shift(); this.cache.delete(oldest); } this.cache.set(filePath, { content, exports: [...exports], // Store copies imports: [...imports], mtime: stats.mtimeMs, size: stats.size, }); this.updateAccessOrder(filePath); } catch { // Ignore cache errors } } /** * Update LRU access order */ updateAccessOrder(filePath) { // Remove from current position const index = this.accessOrder.indexOf(filePath); if (index !== -1) { this.accessOrder.splice(index, 1); } // Add to end (most recently used) this.accessOrder.push(filePath); } /** * Clear cache */ clear() { this.cache.clear(); this.accessOrder = []; } /** * Get cache statistics */ getStats() { return { size: this.cache.size, }; } } /** * Performance-optimized file processor */ class OptimizedFileProcessor { constructor(options = {}) { this.cacheHits = 0; this.cacheMisses = 0; this.options = { enableCache: true, maxCacheSize: 1000, chunkSize: 50, showProgress: false, ...options, }; this.cache = new FileParsingCache(this.options.maxCacheSize); } /** * Process files with optimization */ async processFiles(files, parseFunction, progressCallback) { const allExports = []; const allImports = []; // Process files in chunks to manage memory for (let i = 0; i < files.length; i += this.options.chunkSize) { const chunk = files.slice(i, i + this.options.chunkSize); for (const filePath of chunk) { try { let result; // Try cache first if (this.options.enableCache) { const cached = this.cache.get(filePath); if (cached) { result = cached; this.cacheHits++; } else { const content = (0, fs_1.readFileSync)(filePath, 'utf-8'); result = parseFunction(filePath, content); this.cache.set(filePath, content, result.exports, result.imports); this.cacheMisses++; } } else { const content = (0, fs_1.readFileSync)(filePath, 'utf-8'); result = parseFunction(filePath, content); this.cacheMisses++; } allExports.push(...result.exports); allImports.push(...result.imports); // Report progress if (progressCallback) { progressCallback(i + chunk.indexOf(filePath) + 1, files.length, filePath); } } catch (error) { throw new Error(`Failed to process file ${filePath}: ${error.message}`); } } // Force garbage collection opportunity between chunks if (global.gc && chunk.length === this.options.chunkSize) { global.gc(); } } return { allExports, allImports }; } /** * Get performance statistics */ getPerformanceStats() { const total = this.cacheHits + this.cacheMisses; return { cacheHits: this.cacheHits, cacheMisses: this.cacheMisses, hitRate: total > 0 ? this.cacheHits / total : 0, cacheSize: this.cache.getStats().size, }; } /** * Clear all caches */ clearCache() { this.cache.clear(); this.cacheHits = 0; this.cacheMisses = 0; } } exports.OptimizedFileProcessor = OptimizedFileProcessor; /** * Memory-optimized data structures */ class OptimizedDataStructures { /** * Create efficient lookup map for imports */ static createImportLookupMap(imports) { const importMap = new Map(); for (const imp of imports) { // Resolve relative import paths efficiently const resolvedPath = this.resolveImportPath(imp.file, imp.from); let importNames = importMap.get(resolvedPath); if (!importNames) { importNames = new Set(); importMap.set(resolvedPath, importNames); } if (imp.type === 'default') { importNames.add('default'); } else if (imp.type === 'namespace') { importNames.add('*'); } else { importNames.add(imp.name); } } return importMap; } static resolveImportPath(fromFile, importPath) { const cacheKey = `${fromFile}:${importPath}`; const cached = this.pathCache.get(cacheKey); if (cached) return cached; const fromDir = path_1.default.dirname(fromFile); const resolved = path_1.default.resolve(fromDir, importPath); const result = path_1.default.resolve(resolved); // Cache the result this.pathCache.set(cacheKey, result); return result; } /** * Batch process exports for dead code detection */ static findDeadExportsBatch(exports, importMap, batchSize = 100) { const deadExports = []; for (let i = 0; i < exports.length; i += batchSize) { const batch = exports.slice(i, i + batchSize); for (const exp of batch) { const normalizedPath = path_1.default.resolve(exp.file); const importedNames = importMap.get(normalizedPath); const isImported = importedNames && (importedNames.has(exp.name) || importedNames.has('*') || (exp.isDefault && importedNames.has('default'))); if (!isImported) { deadExports.push(exp); } } } return deadExports; } } exports.OptimizedDataStructures = OptimizedDataStructures; /** * Efficient import path resolution with caching */ OptimizedDataStructures.pathCache = new Map(); /** * Progress indicator for CLI */ class ProgressIndicator { constructor() { this.lastUpdate = 0; this.startTime = Date.now(); } /** * Update progress with throttling */ update(processed, total, currentFile) { const now = Date.now(); // Throttle updates to avoid overwhelming the console if (now - this.lastUpdate < 100 && processed < total) return; this.lastUpdate = now; const percentage = Math.round((processed / total) * 100); const elapsed = (now - this.startTime) / 1000; const estimatedTotal = (elapsed / processed) * total; const remaining = Math.max(0, estimatedTotal - elapsed); const fileName = path_1.default.basename(currentFile); const progress = '█'.repeat(Math.floor(percentage / 2)) + '░'.repeat(50 - Math.floor(percentage / 2)); process.stdout.write(`\r[${progress}] ${percentage}% (${processed}/${total}) ${fileName} - ${remaining.toFixed(1)}s remaining`); if (processed === total) { process.stdout.write(`\nAnalysis complete in ${elapsed.toFixed(1)}s\n`); } } } exports.ProgressIndicator = ProgressIndicator; //# sourceMappingURL=performance-optimizer.js.map