@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
JavaScript
"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