swagger_generator_flutter/lib/commands/generate_command.dart

341 lines
11 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:io';
import 'package:path/path.dart' as path;
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 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) {
progress('正在按tags分组生成Retrofit风格API接口...');
final generator = RetrofitApiGenerator(
className: 'ApiClient',
useRetrofit: true,
useDio: true,
splitByTags: true, // 强制使用拆分模式
);
// 设置文档
generator.document = document;
// 确保参数实体类已生成
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++;
}
}
}
// 重新生成 index.dart 文件,包含所有生成的文件
if (options.generateModels || options.generateApi) {
progress('正在重新生成 index.dart 文件...');
final modelsDir = '$fullOutputDir/api_models';
final allFiles = await _getAllModelFiles(modelsDir);
final indexContent = _generateUpdatedIndexFile(allFiles);
final indexPath = '$modelsDir/index.dart';
await FileUtils.writeFile(indexPath, indexContent);
success('index.dart 文件已更新');
}
// 生成文档
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') ?? true, // 默认启用拆分模式
);
}
/// 获取所有模型文件列表
Future<List<String>> _getAllModelFiles(String modelsDir) async {
try {
final directory = Directory(modelsDir);
if (!await directory.exists()) {
return [];
}
final files = await directory.list().toList();
final dartFiles = <String>[];
for (final entity in files) {
if (entity is File && entity.path.endsWith('.dart')) {
final fileName = path.basename(entity.path);
// 排除 index.dart 本身和 .g.dart 文件
if (fileName != 'index.dart' && !fileName.endsWith('.g.dart')) {
dartFiles.add(fileName);
}
}
}
// 按文件名排序
dartFiles.sort();
return dartFiles;
} catch (e) {
print('获取模型文件列表失败: $e');
return [];
}
}
/// 生成更新的 index.dart 文件内容
String _generateUpdatedIndexFile(List<String> fileNames) {
final buffer = StringBuffer();
// 生成文件头
buffer.writeln('// API 模型导出文件');
buffer.writeln('// 基于 Swagger API 文档: ');
buffer.writeln('// 由 xy_swagger_generator by max 生成');
buffer.writeln('// Copyright (C) 2025 YuanXuan. All rights reserved.');
buffer.writeln('');
buffer.writeln('library;');
buffer.writeln('');
// 导出所有文件
for (final fileName in fileNames) {
buffer.writeln('export \'$fileName\';');
}
return buffer.toString();
}
/// 生成摘要信息
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,
});
}