swagger_generator_flutter/lib/parsers/swagger_data_parser.dart

430 lines
12 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:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import '../core/config.dart';
import '../core/exceptions.dart';
import '../core/models.dart';
import '../utils/cache_manager.dart';
import '../utils/performance_monitor.dart';
import '../utils/reference_resolver.dart';
import '../utils/string_utils.dart';
/// Swagger数据解析器
/// 负责解析Swagger JSON文档并提取相关信息
class SwaggerDataParser {
final CacheManager _cacheManager;
final PerformanceMonitor _performanceMonitor;
// 缓存解析结果
SwaggerDocument? _cachedDocument;
SwaggerDataParser()
: _cacheManager = CacheManager(),
_performanceMonitor = PerformanceMonitor();
/// 获取并解析Swagger JSON文档
Future<SwaggerDocument> fetchAndParseSwaggerDocument() async {
// 如果有缓存且未过期,直接返回缓存结果
if (_cachedDocument != null) {
return _cachedDocument!;
}
return _performanceMonitor.measure(
'fetchAndParseSwaggerDocument',
() async {
try {
print('🔄 正在获取Swagger JSON文档...');
Map<String, dynamic> jsonData;
if (SwaggerConfig.swaggerJsonUrl.startsWith('file://')) {
// 处理本地文件
final filePath =
SwaggerConfig.swaggerJsonUrl.replaceFirst('file://', '');
final file = File(filePath);
if (await file.exists()) {
final content = await file.readAsString();
jsonData = json.decode(content) as Map<String, dynamic>;
} else {
throw SwaggerParseException(
'本地文件不存在',
url: SwaggerConfig.swaggerJsonUrl,
details: '文件路径: $filePath',
);
}
} else {
// 处理远程URL
final response = await http.get(
Uri.parse(SwaggerConfig.swaggerJsonUrl),
headers: SwaggerConfig.httpHeaders,
);
if (response.statusCode == 200) {
jsonData = json.decode(response.body) as Map<String, dynamic>;
} else {
throw SwaggerParseException(
'HTTP请求失败',
url: SwaggerConfig.swaggerJsonUrl,
statusCode: response.statusCode,
details: 'HTTP响应状态码: ${response.statusCode}',
);
}
}
_cachedDocument = await parseSwaggerDocument(jsonData);
print('✅ Swagger文档解析完成');
return _cachedDocument!;
} catch (e) {
if (e is SwaggerParseException) {
rethrow;
}
throw SwaggerParseException(
'获取Swagger文档失败',
url: SwaggerConfig.swaggerJsonUrl,
details: e.toString(),
);
}
},
);
}
/// 解析Swagger JSON文档
Future<SwaggerDocument> parseSwaggerDocument(
Map<String, dynamic> jsonData,
) async {
return _performanceMonitor.measure('parseSwaggerDocument', () async {
// 尝试从缓存获取
final cacheKey = 'swagger_doc_${jsonData.hashCode}';
final cachedResult = _cacheManager.get<SwaggerDocument>(cacheKey);
if (cachedResult != null) {
_cachedDocument = cachedResult;
return cachedResult;
}
// 解析文档基本信息
final info = jsonData['info'] as Map<String, dynamic>? ?? {};
final title = info['title'] as String? ?? 'API Documentation';
final version = info['version'] as String? ?? '1.0.0';
final description = info['description'] as String? ?? '';
// 解析 servers (OpenAPI 3.0)
final servers = _parseServers(jsonData);
// 解析 components (OpenAPI 3.0)
final components = _parseComponents(jsonData);
// 解析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);
_cachedDocument = document;
return document;
});
}
/// 解析 servers 配置 (OpenAPI 3.0)
List<ApiServer> _parseServers(Map<String, dynamic> jsonData) {
final servers = <ApiServer>[];
try {
final serversJson = jsonData['servers'] as List<dynamic>?;
if (serversJson != null) {
for (final serverJson in serversJson) {
if (serverJson is Map<String, dynamic>) {
final server = ApiServer.fromJson(serverJson);
servers.add(server);
}
}
}
// 如果没有 servers 配置,提供默认值
if (servers.isEmpty) {
servers.add(const ApiServer(url: '/'));
}
} catch (e) {
print('⚠️ 解析servers配置时发生错误: $e');
// 提供默认服务器配置
servers.add(const ApiServer(url: '/'));
}
return servers;
}
/// 解析 components 配置 (OpenAPI 3.0)
ApiComponents _parseComponents(Map<String, dynamic> jsonData) {
try {
final componentsJson = jsonData['components'] as Map<String, dynamic>?;
if (componentsJson != null) {
// 使用引用解析器处理复杂嵌套和循环引用
final resolver = ReferenceResolver();
final resolvedSchemas = resolver.resolveModels(componentsJson);
// 创建 ApiComponents但使用解析后的 schemas
final components = ApiComponents.fromJson(componentsJson);
return ApiComponents(
schemas: resolvedSchemas,
responses: components.responses,
parameters: components.parameters,
examples: components.examples,
requestBodies: components.requestBodies,
headers: components.headers,
securitySchemes: components.securitySchemes,
links: components.links,
callbacks: components.callbacks,
);
}
} catch (e) {
print('⚠️ 解析components配置时发生错误: $e');
}
return const ApiComponents();
}
/// 解析tags信息
Map<String, String> _parseTagsInfo(Map<String, dynamic> jsonData) {
final tagsInfo = <String, String>{};
try {
final tags = jsonData['tags'] as List<dynamic>?;
if (tags != null) {
for (final tag in tags) {
if (tag is Map<String, dynamic>) {
final name = tag['name'] as String?;
final description = tag['description'] as String?;
if (name != null && description != null) {
tagsInfo[name] = description;
}
}
}
}
} catch (e) {
print('⚠️ 解析tags信息时发生错误: $e');
}
return tagsInfo;
}
/// 解析API路径
Map<String, ApiPath> _parseApiPaths(Map<String, dynamic> jsonData) {
final paths = <String, ApiPath>{};
final pathsData = jsonData['paths'] as Map<String, dynamic>?;
if (pathsData == null) {
throw SwaggerParseException('未发现API路径定义');
}
try {
pathsData.forEach((pathKey, pathValue) {
if (pathValue is Map<String, dynamic>) {
pathValue.forEach((methodKey, methodValue) {
if (methodValue is Map<String, dynamic>) {
final method = HttpMethod.fromString(methodKey);
final apiPath = ApiPath.fromJson(
pathKey,
methodKey, // 传入字符串而不是HttpMethod对象
methodValue,
);
final key =
'${method.value.toUpperCase()}_${pathKey.replaceAll('/', '_')}';
paths[key] = apiPath;
}
});
}
});
} catch (e) {
throw SwaggerParseException('解析API路径失败', details: e.toString());
}
return paths;
}
/// 解析API控制器
Map<String, ApiController> _parseApiControllers(
Map<String, ApiPath> paths,
Map<String, String> tagsInfo,
) {
final controllers = <String, List<ApiPath>>{};
try {
// 根据tags分组API路径
for (final apiPath in paths.values) {
for (final tag in apiPath.tags) {
controllers.putIfAbsent(tag, () => []).add(apiPath);
}
}
// 创建控制器对象
final result = <String, ApiController>{};
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<String, dynamic> propData) {
try {
// 直接类型
if (propData['type'] != null) {
return propData['type'] as String;
}
// 引用类型 ($ref)
if (propData['\$ref'] != null) {
final ref = propData['\$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<String, dynamic>;
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<dynamic>';
case 'object':
return 'Map<String, dynamic>';
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() {
_cachedDocument = null;
_cacheManager.clear();
}
/// 获取文档统计信息
Map<String, dynamic> getDocumentStats() {
if (_cachedDocument == null) {
return {};
}
final doc = _cachedDocument!;
// 统计HTTP方法
final methodStats = <String, int>{};
for (final path in doc.paths.values) {
final method = path.method.value;
methodStats[method] = (methodStats[method] ?? 0) + 1;
}
// 统计模型类型
final modelStats = <String, int>{};
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,
};
}
}