UNPKG

smartui-migration-tool

Version:

Enterprise-grade CLI tool for migrating visual testing platforms to LambdaTest SmartUI

283 lines 9.75 kB
"use strict"; 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