smartui-migration-tool
Version:
Enterprise-grade CLI tool for migrating visual testing platforms to LambdaTest SmartUI
283 lines • 9.75 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.PerformanceOptimizer = void 0;
const path = __importStar(require("path"));
const fs = __importStar(require("fs/promises"));
const Logger_1 = require("../utils/Logger");
class PerformanceOptimizer {
constructor(verbose = false) {
this.cache = new Map();
this.metrics = [];
this.verbose = verbose;
}
/**
* Cache a value with TTL
*/
setCache(key, value, ttl = 300000) {
const entry = {
key,
value,
timestamp: Date.now(),
ttl
};
this.cache.set(key, entry);
if (this.verbose)
Logger_1.logger.debug(`Cached: ${key} (TTL: ${ttl}ms)`);
}
/**
* Get a cached value
*/
getCache(key) {
const entry = this.cache.get(key);
if (!entry) {
if (this.verbose)
Logger_1.logger.debug(`Cache miss: ${key}`);
return null;
}
// Check if expired
if (Date.now() - entry.timestamp > entry.ttl) {
this.cache.delete(key);
if (this.verbose)
Logger_1.logger.debug(`Cache expired: ${key}`);
return null;
}
if (this.verbose)
Logger_1.logger.debug(`Cache hit: ${key}`);
return entry.value;
}
/**
* Clear expired cache entries
*/
clearExpiredCache() {
const now = Date.now();
let cleared = 0;
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > entry.ttl) {
this.cache.delete(key);
cleared++;
}
}
if (this.verbose && cleared > 0)
Logger_1.logger.debug(`Cleared ${cleared} expired cache entries`);
}
/**
* Clear all cache
*/
clearCache() {
const size = this.cache.size;
this.cache.clear();
if (this.verbose)
Logger_1.logger.debug(`Cleared all cache (${size} entries)`);
}
/**
* Get cache statistics
*/
getCacheStats() {
const now = Date.now();
let expired = 0;
for (const entry of this.cache.values()) {
if (now - entry.timestamp > entry.ttl) {
expired++;
}
}
const totalOperations = this.metrics.reduce((sum, m) => sum + m.cacheHits + m.cacheMisses, 0);
const totalHits = this.metrics.reduce((sum, m) => sum + m.cacheHits, 0);
const hitRate = totalOperations > 0 ? (totalHits / totalOperations) * 100 : 0;
return {
size: this.cache.size,
hitRate: Math.round(hitRate * 100) / 100,
expired
};
}
/**
* Measure operation performance
*/
async measureOperation(operation, fn, useCache = false, cacheKey) {
const startTime = Date.now();
const startMemory = process.memoryUsage().heapUsed;
let result;
let cacheHits = 0;
let cacheMisses = 0;
if (useCache && cacheKey) {
const cached = this.getCache(cacheKey);
if (cached !== null) {
result = cached;
cacheHits = 1;
}
else {
result = await fn();
this.setCache(cacheKey, result);
cacheMisses = 1;
}
}
else {
result = await fn();
}
const duration = Date.now() - startTime;
const memoryUsage = process.memoryUsage().heapUsed - startMemory;
const metrics = {
operation,
duration,
memoryUsage,
cacheHits,
cacheMisses
};
this.metrics.push(metrics);
if (this.verbose) {
Logger_1.logger.debug(`Operation: ${operation} - ${duration}ms, ${Math.round(memoryUsage / 1024)}KB`);
}
return result;
}
/**
* Optimize file operations with caching
*/
async readFileCached(filePath, ttl = 60000) {
const cacheKey = `file:${filePath}`;
return await this.measureOperation(`readFile:${path.basename(filePath)}`, async () => {
const cached = this.getCache(cacheKey);
if (cached !== null) {
return cached;
}
const content = await fs.readFile(filePath, 'utf-8');
this.setCache(cacheKey, content, ttl);
return content;
}, true, cacheKey);
}
/**
* Optimize directory listing with caching
*/
async readDirCached(dirPath, ttl = 30000) {
const cacheKey = `dir:${dirPath}`;
return await this.measureOperation(`readDir:${path.basename(dirPath)}`, async () => {
const cached = this.getCache(cacheKey);
if (cached !== null) {
return cached;
}
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const files = entries
.filter(entry => entry.isFile())
.map(entry => entry.name);
this.setCache(cacheKey, files, ttl);
return files;
}, true, cacheKey);
}
/**
* Optimize file existence checks
*/
async fileExistsCached(filePath, ttl = 60000) {
const cacheKey = `exists:${filePath}`;
return await this.measureOperation(`fileExists:${path.basename(filePath)}`, async () => {
const cached = this.getCache(cacheKey);
if (cached !== null) {
return cached;
}
try {
await fs.access(filePath);
this.setCache(cacheKey, true, ttl);
return true;
}
catch {
this.setCache(cacheKey, false, ttl);
return false;
}
}, true, cacheKey);
}
/**
* Batch file operations for better performance
*/
async batchFileOperations(operations, batchSize = 10) {
const results = [];
for (let i = 0; i < operations.length; i += batchSize) {
const batch = operations.slice(i, i + batchSize);
const batchPromises = batch.map(op => op.operation());
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
if (this.verbose) {
Logger_1.logger.debug(`Processed batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(operations.length / batchSize)}`);
}
}
return results;
}
/**
* Get performance summary
*/
getPerformanceSummary() {
const totalOperations = this.metrics.length;
const averageDuration = totalOperations > 0
? this.metrics.reduce((sum, m) => sum + m.duration, 0) / totalOperations
: 0;
const totalMemoryUsage = this.metrics.reduce((sum, m) => sum + m.memoryUsage, 0);
const slowestOperations = this.metrics
.sort((a, b) => b.duration - a.duration)
.slice(0, 5)
.map(m => ({ operation: m.operation, duration: m.duration }));
return {
totalOperations,
averageDuration: Math.round(averageDuration * 100) / 100,
totalMemoryUsage: Math.round(totalMemoryUsage / 1024),
cacheStats: this.getCacheStats(),
slowestOperations
};
}
/**
* Clear performance metrics
*/
clearMetrics() {
this.metrics = [];
if (this.verbose)
Logger_1.logger.debug('Cleared performance metrics');
}
/**
* Optimize memory usage
*/
optimizeMemory() {
// Clear expired cache entries
this.clearExpiredCache();
// Force garbage collection if available
if (global.gc) {
global.gc();
if (this.verbose)
Logger_1.logger.debug('Forced garbage collection');
}
// Log memory usage
const memUsage = process.memoryUsage();
if (this.verbose) {
Logger_1.logger.debug(`Memory usage: ${Math.round(memUsage.heapUsed / 1024 / 1024)}MB heap, ${Math.round(memUsage.external / 1024 / 1024)}MB external`);
}
}
}
exports.PerformanceOptimizer = PerformanceOptimizer;
//# sourceMappingURL=PerformanceOptimizer.js.map
;