Files
wwjcloud-nest-v1/wwjcloud-nest-v1/tools/java-to-nestjs-migration/migration-coordinator.js
wanwu 3c87db45ff feat(cdr): 建立中央数据仓库(CDR)架构
🎯 核心改进:
1.  创建CentralDataRepository类 - 统一管理元数据
2.  Coordinator集成CDR - 传递给所有Generator
3.  DTO Generator记录位置 - 629个类型已记录
4.  Service Generator CDR查询 - 支持路径查询

📊 CDR统计:
- Service方法: 1,038个
- DTO: 35个
- VO: 277个
- Param: 317个
- 总类型: 629个

⚠️ 待解决问题:
- 类型名查询不匹配(记录vs查询)
- 需要调试类型名映射逻辑

💡 下一步:
- 修复类型名匹配问题
- 验证DTO路径查询效果
- 预期减少4,200+ DTO路径错误
2025-10-29 22:41:23 +08:00

419 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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: 测试查询几个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;