Files
wwjcloud/tools/generators/business-logic-converter.js

811 lines
29 KiB
JavaScript
Raw Normal View History

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 = [
{ from: /BaseController/g, to: '@wwjCommon/base/base.controller' },
{ from: /BaseService/g, to: '@wwjCommon/service/base.service' },
{ from: /core\\cache\\RedisCacheService/g, to: '@wwjCommon/cache/cache.service' },
{ from: /CoreRequestService/g, to: '@wwjCommon/request/request.service' },
{ from: /BaseApiService/g, to: '@wwjCommon/service/base-api.service' },
{ from: /CoreLogService/g, to: '@wwjCommon/log/log.service' }
];
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, 'BusinessException')
.replace(/(?<!Business)Exception/g, 'BusinessException')
// 修复重复的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 BusinessException(')
.replace(/throw\s+new\s+Exception\s*\(/g, 'throw new BusinessException(')
// 修复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;