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