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/index.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 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 execute(List args) async { try { final parsedArgs = parseArguments(args); validateArguments(parsedArgs); await prepare(parsedArgs); final config = ConfigRepository.loadSync(); progress('正在解析 ${config.swaggerUrls.length} 个 Swagger 文档...'); final urls = config.swaggerUrls; progress('URL 处理顺序: ${urls.join(" -> ")}'); final mergedDocument = await _documentMergeService.fetchAndMerge( urls, progress: progress, ); if (mergedDocument == null) { appLogger.severe('❌ 没有成功解析任何 Swagger 文档'); return 1; } success('成功合并 ${config.swaggerUrls.length} 个 Swagger 文档'); final options = _parseGenerateOptions(parsedArgs); final document = _documentFilterService.filter( document: mergedDocument, includedTags: options.includedTags, excludedTags: options.excludedTags, progress: progress, ); // 使用配置的输出目录 final baseDir = config.baseDir; final apiDir = config.apiDir; final modelsDir = config.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? includedTags; final includedTagsStr = args.getOption('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('split-by-tags') ?? true; progress('📂 [命令行] 按 tags 分组: ${splitByTags ? "是" : "否"}'); } else { // 从配置文件读取 final config = ConfigRepository.loadSync(); splitByTags = config.splitByTags; progress('📂 [配置文件] 按 tags 分组: ${splitByTags ? "是" : "否"}'); } // 解析 excluded-tags 参数 // 优先级:命令行参数 > 配置文件 List? excludedTags; final excludedTagsStr = args.getOption('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('models') ?? false) : (args.getOption('all') ?? true), generateApi: hasAnyFlag ? (args.getOption('api') ?? false) : (args.getOption('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? includedTags; final List? excludedTags; }