313 lines
10 KiB
Dart
313 lines
10 KiB
Dart
import '../core/models.dart';
|
||
import '../generators/documentation_generator.dart';
|
||
import '../generators/endpoint_code_generator.dart';
|
||
import '../generators/model_code_generator.dart';
|
||
import '../generators/retrofit_api_generator.dart';
|
||
import '../parsers/swagger_data_parser.dart';
|
||
import '../utils/file_utils.dart';
|
||
import 'base_command.dart';
|
||
|
||
/// Generate命令
|
||
/// 用于生成各种代码文件
|
||
class GenerateCommand extends BaseCommand {
|
||
@override
|
||
String get name => 'generate';
|
||
|
||
@override
|
||
String get description => '生成API代码文件(模型、端点、文档等)';
|
||
|
||
@override
|
||
String get usage => 'dart swagger_cli.dart generate [options]';
|
||
|
||
@override
|
||
List<CommandOption> get options => [
|
||
const CommandOption(
|
||
name: 'endpoints',
|
||
shortName: 'e',
|
||
description: '生成API端点常量',
|
||
type: OptionType.flag,
|
||
),
|
||
const CommandOption(
|
||
name: 'models',
|
||
shortName: 'm',
|
||
description: '生成数据模型',
|
||
type: OptionType.flag,
|
||
),
|
||
const CommandOption(
|
||
name: 'docs',
|
||
shortName: 'd',
|
||
description: '生成API文档',
|
||
type: OptionType.flag,
|
||
),
|
||
const CommandOption(
|
||
name: 'api',
|
||
shortName: 'r',
|
||
description: '生成Retrofit风格API接口',
|
||
type: OptionType.flag,
|
||
),
|
||
const CommandOption(
|
||
name: 'split-by-tags',
|
||
shortName: 't',
|
||
description: '按tags分组生成多个API文件',
|
||
type: OptionType.flag,
|
||
),
|
||
const CommandOption(
|
||
name: 'all',
|
||
shortName: 'a',
|
||
description: '生成所有文件(默认)',
|
||
type: OptionType.flag,
|
||
),
|
||
const CommandOption(
|
||
name: 'simple',
|
||
shortName: 's',
|
||
description: '使用简洁版模型生成',
|
||
type: OptionType.flag,
|
||
),
|
||
const CommandOption(
|
||
name: 'output-dir',
|
||
shortName: 'o',
|
||
description: '输出目录',
|
||
type: OptionType.string,
|
||
defaultValue: 'generator',
|
||
),
|
||
];
|
||
|
||
@override
|
||
Future<int> execute(List<String> args) async {
|
||
try {
|
||
final parsedArgs = parseArguments(args);
|
||
validateArguments(parsedArgs);
|
||
|
||
await prepare(parsedArgs);
|
||
|
||
// 解析Swagger文档
|
||
progress('正在解析Swagger文档...');
|
||
final parser = SwaggerDataParser();
|
||
final document = await parser.fetchAndParseSwaggerDocument();
|
||
|
||
// 解析生成选项
|
||
final options = _parseGenerateOptions(parsedArgs);
|
||
final outputDir =
|
||
parsedArgs.getOption<String>('output-dir') ?? 'generator';
|
||
final fullOutputDir = FileUtils.getProjectRootGeneratorDir();
|
||
|
||
progress('输出目录: $fullOutputDir');
|
||
|
||
// 确保输出目录存在
|
||
await FileUtils.ensureDirectoryExists(fullOutputDir);
|
||
|
||
int generatedFiles = 0;
|
||
|
||
// 生成端点代码
|
||
if (options.generateEndpoints) {
|
||
progress('正在生成API端点常量...');
|
||
final generator = EndpointCodeGenerator(document);
|
||
final code = generator.generate();
|
||
|
||
final filePath = '$fullOutputDir/api_paths.dart';
|
||
await FileUtils.writeFile(filePath, code);
|
||
success('API端点常量已保存到: $filePath');
|
||
generatedFiles++;
|
||
}
|
||
|
||
// 生成模型代码
|
||
if (options.generateModels) {
|
||
progress('正在生成数据模型...');
|
||
final generator = ModelCodeGenerator(
|
||
document,
|
||
useSimpleModels: options.useSimpleModels,
|
||
);
|
||
|
||
final modelsDir = '$fullOutputDir/api_models';
|
||
await FileUtils.ensureDirectoryExists(modelsDir);
|
||
|
||
final modelFiles = generator.generateSeparateModelFiles();
|
||
|
||
for (final entry in modelFiles.entries) {
|
||
final filePath = '$modelsDir/${entry.key}';
|
||
await FileUtils.writeFile(filePath, entry.value);
|
||
success('模型文件已保存到: $filePath');
|
||
generatedFiles++;
|
||
}
|
||
}
|
||
|
||
// 生成 Retrofit 风格的 API 接口
|
||
if (options.generateApi) {
|
||
if (options.splitByTags) {
|
||
progress('正在按tags分组生成Retrofit风格API接口...');
|
||
final generator = RetrofitApiGenerator(
|
||
document,
|
||
className: 'ApiClient',
|
||
useRetrofit: true,
|
||
useDio: true,
|
||
splitByTags: true,
|
||
);
|
||
|
||
// 确保参数实体类已生成
|
||
generator.ensureParameterEntitiesGenerated();
|
||
|
||
// 生成按 tags 分组的多个 API 文件
|
||
final tagApiFiles = generator.generateApiFilesByTags();
|
||
|
||
final apiDir = '$fullOutputDir/api';
|
||
await FileUtils.ensureDirectoryExists(apiDir);
|
||
|
||
for (final entry in tagApiFiles.entries) {
|
||
final fileName = entry.key;
|
||
final code = entry.value;
|
||
final filePath = '$apiDir/$fileName';
|
||
await FileUtils.writeFile(filePath, code);
|
||
success('API接口文件已保存到: $filePath');
|
||
generatedFiles++;
|
||
}
|
||
|
||
// 生成主 API 文件
|
||
final mainCode = generator.generateMainApiFile();
|
||
final mainFilePath = '$apiDir/api_client.dart';
|
||
await FileUtils.writeFile(mainFilePath, mainCode);
|
||
success('主API接口文件已保存到: $mainFilePath');
|
||
generatedFiles++;
|
||
|
||
// 生成参数实体类文件
|
||
final parameterEntityFiles = generator.generateParameterEntityFiles();
|
||
if (parameterEntityFiles.isNotEmpty) {
|
||
final modelsDir = '$fullOutputDir/api_models';
|
||
await FileUtils.ensureDirectoryExists(modelsDir);
|
||
|
||
for (final entry in parameterEntityFiles.entries) {
|
||
final filePath = '$modelsDir/${entry.key}';
|
||
await FileUtils.writeFile(filePath, entry.value);
|
||
success('参数实体类文件已保存到: $filePath');
|
||
generatedFiles++;
|
||
}
|
||
}
|
||
} else {
|
||
progress('正在生成Retrofit风格API接口...');
|
||
final generator = RetrofitApiGenerator(
|
||
document,
|
||
className: 'ApiClient',
|
||
useRetrofit: true,
|
||
useDio: true,
|
||
splitByTags: false,
|
||
);
|
||
|
||
// 确保参数实体类已生成
|
||
generator.ensureParameterEntitiesGenerated();
|
||
|
||
final code = generator.generate();
|
||
|
||
final apiDir = '$fullOutputDir/api';
|
||
await FileUtils.ensureDirectoryExists(apiDir);
|
||
|
||
final filePath = '$apiDir/api.dart';
|
||
await FileUtils.writeFile(filePath, code);
|
||
success('Retrofit API接口已保存到: $filePath');
|
||
generatedFiles++;
|
||
|
||
// 生成参数实体类文件
|
||
final parameterEntityFiles = generator.generateParameterEntityFiles();
|
||
if (parameterEntityFiles.isNotEmpty) {
|
||
final modelsDir = '$fullOutputDir/api_models';
|
||
await FileUtils.ensureDirectoryExists(modelsDir);
|
||
|
||
for (final entry in parameterEntityFiles.entries) {
|
||
final filePath = '$modelsDir/${entry.key}';
|
||
await FileUtils.writeFile(filePath, entry.value);
|
||
success('参数实体类文件已保存到: $filePath');
|
||
generatedFiles++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 生成文档
|
||
if (options.generateDocs) {
|
||
progress('正在生成API文档...');
|
||
final generator = DocumentationGenerator(document);
|
||
final code = generator.generate();
|
||
|
||
final filePath = '$fullOutputDir/api_documentation.md';
|
||
await FileUtils.writeFile(filePath, code);
|
||
success('API文档已保存到: $filePath');
|
||
generatedFiles++;
|
||
}
|
||
|
||
// 生成摘要
|
||
_generateSummary(document, fullOutputDir);
|
||
|
||
success('代码生成完成!共生成 $generatedFiles 个文件');
|
||
return 0;
|
||
} catch (e) {
|
||
print('❌ 生成失败: $e');
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
/// 解析生成选项
|
||
GenerateOptions _parseGenerateOptions(ParsedArguments args) {
|
||
final hasAnyFlag = args.hasOption('endpoints') ||
|
||
args.hasOption('models') ||
|
||
args.hasOption('docs') ||
|
||
args.hasOption('api');
|
||
|
||
return GenerateOptions(
|
||
generateEndpoints: hasAnyFlag
|
||
? (args.getOption<bool>('endpoints') ?? false)
|
||
: (args.getOption<bool>('all') ?? true),
|
||
generateModels: hasAnyFlag
|
||
? (args.getOption<bool>('models') ?? false)
|
||
: (args.getOption<bool>('all') ?? true),
|
||
generateDocs: hasAnyFlag
|
||
? (args.getOption<bool>('docs') ?? false)
|
||
: (args.getOption<bool>('all') ?? true),
|
||
generateApi: hasAnyFlag
|
||
? (args.getOption<bool>('api') ?? false)
|
||
: (args.getOption<bool>('all') ?? true),
|
||
useSimpleModels: args.getOption<bool>('simple') ?? false,
|
||
splitByTags: args.getOption<bool>('split-by-tags') ?? false,
|
||
);
|
||
}
|
||
|
||
/// 生成摘要信息
|
||
void _generateSummary(SwaggerDocument document, String outputDir) {
|
||
final summary = StringBuffer();
|
||
summary.writeln('# 代码生成摘要');
|
||
summary.writeln('');
|
||
summary.writeln('**API标题**: ${document.title}');
|
||
summary.writeln('**API版本**: ${document.version}');
|
||
summary.writeln('**生成时间**: ${DateTime.now().toIso8601String()}');
|
||
summary.writeln('');
|
||
summary.writeln('## 统计信息');
|
||
summary.writeln('- 控制器数量: ${document.controllers.length}');
|
||
summary.writeln('- API路径数量: ${document.paths.length}');
|
||
summary.writeln('- 数据模型数量: ${document.models.length}');
|
||
summary.writeln('');
|
||
summary.writeln('## 控制器列表');
|
||
document.controllers.forEach((name, controller) {
|
||
summary.writeln(
|
||
'- **$name**: ${controller.description} (${controller.paths.length} 个路径)');
|
||
});
|
||
|
||
FileUtils.writeFile('$outputDir/SUMMARY.md', summary.toString());
|
||
}
|
||
}
|
||
|
||
/// 生成选项
|
||
class GenerateOptions {
|
||
final bool generateEndpoints;
|
||
final bool generateModels;
|
||
final bool generateDocs;
|
||
final bool generateApi;
|
||
final bool useSimpleModels;
|
||
final bool splitByTags;
|
||
|
||
const GenerateOptions({
|
||
required this.generateEndpoints,
|
||
required this.generateModels,
|
||
required this.generateDocs,
|
||
required this.generateApi,
|
||
required this.useSimpleModels,
|
||
required this.splitByTags,
|
||
});
|
||
}
|