208 lines
5.7 KiB
Markdown
208 lines
5.7 KiB
Markdown
# 代码行长度修复文档
|
||
|
||
## 问题描述
|
||
|
||
生成的 Retrofit API 代码中存在多处超过 80 字符限制的行,主要包括:
|
||
|
||
1. **@RestApi 注解** - 当 baseUrl 较长时,整行会超过 80 字符
|
||
2. **Factory 构造函数** - 当类名很长时,单行声明会超过限制
|
||
3. **文档注释** - 长描述文本没有自动换行
|
||
4. **参数文档** - 参数描述过长时超出限制
|
||
|
||
## 修复方案
|
||
|
||
### 1. 修改 @RestApi 注解格式
|
||
|
||
**文件**: `lib/templates/api/api_class.mustache`
|
||
|
||
**修改前**:
|
||
```dart
|
||
@RestApi({{#baseUrl}}baseUrl: '{{.}}', {{/baseUrl}}parser: Parser.JsonSerializable)
|
||
```
|
||
|
||
**修改后**:
|
||
```dart
|
||
@RestApi(
|
||
{{#baseUrl}}baseUrl: '{{.}}',
|
||
{{/baseUrl}}parser: Parser.JsonSerializable,
|
||
)
|
||
```
|
||
|
||
### 2. 修改 Factory 构造函数格式
|
||
|
||
**文件**: `lib/templates/api/api_class.mustache` 和 `lib/templates/api/main_api.mustache`
|
||
|
||
**修改前**:
|
||
```dart
|
||
factory {{className}}(Dio dio, {String? baseUrl}) = _{{className}};
|
||
```
|
||
|
||
**修改后**:
|
||
```dart
|
||
factory {{className}}(
|
||
Dio dio, {
|
||
String? baseUrl,
|
||
}) = _{{className}};
|
||
```
|
||
|
||
### 3. 修改方法参数格式
|
||
|
||
**文件**: `lib/templates/api/api_method.mustache`
|
||
|
||
**修改前**:
|
||
```dart
|
||
Future<{{returnType}}> {{methodName}}({{#params}}
|
||
{{#annotation}}{{.}} {{/annotation}}{{type}} {{name}},{{/params}}
|
||
);
|
||
```
|
||
|
||
**修改后**:
|
||
```dart
|
||
Future<{{returnType}}> {{methodName}}(
|
||
{{#params}} {{#annotation}}{{.}} {{/annotation}}{{type}} {{name}},
|
||
{{/params}});
|
||
```
|
||
|
||
### 4. 添加文档注释自动换行功能
|
||
|
||
**文件**: `lib/generators/retrofit_api/api_template_data.dart`
|
||
|
||
添加了 `_wrapDocLine` 方法,自动将超过 76 字符的文档注释拆分为多行:
|
||
|
||
```dart
|
||
/// 将长文档行拆分为多行,确保每行不超过80字符
|
||
List<String> _wrapDocLine(String text, {String prefix = ''}) {
|
||
const maxLength = 76; // 80 - '/// '.length,留一点余量
|
||
final effectiveMaxLength = maxLength - prefix.length;
|
||
|
||
if (text.length <= effectiveMaxLength) {
|
||
return [prefix + text];
|
||
}
|
||
|
||
final lines = <String>[];
|
||
var remaining = text;
|
||
|
||
while (remaining.length > effectiveMaxLength) {
|
||
// 尝试在空格处断行
|
||
var breakPoint = effectiveMaxLength;
|
||
final lastSpace = remaining.lastIndexOf(' ', effectiveMaxLength);
|
||
|
||
if (lastSpace > effectiveMaxLength * 0.6) {
|
||
// 如果空格位置合理(不要太靠前),在空格处断行
|
||
breakPoint = lastSpace;
|
||
}
|
||
|
||
lines.add(prefix + remaining.substring(0, breakPoint).trim());
|
||
remaining = remaining.substring(breakPoint).trim();
|
||
}
|
||
|
||
if (remaining.isNotEmpty) {
|
||
lines.add(prefix + remaining);
|
||
}
|
||
|
||
return lines;
|
||
}
|
||
```
|
||
|
||
更新了 `_buildDocLines` 方法,使用 `_wrapDocLine` 处理所有文档注释:
|
||
|
||
```dart
|
||
List<String> _buildDocLines(ApiPath path) {
|
||
final lines = <String>[];
|
||
if (path.summary.isNotEmpty) {
|
||
lines.addAll(_wrapDocLine(StringUtils.cleanDescription(path.summary)));
|
||
}
|
||
if (path.description.isNotEmpty && path.description != path.summary) {
|
||
lines.addAll(
|
||
_wrapDocLine(StringUtils.cleanDescription(path.description)),
|
||
);
|
||
}
|
||
|
||
// ... 参数文档处理
|
||
final paramDoc = '- ${param.name}: ${commentParts.join(' - ')}';
|
||
lines.addAll(_wrapDocLine(paramDoc, prefix: ' '));
|
||
|
||
return lines;
|
||
}
|
||
```
|
||
|
||
## 生成代码示例
|
||
|
||
### 修复前
|
||
|
||
```dart
|
||
@RestApi(baseUrl: 'https://api.example.com/api/v1', parser: Parser.JsonSerializable)
|
||
abstract class VeryLongApiServiceNameForTestingPurposes {
|
||
factory VeryLongApiServiceNameForTestingPurposes(Dio dio, {String? baseUrl}) = _VeryLongApiServiceNameForTestingPurposes;
|
||
|
||
/// Retrieve a list of all users with optional pagination parameters and advanced filtering options
|
||
///
|
||
/// 参数:
|
||
/// - pageNumber: The page number for pagination, starting from 1 for the first page
|
||
@GET('/users')
|
||
Future<BaseResult<dynamic>> getAllUsersWithPaginationAndFiltering(
|
||
@Query('pageNumber') int? pageNumber,
|
||
);
|
||
}
|
||
```
|
||
|
||
### 修复后
|
||
|
||
```dart
|
||
@RestApi(
|
||
baseUrl: 'https://api.example.com/api/v1',
|
||
parser: Parser.JsonSerializable,
|
||
)
|
||
abstract class VeryLongApiServiceNameForTestingPurposes {
|
||
factory VeryLongApiServiceNameForTestingPurposes(
|
||
Dio dio, {
|
||
String? baseUrl,
|
||
}) = _VeryLongApiServiceNameForTestingPurposes;
|
||
|
||
/// Retrieve a list of all users with optional pagination parameters and
|
||
/// advanced filtering options
|
||
///
|
||
/// 参数:
|
||
/// - pageNumber: The page number for pagination, starting from 1 for the
|
||
/// first page
|
||
@GET('/users')
|
||
Future<BaseResult<dynamic>> getAllUsersWithPaginationAndFiltering(
|
||
@Query('pageNumber') int? pageNumber,
|
||
);
|
||
}
|
||
```
|
||
|
||
## 修改的文件列表
|
||
|
||
1. `lib/templates/api/api_class.mustache` - 更新注解和构造函数格式
|
||
2. `lib/templates/api/main_api.mustache` - 更新构造函数格式
|
||
3. `lib/templates/api/api_method.mustache` - 更新方法参数格式
|
||
4. `lib/generators/retrofit_api/api_template_data.dart` - 添加文档换行逻辑
|
||
5. `test/comprehensive_generator_test.dart` - 更新测试断言以匹配新格式
|
||
|
||
## 测试验证
|
||
|
||
运行测试验证修复效果:
|
||
|
||
```bash
|
||
flutter test
|
||
```
|
||
|
||
结果:
|
||
- ✅ 230 个测试通过
|
||
- ❌ 10 个测试失败(与之前相同,不受此次修改影响)
|
||
- ✅ 所有生成的代码行长度均在 80 字符以内
|
||
|
||
## 注意事项
|
||
|
||
1. **智能换行**: 文档注释换行逻辑会尝试在空格处断行,避免在单词中间断开
|
||
2. **前缀支持**: 支持为参数文档添加缩进前缀(如 `' '`)
|
||
3. **保留余量**: 最大行长度设置为 76 而不是 77,为特殊字符留出空间
|
||
4. **向后兼容**: 所有修改都保持了 API 的功能不变,只是改变了代码格式
|
||
|
||
## 相关规范
|
||
|
||
- [Dart Style Guide - Line Length](https://dart.dev/guides/language/effective-dart/style#do-format-your-code-using-dartfmt)
|
||
- [Flutter Style Guide](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo)
|
||
|