#!/usr/bin/env node const readline = require('readline'); const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const https = require('https'); const http = require('http'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // 🎨 Cores para console const colors = { reset: '\x1b[0m', bright: '\x1b[1m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m' }; const log = { info: (msg) => console.log(`${colors.blue}ℹ️ ${msg}${colors.reset}`), success: (msg) => console.log(`${colors.green}✅ ${msg}${colors.reset}`), warning: (msg) => console.log(`${colors.yellow}⚠️ ${msg}${colors.reset}`), error: (msg) => console.log(`${colors.red}❌ ${msg}${colors.reset}`), title: (msg) => console.log(`${colors.cyan}${colors.bright}🚀 ${msg}${colors.reset}\n`), step: (msg) => console.log(`${colors.bright}🔧 ${msg}${colors.reset}`) }; // 🔐 Configuração da API PraFrota let apiCredentials = { token: null, tenantId: null, baseUrl: 'https://prafrota-be-bff-tenant-api.grupopra.tech' }; // 📝 Configuração do domínio V2.0 - EXPANDIDA let domainConfig = { // Básicos name: '', displayName: '', menuPosition: '', // Funcionalidades V1 hasPhotos: false, hasSideCard: false, hasKilometer: false, hasColor: false, hasStatus: false, remoteSelects: [], // ✨ NOVOS V2.0 - Core Patterns hasFooter: false, footerConfig: { columns: [] // { field, type, format, label, precision } }, hasCheckboxGrouped: false, checkboxGroupedConfig: { fieldName: 'options', groups: [] // { id, label, icon, items } }, hasBulkActions: false, bulkActionsConfig: { type: 'basic', // 'basic' | 'advanced' actions: [] }, // ✨ NOVOS V2.0 - Enhanced Patterns hasDateRangeUtils: false, hasAdvancedSideCard: false, sideCardConfig: { imageField: '', statusConfig: {}, formatFunctions: [] }, hasExtendedSearchOptions: false, searchOptionsConfig: { useStates: false, useVehicleTypes: false, useStatusComplex: false, customOptions: [] }, // ✨ NOVOS V2.0 - Advanced Patterns hasAdvancedSubTabs: false, subTabsConfig: { enableComponents: false, dynamicComponents: [] } }; // 🎯 TEMPLATES LIBRARY V2.0 // ===== FOOTER CONFIG TEMPLATES ===== const FooterTemplates = { count: { type: 'count', format: 'default', label: 'Total:', precision: 0 }, sum_currency: { type: 'sum', format: 'currency', label: 'Total:', precision: 2 }, sum_number: { type: 'sum', format: 'number', label: 'Total:', precision: 2 }, avg_number: { type: 'avg', format: 'number', label: 'Média:', precision: 1 }, avg_default: { type: 'avg', format: 'default', label: 'Média:', precision: 0 }, min_number: { type: 'min', format: 'number', label: 'Mínimo:', precision: 2 }, max_number: { type: 'max', format: 'number', label: 'Máximo:', precision: 2 } }; // ===== CHECKBOX GROUPED TEMPLATES ===== const CheckboxGroupedTemplates = { security: { id: 'security', label: 'Segurança', icon: 'fa-shield-alt', items: [ { id: 1, name: 'Airbag', value: false }, { id: 2, name: 'Freios ABS', value: false }, { id: 3, name: 'Alarme antifurto', value: false }, { id: 4, name: 'Cinto de 3 pontos', value: false }, { id: 5, name: 'Controle de tração', value: false } ] }, comfort: { id: 'comfort', label: 'Conforto', icon: 'fa-couch', expanded: false, items: [ { id: 51, name: 'Ar-condicionado', value: false }, { id: 52, name: 'Direção elétrica', value: false }, { id: 53, name: 'Vidros elétricos', value: false }, { id: 54, name: 'Piloto automático', value: false } ] }, multimedia: { id: 'multimedia', label: 'Multimídia', icon: 'fa-tv', expanded: false, items: [ { id: 101, name: 'Central multimídia', value: false }, { id: 102, name: 'GPS integrado', value: false }, { id: 103, name: 'Bluetooth', value: false }, { id: 104, name: 'USB', value: false } ] } }; // ===== BULK ACTIONS TEMPLATES ===== const BulkActionsTemplates = { basic: [ { id: 'delete-selected', label: 'Excluir Selecionados', icon: 'fas fa-trash', action: `(selectedItems) => this.bulkDelete(selectedItems as ${capitalize(domainConfig.name)}[])` }, { id: 'export-selected', label: 'Exportar Selecionados', icon: 'fas fa-download', action: `(selectedItems) => this.bulkExport(selectedItems as ${capitalize(domainConfig.name)}[])` } ], advanced: [ { id: 'update-data', label: 'Atualizar Dados', icon: 'fas fa-sync-alt', subActions: [ { id: 'update-api-external', label: 'Via API Externa', icon: 'fas fa-cloud', action: `(selectedItems) => this.updateViaExternalAPI(selectedItems as ${capitalize(domainConfig.name)}[])` }, { id: 'update-bulk-edit', label: 'Edição em Lote', icon: 'fas fa-edit', action: `(selectedItems) => this.bulkEdit(selectedItems as ${capitalize(domainConfig.name)}[])` } ] }, { id: 'status-change', label: 'Alterar Status', icon: 'fas fa-toggle-on', action: `(selectedItems) => this.bulkStatusChange(selectedItems as ${capitalize(domainConfig.name)}[])` } ] }; // ===== SEARCH OPTIONS LIBRARY ===== const SearchOptionsLibrary = { estados: [ { value: "AC", label: "Acre" }, { value: "AL", label: "Alagoas" }, { value: "AP", label: "Amapá" }, { value: "AM", label: "Amazonas" }, { value: "BA", label: "Bahia" }, { value: "CE", label: "Ceará" }, { value: "DF", label: "Distrito Federal" }, { value: "ES", label: "Espírito Santo" }, { value: "GO", label: "Goiás" }, { value: "MA", label: "Maranhão" }, { value: "MT", label: "Mato Grosso" }, { value: "MS", label: "Mato Grosso do Sul" }, { value: "MG", label: "Minas Gerais" }, { value: "PA", label: "Pará" }, { value: "PB", label: "Paraíba" }, { value: "PR", label: "Paraná" }, { value: "PE", label: "Pernambuco" }, { value: "PI", label: "Piauí" }, { value: "RJ", label: "Rio de Janeiro" }, { value: "RN", label: "Rio Grande do Norte" }, { value: "RS", label: "Rio Grande do Sul" }, { value: "RO", label: "Rondônia" }, { value: "RR", label: "Roraima" }, { value: "SC", label: "Santa Catarina" }, { value: "SP", label: "São Paulo" }, { value: "SE", label: "Sergipe" }, { value: "TO", label: "Tocantins" } ], vehicleTypes: [ { value: 'CAR', label: 'Carro' }, { value: 'PICKUP_TRUCK', label: 'Caminhonete' }, { value: 'TRUCK', label: 'Caminhão' }, { value: 'TRUCK_TRAILER', label: 'Caminhão com Carreta' }, { value: 'MOTORCYCLE', label: 'Motocicleta' }, { value: 'VAN', label: 'Van' }, { value: 'BUS', label: 'Ônibus' }, { value: 'TRAILER', label: 'Carreta' }, { value: 'SEMI_TRUCK', label: 'Semi-Reboque' }, { value: 'MINIBUS', label: 'Micro Ônibus' }, { value: 'MOTOR_SCOOTER', label: 'Motoneta' }, { value: 'MOPED', label: 'Ciclomotor' }, { value: 'TRICYCLE', label: 'Triciclo' }, { value: 'UTILITY', label: 'Utilitário' }, { value: 'OTHER', label: 'Outro' } ], statusComplex: [ { value: 'active', label: 'Ativo' }, { value: 'inactive', label: 'Inativo' }, { value: 'pending', label: 'Pendente' }, { value: 'processing', label: 'Processando' }, { value: 'completed', label: 'Concluído' }, { value: 'cancelled', label: 'Cancelado' }, { value: 'suspended', label: 'Suspenso' }, { value: 'archived', label: 'Arquivado' } ] }; // 🔐 FUNÇÕES DE CONSULTA À API REAL async function requestAuthCredentials() { log.title('🔐 CONFIGURAÇÃO DA API'); log.info('Para gerar interfaces baseadas em dados reais, precisamos acessar a API PraFrota.'); log.info(''); log.info('📋 Como obter as credenciais:'); log.info('1. Abra a aplicação no navegador (localhost:4200)'); log.info('2. Faça login normalmente'); log.info('3. Abra DevTools (F12) → Console'); log.info('4. Execute: localStorage.getItem("prafrota_auth_token")'); log.info('5. Execute: localStorage.getItem("tenant_id")'); log.info(''); return new Promise((resolve) => { rl.question(`${colors.bright}🔑 Token de autenticação (ou deixe vazio para pular):${colors.reset} `, (token) => { if (!token.trim()) { log.warning('Token não fornecido. Usando geração de interface padrão.'); apiCredentials.token = null; apiCredentials.tenantId = null; resolve(); return; } apiCredentials.token = token.trim(); rl.question(`${colors.bright}🏢 Tenant ID:${colors.reset} `, (tenantId) => { apiCredentials.tenantId = tenantId.trim(); log.success('Credenciais configuradas! Tentaremos acessar dados reais da API.'); resolve(); }); }); }); } async function analyzeRealAPI(domainName) { if (!apiCredentials.token || !apiCredentials.tenantId) { log.info('Credenciais não fornecidas. Usando interface padrão.'); return { success: false, reason: 'no_credentials' }; } log.step(`🔍 Analisando API real para domínio: ${domainName}`); // Endpoints para testar (singular e plural) const endpoints = [ `${domainName}?page=1&limit=1`, `${domainName}s?page=1&limit=1`, `api/${domainName}?page=1&limit=1`, `api/${domainName}s?page=1&limit=1` ]; for (const endpoint of endpoints) { try { log.info(`🔍 Testando endpoint: ${endpoint}`); const response = await makeAPIRequest(endpoint); if (response && response.data && Array.isArray(response.data) && response.data.length > 0) { const sampleObject = response.data[0]; log.success(`✅ Dados reais encontrados! ${Object.keys(sampleObject).length} campos detectados`); log.info(`📊 Total de registros: ${response.totalCount || 'N/A'}`); log.info(`🔗 Endpoint usado: ${endpoint}`); // Mostrar preview dos campos log.info('📝 Campos detectados:'); Object.entries(sampleObject).slice(0, 5).forEach(([key, value]) => { const type = typeof value; const preview = type === 'string' && value.length > 30 ? value.substring(0, 30) + '...' : value; log.info(` • ${key} (${type}): ${preview}`); }); if (Object.keys(sampleObject).length > 5) { log.info(` ... e mais ${Object.keys(sampleObject).length - 5} campos`); } return { success: true, strategy: 'real_api_data', interface: generateInterfaceFromRealData(domainName, sampleObject), fields: extractFieldsFromRealData(sampleObject), metadata: { source: 'authenticated_api', endpoint: endpoint, sampleSize: response.data.length, totalCount: response.totalCount || 'unknown', timestamp: new Date().toISOString() } }; } else { log.warning(`⚠️ Endpoint ${endpoint} sem dados válidos`); } } catch (error) { log.warning(`⚠️ Erro no endpoint ${endpoint}: ${error.message}`); } } log.error('❌ Nenhum endpoint retornou dados válidos'); return { success: false, reason: 'no_data_found', message: 'Endpoints existem mas não retornaram dados válidos. Verifique se o domínio existe na API.' }; } async function makeAPIRequest(endpoint) { const fullUrl = `${apiCredentials.baseUrl}/${endpoint}`; return new Promise((resolve, reject) => { const urlParts = new URL(fullUrl); const options = { hostname: urlParts.hostname, port: urlParts.port || 443, path: urlParts.pathname + urlParts.search, method: 'GET', headers: { 'Accept': 'application/json', 'x-tenant-user-auth': apiCredentials.token, 'x-tenant-uuid': apiCredentials.tenantId, 'User-Agent': 'Create-Domain-V2.0' } }; const req = https.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve(JSON.parse(data)); } catch (error) { reject(new Error('Invalid JSON response')); } }); }); req.on('error', (error) => { reject(error); }); req.setTimeout(10000, () => { req.destroy(); reject(new Error('Request timeout')); }); req.end(); }); } function generateInterfaceFromRealData(domainName, sampleObject) { const className = domainName.charAt(0).toUpperCase() + domainName.slice(1); let interfaceCode = `/** * 🎯 ${className} Interface - DADOS REAIS DA API PraFrota * * ✨ Auto-gerado a partir de dados reais da API autenticada * 📅 Gerado em: ${new Date().toLocaleString()} * 🔗 Fonte: API Response Analysis com autenticação */ export interface ${className} {\n`; Object.entries(sampleObject).forEach(([key, value]) => { const type = detectTypeScriptFromRealData(value); const isOptional = value === null || value === undefined; const optional = isOptional ? '?' : ''; const description = inferFieldDescription(key, type); interfaceCode += ` ${key}${optional}: ${type}; // ${description}\n`; }); interfaceCode += '}'; return interfaceCode; } function detectTypeScriptFromRealData(value) { if (value === null || value === undefined) return 'any'; const type = typeof value; if (type === 'string') { // Detectar datas ISO if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) return 'string'; // Detectar emails if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'string'; return 'string'; } if (type === 'number') return 'number'; if (type === 'boolean') return 'boolean'; if (Array.isArray(value)) { if (value.length === 0) return 'any[]'; return `${detectTypeScriptFromRealData(value[0])}[]`; } if (type === 'object') return 'any'; return 'any'; } function extractFieldsFromRealData(sampleObject) { return Object.entries(sampleObject).map(([name, value]) => ({ name, type: detectTypeScriptFromRealData(value), required: value !== null && value !== undefined, description: inferFieldDescription(name, detectTypeScriptFromRealData(value)), realValue: typeof value === 'string' ? value.substring(0, 50) + '...' : value })); } function inferFieldDescription(fieldName, type) { const descriptions = { id: 'Identificador único', name: 'Nome do registro', email: 'Endereço de email', phone: 'Número de telefone', address: 'Endereço', status: 'Status do registro', active: 'Se está ativo', created_at: 'Data de criação', updated_at: 'Data de atualização', deleted_at: 'Data de exclusão', description: 'Descrição', title: 'Título', price: 'Preço', amount: 'Valor/Quantia', quantity: 'Quantidade', user_id: 'ID do usuário', company_id: 'ID da empresa', tenant_id: 'ID do tenant', brand: 'Marca', model: 'Modelo', year: 'Ano', plate: 'Placa' }; return descriptions[fieldName] || `Campo ${fieldName} (${type})`; } // 🎯 Função principal async function main() { try { log.title('CRIADOR DE DOMÍNIOS V2.0 - SISTEMA PRAFROTA'); log.info('🆕 Versão 2.0 com FooterConfig, CheckboxGrouped, BulkActions e mais!'); // Verificar pré-requisitos await checkPrerequisites(); // 🔐 Solicitar credenciais da API (novo V2.0) await requestAuthCredentials(); // Coletar informações V2.0 await gatherDomainInfoV2(); // Confirmar configuração await confirmConfigurationV2(); // Criar branch para o desenvolvimento await createBranch(); // Gerar domínio V2.0 await generateDomainV2(); // Compilar e testar await compileAndTest(); // Commit automático await autoCommit(); log.success('🎉 DOMÍNIO V2.0 CRIADO COM SUCESSO!'); log.success('🚀 Sistema totalmente integrado com todos os padrões mais recentes!'); showNewFeaturesV2(); } catch (error) { log.error(`Erro: ${error.message}`); process.exit(1); } finally { rl.close(); } } // ===== V2.0 SPECIFIC FUNCTIONS ===== // 📝 Coletar informações V2.0 async function gatherDomainInfoV2() { log.title('CONFIGURAÇÃO DO DOMÍNIO V2.0'); // Básicos await gatherBasicInfo(); // ✨ NOVO: Footer Configuration await gatherFooterConfig(); // ✨ NOVO: Checkbox Grouped Configuration await gatherCheckboxGroupedConfig(); // ✨ NOVO: Bulk Actions Configuration await gatherBulkActionsConfig(); // ✨ NOVO: Enhanced Features await gatherEnhancedFeaturesConfig(); // Funcionalidades V1 (legacy) await gatherLegacyFeatures(); } // Helper para perguntas yes/no function askYesNo(question) { return new Promise((resolve) => { rl.question(`${question} (s/N): `, (answer) => { resolve(answer.toLowerCase() === 's' || answer.toLowerCase() === 'sim'); }); }); } // Helper para perguntas com opções function askOptions(question, options) { return new Promise((resolve) => { const optionsText = options.map((opt, i) => `${i + 1}. ${opt}`).join('\n'); rl.question(`${question}\n${optionsText}\nEscolha (1-${options.length}): `, (answer) => { const index = parseInt(answer) - 1; if (index >= 0 && index < options.length) { resolve(options[index]); } else { log.warning('Opção inválida, usando primeira opção'); resolve(options[0]); } }); }); } // Configuração básica async function gatherBasicInfo() { domainConfig.name = await ask('Nome do domínio (ex: products): '); domainConfig.displayName = await ask('Nome para exibição (ex: Produtos): '); domainConfig.menuPosition = await ask('Posição no menu (após qual item): '); } // ✨ NOVO: Footer Configuration async function gatherFooterConfig() { log.info('\n📊 CONFIGURAÇÃO DE FOOTER NAS COLUNAS'); domainConfig.hasFooter = await askYesNo('Deseja footer com totalização nas colunas?'); if (domainConfig.hasFooter) { log.info('Tipos disponíveis: count, sum_currency, sum_number, avg_number, avg_default, min_number, max_number'); const numColumns = await askNumber('Quantas colunas terão footer? (1-5): ', 1, 5); for (let i = 0; i < numColumns; i++) { log.info(`\n--- Coluna ${i + 1} ---`); const field = await ask(`Campo da coluna ${i + 1} (ex: price, quantity): `); const type = await askOptions(`Tipo de footer para ${field}:`, [ 'count', 'sum_currency', 'sum_number', 'avg_number', 'avg_default' ]); domainConfig.footerConfig.columns.push({ field, ...FooterTemplates[type] }); } } } // ✨ NOVO: Checkbox Grouped Configuration async function gatherCheckboxGroupedConfig() { log.info('\n☑️ CONFIGURAÇÃO DE CHECKBOX AGRUPADO'); domainConfig.hasCheckboxGrouped = await askYesNo('Deseja checkbox agrupado (ex: opcionais, características)?'); if (domainConfig.hasCheckboxGrouped) { domainConfig.checkboxGroupedConfig.fieldName = await ask('Nome do campo (ex: options, features): ') || 'options'; const groupTypes = await askOptions('Quais grupos incluir:', [ 'Segurança + Conforto', 'Segurança + Conforto + Multimídia', 'Todos os grupos', 'Customizado' ]); switch (groupTypes) { case 'Segurança + Conforto': domainConfig.checkboxGroupedConfig.groups = [ CheckboxGroupedTemplates.security, CheckboxGroupedTemplates.comfort ]; break; case 'Segurança + Conforto + Multimídia': domainConfig.checkboxGroupedConfig.groups = [ CheckboxGroupedTemplates.security, CheckboxGroupedTemplates.comfort, CheckboxGroupedTemplates.multimedia ]; break; case 'Todos os grupos': domainConfig.checkboxGroupedConfig.groups = Object.values(CheckboxGroupedTemplates); break; default: log.info('Modo customizado não implementado, usando Segurança + Conforto'); domainConfig.checkboxGroupedConfig.groups = [ CheckboxGroupedTemplates.security, CheckboxGroupedTemplates.comfort ]; } } } // ✨ NOVO: Bulk Actions Configuration async function gatherBulkActionsConfig() { log.info('\n⚡ CONFIGURAÇÃO DE AÇÕES EM LOTE'); domainConfig.hasBulkActions = await askYesNo('Deseja ações em lote (bulk actions)?'); if (domainConfig.hasBulkActions) { domainConfig.bulkActionsConfig.type = await askOptions('Tipo de ações:', [ 'basic', 'advanced' ]); domainConfig.bulkActionsConfig.actions = BulkActionsTemplates[domainConfig.bulkActionsConfig.type]; } } // ✨ NOVO: Enhanced Features Configuration async function gatherEnhancedFeaturesConfig() { log.info('\n🚀 FUNCIONALIDADES AVANÇADAS'); // DateRangeUtils domainConfig.hasDateRangeUtils = await askYesNo('Integrar DateRangeUtils automaticamente?'); // Advanced SideCard if (await askYesNo('Deseja SideCard avançado (com statusConfig e imageField)?')) { domainConfig.hasAdvancedSideCard = true; domainConfig.sideCardConfig.imageField = await ask('Campo para imagem (ex: photos, images): ') || 'photos'; } // Extended Search Options domainConfig.hasExtendedSearchOptions = await askYesNo('Usar searchOptions pré-definidos (Estados, Status, etc.)?'); if (domainConfig.hasExtendedSearchOptions) { domainConfig.searchOptionsConfig.useStates = await askYesNo(' • Incluir Estados (UF)?'); domainConfig.searchOptionsConfig.useVehicleTypes = await askYesNo(' • Incluir Tipos de Veículo?'); domainConfig.searchOptionsConfig.useStatusComplex = await askYesNo(' • Incluir Status Complexos?'); } // Advanced SubTabs domainConfig.hasAdvancedSubTabs = await askYesNo('Usar SubTabs avançadas (componentes dinâmicos)?'); } // Legacy features (V1) async function gatherLegacyFeatures() { log.info('\n📋 FUNCIONALIDADES BÁSICAS'); domainConfig.hasPhotos = await askYesNo('Incluir sub-aba de fotos?'); domainConfig.hasSideCard = await askYesNo('Incluir side card básico?') && !domainConfig.hasAdvancedSideCard; domainConfig.hasStatus = await askYesNo('Incluir campo de status?'); domainConfig.hasKilometer = await askYesNo('Incluir campo de quilometragem?'); domainConfig.hasColor = await askYesNo('Incluir campo de cor?'); } // Helper functions function ask(question) { return new Promise((resolve) => { rl.question(question, (answer) => { resolve(answer.trim()); }); }); } function askNumber(question, min = 1, max = 10) { return new Promise((resolve) => { rl.question(question, (answer) => { const num = parseInt(answer); if (num >= min && num <= max) { resolve(num); } else { log.warning(`Número inválido, usando ${min}`); resolve(min); } }); }); } function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } // Mostrar novas funcionalidades V2.0 function showNewFeaturesV2() { log.info('\n🎯 FUNCIONALIDADES V2.0 IMPLEMENTADAS:'); if (domainConfig.hasFooter) { log.success(` ✅ FooterConfig: ${domainConfig.footerConfig.columns.length} colunas com totalização`); } if (domainConfig.hasCheckboxGrouped) { log.success(` ✅ CheckboxGrouped: ${domainConfig.checkboxGroupedConfig.groups.length} grupos configurados`); } if (domainConfig.hasBulkActions) { log.success(` ✅ BulkActions: Modo ${domainConfig.bulkActionsConfig.type}`); } if (domainConfig.hasDateRangeUtils) { log.success(` ✅ DateRangeUtils: Integração automática`); } if (domainConfig.hasAdvancedSideCard) { log.success(` ✅ SideCard Avançado: Com statusConfig e imageField`); } if (domainConfig.hasExtendedSearchOptions) { log.success(` ✅ SearchOptions Estendidos: Estados, Tipos, Status`); } log.info('\n📝 Próximos passos:'); log.info(` 1. Testar: http://localhost:4200/app/${domainConfig.name}`); log.info(` 2. Push: git push origin feature/domain-${domainConfig.name}`); log.info(` 3. Documentar: Adicionar no .mcp/config.json`); } // Confirmar configuração V2.0 async function confirmConfigurationV2() { log.title('CONFIRMAÇÃO DA CONFIGURAÇÃO V2.0'); console.log('📋 Resumo:'); console.log(` • Domínio: ${domainConfig.name} (${domainConfig.displayName})`); console.log(` • Menu: Após "${domainConfig.menuPosition}"`); // V2.0 Features console.log('\n🆕 Funcionalidades V2.0:'); console.log(` • Footer: ${domainConfig.hasFooter ? '✅ ' + domainConfig.footerConfig.columns.length + ' colunas' : '❌'}`); console.log(` • CheckboxGrouped: ${domainConfig.hasCheckboxGrouped ? '✅ ' + domainConfig.checkboxGroupedConfig.groups.length + ' grupos' : '❌'}`); console.log(` • BulkActions: ${domainConfig.hasBulkActions ? '✅ ' + domainConfig.bulkActionsConfig.type : '❌'}`); console.log(` • DateRangeUtils: ${domainConfig.hasDateRangeUtils ? '✅' : '❌'}`); console.log(` • SideCard Avançado: ${domainConfig.hasAdvancedSideCard ? '✅' : '❌'}`); console.log(` • SearchOptions Estendidos: ${domainConfig.hasExtendedSearchOptions ? '✅' : '❌'}`); // V1 Features console.log('\n📋 Funcionalidades Básicas:'); console.log(` • Fotos: ${domainConfig.hasPhotos ? '✅' : '❌'}`); console.log(` • SideCard: ${domainConfig.hasSideCard ? '✅' : '❌'}`); console.log(` • Status: ${domainConfig.hasStatus ? '✅' : '❌'}`); console.log(` • Quilometragem: ${domainConfig.hasKilometer ? '✅' : '❌'}`); console.log(` • Cor: ${domainConfig.hasColor ? '✅' : '❌'}`); const confirm = await askYesNo('\nConfirma a criação do domínio com estas configurações?'); if (!confirm) { throw new Error('Operação cancelada pelo usuário'); } } // ===== GERAÇÃO V2.0 ===== // Gerar domínio V2.0 async function generateDomainV2() { log.title('GERANDO DOMÍNIO V2.0'); // Criar estrutura de pastas await createDirectoryStructure(); // Gerar arquivos V2.0 await generateComponentV2(); await generateServiceV2(); await generateInterfaceV2(); await generateTemplatesV2(); // Integrações V2.0 await updateRoutingV2(); await updateSidebarV2(); await updateMCPConfigV2(); log.success('Domínio V2.0 gerado com sucesso!'); } // ===== FUNÇÕES AUXILIARES V2.0 ===== // Verificar pré-requisitos async function checkPrerequisites() { log.info('Verificando pré-requisitos...'); // Verificar se está na branch main try { const currentBranch = execSync('git branch --show-current', { encoding: 'utf8' }).trim(); if (currentBranch !== 'main') { throw new Error(`Você deve estar na branch main. Branch atual: ${currentBranch}`); } log.success('Branch main ativa'); } catch (error) { throw new Error('Erro ao verificar branch Git'); } // Verificar se Git está configurado try { const gitUser = execSync('git config user.name', { encoding: 'utf8' }).trim(); const gitEmail = execSync('git config user.email', { encoding: 'utf8' }).trim(); log.success(`Git configurado: ${gitUser} <${gitEmail}>`); } catch (error) { throw new Error('Git não configurado. Execute: git config --global user.name "Seu Nome" && git config --global user.email "seu@email.com"'); } } // Criar branch para desenvolvimento async function createBranch() { log.title('CRIANDO BRANCH DE DESENVOLVIMENTO'); const branchName = `feature/domain-${domainConfig.name}`; try { log.info(`Criando branch: ${branchName}`); execSync(`git checkout -b ${branchName}`, { stdio: 'inherit' }); log.success(`Branch ${branchName} criada e ativada`); } catch (error) { throw new Error(`Erro ao criar branch: ${error.message}`); } } // Criar estrutura de diretórios async function createDirectoryStructure() { const domainPath = `projects/idt_app/src/app/domain/${domainConfig.name}`; log.info('Criando estrutura de diretórios...'); if (!fs.existsSync(domainPath)) { fs.mkdirSync(domainPath, { recursive: true }); log.success(`Diretório criado: ${domainPath}`); } } // Gerar arquivos V2.0 async function generateComponentV2() { try { const generators = require('./create-domain-v2-generators.js'); const componentContent = generators.generateComponentV2(domainConfig); const componentPath = `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.component.ts`; fs.writeFileSync(componentPath, componentContent); log.success(`Component V2.0 gerado: ${componentPath}`); } catch (error) { log.error(`Erro ao gerar component: ${error.message}`); throw error; } } async function generateServiceV2() { try { const generators = require('./create-domain-v2-generators.js'); const serviceContent = generators.generateServiceV2(domainConfig); const servicePath = `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.service.ts`; fs.writeFileSync(servicePath, serviceContent); log.success(`Service V2.0 gerado: ${servicePath}`); } catch (error) { log.error(`Erro ao gerar service: ${error.message}`); throw error; } } async function generateInterfaceV2() { try { let interfaceContent; // 🚀 NOVA FUNCIONALIDADE V2.0: Tentar API real primeiro log.step('🔍 Tentando gerar interface a partir de dados reais da API...'); const apiResult = await analyzeRealAPI(domainConfig.name); if (apiResult.success) { log.success('✅ Interface gerada a partir de dados REAIS da API!'); log.info(`📊 Estratégia: ${apiResult.strategy}`); log.info(`🔗 Endpoint: ${apiResult.metadata.endpoint}`); log.info(`📋 Campos detectados: ${apiResult.fields.length}`); interfaceContent = apiResult.interface; } else { // Fallback para gerador padrão log.warning('⚠️ Não foi possível acessar dados reais da API'); log.info(`📋 Motivo: ${apiResult.message || 'Credenciais não fornecidas'}`); log.info('🔄 Usando geração padrão de interface...'); const generators = require('./create-domain-v2-generators.js'); interfaceContent = await generators.generateInterfaceV2(domainConfig); } const interfacePath = `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.interface.ts`; fs.writeFileSync(interfacePath, interfaceContent); log.success(`Interface V2.0 gerada: ${interfacePath}`); if (apiResult.success) { log.success('🎉 INTERFACE BASEADA EM DADOS REAIS DA API!'); } } catch (error) { log.error(`Erro ao gerar interface: ${error.message}`); throw error; } } async function generateTemplatesV2() { // HTML Template const htmlContent = `
`; // SCSS Template const scssContent = `// 🎨 ${capitalize(domainConfig.name)} Component Styles - V2.0 // Estilos específicos para o domínio ${domainConfig.displayName} .domain-container { height: 100%; display: flex; flex-direction: column; background: var(--background); .main-content { flex: 1; overflow: hidden; padding: 0; } } // 🆕 V2.0: Estilos específicos para funcionalidades ${domainConfig.hasBulkActions ? ` // Bulk Actions específicos .bulk-actions { margin-bottom: 1rem; .bulk-action-button { margin-right: 0.5rem; &.advanced { background: var(--idt-primary-color); color: white; } } }` : ''} ${domainConfig.hasFooter ? ` // Footer customizations .footer-enhanced { font-weight: 600; .footer-currency { color: var(--success-color); } .footer-count { color: var(--info-color); } }` : ''} // 📱 Responsividade @media (max-width: 768px) { .domain-container { .main-content { padding: 0.5rem; } } }`; const htmlPath = `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.component.html`; const scssPath = `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.component.scss`; fs.writeFileSync(htmlPath, htmlContent); fs.writeFileSync(scssPath, scssContent); log.success(`Templates V2.0 gerados: HTML e SCSS`); } // Atualizar roteamento V2.0 async function updateRoutingV2() { log.info('Atualizando roteamento...'); const routesPath = 'projects/idt_app/src/app/app.routes.ts'; let routesContent = fs.readFileSync(routesPath, 'utf8'); // Adicionar import const importLine = `import { ${capitalize(domainConfig.name)}Component } from './domain/${domainConfig.name}/${domainConfig.name}.component';`; if (!routesContent.includes(importLine)) { routesContent = routesContent.replace( /import.*from.*;\n(?=\n)/, `$&${importLine}\n` ); } // Adicionar rota const routeLine = ` { path: '${domainConfig.name}', component: ${capitalize(domainConfig.name)}Component },`; if (!routesContent.includes(routeLine)) { routesContent = routesContent.replace( /export const routes: Routes = \[\n/, `$&${routeLine}\n` ); } fs.writeFileSync(routesPath, routesContent); log.success('Roteamento atualizado'); } // Atualizar sidebar V2.0 async function updateSidebarV2() { log.info('Atualizando menu lateral...'); const sidebarPath = 'projects/idt_app/src/app/shared/components/sidebar/sidebar.component.ts'; let sidebarContent = fs.readFileSync(sidebarPath, 'utf8'); // Encontrar posição do menu const menuPositionRegex = new RegExp(`title: '${domainConfig.menuPosition}'[\\s\\S]*?},`); const match = sidebarContent.match(menuPositionRegex); if (match) { const newMenuItem = `{ title: '${domainConfig.displayName}', icon: 'fas fa-cube', route: '${domainConfig.name}', permissions: ['${domainConfig.name}:read'] },`; const insertPosition = match.index + match[0].length; sidebarContent = sidebarContent.slice(0, insertPosition) + '\n ' + newMenuItem + sidebarContent.slice(insertPosition); } fs.writeFileSync(sidebarPath, sidebarContent); log.success('Menu lateral atualizado'); } // Atualizar configuração MCP V2.0 async function updateMCPConfigV2() { log.info('Atualizando configuração MCP...'); try { const mcpPath = '.mcp/config.json'; const mcpContent = JSON.parse(fs.readFileSync(mcpPath, 'utf8')); // Adicionar domínio à lista if (!mcpContent.projects.idt_app.domains.includes(domainConfig.name)) { mcpContent.projects.idt_app.domains.push(domainConfig.name); } // Adicionar contexto específico V2.0 const domainContext = { description: `Domínio de ${domainConfig.displayName} - V2.0`, files: [ `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.component.ts`, `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.service.ts`, `projects/idt_app/src/app/domain/${domainConfig.name}/${domainConfig.name}.interface.ts` ], features: { baseDomainComponent: true, registryPattern: true, apiClientService: true, // V2.0 Features footerConfig: domainConfig.hasFooter, checkboxGrouped: domainConfig.hasCheckboxGrouped, bulkActions: domainConfig.hasBulkActions, dateRangeUtils: domainConfig.hasDateRangeUtils, advancedSideCard: domainConfig.hasAdvancedSideCard, extendedSearchOptions: domainConfig.hasExtendedSearchOptions } }; mcpContent.contexts[`domain-${domainConfig.name}`] = domainContext; fs.writeFileSync(mcpPath, JSON.stringify(mcpContent, null, 2)); log.success('Configuração MCP V2.0 atualizada'); } catch (error) { log.warning(`Erro ao atualizar MCP: ${error.message} - será atualizado manualmente`); } } // Compilar e testar automaticamente async function compileAndTest() { log.title('COMPILAÇÃO E TESTES V2.0'); try { log.info('Compilando aplicação com funcionalidades V2.0...'); execSync('ng build idt_app --configuration development', { stdio: 'inherit', timeout: 120000 // 2 minutos timeout }); log.success('Compilação V2.0 realizada com sucesso! ✨'); } catch (error) { log.error(`Erro na compilação: ${error.message}`); throw new Error('Falha na compilação - verifique os erros acima'); } } // Commit automático V2.0 async function autoCommit() { log.title('COMMIT AUTOMÁTICO V2.0'); try { const branchName = `feature/domain-${domainConfig.name}`; // Adicionar todos os arquivos execSync('git add .', { stdio: 'inherit' }); // Criar mensagem de commit V2.0 const v2Features = []; if (domainConfig.hasFooter) v2Features.push(`FooterConfig: ${domainConfig.footerConfig.columns.length} colunas`); if (domainConfig.hasCheckboxGrouped) v2Features.push(`CheckboxGrouped: ${domainConfig.checkboxGroupedConfig.groups.length} grupos`); if (domainConfig.hasBulkActions) v2Features.push(`BulkActions: ${domainConfig.bulkActionsConfig.type}`); if (domainConfig.hasDateRangeUtils) v2Features.push('DateRangeUtils integration'); if (domainConfig.hasAdvancedSideCard) v2Features.push('Advanced SideCard'); if (domainConfig.hasExtendedSearchOptions) v2Features.push('Extended SearchOptions'); const commitMessage = `feat: add ${domainConfig.displayName} domain (V2.0) ✨ Features V2.0 implementadas: ${v2Features.map(f => `- ${f}`).join('\n')} 🔧 Arquivos gerados: - Component: ${capitalize(domainConfig.name)}Component (BaseDomainComponent + Registry Pattern) - Service: ${capitalize(domainConfig.name)}Service (DomainService + ApiClientService) - Interface: ${capitalize(domainConfig.name)} TypeScript - Templates: HTML e SCSS com V2.0 features 🔗 Integrações: - Roteamento: app.routes.ts - Menu: sidebar.component.ts (após ${domainConfig.menuPosition}) - MCP: .mcp/config.json com features V2.0 🎯 Gerado automaticamente via create-domain-v2.js`; // Fazer commit execSync(`git commit -m "${commitMessage}"`, { stdio: 'inherit' }); log.success(`Commit V2.0 realizado na branch ${branchName}! 📝`); log.info(`Para fazer push: git push origin ${branchName}`); } catch (error) { log.warning(`Erro no commit automático: ${error.message}`); log.info('Você pode fazer o commit manualmente depois'); } } function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } // ===== EXECUÇÃO ===== if (require.main === module) { main(); } module.exports = { domainConfig, FooterTemplates, CheckboxGroupedTemplates, BulkActionsTemplates, SearchOptionsLibrary, generateComponentV2, generateServiceV2, generateInterfaceV2 };