testes/.agent/agents/PerformanceOptimizationAgen...

242 lines
7.4 KiB
JavaScript

/**
* 🤖 AGENTE DE OTIMIZAÇÃO DE PERFORMANCE
*
* Implementação programática do agente de validação de performance
*/
export class PerformanceOptimizationAgent {
constructor() {
this.name = 'PerformanceOptimizationAgent';
this.description = 'Valida e otimiza performance do sistema';
// Personalidade e Background
this.personality = {
name: 'Nina "The Optimizer"',
traits: [
'Orientada a métricas e números',
'Impaciente com lentidão',
'Eficiente e pragmática',
'Sempre pensa em escala',
'Valoriza cada milissegundo'
],
quirks: [
'Mede tudo - tem métricas para tudo',
'Fica ansiosa quando vê componentes sem memoização',
'Sonha com aplicações que carregam instantaneamente',
'Prefere otimização prematura a código lento'
],
catchphrases: [
'Isso pode ser otimizado!',
'Quantos re-renders isso causa?',
'Precisa de memoização aqui',
'Vamos fazer lazy loading disso'
]
};
this.background = {
origin: 'Ex-desenvolvedora de jogos que migrou para web e trouxe a obsessão por performance',
motivation: 'Garantir que aplicações sejam rápidas e responsivas, mesmo com milhões de usuários',
experience: '6 anos otimizando aplicações web de alta performance',
turningPoint: 'Viu uma aplicação perder 40% dos usuários por causa de lentidão no carregamento',
philosophy: 'Performance não é um recurso, é um requisito',
relationships: {
withUIAdaptation: 'Às vezes discordam - ela prioriza UX, eu priorizo performance',
withFontQuality: 'Respeita, mas acha que às vezes ele é muito detalhista',
withBrowserValidation: 'Aprecia os testes reais que validam performance também'
}
};
}
/**
* Valida um componente
* @param {string|Object} component - Componente ou caminho
* @param {Object} context - Contexto
* @returns {Promise<Object>}
*/
async validate(component, context = {}) {
const errors = [];
const warnings = [];
const metadata = {};
const componentPath = typeof component === 'string' ? component : component.path;
const componentCode = context.code || await this.readComponent(componentPath);
if (!componentCode) {
return {
passed: false,
errors: ['Não foi possível ler o componente'],
warnings: [],
metadata: {}
};
}
// 1. Verificar uso de memoização
const hasMemoization = this.hasMemoization(componentCode);
if (!hasMemoization && this.isHeavyComponent(componentCode)) {
warnings.push('Componente pesado pode se beneficiar de memoização (memo, useMemo, useCallback)');
}
// 2. Verificar code splitting
const hasLazyLoading = this.hasLazyLoading(componentCode);
if (!hasLazyLoading && this.isRouteComponent(componentCode)) {
warnings.push('Componente de rota pode se beneficiar de lazy loading (React.lazy)');
}
// 3. Verificar re-renders desnecessários
const hasUnnecessaryRenders = this.hasUnnecessaryRenders(componentCode);
if (hasUnnecessaryRenders) {
warnings.push('Pode haver re-renders desnecessários. Considere usar memo ou useMemo');
}
// 4. Verificar lógica pesada no render
const hasHeavyLogicInRender = this.hasHeavyLogicInRender(componentCode);
if (hasHeavyLogicInRender) {
warnings.push('Lógica pesada no render pode impactar performance. Considere mover para hooks ou useMemo');
}
// 5. Verificar virtualização de listas
const hasLargeLists = this.hasLargeLists(componentCode);
if (hasLargeLists && !this.hasVirtualization(componentCode)) {
warnings.push('Listas grandes podem se beneficiar de virtualização');
}
// 6. Verificar tamanho do componente
const componentSize = this.getComponentSize(componentCode);
if (componentSize > 200) {
warnings.push(`Componente muito grande (${componentSize} linhas). Considere dividir em componentes menores`);
}
const passed = errors.length === 0;
return {
passed,
errors,
warnings,
metadata: {
hasMemoization,
hasLazyLoading,
componentSize,
...metadata
}
};
}
/**
* Verifica se tem memoização
* @param {string} code - Código
* @returns {boolean}
*/
hasMemoization(code) {
return code.includes('memo') || code.includes('useMemo') ||
code.includes('useCallback') || code.includes('React.memo');
}
/**
* Verifica se é componente pesado
* @param {string} code - Código
* @returns {boolean}
*/
isHeavyComponent(code) {
const heavyIndicators = [
'map(', 'filter(', 'reduce(', 'forEach(',
'Chart', 'Graph', 'Table', 'DataTable',
'Canvas', 'SVG', 'Image'
];
return heavyIndicators.some(indicator => code.includes(indicator));
}
/**
* Verifica se tem lazy loading
* @param {string} code - Código
* @returns {boolean}
*/
hasLazyLoading(code) {
return code.includes('lazy') || code.includes('React.lazy') ||
code.includes('Suspense') || code.includes('dynamic import');
}
/**
* Verifica se é componente de rota
* @param {string} code - Código
* @returns {boolean}
*/
isRouteComponent(code) {
return code.includes('Route') || code.includes('router') ||
code.includes('View') || code.includes('Page');
}
/**
* Verifica re-renders desnecessários
* @param {string} code - Código
* @returns {boolean}
*/
hasUnnecessaryRenders(code) {
// Componentes que criam objetos/arrays no render sem memoização
const problematicPatterns = [
'className={`', 'style={{', 'props={{',
'const obj = {', 'const arr = ['
];
return problematicPatterns.some(pattern => code.includes(pattern)) &&
!code.includes('useMemo') && !code.includes('useCallback');
}
/**
* Verifica lógica pesada no render
* @param {string} code - Código
* @returns {boolean}
*/
hasHeavyLogicInRender(code) {
const heavyPatterns = [
'for (', 'while (', 'forEach(', 'map(', 'filter(',
'Math.', 'Date.', 'JSON.parse', 'JSON.stringify'
];
// Se tem lógica pesada diretamente no return ou antes do return sem useMemo
const hasHeavyLogic = heavyPatterns.some(pattern => code.includes(pattern));
const hasMemo = code.includes('useMemo');
return hasHeavyLogic && !hasMemo;
}
/**
* Verifica se tem listas grandes
* @param {string} code - Código
* @returns {boolean}
*/
hasLargeLists(code) {
return code.includes('.map(') || code.includes('Table') ||
code.includes('DataTable') || code.includes('List');
}
/**
* Verifica se tem virtualização
* @param {string} code - Código
* @returns {boolean}
*/
hasVirtualization(code) {
return code.includes('virtual') || code.includes('Virtual') ||
code.includes('react-window') || code.includes('react-virtualized');
}
/**
* Obtém tamanho do componente em linhas
* @param {string} code - Código
* @returns {number}
*/
getComponentSize(code) {
return code.split('\n').length;
}
/**
* Lê o conteúdo do componente
* @param {string} path - Caminho do arquivo
* @returns {Promise<string|null>}
*/
async readComponent(path) {
try {
const fs = await import('fs/promises');
return await fs.readFile(path, 'utf-8');
} catch (error) {
return null;
}
}
}