fix: 恢复原始迁移工具 - 删除所有enhanced文件
🗑️ 删除的文件: - enhanced-migration-coordinator.js - enhanced-business-logic-converter.js - enhanced-dependency-injection-converter.js - ENHANCED_MIGRATION_REPORT.json ✅ 恢复的文件: - migration-coordinator.js(从git历史恢复) 🎯 原始工具架构: - 1个主协调器(migration-coordinator.js) - 7个层级生成器(controller, service, entity, dto, enum, listener, job) - 已支持保持Java子目录结构
This commit is contained in:
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"summary": {
|
||||
"totalTime": -1761637480243,
|
||||
"filesProcessed": 1215,
|
||||
"servicesGenerated": 158,
|
||||
"typesGenerated": 629,
|
||||
"successRate": "100.0%",
|
||||
"errors": 0
|
||||
},
|
||||
"details": {
|
||||
"diStats": {
|
||||
"description": "依赖注入推断统计",
|
||||
"note": "已集成增强的DI转换器"
|
||||
},
|
||||
"businessLogicStats": {
|
||||
"description": "业务逻辑转换统计",
|
||||
"note": "已集成增强的业务逻辑转换器"
|
||||
},
|
||||
"dtoStats": {
|
||||
"description": "DTO生成统计",
|
||||
"generated": 629
|
||||
}
|
||||
},
|
||||
"errors": []
|
||||
}
|
||||
@@ -1,436 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const NamingUtils = require('../utils/naming-utils');
|
||||
|
||||
/**
|
||||
* 增强的业务逻辑转换器
|
||||
* 核心能力:
|
||||
* 1. QueryWrapper -> TypeORM QueryBuilder
|
||||
* 2. Mapper.xxx() -> Repository.xxx()
|
||||
* 3. Stream API -> Array methods
|
||||
* 4. Java Utils -> wwjcloud-boot services
|
||||
* 5. Lambda -> Arrow functions
|
||||
*/
|
||||
class EnhancedBusinessLogicConverter {
|
||||
constructor() {
|
||||
this.namingUtils = new NamingUtils();
|
||||
|
||||
// Mapper 方法映射到 Repository 方法
|
||||
this.mapperMethodMapping = {
|
||||
'selectById': 'findOne',
|
||||
'selectOne': 'findOne',
|
||||
'selectList': 'find',
|
||||
'selectPage': 'findAndCount',
|
||||
'insert': 'save',
|
||||
'update': 'update',
|
||||
'updateById': 'update',
|
||||
'delete': 'delete',
|
||||
'deleteById': 'delete',
|
||||
'count': 'count'
|
||||
};
|
||||
|
||||
// Java 工具类方法映射
|
||||
this.utilsMethodMapping = {
|
||||
'RequestUtils.getCurrentSiteId': 'this.requestContext.getSiteId',
|
||||
'RequestUtils.getCurrentUserId': 'this.requestContext.getUserId',
|
||||
'StringUtil.isEmpty': '!',
|
||||
'StringUtil.isNotEmpty': '!!',
|
||||
'ObjectUtil.isEmpty': '!',
|
||||
'ObjectUtil.isNotEmpty': '!!',
|
||||
'CollUtil.isEmpty': '!',
|
||||
'CollUtil.isNotEmpty': '!!',
|
||||
'DateUtil.now': 'new Date',
|
||||
'DateUtil.format': 'DateUtils.format',
|
||||
'FileUtils.upload': 'await this.fileUtils.upload',
|
||||
'BeanUtils.copyProperties': 'Object.assign'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 主转换方法:转换完整的方法体
|
||||
*/
|
||||
convertMethodBody(javaMethod) {
|
||||
if (!javaMethod.body) {
|
||||
return ' // TODO: 实现业务逻辑\n throw new Error("Not implemented");';
|
||||
}
|
||||
|
||||
let body = javaMethod.body;
|
||||
|
||||
// 应用所有转换规则
|
||||
body = this.convertQueryWrapper(body);
|
||||
body = this.convertMapperCalls(body);
|
||||
body = this.convertStreamAPI(body);
|
||||
body = this.convertUtilsCalls(body);
|
||||
body = this.convertLambdaExpressions(body);
|
||||
body = this.convertLogStatements(body);
|
||||
body = this.convertExceptionHandling(body);
|
||||
body = this.convertVariableDeclarations(body);
|
||||
body = this.addAwaitToAsyncCalls(body);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. 转换 QueryWrapper
|
||||
* 例:new QueryWrapper<>().eq("id", id)
|
||||
* -> this.repository.createQueryBuilder().where("id = :id", { id })
|
||||
*/
|
||||
convertQueryWrapper(body) {
|
||||
// 匹配 QueryWrapper 创建和链式调用
|
||||
const queryWrapperPattern = /new\s+QueryWrapper<[^>]*>\(\)([\s\S]*?)(?=;)/g;
|
||||
|
||||
body = body.replace(queryWrapperPattern, (match, chainCalls) => {
|
||||
// 解析链式调用
|
||||
const conditions = [];
|
||||
|
||||
// .eq(field, value)
|
||||
const eqPattern = /\.eq\("([^"]+)",\s*([^)]+)\)/g;
|
||||
let eqMatch;
|
||||
while ((eqMatch = eqPattern.exec(chainCalls)) !== null) {
|
||||
const field = eqMatch[1];
|
||||
const value = eqMatch[2];
|
||||
conditions.push(`${field} = :${field}`);
|
||||
}
|
||||
|
||||
// .ne(field, value)
|
||||
const nePattern = /\.ne\("([^"]+)",\s*([^)]+)\)/g;
|
||||
let neMatch;
|
||||
while ((neMatch = nePattern.exec(chainCalls)) !== null) {
|
||||
const field = neMatch[1];
|
||||
conditions.push(`${field} != :${field}`);
|
||||
}
|
||||
|
||||
// .like(field, value)
|
||||
const likePattern = /\.like\("([^"]+)",\s*([^)]+)\)/g;
|
||||
let likeMatch;
|
||||
while ((likeMatch = likePattern.exec(chainCalls)) !== null) {
|
||||
const field = likeMatch[1];
|
||||
conditions.push(`${field} LIKE :${field}`);
|
||||
}
|
||||
|
||||
// .in(field, values)
|
||||
const inPattern = /\.in\("([^"]+)",\s*([^)]+)\)/g;
|
||||
let inMatch;
|
||||
while ((inMatch = inPattern.exec(chainCalls)) !== null) {
|
||||
const field = inMatch[1];
|
||||
conditions.push(`${field} IN (:...${field})`);
|
||||
}
|
||||
|
||||
// .orderByAsc(field) / .orderByDesc(field)
|
||||
let orderBy = '';
|
||||
if (chainCalls.includes('.orderByAsc')) {
|
||||
const orderMatch = chainCalls.match(/\.orderByAsc\("([^"]+)"\)/);
|
||||
if (orderMatch) {
|
||||
orderBy = `.orderBy("${orderMatch[1]}", "ASC")`;
|
||||
}
|
||||
} else if (chainCalls.includes('.orderByDesc')) {
|
||||
const orderMatch = chainCalls.match(/\.orderByDesc\("([^"]+)"\)/);
|
||||
if (orderMatch) {
|
||||
orderBy = `.orderBy("${orderMatch[1]}", "DESC")`;
|
||||
}
|
||||
}
|
||||
|
||||
// 生成 QueryBuilder
|
||||
const whereClause = conditions.join(' AND ');
|
||||
return `this.repository.createQueryBuilder().where("${whereClause}")${orderBy}`;
|
||||
});
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. 转换 Mapper 调用
|
||||
* 例:xxxMapper.selectById(id) -> await this.xxxRepository.findOne({ where: { id } })
|
||||
*/
|
||||
convertMapperCalls(body) {
|
||||
// 匹配 Mapper 方法调用
|
||||
const mapperPattern = /(\w+)Mapper\.(\w+)\(([^)]*)\)/g;
|
||||
|
||||
body = body.replace(mapperPattern, (match, mapperName, methodName, args) => {
|
||||
const entityName = mapperName; // SysUser
|
||||
const repositoryName = mapperName.charAt(0).toLowerCase() + mapperName.slice(1) + 'Repository';
|
||||
|
||||
// 根据方法名转换
|
||||
switch (methodName) {
|
||||
case 'selectById':
|
||||
return `await this.${repositoryName}.findOne({ where: { id: ${args} } })`;
|
||||
|
||||
case 'selectOne':
|
||||
// selectOne(queryWrapper) -> findOne(where)
|
||||
return `await this.${repositoryName}.findOne({ where: ${args} })`;
|
||||
|
||||
case 'selectList':
|
||||
// selectList(queryWrapper) -> find(where)
|
||||
if (args.includes('QueryWrapper')) {
|
||||
return `await this.${repositoryName}.find()`;
|
||||
}
|
||||
return `await this.${repositoryName}.find({ where: ${args} })`;
|
||||
|
||||
case 'selectPage':
|
||||
// selectPage(page, queryWrapper) -> findAndCount
|
||||
return `await this.${repositoryName}.findAndCount({ skip: (page - 1) * limit, take: limit })`;
|
||||
|
||||
case 'insert':
|
||||
return `await this.${repositoryName}.save(${args})`;
|
||||
|
||||
case 'updateById':
|
||||
// updateById(entity) -> update(id, data)
|
||||
return `await this.${repositoryName}.update(${args}.id, ${args})`;
|
||||
|
||||
case 'update':
|
||||
// update(entity, queryWrapper) -> update
|
||||
return `await this.${repositoryName}.update(${args})`;
|
||||
|
||||
case 'deleteById':
|
||||
return `await this.${repositoryName}.delete(${args})`;
|
||||
|
||||
case 'delete':
|
||||
return `await this.${repositoryName}.delete(${args})`;
|
||||
|
||||
case 'count':
|
||||
if (args.includes('QueryWrapper')) {
|
||||
return `await this.${repositoryName}.count()`;
|
||||
}
|
||||
return `await this.${repositoryName}.count({ where: ${args} })`;
|
||||
|
||||
default:
|
||||
return `await this.${repositoryName}.${methodName}(${args})`;
|
||||
}
|
||||
});
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3. 转换 Stream API
|
||||
* 例:list.stream().map(x -> x.getName()).collect(Collectors.toList())
|
||||
* -> list.map(x => x.name)
|
||||
*/
|
||||
convertStreamAPI(body) {
|
||||
// .stream().map().collect(Collectors.toList())
|
||||
body = body.replace(/(\w+)\.stream\(\)\.map\(([^)]+)\)\.collect\(Collectors\.toList\(\)\)/g,
|
||||
'$1.map($2)');
|
||||
|
||||
// .stream().filter().collect()
|
||||
body = body.replace(/(\w+)\.stream\(\)\.filter\(([^)]+)\)\.collect\(Collectors\.toList\(\)\)/g,
|
||||
'$1.filter($2)');
|
||||
|
||||
// .stream().collect(Collectors.toList())
|
||||
body = body.replace(/\.stream\(\)\.collect\(Collectors\.toList\(\)\)/g, '');
|
||||
|
||||
// .stream().collect(Collectors.toSet())
|
||||
body = body.replace(/\.stream\(\)\.collect\(Collectors\.toSet\(\)\)/g, '');
|
||||
|
||||
// .stream().forEach(x -> ...)
|
||||
body = body.replace(/\.stream\(\)\.forEach\(/g, '.forEach(');
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 4. 转换工具类调用
|
||||
*/
|
||||
convertUtilsCalls(body) {
|
||||
// 遍历所有工具类方法映射
|
||||
for (const [javaCall, nestCall] of Object.entries(this.utilsMethodMapping)) {
|
||||
const pattern = new RegExp(javaCall.replace(/\./g, '\\.'), 'g');
|
||||
body = body.replace(pattern, nestCall);
|
||||
}
|
||||
|
||||
// 特殊处理:BeanUtils.copyProperties(source, target)
|
||||
body = body.replace(/BeanUtils\.copyProperties\(([^,]+),\s*([^)]+)\)/g,
|
||||
'Object.assign($2, $1)');
|
||||
|
||||
// Assert.notNull -> if (!xxx) throw
|
||||
body = body.replace(/Assert\.notNull\(([^,]+),\s*"([^"]+)"\)/g,
|
||||
'if (!$1) throw new BadRequestException("$2")');
|
||||
|
||||
// Assert.isTrue -> if (!xxx) throw
|
||||
body = body.replace(/Assert\.isTrue\(([^,]+),\s*"([^"]+)"\)/g,
|
||||
'if (!($1)) throw new BadRequestException("$2")');
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 5. 转换 Lambda 表达式
|
||||
* 例:x -> x.getName() -> x => x.name
|
||||
*/
|
||||
convertLambdaExpressions(body) {
|
||||
// 单参数 lambda: x -> ...
|
||||
body = body.replace(/(\w+)\s*->\s*/g, '$1 => ');
|
||||
|
||||
// 多参数 lambda: (x, y) -> ...
|
||||
body = body.replace(/\(([^)]+)\)\s*->\s*/g, '($1) => ');
|
||||
|
||||
// Java getter: x.getName() -> x.name
|
||||
body = body.replace(/\.get(\w+)\(\)/g, (match, propName) => {
|
||||
return '.' + propName.charAt(0).toLowerCase() + propName.slice(1);
|
||||
});
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 6. 转换日志语句
|
||||
* 例:log.info(...) -> this.logger.log(...)
|
||||
*/
|
||||
convertLogStatements(body) {
|
||||
body = body.replace(/\blog\.info\(/g, 'this.logger.log(');
|
||||
body = body.replace(/\blog\.error\(/g, 'this.logger.error(');
|
||||
body = body.replace(/\blog\.warn\(/g, 'this.logger.warn(');
|
||||
body = body.replace(/\blog\.debug\(/g, 'this.logger.debug(');
|
||||
|
||||
// logger.info -> this.logger.log
|
||||
body = body.replace(/\blogger\.info\(/g, 'this.logger.log(');
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 7. 转换异常处理
|
||||
* 例:throw new RuntimeException(...) -> throw new Error(...)
|
||||
*/
|
||||
convertExceptionHandling(body) {
|
||||
// RuntimeException -> Error
|
||||
body = body.replace(/throw\s+new\s+RuntimeException\(/g, 'throw new Error(');
|
||||
|
||||
// IllegalArgumentException -> BadRequestException
|
||||
body = body.replace(/throw\s+new\s+IllegalArgumentException\(/g, 'throw new BadRequestException(');
|
||||
|
||||
// NullPointerException -> Error
|
||||
body = body.replace(/throw\s+new\s+NullPointerException\(/g, 'throw new Error(');
|
||||
|
||||
// try-catch
|
||||
body = body.replace(/catch\s*\(\s*Exception\s+e\s*\)/g, 'catch (e)');
|
||||
body = body.replace(/catch\s*\(\s*(\w+Exception)\s+e\s*\)/g, 'catch (e)');
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 8. 转换变量声明
|
||||
* 例:String name = ... -> const name: string = ...
|
||||
*/
|
||||
convertVariableDeclarations(body) {
|
||||
// String/Integer/Long/Boolean -> const
|
||||
body = body.replace(/\b(String|Integer|Long|Boolean|Double|Float)\s+(\w+)\s*=/g, 'const $2: string =');
|
||||
|
||||
// List<T> -> const xxx: T[] =
|
||||
body = body.replace(/List<([^>]+)>\s+(\w+)\s*=/g, 'const $2: $1[] =');
|
||||
|
||||
// Map<K,V> -> const xxx: Map<K,V> =
|
||||
body = body.replace(/Map<([^>]+)>\s+(\w+)\s*=/g, 'const $2: any =');
|
||||
|
||||
// new ArrayList<>() -> []
|
||||
body = body.replace(/new\s+ArrayList<[^>]*>\(\)/g, '[]');
|
||||
|
||||
// new HashMap<>() -> {}
|
||||
body = body.replace(/new\s+HashMap<[^>]*>\(\)/g, '{}');
|
||||
|
||||
// new HashSet<>() -> new Set()
|
||||
body = body.replace(/new\s+HashSet<[^>]*>\(\)/g, 'new Set()');
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 9. 为异步调用添加 await
|
||||
*/
|
||||
addAwaitToAsyncCalls(body) {
|
||||
// 为 Repository 调用添加 await
|
||||
body = body.replace(/(\s+)(this\.\w+Repository\.\w+\()/g, '$1await $2');
|
||||
|
||||
// 避免重复的 await await
|
||||
body = body.replace(/await\s+await/g, 'await');
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 10. 转换分页逻辑
|
||||
* 例:IPage<User> page = xxxMapper.selectPage(...)
|
||||
* -> const [data, total] = await this.repository.findAndCount(...)
|
||||
*/
|
||||
convertPaginationLogic(body) {
|
||||
// IPage<T> page = mapper.selectPage(...)
|
||||
body = body.replace(
|
||||
/IPage<([^>]+)>\s+(\w+)\s*=\s*(\w+)Mapper\.selectPage\(([^)]+)\)/g,
|
||||
'const [data, total] = await this.$3Repository.findAndCount({ skip: ($4 - 1) * limit, take: limit })'
|
||||
);
|
||||
|
||||
// page.getRecords() -> data
|
||||
body = body.replace(/(\w+)\.getRecords\(\)/g, 'data');
|
||||
|
||||
// page.getTotal() -> total
|
||||
body = body.replace(/(\w+)\.getTotal\(\)/g, 'total');
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整转换方法(包含所有步骤)
|
||||
*/
|
||||
convertFullMethod(javaMethod) {
|
||||
if (!javaMethod.body) {
|
||||
return {
|
||||
body: ' // TODO: 实现业务逻辑\n throw new Error("Not implemented");',
|
||||
hasBusinessLogic: false
|
||||
};
|
||||
}
|
||||
|
||||
let body = javaMethod.body;
|
||||
const originalBody = body;
|
||||
|
||||
// 应用所有转换
|
||||
body = this.convertQueryWrapper(body);
|
||||
body = this.convertMapperCalls(body);
|
||||
body = this.convertStreamAPI(body);
|
||||
body = this.convertUtilsCalls(body);
|
||||
body = this.convertLambdaExpressions(body);
|
||||
body = this.convertLogStatements(body);
|
||||
body = this.convertExceptionHandling(body);
|
||||
body = this.convertVariableDeclarations(body);
|
||||
body = this.convertPaginationLogic(body);
|
||||
body = this.addAwaitToAsyncCalls(body);
|
||||
|
||||
// 计算转换质量
|
||||
const quality = this.assessConversionQuality(originalBody, body);
|
||||
|
||||
return {
|
||||
body,
|
||||
hasBusinessLogic: true,
|
||||
quality,
|
||||
stats: {
|
||||
queryWrapperConverted: (originalBody.match(/QueryWrapper/g) || []).length,
|
||||
mapperCallsConverted: (originalBody.match(/Mapper\./g) || []).length,
|
||||
streamAPIConverted: (originalBody.match(/\.stream\(\)/g) || []).length,
|
||||
utilsCallsConverted: (originalBody.match(/(StringUtil|ObjectUtil|CollUtil|RequestUtils)\./g) || []).length
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 评估转换质量
|
||||
*/
|
||||
assessConversionQuality(original, converted) {
|
||||
const issues = [];
|
||||
|
||||
// 检查是否还有 Java 语法残留
|
||||
if (converted.includes('QueryWrapper')) issues.push('QueryWrapper 未完全转换');
|
||||
if (converted.includes('Mapper.')) issues.push('Mapper 调用未完全转换');
|
||||
if (converted.includes('.stream()')) issues.push('Stream API 未完全转换');
|
||||
if (converted.includes('StringUtil.')) issues.push('StringUtil 未完全转换');
|
||||
if (converted.includes('->')) issues.push('Lambda 表达式未完全转换');
|
||||
if (converted.includes('log.')) issues.push('日志语句未完全转换');
|
||||
|
||||
return {
|
||||
isComplete: issues.length === 0,
|
||||
issues,
|
||||
score: Math.max(0, 100 - issues.length * 10)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EnhancedBusinessLogicConverter;
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const NamingUtils = require('../utils/naming-utils');
|
||||
|
||||
/**
|
||||
* 增强的依赖注入转换器
|
||||
* 核心能力:
|
||||
* 1. 分析方法体,智能推断所需依赖
|
||||
* 2. 自动映射 Mapper -> Repository
|
||||
* 3. 自动映射 Java Utils -> wwjcloud-boot 服务
|
||||
* 4. 推断 Service 间依赖关系
|
||||
*/
|
||||
class EnhancedDependencyInjectionConverter {
|
||||
constructor() {
|
||||
this.namingUtils = new NamingUtils();
|
||||
|
||||
// Java Utils -> wwjcloud-boot 服务映射
|
||||
this.utilsServiceMapping = {
|
||||
'RequestUtils': 'RequestContextService',
|
||||
'RedisUtils': 'CacheService',
|
||||
'JwtUtil': 'JwtService',
|
||||
'FileUtil': 'FileUtils',
|
||||
'DateUtil': 'DateUtils',
|
||||
'StringUtil': 'StringUtils',
|
||||
'ObjectUtil': 'CommonUtils'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能推断依赖(核心方法)
|
||||
*/
|
||||
inferDependencies(javaClass) {
|
||||
const dependencies = new Map(); // 使用 Map 避免重复
|
||||
|
||||
// 1. 提取显式声明的依赖(@Autowired/@Resource)
|
||||
this.extractExplicitDependencies(javaClass, dependencies);
|
||||
|
||||
// 2. 分析方法体,推断 Mapper -> Repository
|
||||
this.inferRepositoryDependencies(javaClass, dependencies);
|
||||
|
||||
// 3. 分析方法体,推断 Service 依赖
|
||||
this.inferServiceDependencies(javaClass, dependencies);
|
||||
|
||||
// 4. 分析方法体,推断 Utils -> wwjcloud-boot 服务
|
||||
this.inferUtilsServiceDependencies(javaClass, dependencies);
|
||||
|
||||
// 5. 自动添加 Logger
|
||||
this.addLoggerDependency(javaClass, dependencies);
|
||||
|
||||
return Array.from(dependencies.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. 提取显式声明的依赖
|
||||
*/
|
||||
extractExplicitDependencies(javaClass, dependencies) {
|
||||
if (!javaClass.fields) return;
|
||||
|
||||
javaClass.fields.forEach(field => {
|
||||
if (field.annotations && (
|
||||
field.annotations.includes('@Autowired') ||
|
||||
field.annotations.includes('@Resource')
|
||||
)) {
|
||||
const key = field.name;
|
||||
if (!dependencies.has(key)) {
|
||||
dependencies.set(key, {
|
||||
source: 'explicit',
|
||||
name: field.name,
|
||||
javaType: field.type,
|
||||
nestType: this.mapJavaTypeToNestType(field.type),
|
||||
injectionType: this.determineInjectionType(field.type)
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. 推断 Repository 依赖
|
||||
* 分析:xxxMapper.selectById() -> @InjectRepository(Entity)
|
||||
*/
|
||||
inferRepositoryDependencies(javaClass, dependencies) {
|
||||
if (!javaClass.methods) return;
|
||||
|
||||
javaClass.methods.forEach(method => {
|
||||
if (!method.body) return;
|
||||
|
||||
// 匹配 xxxMapper.xxx() 调用
|
||||
const mapperPattern = /(\w+Mapper)\.(\w+)\(/g;
|
||||
let match;
|
||||
|
||||
while ((match = mapperPattern.exec(method.body)) !== null) {
|
||||
const mapperName = match[1]; // 例如: SysUserMapper
|
||||
const mapperField = mapperName.charAt(0).toLowerCase() + mapperName.slice(1);
|
||||
|
||||
// 转换为 Entity 名称
|
||||
const entityName = mapperName.replace('Mapper', ''); // SysUser
|
||||
|
||||
const key = mapperField;
|
||||
if (!dependencies.has(key)) {
|
||||
dependencies.set(key, {
|
||||
source: 'inferred-repository',
|
||||
name: mapperField, // sysUserMapper
|
||||
javaType: mapperName, // SysUserMapper
|
||||
nestType: `Repository<${entityName}>`, // Repository<SysUser>
|
||||
entityName: entityName,
|
||||
injectionType: 'repository'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 3. 推断 Service 依赖
|
||||
* 分析:this.xxxService.xxx() 或 xxxService.xxx()
|
||||
*/
|
||||
inferServiceDependencies(javaClass, dependencies) {
|
||||
if (!javaClass.methods) return;
|
||||
|
||||
javaClass.methods.forEach(method => {
|
||||
if (!method.body) return;
|
||||
|
||||
// 匹配 Service 调用
|
||||
const servicePattern = /(?:this\.)?(\w+Service)\.(\w+)\(/g;
|
||||
let match;
|
||||
|
||||
while ((match = servicePattern.exec(method.body)) !== null) {
|
||||
const serviceType = match[1]; // 例如: SysUserService
|
||||
const serviceField = serviceType.charAt(0).toLowerCase() + serviceType.slice(1);
|
||||
|
||||
const key = serviceField;
|
||||
if (!dependencies.has(key)) {
|
||||
dependencies.set(key, {
|
||||
source: 'inferred-service',
|
||||
name: serviceField, // sysUserService
|
||||
javaType: serviceType, // SysUserService
|
||||
nestType: this.convertServiceName(serviceType), // SysUserServiceImplService
|
||||
injectionType: 'service'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 4. 推断 Utils -> wwjcloud-boot 服务依赖
|
||||
* 分析:RequestUtils.xxx() -> RequestContextService
|
||||
*/
|
||||
inferUtilsServiceDependencies(javaClass, dependencies) {
|
||||
if (!javaClass.methods) return;
|
||||
|
||||
javaClass.methods.forEach(method => {
|
||||
if (!method.body) return;
|
||||
|
||||
// 检查每种 Utils 的使用
|
||||
for (const [javaUtil, nestService] of Object.entries(this.utilsServiceMapping)) {
|
||||
if (method.body.includes(javaUtil + '.')) {
|
||||
const serviceField = nestService.charAt(0).toLowerCase() + nestService.slice(1);
|
||||
const key = serviceField;
|
||||
|
||||
if (!dependencies.has(key)) {
|
||||
dependencies.set(key, {
|
||||
source: 'inferred-utils',
|
||||
name: serviceField,
|
||||
javaType: javaUtil,
|
||||
nestType: nestService,
|
||||
injectionType: 'boot-service'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 5. 自动添加 Logger
|
||||
*/
|
||||
addLoggerDependency(javaClass, dependencies) {
|
||||
// 检查是否有 log.xxx() 或 logger.xxx() 调用
|
||||
let needsLogger = false;
|
||||
|
||||
if (javaClass.methods) {
|
||||
javaClass.methods.forEach(method => {
|
||||
if (method.body && (
|
||||
method.body.includes('log.') ||
|
||||
method.body.includes('logger.')
|
||||
)) {
|
||||
needsLogger = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (needsLogger && !dependencies.has('logger')) {
|
||||
dependencies.set('logger', {
|
||||
source: 'auto-logger',
|
||||
name: 'logger',
|
||||
javaType: 'Logger',
|
||||
nestType: 'Logger',
|
||||
injectionType: 'logger',
|
||||
isField: true // Logger 作为字段,不在 constructor 中
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 NestJS 构造函数
|
||||
*/
|
||||
generateConstructor(dependencies, className) {
|
||||
// 过滤掉字段依赖(如 Logger)
|
||||
const constructorDeps = dependencies.filter(dep => !dep.isField);
|
||||
|
||||
if (constructorDeps.length === 0) {
|
||||
return ' constructor() {}';
|
||||
}
|
||||
|
||||
const injections = constructorDeps.map(dep => {
|
||||
return this.generateInjection(dep);
|
||||
});
|
||||
|
||||
return ` constructor(\n${injections.join(',\n')}\n ) {}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成单个依赖注入
|
||||
*/
|
||||
generateInjection(dependency) {
|
||||
const { injectionType, name, nestType, entityName } = dependency;
|
||||
|
||||
switch (injectionType) {
|
||||
case 'repository':
|
||||
return ` @InjectRepository(${entityName})\n private readonly ${name}: Repository<${entityName}>`;
|
||||
|
||||
case 'service':
|
||||
return ` private readonly ${name}: ${nestType}`;
|
||||
|
||||
case 'boot-service':
|
||||
return ` private readonly ${name}: ${nestType}`;
|
||||
|
||||
default:
|
||||
return ` private readonly ${name}: ${nestType}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成导入语句
|
||||
*/
|
||||
generateImports(dependencies) {
|
||||
const imports = new Set();
|
||||
|
||||
// 基础导入
|
||||
imports.add("import { Injectable, Logger } from '@nestjs/common';");
|
||||
|
||||
// Repository 导入
|
||||
const hasRepository = dependencies.some(dep => dep.injectionType === 'repository');
|
||||
if (hasRepository) {
|
||||
imports.add("import { InjectRepository } from '@nestjs/typeorm';");
|
||||
imports.add("import { Repository } from 'typeorm';");
|
||||
}
|
||||
|
||||
// Entity 导入
|
||||
dependencies
|
||||
.filter(dep => dep.injectionType === 'repository')
|
||||
.forEach(dep => {
|
||||
const entityPath = this.generateEntityImportPath(dep.entityName);
|
||||
imports.add(`import { ${dep.entityName} } from '${entityPath}';`);
|
||||
});
|
||||
|
||||
// Service 导入
|
||||
dependencies
|
||||
.filter(dep => dep.injectionType === 'service')
|
||||
.forEach(dep => {
|
||||
const servicePath = this.generateServiceImportPath(dep.nestType);
|
||||
imports.add(`import { ${dep.nestType} } from '${servicePath}';`);
|
||||
});
|
||||
|
||||
// wwjcloud-boot 服务导入
|
||||
dependencies
|
||||
.filter(dep => dep.injectionType === 'boot-service')
|
||||
.forEach(dep => {
|
||||
const bootPath = this.generateBootServiceImportPath(dep.nestType);
|
||||
imports.add(`import { ${dep.nestType} } from '${bootPath}';`);
|
||||
});
|
||||
|
||||
return Array.from(imports);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成字段声明(如 Logger)
|
||||
*/
|
||||
generateFields(dependencies, className) {
|
||||
const fields = [];
|
||||
|
||||
const fieldDeps = dependencies.filter(dep => dep.isField);
|
||||
|
||||
fieldDeps.forEach(dep => {
|
||||
if (dep.injectionType === 'logger') {
|
||||
fields.push(` private readonly logger = new Logger(${className}.name);`);
|
||||
}
|
||||
});
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:映射 Java 类型到 NestJS 类型
|
||||
*/
|
||||
mapJavaTypeToNestType(javaType) {
|
||||
// SysUserMapper -> Repository<SysUser>
|
||||
if (javaType.endsWith('Mapper')) {
|
||||
const entityName = javaType.replace('Mapper', '');
|
||||
return `Repository<${entityName}>`;
|
||||
}
|
||||
|
||||
// SysUserService -> SysUserServiceImplService
|
||||
if (javaType.endsWith('Service')) {
|
||||
return this.convertServiceName(javaType);
|
||||
}
|
||||
|
||||
// 工具类
|
||||
if (this.utilsServiceMapping[javaType]) {
|
||||
return this.utilsServiceMapping[javaType];
|
||||
}
|
||||
|
||||
return javaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:判断注入类型
|
||||
*/
|
||||
determineInjectionType(javaType) {
|
||||
if (javaType.endsWith('Mapper')) return 'repository';
|
||||
if (javaType.endsWith('Service')) return 'service';
|
||||
if (this.utilsServiceMapping[javaType]) return 'boot-service';
|
||||
return 'other';
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:转换 Service 名称
|
||||
*/
|
||||
convertServiceName(javaServiceName) {
|
||||
// SysUserService -> SysUserServiceImplService
|
||||
if (javaServiceName.endsWith('Service')) {
|
||||
const baseName = javaServiceName.replace('Service', '');
|
||||
return `${baseName}ServiceImplService`;
|
||||
}
|
||||
return javaServiceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:生成 Entity 导入路径
|
||||
*/
|
||||
generateEntityImportPath(entityName) {
|
||||
// 简化版本,实际需要根据项目结构调整
|
||||
const kebabName = this.namingUtils.toKebabCase(entityName);
|
||||
return `@/entities/${kebabName}.entity`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:生成 Service 导入路径
|
||||
*/
|
||||
generateServiceImportPath(serviceName) {
|
||||
const kebabName = this.namingUtils.toKebabCase(serviceName);
|
||||
return `../${kebabName}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:生成 wwjcloud-boot 服务导入路径
|
||||
*/
|
||||
generateBootServiceImportPath(serviceName) {
|
||||
const pathMap = {
|
||||
'RequestContextService': '@/wwjcloud-boot/infra/http/request-context.service',
|
||||
'CacheService': '@/wwjcloud-boot/infra/cache/cache.service',
|
||||
'JwtService': '@nestjs/jwt',
|
||||
'FileUtils': '@/wwjcloud-boot/vendor/utils/file.utils',
|
||||
'DateUtils': '@/wwjcloud-boot/vendor/utils/date.utils',
|
||||
'StringUtils': '@/wwjcloud-boot/vendor/utils/string.utils',
|
||||
'CommonUtils': '@/wwjcloud-boot/vendor/utils/common.utils'
|
||||
};
|
||||
|
||||
return pathMap[serviceName] || '@/wwjcloud-boot';
|
||||
}
|
||||
|
||||
/**
|
||||
* 主转换方法
|
||||
*/
|
||||
convertDependencyInjection(javaClass) {
|
||||
const dependencies = this.inferDependencies(javaClass);
|
||||
const className = javaClass.className || 'UnknownClass';
|
||||
const constructor = this.generateConstructor(dependencies, className);
|
||||
const imports = this.generateImports(dependencies);
|
||||
const fields = this.generateFields(dependencies, className);
|
||||
|
||||
return {
|
||||
dependencies,
|
||||
constructor,
|
||||
imports,
|
||||
fields,
|
||||
stats: {
|
||||
total: dependencies.length,
|
||||
explicit: dependencies.filter(d => d.source === 'explicit').length,
|
||||
inferred: dependencies.filter(d => d.source.startsWith('inferred')).length,
|
||||
auto: dependencies.filter(d => d.source.startsWith('auto')).length
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成完整的服务文件头部
|
||||
*/
|
||||
generateServiceHeader(javaClass) {
|
||||
const result = this.convertDependencyInjection(javaClass);
|
||||
const className = javaClass.className || 'UnknownClass';
|
||||
|
||||
let header = '';
|
||||
|
||||
// 导入语句
|
||||
header += result.imports.join('\n') + '\n\n';
|
||||
|
||||
// 类声明和字段
|
||||
header += `@Injectable()\n`;
|
||||
header += `export class ${className} {\n`;
|
||||
|
||||
// 字段声明(如 Logger)
|
||||
if (result.fields.length > 0) {
|
||||
header += result.fields.join('\n') + '\n\n';
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
header += result.constructor + '\n';
|
||||
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EnhancedDependencyInjectionConverter;
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
#!/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 FrameworkIntegrationValidator = require('./utils/framework-integration-validator');
|
||||
|
||||
/**
|
||||
* Java到NestJS迁移协调器
|
||||
* 按技术层级组织模块,严格遵循NestJS官方规范
|
||||
*/
|
||||
class JavaToNestJSMigrationCoordinator {
|
||||
constructor() {
|
||||
this.javaPath = '';
|
||||
this.nestJSPath = '';
|
||||
this.scanner = new JavaScanner();
|
||||
this.mapper = new LayerMapper();
|
||||
this.moduleGenerator = new ModuleGenerator();
|
||||
this.frameworkValidator = new FrameworkIntegrationValidator();
|
||||
|
||||
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();
|
||||
|
||||
} 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} 个文件`);
|
||||
|
||||
// 验证扫描结果
|
||||
this.validateScanResults(scanResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证扫描结果
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成NestJS模块
|
||||
*/
|
||||
async generateModules(nestJSModules) {
|
||||
this.moduleGenerator.setOutputDir(this.nestJSPath);
|
||||
await this.moduleGenerator.generateAllModules(nestJSModules);
|
||||
|
||||
this.stats.modulesGenerated = Object.keys(nestJSModules).length;
|
||||
console.log(`✅ 生成了 ${this.stats.modulesGenerated} 个模块`);
|
||||
|
||||
// 后处理:自动生成缺失的Service方法存根
|
||||
console.log('\n📝 后处理:生成缺失的Service方法存根...');
|
||||
const MethodStubGenerator = require('./generators/method-stub-generator');
|
||||
const stubGenerator = new MethodStubGenerator();
|
||||
stubGenerator.process(this.nestJSPath);
|
||||
|
||||
// 验证框架集成
|
||||
console.log('\n🔍 开始验证框架集成...');
|
||||
const generatedFiles = this.getGeneratedFiles();
|
||||
const validationResults = this.frameworkValidator.validateFrameworkIntegration(generatedFiles);
|
||||
this.printFrameworkValidationResults(validationResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成迁移报告
|
||||
*/
|
||||
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;
|
||||
Reference in New Issue
Block a user