Skip to content

Commit 790d844

Browse files
stereotype441Commit Queue
authored andcommitted
[analyzer_utilities] Add String.toSnakeCase extension method.
This extension method complements the existing `toCamelCase` and `toPascalCase` extension methods, allowing a string to be converted from `camelCase` or `PascalCase` to `snake_case`. This extension method will be useful in the analyzer diagnostic message generation logic, which still uses a mix of case styles. Note that there's no need for a separate method to convert to `UPPER_SNAKE_CASE`; that can be easily done by calling `toUpperCase` after `toSnakeCase`. Change-Id: I6a6a69647f4ee176ecdbaefc3de0906a88c69079 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/460206 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent a6faf24 commit 790d844

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

pkg/analyzer_utilities/lib/extensions/string.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
extension StringExtension on String {
6+
static final _toSnakeCaseRegExp = RegExp('_?[A-Z]');
7+
68
/// Converts `SCREAMING_SNAKE_CASE` or `snake_case` to `camelCase`.
79
String toCamelCase() {
810
var parts = toLowerCase().split('_');
@@ -51,4 +53,26 @@ extension StringExtension on String {
5153
}
5254
return buffer.toString();
5355
}
56+
57+
/// Converts `camelCase` or `PascalCase` to `snake_case`
58+
String toSnakeCase() {
59+
var parts = <String>[];
60+
var i = 0;
61+
var wordStarts = _toSnakeCaseRegExp.allMatches(this);
62+
for (var RegExpMatch(:start) in wordStarts) {
63+
if (i < start) {
64+
parts.add(substring(i, start).toLowerCase());
65+
i = start;
66+
}
67+
if (this[i] == '_' && parts.isNotEmpty) {
68+
// Avoid doubling up the `_`. This handles strings that are already in
69+
// snake case like `foo_Bar` (which translates to `foo_bar`).
70+
i++;
71+
}
72+
}
73+
if (i < length) {
74+
parts.add(substring(i).toLowerCase());
75+
}
76+
return parts.join('_');
77+
}
5478
}

pkg/analyzer_utilities/test/extensions/string_test.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,20 @@ class StringExtensionTest {
4141
expect('FOO__BAR'.toPascalCase(), 'FooBar');
4242
expect('FOO_BAR_'.toPascalCase(), 'FooBar');
4343
}
44+
45+
void test_toSnakeCase() {
46+
expect('camelCase'.toSnakeCase(), 'camel_case');
47+
expect('PascalCase'.toSnakeCase(), 'pascal_case');
48+
expect('already_snake_case'.toSnakeCase(), 'already_snake_case');
49+
expect(
50+
'mixedCamel_AndPascal_and_snake'.toSnakeCase(),
51+
'mixed_camel_and_pascal_and_snake',
52+
);
53+
expect('with123Numbers'.toSnakeCase(), 'with123_numbers');
54+
expect(''.toSnakeCase(), '');
55+
expect(
56+
'CONSECUTIVE_UPCASE'.toSnakeCase(),
57+
'c_o_n_s_e_c_u_t_i_v_e_u_p_c_a_s_e',
58+
);
59+
}
4460
}

0 commit comments

Comments
 (0)