const fs = require('fs'); const path = require('path'); /** * NestJS模块生成器 * 为每个模块创建对应的.module.ts文件并正确引用所有组件 */ class ModuleGenerator { constructor() { this.config = { nestjsBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud/src/common', discoveryResultPath: './tools/php-discovery-result.json' }; this.discoveryData = null; this.stats = { createdModules: 0, updatedModules: 0, errors: 0 }; } /** * 运行模块生成 */ async run() { try { console.log('🚀 启动NestJS模块生成器...'); console.log('目标:为每个模块创建.module.ts文件并正确引用所有组件\n'); // 第1阶段:加载PHP文件发现结果 console.log('📊 第1阶段:加载PHP文件发现结果...'); await this.loadDiscoveryData(); console.log(' ✅ 成功加载PHP文件发现结果'); // 第2阶段:扫描现有文件结构 console.log('\n📊 第2阶段:扫描现有文件结构...'); const moduleStructure = await this.scanModuleStructure(); console.log(` ✅ 扫描了 ${Object.keys(moduleStructure).length} 个模块`); // 第3阶段:生成模块文件 console.log('\n📊 第3阶段:生成模块文件...'); await this.generateModules(moduleStructure); console.log(` ✅ 生成了 ${this.stats.createdModules} 个模块文件`); // 第4阶段:生成统计报告 console.log('\n📊 第4阶段:生成统计报告...'); this.generateStatsReport(); } catch (error) { console.error('❌ 生成过程中发生错误:', error.message); this.stats.errors++; throw error; } } /** * 加载PHP文件发现结果 */ async loadDiscoveryData() { try { const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8'); this.discoveryData = JSON.parse(data); } catch (error) { throw new Error(`无法加载发现结果文件: ${error.message}`); } } /** * 扫描模块结构 */ async scanModuleStructure() { const moduleStructure = {}; const commonPath = this.config.nestjsBasePath; if (!fs.existsSync(commonPath)) { console.log(' ⚠️ common目录不存在'); return moduleStructure; } const modules = fs.readdirSync(commonPath, { withFileTypes: true }) .filter(dirent => dirent.isDirectory()) .map(dirent => dirent.name); for (const moduleName of modules) { const modulePath = path.join(commonPath, moduleName); moduleStructure[moduleName] = { controllers: this.scanControllers(modulePath), services: this.scanServices(modulePath), entities: this.scanEntities(modulePath), validators: this.scanValidators(modulePath), middlewares: this.scanMiddlewares(modulePath), jobs: this.scanJobs(modulePath), listeners: this.scanListeners(modulePath), commands: this.scanCommands(modulePath), dicts: this.scanDicts(modulePath) }; } return moduleStructure; } /** * 读取实际文件中的类名 */ getActualClassName(filePath) { try { if (!fs.existsSync(filePath)) { return null; } const content = fs.readFileSync(filePath, 'utf8'); const match = content.match(/export\s+(?:class|interface|enum)\s+(\w+)/); return match ? match[1] : null; } catch (error) { console.error(`读取文件 ${filePath} 时出错:`, error.message); return null; } } /** * 扫描控制器 */ scanControllers(modulePath) { const controllers = []; const controllersPath = path.join(modulePath, 'controllers'); if (fs.existsSync(controllersPath)) { const layers = ['adminapi', 'api']; for (const layer of layers) { const layerPath = path.join(controllersPath, layer); if (fs.existsSync(layerPath)) { const allFiles = fs.readdirSync(layerPath); const controllerFiles = allFiles.filter(file => file.endsWith('Controller.ts')); if (controllerFiles.length > 0) { console.log(` 发现 ${layer} 层控制器: ${controllerFiles.join(', ')}`); } const files = controllerFiles.map(file => { const filePath = path.join(layerPath, file); const actualClassName = this.getActualClassName(filePath); return { name: actualClassName || file.replace('Controller.ts', ''), path: `./controllers/${layer}/${file}`, layer: layer }; }); controllers.push(...files); } } } return controllers; } /** * 扫描服务 */ scanServices(modulePath) { const services = []; const servicesPath = path.join(modulePath, 'services'); if (fs.existsSync(servicesPath)) { const layers = ['admin', 'api', 'core']; for (const layer of layers) { const layerPath = path.join(servicesPath, layer); if (fs.existsSync(layerPath)) { const files = fs.readdirSync(layerPath) .filter(file => file.endsWith('.service.ts')) .map(file => { const filePath = path.join(layerPath, file); const actualClassName = this.getActualClassName(filePath); return { name: actualClassName || file.replace('.service.ts', ''), path: `./services/${layer}/${file}`, layer: layer }; }); services.push(...files); } } } return services; } /** * 扫描实体 */ scanEntities(modulePath) { const entities = []; const entitiesPath = path.join(modulePath, 'entity'); if (fs.existsSync(entitiesPath)) { const files = fs.readdirSync(entitiesPath) .filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts')) .map(file => ({ name: file.replace('.ts', ''), path: `./entity/${file}` })); entities.push(...files); } return entities; } /** * 扫描验证器 */ scanValidators(modulePath) { const validators = []; const validatorsPath = path.join(modulePath, 'dto'); if (fs.existsSync(validatorsPath)) { const files = fs.readdirSync(validatorsPath, { recursive: true }) .filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts')) .map(file => ({ name: file.replace('.ts', ''), path: `./dto/${file}` })); validators.push(...files); } return validators; } /** * 扫描中间件 */ scanMiddlewares(modulePath) { const middlewares = []; const middlewaresPath = path.join(modulePath, 'guards'); if (fs.existsSync(middlewaresPath)) { const files = fs.readdirSync(middlewaresPath) .filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts')) .map(file => ({ name: file.replace('.ts', ''), path: `./guards/${file}` })); middlewares.push(...files); } return middlewares; } /** * 扫描任务 */ scanJobs(modulePath) { const jobs = []; const jobsPath = path.join(modulePath, 'jobs'); if (fs.existsSync(jobsPath)) { const files = fs.readdirSync(jobsPath) .filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts')) .map(file => ({ name: file.replace('.ts', ''), path: `./jobs/${file}` })); jobs.push(...files); } return jobs; } /** * 扫描监听器 */ scanListeners(modulePath) { const listeners = []; const listenersPath = path.join(modulePath, 'listeners'); if (fs.existsSync(listenersPath)) { const files = fs.readdirSync(listenersPath) .filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts')) .map(file => ({ name: file.replace('.ts', ''), path: `./listeners/${file}` })); listeners.push(...files); } return listeners; } /** * 扫描命令 */ scanCommands(modulePath) { const commands = []; const commandsPath = path.join(modulePath, 'commands'); if (fs.existsSync(commandsPath)) { const files = fs.readdirSync(commandsPath) .filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts')) .map(file => ({ name: file.replace('.ts', ''), path: `./commands/${file}` })); commands.push(...files); } return commands; } /** * 扫描字典 */ scanDicts(modulePath) { const dicts = []; const dictsPath = path.join(modulePath, 'dicts'); if (fs.existsSync(dictsPath)) { const files = fs.readdirSync(dictsPath) .filter(file => file.endsWith('.ts') && !file.endsWith('.d.ts')) .map(file => ({ name: file.replace('.ts', ''), path: `./dicts/${file}` })); dicts.push(...files); } return dicts; } /** * 生成模块文件 */ async generateModules(moduleStructure) { console.log(' 🔨 生成模块文件...'); for (const [moduleName, components] of Object.entries(moduleStructure)) { try { await this.generateModuleFile(moduleName, components); this.stats.createdModules++; } catch (error) { console.error(` ❌ 生成模块 ${moduleName} 失败:`, error.message); this.stats.errors++; } } } /** * 生成单个模块文件 */ async generateModuleFile(moduleName, components) { const modulePath = path.join(this.config.nestjsBasePath, moduleName, `${moduleName}.module.ts`); // 生成模块内容 const moduleContent = this.generateModuleContent(moduleName, components); // 确保目录存在 this.ensureDir(path.dirname(modulePath)); // 写入文件 fs.writeFileSync(modulePath, moduleContent); console.log(` ✅ 创建模块: ${moduleName}/${moduleName}.module.ts`); } /** * 生成模块内容 */ generateModuleContent(moduleName, components) { const className = this.toPascalCase(moduleName); let imports = []; let controllers = []; let providers = []; let exports = []; let importSet = new Set(); // 用于去重 // 导入控制器 for (const controller of components.controllers) { const importName = this.toPascalCase(controller.name); const cleanPath = controller.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${importName} } from '${cleanPath}';`); controllers.push(importName); importSet.add(importKey); } } // 导入服务 for (const service of components.services) { const baseName = this.toPascalCase(service.name); const layerPrefix = this.getLayerPrefix(service.layer, baseName); const importName = layerPrefix ? `${layerPrefix}${baseName}` : baseName; const cleanPath = service.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { if (this.needsAlias(service.layer, baseName)) { imports.push(`import { ${baseName} as ${importName} } from '${cleanPath}';`); } else { imports.push(`import { ${importName} } from '${cleanPath}';`); } providers.push(importName); importSet.add(importKey); } } // 导入实体 for (const entity of components.entities) { const baseName = this.toPascalCase(entity.name); const importName = `Entity${baseName}`; const cleanPath = entity.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${baseName} as ${importName} } from '${cleanPath}';`); providers.push(importName); importSet.add(importKey); } } // 导入验证器 for (const validator of components.validators) { const baseName = this.toPascalCase(validator.name); const importName = `Validator${baseName}`; const cleanPath = validator.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${baseName} as ${importName} } from '${cleanPath}';`); providers.push(importName); importSet.add(importKey); } } // 导入中间件 for (const middleware of components.middlewares) { const importName = this.toPascalCase(middleware.name); const cleanPath = middleware.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${importName} } from '${cleanPath}';`); providers.push(importName); importSet.add(importKey); } } // 导入任务 for (const job of components.jobs) { const importName = this.toPascalCase(job.name); const cleanPath = job.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${importName} } from '${cleanPath}';`); providers.push(importName); importSet.add(importKey); } } // 导入监听器 for (const listener of components.listeners) { const importName = this.toPascalCase(listener.name); const cleanPath = listener.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${importName} } from '${cleanPath}';`); providers.push(importName); importSet.add(importKey); } } // 导入命令 for (const command of components.commands) { const importName = this.toPascalCase(command.name); const cleanPath = command.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${importName} } from '${cleanPath}';`); providers.push(importName); importSet.add(importKey); } } // 导入字典 for (const dict of components.dicts) { const importName = this.toPascalCase(dict.name); const cleanPath = dict.path.replace('.ts', ''); const importKey = `${importName}:${cleanPath}`; if (!importSet.has(importKey)) { imports.push(`import { ${importName} } from '${cleanPath}';`); providers.push(importName); importSet.add(importKey); } } // 导出服务 exports.push(...providers); const content = `import { Module } from '@nestjs/common'; ${imports.join('\n')} @Module({ controllers: [${controllers.join(', ')}], providers: [${providers.join(', ')}], exports: [${exports.join(', ')}], }) export class ${className}Module {} `; return content; } /** * 确保目录存在 */ ensureDir(dirPath) { if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } } /** * 转换为PascalCase */ toPascalCase(str) { return str.replace(/(^|_)([a-z])/g, (match, p1, p2) => p2.toUpperCase()); } /** * 获取层前缀 */ getLayerPrefix(layer, serviceName) { // 如果服务名已经包含Core前缀,则不需要再添加 if (layer === 'core' && serviceName.toLowerCase().startsWith('core')) { return ''; } const layerMap = { 'admin': 'Admin', 'api': 'Api', 'core': 'Core' }; return layerMap[layer] || ''; } /** * 检查是否需要别名 */ needsAlias(layer, serviceName) { // 如果服务名已经包含层前缀,则不需要别名 if (layer === 'core' && serviceName.toLowerCase().startsWith('core')) { return false; } return true; } /** * 生成统计报告 */ generateStatsReport() { console.log('\n📊 NestJS模块生成统计报告:'); console.log('============================================================'); console.log(` 📁 创建模块: ${this.stats.createdModules} 个`); console.log(` 🔄 更新模块: ${this.stats.updatedModules} 个`); console.log(` ❌ 错误数量: ${this.stats.errors} 个`); console.log('============================================================'); console.log('\n✅ 🎉 NestJS模块生成完成!'); } } // 运行模块生成器 if (require.main === module) { const generator = new ModuleGenerator(); generator.run().catch(console.error); } module.exports = ModuleGenerator;