712 lines
21 KiB
Dart
712 lines
21 KiB
Dart
import '../core/models.dart';
|
||
import '../utils/string_utils.dart';
|
||
import 'base_generator.dart';
|
||
|
||
/// 文档生成器
|
||
/// 负责生成API文档
|
||
class DocumentationGenerator extends BaseGenerator {
|
||
final SwaggerDocument document;
|
||
final bool includeExamples;
|
||
final bool includeSchemas;
|
||
final bool includeResponses;
|
||
final String? customTitle;
|
||
|
||
DocumentationGenerator(
|
||
this.document, {
|
||
this.includeExamples = true,
|
||
this.includeSchemas = true,
|
||
this.includeResponses = true,
|
||
this.customTitle,
|
||
});
|
||
|
||
@override
|
||
String get generatorType => 'DocumentationGenerator';
|
||
|
||
@override
|
||
String generate() {
|
||
final buffer = StringBuffer();
|
||
|
||
// 生成文档头部
|
||
_generateHeader(buffer);
|
||
|
||
// 生成目录
|
||
_generateTableOfContents(buffer);
|
||
|
||
// 生成API概述
|
||
_generateApiOverview(buffer);
|
||
|
||
// 生成认证信息
|
||
_generateAuthenticationInfo(buffer);
|
||
|
||
// 生成API端点文档
|
||
_generateEndpointsDocumentation(buffer);
|
||
|
||
// 生成数据模型文档
|
||
if (includeSchemas) {
|
||
_generateSchemasDocumentation(buffer);
|
||
}
|
||
|
||
// 生成错误代码文档
|
||
_generateErrorCodesDocumentation(buffer);
|
||
|
||
// 生成示例代码
|
||
if (includeExamples) {
|
||
_generateExamplesDocumentation(buffer);
|
||
}
|
||
|
||
// 生成更新日志
|
||
_generateChangeLog(buffer);
|
||
|
||
return generateTypeCheckedCode(buffer.toString());
|
||
}
|
||
|
||
/// 生成文档头部
|
||
void _generateHeader(StringBuffer buffer) {
|
||
final title = customTitle ?? document.title;
|
||
|
||
buffer.writeln('# $title');
|
||
buffer.writeln('');
|
||
|
||
if (document.description.isNotEmpty) {
|
||
buffer.writeln('${document.description}');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
buffer.writeln('**版本**: ${document.version}');
|
||
buffer.writeln('**基础URL**: ${_getBaseUrl()}');
|
||
buffer.writeln('**生成时间**: ${DateTime.now().toIso8601String()}');
|
||
buffer.writeln('');
|
||
|
||
// 生成徽章
|
||
buffer.writeln(
|
||
'');
|
||
buffer.writeln('');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成目录
|
||
void _generateTableOfContents(StringBuffer buffer) {
|
||
buffer.writeln('## 📋 目录');
|
||
buffer.writeln('');
|
||
buffer.writeln('- [API概述](#api概述)');
|
||
buffer.writeln('- [认证](#认证)');
|
||
buffer.writeln('- [API端点](#api端点)');
|
||
|
||
// 按控制器分组的端点
|
||
final controllerGroups = _groupPathsByController();
|
||
for (final controllerName in controllerGroups.keys) {
|
||
final anchor = controllerName.toLowerCase().replaceAll(' ', '-');
|
||
buffer.writeln(' - [$controllerName](#$anchor)');
|
||
}
|
||
|
||
if (includeSchemas) {
|
||
buffer.writeln('- [数据模型](#数据模型)');
|
||
}
|
||
|
||
buffer.writeln('- [错误代码](#错误代码)');
|
||
|
||
if (includeExamples) {
|
||
buffer.writeln('- [示例代码](#示例代码)');
|
||
}
|
||
|
||
buffer.writeln('- [更新日志](#更新日志)');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成API概述
|
||
void _generateApiOverview(StringBuffer buffer) {
|
||
buffer.writeln('## 🚀 API概述');
|
||
buffer.writeln('');
|
||
|
||
// 统计信息
|
||
final stats = _generateStats();
|
||
buffer.writeln('### 📊 统计信息');
|
||
buffer.writeln('');
|
||
buffer.writeln('- **总端点数**: ${stats['totalEndpoints']}');
|
||
buffer.writeln('- **控制器数**: ${stats['controllersCount']}');
|
||
buffer.writeln('- **数据模型数**: ${stats['modelsCount']}');
|
||
buffer.writeln('');
|
||
|
||
// HTTP方法统计
|
||
final methodStats = stats['methodStats'] as Map<String, int>;
|
||
buffer.writeln('### 🔗 HTTP方法分布');
|
||
buffer.writeln('');
|
||
for (final entry in methodStats.entries) {
|
||
final method = entry.key;
|
||
final count = entry.value;
|
||
final percentage =
|
||
((count / stats['totalEndpoints']) * 100).toStringAsFixed(1);
|
||
buffer.writeln('- **$method**: $count个 ($percentage%)');
|
||
}
|
||
buffer.writeln('');
|
||
|
||
// 支持的格式
|
||
buffer.writeln('### 🌐 服务器配置');
|
||
buffer.writeln('');
|
||
if (document.servers.isNotEmpty) {
|
||
for (final server in document.servers) {
|
||
buffer.writeln('**服务器**: `${server.url}`');
|
||
if (server.description.isNotEmpty) {
|
||
buffer.writeln('- ${server.description}');
|
||
}
|
||
if (server.variables.isNotEmpty) {
|
||
buffer.writeln('- 变量:');
|
||
server.variables.forEach((name, variable) {
|
||
buffer.writeln(
|
||
' - `$name`: ${variable.description} (默认: ${variable.defaultValue})');
|
||
});
|
||
}
|
||
buffer.writeln('');
|
||
}
|
||
} else {
|
||
buffer.writeln('**服务器**: 相对路径 `/`');
|
||
buffer.writeln('');
|
||
}
|
||
}
|
||
|
||
/// 生成认证信息
|
||
void _generateAuthenticationInfo(StringBuffer buffer) {
|
||
buffer.writeln('## 🔐 认证');
|
||
buffer.writeln('');
|
||
buffer.writeln('本API使用以下认证方式:');
|
||
buffer.writeln('');
|
||
buffer.writeln('### Bearer Token');
|
||
buffer.writeln('');
|
||
buffer.writeln('在请求头中包含Authorization字段:');
|
||
buffer.writeln('');
|
||
buffer.writeln('```');
|
||
buffer.writeln('Authorization: Bearer YOUR_TOKEN_HERE');
|
||
buffer.writeln('```');
|
||
buffer.writeln('');
|
||
buffer.writeln('### 获取Token');
|
||
buffer.writeln('');
|
||
buffer.writeln('请使用登录接口获取访问令牌。');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成端点文档
|
||
void _generateEndpointsDocumentation(StringBuffer buffer) {
|
||
buffer.writeln('## 📡 API端点');
|
||
buffer.writeln('');
|
||
|
||
final controllerGroups = _groupPathsByController();
|
||
|
||
for (final entry in controllerGroups.entries) {
|
||
final controllerName = entry.key;
|
||
final paths = entry.value;
|
||
|
||
buffer.writeln('### $controllerName');
|
||
buffer.writeln('');
|
||
|
||
// 按HTTP方法和路径排序
|
||
paths.sort((a, b) {
|
||
final methodOrder = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
||
final aIndex = methodOrder.indexOf(a.method.value);
|
||
final bIndex = methodOrder.indexOf(b.method.value);
|
||
|
||
if (aIndex != bIndex) {
|
||
return aIndex.compareTo(bIndex);
|
||
}
|
||
|
||
return a.path.compareTo(b.path);
|
||
});
|
||
|
||
for (final path in paths) {
|
||
_generateEndpointDocumentation(buffer, path);
|
||
}
|
||
|
||
buffer.writeln('');
|
||
}
|
||
}
|
||
|
||
/// 生成单个端点文档
|
||
void _generateEndpointDocumentation(StringBuffer buffer, ApiPath path) {
|
||
// 端点标题
|
||
final title = path.summary.isNotEmpty ? path.summary : path.operationId;
|
||
buffer.writeln('#### ${path.method.value} ${path.path}');
|
||
buffer.writeln('');
|
||
|
||
if (title.isNotEmpty) {
|
||
buffer.writeln('**$title**');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
// 描述
|
||
if (path.description.isNotEmpty) {
|
||
buffer.writeln(path.description);
|
||
buffer.writeln('');
|
||
}
|
||
|
||
// 标签
|
||
if (path.tags.isNotEmpty) {
|
||
buffer.writeln('**标签**: ${path.tags.join(', ')}');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
// 参数
|
||
if (path.parameters.isNotEmpty) {
|
||
buffer.writeln('**参数**:');
|
||
buffer.writeln('');
|
||
|
||
// 按参数位置分组
|
||
final paramGroups = <ParameterLocation, List<ApiParameter>>{};
|
||
for (final param in path.parameters) {
|
||
paramGroups.putIfAbsent(param.location, () => []).add(param);
|
||
}
|
||
|
||
for (final entry in paramGroups.entries) {
|
||
final location = entry.key;
|
||
final params = entry.value;
|
||
|
||
buffer.writeln('*${_getLocationName(location)}参数*:');
|
||
buffer.writeln('');
|
||
|
||
buffer.writeln('| 参数名 | 类型 | 必填 | 描述 | 示例 |');
|
||
buffer.writeln('|--------|------|------|------|------|');
|
||
|
||
for (final param in params) {
|
||
final required = param.required ? '✅' : '❌';
|
||
final example = param.example?.toString() ?? '-';
|
||
final description =
|
||
param.description.isNotEmpty ? param.description : '-';
|
||
|
||
buffer.writeln(
|
||
'| ${param.name} | ${param.type.value} | $required | $description | $example |');
|
||
}
|
||
|
||
buffer.writeln('');
|
||
}
|
||
}
|
||
|
||
// 响应
|
||
if (includeResponses && path.responses.isNotEmpty) {
|
||
buffer.writeln('**响应**:');
|
||
buffer.writeln('');
|
||
|
||
for (final entry in path.responses.entries) {
|
||
final code = entry.key;
|
||
final response = entry.value;
|
||
|
||
buffer.writeln('*HTTP $code*:');
|
||
if (response.description.isNotEmpty) {
|
||
buffer.writeln('- ${response.description}');
|
||
}
|
||
buffer.writeln('');
|
||
}
|
||
}
|
||
|
||
// 示例
|
||
if (includeExamples) {
|
||
_generateEndpointExample(buffer, path);
|
||
}
|
||
|
||
buffer.writeln('---');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成端点示例
|
||
void _generateEndpointExample(StringBuffer buffer, ApiPath path) {
|
||
buffer.writeln('**示例**:');
|
||
buffer.writeln('');
|
||
|
||
// cURL示例
|
||
buffer.writeln('```bash');
|
||
buffer.write('curl -X ${path.method.value} ');
|
||
buffer.write('${_getBaseUrl()}${path.path}');
|
||
|
||
if (path.parameters.any((p) => p.location == ParameterLocation.header)) {
|
||
buffer.write(' \\');
|
||
buffer.writeln('');
|
||
buffer.write(' -H "Authorization: Bearer YOUR_TOKEN"');
|
||
}
|
||
|
||
if (path.method == HttpMethod.post || path.method == HttpMethod.put) {
|
||
buffer.write(' \\');
|
||
buffer.writeln('');
|
||
buffer.write(' -H "Content-Type: application/json"');
|
||
buffer.write(' \\');
|
||
buffer.writeln('');
|
||
buffer.write(' -d \'{"key": "value"}\'');
|
||
}
|
||
|
||
buffer.writeln('');
|
||
buffer.writeln('```');
|
||
buffer.writeln('');
|
||
|
||
// Dart示例
|
||
buffer.writeln('```dart');
|
||
buffer.writeln('import \'dart:convert\';');
|
||
buffer.writeln('import \'package:http/http.dart\' as http;');
|
||
buffer.writeln('');
|
||
buffer.writeln('class ApiClient {');
|
||
buffer.writeln(' static const String baseUrl = \'${_getBaseUrl()}\';');
|
||
buffer.writeln(' String? _token;');
|
||
buffer.writeln('');
|
||
buffer.writeln(' void setToken(String token) {');
|
||
buffer.writeln(' _token = token;');
|
||
buffer.writeln(' }');
|
||
buffer.writeln('');
|
||
buffer.writeln(' Map<String, String> get _headers => {');
|
||
buffer.writeln(' \'Content-Type\': \'application/json\',');
|
||
buffer.writeln(
|
||
' if (_token != null) \'Authorization\': \'Bearer \$_token\',');
|
||
buffer.writeln(' };');
|
||
buffer.writeln('');
|
||
buffer
|
||
.writeln(' Future<Map<String, dynamic>> get(String endpoint) async {');
|
||
buffer.writeln(' final response = await http.get(');
|
||
buffer.writeln(' Uri.parse(\'\$baseUrl\$endpoint\'),');
|
||
buffer.writeln(' headers: _headers,');
|
||
buffer.writeln(' );');
|
||
buffer.writeln('');
|
||
buffer.writeln(' if (response.statusCode == 200) {');
|
||
buffer.writeln(' return jsonDecode(response.body);');
|
||
buffer.writeln(' } else {');
|
||
buffer.writeln(
|
||
' throw Exception(\'Failed to load data: \${response.statusCode}\');');
|
||
buffer.writeln(' }');
|
||
buffer.writeln(' }');
|
||
buffer.writeln('');
|
||
buffer.writeln(
|
||
' Future<Map<String, dynamic>> post(String endpoint, Map<String, dynamic> data) async {');
|
||
buffer.writeln(' final response = await http.post(');
|
||
buffer.writeln(' Uri.parse(\'\$baseUrl\$endpoint\'),');
|
||
buffer.writeln(' headers: _headers,');
|
||
buffer.writeln(' body: jsonEncode(data),');
|
||
buffer.writeln(' );');
|
||
buffer.writeln('');
|
||
buffer.writeln(
|
||
' if (response.statusCode == 200 || response.statusCode == 201) {');
|
||
buffer.writeln(' return jsonDecode(response.body);');
|
||
buffer.writeln(' } else {');
|
||
buffer.writeln(
|
||
' throw Exception(\'Failed to post data: \${response.statusCode}\');');
|
||
buffer.writeln(' }');
|
||
buffer.writeln(' }');
|
||
buffer.writeln('}');
|
||
buffer.writeln('```');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成数据模型文档
|
||
void _generateSchemasDocumentation(StringBuffer buffer) {
|
||
if (document.models.isEmpty) return;
|
||
|
||
buffer.writeln('## 📋 数据模型');
|
||
buffer.writeln('');
|
||
|
||
final sortedModels = document.models.values.toList()
|
||
..sort((a, b) => a.name.compareTo(b.name));
|
||
|
||
for (final model in sortedModels) {
|
||
_generateModelDocumentation(buffer, model);
|
||
}
|
||
}
|
||
|
||
/// 生成模型文档
|
||
void _generateModelDocumentation(StringBuffer buffer, ApiModel model) {
|
||
buffer.writeln('### ${model.name}');
|
||
buffer.writeln('');
|
||
|
||
if (model.description.isNotEmpty) {
|
||
buffer.writeln(model.description);
|
||
buffer.writeln('');
|
||
}
|
||
|
||
if (model.isEnum) {
|
||
buffer.writeln('**枚举值**:');
|
||
buffer.writeln('');
|
||
|
||
for (final value in model.enumValues) {
|
||
buffer.writeln('- `$value`');
|
||
}
|
||
|
||
buffer.writeln('');
|
||
} else {
|
||
buffer.writeln('**属性**:');
|
||
buffer.writeln('');
|
||
|
||
if (model.properties.isNotEmpty) {
|
||
buffer.writeln('| 属性名 | 类型 | 必填 | 描述 |');
|
||
buffer.writeln('|--------|------|------|------|');
|
||
|
||
for (final entry in model.properties.entries) {
|
||
final propName = entry.key;
|
||
final prop = entry.value;
|
||
|
||
final required = model.required.contains(propName) ? '✅' : '❌';
|
||
final type = _getPropertyTypeDescription(prop);
|
||
final description =
|
||
prop.description.isNotEmpty ? prop.description : '-';
|
||
|
||
buffer.writeln('| $propName | $type | $required | $description |');
|
||
}
|
||
}
|
||
|
||
buffer.writeln('');
|
||
}
|
||
|
||
// JSON示例
|
||
if (includeExamples) {
|
||
buffer.writeln('**JSON示例**:');
|
||
buffer.writeln('');
|
||
buffer.writeln('```json');
|
||
buffer.writeln(_generateModelExample(model));
|
||
buffer.writeln('```');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
buffer.writeln('---');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成错误代码文档
|
||
void _generateErrorCodesDocumentation(StringBuffer buffer) {
|
||
buffer.writeln('## ❌ 错误代码');
|
||
buffer.writeln('');
|
||
|
||
// 标准HTTP状态码
|
||
final errorCodes = {
|
||
'400': '请求参数错误',
|
||
'401': '未授权访问',
|
||
'403': '禁止访问',
|
||
'404': '资源不存在',
|
||
'405': '方法不允许',
|
||
'422': '参数验证失败',
|
||
'500': '服务器内部错误',
|
||
'502': '网关错误',
|
||
'503': '服务不可用',
|
||
};
|
||
|
||
buffer.writeln('| 状态码 | 描述 |');
|
||
buffer.writeln('|--------|------|');
|
||
|
||
for (final entry in errorCodes.entries) {
|
||
buffer.writeln('| ${entry.key} | ${entry.value} |');
|
||
}
|
||
|
||
buffer.writeln('');
|
||
|
||
// 错误响应格式
|
||
buffer.writeln('### 错误响应格式');
|
||
buffer.writeln('');
|
||
buffer.writeln('```json');
|
||
buffer.writeln('{');
|
||
buffer.writeln(' "error": {');
|
||
buffer.writeln(' "code": "ERROR_CODE",');
|
||
buffer.writeln(' "message": "错误描述",');
|
||
buffer.writeln(' "details": "详细信息"');
|
||
buffer.writeln(' }');
|
||
buffer.writeln('}');
|
||
buffer.writeln('```');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成示例代码
|
||
void _generateExamplesDocumentation(StringBuffer buffer) {
|
||
buffer.writeln('## 💡 示例代码');
|
||
buffer.writeln('');
|
||
|
||
// Dart HTTP客户端示例
|
||
buffer.writeln('### Dart HTTP客户端');
|
||
buffer.writeln('');
|
||
buffer.writeln('```dart');
|
||
buffer.writeln('import \'dart:convert\';');
|
||
buffer.writeln('import \'package:http/http.dart\' as http;');
|
||
buffer.writeln('');
|
||
buffer.writeln('class ApiClient {');
|
||
buffer.writeln(' static const String baseUrl = \'${_getBaseUrl()}\';');
|
||
buffer.writeln(' String? _token;');
|
||
buffer.writeln('');
|
||
buffer.writeln(' void setToken(String token) {');
|
||
buffer.writeln(' _token = token;');
|
||
buffer.writeln(' }');
|
||
buffer.writeln('');
|
||
buffer.writeln(' Map<String, String> get _headers => {');
|
||
buffer.writeln(' \'Content-Type\': \'application/json\',');
|
||
buffer.writeln(
|
||
' if (_token != null) \'Authorization\': \'Bearer \$_token\',');
|
||
buffer.writeln(' };');
|
||
buffer.writeln('');
|
||
buffer
|
||
.writeln(' Future<Map<String, dynamic>> get(String endpoint) async {');
|
||
buffer.writeln(' final response = await http.get(');
|
||
buffer.writeln(' Uri.parse(\'\$baseUrl\$endpoint\'),');
|
||
buffer.writeln(' headers: _headers,');
|
||
buffer.writeln(' );');
|
||
buffer.writeln('');
|
||
buffer.writeln(' if (response.statusCode == 200) {');
|
||
buffer.writeln(' return jsonDecode(response.body);');
|
||
buffer.writeln(' } else {');
|
||
buffer.writeln(
|
||
' throw Exception(\'Failed to load data: \${response.statusCode}\');');
|
||
buffer.writeln(' }');
|
||
buffer.writeln(' }');
|
||
buffer.writeln('');
|
||
buffer.writeln(
|
||
' Future<Map<String, dynamic>> post(String endpoint, Map<String, dynamic> data) async {');
|
||
buffer.writeln(' final response = await http.post(');
|
||
buffer.writeln(' Uri.parse(\'\$baseUrl\$endpoint\'),');
|
||
buffer.writeln(' headers: _headers,');
|
||
buffer.writeln(' body: jsonEncode(data),');
|
||
buffer.writeln(' );');
|
||
buffer.writeln('');
|
||
buffer.writeln(
|
||
' if (response.statusCode == 200 || response.statusCode == 201) {');
|
||
buffer.writeln(' return jsonDecode(response.body);');
|
||
buffer.writeln(' } else {');
|
||
buffer.writeln(
|
||
' throw Exception(\'Failed to post data: \${response.statusCode}\');');
|
||
buffer.writeln(' }');
|
||
buffer.writeln(' }');
|
||
buffer.writeln('}');
|
||
buffer.writeln('```');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 生成更新日志
|
||
void _generateChangeLog(StringBuffer buffer) {
|
||
buffer.writeln('## 📝 更新日志');
|
||
buffer.writeln('');
|
||
|
||
buffer.writeln(
|
||
'### ${document.version} - ${DateTime.now().toIso8601String().split('T')[0]}');
|
||
buffer.writeln('');
|
||
buffer.writeln('- 🎉 初始版本发布');
|
||
buffer.writeln('- 📡 ${document.paths.length} 个API端点');
|
||
buffer.writeln('- 📋 ${document.models.length} 个数据模型');
|
||
buffer.writeln('- 🔧 完整的API文档');
|
||
buffer.writeln('');
|
||
|
||
buffer.writeln('---');
|
||
buffer.writeln('');
|
||
buffer.writeln('*文档由 Swagger CLI By Max 自动生成*');
|
||
buffer.writeln('');
|
||
}
|
||
|
||
/// 按控制器分组路径
|
||
Map<String, List<ApiPath>> _groupPathsByController() {
|
||
final groups = <String, List<ApiPath>>{};
|
||
|
||
for (final path in document.paths.values) {
|
||
final controllerName = StringUtils.extractControllerName(path);
|
||
groups.putIfAbsent(controllerName, () => []).add(path);
|
||
}
|
||
|
||
return groups;
|
||
}
|
||
|
||
// 已移动到 StringUtils.extractControllerName
|
||
|
||
/// 获取基础URL (从 OpenAPI 3.0 servers 配置)
|
||
String _getBaseUrl() {
|
||
if (document.servers.isNotEmpty) {
|
||
return document.servers.first.url;
|
||
}
|
||
return '/'; // 默认相对路径
|
||
}
|
||
|
||
/// 获取参数位置名称
|
||
String _getLocationName(ParameterLocation location) {
|
||
switch (location) {
|
||
case ParameterLocation.query:
|
||
return '查询';
|
||
case ParameterLocation.path:
|
||
return '路径';
|
||
case ParameterLocation.header:
|
||
return '请求头';
|
||
case ParameterLocation.body:
|
||
return '请求体';
|
||
case ParameterLocation.form:
|
||
return '表单';
|
||
case ParameterLocation.cookie:
|
||
return 'Cookie';
|
||
}
|
||
}
|
||
|
||
/// 获取属性类型描述
|
||
String _getPropertyTypeDescription(ApiProperty prop) {
|
||
String baseType = prop.type.value;
|
||
|
||
if (prop.format != null) {
|
||
baseType += ' (${prop.format})';
|
||
}
|
||
|
||
if (prop.nullable) {
|
||
baseType += '?';
|
||
}
|
||
|
||
return baseType;
|
||
}
|
||
|
||
/// 生成模型示例
|
||
String _generateModelExample(ApiModel model) {
|
||
if (model.isEnum) {
|
||
return '"${model.enumValues.first}"';
|
||
}
|
||
|
||
final buffer = StringBuffer();
|
||
buffer.writeln('{');
|
||
|
||
final properties = model.properties.entries.toList();
|
||
for (int i = 0; i < properties.length; i++) {
|
||
final entry = properties[i];
|
||
final propName = entry.key;
|
||
final prop = entry.value;
|
||
|
||
final exampleValue = _generatePropertyExample(prop);
|
||
buffer.write(' "$propName": $exampleValue');
|
||
|
||
if (i < properties.length - 1) {
|
||
buffer.write(',');
|
||
}
|
||
|
||
buffer.writeln();
|
||
}
|
||
|
||
buffer.write('}');
|
||
return buffer.toString();
|
||
}
|
||
|
||
/// 生成属性示例
|
||
String _generatePropertyExample(ApiProperty prop) {
|
||
switch (prop.type) {
|
||
case PropertyType.string:
|
||
return '"string"';
|
||
case PropertyType.integer:
|
||
return '0';
|
||
case PropertyType.number:
|
||
return '0.0';
|
||
case PropertyType.boolean:
|
||
return 'true';
|
||
case PropertyType.array:
|
||
return '[]';
|
||
case PropertyType.object:
|
||
return '{}';
|
||
case PropertyType.reference:
|
||
return '{}';
|
||
default:
|
||
return 'null';
|
||
}
|
||
}
|
||
|
||
/// 生成统计信息
|
||
Map<String, dynamic> _generateStats() {
|
||
final stats = <String, dynamic>{};
|
||
|
||
stats['totalEndpoints'] = document.paths.length;
|
||
stats['controllersCount'] = _groupPathsByController().length;
|
||
stats['modelsCount'] = document.models.length;
|
||
|
||
// HTTP方法统计
|
||
final methodStats = <String, int>{};
|
||
for (final path in document.paths.values) {
|
||
final method = path.method.value;
|
||
methodStats[method] = (methodStats[method] ?? 0) + 1;
|
||
}
|
||
stats['methodStats'] = methodStats;
|
||
|
||
return stats;
|
||
}
|
||
}
|