UNPKG

weaver-frontend-cli

Version:

🕷️ Weaver CLI - Generador completo de arquitectura Clean Architecture para entidades CRUD y flujos de negocio desde OpenAPI/Swagger

276 lines 13.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProjectValidator = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const chalk_1 = __importDefault(require("chalk")); class ProjectValidator { /** * Valida que la estructura del proyecto sea la correcta */ static async validateProjectStructure(basePath, apiName = 'platform') { console.log(chalk_1.default.blue('🔍 Validando estructura del proyecto...')); // Determinar si estamos en el directorio de la API o necesitamos crear uno const currentDirName = path.basename(basePath); const shouldCreateApiDir = currentDirName !== apiName; const apiPrefix = shouldCreateApiDir ? `${apiName}/` : ''; const requiredDirectories = [ `${apiPrefix}domain/models/apis/${apiName}/entities`, `${apiPrefix}domain/services/repositories/apis/${apiName}/entities`, `${apiPrefix}domain/services/use_cases/apis/${apiName}/entities`, `${apiPrefix}infrastructure/entities/apis/${apiName}/entities`, `${apiPrefix}infrastructure/mappers/apis/${apiName}/entities`, `${apiPrefix}infrastructure/repositories/apis/${apiName}/repositories/entities`, `${apiPrefix}facade/apis/${apiName}/entities` ]; const missingDirectories = []; const warnings = []; // Verificar que el directorio base existe if (!await fs.pathExists(basePath)) { return { isValid: false, message: `❌ El directorio base no existe: ${basePath}` }; } // Verificar directorios requeridos for (const dir of requiredDirectories) { const fullPath = path.join(basePath, dir); if (!await fs.pathExists(fullPath)) { missingDirectories.push(dir); } } // Verificar archivos de configuración clave const coreFiles = [ 'core/interfaces/index.ts', 'core/classes/index.ts', 'core/axios/platform-axios.ts' ]; for (const file of coreFiles) { const fullPath = path.join(basePath, file); if (!await fs.pathExists(fullPath)) { warnings.push(`⚠️ Archivo core no encontrado: ${file}`); } } // Ser más permisivo - no bloquear por directorios faltantes if (missingDirectories.length > 0) { warnings.push(`Se crearán los directorios faltantes automáticamente: ${missingDirectories.length} directorios`); } // Verificar que parece ser un proyecto goluti-frontend const indicatorFiles = [ 'core/const/const-platform-api-routes.ts', 'core/injection/injection-core.ts' ]; let projectIndicators = 0; for (const file of indicatorFiles) { const fullPath = path.join(basePath, file); if (await fs.pathExists(fullPath)) { projectIndicators++; } } if (projectIndicators === 0) { warnings.push('⚠️ No se detectaron archivos característicos del proyecto goluti-frontend'); } return { isValid: true, message: '✅ Estructura del proyecto válida', warnings }; } /** * Verifica si una entidad ya existe en el proyecto */ static async checkEntityExists(entityName, basePath, apiName = 'platform') { const entityNameLower = entityName.toLowerCase(); const entityNameKebab = entityName.replace(/([A-Z])/g, '-$1').toLowerCase().substring(1); console.log(chalk_1.default.blue(`🔍 Verificando si la entidad "${entityName}" ya existe...`)); const conflictingFiles = []; // Determinar si estamos en el directorio de la API o necesitamos crear uno const currentDirName = path.basename(basePath); const shouldCreateApiDir = currentDirName !== apiName; const apiPrefix = shouldCreateApiDir ? `${apiName}/` : ''; // Directorios donde buscar archivos de la entidad (usando apiName dinámico) const searchPaths = [ `${apiPrefix}domain/models/apis/${apiName}/entities/${entityNameLower}`, `${apiPrefix}domain/services/repositories/apis/${apiName}/entities/i-${entityNameKebab}-repository.ts`, `${apiPrefix}domain/services/use_cases/apis/${apiName}/entities/${entityNameLower}`, `${apiPrefix}infrastructure/entities/apis/${apiName}/entities/${entityNameLower}`, `${apiPrefix}infrastructure/mappers/apis/${apiName}/entities/${entityNameLower}`, `${apiPrefix}infrastructure/repositories/apis/${apiName}/repositories/entities/${entityNameLower}`, `${apiPrefix}facade/apis/${apiName}/entities/${entityNameKebab}-facade.ts` ]; for (const searchPath of searchPaths) { const fullPath = path.join(basePath, searchPath); if (await fs.pathExists(fullPath)) { const stat = await fs.stat(fullPath); if (stat.isDirectory()) { // Si es directorio, verificar si tiene archivos const files = await fs.readdir(fullPath); if (files.length > 0) { conflictingFiles.push(`📁 ${searchPath}/ (${files.length} archivos)`); } } else { // Si es archivo conflictingFiles.push(`📄 ${searchPath}`); } } } const exists = conflictingFiles.length > 0; return { exists, conflictingFiles, message: exists ? `⚠️ La entidad "${entityName}" ya existe parcial o completamente` : `✅ La entidad "${entityName}" no existe, se puede generar` }; } /** * Verifica si una entidad de negocio ya existe en el proyecto */ static async checkBusinessEntityExists(entityName, basePath, apiName = 'platform') { const entityNameLower = entityName.toLowerCase(); const entityNameKebab = entityName.replace(/([A-Z])/g, '-$1').toLowerCase().substring(1); const conflictingFiles = []; // Determinar si estamos en el directorio de la API o necesitamos crear uno const currentDirName = path.basename(basePath); const shouldCreateApiDir = currentDirName !== apiName; const apiPrefix = shouldCreateApiDir ? `${apiName}/` : ''; // Directorios donde buscar archivos de la entidad de negocio (usando business en lugar de entities) const searchPaths = [ `${apiPrefix}domain/models/apis/${apiName}/business/${entityNameLower}`, `${apiPrefix}domain/services/repositories/apis/${apiName}/business/i-${entityNameKebab}-repository.ts`, `${apiPrefix}domain/services/use_cases/apis/${apiName}/business/${entityNameLower}`, `${apiPrefix}infrastructure/entities/apis/${apiName}/business/${entityNameLower}`, `${apiPrefix}infrastructure/mappers/apis/${apiName}/business/${entityNameLower}`, `${apiPrefix}infrastructure/repositories/apis/${apiName}/repositories/business/${entityNameLower}`, `${apiPrefix}facade/apis/${apiName}/business/${entityNameKebab}-facade.ts` ]; for (const searchPath of searchPaths) { const fullPath = path.join(basePath, searchPath); if (await fs.pathExists(fullPath)) { const stat = await fs.stat(fullPath); if (stat.isDirectory()) { // Si es directorio, verificar si tiene archivos const files = await fs.readdir(fullPath); if (files.length > 0) { conflictingFiles.push(`📁 ${searchPath}/ (${files.length} archivos)`); } } else { // Si es archivo conflictingFiles.push(`📄 ${searchPath}`); } } } const exists = conflictingFiles.length > 0; return { exists, conflictingFiles: conflictingFiles, message: exists ? `⚠️ La entidad de negocio "${entityName}" ya existe parcial o completamente` : `✅ La entidad de negocio "${entityName}" no existe, se puede generar` }; } /** * Valida la configuración completa antes de generar */ static async validateBeforeGeneration(entityName, basePath, apiName = 'platform') { console.log(chalk_1.default.yellow('\n🔍 Ejecutando validaciones pre-generación...\n')); const structureResult = await this.validateProjectStructure(basePath, apiName); const entityResult = await this.checkEntityExists(entityName, basePath, apiName); const recommendations = []; let canProceed = structureResult.isValid; // Mostrar resultados de validación console.log(structureResult.message); if (structureResult.warnings) { structureResult.warnings.forEach(warning => console.log(chalk_1.default.yellow(warning))); } console.log(entityResult.message); if (entityResult.conflictingFiles.length > 0) { console.log(chalk_1.default.yellow('\nArchivos/directorios existentes:')); entityResult.conflictingFiles.forEach(file => console.log(chalk_1.default.gray(` ${file}`))); } // Generar recomendaciones if (!structureResult.isValid) { recommendations.push('Verifica que estés ejecutando el comando en el directorio correcto del proyecto goluti-frontend'); canProceed = false; } if (entityResult.exists) { recommendations.push('La entidad ya existe. Si continúas, se sobrescribirán los archivos existentes'); recommendations.push('Considera hacer un backup antes de continuar'); // No bloqueamos la generación, pero advertimos } if (structureResult.warnings && structureResult.warnings.length > 0) { recommendations.push('Algunas dependencias core no fueron encontradas. El código generado podría necesitar ajustes'); } return { canProceed, structureResult, entityResult, recommendations }; } /** * Muestra un resumen de lo que se va a generar */ static showGenerationSummary(entityName, basePath, willOverwrite) { const entityNameLower = entityName.toLowerCase(); const entityNameKebab = entityName.replace(/([A-Z])/g, '-$1').toLowerCase().substring(1); console.log(chalk_1.default.blue('\n📋 Resumen de generación:')); console.log(chalk_1.default.gray(`Entidad: ${entityName}`)); console.log(chalk_1.default.gray(`Ubicación: ${basePath}`)); console.log(chalk_1.default.gray(`Archivos a generar: ~29 archivos TypeScript`)); if (willOverwrite) { console.log(chalk_1.default.yellow('⚠️ Se sobrescribirán archivos existentes')); } console.log(chalk_1.default.blue('\n📁 Directorios que se crearán/utilizarán:')); const directories = [ `📂 domain/models/apis/platform/entities/${entityNameLower}/`, `📂 domain/services/use_cases/apis/platform/entities/${entityNameLower}/`, `📂 infrastructure/entities/apis/platform/entities/${entityNameLower}/`, `📂 infrastructure/mappers/apis/platform/entities/${entityNameLower}/`, `📂 infrastructure/repositories/.../entities/${entityNameLower}/`, `📂 facade/apis/platform/entities/`, `📂 injection folders...` ]; directories.forEach(dir => console.log(chalk_1.default.gray(` ${dir}`))); } } exports.ProjectValidator = ProjectValidator; //# sourceMappingURL=project-validator.js.map