251 lines
7.9 KiB
JavaScript
251 lines
7.9 KiB
JavaScript
/**
|
|
* 🤖 AGENTE DE INTEGRIDADE DE DADOS
|
|
*
|
|
* Implementação programática do agente de validação de integridade de dados
|
|
*/
|
|
|
|
export class DataIntegrityAgent {
|
|
constructor() {
|
|
this.name = 'DataIntegrityAgent';
|
|
this.description = 'Valida integridade e mapeamento de dados front-back';
|
|
|
|
// Personalidade e Background
|
|
this.personality = {
|
|
name: 'Dr. Data "The Mapper"',
|
|
traits: [
|
|
'Analítico e preciso',
|
|
'Obsessivo com detalhes de dados',
|
|
'Sistemático e organizado',
|
|
'Cético até provar o contrário',
|
|
'Valoriza documentação e tipos'
|
|
],
|
|
quirks: [
|
|
'Sempre verifica null/undefined antes de confiar',
|
|
'Tem uma memória fotográfica de estruturas de dados',
|
|
'Fica incomodado quando vê dados sem tipagem',
|
|
'Prefere JSDoc detalhado a código sem documentação'
|
|
],
|
|
catchphrases: [
|
|
'E se esse campo vier null?',
|
|
'Onde está a tipagem disso?',
|
|
'Isso está mapeado corretamente?',
|
|
'Precisamos validar esse dado antes de usar'
|
|
]
|
|
};
|
|
|
|
this.background = {
|
|
origin: 'Ex-backend developer que migrou para frontend e viu o caos de dados não tipados',
|
|
motivation: 'Garantir que nenhum dado seja perdido ou corrompido na jornada front-back',
|
|
experience: '8 anos trabalhando com APIs e mapeamento de dados',
|
|
turningPoint: 'Perdeu um fim de semana inteiro debugando um bug causado por um campo null não tratado',
|
|
philosophy: 'Dados são sagrados - devem ser tratados com respeito e precisão',
|
|
relationships: {
|
|
withBrowserValidation: 'Trabalham em parceria - ele valida o fluxo, eu valido os dados',
|
|
withSecurity: 'Compartilha a preocupação com integridade, mas foca em dados, não em segurança',
|
|
withDocumentation: 'Aprecia muito a documentação que ele manté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 null-safety
|
|
const hasNullSafety = this.hasNullSafetyChecks(componentCode);
|
|
if (!hasNullSafety && this.usesApiData(componentCode)) {
|
|
warnings.push('Componente pode não estar tratando valores null/undefined da API');
|
|
}
|
|
|
|
// 2. Verificar formatação de dados
|
|
const needsFormatting = this.needsDataFormatting(componentCode);
|
|
if (needsFormatting && !this.hasFormatting(componentCode)) {
|
|
warnings.push('Dados podem precisar de formatação (datas, moedas, CPF/CNPJ)');
|
|
}
|
|
|
|
// 3. Verificar uso de Service para mapeamento
|
|
const usesDirectApi = this.usesDirectApi(componentCode);
|
|
if (usesDirectApi) {
|
|
warnings.push('Comunicação com API deve ser feita via Services para melhor mapeamento de dados');
|
|
}
|
|
|
|
// 4. Verificar tratamento de valores falsy
|
|
const hasFalsyIssues = this.hasFalsyValueIssues(componentCode);
|
|
if (hasFalsyIssues) {
|
|
warnings.push('Pode haver problemas com valores 0 ou false sendo ocultados erroneamente');
|
|
}
|
|
|
|
// 5. Verificar sincronização de estado
|
|
const hasStateSync = this.hasStateSynchronization(componentCode);
|
|
if (!hasStateSync && this.hasDataUpdates(componentCode)) {
|
|
warnings.push('Atualizações de dados podem não estar sincronizando com a interface');
|
|
}
|
|
|
|
// 6. Verificar JSDoc/types
|
|
const hasTypeDocumentation = this.hasTypeDocumentation(componentCode);
|
|
if (!hasTypeDocumentation && this.usesComplexData(componentCode)) {
|
|
warnings.push('Componente pode se beneficiar de documentação de tipos (JSDoc)');
|
|
}
|
|
|
|
const passed = errors.length === 0;
|
|
|
|
return {
|
|
passed,
|
|
errors,
|
|
warnings,
|
|
metadata: {
|
|
hasNullSafety,
|
|
hasFormatting,
|
|
hasTypeDocumentation,
|
|
...metadata
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem checks de null-safety
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasNullSafetyChecks(code) {
|
|
const nullSafetyPatterns = [
|
|
'?.', '??', 'optional chaining', 'nullish',
|
|
'||', 'if (', '&&', '?.map', '?.filter'
|
|
];
|
|
return nullSafetyPatterns.some(pattern => code.includes(pattern));
|
|
}
|
|
|
|
/**
|
|
* Verifica se usa dados de API
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
usesApiData(code) {
|
|
return code.includes('data') || code.includes('response') ||
|
|
code.includes('api') || code.includes('fetch') || code.includes('axios');
|
|
}
|
|
|
|
/**
|
|
* Verifica se precisa de formatação
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
needsDataFormatting(code) {
|
|
return code.includes('date') || code.includes('Date') ||
|
|
code.includes('price') || code.includes('value') ||
|
|
code.includes('cpf') || code.includes('cnpj') || code.includes('CPF') || code.includes('CNPJ');
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem formatação
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasFormatting(code) {
|
|
return code.includes('format') || code.includes('Format') ||
|
|
code.includes('toLocaleString') || code.includes('toFixed') ||
|
|
code.includes('Intl') || code.includes('mask');
|
|
}
|
|
|
|
/**
|
|
* Verifica se usa API diretamente
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
usesDirectApi(code) {
|
|
return (code.includes('axios') || code.includes('fetch')) &&
|
|
!code.includes('Service') && !code.includes('service');
|
|
}
|
|
|
|
/**
|
|
* Verifica problemas com valores falsy
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasFalsyValueIssues(code) {
|
|
// Padrões problemáticos: && data.value (oculta 0), !data (oculta false)
|
|
const problematicPatterns = [
|
|
'&& data.', '&& item.', '&& value.',
|
|
'!data &&', '!item &&', '!value &&'
|
|
];
|
|
return problematicPatterns.some(pattern => code.includes(pattern));
|
|
}
|
|
|
|
/**
|
|
* Verifica sincronização de estado
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasStateSynchronization(code) {
|
|
return code.includes('useState') || code.includes('useEffect') ||
|
|
code.includes('refetch') || code.includes('invalidate') ||
|
|
code.includes('setState') || code.includes('update');
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem atualizações de dados
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasDataUpdates(code) {
|
|
return code.includes('update') || code.includes('edit') ||
|
|
code.includes('save') || code.includes('submit') ||
|
|
code.includes('create') || code.includes('delete');
|
|
}
|
|
|
|
/**
|
|
* Verifica se usa dados complexos
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
usesComplexData(code) {
|
|
return code.includes('object') || code.includes('array') ||
|
|
code.includes('interface') || code.includes('type ') ||
|
|
code.includes('{') && code.includes('}');
|
|
}
|
|
|
|
/**
|
|
* Verifica se tem documentação de tipos
|
|
* @param {string} code - Código
|
|
* @returns {boolean}
|
|
*/
|
|
hasTypeDocumentation(code) {
|
|
return code.includes('/**') || code.includes('@typedef') ||
|
|
code.includes('@param') || code.includes('@property') ||
|
|
code.includes('interface') || code.includes('type ');
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
}
|
|
}
|