feat: 发布 v1 智能框架 0.1.0 版本
🚀 新增功能: - wwjcloud-nest-v1: 完整的 NestJS 智能框架 - AI 自愈机制: @wwjcloud/auto-healing 模块 - 智能代码生成: tools-v1/php-tools 迁移工具链 - AI 能力规划: v1/docs/AI-CAPABILITY-ROADMAP.md 📦 核心模块: - libs/wwjcloud-ai: AI 策略和恢复服务 - libs/wwjcloud-boot: 启动和配置管理 - libs/wwjcloud-core: 核心基础设施 - libs/wwjcloud-addon: 插件系统 🏗️ 架构特性: - 分层渐进式 AI 策略 - 微服务导向的模块化设计 - 与 PHP 项目 100% 业务一致性 - Docker 容器化部署支持 📋 版本信息: - 版本: v0.1.0 - 发布日期: 2025-01-25 - 分支: v1
This commit is contained in:
372
tools-v1/php-tools/generators/validator-generator.js
Normal file
372
tools-v1/php-tools/generators/validator-generator.js
Normal file
@@ -0,0 +1,372 @@
|
||||
#!/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: '${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;
|
||||
Reference in New Issue
Block a user