240 lines
6.8 KiB
Dart
240 lines
6.8 KiB
Dart
#!/usr/bin/env dart
|
||
|
||
/// Augment 代码生成规范验证脚本
|
||
/// 用于验证生成的代码是否符合规范要求
|
||
|
||
import 'dart:convert';
|
||
import 'dart:io';
|
||
|
||
void main(List<String> args) async {
|
||
print('🔍 Augment 代码生成规范验证');
|
||
print('=' * 50);
|
||
|
||
final validator = StandardsValidator();
|
||
|
||
try {
|
||
await validator.validateAll();
|
||
print('\n✅ 所有检查通过!代码符合 Augment 规范。');
|
||
} catch (e) {
|
||
print('\n❌ 验证失败:$e');
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
class StandardsValidator {
|
||
final List<String> errors = [];
|
||
final List<String> warnings = [];
|
||
|
||
/// 验证所有规范
|
||
Future<void> validateAll() async {
|
||
print('📋 开始验证...\n');
|
||
|
||
await _validateSwaggerJson();
|
||
await _validateGeneratedFiles();
|
||
await _validateCodeQuality();
|
||
await _validateNamingConventions();
|
||
await _validateTypeConsistency();
|
||
|
||
_printResults();
|
||
|
||
if (errors.isNotEmpty) {
|
||
throw Exception('发现 ${errors.length} 个错误');
|
||
}
|
||
}
|
||
|
||
/// 验证 swagger.json
|
||
Future<void> _validateSwaggerJson() async {
|
||
print('🔍 验证 swagger.json...');
|
||
|
||
final swaggerFile = File('swagger.json');
|
||
if (!swaggerFile.existsSync()) {
|
||
errors.add('swagger.json 文件不存在');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
final content = await swaggerFile.readAsString();
|
||
final swagger = jsonDecode(content) as Map<String, dynamic>;
|
||
|
||
// 检查 OpenAPI 版本
|
||
final openapi = swagger['openapi'] as String?;
|
||
if (openapi == null || !openapi.startsWith('3.0')) {
|
||
errors.add('OpenAPI 版本必须是 3.0.x,当前:$openapi');
|
||
}
|
||
|
||
// 检查基本结构
|
||
if (!swagger.containsKey('paths')) {
|
||
errors.add('swagger.json 缺少 paths 定义');
|
||
}
|
||
|
||
if (!swagger.containsKey('components')) {
|
||
warnings.add('swagger.json 缺少 components 定义');
|
||
}
|
||
|
||
// 检查 schemas
|
||
final components = swagger['components'] as Map<String, dynamic>?;
|
||
if (components != null) {
|
||
final schemas = components['schemas'] as Map<String, dynamic>?;
|
||
if (schemas == null || schemas.isEmpty) {
|
||
warnings.add('components/schemas 为空,可能影响类型生成');
|
||
}
|
||
}
|
||
|
||
print(' ✅ swagger.json 格式正确');
|
||
} catch (e) {
|
||
errors.add('swagger.json 格式错误:$e');
|
||
}
|
||
}
|
||
|
||
/// 验证生成的文件
|
||
Future<void> _validateGeneratedFiles() async {
|
||
print('🔍 验证生成的文件...');
|
||
|
||
final generatorDir = Directory('generator');
|
||
if (!generatorDir.existsSync()) {
|
||
errors.add('generator 目录不存在');
|
||
return;
|
||
}
|
||
|
||
// 检查目录结构
|
||
final apiDir = Directory('generator/api');
|
||
final modelsDir = Directory('generator/api_models');
|
||
|
||
if (!apiDir.existsSync()) {
|
||
errors.add('generator/api 目录不存在');
|
||
}
|
||
|
||
if (!modelsDir.existsSync()) {
|
||
errors.add('generator/api_models 目录不存在');
|
||
}
|
||
|
||
// 检查 index.dart 文件
|
||
final indexFile = File('generator/api_models/index.dart');
|
||
if (!indexFile.existsSync()) {
|
||
warnings.add('generator/api_models/index.dart 文件不存在');
|
||
}
|
||
|
||
print(' ✅ 文件结构正确');
|
||
}
|
||
|
||
/// 验证代码质量
|
||
Future<void> _validateCodeQuality() async {
|
||
print('🔍 验证代码质量...');
|
||
|
||
// 运行 dart analyze
|
||
final analyzeResult = await Process.run('dart', ['analyze', 'generator/']);
|
||
|
||
if (analyzeResult.exitCode != 0) {
|
||
final output = analyzeResult.stdout.toString();
|
||
final errorOutput = analyzeResult.stderr.toString();
|
||
|
||
if (output.contains('error') || errorOutput.contains('error')) {
|
||
errors.add('dart analyze 发现错误:\n$output\n$errorOutput');
|
||
} else if (output.contains('warning') ||
|
||
errorOutput.contains('warning')) {
|
||
warnings.add('dart analyze 发现警告:\n$output\n$errorOutput');
|
||
}
|
||
} else {
|
||
print(' ✅ 静态分析通过');
|
||
}
|
||
}
|
||
|
||
/// 验证命名规范
|
||
Future<void> _validateNamingConventions() async {
|
||
print('🔍 验证命名规范...');
|
||
|
||
final apiDir = Directory('generator/api');
|
||
if (apiDir.existsSync()) {
|
||
await for (final file in apiDir.list()) {
|
||
if (file is File && file.path.endsWith('.dart')) {
|
||
final fileName = file.path.split('/').last;
|
||
|
||
// API 文件应该以 _api.dart 结尾
|
||
if (!fileName.endsWith('_api.dart')) {
|
||
errors.add('API 文件命名不规范:$fileName(应该以 _api.dart 结尾)');
|
||
}
|
||
|
||
// 检查文件名是否为 snake_case
|
||
final baseName = fileName.replaceAll('_api.dart', '');
|
||
if (!_isSnakeCase(baseName)) {
|
||
errors.add('API 文件名不是 snake_case:$fileName');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
final modelsDir = Directory('generator/api_models');
|
||
if (modelsDir.existsSync()) {
|
||
await for (final file in modelsDir.list()) {
|
||
if (file is File &&
|
||
file.path.endsWith('.dart') &&
|
||
!file.path.endsWith('index.dart')) {
|
||
final fileName = file.path.split('/').last;
|
||
final baseName = fileName.replaceAll('.dart', '');
|
||
|
||
// 检查模型文件名是否为 snake_case
|
||
if (!_isSnakeCase(baseName)) {
|
||
errors.add('模型文件名不是 snake_case:$fileName');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
print(' ✅ 命名规范检查完成');
|
||
}
|
||
|
||
/// 验证类型一致性
|
||
Future<void> _validateTypeConsistency() async {
|
||
print('🔍 验证类型一致性...');
|
||
|
||
// 检查是否有硬编码的类型推断
|
||
final generatorFile = File('lib/generators/retrofit_api_generator.dart');
|
||
if (generatorFile.existsSync()) {
|
||
final content = await generatorFile.readAsString();
|
||
|
||
// 检查是否还有硬编码的类型映射
|
||
final hardcodedPatterns = [
|
||
'TaskInfoResult',
|
||
'if.*contains.*login.*return',
|
||
'if.*contains.*task.*return',
|
||
'if.*tag.*contains.*return',
|
||
];
|
||
|
||
for (final pattern in hardcodedPatterns) {
|
||
final regex = RegExp(pattern, caseSensitive: false);
|
||
if (regex.hasMatch(content)) {
|
||
errors.add('发现硬编码类型推断:$pattern');
|
||
}
|
||
}
|
||
}
|
||
|
||
print(' ✅ 类型一致性检查完成');
|
||
}
|
||
|
||
/// 检查是否为 snake_case
|
||
bool _isSnakeCase(String name) {
|
||
return RegExp(r'^[a-z][a-z0-9_]*$').hasMatch(name);
|
||
}
|
||
|
||
/// 打印验证结果
|
||
void _printResults() {
|
||
print('\n📊 验证结果:');
|
||
print(' 错误:${errors.length}');
|
||
print(' 警告:${warnings.length}');
|
||
|
||
if (errors.isNotEmpty) {
|
||
print('\n❌ 错误列表:');
|
||
for (int i = 0; i < errors.length; i++) {
|
||
print(' ${i + 1}. ${errors[i]}');
|
||
}
|
||
}
|
||
|
||
if (warnings.isNotEmpty) {
|
||
print('\n⚠️ 警告列表:');
|
||
for (int i = 0; i < warnings.length; i++) {
|
||
print(' ${i + 1}. ${warnings[i]}');
|
||
}
|
||
}
|
||
}
|
||
}
|