#!/usr/bin/env node const fs = require('fs'); const path = require('path'); /** * 📝 验证器生成器 * 专门负责生成NestJS验证器/DTO文件 */ class ValidatorGenerator { constructor() { this.config = { phpBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/niucloud-php/niucloud', nestjsBasePath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/wwjcloud-nest-v1/libs/wwjcloud-core/src', discoveryResultPath: '/Users/wanwu/Documents/wwjcloud/wwjcloud-nsetjs/tools-v1/php-tools/php-discovery-result.json' }; this.discoveryData = null; this.stats = { validatorsCreated: 0, errors: 0 }; } /** * 运行验证器生成 */ async run() { try { console.log('📝 启动验证器生成器...'); console.log('目标:生成NestJS验证器/DTO文件\n'); // 加载PHP文件发现结果 await this.loadDiscoveryData(); // 生成验证器 await this.generateValidators(); // 输出统计报告 this.printStats(); } catch (error) { console.error('❌ 验证器生成失败:', error); this.stats.errors++; } } /** * 加载PHP文件发现结果 */ async loadDiscoveryData() { try { const data = fs.readFileSync(this.config.discoveryResultPath, 'utf8'); this.discoveryData = JSON.parse(data); console.log(' ✅ 成功加载PHP文件发现结果'); } catch (error) { console.error('❌ 加载发现结果失败:', error); throw error; } } /** * 生成验证器 */ async generateValidators() { console.log(' 🔨 生成验证器...'); for (const [moduleName, validates] of Object.entries(this.discoveryData.validates)) { for (const [validateName, validateInfo] of Object.entries(validates)) { await this.createValidator(moduleName, validateName, validateInfo); this.stats.validatorsCreated++; } } console.log(` ✅ 生成了 ${this.stats.validatorsCreated} 个验证器`); } /** * 创建验证器 */ async createValidator(moduleName, validateName, validateInfo) { const validatorDir = path.join(this.config.nestjsBasePath, moduleName, 'dto'); this.ensureDir(validatorDir); const validatorPath = path.join( validatorDir, `${this.toPascalCase(validateName)}Dto.ts` ); const content = this.generateValidatorContent(moduleName, validateName); if (content) { fs.writeFileSync(validatorPath, content); console.log(` ✅ 创建验证器: ${moduleName}/${this.toPascalCase(validateName)}Dto.ts`); } else { console.log(` ⚠️ 跳过验证器生成: ${moduleName}/${this.toPascalCase(validateName)}Dto.ts (无PHP源码)`); } } /** * 生成验证器内容 - 基于真实PHP验证器 */ generateValidatorContent(moduleName, validateName) { const className = `${this.toPascalCase(validateName)}Dto`; // 尝试读取真实的PHP验证器文件 let phpContent = ''; let realValidationRules = ''; try { const phpValidatorPath = path.join(this.config.phpBasePath, 'app/validate', moduleName, `${validateName}.php`); if (fs.existsSync(phpValidatorPath)) { phpContent = fs.readFileSync(phpValidatorPath, 'utf-8'); realValidationRules = this.extractValidationRulesFromPHP(phpContent, validateName); console.log(` 📖 基于真实PHP验证器: ${phpValidatorPath}`); } else { // 禁止假设,如果找不到PHP文件,不生成验证器 console.log(` ❌ 未找到PHP验证器文件,跳过生成: ${phpValidatorPath}`); return null; } } catch (error) { // 禁止假设,如果读取失败,不生成验证器 console.log(` ❌ 读取PHP验证器文件失败,跳过生成: ${error.message}`); return null; } const content = `import { IsString, IsNumber, IsOptional, IsNotEmpty, IsEmail, IsUrl, IsArray, IsObject, validateSync } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; /** * ${className} - 数据传输对象 * 基于真实PHP验证器规则生成,禁止假设字段 * 使用Core层基础设施:class-validator + Swagger文档 */ export class ${className} { ${realValidationRules} } /** * ${className} 验证器类 * 使用 class-validator 进行同步验证 */ export class ${className}Validator { /** * 验证数据 * 使用 class-validator 统一验证 */ static validate(data: ${className}): void { const instance = Object.assign(new ${className}(), data); const errors = validateSync(instance, { whitelist: true }); if (errors && errors.length > 0) { const messages = errors.map(e => Object.values(e.constraints || {}).join(';')).filter(Boolean); throw new Error(messages.join('\n')); } } /** * 验证场景 - 基于真实PHP的$scene */ static validateAdd(data: ${className}): void { // 基于真实PHP add场景验证规则 this.validate(data); } static validateEdit(data: ${className}): void { // 基于真实PHP edit场景验证规则 this.validate(data); } } export class Create${this.toPascalCase(validateName)}Dto { // 字段定义需要基于真实PHP验证器解析 // 禁止假设字段 // 使用Core层基础设施:class-validator装饰器、Swagger文档 } export class Update${this.toPascalCase(validateName)}Dto { // 字段定义需要基于真实PHP验证器解析 // 禁止假设字段 // 使用Core层基础设施:class-validator装饰器、Swagger文档 } export class Query${this.toPascalCase(validateName)}Dto { // 字段定义需要基于真实PHP验证器解析 // 禁止假设字段 // 使用Core层基础设施:class-validator装饰器、Swagger文档 } `; return content; } /** * 从PHP验证器内容中提取验证规则 */ extractValidationRulesFromPHP(phpContent, validateName) { // 提取验证规则 const ruleMatch = phpContent.match(/protected\s+\$rule\s*=\s*\[([\s\S]*?)\];/); const messageMatch = phpContent.match(/protected\s+\$message\s*=\s*\[([\s\S]*?)\];/); const sceneMatch = phpContent.match(/protected\s+\$scene\s*=\s*\[([\s\S]*?)\];/); if (ruleMatch) { console.log(` 📖 找到PHP验证规则: ${validateName}`); // 解析规则内容 return this.parsePHPValidationRules(ruleMatch[1], messageMatch ? messageMatch[1] : '', sceneMatch ? sceneMatch[1] : ''); } return ''; } /** * 解析PHP验证规则 */ parsePHPValidationRules(rulesContent, messagesContent, scenesContent) { const fields = []; // 解析规则 const ruleMatches = rulesContent.match(/(['"][^'"]*['"])\s*=>\s*(['"][^'"]*['"])/g); if (ruleMatches) { ruleMatches.forEach(match => { const fieldMatch = match.match(/(['"][^'"]*['"])\s*=>\s*(['"][^'"]*['"])/); if (fieldMatch) { const fieldName = fieldMatch[1].replace(/['"]/g, ''); const fieldRules = fieldMatch[2].replace(/['"]/g, ''); // 解析规则类型 const fieldType = this.parseFieldType(fieldRules); const validators = this.parseValidators(fieldRules); fields.push({ name: fieldName, type: fieldType, validators: validators, rules: fieldRules }); } }); } // 生成DTO字段 const dtoFields = fields.map(field => { const validatorsStr = field.validators.map(v => `@${v}()`).join('\n '); return ` @ApiProperty({ description: ${JSON.stringify(field.name)} }) ${validatorsStr} ${this.toCamelCase(field.name)}: ${field.type};`; }).join('\n\n'); return dtoFields; } /** * 解析字段类型 */ parseFieldType(rules) { if (rules.includes('number') || rules.includes('integer')) { return 'number'; } else if (rules.includes('email')) { return 'string'; } else if (rules.includes('url')) { return 'string'; } else if (rules.includes('array')) { return 'any[]'; } else if (rules.includes('object')) { return 'object'; } else { return 'string'; } } /** * 解析验证器 */ parseValidators(rules) { const validators = []; if (rules.includes('require')) { validators.push('IsNotEmpty'); } if (rules.includes('number') || rules.includes('integer')) { validators.push('IsNumber'); } else if (rules.includes('email')) { validators.push('IsEmail'); } else if (rules.includes('url')) { validators.push('IsUrl'); } else if (rules.includes('array')) { validators.push('IsArray'); } else if (rules.includes('object')) { validators.push('IsObject'); } else { validators.push('IsString'); } return validators; } /** * 转换为PascalCase - 处理连字符 */ toPascalCase(str) { return str.replace(/(^|-)([a-z])/g, (match, p1, p2) => p2.toUpperCase()); } /** * 转换为camelCase */ toCamelCase(str) { return str.charAt(0).toLowerCase() + str.slice(1); } toPascalCase(str) { return str.charAt(0).toUpperCase() + str.slice(1); } /** * 确保目录存在 - 基于PHP实际存在的层级 */ ensureDir(dirPath) { // 检查是否应该创建这个目录(基于PHP实际存在的层级) if (this.shouldCreateDir(dirPath)) { if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } } } /** * 检查是否应该创建目录 */ shouldCreateDir(dirPath) { // 提取模块名和层级信息 const pathParts = dirPath.split('/'); const moduleIndex = pathParts.indexOf('common') + 1; if (moduleIndex < pathParts.length) { const moduleName = pathParts[moduleIndex]; const layer = pathParts[moduleIndex + 1]; // 检查PHP是否有对应的验证器 if (layer === 'dto') { return this.hasPHPValidators(moduleName); } } return true; // 默认创建 } /** * 检查模块是否有PHP验证器 */ hasPHPValidators(moduleName) { const phpProjectPath = path.join(__dirname, '../../niucloud-php/niucloud'); const validatePath = path.join(phpProjectPath, 'app/validate', moduleName); return fs.existsSync(validatePath); } /** * 输出统计报告 */ printStats() { console.log('\n📊 验证器生成统计报告'); console.log('=================================================='); console.log(`✅ 创建验证器数量: ${this.stats.validatorsCreated}`); console.log(`❌ 错误数量: ${this.stats.errors}`); console.log(`📈 成功率: ${this.stats.validatorsCreated > 0 ? '100.00%' : '0.00%'}`); } } // 如果直接运行此文件 if (require.main === module) { const generator = new ValidatorGenerator(); generator.run().catch(console.error); } module.exports = ValidatorGenerator;