232 lines
7.7 KiB
Dart
232 lines
7.7 KiB
Dart
import 'package:swagger_generator_flutter/commands/base_command.dart';
|
||
import 'package:swagger_generator_flutter/commands/services/document_filter_service.dart';
|
||
import 'package:swagger_generator_flutter/commands/services/document_merge_service.dart';
|
||
import 'package:swagger_generator_flutter/commands/services/generation_output_service.dart';
|
||
import 'package:swagger_generator_flutter/core/config.dart';
|
||
import 'package:swagger_generator_flutter/core/config_repository.dart';
|
||
import 'package:swagger_generator_flutter/utils/logger.dart';
|
||
|
||
/// Generate命令
|
||
/// 用于生成各种代码文件
|
||
class GenerateCommand extends BaseCommand {
|
||
GenerateCommand({
|
||
DocumentMergeService? documentMergeService,
|
||
DocumentFilterService? documentFilterService,
|
||
GenerationOutputService? generationOutputService,
|
||
}) : _documentMergeService = documentMergeService ?? DocumentMergeService(),
|
||
_documentFilterService =
|
||
documentFilterService ?? DocumentFilterService(),
|
||
_generationOutputService =
|
||
generationOutputService ?? const GenerationOutputService();
|
||
|
||
final DocumentMergeService _documentMergeService;
|
||
final DocumentFilterService _documentFilterService;
|
||
final GenerationOutputService _generationOutputService;
|
||
@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: 'models',
|
||
shortName: 'm',
|
||
description: '生成数据模型',
|
||
),
|
||
const CommandOption(
|
||
name: 'api',
|
||
shortName: 'r',
|
||
description: '生成Retrofit风格API接口',
|
||
),
|
||
const CommandOption(
|
||
name: 'split-by-tags',
|
||
shortName: 't',
|
||
description: '按tags分组生成多个API文件(默认启用)',
|
||
),
|
||
const CommandOption(
|
||
name: 'all',
|
||
shortName: 'a',
|
||
description: '生成所有文件(默认)',
|
||
),
|
||
const CommandOption(
|
||
name: 'output-dir',
|
||
shortName: 'o',
|
||
description: '输出目录',
|
||
type: OptionType.string,
|
||
defaultValue: 'generator',
|
||
),
|
||
const CommandOption(
|
||
name: 'included-tags',
|
||
shortName: 'i',
|
||
description: '只生成指定tags的API和模型(逗号分隔,如:User,Pet,Store)',
|
||
type: OptionType.string,
|
||
),
|
||
const CommandOption(
|
||
name: 'excluded-tags',
|
||
shortName: 'e',
|
||
description: '从生成中排除指定的tags(逗号分隔)',
|
||
type: OptionType.string,
|
||
),
|
||
];
|
||
|
||
@override
|
||
Future<int> execute(List<String> args) async {
|
||
try {
|
||
final parsedArgs = parseArguments(args);
|
||
validateArguments(parsedArgs);
|
||
|
||
await prepare(parsedArgs);
|
||
|
||
progress('正在解析 ${SwaggerConfig.swaggerJsonUrls.length} 个 Swagger 文档...');
|
||
final urls = SwaggerConfig.swaggerJsonUrls;
|
||
progress('URL 处理顺序: ${urls.join(" -> ")}');
|
||
|
||
final mergedDocument = await _documentMergeService.fetchAndMerge(
|
||
urls,
|
||
progress: progress,
|
||
);
|
||
|
||
if (mergedDocument == null) {
|
||
appLogger.severe('❌ 没有成功解析任何 Swagger 文档');
|
||
return 1;
|
||
}
|
||
|
||
success('成功合并 ${SwaggerConfig.swaggerJsonUrls.length} 个 Swagger 文档');
|
||
|
||
final options = _parseGenerateOptions(parsedArgs);
|
||
|
||
final document = _documentFilterService.filter(
|
||
document: mergedDocument,
|
||
includedTags: options.includedTags,
|
||
excludedTags: options.excludedTags,
|
||
progress: progress,
|
||
);
|
||
|
||
// 使用配置的输出目录
|
||
final baseDir = SwaggerConfig.generatorDir;
|
||
final apiDir = SwaggerConfig.apiDir;
|
||
final modelsDir = SwaggerConfig.modelsDir;
|
||
|
||
progress('输出目录: $baseDir');
|
||
progress('API 目录: $apiDir');
|
||
progress('模型目录: $modelsDir');
|
||
|
||
final generatedFiles = await _generationOutputService.generateOutputs(
|
||
document: document,
|
||
options: options,
|
||
baseDir: baseDir,
|
||
apiDir: apiDir,
|
||
modelsDir: modelsDir,
|
||
progress: progress,
|
||
success: success,
|
||
);
|
||
|
||
success('代码生成完成!共生成 $generatedFiles 个文件');
|
||
return 0;
|
||
} on Exception catch (e, stackTrace) {
|
||
appLogger.severe('❌ 生成失败', e, stackTrace);
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
/// 解析生成选项
|
||
GenerateOptions _parseGenerateOptions(ParsedArguments args) {
|
||
final hasAnyFlag = args.hasOption('models') || args.hasOption('api');
|
||
|
||
// 解析 included-tags 参数
|
||
// 优先级:命令行参数 > 配置文件
|
||
List<String>? includedTags;
|
||
final includedTagsStr = args.getOption<String>('included-tags');
|
||
if (includedTagsStr != null && includedTagsStr.isNotEmpty) {
|
||
// 从命令行参数读取
|
||
includedTags = includedTagsStr
|
||
.split(',')
|
||
.map((tag) => tag.trim())
|
||
.where((tag) => tag.isNotEmpty)
|
||
.toList();
|
||
|
||
if (includedTags.isNotEmpty) {
|
||
progress('🏷️ [命令行] 只生成以下 tags: ${includedTags.join(", ")}');
|
||
}
|
||
} else {
|
||
// 从配置文件读取
|
||
final config = ConfigRepository.loadSync();
|
||
includedTags = config.includedTags;
|
||
if (includedTags != null && includedTags.isNotEmpty) {
|
||
progress('🏷️ [配置文件] 只生成以下 tags: ${includedTags.join(", ")}');
|
||
}
|
||
}
|
||
|
||
// 解析 split-by-tags 参数
|
||
// 优先级:命令行参数 > 配置文件 > 默认值(true)
|
||
bool splitByTags;
|
||
if (args.hasOption('split-by-tags')) {
|
||
// 从命令行参数读取
|
||
splitByTags = args.getOption<bool>('split-by-tags') ?? true;
|
||
progress('📂 [命令行] 按 tags 分组: ${splitByTags ? "是" : "否"}');
|
||
} else {
|
||
// 从配置文件读取
|
||
final config = ConfigRepository.loadSync();
|
||
splitByTags = config.splitByTags;
|
||
progress('📂 [配置文件] 按 tags 分组: ${splitByTags ? "是" : "否"}');
|
||
}
|
||
|
||
// 解析 excluded-tags 参数
|
||
// 优先级:命令行参数 > 配置文件
|
||
List<String>? excludedTags;
|
||
final excludedTagsStr = args.getOption<String>('excluded-tags');
|
||
if (excludedTagsStr != null && excludedTagsStr.isNotEmpty) {
|
||
// 从命令行参数读取
|
||
excludedTags = excludedTagsStr
|
||
.split(',')
|
||
.map((tag) => tag.trim())
|
||
.where((tag) => tag.isNotEmpty)
|
||
.toList();
|
||
|
||
if (excludedTags.isNotEmpty) {
|
||
progress('🚫 [命令行] 排除以下 tags: ${excludedTags.join(", ")}');
|
||
}
|
||
} else {
|
||
// 从配置文件读取
|
||
final config = ConfigRepository.loadSync();
|
||
excludedTags = config.excludedTags;
|
||
if (excludedTags != null && excludedTags.isNotEmpty) {
|
||
progress('🚫 [配置文件] 排除以下 tags: ${excludedTags.join(", ")}');
|
||
}
|
||
}
|
||
|
||
return GenerateOptions(
|
||
generateModels: hasAnyFlag
|
||
? (args.getOption<bool>('models') ?? false)
|
||
: (args.getOption<bool>('all') ?? true),
|
||
generateApi: hasAnyFlag
|
||
? (args.getOption<bool>('api') ?? false)
|
||
: (args.getOption<bool>('all') ?? true),
|
||
splitByTags: splitByTags,
|
||
includedTags: includedTags,
|
||
excludedTags: excludedTags,
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 生成选项
|
||
class GenerateOptions {
|
||
const GenerateOptions({
|
||
required this.generateModels,
|
||
required this.generateApi,
|
||
required this.splitByTags,
|
||
this.includedTags,
|
||
this.excludedTags,
|
||
});
|
||
final bool generateModels;
|
||
final bool generateApi;
|
||
final bool splitByTags;
|
||
final List<String>? includedTags;
|
||
final List<String>? excludedTags;
|
||
}
|