From be792c9735933b37d3b5ee0311f4771622109be6 Mon Sep 17 00:00:00 2001 From: wanwu Date: Tue, 28 Oct 2025 15:53:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8D=E5=8E=9F=E5=A7=8B?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E5=B7=A5=E5=85=B7=20-=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=89=80=E6=9C=89enhanced=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🗑️ 删除的文件: - 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子目录结构 --- .../ENHANCED_MIGRATION_REPORT.json | 25 - .../enhanced-business-logic-converter.js | 436 ----------------- ...enhanced-dependency-injection-converter.js | 437 ------------------ .../migration-coordinator.js | 365 +++++++++++++++ 4 files changed, 365 insertions(+), 898 deletions(-) delete mode 100644 wwjcloud-nest-v1/tools/java-to-nestjs-migration/ENHANCED_MIGRATION_REPORT.json delete mode 100644 wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-business-logic-converter.js delete mode 100644 wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-dependency-injection-converter.js create mode 100644 wwjcloud-nest-v1/tools/java-to-nestjs-migration/migration-coordinator.js diff --git a/wwjcloud-nest-v1/tools/java-to-nestjs-migration/ENHANCED_MIGRATION_REPORT.json b/wwjcloud-nest-v1/tools/java-to-nestjs-migration/ENHANCED_MIGRATION_REPORT.json deleted file mode 100644 index 0888cdd3..00000000 --- a/wwjcloud-nest-v1/tools/java-to-nestjs-migration/ENHANCED_MIGRATION_REPORT.json +++ /dev/null @@ -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": [] -} \ No newline at end of file diff --git a/wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-business-logic-converter.js b/wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-business-logic-converter.js deleted file mode 100644 index e41998df..00000000 --- a/wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-business-logic-converter.js +++ /dev/null @@ -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 -> const xxx: T[] = - body = body.replace(/List<([^>]+)>\s+(\w+)\s*=/g, 'const $2: $1[] ='); - - // Map -> const xxx: Map = - 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 page = xxxMapper.selectPage(...) - * -> const [data, total] = await this.repository.findAndCount(...) - */ - convertPaginationLogic(body) { - // IPage 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; - diff --git a/wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-dependency-injection-converter.js b/wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-dependency-injection-converter.js deleted file mode 100644 index 2705be05..00000000 --- a/wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/enhanced-dependency-injection-converter.js +++ /dev/null @@ -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 - 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 - 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; - diff --git a/wwjcloud-nest-v1/tools/java-to-nestjs-migration/migration-coordinator.js b/wwjcloud-nest-v1/tools/java-to-nestjs-migration/migration-coordinator.js new file mode 100644 index 00000000..84ac3568 --- /dev/null +++ b/wwjcloud-nest-v1/tools/java-to-nestjs-migration/migration-coordinator.js @@ -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;