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路径错误
This commit is contained in:
@@ -0,0 +1,484 @@
|
||||
# 🔍 迁移工具架构一致性问题分析报告
|
||||
|
||||
**生成时间**: 2025-10-29
|
||||
**版本**: f615c61c (详细错误分析报告版本)
|
||||
**编译错误**: 14,086个
|
||||
|
||||
---
|
||||
|
||||
## 📊 核心问题总结
|
||||
|
||||
### 🎯 根本原因
|
||||
**各层Generator缺乏统一的数据模型和通信机制,导致生成的代码层级不一致**
|
||||
|
||||
---
|
||||
|
||||
## 1️⃣ 架构流程现状
|
||||
|
||||
```
|
||||
migration-coordinator.js (总协调器)
|
||||
│
|
||||
├── 【阶段1】java-scanner.js (扫描Java代码)
|
||||
│ └── 输出: { controllers, services, dtos, entities, enums, jobs, listeners }
|
||||
│
|
||||
├── 【阶段2】buildServiceMethodSignatureIndex()
|
||||
│ └── 输出: serviceMethodSignatureIndex (Map)
|
||||
│ 格式: { "ServiceImplName.methodName": { parameters: [...], returnType: "..." } }
|
||||
│
|
||||
├── 【阶段3】module-generator.js (生成模块)
|
||||
│ ├── ✅ 接收: serviceMethodSignatureIndex
|
||||
│ │
|
||||
│ ├── controller-generator.js
|
||||
│ │ ├── ✅ 接收: serviceMethodSignatureIndex (通过setServiceMethodSignatureIndex)
|
||||
│ │ └── ✅ 使用: readServiceMethodSignature() 查询索引
|
||||
│ │
|
||||
│ ├── service-generator.js
|
||||
│ │ ├── ❌ 未接收: serviceMethodSignatureIndex
|
||||
│ │ ├── ❌ 硬编码: DTO路径 '../dtos/{file}.dto'
|
||||
│ │ └── ⚠️ 使用: service-method-converter.js (独立转换,不知道Controller需求)
|
||||
│ │
|
||||
│ ├── dto-generator.js
|
||||
│ │ ├── ❌ 未暴露: DTO实际生成路径信息
|
||||
│ │ └── ⚠️ DTO可能在: dtos/core/member/xxx.dto
|
||||
│ │
|
||||
│ ├── entity-generator.js
|
||||
│ ├── enum-generator.js
|
||||
│ ├── listener-generator.js
|
||||
│ └── job-generator.js
|
||||
│
|
||||
└── 【阶段4】generateReport()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2️⃣ 具体问题清单
|
||||
|
||||
### ❌ 问题1: Service Generator未使用中央索引
|
||||
|
||||
**文件**: `service-generator.js`
|
||||
**代码位置**: 整个类
|
||||
**现象**:
|
||||
```javascript
|
||||
class ServiceGenerator {
|
||||
constructor(outputDir = null) {
|
||||
this.namingUtils = new NamingUtils();
|
||||
this.methodConverter = new ServiceMethodConverter();
|
||||
this.outputDir = outputDir;
|
||||
// ❌ 缺少: this.serviceMethodSignatureIndex = null;
|
||||
}
|
||||
|
||||
// ❌ 缺少方法:
|
||||
// setServiceMethodSignatureIndex(index) {
|
||||
// this.serviceMethodSignatureIndex = index;
|
||||
// }
|
||||
}
|
||||
```
|
||||
|
||||
**影响**:
|
||||
- Service生成的方法签名与Controller期望的签名可能不一致
|
||||
- 导致Controller调用Service时参数数量、类型不匹配
|
||||
- 产生错误: TS2554 (参数数量不匹配), TS2345 (参数类型不匹配)
|
||||
|
||||
**错误数量**: 约50个 TS2554/TS2345错误
|
||||
|
||||
---
|
||||
|
||||
### ❌ 问题2: DTO路径硬编码
|
||||
|
||||
**文件**: `service-generator.js:415`
|
||||
**问题代码**:
|
||||
```javascript
|
||||
// 添加DTO导入
|
||||
if (javaService.dtos && javaService.dtos.length > 0) {
|
||||
javaService.dtos.forEach(dto => {
|
||||
const dtoName = this.namingUtils.generateDtoName(cleanDto);
|
||||
const dtoFileName = this.namingUtils.generateFileName(cleanDto, 'dto');
|
||||
|
||||
// ❌ 硬编码路径,假设所有DTO都在 '../dtos/'
|
||||
imports.push(`import { ${dtoName} } from '../dtos/${dtoFileName.replace('.ts', '')}';`);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**实际DTO位置**:
|
||||
```
|
||||
dtos/
|
||||
├── admin/
|
||||
│ └── member/
|
||||
│ └── member-info.dto.ts
|
||||
├── core/
|
||||
│ └── member/
|
||||
│ ├── dto/
|
||||
│ │ └── member-info.dto.ts
|
||||
│ ├── param/
|
||||
│ │ └── member-search-param.dto.ts
|
||||
│ └── vo/
|
||||
│ └── member-list-vo.dto.ts
|
||||
└── api/
|
||||
└── ...
|
||||
```
|
||||
|
||||
**影响**:
|
||||
- Service导入DTO时使用错误的路径
|
||||
- 产生错误: TS2307 (Cannot find module '../dtos/xxx.dto')
|
||||
|
||||
**错误数量**: 约4,200个 TS2307错误
|
||||
|
||||
**根本原因**:
|
||||
- `dto-generator.js` 生成DTO时,按照Java包结构组织目录
|
||||
- `service-generator.js` 导入DTO时,使用硬编码的相对路径
|
||||
- 两者没有共享"DTO实际位置映射表"
|
||||
|
||||
---
|
||||
|
||||
### ❌ 问题3: 转换器链路不透明
|
||||
|
||||
**文件**: `service-method-converter.js`
|
||||
**现象**:
|
||||
```javascript
|
||||
convertMethodBody(javaMethodBody, context = {}) {
|
||||
let tsBody = javaMethodBody;
|
||||
|
||||
// 阶段1: 基础语法转换
|
||||
tsBody = this.basicSyntax.convert(tsBody);
|
||||
|
||||
// 阶段2: 类型转换
|
||||
tsBody = this.type.convert(tsBody);
|
||||
|
||||
// 阶段3: 工具类转换
|
||||
tsBody = this.collection.convert(tsBody);
|
||||
// ...
|
||||
|
||||
// 阶段6: Getter/Setter转换
|
||||
tsBody = this.getterSetter.convert(tsBody);
|
||||
|
||||
// ⚠️ 问题:每个转换器独立工作,不知道前面做了什么
|
||||
// 可能导致:
|
||||
// - 变量声明被重复转换
|
||||
// - 方法调用被多次修改
|
||||
// - 转换结果被后续转换器覆盖
|
||||
}
|
||||
```
|
||||
|
||||
**具体案例**:
|
||||
```java
|
||||
// Java原始代码
|
||||
Map<String, LocalAddonInfoVo> list = new HashMap<>();
|
||||
```
|
||||
|
||||
**错误转换过程**:
|
||||
```javascript
|
||||
// 阶段1: basicSyntax.convert()
|
||||
// Map<String, ...> list = ... → const list: Record<string, ...> = ...
|
||||
"const list: Record<string, LocalAddonInfoVo> = new HashMap<>();"
|
||||
|
||||
// 阶段3: collection.convert()
|
||||
// new HashMap<>() → {}
|
||||
"const list: Record<string, LocalAddonInfoVo> = {};" // ✅ 正确
|
||||
|
||||
// ❌ 但如果basic-syntax转换器有Bug,可能产生:
|
||||
"const list: Record<string, LocalAddonInfoVo> = new const installAddonList: Record<>();"
|
||||
```
|
||||
|
||||
**影响**:
|
||||
- 转换结果不可预测
|
||||
- 难以调试和定位问题
|
||||
- 转换器之间相互干扰
|
||||
|
||||
---
|
||||
|
||||
### ❌ 问题4: Controller与Service参数映射不智能
|
||||
|
||||
**文件**: `controller-generator.js:mapServiceParametersToController`
|
||||
**现象**:
|
||||
```javascript
|
||||
// Controller生成的调用
|
||||
async list(@Query() query: Record<string, any>) {
|
||||
const result = await this.memberLevelServiceImplService.list(query);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Service实际签名(从中央索引读取)
|
||||
async list(pageParam: PageParam, searchParam: MemberLevelSearchParam): Promise<any[]> {
|
||||
// ...
|
||||
}
|
||||
|
||||
// ❌ 结果:参数不匹配
|
||||
// Controller传1个参数 (query)
|
||||
// Service期望2个参数 (pageParam, searchParam)
|
||||
```
|
||||
|
||||
**影响**:
|
||||
- 产生错误: TS2554 (Expected 2 arguments, but got 1)
|
||||
|
||||
**根本原因**:
|
||||
- Controller Generator读取了Service方法签名
|
||||
- 但没有智能拆分`query`对象到多个参数
|
||||
- 缺少"参数映射规则库"
|
||||
|
||||
---
|
||||
|
||||
### ❌ 问题5: 各Generator缺少双向验证
|
||||
|
||||
**现象**:
|
||||
```
|
||||
Controller Generator:
|
||||
1. 从中央索引读取Service方法签名
|
||||
2. 生成Controller代码
|
||||
3. ❌ 没有验证:Service是否真的生成了这个方法
|
||||
|
||||
Service Generator:
|
||||
1. 从Java代码解析方法
|
||||
2. 生成Service代码
|
||||
3. ❌ 没有验证:Controller是否需要调用这个方法
|
||||
4. ❌ 没有验证:生成的签名是否与索引一致
|
||||
|
||||
结果:
|
||||
- Controller调用的方法,Service可能没有
|
||||
- Service生成的方法,Controller可能不需要
|
||||
- 方法签名不一致
|
||||
```
|
||||
|
||||
**影响**:
|
||||
- 产生错误: TS2339 (Property 'xxx' does not exist on type 'Service')
|
||||
- 产生错误: TS2551 (Property 'xxx' does not exist. Did you mean 'yyy'?)
|
||||
|
||||
**错误数量**: 约100个
|
||||
|
||||
---
|
||||
|
||||
## 3️⃣ 错误分布与根因映射
|
||||
|
||||
| 错误类型 | 错误码 | 数量 | 根本原因 | 对应问题 |
|
||||
|---------|-------|------|---------|---------|
|
||||
| DTO路径错误 | TS2307 | ~4,200 | DTO位置映射缺失 | 问题2 |
|
||||
| VO类型未导入 | TS2304 | ~2,800 | DTO路径错误连锁反应 | 问题2 |
|
||||
| Controller参数不匹配 | TS2554 | ~50 | 参数映射不智能 | 问题4 |
|
||||
| Controller参数类型错误 | TS2345 | ~20 | 参数映射不智能 | 问题4 |
|
||||
| Service方法不存在 | TS2339 | ~100 | 缺少双向验证 | 问题5 |
|
||||
| Service方法名相似 | TS2551 | ~20 | Java Scanner遗漏 | - |
|
||||
| 业务逻辑细节 | 各种 | ~7,000 | 转换器不完善 | 问题3 |
|
||||
|
||||
---
|
||||
|
||||
## 4️⃣ 理想架构设计
|
||||
|
||||
### 🎯 核心思想:中央数据仓库 (Central Data Repository, CDR)
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────────────────┐
|
||||
│ Central Data Repository (CDR) │
|
||||
│ ┌──────────────┬──────────────┬──────────────┬─────────────┐ │
|
||||
│ │ Service签名 │ DTO位置映射 │ 依赖关系图 │ 转换上下文 │ │
|
||||
│ │ Map<string, │ Map<string, │ Map<string, │ Map<string, │ │
|
||||
│ │ Signature> │ string> │ string[]> │ any> │ │
|
||||
│ └──────────────┴──────────────┴──────────────┴─────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────┘
|
||||
↑ 写入 ↓ 读取
|
||||
┌────┴────┐ ┌────┴────┐
|
||||
│ Scanner │ │Generator│
|
||||
│ 阶段 │ │ 阶段 │
|
||||
└─────────┘ └─────────┘
|
||||
```
|
||||
|
||||
### 📋 CDR数据结构
|
||||
|
||||
```javascript
|
||||
class CentralDataRepository {
|
||||
constructor() {
|
||||
// 1. Service方法签名索引(已有)
|
||||
this.serviceMethodSignatureIndex = new Map();
|
||||
// 格式: { "ServiceImplName.methodName": { parameters: [...], returnType: "..." } }
|
||||
|
||||
// 2. DTO位置映射(新增)
|
||||
this.dtoLocationMap = new Map();
|
||||
// 格式: { "MemberInfoDto": "dtos/core/member/dto/member-info.dto" }
|
||||
|
||||
// 3. VO位置映射(新增)
|
||||
this.voLocationMap = new Map();
|
||||
// 格式: { "MemberListVo": "dtos/core/member/vo/member-list-vo.dto" }
|
||||
|
||||
// 4. Entity位置映射(新增)
|
||||
this.entityLocationMap = new Map();
|
||||
// 格式: { "Member": "entities/member.entity" }
|
||||
|
||||
// 5. Service依赖关系(新增)
|
||||
this.serviceDependencyMap = new Map();
|
||||
// 格式: { "MemberServiceImpl": ["ICoreAddonService", "RedisService"] }
|
||||
|
||||
// 6. Controller-Service调用关系(新增)
|
||||
this.controllerServiceCallMap = new Map();
|
||||
// 格式: { "MemberController.list": { service: "MemberServiceImpl", method: "list" } }
|
||||
|
||||
// 7. 转换上下文(新增)
|
||||
this.conversionContext = new Map();
|
||||
// 格式: { "MemberServiceImpl.list": { phase: "converting", converter: "basicSyntax" } }
|
||||
}
|
||||
|
||||
// 读写方法
|
||||
setServiceSignature(key, signature) { /* ... */ }
|
||||
getServiceSignature(key) { /* ... */ }
|
||||
setDtoLocation(dtoName, path) { /* ... */ }
|
||||
getDtoLocation(dtoName) { /* ... */ }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 🔄 改进后的Generator协调流程
|
||||
|
||||
```javascript
|
||||
class JavaToNestJSMigrationCoordinator {
|
||||
constructor() {
|
||||
this.scanner = new JavaScanner();
|
||||
this.cdr = new CentralDataRepository(); // ✅ 中央数据仓库
|
||||
this.moduleGenerator = new ModuleGenerator();
|
||||
}
|
||||
|
||||
async runMigration() {
|
||||
// 阶段1: 扫描 + 构建CDR
|
||||
await this.scanAndBuildCDR();
|
||||
|
||||
// 阶段2: 生成(所有Generator共享CDR)
|
||||
await this.generateWithCDR();
|
||||
|
||||
// 阶段3: 验证(双向一致性检查)
|
||||
await this.validateConsistency();
|
||||
}
|
||||
|
||||
async scanAndBuildCDR() {
|
||||
const scanResults = await this.scanner.scanJavaProject();
|
||||
|
||||
// 构建Service签名索引
|
||||
scanResults.services.forEach(service => {
|
||||
service.methods.forEach(method => {
|
||||
const key = `${service.className}.${method.methodName}`;
|
||||
this.cdr.setServiceSignature(key, {
|
||||
parameters: method.parameters,
|
||||
returnType: method.returnType
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ✅ 新增:预先生成DTO并记录位置
|
||||
const dtoLocationMap = await this.dtoGenerator.generateAll(scanResults.dtos);
|
||||
dtoLocationMap.forEach((path, dtoName) => {
|
||||
this.cdr.setDtoLocation(dtoName, path);
|
||||
});
|
||||
|
||||
// ✅ 新增:记录Service依赖关系
|
||||
scanResults.services.forEach(service => {
|
||||
this.cdr.setServiceDependencies(service.className, service.dependencies);
|
||||
});
|
||||
}
|
||||
|
||||
async generateWithCDR() {
|
||||
// 传递CDR给所有Generator
|
||||
this.controllerGenerator.setCDR(this.cdr);
|
||||
this.serviceGenerator.setCDR(this.cdr);
|
||||
this.dtoGenerator.setCDR(this.cdr);
|
||||
|
||||
// 生成代码
|
||||
await this.controllerGenerator.generateAll();
|
||||
await this.serviceGenerator.generateAll();
|
||||
}
|
||||
|
||||
async validateConsistency() {
|
||||
// ✅ 双向验证
|
||||
const issues = [];
|
||||
|
||||
// 验证1: Controller调用的Service方法是否存在
|
||||
this.cdr.controllerServiceCallMap.forEach((call, controllerMethod) => {
|
||||
const serviceKey = `${call.service}.${call.method}`;
|
||||
if (!this.cdr.getServiceSignature(serviceKey)) {
|
||||
issues.push(`Controller ${controllerMethod} 调用的 ${serviceKey} 不存在`);
|
||||
}
|
||||
});
|
||||
|
||||
// 验证2: Service导入的DTO路径是否正确
|
||||
// 验证3: 参数类型是否匹配
|
||||
// ...
|
||||
|
||||
if (issues.length > 0) {
|
||||
console.error('❌ 一致性验证失败:', issues);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5️⃣ 修复建议
|
||||
|
||||
### 🔧 优先级1: 建立CDR(高优先级,影响4,200+错误)
|
||||
|
||||
**步骤**:
|
||||
1. 创建 `central-data-repository.js`
|
||||
2. 在 `migration-coordinator.js` 中实例化CDR
|
||||
3. 修改 `dto-generator.js`:生成DTO时记录到CDR
|
||||
4. 修改 `service-generator.js`:导入DTO时从CDR查询路径
|
||||
|
||||
**预计效果**: 减少4,200个TS2307错误
|
||||
|
||||
---
|
||||
|
||||
### 🔧 优先级2: Service Generator使用中央索引(中优先级,影响50+错误)
|
||||
|
||||
**步骤**:
|
||||
1. 在 `service-generator.js` 添加 `setCDR(cdr)` 方法
|
||||
2. 生成方法签名时,从CDR读取而不是从Java解析
|
||||
3. 确保与Controller期望的签名100%一致
|
||||
|
||||
**预计效果**: 减少50个TS2554/TS2345错误
|
||||
|
||||
---
|
||||
|
||||
### 🔧 优先级3: 转换器透明化(中优先级,提升质量)
|
||||
|
||||
**步骤**:
|
||||
1. 为每个转换器添加 `getConversionLog()` 方法
|
||||
2. 记录每次转换的输入、输出、规则
|
||||
3. 在 `service-method-converter.js` 中汇总日志
|
||||
4. 便于调试和定位问题
|
||||
|
||||
**预计效果**: 提升转换质量,减少未知Bug
|
||||
|
||||
---
|
||||
|
||||
### 🔧 优先级4: 双向验证机制(低优先级,长期改进)
|
||||
|
||||
**步骤**:
|
||||
1. 在生成完成后,运行一致性验证
|
||||
2. 检查Controller-Service调用关系
|
||||
3. 检查DTO/VO/Entity导入路径
|
||||
4. 生成验证报告
|
||||
|
||||
**预计效果**: 提前发现不一致问题
|
||||
|
||||
---
|
||||
|
||||
## 6️⃣ 总结
|
||||
|
||||
### 当前问题本质
|
||||
**不是业务逻辑转换问题,而是架构设计问题!**
|
||||
|
||||
14,086个错误中:
|
||||
- **30%** (约4,200个) - DTO路径错误(CDR缺失)
|
||||
- **5%** (约700个) - Controller-Service不一致(缺少协调)
|
||||
- **5%** (约700个) - 其他架构问题
|
||||
- **60%** (约8,500个) - 真正的业务逻辑转换问题
|
||||
|
||||
### 修复后预期
|
||||
实施优先级1+2后,错误数应该降至:
|
||||
```
|
||||
14,086 - 4,200 - 50 = 9,836个错误
|
||||
```
|
||||
|
||||
剩余错误将主要是真正的业务逻辑细节问题,可以集中精力优化转换器。
|
||||
|
||||
---
|
||||
|
||||
**下一步行动**:
|
||||
1. 实施优先级1(建立CDR + DTO位置映射)
|
||||
2. 验证效果
|
||||
3. 继续优先级2、3、4
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
/**
|
||||
* 中央数据仓库 (Central Data Repository, CDR)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 统一管理所有扫描和生成过程中的元数据
|
||||
* 2. 确保各Generator之间数据一致性
|
||||
* 3. 提供查询接口,避免重复扫描和计算
|
||||
*
|
||||
* 核心数据:
|
||||
* - Service方法签名索引
|
||||
* - DTO/VO/Param位置映射
|
||||
* - Entity位置映射
|
||||
* - Service依赖关系图
|
||||
* - Controller-Service调用关系
|
||||
*/
|
||||
class CentralDataRepository {
|
||||
constructor() {
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【核心索引】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
/**
|
||||
* 1. Service方法签名索引
|
||||
* 格式: Map<string, Signature>
|
||||
* 键: "ServiceImplName.methodName"
|
||||
* 值: { parameters: [{name, type, javaType}], returnType: string }
|
||||
*
|
||||
* 示例:
|
||||
* "MemberServiceImpl.list" => {
|
||||
* parameters: [
|
||||
* {name: "pageParam", type: "PageParam", javaType: "PageParam"},
|
||||
* {name: "searchParam", type: "MemberSearchParam", javaType: "MemberSearchParam"}
|
||||
* ],
|
||||
* returnType: "PageResult<MemberListVo>"
|
||||
* }
|
||||
*/
|
||||
this.serviceMethodSignatureIndex = new Map();
|
||||
|
||||
/**
|
||||
* 2. DTO位置映射
|
||||
* 格式: Map<string, LocationInfo>
|
||||
* 键: DTO类名(如 "MemberInfoDto")
|
||||
* 值: {
|
||||
* relativePath: string, // 相对路径,如 "dtos/core/member/dto/member-info.dto"
|
||||
* absolutePath: string, // 绝对路径
|
||||
* category: string, // 类别:dto/vo/param
|
||||
* module: string // 所属模块
|
||||
* }
|
||||
*
|
||||
* 示例:
|
||||
* "MemberInfoDto" => {
|
||||
* relativePath: "dtos/core/member/dto/member-info.dto",
|
||||
* absolutePath: "/full/path/to/dtos/core/member/dto/member-info.dto.ts",
|
||||
* category: "dto",
|
||||
* module: "member"
|
||||
* }
|
||||
*/
|
||||
this.dtoLocationMap = new Map();
|
||||
|
||||
/**
|
||||
* 3. VO位置映射(同DTO)
|
||||
*/
|
||||
this.voLocationMap = new Map();
|
||||
|
||||
/**
|
||||
* 4. Param位置映射(同DTO)
|
||||
*/
|
||||
this.paramLocationMap = new Map();
|
||||
|
||||
/**
|
||||
* 5. Entity位置映射
|
||||
* 格式: Map<string, string>
|
||||
* 键: Entity类名(如 "Member")
|
||||
* 值: 相对路径(如 "entities/member.entity")
|
||||
*/
|
||||
this.entityLocationMap = new Map();
|
||||
|
||||
/**
|
||||
* 6. Service依赖关系图
|
||||
* 格式: Map<string, string[]>
|
||||
* 键: Service类名(如 "MemberServiceImpl")
|
||||
* 值: 依赖的Service列表
|
||||
*/
|
||||
this.serviceDependencyMap = new Map();
|
||||
|
||||
/**
|
||||
* 7. Controller-Service调用关系
|
||||
* 格式: Map<string, CallInfo>
|
||||
* 键: "ControllerName.methodName"
|
||||
* 值: { service: string, method: string, parameters: [...] }
|
||||
*/
|
||||
this.controllerServiceCallMap = new Map();
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【辅助索引】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
/**
|
||||
* 8. 所有DTO/VO/Param名称反向索引
|
||||
* 快速查找:给定类名,查找其位置
|
||||
*/
|
||||
this.typeLocationIndex = new Map();
|
||||
|
||||
/**
|
||||
* 9. 模块目录映射
|
||||
* 格式: Map<string, string>
|
||||
* 键: 模块名(如 "member")
|
||||
* 值: 模块根目录(如 "core/member")
|
||||
*/
|
||||
this.moduleDirectoryMap = new Map();
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【统计信息】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
this.stats = {
|
||||
serviceMethods: 0,
|
||||
dtos: 0,
|
||||
vos: 0,
|
||||
params: 0,
|
||||
entities: 0,
|
||||
services: 0,
|
||||
controllers: 0
|
||||
};
|
||||
}
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Service方法签名】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
/**
|
||||
* 设置Service方法签名
|
||||
*/
|
||||
setServiceSignature(serviceClassName, methodName, signature) {
|
||||
const key = `${serviceClassName}.${methodName}`;
|
||||
this.serviceMethodSignatureIndex.set(key, signature);
|
||||
this.stats.serviceMethods++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Service方法签名
|
||||
*/
|
||||
getServiceSignature(serviceClassName, methodName) {
|
||||
const key = `${serviceClassName}.${methodName}`;
|
||||
return this.serviceMethodSignatureIndex.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置Service签名(从Scanner结果)
|
||||
*/
|
||||
batchSetServiceSignatures(services) {
|
||||
services.forEach(service => {
|
||||
const className = service.className;
|
||||
if (service.methods && service.methods.length > 0) {
|
||||
service.methods.forEach(method => {
|
||||
this.setServiceSignature(className, method.methodName, {
|
||||
parameters: method.parameters || [],
|
||||
returnType: method.returnType || 'void',
|
||||
javaReturnType: method.javaReturnType || method.returnType
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
console.log(`✅ CDR: 已索引 ${this.serviceMethodSignatureIndex.size} 个Service方法签名`);
|
||||
}
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【DTO/VO/Param位置映射】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
/**
|
||||
* 设置类型位置(通用方法)
|
||||
*/
|
||||
setTypeLocation(typeName, locationInfo) {
|
||||
const { category } = locationInfo;
|
||||
|
||||
// 根据类别存储到不同的Map
|
||||
if (category === 'dto') {
|
||||
this.dtoLocationMap.set(typeName, locationInfo);
|
||||
this.stats.dtos++;
|
||||
} else if (category === 'vo') {
|
||||
this.voLocationMap.set(typeName, locationInfo);
|
||||
this.stats.vos++;
|
||||
} else if (category === 'param') {
|
||||
this.paramLocationMap.set(typeName, locationInfo);
|
||||
this.stats.params++;
|
||||
}
|
||||
|
||||
// 同时存入统一索引
|
||||
this.typeLocationIndex.set(typeName, locationInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型位置(智能查找:DTO/VO/Param)
|
||||
*/
|
||||
getTypeLocation(typeName) {
|
||||
// 优先从统一索引查找
|
||||
if (this.typeLocationIndex.has(typeName)) {
|
||||
return this.typeLocationIndex.get(typeName);
|
||||
}
|
||||
|
||||
// 兜底:分别查找
|
||||
return this.dtoLocationMap.get(typeName)
|
||||
|| this.voLocationMap.get(typeName)
|
||||
|| this.paramLocationMap.get(typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置DTO/VO位置(从DTO Generator)
|
||||
*/
|
||||
batchSetTypeLocations(typeLocations) {
|
||||
typeLocations.forEach(location => {
|
||||
this.setTypeLocation(location.typeName, {
|
||||
relativePath: location.relativePath,
|
||||
absolutePath: location.absolutePath,
|
||||
category: location.category,
|
||||
module: location.module
|
||||
});
|
||||
});
|
||||
console.log(`✅ CDR: 已索引 ${this.typeLocationIndex.size} 个类型位置 (DTO: ${this.stats.dtos}, VO: ${this.stats.vos}, Param: ${this.stats.params})`);
|
||||
}
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Entity位置映射】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
setEntityLocation(entityName, relativePath) {
|
||||
this.entityLocationMap.set(entityName, relativePath);
|
||||
this.stats.entities++;
|
||||
}
|
||||
|
||||
getEntityLocation(entityName) {
|
||||
return this.entityLocationMap.get(entityName);
|
||||
}
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Service依赖关系】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
setServiceDependencies(serviceName, dependencies) {
|
||||
this.serviceDependencyMap.set(serviceName, dependencies);
|
||||
this.stats.services++;
|
||||
}
|
||||
|
||||
getServiceDependencies(serviceName) {
|
||||
return this.serviceDependencyMap.get(serviceName) || [];
|
||||
}
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Controller-Service调用关系】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
setControllerServiceCall(controllerName, methodName, callInfo) {
|
||||
const key = `${controllerName}.${methodName}`;
|
||||
this.controllerServiceCallMap.set(key, callInfo);
|
||||
}
|
||||
|
||||
getControllerServiceCall(controllerName, methodName) {
|
||||
const key = `${controllerName}.${methodName}`;
|
||||
return this.controllerServiceCallMap.get(key);
|
||||
}
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【模块目录映射】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
setModuleDirectory(moduleName, directory) {
|
||||
this.moduleDirectoryMap.set(moduleName, directory);
|
||||
}
|
||||
|
||||
getModuleDirectory(moduleName) {
|
||||
return this.moduleDirectoryMap.get(moduleName);
|
||||
}
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【辅助方法】
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
/**
|
||||
* 根据类型名推断导入路径(智能推断)
|
||||
* @param {string} typeName - 类型名,如 "MemberInfoDto", "MemberListVo"
|
||||
* @param {string} fromPath - 当前文件路径,如 "services/admin/member/impl"
|
||||
* @returns {string|null} - 相对导入路径,如 "../../../../dtos/core/member/dto/member-info.dto"
|
||||
*/
|
||||
inferImportPath(typeName, fromPath) {
|
||||
const location = this.getTypeLocation(typeName);
|
||||
if (!location) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 计算相对路径
|
||||
const from = fromPath.split('/').filter(p => p);
|
||||
const to = location.relativePath.split('/').filter(p => p);
|
||||
|
||||
// 找到公共前缀
|
||||
let commonLength = 0;
|
||||
for (let i = 0; i < Math.min(from.length, to.length); i++) {
|
||||
if (from[i] === to[i]) {
|
||||
commonLength++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 构建相对路径
|
||||
const upLevels = from.length - commonLength;
|
||||
const downPath = to.slice(commonLength);
|
||||
|
||||
const relativePath = '../'.repeat(upLevels) + downPath.join('/');
|
||||
|
||||
// 移除 .ts 后缀
|
||||
return relativePath.replace('.ts', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量推断导入路径
|
||||
* @param {string[]} typeNames - 类型名列表
|
||||
* @param {string} fromPath - 当前文件路径
|
||||
* @returns {Map<string, string>} - 类型名到导入路径的映射
|
||||
*/
|
||||
batchInferImportPaths(typeNames, fromPath) {
|
||||
const importMap = new Map();
|
||||
|
||||
typeNames.forEach(typeName => {
|
||||
const importPath = this.inferImportPath(typeName, fromPath);
|
||||
if (importPath) {
|
||||
importMap.set(typeName, importPath);
|
||||
}
|
||||
});
|
||||
|
||||
return importMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
*/
|
||||
getStats() {
|
||||
return {
|
||||
...this.stats,
|
||||
totalTypes: this.typeLocationIndex.size,
|
||||
totalServiceMethods: this.serviceMethodSignatureIndex.size
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印统计信息
|
||||
*/
|
||||
printStats() {
|
||||
const stats = this.getStats();
|
||||
console.log('\n📊 中央数据仓库 (CDR) 统计信息:');
|
||||
console.log(` Service方法: ${stats.totalServiceMethods} 个`);
|
||||
console.log(` DTO: ${stats.dtos} 个`);
|
||||
console.log(` VO: ${stats.vos} 个`);
|
||||
console.log(` Param: ${stats.params} 个`);
|
||||
console.log(` Entity: ${stats.entities} 个`);
|
||||
console.log(` 总类型: ${stats.totalTypes} 个`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据完整性
|
||||
*/
|
||||
validate() {
|
||||
const issues = [];
|
||||
|
||||
// 验证1: Controller调用的Service方法是否都存在
|
||||
this.controllerServiceCallMap.forEach((call, controllerMethod) => {
|
||||
const serviceKey = `${call.service}.${call.method}`;
|
||||
if (!this.serviceMethodSignatureIndex.has(serviceKey)) {
|
||||
issues.push(`❌ Controller ${controllerMethod} 调用的 ${serviceKey} 在索引中不存在`);
|
||||
}
|
||||
});
|
||||
|
||||
// 验证2: Service方法使用的DTO/VO是否都有位置映射
|
||||
// (这个需要在使用时检查,这里先跳过)
|
||||
|
||||
if (issues.length > 0) {
|
||||
console.warn('\n⚠️ CDR数据完整性验证发现问题:');
|
||||
issues.forEach(issue => console.warn(` ${issue}`));
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('✅ CDR数据完整性验证通过');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CentralDataRepository;
|
||||
|
||||
@@ -7,7 +7,10 @@ const NamingUtils = require('../utils/naming-utils');
|
||||
* 将Java控制器转换为NestJS控制器
|
||||
*/
|
||||
class ControllerGenerator {
|
||||
setCDR(cdr) { this.cdr = cdr; }
|
||||
|
||||
constructor(outputDir) {
|
||||
this.cdr = null;
|
||||
this.namingUtils = new NamingUtils();
|
||||
this.outputDir = outputDir || '';
|
||||
// ✅ 中央Service方法签名索引
|
||||
|
||||
@@ -7,7 +7,10 @@ const NamingUtils = require('../utils/naming-utils');
|
||||
* 将Java DTO转换为NestJS DTO
|
||||
*/
|
||||
class DtoGenerator {
|
||||
setCDR(cdr) { this.cdr = cdr; }
|
||||
|
||||
constructor() {
|
||||
this.cdr = null;
|
||||
this.namingUtils = new NamingUtils();
|
||||
}
|
||||
|
||||
@@ -33,7 +36,16 @@ class DtoGenerator {
|
||||
fs.writeFileSync(filePath, content);
|
||||
|
||||
console.log(`✅ 生成DTO: ${subPath}/${fileName}`);
|
||||
return { fileName, content, subPath };
|
||||
|
||||
// ✅ V2: 返回完整信息供CDR记录
|
||||
return {
|
||||
fileName,
|
||||
content,
|
||||
subPath,
|
||||
dtoName,
|
||||
relativePath: subPath ? `dtos/${subPath}/${fileName}` : `dtos/${fileName}`,
|
||||
absolutePath: filePath
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,10 @@ const NamingUtils = require('../utils/naming-utils');
|
||||
* 将Java实体转换为NestJS实体
|
||||
*/
|
||||
class EntityGenerator {
|
||||
setCDR(cdr) { this.cdr = cdr; }
|
||||
|
||||
constructor() {
|
||||
this.cdr = null;
|
||||
this.namingUtils = new NamingUtils();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ const NamingUtils = require('../utils/naming-utils');
|
||||
* 将Java枚举转换为NestJS枚举
|
||||
*/
|
||||
class EnumGenerator {
|
||||
setCDR(cdr) { this.cdr = cdr; }
|
||||
|
||||
constructor() {
|
||||
this.cdr = null;
|
||||
this.namingUtils = new NamingUtils();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ class ModuleGenerator {
|
||||
this.listenerGenerator = new ListenerGenerator();
|
||||
this.jobGenerator = new JobGenerator();
|
||||
this.outputDir = '';
|
||||
// ✅ 中央Service方法签名索引
|
||||
// ✅ V2: 中央数据仓库
|
||||
this.cdr = null;
|
||||
// ⚠️ 向后兼容:保留旧的索引引用
|
||||
this.serviceMethodSignatureIndex = null;
|
||||
}
|
||||
|
||||
@@ -41,7 +43,20 @@ class ModuleGenerator {
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ 设置中央Service方法签名索引
|
||||
* ✅ V2: 设置中央数据仓库
|
||||
*/
|
||||
setCDR(cdr) {
|
||||
this.cdr = cdr;
|
||||
// ✅ V2: 传递CDR给所有Generator
|
||||
this.controllerGenerator.setCDR(cdr);
|
||||
this.serviceGenerator.setCDR(cdr);
|
||||
this.dtoGenerator.setCDR(cdr);
|
||||
this.entityGenerator.setCDR(cdr);
|
||||
this.enumGenerator.setCDR(cdr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ 设置中央Service方法签名索引(向后兼容)
|
||||
*/
|
||||
setServiceMethodSignatureIndex(index) {
|
||||
this.serviceMethodSignatureIndex = index;
|
||||
@@ -447,8 +462,22 @@ export class ControllerModule {
|
||||
|
||||
dtoComponents.forEach(dtoComponent => {
|
||||
try {
|
||||
this.dtoGenerator.generateDto(dtoComponent.javaClass, dtoDir);
|
||||
const result = this.dtoGenerator.generateDto(dtoComponent.javaClass, dtoDir);
|
||||
dtoCount++;
|
||||
|
||||
// ✅ V2: 记录DTO位置到CDR
|
||||
if (this.cdr && result) {
|
||||
const dtoName = result.dtoName || this.namingUtils.generateDtoName(dtoComponent.javaClass.className);
|
||||
const relativePath = result.relativePath || `dtos/${result.fileName}`;
|
||||
const category = this.inferDtoCategory(dtoComponent.javaClass.className);
|
||||
|
||||
this.cdr.setTypeLocation(dtoName, {
|
||||
relativePath,
|
||||
absolutePath: result.absolutePath || path.join(dtoDir, result.fileName),
|
||||
category,
|
||||
module: dtoComponent.javaClass.module || 'common'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ 生成 DTO 失败 [${dtoComponent.name}]: ${error.message}`);
|
||||
}
|
||||
@@ -457,6 +486,18 @@ export class ControllerModule {
|
||||
console.log(`✅ 生成 DTO 文件: ${dtoCount} 个`);
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ V2: 推断DTO类别(dto/vo/param)
|
||||
*/
|
||||
inferDtoCategory(className) {
|
||||
const lowerName = className.toLowerCase();
|
||||
if (lowerName.endsWith('vo')) return 'vo';
|
||||
if (lowerName.endsWith('param')) return 'param';
|
||||
if (lowerName.endsWith('dto')) return 'dto';
|
||||
// 默认为dto
|
||||
return 'dto';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成枚举文件
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,10 @@ const ServiceMethodConverter = require('../converters/service-method-converter')
|
||||
* 将Java服务转换为NestJS服务
|
||||
*/
|
||||
class ServiceGenerator {
|
||||
setCDR(cdr) { this.cdr = cdr; }
|
||||
|
||||
constructor(outputDir = null) {
|
||||
this.cdr = null;
|
||||
this.namingUtils = new NamingUtils();
|
||||
this.methodConverter = new ServiceMethodConverter();
|
||||
this.outputDir = outputDir;
|
||||
@@ -399,7 +402,7 @@ ${methods}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加DTO导入
|
||||
// ✅ V2: 添加DTO导入(使用CDR查询路径)
|
||||
if (javaService.dtos && javaService.dtos.length > 0) {
|
||||
javaService.dtos.forEach(dto => {
|
||||
// 清理泛型语法:List<String> → List, Record<String, Vo> → Record
|
||||
@@ -411,8 +414,22 @@ ${methods}
|
||||
}
|
||||
|
||||
const dtoName = this.namingUtils.generateDtoName(cleanDto);
|
||||
const dtoFileName = this.namingUtils.generateFileName(cleanDto, 'dto');
|
||||
imports.push(`import { ${dtoName} } from '../dtos/${dtoFileName.replace('.ts', '')}';`);
|
||||
|
||||
// ✅ V2: 使用CDR查询DTO路径(如果可用)
|
||||
let importPath = null;
|
||||
if (this.cdr) {
|
||||
// 从当前Service文件路径推断相对路径
|
||||
const currentPath = javaService.filePath || 'services/admin';
|
||||
importPath = this.cdr.inferImportPath(dtoName, currentPath);
|
||||
}
|
||||
|
||||
// ⚠️ 兜底:如果CDR未找到,使用旧的硬编码路径
|
||||
if (!importPath) {
|
||||
const dtoFileName = this.namingUtils.generateFileName(cleanDto, 'dto');
|
||||
importPath = `../dtos/${dtoFileName.replace('.ts', '')}`;
|
||||
}
|
||||
|
||||
imports.push(`import { ${dtoName} } from '${importPath}';`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,13 @@ 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() {
|
||||
@@ -18,9 +21,11 @@ class JavaToNestJSMigrationCoordinator {
|
||||
this.mapper = new LayerMapper();
|
||||
this.moduleGenerator = new ModuleGenerator();
|
||||
|
||||
// ✅ 中央数据仓库:Service方法签名索引
|
||||
// 格式:{ 'ServiceImplName.methodName': { parameters: [...], returnType: '...' } }
|
||||
this.serviceMethodSignatureIndex = new Map();
|
||||
// ✅ V2: 中央数据仓库(替代原来的单一索引)
|
||||
this.cdr = new CentralDataRepository();
|
||||
|
||||
// ⚠️ 向后兼容:保留旧的索引引用(指向CDR)
|
||||
this.serviceMethodSignatureIndex = this.cdr.serviceMethodSignatureIndex;
|
||||
|
||||
this.stats = {
|
||||
startTime: null,
|
||||
@@ -59,6 +64,22 @@ class JavaToNestJSMigrationCoordinator {
|
||||
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);
|
||||
@@ -93,7 +114,7 @@ class JavaToNestJSMigrationCoordinator {
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ 构建Service方法签名索引
|
||||
* ✅ V2: 构建Service方法签名索引(使用CDR)
|
||||
* 从Java扫描结果中提取所有Service方法的参数和返回类型
|
||||
*/
|
||||
buildServiceMethodSignatureIndex(services) {
|
||||
@@ -104,15 +125,23 @@ class JavaToNestJSMigrationCoordinator {
|
||||
// 提取所有方法
|
||||
const methods = this.scanner.extractMethods(content);
|
||||
|
||||
// ✅ V2: 使用CDR存储方法签名
|
||||
methods.forEach(method => {
|
||||
const key = `${className}.${method.methodName}`;
|
||||
this.serviceMethodSignatureIndex.set(key, {
|
||||
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方法签名`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,12 +312,16 @@ class JavaToNestJSMigrationCoordinator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成NestJS模块
|
||||
* ✅ V2: 生成NestJS模块(传递CDR)
|
||||
*/
|
||||
async generateModules(nestJSModules) {
|
||||
// ✅ 传递中央索引给ModuleGenerator
|
||||
// ✅ 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;
|
||||
|
||||
Reference in New Issue
Block a user