feat: fix bugs

This commit is contained in:
Max 2025-07-13 20:10:12 +08:00
parent 665c9e6049
commit c40f6acc36
7 changed files with 141 additions and 50 deletions

View File

@ -2,7 +2,9 @@ targets:
$default: $default:
sources: sources:
- "lib/**" - "lib/**"
- "generator/**"
builders: builders:
json_serializable: json_serializable:
generate_for: generate_for:
- "lib/**" - "lib/**"
- "generator/**"

View File

@ -60,10 +60,10 @@ class EndpointCodeGenerator extends BaseGenerator {
// //
if (path.summary.isNotEmpty) { if (path.summary.isNotEmpty) {
buffer.writeln(' /// ${path.summary}'); buffer.writeln(' ${StringUtils.generateComment(path.summary)}');
} }
if (path.description.isNotEmpty && path.description != path.summary) { if (path.description.isNotEmpty && path.description != path.summary) {
buffer.writeln(' /// ${path.description}'); buffer.writeln(' ${StringUtils.generateComment(path.description)}');
} }
buffer.writeln(' static const String $constantName = \'$cleanPath\';'); buffer.writeln(' static const String $constantName = \'$cleanPath\';');
@ -171,7 +171,7 @@ class EndpointCodeGenerator extends BaseGenerator {
final constantName = _generateConstantName(path); final constantName = _generateConstantName(path);
if (path.summary.isNotEmpty) { if (path.summary.isNotEmpty) {
buffer.writeln(' /// ${path.summary}'); buffer.writeln(' ${StringUtils.generateComment(path.summary)}');
} }
buffer.writeln( buffer.writeln(
' $enumName(ApiPaths.$constantName, \'${path.method.value}\'),'); ' $enumName(ApiPaths.$constantName, \'${path.method.value}\'),');

View File

@ -181,10 +181,10 @@ class RetrofitApiGenerator extends BaseGenerator {
// //
if (path.summary.isNotEmpty) { if (path.summary.isNotEmpty) {
buffer.writeln(' /// ${path.summary}'); buffer.writeln(' ${StringUtils.generateComment(path.summary)}');
} }
if (path.description.isNotEmpty && path.description != path.summary) { if (path.description.isNotEmpty && path.description != path.summary) {
buffer.writeln(' /// ${path.description}'); buffer.writeln(' ${StringUtils.generateComment(path.description)}');
} }
// HTTP // HTTP
@ -226,8 +226,8 @@ class RetrofitApiGenerator extends BaseGenerator {
if (operationId.toLowerCase().startsWith(method)) { if (operationId.toLowerCase().startsWith(method)) {
return StringUtils.toCamelCase(operationId); return StringUtils.toCamelCase(operationId);
} }
// HTTP // 使 operationId HTTP
return '$method${StringUtils.toPascalCase(operationId)}'; return StringUtils.toCamelCase(operationId);
} }
// /api/v1 // /api/v1
@ -247,34 +247,18 @@ class RetrofitApiGenerator extends BaseGenerator {
// /TaskSummarize/GetSummarizeTaskByDate -> getSummarizeTaskByDate // /TaskSummarize/GetSummarizeTaskByDate -> getSummarizeTaskByDate
final action = StringUtils.toPascalCase(pathParts[1]); final action = StringUtils.toPascalCase(pathParts[1]);
// HTTP方法开头 return StringUtils.toCamelCase(action);
final actionLower = action.toLowerCase();
if (actionLower.startsWith(method)) {
// HTTP方法前缀
final cleanAction = action.substring(method.length);
return '$method${StringUtils.toPascalCase(cleanAction)}';
}
return '$method$action';
} else if (pathParts.length == 1) { } else if (pathParts.length == 1) {
// /HealthCheck -> getHealthCheck // /HealthCheck -> healthCheck
final action = StringUtils.toPascalCase(pathParts[0]); final action = StringUtils.toPascalCase(pathParts[0]);
// HTTP方法开头 return StringUtils.toCamelCase(action);
final actionLower = action.toLowerCase();
if (actionLower.startsWith(method)) {
// HTTP方法前缀
final cleanAction = action.substring(method.length);
return '$method${StringUtils.toPascalCase(cleanAction)}';
}
return '$method$action';
} }
// 使 // 使
final sanitizedPath = final sanitizedPath =
pathParts.map((part) => StringUtils.toPascalCase(part)).join(''); pathParts.map((part) => StringUtils.toPascalCase(part)).join('');
return '$method$sanitizedPath'; return StringUtils.toCamelCase(sanitizedPath);
} }
/// ///
@ -649,7 +633,7 @@ class RetrofitApiGenerator extends BaseGenerator {
.toList(); .toList();
for (final param in pathParams) { for (final param in pathParams) {
parameters.add(ApiMethodParameter( parameters.add(ApiMethodParameter(
name: StringUtils.toCamelCase(param.name), name: StringUtils.toDartPropertyName(param.name),
type: _getDartType(param.type), type: _getDartType(param.type),
annotation: useRetrofit ? '@Path(\'${param.name}\')' : '', annotation: useRetrofit ? '@Path(\'${param.name}\')' : '',
required: param.required, required: param.required,
@ -680,7 +664,7 @@ class RetrofitApiGenerator extends BaseGenerator {
for (final param in queryParams) { for (final param in queryParams) {
final nullable = param.required ? '' : '?'; final nullable = param.required ? '' : '?';
parameters.add(ApiMethodParameter( parameters.add(ApiMethodParameter(
name: StringUtils.toCamelCase(param.name), name: StringUtils.toDartPropertyName(param.name),
type: '${_getDartType(param.type)}$nullable', type: '${_getDartType(param.type)}$nullable',
annotation: useRetrofit ? '@Query(\'${param.name}\')' : '', annotation: useRetrofit ? '@Query(\'${param.name}\')' : '',
required: param.required, required: param.required,
@ -695,7 +679,7 @@ class RetrofitApiGenerator extends BaseGenerator {
for (final param in bodyParams) { for (final param in bodyParams) {
final bodyType = _inferRequestBodyType(path); final bodyType = _inferRequestBodyType(path);
parameters.add(ApiMethodParameter( parameters.add(ApiMethodParameter(
name: StringUtils.toCamelCase( name: StringUtils.toDartPropertyName(
param.name.isNotEmpty ? param.name : 'request'), param.name.isNotEmpty ? param.name : 'request'),
type: bodyType, type: bodyType,
annotation: useRetrofit ? '@Body()' : '', annotation: useRetrofit ? '@Body()' : '',
@ -1037,7 +1021,7 @@ class RetrofitApiGenerator extends BaseGenerator {
for (final tagName in tagGroups.keys) { for (final tagName in tagGroups.keys) {
final className = _generateTagClassName(tagName); final className = _generateTagClassName(tagName);
buffer.writeln( buffer.writeln(
' late final $className _${StringUtils.toCamelCase(tagName)}Api;'); ' late final $className _${StringUtils.toDartPropertyName(tagName)}Api;');
} }
buffer.writeln(''); buffer.writeln('');
@ -1046,7 +1030,7 @@ class RetrofitApiGenerator extends BaseGenerator {
buffer.writeln(' $className(this._dio, {String? baseUrl}) {'); buffer.writeln(' $className(this._dio, {String? baseUrl}) {');
for (final tagName in tagGroups.keys) { for (final tagName in tagGroups.keys) {
final className = _generateTagClassName(tagName); final className = _generateTagClassName(tagName);
final fieldName = '_${StringUtils.toCamelCase(tagName)}Api'; final fieldName = '_${StringUtils.toDartPropertyName(tagName)}Api';
buffer.writeln(' $fieldName = $className(_dio, baseUrl: baseUrl);'); buffer.writeln(' $fieldName = $className(_dio, baseUrl: baseUrl);');
} }
buffer.writeln(' }'); buffer.writeln(' }');
@ -1056,10 +1040,10 @@ class RetrofitApiGenerator extends BaseGenerator {
// tag // tag
for (final tagName in tagGroups.keys) { for (final tagName in tagGroups.keys) {
final className = _generateTagClassName(tagName); final className = _generateTagClassName(tagName);
final fieldName = '_${StringUtils.toCamelCase(tagName)}Api'; final fieldName = '_${StringUtils.toDartPropertyName(tagName)}Api';
buffer.writeln(' /// ${tagName}相关API'); buffer.writeln(' /// ${tagName}相关API');
buffer.writeln( buffer.writeln(
' $className get ${StringUtils.toCamelCase(tagName)} => $fieldName;'); ' $className get ${StringUtils.toDartPropertyName(tagName)} => $fieldName;');
buffer.writeln(''); buffer.writeln('');
} }
@ -1343,9 +1327,9 @@ class RetrofitApiGenerator extends BaseGenerator {
final buffer = StringBuffer(); final buffer = StringBuffer();
// //
buffer.writeln('/// 参数实体类 - $className'); buffer.writeln('// 参数实体类 - $className');
buffer.writeln( buffer.writeln(
'/// 用于 ${path.method.value.toUpperCase()} ${path.path} 的查询参数'); '// 用于 ${path.method.value.toUpperCase()} ${path.path} 的查询参数');
buffer.writeln(''); buffer.writeln('');
// //
@ -1361,7 +1345,7 @@ class RetrofitApiGenerator extends BaseGenerator {
// //
for (final param in queryParams) { for (final param in queryParams) {
final dartName = StringUtils.toCamelCase(param.name); final dartName = StringUtils.toDartPropertyName(param.name);
final dartType = _getDartType(param.type); final dartType = _getDartType(param.type);
final nullable = param.required ? '' : '?'; final nullable = param.required ? '' : '?';
@ -1381,7 +1365,7 @@ class RetrofitApiGenerator extends BaseGenerator {
// //
buffer.writeln(' const $className({'); buffer.writeln(' const $className({');
for (final param in queryParams) { for (final param in queryParams) {
final dartName = StringUtils.toCamelCase(param.name); final dartName = StringUtils.toDartPropertyName(param.name);
final required = param.required ? 'required ' : ''; final required = param.required ? 'required ' : '';
buffer.writeln(' ${required}this.$dartName,'); buffer.writeln(' ${required}this.$dartName,');
} }
@ -1404,7 +1388,7 @@ class RetrofitApiGenerator extends BaseGenerator {
buffer.writeln(' Map<String, dynamic> toQueryMap() {'); buffer.writeln(' Map<String, dynamic> toQueryMap() {');
buffer.writeln(' final map = <String, dynamic>{};'); buffer.writeln(' final map = <String, dynamic>{};');
for (final param in queryParams) { for (final param in queryParams) {
final dartName = StringUtils.toCamelCase(param.name); final dartName = StringUtils.toDartPropertyName(param.name);
buffer.writeln( buffer.writeln(
' if ($dartName != null) map[\'${param.name}\'] = $dartName;'); ' if ($dartName != null) map[\'${param.name}\'] = $dartName;');
} }

View File

@ -26,6 +26,17 @@ class StringUtils {
static String toCamelCase(String input) { static String toCamelCase(String input) {
if (input.isEmpty) return input; if (input.isEmpty) return input;
// camelCase格式
if (RegExp(r'^[a-z][a-zA-Z0-9]*$').hasMatch(input)) {
return input;
}
// PascalCase格式camelCase
if (RegExp(r'^[A-Z][a-zA-Z0-9]*$').hasMatch(input)) {
return input[0].toLowerCase() + input.substring(1);
}
// 线
final parts = input.split('_').where((p) => p.isNotEmpty).toList(); final parts = input.split('_').where((p) => p.isNotEmpty).toList();
if (parts.isEmpty) return input; if (parts.isEmpty) return input;
@ -95,6 +106,7 @@ class StringUtils {
/// ///
/// - snake_casekebab-case camelCase /// - snake_casekebab-case camelCase
/// - /// -
/// - PascalCasecamelCase
/// - n /// - n
/// - 'property' /// - 'property'
/// ///
@ -104,33 +116,32 @@ class StringUtils {
/// StringUtils.toDartPropertyName('user-id'); // userId /// StringUtils.toDartPropertyName('user-id'); // userId
/// StringUtils.toDartPropertyName('1st_field'); // n1stField /// StringUtils.toDartPropertyName('1st_field'); // n1stField
/// StringUtils.toDartPropertyName('classCadreId'); // classCadreId /// StringUtils.toDartPropertyName('classCadreId'); // classCadreId
/// StringUtils.toDartPropertyName('PageIndex'); // pageIndex
/// StringUtils.toDartPropertyName(''); // property /// StringUtils.toDartPropertyName(''); // property
/// ``` /// ```
static String toDartPropertyName(String propName) { static String toDartPropertyName(String propName) {
// 线 // camelCase命线
if (RegExp(r'^[a-z][a-zA-Z0-9]*$').hasMatch(propName)) { if (RegExp(r'^[a-z][a-zA-Z0-9]*$').hasMatch(propName)) {
return propName; return propName;
} }
// PascalCase camelCase
if (RegExp(r'^[A-Z][a-zA-Z0-9]*$').hasMatch(propName)) {
return propName[0].toLowerCase() + propName.substring(1);
}
// //
String result = propName; String result = propName;
// //
if (RegExp(r'^[0-9]').hasMatch(result)) { if (RegExp(r'^[0-9]').hasMatch(result)) {
result = 'n$result'; result = 'n$result';
} }
// 线 // 线
result = result.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_'); result = result.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_');
// camelCase // camelCase
result = toCamelCase(result); result = toCamelCase(result);
// //
if (result.isEmpty) { if (result.isEmpty) {
result = 'property'; result = 'property';
} }
return result; return result;
} }
@ -146,7 +157,7 @@ class StringUtils {
// //
cleaned = cleaned cleaned = cleaned
.replaceAll(RegExp(r'[^\w\s\u4e00-\u9fa5(),.。:;!?_/\\-]'), '') .replaceAll(RegExp(r'[^\w\s\u4e00-\u9fa5,.。:;!?_/\\-]'), '')
.replaceAll(RegExp(r'\s+'), ' ') .replaceAll(RegExp(r'\s+'), ' ')
.trim(); .trim();

21
test_function_name.dart Normal file
View File

@ -0,0 +1,21 @@
import 'lib/utils/string_utils.dart';
void main() {
print('Testing function name generation:');
print(
'GetClassesTaskChecklistUsers -> ${StringUtils.toCamelCase('GetClassesTaskChecklistUsers')}');
print('GetUserInfo -> ${StringUtils.toCamelCase('GetUserInfo')}');
print('CreateTask -> ${StringUtils.toCamelCase('CreateTask')}');
print('UpdateUserProfile -> ${StringUtils.toCamelCase('UpdateUserProfile')}');
print('DeleteTaskById -> ${StringUtils.toCamelCase('DeleteTaskById')}');
print('\nTesting existing camelCase:');
print(
'getClassesTaskChecklistUsers -> ${StringUtils.toCamelCase('getClassesTaskChecklistUsers')}');
print('getUserInfo -> ${StringUtils.toCamelCase('getUserInfo')}');
print('\nTesting snake_case:');
print(
'get_classes_task_checklist_users -> ${StringUtils.toCamelCase('get_classes_task_checklist_users')}');
print('get_user_info -> ${StringUtils.toCamelCase('get_user_info')}');
}

View File

@ -1,7 +1,6 @@
import 'lib/utils/string_utils.dart'; import 'lib/utils/string_utils.dart';
void main() { void main() {
//
print('Testing property name conversion:'); print('Testing property name conversion:');
print('classCadreId -> ${StringUtils.toDartPropertyName('classCadreId')}'); print('classCadreId -> ${StringUtils.toDartPropertyName('classCadreId')}');
print('meetingTitle -> ${StringUtils.toDartPropertyName('meetingTitle')}'); print('meetingTitle -> ${StringUtils.toDartPropertyName('meetingTitle')}');
@ -11,10 +10,67 @@ void main() {
print( print(
'sunTaskFileResults -> ${StringUtils.toDartPropertyName('sunTaskFileResults')}'); 'sunTaskFileResults -> ${StringUtils.toDartPropertyName('sunTaskFileResults')}');
// 线
print('\nTesting snake_case conversion:'); print('\nTesting snake_case conversion:');
print( print(
'class_cadre_id -> ${StringUtils.toDartPropertyName('class_cadre_id')}'); 'class_cadre_id -> ${StringUtils.toDartPropertyName('class_cadre_id')}');
print('meeting_title -> ${StringUtils.toDartPropertyName('meeting_title')}'); print('meeting_title -> ${StringUtils.toDartPropertyName('meeting_title')}');
print('task_info -> ${StringUtils.toDartPropertyName('task_info')}'); print('task_info -> ${StringUtils.toDartPropertyName('task_info')}');
print('\nTesting problematic field names:');
print('PageIndex -> ${StringUtils.toDartPropertyName('PageIndex')}');
print('ProblemTitle -> ${StringUtils.toDartPropertyName('ProblemTitle')}');
print('ProblemObj -> ${StringUtils.toDartPropertyName('ProblemObj')}');
print(
'ProblemPhenomenon -> ${StringUtils.toDartPropertyName('ProblemPhenomenon')}');
print('ClassesId -> ${StringUtils.toDartPropertyName('ClassesId')}');
print(
'ProblemTaskType -> ${StringUtils.toDartPropertyName('ProblemTaskType')}');
print('PageSize -> ${StringUtils.toDartPropertyName('PageSize')}');
print('\nTesting parameter name conversion:');
print('api-version -> ${StringUtils.toDartPropertyName('api-version')}');
print('user-id -> ${StringUtils.toDartPropertyName('user-id')}');
print('file_name -> ${StringUtils.toDartPropertyName('file_name')}');
print('with space -> ${StringUtils.toDartPropertyName('with space')}');
print('\nTesting kebab-case conversion:');
print('api-version -> ${StringUtils.toDartPropertyName('api-version')}');
print('user-id -> ${StringUtils.toDartPropertyName('user-id')}');
print('page-size -> ${StringUtils.toDartPropertyName('page-size')}');
print('to-camel-case -> ${StringUtils.toDartPropertyName('to-camel-case')}');
print('\nTesting tag names:');
print(
'Follow Manager -> ${StringUtils.toDartPropertyName('Follow Manager')}');
print('Health Check -> ${StringUtils.toDartPropertyName('Health Check')}');
print(
'Mobile Manager -> ${StringUtils.toDartPropertyName('Mobile Manager')}');
print('My Info -> ${StringUtils.toDartPropertyName('My Info')}');
print(
'Task Class Cadre Meeting -> ${StringUtils.toDartPropertyName('Task Class Cadre Meeting')}');
print(
'Task Class Meeting -> ${StringUtils.toDartPropertyName('Task Class Meeting')}');
print(
'Task Coach Sub -> ${StringUtils.toDartPropertyName('Task Coach Sub')}');
print('Task Cultural -> ${StringUtils.toDartPropertyName('Task Cultural')}');
print(
'Task Data Collect -> ${StringUtils.toDartPropertyName('Task Data Collect')}');
print('Task Follow -> ${StringUtils.toDartPropertyName('Task Follow')}');
print('Task Info -> ${StringUtils.toDartPropertyName('Task Info')}');
print('Task Meeting -> ${StringUtils.toDartPropertyName('Task Meeting')}');
print('Task Other -> ${StringUtils.toDartPropertyName('Task Other')}');
print('Task Solution -> ${StringUtils.toDartPropertyName('Task Solution')}');
print('Task Spot -> ${StringUtils.toDartPropertyName('Task Spot')}');
print(
'Task Summarize -> ${StringUtils.toDartPropertyName('Task Summarize')}');
print('Task Talk -> ${StringUtils.toDartPropertyName('Task Talk')}');
print(
'Task Teacher Behavior -> ${StringUtils.toDartPropertyName('Task Teacher Behavior')}');
print(
'Task Teacher Talk -> ${StringUtils.toDartPropertyName('Task Teacher Talk')}');
print('\nTesting comment cleaning:');
print('部长新增工作任务指标(会删除所有管理的班级任务指标)-删除所有管理的学习官的通用任务指标');
print(
'Cleaned: ${StringUtils.cleanDescription('部长新增工作任务指标(会删除所有管理的班级任务指标)-删除所有管理的学习官的通用任务指标')}');
} }

View File

@ -32,6 +32,23 @@ void main() {
expect(StringUtils.toCamelCase('api_version'), 'apiVersion'); expect(StringUtils.toCamelCase('api_version'), 'apiVersion');
}); });
test('converts PascalCase to camelCase', () {
expect(StringUtils.toCamelCase('GetClassesTaskChecklistUsers'),
'getClassesTaskChecklistUsers');
expect(StringUtils.toCamelCase('GetUserInfo'), 'getUserInfo');
expect(StringUtils.toCamelCase('CreateTask'), 'createTask');
expect(
StringUtils.toCamelCase('UpdateUserProfile'), 'updateUserProfile');
expect(StringUtils.toCamelCase('DeleteTaskById'), 'deleteTaskById');
});
test('preserves existing camelCase', () {
expect(StringUtils.toCamelCase('getClassesTaskChecklistUsers'),
'getClassesTaskChecklistUsers');
expect(StringUtils.toCamelCase('getUserInfo'), 'getUserInfo');
expect(StringUtils.toCamelCase('createTask'), 'createTask');
});
test('handles single word', () { test('handles single word', () {
expect(StringUtils.toCamelCase('user'), 'user'); expect(StringUtils.toCamelCase('user'), 'user');
expect(StringUtils.toCamelCase(''), ''); expect(StringUtils.toCamelCase(''), '');