#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const JavaScanner = require('./scanners/java-scanner'); const LayerMapper = require('./mappers/layer-mapper'); const ModuleGenerator = require('./generators/module-generator'); const CentralDataRepository = require('./central-data-repository'); /** * Java到NestJS迁移协调器 * 按技术层级组织模块,严格遵循NestJS官方规范 * * ✅ V2: 使用中央数据仓库(CDR)统一管理元数据 */ class JavaToNestJSMigrationCoordinator { constructor() { this.javaPath = ''; this.nestJSPath = ''; this.scanner = new JavaScanner(); this.mapper = new LayerMapper(); this.moduleGenerator = new ModuleGenerator(); // ✅ V2: 中央数据仓库(替代原来的单一索引) this.cdr = new CentralDataRepository(); // ⚠️ 向后兼容:保留旧的索引引用(指向CDR) this.serviceMethodSignatureIndex = this.cdr.serviceMethodSignatureIndex; this.stats = { startTime: null, endTime: null, filesProcessed: 0, modulesGenerated: 0, errors: [] }; } /** * 执行完整迁移流程 */ async runMigration() { console.log('🚀 开始Java到NestJS迁移流程...'); this.stats.startTime = new Date(); try { // 第1阶段:扫描Java项目 console.log('\n📊 第1阶段:扫描Java项目结构...'); await this.scanJavaProject(); // 第2阶段:映射层级关系 console.log('\n🔄 第2阶段:映射层级关系...'); const nestJSModules = this.mapLayers(); // 第3阶段:生成NestJS模块 console.log('\n🔧 第3阶段:生成NestJS模块...'); await this.generateModules(nestJSModules); // 第4阶段:生成报告 console.log('\n📋 第4阶段:生成迁移报告...'); this.generateReport(); this.stats.endTime = new Date(); console.log('\n✅ 迁移流程完成!'); this.printStats(); // ✅ V2: 打印CDR统计 console.log(''); this.cdr.printStats(); // ✅ V2: 打印实际记录的类型名(前20个) console.log('\n🔍 CDR中实际记录的类型名(前20个):'); let count = 0; for (const [typeName, location] of this.cdr.typeLocationIndex) { if (count < 20) { console.log(` ${count + 1}. ${typeName} (${location.category}) -> ${location.relativePath}`); count++; } else { break; } } // ✅ V2: 测试查询几个DTO console.log('\n🔍 测试CDR查询:'); const testTypes = ['MemberInfoDto', 'MemberListVo', 'PageParam', 'MemberSearchParam']; testTypes.forEach(typeName => { const location = this.cdr.getTypeLocation(typeName); if (location) { console.log(` ✅ ${typeName}: ${location.relativePath}`); } else { console.log(` ❌ ${typeName}: 未找到`); } }); } catch (error) { console.error('❌ 迁移过程中发生错误:', error.message); this.stats.errors.push(error.message); throw error; } } /** * 扫描Java项目 */ async scanJavaProject() { this.javaPath = '/Users/wanwu/Documents/wanwujie/wwjcloud-nsetjs/niucloud-java/niucloud-core/src/main/java'; this.nestJSPath = path.resolve(__dirname, '../../wwjcloud/libs/wwjcloud-core/src'); console.log(`📁 Java项目路径: ${this.javaPath}`); console.log(`📁 NestJS项目路径: ${this.nestJSPath}`); this.scanner.setJavaPath(this.javaPath); await this.scanner.scanJavaProject(); const scanResults = this.scanner.getScanResults(); this.stats.filesProcessed = Object.values(scanResults).reduce((total, arr) => total + arr.length, 0); console.log(`📊 扫描完成,共处理 ${this.stats.filesProcessed} 个文件`); // ✅ 构建中央Service方法签名索引 console.log('🔍 构建Service方法签名索引...'); this.buildServiceMethodSignatureIndex(scanResults.services); console.log(`📋 索引完成,共 ${this.serviceMethodSignatureIndex.size} 个方法签名`); // 验证扫描结果 this.validateScanResults(scanResults); } /** * ✅ V2: 构建Service方法签名索引(使用CDR) * 从Java扫描结果中提取所有Service方法的参数和返回类型 */ buildServiceMethodSignatureIndex(services) { services.forEach(service => { const className = service.className; const content = service.content; // 提取所有方法 const methods = this.scanner.extractMethods(content); // ✅ V2: 使用CDR存储方法签名 methods.forEach(method => { this.cdr.setServiceSignature(className, method.methodName, { parameters: method.parameters || [], returnType: method.returnType || 'void', methodBody: method.methodBody || '' }); }); // ✅ V2: 记录Service依赖关系 if (service.dependencies && service.dependencies.length > 0) { this.cdr.setServiceDependencies(className, service.dependencies); } }); // ✅ V2: 打印CDR统计 console.log(`📋 CDR: 已索引 ${this.cdr.serviceMethodSignatureIndex.size} 个Service方法签名`); } /** * 验证扫描结果 */ validateScanResults(scanResults) { console.log('\n🔍 验证扫描结果...'); // 检查是否有重复文件 const allFiles = Object.values(scanResults).flat(); const uniqueFiles = new Set(allFiles.map(f => f.filePath)); if (allFiles.length !== uniqueFiles.size) { console.warn(`⚠️ 发现重复文件: ${allFiles.length - uniqueFiles.size} 个`); } // 检查分类准确性 const totalClassified = Object.values(scanResults).reduce((sum, arr) => sum + arr.length, 0); console.log(`📊 分类文件总数: ${totalClassified} 个`); // 检查每个分类的质量 this.validateClassificationQuality(scanResults); } /** * 验证分类质量 */ validateClassificationQuality(scanResults) { console.log('\n🔍 验证分类质量...'); // 验证控制器分类 const controllerQuality = this.validateControllerClassification(scanResults.controllers); console.log(`📋 控制器分类质量: ${controllerQuality.score}/100`); // 验证服务分类 const serviceQuality = this.validateServiceClassification(scanResults.services); console.log(`🔧 服务分类质量: ${serviceQuality.score}/100`); // 验证实体分类 const entityQuality = this.validateEntityClassification(scanResults.entities); console.log(`🗄️ 实体分类质量: ${entityQuality.score}/100`); } /** * 验证控制器分类质量 */ validateControllerClassification(controllers) { let score = 0; let issues = []; controllers.forEach(controller => { const className = controller.className.toLowerCase(); const content = controller.content.toLowerCase(); // 检查类名是否包含controller if (className.includes('controller')) { score += 20; } else { issues.push(`类名不包含controller: ${controller.className}`); } // 检查是否有控制器注解 if (content.includes('@restcontroller') || content.includes('@controller')) { score += 30; } else { issues.push(`缺少控制器注解: ${controller.className}`); } // 检查是否有路由映射 if (content.includes('@requestmapping')) { score += 30; } else { issues.push(`缺少路由映射: ${controller.className}`); } // 检查是否有HTTP方法映射 if (content.includes('@getmapping') || content.includes('@postmapping')) { score += 20; } else { issues.push(`缺少HTTP方法映射: ${controller.className}`); } }); return { score: Math.min(score, 100), issues }; } /** * 验证服务分类质量 */ validateServiceClassification(services) { let score = 0; let issues = []; services.forEach(service => { const className = service.className.toLowerCase(); const content = service.content.toLowerCase(); // 检查类名是否包含service if (className.includes('service')) { score += 30; } else { issues.push(`类名不包含service: ${service.className}`); } // 检查是否有服务注解 if (content.includes('@service') || content.includes('@component')) { score += 40; } else { issues.push(`缺少服务注解: ${service.className}`); } // 检查是否有业务方法 if (content.includes('public') && content.includes('(')) { score += 30; } else { issues.push(`缺少业务方法: ${service.className}`); } }); return { score: Math.min(score, 100), issues }; } /** * 验证实体分类质量 */ validateEntityClassification(entities) { let score = 0; let issues = []; entities.forEach(entity => { const className = entity.className.toLowerCase(); const content = entity.content.toLowerCase(); // 检查类名是否包含entity if (className.includes('entity') || className.includes('model')) { score += 25; } else { issues.push(`类名不包含entity/model: ${entity.className}`); } // 检查是否有实体注解 if (content.includes('@entity') || content.includes('@table')) { score += 35; } else { issues.push(`缺少实体注解: ${entity.className}`); } // 检查是否有字段映射 if (content.includes('@column') || content.includes('@id')) { score += 40; } else { issues.push(`缺少字段映射: ${entity.className}`); } }); return { score: Math.min(score, 100), issues }; } /** * 映射层级关系 */ mapLayers() { const scanResults = this.scanner.getScanResults(); const nestJSModules = this.mapper.mapToNestJSModules(scanResults); console.log('✅ 层级映射完成'); return nestJSModules; } /** * ✅ V2: 生成NestJS模块(传递CDR) */ async generateModules(nestJSModules) { // ✅ V2: 传递CDR给ModuleGenerator this.moduleGenerator.setOutputDir(this.nestJSPath); this.moduleGenerator.setCDR(this.cdr); // ✅ 传递整个CDR // ⚠️ 向后兼容:也传递旧的索引(指向CDR内部) this.moduleGenerator.setServiceMethodSignatureIndex(this.serviceMethodSignatureIndex); await this.moduleGenerator.generateAllModules(nestJSModules); this.stats.modulesGenerated = Object.keys(nestJSModules).length; console.log(`✅ 生成了 ${this.stats.modulesGenerated} 个模块`); } /** * 生成迁移报告 */ generateReport() { const report = { timestamp: new Date().toISOString(), stats: this.stats, modules: [ 'CommonModule - 通用功能模块', 'EntityModule - 实体模块', 'ServiceModule - 服务模块', 'ControllerModule - 控制器模块', 'ListenerModule - 监听器模块', 'JobModule - 任务模块' ] }; const reportPath = path.join(__dirname, 'migration-report.json'); fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); console.log(`📋 迁移报告已生成: ${reportPath}`); } /** * 获取生成的文件列表 */ getGeneratedFiles() { const files = []; const nestJSDir = this.nestJSPath; if (fs.existsSync(nestJSDir)) { const walkDir = (dir) => { const items = fs.readdirSync(dir); items.forEach(item => { const itemPath = path.join(dir, item); const stat = fs.statSync(itemPath); if (stat.isDirectory()) { walkDir(itemPath); } else if (item.endsWith('.ts')) { files.push({ path: itemPath, name: item }); } }); }; walkDir(nestJSDir); } return files; } /** * 打印框架验证结果 */ printFrameworkValidationResults(validationResults) { if (!validationResults || !validationResults.summary) { console.log('⚠️ 框架验证结果为空'); return; } console.log('\n🔍 框架集成验证结果:'); console.log(`📊 总文件数: ${validationResults.summary.totalFiles || 0}`); console.log(`✅ 框架导入: ${validationResults.summary.frameworkImports?.['✅'] || 0}/${(validationResults.summary.frameworkImports?.['✅'] || 0) + (validationResults.summary.frameworkImports?.['❌'] || 0)}`); console.log(`✅ 框架服务: ${validationResults.summary.frameworkServices?.['✅'] || 0}/${(validationResults.summary.frameworkServices?.['✅'] || 0) + (validationResults.summary.frameworkServices?.['❌'] || 0)}`); console.log(`✅ 框架配置: ${validationResults.summary.frameworkConfig?.['✅'] || 0}/${(validationResults.summary.frameworkConfig?.['✅'] || 0) + (validationResults.summary.frameworkConfig?.['❌'] || 0)}`); console.log(`✅ 框架事件: ${validationResults.summary.frameworkEvents?.['✅'] || 0}/${(validationResults.summary.frameworkEvents?.['✅'] || 0) + (validationResults.summary.frameworkEvents?.['❌'] || 0)}`); console.log(`✅ 框架队列: ${validationResults.summary.frameworkQueues?.['✅'] || 0}/${(validationResults.summary.frameworkQueues?.['✅'] || 0) + (validationResults.summary.frameworkQueues?.['❌'] || 0)}`); console.log(`✅ 数据库兼容: ${validationResults.summary.databaseCompatibility?.['✅'] || 0}/${(validationResults.summary.databaseCompatibility?.['✅'] || 0) + (validationResults.summary.databaseCompatibility?.['❌'] || 0)}`); console.log(`✅ API兼容: ${validationResults.summary.apiCompatibility?.['✅'] || 0}/${(validationResults.summary.apiCompatibility?.['✅'] || 0) + (validationResults.summary.apiCompatibility?.['❌'] || 0)}`); } /** * 打印统计信息 */ printStats() { const duration = this.stats.endTime - this.stats.startTime; console.log('\n📊 迁移统计:'); console.log(`⏱️ 总耗时: ${duration}ms`); console.log(`📁 处理文件: ${this.stats.filesProcessed} 个`); console.log(`🔧 生成模块: ${this.stats.modulesGenerated} 个`); console.log(`❌ 错误数量: ${this.stats.errors.length} 个`); } } // 如果直接运行此文件,则执行迁移 if (require.main === module) { const coordinator = new JavaToNestJSMigrationCoordinator(); coordinator.runMigration().catch(console.error); } module.exports = JavaToNestJSMigrationCoordinator;