feat: 重构多语言模块,符合NestJS规范
- 重构LanguageUtils为LanguageService,实现ILanguageService接口 - 移除自定义验证管道和装饰器,使用标准NestJS验证 - 集成框架ValidatorService进行业务验证 - 简化目录结构,移除不必要的子目录 - 支持模块化语言包加载(common、user、order等) - 统一API响应格式(code、msg、data、timestamp) - 添加ValidationExceptionFilter处理多语言验证错误 - 完善多语言示例和文档
This commit is contained in:
184
tools/generators/base-generator.js
Normal file
184
tools/generators/base-generator.js
Normal file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* 基础生成器类
|
||||
* 提供通用的 dry-run、文件操作、日志等功能
|
||||
*/
|
||||
class BaseGenerator {
|
||||
constructor(generatorName = 'Generator') {
|
||||
this.generatorName = generatorName;
|
||||
|
||||
// 从环境变量或参数读取配置
|
||||
this.dryRun = process.env.DRY_RUN === 'true' || process.argv.includes('--dry-run');
|
||||
this.verbose = process.env.VERBOSE === 'true' || process.argv.includes('--verbose');
|
||||
|
||||
this.stats = {
|
||||
filesCreated: 0,
|
||||
filesUpdated: 0,
|
||||
filesSkipped: 0,
|
||||
errors: 0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全写入文件(支持 dry-run)
|
||||
*/
|
||||
writeFile(filePath, content, description = '') {
|
||||
try {
|
||||
if (this.dryRun) {
|
||||
console.log(` [DRY-RUN] Would create/update: ${filePath}`);
|
||||
if (this.verbose && description) {
|
||||
console.log(` Description: ${description}`);
|
||||
}
|
||||
this.stats.filesCreated++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 确保目录存在
|
||||
this.ensureDir(path.dirname(filePath));
|
||||
|
||||
// 写入文件
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
|
||||
const action = fs.existsSync(filePath) ? 'Updated' : 'Created';
|
||||
console.log(` ✅ ${action}: ${filePath}`);
|
||||
|
||||
if (action === 'Created') {
|
||||
this.stats.filesCreated++;
|
||||
} else {
|
||||
this.stats.filesUpdated++;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(` ❌ Failed to write ${filePath}:`, error.message);
|
||||
this.stats.errors++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保目录存在
|
||||
*/
|
||||
ensureDir(dirPath) {
|
||||
if (this.dryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
fs.mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取文件(安全)
|
||||
*/
|
||||
readFile(filePath) {
|
||||
try {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return null;
|
||||
}
|
||||
return fs.readFileSync(filePath, 'utf8');
|
||||
} catch (error) {
|
||||
console.error(` ❌ Failed to read ${filePath}:`, error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否存在
|
||||
*/
|
||||
fileExists(filePath) {
|
||||
return fs.existsSync(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志输出
|
||||
*/
|
||||
log(message, level = 'info') {
|
||||
const prefix = {
|
||||
'info': ' ℹ️ ',
|
||||
'success': ' ✅',
|
||||
'warning': ' ⚠️ ',
|
||||
'error': ' ❌',
|
||||
'debug': ' 🔍'
|
||||
};
|
||||
|
||||
if (level === 'debug' && !this.verbose) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`${prefix[level] || ' '}${message}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出统计信息
|
||||
*/
|
||||
printStats(additionalStats = {}) {
|
||||
console.log('\n📊 Generation Statistics');
|
||||
console.log('==================================================');
|
||||
|
||||
if (this.dryRun) {
|
||||
console.log(' 🔍 DRY-RUN MODE - No files were actually modified');
|
||||
}
|
||||
|
||||
console.log(` 📁 Files Created: ${this.stats.filesCreated}`);
|
||||
console.log(` 🔄 Files Updated: ${this.stats.filesUpdated}`);
|
||||
console.log(` ⏭️ Files Skipped: ${this.stats.filesSkipped}`);
|
||||
console.log(` ❌ Errors: ${this.stats.errors}`);
|
||||
|
||||
// 输出额外的统计信息
|
||||
for (const [key, value] of Object.entries(additionalStats)) {
|
||||
console.log(` 📈 ${key}: ${value}`);
|
||||
}
|
||||
|
||||
const total = this.stats.filesCreated + this.stats.filesUpdated;
|
||||
const successRate = total > 0
|
||||
? ((total / (total + this.stats.errors)) * 100).toFixed(2)
|
||||
: '0.00';
|
||||
|
||||
console.log(` 📊 Success Rate: ${successRate}%`);
|
||||
console.log('==================================================');
|
||||
}
|
||||
|
||||
/**
|
||||
* kebab-case 转换
|
||||
*/
|
||||
toKebabCase(str) {
|
||||
return String(str)
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
||||
.replace(/_/g, '-')
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* PascalCase 转换
|
||||
*/
|
||||
toPascalCase(str) {
|
||||
return String(str)
|
||||
.split(/[-_]/)
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* camelCase 转换
|
||||
*/
|
||||
toCamelCase(str) {
|
||||
const pascal = this.toPascalCase(str);
|
||||
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* snake_case 转换
|
||||
*/
|
||||
toSnakeCase(str) {
|
||||
return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BaseGenerator;
|
||||
|
||||
Reference in New Issue
Block a user