feat: 增强Service层转换器
✅ DTO导入增强: - 清理泛型语法: List<String> → List - 跳过Java基础类型(List/Map/String等) - 防止异常import语句 ✅ VO类型自动识别: - 从方法体中提取VO类型 - 正则匹配所有XxxVo/Dto/Param引用 - 自动添加到导入列表 ✅ Java API转换器(新增): - path.toFile() → path - file.path → file - Files.* → fs.* - Paths.get() → path.join() - Charset/Encoding处理 📊 效果: 14086 errors (持平) 🔧 原因: 这些是结构性/业务逻辑错误,需要手动介入
This commit is contained in:
@@ -21,6 +21,7 @@ const StringConverter = require('./utils/string.converter');
|
||||
const CollectionConverter = require('./utils/collection.converter');
|
||||
const JsonConverter = require('./utils/json.converter');
|
||||
const ObjectConverter = require('./utils/object.converter');
|
||||
const JavaApiConverter = require('./utils/java-api.converter');
|
||||
|
||||
const QueryWrapperConverter = require('./mybatis/query-wrapper.converter');
|
||||
const MapperConverter = require('./mybatis/mapper.converter');
|
||||
@@ -45,6 +46,7 @@ class ServiceMethodConverter {
|
||||
this.collection = new CollectionConverter();
|
||||
this.json = new JsonConverter();
|
||||
this.object = new ObjectConverter();
|
||||
this.javaApi = new JavaApiConverter();
|
||||
|
||||
this.queryWrapper = new QueryWrapperConverter();
|
||||
this.mapper = new MapperConverter();
|
||||
@@ -90,6 +92,7 @@ class ServiceMethodConverter {
|
||||
tsBody = this.collection.convert(tsBody);
|
||||
tsBody = this.json.convert(tsBody);
|
||||
tsBody = this.object.convert(tsBody);
|
||||
tsBody = this.javaApi.convert(tsBody);
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【阶段4】MyBatis → TypeORM转换
|
||||
@@ -173,6 +176,15 @@ class ServiceMethodConverter {
|
||||
const configImports = this.config.analyzeImports(convertedBody);
|
||||
configImports.forEach(imp => imports.boot.add(imp));
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Java API转换】fs/path (Node.js模块)
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
const javaApiImports = this.javaApi.analyzeImports(convertedBody);
|
||||
javaApiImports.forEach(imp => {
|
||||
if (imp === 'node:fs') imports.nodeModules.add('fs');
|
||||
if (imp === 'node:path') imports.nodeModules.add('path');
|
||||
});
|
||||
|
||||
return {
|
||||
nestjs: Array.from(imports.nestjs),
|
||||
boot: Array.from(imports.boot),
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Java API转换器
|
||||
*
|
||||
* Java特有API → Node.js/TypeScript API
|
||||
*
|
||||
* - path.toFile() → path (Path对象在Node.js中就是string)
|
||||
* - file.path → file (File对象在Node.js中就是path string)
|
||||
* - Files.readString(path) → fs.readFileSync(path, 'utf-8')
|
||||
* - Files.write(path, content) → fs.writeFileSync(path, content)
|
||||
*/
|
||||
class JavaApiConverter {
|
||||
/**
|
||||
* 转换Java API
|
||||
*/
|
||||
convert(javaCode) {
|
||||
let tsCode = javaCode;
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【File/Path API】→ Node.js string paths
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
// path.toFile() → path (在Node.js中path就是string)
|
||||
tsCode = tsCode.replace(/(\w+)\.toFile\(\)/g, '$1');
|
||||
|
||||
// file.path → file (在Node.js中file就是path string)
|
||||
tsCode = tsCode.replace(/(\w+)\.path\b/g, '$1');
|
||||
|
||||
// Paths.get(...) → path.join(...)
|
||||
tsCode = tsCode.replace(/Paths\.get\(/g, 'path.join(');
|
||||
|
||||
// File.separator → path.sep
|
||||
tsCode = tsCode.replace(/File\.separator/g, 'path.sep');
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Files API】→ fs module
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
// Files.readString(path) → fs.readFileSync(path, 'utf-8')
|
||||
tsCode = tsCode.replace(/Files\.readString\(([^)]+)\)/g, "fs.readFileSync($1, 'utf-8')");
|
||||
|
||||
// Files.readAllBytes(path) → fs.readFileSync(path)
|
||||
tsCode = tsCode.replace(/Files\.readAllBytes\(([^)]+)\)/g, 'fs.readFileSync($1)');
|
||||
|
||||
// Files.write(path, content) → fs.writeFileSync(path, content)
|
||||
tsCode = tsCode.replace(/Files\.write\(([^,]+),\s*([^)]+)\)/g, 'fs.writeFileSync($1, $2)');
|
||||
|
||||
// Files.exists(path) → fs.existsSync(path)
|
||||
tsCode = tsCode.replace(/Files\.exists\(([^)]+)\)/g, 'fs.existsSync($1)');
|
||||
|
||||
// Files.createDirectories(path) → fs.mkdirSync(path, { recursive: true })
|
||||
tsCode = tsCode.replace(/Files\.createDirectories\(([^)]+)\)/g, 'fs.mkdirSync($1, { recursive: true })');
|
||||
|
||||
// Files.delete(path) → fs.unlinkSync(path)
|
||||
tsCode = tsCode.replace(/Files\.delete\(([^)]+)\)/g, 'fs.unlinkSync($1)');
|
||||
|
||||
// Files.list(path) → fs.readdirSync(path)
|
||||
tsCode = tsCode.replace(/Files\.list\(([^)]+)\)/g, 'fs.readdirSync($1)');
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Stream/Optional API】→ TypeScript
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
// .orElse(null) → || null
|
||||
tsCode = tsCode.replace(/\.orElse\(null\)/g, ' || null');
|
||||
|
||||
// .orElse(defaultValue) → || defaultValue
|
||||
tsCode = tsCode.replace(/\.orElse\(([^)]+)\)/g, ' || $1');
|
||||
|
||||
// .isPresent() → (删除,TypeScript直接判断truthy)
|
||||
// 注意:这个需要上下文判断,暂时保留
|
||||
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
// 【Charset/Encoding】→ 字符串编码
|
||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
// Charset.forName("UTF-8") → 'utf-8'
|
||||
tsCode = tsCode.replace(/Charset\.forName\("UTF-8"\)/g, "'utf-8'");
|
||||
tsCode = tsCode.replace(/Charset\.forName\('UTF-8'\)/g, "'utf-8'");
|
||||
|
||||
// System.getProperty("sun.jnu.encoding") → 'utf-8' (默认UTF-8)
|
||||
tsCode = tsCode.replace(/System\.getProperty\("sun\.jnu\.encoding"\)/g, "'utf-8'");
|
||||
|
||||
// StandardCharsets.UTF_8 → 'utf-8'
|
||||
tsCode = tsCode.replace(/StandardCharsets\.UTF_8/g, "'utf-8'");
|
||||
|
||||
return tsCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析需要的imports
|
||||
*/
|
||||
analyzeImports(tsCode) {
|
||||
const imports = new Set();
|
||||
|
||||
// 检查是否使用了fs
|
||||
if (tsCode.includes('fs.readFileSync') || tsCode.includes('fs.writeFileSync') ||
|
||||
tsCode.includes('fs.existsSync') || tsCode.includes('fs.mkdirSync') ||
|
||||
tsCode.includes('fs.unlinkSync') || tsCode.includes('fs.readdirSync') ||
|
||||
tsCode.includes('fs.statSync')) {
|
||||
imports.add('node:fs');
|
||||
}
|
||||
|
||||
// 检查是否使用了path
|
||||
if (tsCode.includes('path.join') || tsCode.includes('path.sep') ||
|
||||
tsCode.includes('path.dirname') || tsCode.includes('path.basename')) {
|
||||
imports.add('node:path');
|
||||
}
|
||||
|
||||
return Array.from(imports);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = JavaApiConverter;
|
||||
|
||||
@@ -177,7 +177,7 @@ ${methods}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从方法参数中提取DTO/VO类型
|
||||
* 从方法参数和方法体中提取DTO/VO类型
|
||||
*
|
||||
* @param {object} javaService - Java服务对象
|
||||
* @returns {string[]} DTO/VO类型列表
|
||||
@@ -190,10 +190,8 @@ ${methods}
|
||||
}
|
||||
|
||||
javaService.methods.forEach(method => {
|
||||
if (!method.parameters) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 从参数中提取
|
||||
if (method.parameters) {
|
||||
method.parameters.forEach(param => {
|
||||
const paramType = param.type;
|
||||
if (!paramType) {
|
||||
@@ -211,6 +209,21 @@ ${methods}
|
||||
dtos.add(simpleType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 从方法体中提取VO类型(通过正则匹配)
|
||||
if (method.methodBody) {
|
||||
// 匹配 new XxxVo(), XxxVo xxx = ..., List<XxxVo>, etc.
|
||||
const voMatches = method.methodBody.match(/\b([A-Z]\w*(Vo|Dto|Param))\b/g);
|
||||
if (voMatches) {
|
||||
voMatches.forEach(vo => {
|
||||
// 排除Java基本类型
|
||||
if (!['String', 'Integer', 'Long', 'Double', 'Float', 'Boolean', 'List', 'Map', 'Set'].includes(vo)) {
|
||||
dtos.add(vo);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(dtos);
|
||||
@@ -389,8 +402,16 @@ ${methods}
|
||||
// 添加DTO导入
|
||||
if (javaService.dtos && javaService.dtos.length > 0) {
|
||||
javaService.dtos.forEach(dto => {
|
||||
const dtoName = this.namingUtils.generateDtoName(dto);
|
||||
const dtoFileName = this.namingUtils.generateFileName(dto, 'dto');
|
||||
// 清理泛型语法:List<String> → List, Record<String, Vo> → Record
|
||||
let cleanDto = dto.replace(/<[^>]+>/g, '');
|
||||
|
||||
// 跳过Java基础类型和集合类型(不是DTO)
|
||||
if (['List', 'ArrayList', 'Map', 'HashMap', 'Set', 'HashSet', 'Record', 'String', 'Integer', 'Long', 'Boolean'].includes(cleanDto)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dtoName = this.namingUtils.generateDtoName(cleanDto);
|
||||
const dtoFileName = this.namingUtils.generateFileName(cleanDto, 'dto');
|
||||
imports.push(`import { ${dtoName} } from '../dtos/${dtoFileName.replace('.ts', '')}';`);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user