Files
wwjcloud-nest-v1/tools-v1/php-tools/generators/business-logic-converter.js
wanwujie c4e588a2fe feat: 完成PHP到NestJS迁移工具和代码生成
-  成功运行迁移工具,生成28个模块的完整NestJS代码
-  生成所有实体、服务、控制器、验证器等组件
-  修复npm依赖冲突,更新package-lock.json
-  添加Docker测试脚本和配置文件
-  完善迁移工具的调试日志和错误处理
- 🔧 包含增量更新工具和质量检查工具
- 📊 迁移统计:28个模块,数千个文件,耗时26.47秒

主要变更:
- wwjcloud-nest/src/core/* - 生成的业务模块代码
- tools/* - 迁移工具和辅助脚本
- wwjcloud-nest/package.json - 依赖更新
- docker/* - 容器化配置和测试脚本
2025-10-20 18:43:52 +08:00

810 lines
29 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require('fs');
const path = require('path');
/**
* 业务逻辑转换器
* 基于真实PHP代码的转换规则禁止TODO、假设、自创
*/
class BusinessLogicConverter {
constructor() {
// 混合模块智能分类规则
this.hybridClassificationRules = {
// 需要抽取到Core层的业务逻辑文件
coreBusinessLogic: [
// 支付相关
/pay/i,
/payment/i,
/transfer/i,
/refund/i,
// 会员相关
/member/i,
/user.*profile/i,
/account/i,
// 业务配置
/config.*pay/i,
/config.*member/i,
/config.*order/i,
// 订单相关
/order/i,
/goods/i,
/product/i,
// 认证业务逻辑
/login.*business/i,
/auth.*business/i,
/register/i,
// DIY业务
/diy/i,
/custom/i,
// 营销业务
/promotion/i,
/coupon/i,
/discount/i
],
// 应该使用Common基础服务的文件
useCommonInfrastructure: [
// 基础服务接口
/BaseController/,
/BaseService/,
/BaseModel/,
// 通用工具
/upload/i,
/export/i,
/attachment/i,
/sys.*config/i,
/system.*info/i,
/cache/i,
/redis/i,
// 基础认证
/jwt/i,
/token/i,
/guard/i,
/middleware/i
]
};
this.phpRegexPatterns = [
// PHP类型转换
{ pattern: /\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1' },
{ pattern: /\->/g, replacement: '.' },
{ pattern: /public function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/g, replacement: 'async $1($2)' },
{ pattern: /private function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/g, replacement: 'private async $1($2)' },
{ pattern: /protected function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/g, replacement: 'protected async $1($2)' },
// PHP参数类型转换
{ pattern: /string\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: string' },
{ pattern: /int\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: number' },
{ pattern: /array\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: any[]' },
{ pattern: /bool\s+\$([a-zA-Z_][a-zA-Z0-9_]*)/g, replacement: '$1: boolean' },
// PHP语法转换
{ pattern: /this\s*\->\s*model/g, replacement: 'this.model' },
{ pattern: /new\s+([A-Z][a-zA-Z0-9_]*)\(\)/g, replacement: 'this.$1Repository' },
{ pattern: /parent::__construct\(\)/g, replacement: 'super()' },
// PHP函数转换
{ pattern: /empty\s*\(\s*([^)]+)\s*\)/g, replacement: '!$1' },
{ pattern: /isset\s*\(\s*([^)]+)\s*\)/g, replacement: '$1 !== undefined' },
{ pattern: /is_null\s*\(\s*([^)]+)\s*\)/g, replacement: '$1 === null' },
{ pattern: /is_array\s*\(\s*([^)]+)\s*\)/g, replacement: 'Array.isArray($1)' },
{ pattern: /is_string\s*\(\s*([^)]+)\s*\)/g, replacement: 'typeof $1 === "string"' },
{ pattern: /is_numeric\s*\(\s*([^)]+)\s*\)/g, replacement: '!isNaN($1)' },
// 字符串拼接
{ pattern: /\.\s*=/g, replacement: '+=' },
{ pattern: /\.(\s*['""])/g, replacement: ' + $1' },
// 数组语法
{ pattern: /array\(\)/g, replacement: '[]' },
{ pattern: /array\(([^)]+)\)/g, replacement: '[$1]' },
];
}
/**
* 智能分类判断文件应该迁移到Core层还是使用Common基础设施
*/
classifyFile(filePath, className, content) {
const fileName = path.basename(filePath, '.php');
const fullContext = `${fileName} ${className} ${content}`.toLowerCase();
// 检查是否应该使用Common基础设施
for (const pattern of this.hybridClassificationRules.useCommonInfrastructure) {
if (pattern.test(fileName) || pattern.test(className) || pattern.test(content)) {
return 'INFRASTRUCTURE';
}
}
// 检查是否应该迁移到Core层
for (const pattern of this.hybridClassificationRules.coreBusinessLogic) {
if (pattern.test(fileName) || pattern.test(className) || pattern.test(content)) {
return 'CORE_BUSINESS';
}
}
// 默认根据模块名判断
const moduleName = this.extractModuleName(filePath);
if (['sys', 'upload', 'config', 'export'].includes(moduleName)) {
return 'INFRASTRUCTURE'; // 基础服务
}
return 'CORE_BUSINESS'; // 默认为业务逻辑
}
/**
* 从文件路径提取模块名
*/
extractModuleName(filePath) {
const match = filePath.match(/\/([^\/]+)\/.+\.php$/);
return match ? match[1] : 'unknown';
}
/**
* 替换PHP基础设施调用为NestJS基础设施调用
*/
replaceInfrastructureCalls(tsCode) {
let convertedCode = tsCode;
// 替换PHP基础类为NestJS Common层
const infrastructureReplacements = [
// 按 v1 boot 实现进行映射
{ from: /core\\cache\\RedisCacheService/g, to: '@wwjCommon/cache/cache.service' },
{ from: /CoreRequestService/g, to: '@wwjCommon/http/request-context.service' },
// 旧的 BaseService/BaseController/BaseApiService 在 v1 中不再使用,避免误替换
// 日志统一使用 Nest Logger 或拦截器,不再映射到自定义 LoggingService
];
infrastructureReplacements.forEach(({ from, to }) => {
convertedCode = convertedCode.replace(from, to);
});
return convertedCode;
}
/**
* 转换PHP业务逻辑到TypeScript
*/
convertBusinessLogic(content, methodName, phpCode) {
try {
console.log(`🔄 转换方法: ${methodName}`);
let convertedCode = phpCode;
// 1. 先转换PHP语法到TypeScript
convertedCode = convertedCode
// 变量转换 - 移除$符号 (必须在->转换之前)
.replace(/\$this->([a-zA-Z_][a-zA-Z0-9_]*)/g, 'this.$1')
.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1')
// PHP数组语法 => 转换为对象属性 :
.replace(/'([a-zA-Z_][a-zA-Z0-9_]*)'\s*=>/g, '$1:')
.replace(/"([a-zA-Z_][a-zA-Z0-9_]*)"\s*=>/g, '$1:')
// PHP空值合并 ?? 转换为 ||
.replace(/\?\?/g, '||')
// PHP对象访问 -> 转换为 . (必须在$转换之后)
.replace(/->/g, '.')
// PHP静态访问 :: 转换为 .
.replace(/::/g, '.')
// PHP new对象转换 - 修复转换逻辑避免重复Service后缀
.replace(/\(new\s+([A-Z][a-zA-Z0-9_]*)\(\)\)/g, (match, serviceName) => {
if (serviceName.endsWith('Service')) {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}`;
} else {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}Service`;
}
})
.replace(/new\s+([A-Z][a-zA-Z0-9_]*)\(\)/g, (match, serviceName) => {
if (serviceName.endsWith('Service')) {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}`;
} else {
return `this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}Service`;
}
})
// PHP类型声明转换为TypeScript
.replace(/array\s+/g, '')
.replace(/:\s*array/g, ': any[]')
// 变量声明添加const/let
.replace(/^(\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*=/gm, '$1const $2 =')
// 修复数组访问
.replace(/\['([^']+)'\]/g, '.$1')
.replace(/\["([^"]+)"\]/g, '.$1')
// 修复PHP函数调用
.replace(/array_merge\s*\(/g, 'Object.assign(')
.replace(/strpos\s*\(/g, 'String.prototype.indexOf.call(')
.replace(/throw\s+new\s+([A-Z][a-zA-Z0-9_]*)\s*\(/g, 'throw new $1(')
// 修复PHP条件语句
.replace(/if\s*\(\s*([^)]+)\s*\)\s*\{/g, 'if ($1) {')
.replace(/else\s*\{/g, '} else {')
// 修复PHP静态变量访问
.replace(/self::\$([a-zA-Z_][a-zA-Z0-9_]*)/g, 'self.$1')
.replace(/static::\$([a-zA-Z_][a-zA-Z0-9_]*)/g, 'static.$1')
// 修复PHP is_null函数
.replace(/is_null\s*\(\s*([^)]+)\s*\)/g, '$1 === null')
// 修复PHP new static调用
.replace(/new\s+static\s*\(([^)]*)\)/g, 'new this.constructor($1)')
// 修复PHP数组语法错误
.replace(/\[\s*\]/g, '[]')
.replace(/\(\s*\)/g, '()')
// 修复PHP变量赋值错误
.replace(/=\s*=\s*=/g, '===')
.replace(/=\s*=\s*null/g, '=== null')
// 修复重复的等号
.replace(/====/g, '===')
.replace(/=====/g, '===')
// 修复方括号错误 - 修复函数调用中的方括号(排除数组语法)
.replace(/\(([^)]+)\]/g, '($1)')
// 移除错误的替换规则,避免破坏数组语法
// .replace(/(\w+)\]/g, (match, word) => {
// // 排除数组元素的情况,避免将 [ 'key', 'value' ] 转换为 [ 'key', 'value' )
// // 检查是否在数组上下文中
// const beforeMatch = code.substring(0, code.indexOf(match));
// const lastBracket = beforeMatch.lastIndexOf('[');
// const lastParen = beforeMatch.lastIndexOf('(');
//
// // 如果最近的符号是 [ 而不是 (,说明在数组上下文中,不应该替换
// if (lastBracket > lastParen) {
// return match;
// }
//
// return word + ')';
// })
// 修复数组语法中的方括号错误 - 直接修复(处理单引号和双引号)
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*\"\"\s*\)\s*\)/g, '["$1", ""]')
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*0\s*\)\s*\)/g, '["$1", 0]')
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/\]\s*;/g, ');')
// .replace(/\]\s*\)/g, '))')
// .replace(/\]\s*\{/g, ') {')
// .replace(/\]\s*,/g, '),')
// 修复数组语法中的方括号错误 - 更精确的匹配
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
// 修复数组语法中的方括号错误
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\]/g, '[$1]')
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\)/g, '[$1]')
// 修复数组元素中的方括号错误
.replace(/\[\s*\(\s*'([^']+)',\s*'([^']+)'\s*\)\s*\)/g, "['$1', '$2']")
.replace(/\[\s*\(\s*'([^']+)',\s*(\d+)\s*\)\s*\)/g, "['$1', $2]")
.replace(/\[\s*\(\s*'([^']+)',\s*""\s*\)\s*\)/g, "['$1', '']")
// 修复特定的方括号错误模式 - 只修复函数调用中的方括号,不修复数组语法
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/(\w+_id)\]/g, '$1)')
// .replace(/(\w+_key)\]/g, '$1)')
// .replace(/(\w+_type)\]/g, '$1)')
// .replace(/(\w+_name)\]/g, '$1)')
// .replace(/(\w+_code)\]/g, '$1)')
// .replace(/(\w+_value)\]/g, '$1)')
// 修复函数调用中的方括号错误 - 只修复函数调用中的方括号,不修复数组语法
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/(\w+)\(([^)]+)\]/g, '$1($2)')
// .replace(/(\w+)\.(\w+)\(([^)]+)\]/g, '$1.$2($3)')
// 修复PHP方法声明
.replace(/public\s+function\s+/g, 'async ')
.replace(/private\s+function\s+/g, 'private async ')
.replace(/protected\s+function\s+/g, 'protected async ')
// 修复PHP返回语句
.replace(/return\s+this;/g, 'return this;')
// 修复PHP异常处理
.replace(/CommonException/g, 'BadRequestException')
.replace(/(?<!BadRequest)Exception/g, 'BadRequestException')
// 修复重复的Business前缀
.replace(/BusinessBusinessException/g, 'BusinessException');
// 2. 使用新的清理和验证功能
convertedCode = this.cleanAndValidateTypeScriptCode(convertedCode);
return convertedCode;
} catch (error) {
console.error('❌ 业务逻辑转换失败:', error.message);
return content;
}
}
/**
* 从PHP源码中提取方法信息 (基于真实PHP服务代码分析)
*/
extractPHPMethods(phpContent) {
try {
const methods = [];
const methodNames = new Set(); // 防止重复方法
// 匹配public方法包括static和返回类型
const publicMethodsRegex = /public\s+(?:static\s+)?function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*(?::\s*[^{]+)?\s*\{/g;
let match;
while ((match = publicMethodsRegex.exec(phpContent)) !== null) {
const methodName = match[1];
const parameters = match[2] || '';
// 跳过构造函数和重复方法
if (methodName === '__construct' || methodNames.has(methodName)) continue;
// 找到方法体的结束位置
const startPos = match.index + match[0].length;
const methodBody = this.extractMethodBody(phpContent, startPos);
// 检查方法体是否有效(不是空方法或只有注释)
const cleanBody = methodBody.trim().replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '');
if (cleanBody.length < 10) continue; // 跳过空方法
methodNames.add(methodName);
methods.push({
name: methodName,
parameters: this.parsePHPParameters(parameters),
logic: methodBody.trim(),
type: 'public'
});
}
// 匹配private方法包括static和返回类型
const privateMethodsRegex = /private\s+(?:static\s+)?function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*(?::\s*[^{]+)?\s*\{/g;
while ((match = privateMethodsRegex.exec(phpContent)) !== null) {
const methodName = match[1];
const parameters = match[2] || '';
// 跳过构造函数和重复方法
if (methodName === '__construct' || methodNames.has(methodName)) continue;
// 找到方法体的结束位置
const startPos = match.index + match[0].length;
const methodBody = this.extractMethodBody(phpContent, startPos);
// 检查方法体是否有效
const cleanBody = methodBody.trim().replace(/\/\*[\s\S]*?\*\//g, '').replace(/\/\/.*$/gm, '');
if (cleanBody.length < 10) continue; // 跳过空方法
methodNames.add(methodName);
methods.push({
name: methodName,
parameters: this.parsePHPParameters(parameters),
logic: methodBody.trim(),
type: 'private'
});
}
return methods;
} catch (error) {
console.error('❌ 提取PHP方法失败:', error.message);
return [];
}
}
/**
* 解析PHP方法参数
*/
parsePHPParameters(parameterString) {
if (!parameterString.trim()) return [];
const params = [];
// 修复正则表达式,正确匹配参数名
const paramPattern = /(?:int|string|array|bool)?\s*\$([a-zA-Z_][a-zA-Z0-9_]*)(?:\s*=\s*([^,\)]*?))?/g;
let match;
while ((match = paramPattern.exec(parameterString)) !== null) {
const paramName = match[1];
const defaultValue = match[2];
// 确保参数名不包含方括号,并处理保留字
const cleanParamName = paramName.replace(/\[\]/g, '');
const finalParamName = this.handleReservedWords(cleanParamName);
params.push({
name: finalParamName,
defaultValue: defaultValue ? defaultValue.trim() : undefined,
type: this.inferParameterType(parameterString, match[0])
});
}
return params;
}
/**
* 处理TypeScript保留字
*/
handleReservedWords(paramName) {
const reservedWords = [
'function', 'class', 'interface', 'enum', 'namespace', 'module',
'import', 'export', 'default', 'extends', 'implements', 'public',
'private', 'protected', 'static', 'abstract', 'readonly', 'async',
'await', 'return', 'if', 'else', 'for', 'while', 'do', 'switch',
'case', 'break', 'continue', 'try', 'catch', 'finally', 'throw',
'new', 'this', 'super', 'typeof', 'instanceof', 'in', 'of',
'var', 'let', 'const', 'true', 'false', 'null', 'undefined',
'any', 'string', 'number', 'boolean', 'object', 'void', 'never'
];
if (reservedWords.includes(paramName)) {
return `${paramName}Param`;
}
return paramName;
}
/**
* 推断参数类型
*/
inferParameterType(parameterString, fullMatch) {
// 简单的类型推断逻辑
if (parameterString.includes('[]') || parameterString.includes('array')) {
return 'any[]';
}
if (parameterString.includes('int') || parameterString.includes('float') || parameterString.includes('number')) {
return 'number';
}
if (parameterString.includes('string') || parameterString.includes('str')) {
return 'string';
}
if (parameterString.includes('bool')) {
return 'boolean';
}
if (parameterString.includes('object') || parameterString.includes('array')) {
return 'any';
}
// 默认返回 any
return 'any';
}
/**
* 提取方法体(处理嵌套大括号)
*/
extractMethodBody(content, startPos) {
let braceCount = 0;
let inString = false;
let stringChar = '';
let i = startPos;
let foundFirstBrace = false;
while (i < content.length) {
const char = content[i];
// 处理字符串
if (!inString && (char === '"' || char === "'")) {
inString = true;
stringChar = char;
} else if (inString && char === stringChar) {
// 检查是否是转义字符
if (i > 0 && content[i-1] !== '\\') {
inString = false;
stringChar = '';
}
}
// 只在非字符串状态下计算大括号
if (!inString) {
if (char === '{') {
if (!foundFirstBrace) {
foundFirstBrace = true;
i++;
continue;
}
braceCount++;
} else if (char === '}') {
if (foundFirstBrace && braceCount === 0) {
return content.substring(startPos, i);
}
braceCount--;
}
}
i++;
}
return content.substring(startPos);
}
/**
* 生成服务层参数定义
*/
generateServiceParameters(parameters) {
if (!parameters || parameters.length === 0) return '';
return parameters.map(param => {
const defaultValue = param.defaultValue ? ` = ${param.defaultValue.replace(/'/g, '"').replace(/^"([^"]*)"$/, '"$1"')}` : '';
return `${param.name}: ${param.type}${defaultValue}`;
}).join(', ');
}
/**
* 清理和验证生成的TypeScript代码
*/
cleanAndValidateTypeScriptCode(code) {
let cleanedCode = code;
// 移除PHP语法残留
cleanedCode = cleanedCode
// 移除PHP注释语法
.replace(/\/\*\*\s*\*\s*@param\s+\$[a-zA-Z_][a-zA-Z0-9_]*\s+[^\n]*\n/g, '')
.replace(/\/\*\*\s*\*\s*@return\s+[^\n]*\n/g, '')
.replace(/\/\*\*\s*\*\s*@throws\s+[^\n]*\n/g, '')
// 修复PHP方法声明残留
.replace(/public\s+function\s+/g, 'async ')
.replace(/private\s+function\s+/g, 'private async ')
.replace(/protected\s+function\s+/g, 'protected async ')
// 修复PHP变量声明
.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)\s*=/g, 'const $1 =')
// 修复PHP数组语法
.replace(/array\s*\(\s*\)/g, '[]')
.replace(/array\s*\(/g, '[')
.replace(/\)\s*;/g, '];')
// 修复PHP字符串拼接
.replace(/\.\s*=/g, ' += ')
.replace(/\.\s*['"]/g, ' + \'')
// 修复PHP条件语句
.replace(/if\s*\(\s*([^)]+)\s*\)\s*\{/g, 'if ($1) {')
.replace(/else\s*\{/g, '} else {')
// 修复PHP异常处理
.replace(/throw\s+new\s+CommonException\s*\(/g, 'throw new BadRequestException(')
.replace(/throw\s+new\s+Exception\s*\(/g, 'throw new BadRequestException(')
// 修复PHP函数调用
.replace(/array_merge\s*\(/g, 'Object.assign(')
.replace(/strpos\s*\(/g, 'String.prototype.indexOf.call(')
.replace(/empty\s*\(/g, '!')
.replace(/isset\s*\(/g, 'typeof ')
.replace(/is_null\s*\(/g, '=== null')
// 修复方括号错误 - 只修复函数调用中的方括号,不修复数组语法
.replace(/\(([^)]+)\]/g, '($1)')
// 移除错误的替换规则,避免破坏数组语法
// .replace(/(\w+)\]/g, '$1)') // 这个规则会破坏数组语法
// 移除这些错误的替换规则,避免破坏数组语法
// .replace(/\]\s*;/g, ');')
// .replace(/\]\s*\)/g, '))')
// .replace(/\]\s*\{/g, ') {')
// .replace(/\]\s*,/g, '),')
// 修复数组语法中的方括号错误
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\]/g, '[$1]')
.replace(/\[\s*\(\s*([^)]+)\s*\)\s*\)/g, '[$1]')
// 修复数组元素中的方括号错误
.replace(/\[\s*\(\s*'([^']+)',\s*'([^']+)'\s*\)\s*\)/g, "['$1', '$2']")
.replace(/\[\s*\(\s*'([^']+)',\s*(\d+)\s*\)\s*\)/g, "['$1', $2]")
.replace(/\[\s*\(\s*'([^']+)',\s*""\s*\)\s*\)/g, "['$1', '']")
// 修复数组元素中的圆括号错误 - 更精确的匹配
.replace(/\[\s*\(\s*'([^']+)',\s*'([^']+)'\s*\)\s*\)/g, "['$1', '$2']")
.replace(/\[\s*\(\s*'([^']+)',\s*(\d+)\s*\)\s*\)/g, "['$1', $2]")
.replace(/\[\s*\(\s*'([^']+)',\s*""\s*\)\s*\)/g, "['$1', '']")
// 修复数组元素中的圆括号错误 - 处理空字符串(单引号和双引号)
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*\"\"\s*\)\s*\)/g, '["$1", ""]')
.replace(/\[\s*\(\s*\"([^\"]+)\",\s*0\s*\)\s*\)/g, '["$1", 0]')
// 修复数组语法中的方括号错误 - 直接修复
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
// 修复数组语法中的方括号错误 - 处理所有情况
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
// 修复数组语法中的方括号错误 - 最终修复
.replace(/\[\s*\(\s*'([^']+)',\s*''\s*\)\s*\)/g, "['$1', '']")
.replace(/\[\s*\(\s*'([^']+)',\s*0\s*\)\s*\)/g, "['$1', 0]")
.replace(/is_array\s*\(/g, 'Array.isArray(')
.replace(/is_string\s*\(/g, 'typeof ')
.replace(/is_numeric\s*\(/g, '!isNaN(')
// 修复PHP对象访问
.replace(/->/g, '.')
.replace(/::/g, '.')
// 修复PHP空值合并
.replace(/\?\?/g, '||')
// 修复PHP数组访问
.replace(/\['([^']+)'\]/g, '.$1')
.replace(/\["([^"]+)"\]/g, '.$1')
// 修复PHP类型声明
.replace(/:\s*array/g, ': any[]')
.replace(/:\s*string/g, ': string')
.replace(/:\s*int/g, ': number')
.replace(/:\s*float/g, ': number')
.replace(/:\s*bool/g, ': boolean')
// 移除PHP语法残留
.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1')
// 修复方法体格式
.replace(/\{\s*\}/g, '{\n // 待实现\n }')
.replace(/\{\s*return\s+this;\s*\}/g, '{\n return this;\n }');
// 修复严重的语法错误
cleanedCode = this.fixCriticalSyntaxErrors(cleanedCode);
// 验证TypeScript语法
const validationErrors = this.validateTypeScriptSyntax(cleanedCode);
if (validationErrors.length > 0) {
console.warn('⚠️ TypeScript语法警告:', validationErrors);
}
return cleanedCode;
}
/**
* 修复严重的语法错误
*/
fixCriticalSyntaxErrors(code) {
return code
// 修复不完整的类结构
.replace(/export class \w+ \{[^}]*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的构造函数
.replace(/constructor\([^)]*\)\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*super\([^)]*\)\s*;\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*super\([^)]*\)\s*;\s*\}\s*$/, ' super(repository);\n }');
})
// 修复不完整的方法体
.replace(/async \w+\([^)]*\)\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*try\s*\{/gm, (match) => {
return match.replace(/\}\s*\}\s*try\s*\{/, ' {\n try {');
})
// 修复不完整的try-catch块
.replace(/try\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*catch\s*\([^)]*\)\s*\{/gm, (match) => {
return match.replace(/\}\s*\}\s*catch\s*\([^)]*\)\s*\{/, ' // 待实现\n } catch (error) {');
})
// 修复不完整的异常处理
.replace(/throw new BusinessException\('[^']*',\s*error\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/error\]\s*;\s*\}\s*\}\s*$/, 'error);\n }\n }');
})
// 修复不完整的import语句
.replace(/import\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*from/gm, (match) => {
return match.replace(/\{\s*\/\/ 待实现\s*\}\s*\}\s*from/, '{\n } from');
})
// 修复不完整的装饰器
.replace(/@\w+\([^)]*\)\s*\{\s*\/\/ 待实现\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的数组语法
.replace(/\[\s*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的对象语法
.replace(/\{\s*\}\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的字符串
.replace(/'[^']*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\]\s*;\s*\}\s*\}\s*$/, ';\n }');
})
// 修复不完整的括号
.replace(/\(\s*\)\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的方括号
.replace(/\[\s*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的尖括号
.replace(/<\s*>\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\}\s*\}\s*$/, '}');
})
// 修复不完整的注释
.replace(/\/\/[^\n]*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\]\s*;\s*\}\s*\}\s*$/, ';\n }');
})
// 修复不完整的多行注释
.replace(/\/\*[\s\S]*?\*\/\s*\]\s*;\s*\}\s*\}\s*$/gm, (match) => {
return match.replace(/\]\s*;\s*\}\s*\}\s*$/, ';\n }');
});
}
/**
* 验证TypeScript语法
*/
validateTypeScriptSyntax(code) {
const errors = [];
// 检查常见语法错误
if (code.includes('=>')) {
errors.push('发现PHP数组语法 => 未转换');
}
if (code.includes('??')) {
errors.push('发现PHP空值合并 ?? 未转换');
}
if (code.includes('::')) {
errors.push('发现PHP静态访问 :: 未转换');
}
if (code.includes('->')) {
errors.push('发现PHP对象访问 -> 未转换');
}
if (code.includes('$')) {
errors.push('发现PHP变量 $ 未转换');
}
if (code.includes('array(')) {
errors.push('发现PHP数组语法 array() 未转换');
}
if (code.includes('public function') || code.includes('private function') || code.includes('protected function')) {
errors.push('发现PHP方法声明未转换');
}
// 检查严重的语法错误
if (code.includes(']') && !code.includes('[')) {
errors.push('发现不完整的方括号 ]');
}
if (code.includes('}') && !code.includes('{')) {
errors.push('发现不完整的大括号 }');
}
// 检查括号匹配
const openBraces = (code.match(/\{/g) || []).length;
const closeBraces = (code.match(/\}/g) || []).length;
if (openBraces !== closeBraces) {
errors.push(`大括号不匹配: 开括号${openBraces}个, 闭括号${closeBraces}`);
}
const openBrackets = (code.match(/\[/g) || []).length;
const closeBrackets = (code.match(/\]/g) || []).length;
if (openBrackets !== closeBrackets) {
errors.push(`方括号不匹配: 开括号${openBrackets}个, 闭括号${closeBrackets}`);
}
if (code.includes('// 待实现')) {
errors.push('发现未实现的方法体');
}
return errors;
}
}
module.exports = BusinessLogicConverter;