swagger_generator_flutter/lib/commands/generate_command.dart

232 lines
7.7 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 '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;
}