UNPKG

figma-to-react-mcp

Version:

Convert Figma designs to React components automatically. MCP server with GitHub, Figma, and Playwright integrations for seamless design-to-code workflow.

177 lines 6.25 kB
import { Logger } from "./logger.js"; export class PerformanceMonitor { static instance; metrics = new Map(); aggregatedMetrics = new Map(); logger; maxMetrics = 1000; constructor() { this.logger = Logger.getInstance(); } static getInstance() { if (!PerformanceMonitor.instance) { PerformanceMonitor.instance = new PerformanceMonitor(); } return PerformanceMonitor.instance; } startTiming(name, metadata) { const id = `${name}-${Date.now()}-${Math.random() .toString(36) .substr(2, 9)}`; this.metrics.set(id, { name, startTime: performance.now(), memoryStart: process.memoryUsage(), metadata: metadata || {}, }); return id; } endTiming(id) { const metric = this.metrics.get(id); if (!metric) { this.logger.warn(`Performance metric not found: ${id}`); return null; } const endTime = performance.now(); const duration = endTime - metric.startTime; const memoryEnd = process.memoryUsage(); const completedMetric = { ...metric, endTime, duration, memoryEnd, }; this.metrics.set(id, completedMetric); this.updateAggregatedMetrics(metric.name, duration); if (this.metrics.size > this.maxMetrics) { this.cleanupOldMetrics(); } return completedMetric; } measureAsync(name, fn, metadata) { const id = this.startTiming(name, metadata); return fn() .then((result) => { const metric = this.endTiming(id); if (metric && metric.duration) { this.logger.debug(`${name} completed in ${metric.duration.toFixed(2)}ms`); } return result; }) .catch((error) => { this.endTiming(id); this.logger.error(`${name} failed`, error); throw error; }); } measureSync(name, fn, metadata) { const id = this.startTiming(name, metadata); try { const result = fn(); const metric = this.endTiming(id); if (metric && metric.duration) { this.logger.debug(`${name} completed in ${metric.duration.toFixed(2)}ms`); } return result; } catch (error) { this.endTiming(id); this.logger.error(`${name} failed`, error); throw error; } } getMetric(id) { return this.metrics.get(id); } getAggregatedMetrics(name) { if (name) { return this.aggregatedMetrics.get(name); } return this.aggregatedMetrics; } getTopSlowOperations(limit = 10) { return Array.from(this.aggregatedMetrics.entries()) .sort((a, b) => b[1].averageDuration - a[1].averageDuration) .slice(0, limit) .map(([name, metrics]) => ({ name, metrics })); } logPerformanceSummary() { const summary = this.generatePerformanceSummary(); this.logger.info("Performance Summary", summary); } updateAggregatedMetrics(name, duration) { const existing = this.aggregatedMetrics.get(name); if (existing) { existing.totalExecutions++; existing.totalDuration += duration; existing.averageDuration = existing.totalDuration / existing.totalExecutions; existing.minDuration = Math.min(existing.minDuration, duration); existing.maxDuration = Math.max(existing.maxDuration, duration); existing.lastExecution = Date.now(); } else { this.aggregatedMetrics.set(name, { totalExecutions: 1, averageDuration: duration, minDuration: duration, maxDuration: duration, totalDuration: duration, lastExecution: Date.now(), }); } } cleanupOldMetrics() { const now = performance.now(); const oneHourAgo = now - 60 * 60 * 1000; for (const [id, metric] of this.metrics.entries()) { if (metric.startTime < oneHourAgo) { this.metrics.delete(id); } } } generatePerformanceSummary() { const totalOperations = Array.from(this.aggregatedMetrics.values()).reduce((sum, metrics) => sum + metrics.totalExecutions, 0); const slowestOperations = this.getTopSlowOperations(5); return { totalOperations, uniqueOperations: this.aggregatedMetrics.size, slowestOperations: slowestOperations.map(({ name, metrics }) => ({ name, averageDuration: `${metrics.averageDuration.toFixed(2)}ms`, totalExecutions: metrics.totalExecutions, })), memoryUsage: this.getMemoryUsage(), }; } getMemoryUsage() { const usage = process.memoryUsage(); return { heapUsed: `${(usage.heapUsed / 1024 / 1024).toFixed(2)} MB`, heapTotal: `${(usage.heapTotal / 1024 / 1024).toFixed(2)} MB`, external: `${(usage.external / 1024 / 1024).toFixed(2)} MB`, rss: `${(usage.rss / 1024 / 1024).toFixed(2)} MB`, }; } clear() { this.metrics.clear(); this.aggregatedMetrics.clear(); } } export function measurePerformance(name) { return function (target, propertyName, descriptor) { const method = descriptor.value; const monitor = PerformanceMonitor.getInstance(); const metricName = name || `${target.constructor.name}.${propertyName}`; descriptor.value = async function (...args) { if (method.constructor.name === "AsyncFunction") { return monitor.measureAsync(metricName, () => method.apply(this, args)); } else { return monitor.measureSync(metricName, () => method.apply(this, args)); } }; return descriptor; }; } //# sourceMappingURL=performance.js.map