swagger_generator_flutter/lib/utils/string_utils.dart

355 lines
11 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.

/// 字符串工具类
///
/// 提供常用的字符串处理功能,包括命名风格转换、注释生成等。
///
/// # 典型用法示例
/// ```dart
/// // snake_case 转 camelCase
/// StringUtils.toDartPropertyName('user_id'); // userId
/// // 含特殊字符
/// StringUtils.toDartPropertyName('user-id'); // userId
/// // 数字开头
/// StringUtils.toDartPropertyName('1st_field'); // n1stField
/// // 空字符串
/// StringUtils.toDartPropertyName(''); // property
/// ```
///
/// This utility provides string conversion helpers for code generation, such as
/// converting snake_case to camelCase, generating Dart class names, and cleaning descriptions.
///
library;
import '../core/models.dart';
class StringUtils {
/// 转换为camelCase
static String toCamelCase(String 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();
if (parts.isEmpty) return input;
String result = parts.first.toLowerCase();
for (int i = 1; i < parts.length; i++) {
final part = parts[i];
if (part.isNotEmpty) {
result += part[0].toUpperCase() + part.substring(1).toLowerCase();
}
}
return result.isEmpty ? input : result;
}
/// 转换为PascalCase
static String toPascalCase(String input) {
if (input.isEmpty) return input;
// 如果输入包含下划线,先按下划线分割并转换每个部分
if (input.contains('_')) {
final parts = input.split('_');
String result = '';
for (final part in parts) {
if (part.isNotEmpty) {
// 保持每个部分的原始大小写,只确保首字母大写
if (part[0].toUpperCase() == part[0]) {
// 如果首字母已经是大写,保持整个部分不变
result += part;
} else {
// 如果首字母是小写,只转换首字母为大写
result += part[0].toUpperCase() + part.substring(1);
}
}
}
return result.isEmpty ? input : result;
}
// 如果输入已经是PascalCase格式没有下划线且首字母大写直接返回
if (input[0].toUpperCase() == input[0]) {
return input;
}
// 如果输入是camelCase格式没有下划线转换首字母为大写
if (RegExp(r'^[a-zA-Z][a-zA-Z0-9]*$').hasMatch(input)) {
return input[0].toUpperCase() + input.substring(1);
}
return input;
}
/// 转换为snake_case
static String toSnakeCase(String input) {
if (input.isEmpty) return input;
// 处理PascalCase和camelCase
final result =
input.replaceAllMapped(RegExp(r'([A-Z]+)([A-Z][a-z])'), (match) {
return '${match[1]!.substring(0, match[1]!.length - 1)}_${match[2]}';
}).replaceAllMapped(RegExp(r'([a-z\d])([A-Z])'), (match) {
return '${match[1]}_${match[2]}';
}).toLowerCase();
return result;
}
/// 转换为符合Dart命名规范的属性名
///
/// - 支持 snake_case、kebab-case、空格、特殊字符自动转为 camelCase
/// - 已经是驼峰命名的字符串保持不变
/// - PascalCase首字母大写转换为camelCase首字母小写
/// - 数字开头自动加前缀 n
/// - 空字符串返回 'property'
///
/// # 示例
/// ```dart
/// StringUtils.toDartPropertyName('user_id'); // userId
/// StringUtils.toDartPropertyName('user-id'); // userId
/// StringUtils.toDartPropertyName('1st_field'); // n1stField
/// StringUtils.toDartPropertyName('classCadreId'); // classCadreId
/// StringUtils.toDartPropertyName('PageIndex'); // pageIndex
/// StringUtils.toDartPropertyName(''); // property
/// ```
static String toDartPropertyName(String propName) {
// 如果已经是camelCase命名没有下划线且首字母小写直接返回
if (RegExp(r'^[a-z][a-zA-Z0-9]*$').hasMatch(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;
// 如果以数字开头,添加前缀
if (RegExp(r'^[0-9]').hasMatch(result)) {
result = 'n$result';
}
// 替换特殊字符为下划线
result = result.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_');
// 转换为camelCase
result = toCamelCase(result);
// 确保不为空
if (result.isEmpty) {
result = 'property';
}
return result;
}
/// 清理描述文本,移除特殊字符和格式化多行注释
static String cleanDescription(String description) {
if (description.isEmpty) return description;
// 移除多余的空白字符和换行符
String cleaned = description
.replaceAll(RegExp(r'\s+'), ' ')
.replaceAll(RegExp(r'[\r\n]+'), ' ')
.trim();
// 移除可能引起语法错误的特殊字符
cleaned = cleaned
.replaceAll(RegExp(r'[^\w\s\u4e00-\u9fa5,.。:;!?_/\\-]'), '')
.replaceAll(RegExp(r'\s+'), ' ')
.trim();
// 如果描述过长截取前200个字符
if (cleaned.length > 200) {
cleaned = '${cleaned.substring(0, 200)}...';
}
return cleaned;
}
/// 生成端点名称
static String generateEndpointName(String path, String? operationId) {
// 如果有operationId优先使用
if (operationId != null && operationId.isNotEmpty) {
return toCamelCase(operationId);
}
// 移除路径中的版本前缀
String cleanPath = path.replaceFirst('/api/v1', '');
// 移除开头的斜杠
if (cleanPath.startsWith('/')) {
cleanPath = cleanPath.substring(1);
}
// 将路径转换为camelCase
final parts = cleanPath.split('/');
if (parts.length >= 2) {
final controller = parts[0];
final action = parts[1];
// 特殊情况处理
if (controller.toLowerCase() == 'login' &&
action.toLowerCase() == 'userlogin') {
return 'login';
}
// 转换为camelCase
return toCamelCase('${controller}_$action');
}
return toCamelCase(cleanPath.replaceAll('/', '_'));
}
/// 生成Dart类名
static String generateClassName(String name) {
// 确保类名以大写字母开头
final cleanName = name.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_');
return toPascalCase(cleanName);
}
/// 生成文件名
static String generateFileName(String name) {
// 转换为snake_case并添加.dart扩展名
return '${toSnakeCase(name)}.dart';
}
/// 验证是否为有效的Dart标识符
static bool isValidDartIdentifier(String identifier) {
if (identifier.isEmpty) return false;
// Dart标识符规则以字母或下划线开头后面可以是字母、数字或下划线
final regex = RegExp(r'^[a-zA-Z_][a-zA-Z0-9_]*$');
return regex.hasMatch(identifier);
}
/// 生成枚举值名称
static String generateEnumValueName(dynamic value, int index) {
if (value is String) {
// 尝试从字符串生成合法的枚举名
final cleanValue = value.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '');
if (cleanValue.isNotEmpty && isValidDartIdentifier(cleanValue)) {
return toCamelCase(cleanValue);
}
}
// 默认使用 value + 索引
return 'value${index + 1}';
}
/// 提取控制器名称
static String extractControllerName(ApiPath path) {
// 从tags中提取控制器名称
if (path.tags.isNotEmpty) {
return path.tags.first;
}
// 从路径中提取控制器名称
final pathParts = path.path.split('/');
if (pathParts.length > 1) {
return toPascalCase(pathParts[1]);
}
return 'General';
}
/// 清理路径,保留版本前缀
static String cleanPath(String path) {
// 保留版本前缀,只清理其他不必要的字符
return path;
}
/// 格式化字节大小
static String formatBytes(int bytes) {
if (bytes < 1024) return '${bytes}B';
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}KB';
if (bytes < 1024 * 1024 * 1024)
return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}MB';
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(1)}GB';
}
/// 格式化持续时间
static String formatDuration(Duration duration) {
if (duration.inMilliseconds >= 1000) {
return '${(duration.inMilliseconds / 1000).toStringAsFixed(2)}';
} else {
return '${duration.inMilliseconds}毫秒';
}
}
/// 转义字符串中的特殊字符
String escapeString(String input) {
return input
.replaceAll('\\', '\\\\')
.replaceAll('"', '\\"')
.replaceAll('\n', '\\n')
.replaceAll('\r', '\\r')
.replaceAll('\t', '\\t');
}
/// 缩进文本
String indent(String text, int spaces) {
final indentation = ' ' * spaces;
return text.split('\n').map((line) => '$indentation$line').join('\n');
}
/// 生成注释块
static String generateComment(String text, {bool isBlock = false}) {
if (text.isEmpty) return '';
final cleanText = cleanDescription(text);
if (isBlock) {
return '/**\n * $cleanText\n */';
} else {
return '/// $cleanText';
}
}
/// pluralize 单词
String pluralize(String word) {
if (word.isEmpty) return word;
final lowerWord = word.toLowerCase();
// 特殊复数形式
const irregularPlurals = {
'child': 'children',
'person': 'people',
'man': 'men',
'woman': 'women',
'mouse': 'mice',
'goose': 'geese',
};
if (irregularPlurals.containsKey(lowerWord)) {
return irregularPlurals[lowerWord]!;
}
// 规则复数形式
if (lowerWord.endsWith('y')) {
return '${word.substring(0, word.length - 1)}ies';
} else if (lowerWord.endsWith('s') ||
lowerWord.endsWith('sh') ||
lowerWord.endsWith('ch') ||
lowerWord.endsWith('x') ||
lowerWord.endsWith('z')) {
return '${word}es';
} else {
return '${word}s';
}
}
/// 生成文件头注释
static String generateFileHeader(String description, String source) {
final timestamp = DateTime.now().toIso8601String();
return '''// $description
// 基于 Swagger API 文档:
// 自动生成于: $timestamp by Max
// Copyright (C) 2025 YuanXuan. All rights reserved.
''';
}
}