Files
wwjcloud/tools/migration-coordinator.js
wanwu b1e16be25d feat: 重构多语言模块,符合NestJS规范
- 重构LanguageUtils为LanguageService,实现ILanguageService接口
- 移除自定义验证管道和装饰器,使用标准NestJS验证
- 集成框架ValidatorService进行业务验证
- 简化目录结构,移除不必要的子目录
- 支持模块化语言包加载(common、user、order等)
- 统一API响应格式(code、msg、data、timestamp)
- 添加ValidationExceptionFilter处理多语言验证错误
- 完善多语言示例和文档
2025-10-06 10:56:59 +08:00

1208 lines
36 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const ServiceGenerator = require('./generators/service-generator');
const EntityGenerator = require('./generators/entity-generator');
const ModuleGenerator = require('./generators/module-generator');
const ControllerGenerator = require('./generators/controller-generator');
const ValidatorGenerator = require('./generators/validator-generator');
// const MiddlewareGenerator = require('./generators/middleware-generator'); // 已废弃使用Core层Guards+Interceptors+Pipes
const RouteGenerator = require('./generators/route-generator');
const JobGenerator = require('./generators/job-generator');
const ListenerGenerator = require('./generators/listener-generator');
// const CommandGenerator = require('./generators/command-generator'); // 文件不存在,暂时注释
const DictGenerator = require('./generators/dict-generator');
const QualityGate = require('./generators/quality-gate');
/**
* 🎯 迁移协调器
* 协调所有工具的执行按步骤完成PHP到NestJS的迁移
*/
class MigrationCoordinator {
constructor() {
this.config = {
phpBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-php/niucloud',
nestjsBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest/src/core',
discoveryResultPath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/tools/php-discovery-result.json',
enableJobs: true,
enableListeners: true,
enableCommands: false,
dryRun: false
};
this.stats = {
totalSteps: 0,
completedSteps: 0,
failedSteps: 0,
startTime: null,
endTime: null,
errors: 0
};
}
/**
* 🚀 启动完整自动化迁移工具
*/
async run() {
console.log('🚀 启动完整自动化迁移工具...');
console.log('目标完整迁移PHP项目到NestJS包括所有组件\n');
this.stats.startTime = new Date();
try {
// 第1阶段加载PHP文件发现结果
console.log('📊 第1阶段加载PHP文件发现结果...');
await this.loadDiscoveryData();
// 第2阶段创建完整模块结构
console.log('📊 第2阶段创建完整模块结构...');
await this.createCompleteModuleStructure();
// 第3阶段生成实体数据模型层
console.log('📊 第3阶段生成实体...');
await this.generateEntities();
console.log('🔍 验证实体生成结果...');
await this.validateEntities();
// 第4阶段生成服务业务逻辑层
console.log('📊 第4阶段生成服务...');
await this.generateServices();
console.log('🔍 验证服务生成结果...');
await this.validateServices();
// 第5阶段生成验证器依赖服务
console.log('📊 第5阶段生成验证器...');
await this.generateValidators();
console.log('🔍 验证验证器生成结果...');
await this.validateValidators();
// 第6阶段生成控制器依赖服务和验证器
console.log('📊 第6阶段生成控制器...');
await this.generateControllersWithClassification();
console.log('🔍 验证控制器生成结果...');
await this.validateControllers();
// 第7阶段生成路由依赖控制器
console.log('📊 第7阶段生成路由...');
await this.generateRoutes();
console.log('🔍 验证路由生成结果...');
await this.validateRoutes();
// 第8阶段生成任务
if (this.config.enableJobs) {
console.log('📊 第8阶段生成任务...');
await this.generateJobs();
console.log('🔍 验证任务生成结果...');
await this.validateJobs();
} else {
console.log('⏭️ 跳过任务生成 (已禁用)');
}
// 第9阶段生成监听器
if (this.config.enableListeners) {
console.log('📊 第9阶段生成监听器...');
await this.generateListeners();
console.log('🔍 验证监听器生成结果...');
await this.validateListeners();
} else {
console.log('⏭️ 跳过监听器生成 (已禁用)');
}
// 第10阶段生成命令
if (this.config.enableCommands) {
console.log('📊 第10阶段生成命令...');
await this.generateCommands();
console.log('🔍 验证命令生成结果...');
await this.validateCommands();
} else {
console.log('⏭️ 跳过命令生成 (已禁用)');
}
// 第11阶段生成字典
console.log('📊 第11阶段生成字典...');
await this.generateDicts();
console.log('🔍 验证字典生成结果...');
await this.validateDicts();
// 第12阶段生成模块文件依赖所有组件
console.log('📊 第12阶段生成模块文件...');
await this.generateModuleFiles();
console.log('🔍 验证模块文件生成结果...');
await this.validateModuleFiles();
// 第13阶段最终质量检查
console.log('📊 第13阶段最终质量检查...');
await this.runQualityGate();
// 第14阶段生成统计报告
console.log('📊 第14阶段生成统计报告...');
this.generateStatsReport();
} catch (error) {
console.error('❌ 迁移过程中发生错误:', error.message);
this.stats.errors++;
throw error;
} finally {
this.stats.endTime = new Date();
const duration = this.stats.endTime - this.stats.startTime;
console.log(`\n⏱️ 总耗时: ${(duration / 1000).toFixed(2)}`);
}
}
/**
* 加载PHP文件发现结果
*/
async loadDiscoveryData() {
try {
const data = fs.readFileSync(this.config.discoveryResultPath, 'utf-8');
this.discoveryData = JSON.parse(data);
console.log(' ✅ 成功加载PHP文件发现结果');
} catch (error) {
console.error(' ❌ 加载发现数据失败:', error.message);
throw error;
}
}
/**
* 创建完整模块结构
*/
async createCompleteModuleStructure() {
console.log(' 🔨 创建完整模块结构...');
// 获取所有模块
const modules = new Set();
// 从控制器中提取模块
for (const [moduleName, controllers] of Object.entries(this.discoveryData.controllers)) {
modules.add(moduleName);
}
// 从服务中提取模块
for (const [layerName, services] of Object.entries(this.discoveryData.services)) {
for (const [serviceName, serviceInfo] of Object.entries(services)) {
const moduleName = this.extractModuleNameFromServicePath(serviceInfo.filePath);
modules.add(moduleName);
}
}
// 从模型中提取模块
for (const [moduleName, models] of Object.entries(this.discoveryData.models)) {
modules.add(moduleName);
}
// 创建每个模块的目录结构
for (const moduleName of modules) {
await this.createModuleStructure(moduleName);
}
console.log(` ✅ 创建了 ${modules.size} 个模块的目录结构`);
}
/**
* 创建模块结构 - 基于PHP实际存在的层级
*/
async createModuleStructure(moduleName) {
const modulePath = path.join(this.config.nestjsBasePath, moduleName);
// 创建模块目录
if (!fs.existsSync(modulePath)) {
fs.mkdirSync(modulePath, { recursive: true });
}
// 检查PHP实际存在的层级只创建对应的目录
const phpLayers = this.getPHPLayersForModule(moduleName);
for (const layer of phpLayers) {
const fullPath = path.join(modulePath, layer);
if (!fs.existsSync(fullPath)) {
fs.mkdirSync(fullPath, { recursive: true });
}
}
}
/**
* 获取模块在PHP中实际存在的层级
*/
getPHPLayersForModule(moduleName) {
const layers = [];
// 检查控制器层级
if (this.hasPHPControllers(moduleName)) {
layers.push('controllers');
if (this.hasPHPAdminControllers(moduleName)) {
layers.push('controllers/adminapi');
}
if (this.hasPHPApiControllers(moduleName)) {
layers.push('controllers/api');
}
}
// 检查服务层级
if (this.hasPHPServices(moduleName)) {
layers.push('services');
if (this.hasPHPAdminServices(moduleName)) {
layers.push('services/admin');
}
if (this.hasPHPApiServices(moduleName)) {
layers.push('services/api');
}
if (this.hasPHPCoreServices(moduleName)) {
layers.push('services/core');
}
}
// 检查实体层级
if (this.hasPHPModels(moduleName)) {
layers.push('entity');
}
// 检查验证器层级
if (this.hasPHPValidators(moduleName)) {
layers.push('dto');
if (this.hasPHPAdminValidators(moduleName)) {
layers.push('dto/admin');
}
if (this.hasPHPApiValidators(moduleName)) {
layers.push('dto/api');
}
}
return layers;
}
/**
* 智能分类判断模块应该迁移到Core层还是跳过
*/
classifyModule(moduleName, phpFilePath) {
const BusinessLogicConverter = require('./generators/business-logic-converter');
const businessLogicConverter = new BusinessLogicConverter();
const className = path.basename(phpFilePath, '.php');
// 读取文件内容用于智能分析
let content = '';
try {
content = fs.readFileSync(phpFilePath, 'utf-8');
} catch (error) {
console.warn(`⚠️ 无法读取文件 ${phpFilePath}: ${error.message}`);
content = '';
}
const classification = businessLogicConverter.classifyFile(phpFilePath, className, content);
return {
moduleName,
classification, // 'CORE_BUSINESS' | 'INFRASTRUCTURE'
shouldMigrate: classification === 'CORE_BUSINESS',
skipReason: classification === 'INFRASTRUCTURE' ? '属于基础设施使用Common层服务' : null
};
}
/**
* 检查模块是否有PHP控制器
*/
hasPHPControllers(moduleName) {
const adminPath = path.join(this.config.phpBasePath, 'app/adminapi/controller', moduleName);
const apiPath = path.join(this.config.phpBasePath, 'app/api/controller', moduleName);
return fs.existsSync(adminPath) || fs.existsSync(apiPath);
}
/**
* 检查模块是否有PHP管理端控制器
*/
hasPHPAdminControllers(moduleName) {
const adminPath = path.join(this.config.phpBasePath, 'app/adminapi/controller', moduleName);
return fs.existsSync(adminPath);
}
/**
* 检查模块是否有PHP前台控制器
*/
hasPHPApiControllers(moduleName) {
const apiPath = path.join(this.config.phpBasePath, 'app/api/controller', moduleName);
return fs.existsSync(apiPath);
}
/**
* 检查模块是否有PHP服务
*/
hasPHPServices(moduleName) {
const adminPath = path.join(this.config.phpBasePath, 'app/service/admin', moduleName);
const apiPath = path.join(this.config.phpBasePath, 'app/service/api', moduleName);
const corePath = path.join(this.config.phpBasePath, 'app/service/core', moduleName);
return fs.existsSync(adminPath) || fs.existsSync(apiPath) || fs.existsSync(corePath);
}
/**
* 检查模块是否有PHP管理端服务
*/
hasPHPAdminServices(moduleName) {
const adminPath = path.join(this.config.phpBasePath, 'app/service/admin', moduleName);
return fs.existsSync(adminPath);
}
/**
* 检查模块是否有PHP前台服务
*/
hasPHPApiServices(moduleName) {
const apiPath = path.join(this.config.phpBasePath, 'app/service/api', moduleName);
return fs.existsSync(apiPath);
}
/**
* 检查模块是否有PHP核心服务
*/
hasPHPCoreServices(moduleName) {
const corePath = path.join(this.config.phpBasePath, 'app/service/core', moduleName);
return fs.existsSync(corePath);
}
/**
* 检查模块是否有PHP模型
*/
hasPHPModels(moduleName) {
const modelPath = path.join(this.config.phpBasePath, 'app/model', moduleName);
return fs.existsSync(modelPath);
}
/**
* 检查模块是否有PHP验证器
*/
hasPHPValidators(moduleName) {
const adminPath = path.join(this.config.phpBasePath, 'app/adminapi/validate', moduleName);
const apiPath = path.join(this.config.phpBasePath, 'app/api/validate', moduleName);
return fs.existsSync(adminPath) || fs.existsSync(apiPath);
}
/**
* 检查模块是否有PHP管理端验证器
*/
hasPHPAdminValidators(moduleName) {
const adminPath = path.join(this.config.phpBasePath, 'app/adminapi/validate', moduleName);
return fs.existsSync(adminPath);
}
/**
* 检查模块是否有PHP前台验证器
*/
hasPHPApiValidators(moduleName) {
const apiPath = path.join(this.config.phpBasePath, 'app/api/validate', moduleName);
return fs.existsSync(apiPath);
}
/**
* 智能分类生成控制器文件
*/
async generateControllersWithClassification() {
console.log('🔍 开始智能分类分析...');
const classificationResults = [];
const modulesToMigrate = [];
// 分析所有模块
for (const moduleName in this.discoveryData.controllers) {
const controllers = this.discoveryData.controllers[moduleName];
for (const controllerName in controllers) {
const controllerInfo = controllers[controllerName];
const classification = this.classifyModule(moduleName, controllerInfo.filePath);
classificationResults.push({
file: controllerInfo.filePath,
module: moduleName,
controller: controllerName,
classification: classification.classification,
shouldMigrate: classification.shouldMigrate,
skipReason: classification.skipReason
});
if (classification.shouldMigrate) {
modulesToMigrate.push(moduleName);
}
}
}
// 生成分类报告
console.log('\n📋 智能分类结果:');
console.log('='.repeat(80));
const businessModules = classificationResults.filter(r => r.classification === 'CORE_BUSINESS');
const infrastructureModules = classificationResults.filter(r => r.classification === 'INFRASTRUCTURE');
console.log(`✅ 业务模块 (需要迁移到Core层): ${businessModules.length}`);
businessModules.forEach(r => console.log(` - ${r.module}/${r.controller}`));
console.log(`⚠️ 基础设施模块 (使用Common层): ${infrastructureModules.length}`);
infrastructureModules.forEach(r => console.log(` - ${r.module}/${r.controller} (${r.skipReason})`));
console.log('\n🚀 开始生成业务模块...');
// 只迁移业务模块
const uniqueModules = [...new Set(modulesToMigrate)];
for (const moduleName of uniqueModules) {
console.log(`📁 生成模块: ${moduleName}`);
await this.generateControllersForModule(moduleName);
}
console.log('✅ 智能分类控制器生成完成!');
return { classificationResults, businessModules, infrastructureModules };
}
/**
* 为指定模块生成控制器
*/
async generateControllersForModule(moduleName) {
if (!this.hasPHPControllers(moduleName)) return;
const controllerGenerator = new ControllerGenerator();
await controllerGenerator.run();
this.stats.generatedControllers++;
}
/**
* 生成控制器
*/
async generateControllers() {
const controllerGenerator = new ControllerGenerator();
await controllerGenerator.run();
}
/**
* 生成服务
*/
async generateServices() {
const serviceGenerator = new ServiceGenerator();
await serviceGenerator.run();
}
/**
* 生成实体
*/
async generateEntities() {
console.log(' 🔨 生成实体文件...');
let processedCount = 0;
for (const [moduleName, models] of Object.entries(this.discoveryData.models)) {
console.log(` 📁 处理模块: ${moduleName}, 模型数量: ${Object.keys(models).length}`);
for (const [modelName, modelInfo] of Object.entries(models)) {
console.log(` 📊 处理模型: ${modelName}`);
try {
await this.createEntity(moduleName, modelName, modelInfo);
processedCount++;
console.log(` ✅ 成功创建实体: ${moduleName}/${modelName}`);
} catch (error) {
console.error(` ❌ 创建实体失败 ${moduleName}/${modelName}:`, error.message);
this.stats.errors++;
}
}
}
console.log(` ✅ 创建了 ${processedCount} 个实体`);
}
/**
* 创建实体
*/
async createEntity(moduleName, modelName, modelInfo) {
const entityPath = path.join(
this.config.nestjsBasePath,
moduleName,
'entity',
`${this.toKebabCase(modelName)}.entity.ts`
);
// 确保目录存在
const entityDir = path.dirname(entityPath);
if (!this.config.dryRun && !fs.existsSync(entityDir)) {
fs.mkdirSync(entityDir, { recursive: true });
}
// 生成实体内容
const entityContent = this.generateEntityContent(moduleName, modelName, modelInfo);
// 写入文件
if (!this.config.dryRun) fs.writeFileSync(entityPath, entityContent);
console.log(` ✅ 创建实体: ${moduleName}/${this.toKebabCase(modelName)}.entity.ts`);
}
/**
* 转换为kebab-case
*/
toKebabCase(str) {
return String(str)
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/_/g, '-')
.toLowerCase();
}
/**
* 生成实体内容
*/
generateEntityContent(moduleName, modelName, modelInfo) {
const className = this.toPascalCase(modelName);
return `import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity('${this.toSnakeCase(modelName)}')
export class ${className} {
@PrimaryGeneratedColumn()
id: number;
@Column({ type: 'varchar', length: 255, nullable: true })
name: string;
@Column({ type: 'text', nullable: true })
description: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
`;
}
/**
* 生成验证器
*/
async generateValidators() {
const validatorGenerator = new ValidatorGenerator();
await validatorGenerator.run();
}
/**
* 生成中间件
*/
async generateMiddlewares() {
// const middlewareGenerator = new MiddlewareGenerator(); // 已废弃使用Core层Guards+Interceptors+Pipes
// await middlewareGenerator.run();
}
/**
* 生成路由
*/
async generateRoutes() {
const routeGenerator = new RouteGenerator();
await routeGenerator.run();
}
/**
* 生成任务
*/
async generateJobs() {
const jobGenerator = new JobGenerator();
await jobGenerator.run();
}
/**
* 生成监听器
*/
async generateListeners() {
const listenerGenerator = new ListenerGenerator();
await listenerGenerator.run();
}
/**
* 生成命令
*/
async generateCommands() {
// const commandGenerator = new CommandGenerator(); // 文件不存在,暂时跳过
// await commandGenerator.run();
console.log(' ⏭️ 跳过命令生成 (文件不存在)');
}
/**
* 生成特征 - 已废弃
* 原因PHP项目只有2个Trait文件NestJS不支持Trait概念
* 应改用 Injectable Service 模式
*/
async generateTraits() {
console.log(' ⏭️ 跳过特征生成 (已废弃:建议使用 Injectable Service)');
}
/**
* 生成字典
*/
async generateDicts() {
const dictGenerator = new DictGenerator();
await dictGenerator.run();
}
/**
* 生成模块文件
*/
async generateModuleFiles() {
console.log(' 🔨 生成模块文件...');
// 获取所有模块
const modules = new Set();
// 从发现数据中提取模块名
if (this.discoveryData && this.discoveryData.modules) {
Object.keys(this.discoveryData.modules).forEach(moduleName => {
modules.add(moduleName);
});
}
// 从控制器中提取模块名
if (this.discoveryData && this.discoveryData.controllers) {
Object.keys(this.discoveryData.controllers).forEach(controllerPath => {
const pathParts = controllerPath.split('/');
if (pathParts.length > 0) {
modules.add(pathParts[0]);
}
});
}
// 从服务中提取模块名
if (this.discoveryData && this.discoveryData.services) {
Object.keys(this.discoveryData.services).forEach(servicePath => {
const pathParts = servicePath.split('/');
if (pathParts.length > 0) {
modules.add(pathParts[0]);
}
});
}
const moduleArray = Array.from(modules);
for (const moduleName of moduleArray) {
await this.createModuleFile(moduleName);
}
console.log(' ✅ 模块文件生成完成');
}
/**
* 创建模块文件
*/
async createModuleFile(moduleName) {
const moduleDir = path.join(this.config.nestjsBasePath, moduleName);
const modulePath = path.join(moduleDir, `${moduleName}.module.ts`);
// 确保目录存在
if (!fs.existsSync(moduleDir)) {
fs.mkdirSync(moduleDir, { recursive: true });
}
const content = this.generateModuleContent(moduleName);
fs.writeFileSync(modulePath, content);
console.log(` ✅ 创建模块: ${moduleName}/${moduleName}.module.ts`);
}
/**
* 生成模块内容
*/
generateModuleContent(moduleName) {
const className = `${this.toPascalCase(moduleName)}Module`;
return `import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
exports: [],
})
export class ${className} {}
`;
}
/**
* 从服务路径提取模块名
*/
extractModuleNameFromServicePath(filePath) {
const pathParts = filePath.split('/');
const serviceIndex = pathParts.findIndex(part => part === 'service');
if (serviceIndex > 0) {
return pathParts[serviceIndex - 1];
}
const fileName = path.basename(filePath, '.php');
if (fileName.includes('Service')) {
return fileName.replace('Service', '').toLowerCase();
}
return 'unknown';
}
/**
* 转换为驼峰命名
*/
toCamelCase(str) {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
}
/**
* 转换为帕斯卡命名 - 处理连字符
*/
toPascalCase(str) {
return str.replace(/(^|-)([a-z])/g, (match, p1, p2) => p2.toUpperCase());
}
/**
* 转换为蛇形命名
*/
toSnakeCase(str) {
return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
}
/**
* 运行 Quality Gate 质量检查
*/
async runQualityGate() {
try {
const qualityGate = new QualityGate(path.dirname(this.config.nestjsBasePath));
const passed = await qualityGate.run();
if (passed) {
console.log(' ✅ Quality Gate 通过');
this.stats.completedSteps++;
} else {
console.log(' ❌ Quality Gate 失败');
this.stats.failedSteps++;
// Quality Gate 失败不中断流程,但记录错误
console.log(' ⚠️ 继续执行,但建议修复质量问题');
}
} catch (error) {
console.log(` ⚠️ Quality Gate 检查失败: ${error.message}`);
console.log(' 跳过质量检查,继续执行迁移流程');
this.stats.failedSteps++;
}
}
/**
* 生成统计报告
*/
generateStatsReport() {
console.log('\n📊 完整迁移统计报告');
console.log('='.repeat(50));
console.log(`✅ 完成步骤: ${this.stats.completedSteps}`);
console.log(`❌ 失败步骤: ${this.stats.failedSteps}`);
console.log(`📈 成功率: ${this.stats.completedSteps > 0 ? ((this.stats.completedSteps - this.stats.failedSteps) / this.stats.completedSteps * 100).toFixed(2) : 0}%`);
console.log(`⏱️ 总耗时: ${this.stats.endTime ? ((this.stats.endTime - this.stats.startTime) / 1000).toFixed(2) : 0}`);
}
/**
* 验证实体生成结果
*/
async validateEntities() {
try {
const entityFiles = this.findFilesByPattern('**/*.entity.ts');
console.log(` 📊 验证 ${entityFiles.length} 个实体文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of entityFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('@Entity') && content.includes('export class')) {
validCount++;
} else {
console.log(` ⚠️ 实体文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 实体文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 实体验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 实体验证失败: ${error.message}`);
return false;
}
}
/**
* 验证服务生成结果
*/
async validateServices() {
try {
const serviceFiles = this.findFilesByPattern('**/*.service.ts');
console.log(` 📊 验证 ${serviceFiles.length} 个服务文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of serviceFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('@Injectable') && content.includes('export class')) {
// 检查是否有语法错误
if (content.includes(']]') || content.includes('BusinessBusinessException')) {
console.log(` ⚠️ 服务文件有语法错误: ${file}`);
errorCount++;
} else {
validCount++;
}
} else {
console.log(` ⚠️ 服务文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 服务文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 服务验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 服务验证失败: ${error.message}`);
return false;
}
}
/**
* 验证验证器生成结果
*/
async validateValidators() {
try {
const validatorFiles = this.findFilesByPattern('**/*.validator.ts');
console.log(` 📊 验证 ${validatorFiles.length} 个验证器文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of validatorFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('export class') && content.includes('validate')) {
validCount++;
} else {
console.log(` ⚠️ 验证器文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 验证器文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 验证器验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 验证器验证失败: ${error.message}`);
return false;
}
}
/**
* 验证控制器生成结果
*/
async validateControllers() {
try {
const controllerFiles = this.findFilesByPattern('**/*.controller.ts');
console.log(` 📊 验证 ${controllerFiles.length} 个控制器文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of controllerFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('@Controller') && content.includes('export class')) {
validCount++;
} else {
console.log(` ⚠️ 控制器文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 控制器文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 控制器验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 控制器验证失败: ${error.message}`);
return false;
}
}
/**
* 验证路由生成结果
*/
async validateRoutes() {
try {
const routeFiles = this.findFilesByPattern('**/*.routes.ts');
console.log(` 📊 验证 ${routeFiles.length} 个路由文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of routeFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('export') && content.includes('Routes')) {
validCount++;
} else {
console.log(` ⚠️ 路由文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 路由文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 路由验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 路由验证失败: ${error.message}`);
return false;
}
}
/**
* 验证任务生成结果
*/
async validateJobs() {
try {
const jobFiles = this.findFilesByPattern('**/*.job.ts');
console.log(` 📊 验证 ${jobFiles.length} 个任务文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of jobFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('@Processor') && content.includes('export class')) {
validCount++;
} else {
console.log(` ⚠️ 任务文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 任务文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 任务验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 任务验证失败: ${error.message}`);
return false;
}
}
/**
* 验证监听器生成结果
*/
async validateListeners() {
try {
const listenerFiles = this.findFilesByPattern('**/*.listener.ts');
console.log(` 📊 验证 ${listenerFiles.length} 个监听器文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of listenerFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('@OnEvent') && content.includes('export class')) {
validCount++;
} else {
console.log(` ⚠️ 监听器文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 监听器文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 监听器验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 监听器验证失败: ${error.message}`);
return false;
}
}
/**
* 验证命令生成结果
*/
async validateCommands() {
try {
const commandFiles = this.findFilesByPattern('**/*.command.ts');
console.log(` 📊 验证 ${commandFiles.length} 个命令文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of commandFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('@Command') && content.includes('export class')) {
validCount++;
} else {
console.log(` ⚠️ 命令文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 命令文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 命令验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 命令验证失败: ${error.message}`);
return false;
}
}
/**
* 验证字典生成结果
*/
async validateDicts() {
try {
const dictFiles = this.findFilesByPattern('**/*.enum.ts');
console.log(` 📊 验证 ${dictFiles.length} 个字典文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of dictFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('export enum') || content.includes('export const')) {
validCount++;
} else {
console.log(` ⚠️ 字典文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 字典文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 字典验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 字典验证失败: ${error.message}`);
return false;
}
}
/**
* 验证模块文件生成结果
*/
async validateModuleFiles() {
try {
const moduleFiles = this.findFilesByPattern('**/*.module.ts');
console.log(` 📊 验证 ${moduleFiles.length} 个模块文件...`);
let validCount = 0;
let errorCount = 0;
for (const file of moduleFiles) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('@Module') && content.includes('export class')) {
validCount++;
} else {
console.log(` ⚠️ 模块文件格式异常: ${file}`);
errorCount++;
}
} catch (error) {
console.log(` ❌ 模块文件读取失败: ${file} - ${error.message}`);
errorCount++;
}
}
console.log(` ✅ 模块文件验证完成: ${validCount}个有效, ${errorCount}个错误`);
return errorCount === 0;
} catch (error) {
console.log(` ❌ 模块文件验证失败: ${error.message}`);
return false;
}
}
/**
* 查找匹配模式的文件
*/
findFilesByPattern(pattern) {
try {
const glob = require('glob');
const searchPath = path.join(this.config.nestjsBasePath, pattern);
return glob.sync(searchPath);
} catch (error) {
// 如果glob模块不存在使用简单的文件系统搜索
console.log(` ⚠️ glob模块不可用使用简单文件搜索: ${error.message}`);
return this.findFilesByPatternSimple(pattern);
}
}
/**
* 简单的文件搜索当glob不可用时
*/
findFilesByPatternSimple(pattern) {
const files = [];
const searchDir = this.config.nestjsBasePath;
if (!fs.existsSync(searchDir)) {
return files;
}
const walkDir = (dir) => {
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
walkDir(fullPath);
} else if (stat.isFile() && item.endsWith('.ts')) {
const relativePath = path.relative(this.config.nestjsBasePath, fullPath);
if (this.matchesPattern(relativePath, pattern)) {
files.push(fullPath);
}
}
}
};
walkDir(searchDir);
return files;
}
/**
* 简单的模式匹配
*/
matchesPattern(filePath, pattern) {
// 将glob模式转换为简单的字符串匹配
const simplePattern = pattern
.replace(/\*\*/g, '')
.replace(/\*/g, '')
.replace(/\.ts$/, '');
return filePath.includes(simplePattern);
}
}
// 如果直接运行此文件
if (require.main === module) {
const coordinator = new MigrationCoordinator();
coordinator.run().catch(console.error);
}
module.exports = MigrationCoordinator;