import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import 'package:logging/logging.dart'; import 'package:swagger_generator_flutter/core/config.dart'; import 'package:swagger_generator_flutter/core/exceptions.dart'; import 'package:swagger_generator_flutter/core/models.dart'; import 'package:swagger_generator_flutter/utils/cache_manager.dart'; import 'package:swagger_generator_flutter/utils/performance_monitor.dart'; import 'package:swagger_generator_flutter/utils/reference_resolver.dart'; import 'package:swagger_generator_flutter/utils/string_utils.dart'; /// Swagger数据解析器 /// 负责解析Swagger JSON文档并提取相关信息 class SwaggerDataParser { SwaggerDataParser() : _cacheManager = CacheManager(), _performanceMonitor = PerformanceMonitor(); final CacheManager _cacheManager; final PerformanceMonitor _performanceMonitor; static final Logger _logger = Logger('SwaggerDataParser'); // 缓存解析结果 final Map _cachedDocuments = {}; /// 获取并解析Swagger JSON文档 /// [url] 可选参数,如果不传则使用配置中的第一个 URL Future fetchAndParseSwaggerDocument([String? url]) async { final swaggerUrl = url ?? SwaggerConfig.swaggerJsonUrls.first; // 如果有缓存,直接返回缓存结果 if (_cachedDocuments.containsKey(swaggerUrl)) { _logger.info('📦 使用缓存的文档: $swaggerUrl'); return _cachedDocuments[swaggerUrl]!; } return _performanceMonitor.measure( 'fetchAndParseSwaggerDocument', () async { try { print('🔄 正在获取Swagger JSON文档: $swaggerUrl'); Map jsonData; if (swaggerUrl.startsWith('file://')) { // 处理本地文件 final filePath = swaggerUrl.replaceFirst('file://', ''); final file = File(filePath); if (file.existsSync()) { final content = file.readAsStringSync(); jsonData = json.decode(content) as Map; } else { throw SwaggerParseException( '本地文件不存在', url: swaggerUrl, details: '文件路径: $filePath', ); } } else { // 处理远程URL final response = await http.get( Uri.parse(swaggerUrl), headers: SwaggerConfig.httpHeaders, ); if (response.statusCode == 200) { jsonData = json.decode(response.body) as Map; } else { throw SwaggerParseException( 'HTTP请求失败', url: swaggerUrl, statusCode: response.statusCode, details: 'HTTP响应状态码: ${response.statusCode}', ); } } final document = await parseSwaggerDocument(jsonData); _cachedDocuments[swaggerUrl] = document; _logger.info('✅ Swagger文档解析完成'); return document; } on Object catch (e) { if (e is SwaggerParseException) { rethrow; } throw SwaggerParseException( '获取Swagger文档失败', url: swaggerUrl, details: e.toString(), ); } }, ); } /// 解析Swagger JSON文档 Future parseSwaggerDocument( Map jsonData, ) async { return _performanceMonitor.measure('parseSwaggerDocument', () async { // 尝试从缓存获取 final cacheKey = 'swagger_doc_${jsonData.hashCode}'; final cachedResult = _cacheManager.get(cacheKey); if (cachedResult != null) { // 将缓存结果存储到 map 中(使用第一个 URL 作为 key) _cachedDocuments[SwaggerConfig.swaggerJsonUrls.first] = cachedResult; return cachedResult; } // 解析文档基本信息 final info = jsonData['info'] as Map? ?? {}; final title = info['title'] as String? ?? 'API Documentation'; final version = info['version'] as String? ?? '1.0.0'; final description = info['description'] as String? ?? ''; // ✨ 分析 schema 使用情况(在解析 components 之前) final schemaUsage = _analyzeSchemaUsage(jsonData); // 解析 servers (OpenAPI 3.0) final servers = _parseServers(jsonData); // 解析 components (OpenAPI 3.0),传入使用情况分析结果 final components = _parseComponents(jsonData, schemaUsage); // 解析tags信息 (用于获取控制器描述) final tagsInfo = _parseTagsInfo(jsonData); // 解析API路径 final paths = _parseApiPaths(jsonData); // 解析API模型 (从 components 中提取) final models = components.schemas; // 解析API控制器 (传入tags信息) final controllers = _parseApiControllers(paths, tagsInfo); final document = SwaggerDocument( title: title, version: version, description: description, servers: servers, components: components, paths: paths, models: models, controllers: controllers, ); // 缓存结果 _cacheManager.put(cacheKey, document); _cachedDocuments[SwaggerConfig.swaggerJsonUrls.first] = document; return document; }); } /// 解析 servers 配置 (OpenAPI 3.0) List _parseServers(Map jsonData) { final servers = []; try { final serversJson = jsonData['servers'] as List?; if (serversJson != null) { for (final serverJson in serversJson) { if (serverJson is Map) { final server = ApiServer.fromJson(serverJson); servers.add(server); } } } // 如果没有 servers 配置,提供默认值 if (servers.isEmpty) { servers.add(const ApiServer(url: '/')); } } on Object catch (e) { _logger.warning('⚠️ 解析servers配置时发生错误: $e'); // 提供默认服务器配置 servers.add(const ApiServer(url: '/')); } return servers; } /// 解析 components 配置 (OpenAPI 3.0) ApiComponents _parseComponents( Map jsonData, Map> schemaUsage, ) { try { final componentsJson = jsonData['components'] as Map?; if (componentsJson != null) { // 使用引用解析器处理复杂嵌套和循环引用 final resolver = ReferenceResolver(); final resolvedSchemas = resolver.resolveModels(componentsJson); // ✨ 根据使用情况更新模型的 usageType final schemasWithUsageType = {}; resolvedSchemas.forEach((name, model) { final usages = schemaUsage[name] ?? {}; final ModelUsageType usageType; if (usages.isEmpty) { usageType = ModelUsageType.unknown; } else if (usages.length == 1) { usageType = usages.first; } else { // 既用于请求又用于响应 usageType = ModelUsageType.common; } schemasWithUsageType[name] = model.copyWithUsageType(usageType); }); // 创建 ApiComponents,但使用解析后的 schemas final components = ApiComponents.fromJson(componentsJson); return ApiComponents( schemas: schemasWithUsageType, responses: components.responses, parameters: components.parameters, examples: components.examples, requestBodies: components.requestBodies, headers: components.headers, securitySchemes: components.securitySchemes, links: components.links, callbacks: components.callbacks, ); } } on Object catch (e) { _logger.warning('⚠️ 解析components配置时发生错误: $e'); } return const ApiComponents(); } /// 解析tags信息 Map _parseTagsInfo(Map jsonData) { final tagsInfo = {}; try { final tags = jsonData['tags'] as List?; if (tags != null) { for (final tag in tags) { if (tag is Map) { final name = tag['name'] as String?; final description = tag['description'] as String?; if (name != null && description != null) { tagsInfo[name] = description; } } } } } on Object catch (e) { _logger.warning('⚠️ 解析tags信息时发生错误: $e'); } return tagsInfo; } /// 解析API路径 Map _parseApiPaths(Map jsonData) { final paths = {}; final pathsData = jsonData['paths'] as Map?; if (pathsData == null) { throw SwaggerParseException('未发现API路径定义'); } try { pathsData.forEach((pathKey, pathValue) { if (pathValue is Map) { pathValue.forEach((methodKey, methodValue) { if (methodValue is Map) { final method = HttpMethod.fromString(methodKey); final apiPath = ApiPath.fromJson( pathKey, method, methodValue, ); final key = '${method.value.toUpperCase()}_' '${pathKey.replaceAll('/', '_')}'; paths[key] = apiPath; } }); } }); } catch (e) { throw SwaggerParseException('解析API路径失败', details: e.toString()); } return paths; } /// 解析API控制器 Map _parseApiControllers( Map paths, Map tagsInfo, ) { final controllers = >{}; try { // 根据tags分组API路径 for (final apiPath in paths.values) { for (final tag in apiPath.tags) { controllers.putIfAbsent(tag, () => []).add(apiPath); } } // 创建控制器对象 final result = {}; controllers.forEach((name, pathList) { // 从tags信息中获取描述 final swaggerDescription = tagsInfo[name]; // 使用通用的描述获取方法 final description = SwaggerConfig.getControllerDescription( name, swaggerDescription: swaggerDescription, ); result[name] = ApiController( name: name, description: description, paths: pathList, ); }); return result; } catch (e) { throw SwaggerParseException('解析API控制器失败', details: e.toString()); } } /// 解析属性类型 String parsePropertyType(Map propData) { try { // 直接类型 if (propData['type'] != null) { return propData['type'] as String; } // 引用类型 ($ref) if (propData[r'$ref'] != null) { final ref = propData[r'$ref'] as String; // 从 #/components/schemas/ModelName 或 #/definitions/ModelName 中提取类型名 final parts = ref.split('/'); if (parts.isNotEmpty) { return parts.last; } } // 数组类型 if (propData['items'] != null) { final items = propData['items'] as Map; final itemType = parsePropertyType(items); return 'array<$itemType>'; } // 默认类型 return 'string'; } catch (e) { throw SwaggerParseException('解析属性类型失败', details: e.toString()); } } /// 获取Dart类型映射 String getDartType(String swaggerType, String? format) { switch (swaggerType.toLowerCase()) { case 'string': switch (format?.toLowerCase()) { case 'date': case 'date-time': return 'DateTime'; case 'byte': case 'binary': return 'String'; default: return 'String'; } case 'integer': switch (format?.toLowerCase()) { case 'int64': return 'int'; case 'int32': default: return 'int'; } case 'number': switch (format?.toLowerCase()) { case 'float': case 'double': return 'double'; default: return 'double'; } case 'boolean': return 'bool'; case 'array': return 'List'; case 'object': return 'Map'; case 'file': return 'String'; default: // 检查是否为数组类型 if (swaggerType.startsWith('array<') && swaggerType.endsWith('>')) { final itemType = swaggerType.substring(6, swaggerType.length - 1); final dartItemType = getDartType(itemType, null); return 'List<$dartItemType>'; } // 默认为自定义类型 return StringUtils.generateClassName(swaggerType); } } /// 清除缓存 void clearCache() { _cachedDocuments.clear(); _cacheManager.clear(); } /// 获取文档统计信息 Map getDocumentStats() { if (_cachedDocuments.isEmpty) { return {}; } // 使用第一个缓存的文档 final doc = _cachedDocuments.values.first; // 统计HTTP方法 final methodStats = {}; for (final path in doc.paths.values) { final method = path.method.value; methodStats[method] = (methodStats[method] ?? 0) + 1; } // 统计模型类型 final modelStats = {}; for (final model in doc.models.values) { if (model.isEnum) { modelStats['enum'] = (modelStats['enum'] ?? 0) + 1; } else { modelStats['class'] = (modelStats['class'] ?? 0) + 1; } } return { 'title': doc.title, 'version': doc.version, 'paths': doc.paths.length, 'models': doc.models.length, 'controllers': doc.controllers.length, 'methods': methodStats, 'modelTypes': modelStats, }; } /// 分析 schemas 在 API 中的使用情况 /// 返回每个 schema 的用途类型集合 Map> _analyzeSchemaUsage( Map jsonData, ) { final schemaUsage = >{}; final pathsData = jsonData['paths'] as Map?; if (pathsData == null) return schemaUsage; pathsData.forEach((pathKey, pathValue) { if (pathValue is! Map) return; pathValue.forEach((methodKey, methodValue) { if (methodValue is! Map) return; // 分析 requestBody 中使用的 schemas final requestBody = methodValue['requestBody'] as Map?; if (requestBody != null) { _extractSchemasFromContent( requestBody['content'] as Map?, schemaUsage, ModelUsageType.request, ); } // 分析 parameters 中使用的 schemas final parameters = methodValue['parameters'] as List?; if (parameters != null) { for (final param in parameters) { if (param is Map) { final schema = param['schema'] as Map?; if (schema != null) { _extractSchemaRef(schema, schemaUsage, ModelUsageType.request); } } } } // 分析 responses 中使用的 schemas final responses = methodValue['responses'] as Map?; if (responses != null) { responses.forEach((statusCode, responseValue) { if (responseValue is Map) { _extractSchemasFromContent( responseValue['content'] as Map?, schemaUsage, ModelUsageType.response, ); } }); } }); }); return schemaUsage; } /// 从 content 中提取 schema 引用 void _extractSchemasFromContent( Map? content, Map> schemaUsage, ModelUsageType usageType, ) { if (content == null) return; content.forEach((mediaType, mediaTypeValue) { if (mediaTypeValue is Map) { final schema = mediaTypeValue['schema'] as Map?; if (schema != null) { _extractSchemaRef(schema, schemaUsage, usageType); } } }); } /// 递归提取 schema $ref 并记录用途 void _extractSchemaRef( Map schema, Map> schemaUsage, ModelUsageType usageType, ) { // 处理 $ref final ref = schema[r'$ref'] as String?; if (ref != null) { // 从 #/components/schemas/ModelName 提取 ModelName final schemaName = ref.split('/').last; schemaUsage.putIfAbsent(schemaName, () => {}).add(usageType); return; // $ref 存在时,不再处理其他字段 } // 处理数组类型 if (schema['type'] == 'array') { final items = schema['items'] as Map?; if (items != null) { _extractSchemaRef(items, schemaUsage, usageType); } } // 处理 allOf/oneOf/anyOf for (final key in ['allOf', 'oneOf', 'anyOf']) { final schemas = schema[key] as List?; if (schemas != null) { for (final s in schemas) { if (s is Map) { _extractSchemaRef(s, schemaUsage, usageType); } } } } // 处理对象属性 final properties = schema['properties'] as Map?; if (properties != null) { properties.forEach((propName, propSchema) { if (propSchema is Map) { _extractSchemaRef(propSchema, schemaUsage, usageType); } }); } // 处理 additionalProperties final additionalProperties = schema['additionalProperties']; if (additionalProperties is Map) { _extractSchemaRef(additionalProperties, schemaUsage, usageType); } } }