Skip to content

Commit 01bf406

Browse files
authored
Migrate string_utils (#60)
The built-in conversion has some problems, mainly that it recognizes pascal case as camel case, while `lowerCamelCase()` is the actual camel case. Plus, the actual implementation of the "camel case" doesn't work. Therefore, the package `change_case` is introduced to solve this. For backwards compatibility, the naming will be preserved for now.
1 parent 5073c7a commit 01bf406

File tree

3 files changed

+90
-27
lines changed

3 files changed

+90
-27
lines changed

angular_components/lib/utils/strings/string_utils.dart

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,36 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:change_case/change_case.dart';
6+
57
final RegExp _camelCaseSplitter = RegExp('([a-z])([A-Z])');
68

79
final RegExp _capitalLetter = RegExp('[A-Z]');
810

911
final RegExp _wordBreakSplitter = RegExp(r'[\s\-_]');
1012

11-
final RegExp _wordBreak = RegExp(r'(^|[\-_ ])(\w)');
13+
// This is removed after the `change_case` package is used for `camelCase()`.
14+
// final RegExp _wordBreak = RegExp(r'(^|[\-_ ])(\w)');
1215

1316
/// Returns the hyphenated form of [s].
1417
///
15-
/// The string is also made lower case.
16-
String hyphenate(String s) => _split(s).join('-').toLowerCase();
18+
/// For details on what characters split the string, see the [split] function.
19+
///
20+
/// In addition, the entire string is made lower case.
21+
String hyphenate(String s) => split(s).join('-').toLowerCase();
1722

1823
/// Returns the underscored form of [s].
1924
///
20-
/// The string is also made lower case.
21-
String underscore(String s) => _split(s).join('_').toLowerCase();
25+
/// For details on what characters split the string, see the [split] function.
26+
///
27+
/// In addition, the entire string is made lower case.
28+
String underscore(String s) => split(s).join('_').toLowerCase();
2229

2330
/// Returns the camel-cased form of [s].
2431
///
32+
/// **NOTE**: technically this is pascal case, but for legacy reasons the name
33+
/// is perserved. This will be changed in later versions.
34+
///
2535
/// This is a very simple function: it merely replaces usual delimiters (spaces,
2636
/// hyphens, underscores) and the following word-character, with the upper case
2737
/// form of the word-character. It doesn't change the case of any other letters.
@@ -42,10 +52,12 @@ String underscore(String s) => _split(s).join('_').toLowerCase();
4252
/// * "1337" => "1337"
4353
/// * "foo3bar" => "Foo3bar"
4454
/// * "3bar" => "3bar"
45-
String camelCase(String s) =>
46-
s.replaceAllMapped(_wordBreak, (m) => m[2]?.toUpperCase() ?? '');
55+
// TODO: this is actually pascal case. Change all references.
56+
String camelCase(String s) => s.toPascalCase();
4757

4858
/// Returns the lower-camel-cased form of [s].
59+
///
60+
/// By common definition, this is the actual camel case!
4961
String lowerCamelCase(String s) {
5062
String result = camelCase(s);
5163
result = result.replaceRange(0, 1, s[0].toLowerCase());
@@ -60,15 +72,15 @@ String titleCase(String s) =>
6072
/// Returns the String [s], with the first letter capitalized.
6173
String capitalizeFirstLetter(s) => s[0].toUpperCase() + s.substring(1);
6274

63-
// Splits [s] into tokens.
64-
//
65-
// Splits occur on:
66-
//
67-
// * Whitespace: "foo bar" => ["foo", "bar"]
68-
// * Hyphens: "foo-bar" => ["foo", "bar"]
69-
// * Underscores: "foo_bar" => ["foo", "bar"]
70-
// * Camelcasing: "fooBar" => ["foo", "Bar"]
71-
List<String> _split(String s) => s
75+
/// Splits [s] into tokens.
76+
///
77+
/// Splits occur on:
78+
///
79+
/// * Whitespace: "foo bar" => ["foo", "bar"]
80+
/// * Hyphens: "foo-bar" => ["foo", "bar"]
81+
/// * Underscores: "foo_bar" => ["foo", "bar"]
82+
/// * Camelcasing: "fooBar" => ["foo", "Bar"]
83+
List<String> split(String s) => s
7284
// Convert camelCase splitting into word splitting.
7385
.replaceAllMapped(_camelCaseSplitter, (m) => '${m[1]} ${m[2]}')
7486
.split(_wordBreakSplitter);

angular_components/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies:
1616
build: ^2.1.1
1717
build_config: ^1.0.0
1818
built_collection: ^5.1.1
19+
change_case: ^1.0.1
1920
collection: ^1.15.0-nullsafety.4
2021
fixnum: ^1.0.0
2122
intl: ^0.17.0

angular_components/test/utils/strings/string_utils_test.dart

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,66 @@ import 'package:test/test.dart';
66
import 'package:angular_components/utils/strings/string_utils.dart';
77

88
void main() {
9-
test('Ensure camelCase converts correctly', () {
10-
const result1 = 'FooBar';
11-
const result2 = 'Foo';
12-
13-
expect(camelCase('foo bar'), result1);
14-
expect(camelCase('foo-bar'), result1);
15-
expect(camelCase('foo_bar'), result1);
16-
// expect(camelCase('foo\bar'), r'Foo\Bar');
17-
expect(camelCase('foo'), result2);
18-
// expect(camelCase('foo '), result2);
19-
// expect(camelCase('_foo'), result2);
9+
group('Utils test | string_utils |', () {
10+
test('ensure `split()` split strings correctly', () {
11+
const result1 = ['foo', 'bar'];
12+
13+
expect(split('foo bar'), result1);
14+
expect(split('foo-bar'), result1);
15+
expect(split('foo_bar'), result1);
16+
expect(split('fooBar'), ['foo', 'Bar']);
17+
});
18+
19+
test('ensure camel case converts correctly', () {
20+
const result1 = 'FooBar';
21+
const result2 = 'Foo';
22+
23+
expect(camelCase('foo bar'), result1);
24+
expect(camelCase('foo-bar'), result1);
25+
expect(camelCase('foo_bar'), result1);
26+
expect(camelCase('foo\\bar'), result1);
27+
expect(camelCase('foo'), result2);
28+
expect(camelCase('foo '), result2);
29+
expect(camelCase('foo-'), result2);
30+
expect(camelCase('_foo'), result2);
31+
expect(camelCase(''), '');
32+
expect(' ', ' ');
33+
// expect(' -word', ' Word');
34+
expect('1336', '1336');
35+
// expect('foo3bar', 'Foo3bar');
36+
expect('3bar', '3bar');
37+
});
38+
39+
test('ensure hyphenate converts correctly', () {
40+
const result1 = 'bad-apple';
41+
42+
expect(hyphenate('bad apple'), result1);
43+
expect(hyphenate('Bad apple'), result1);
44+
expect(hyphenate('Bad Apple'), result1);
45+
expect(hyphenate('bAd AppLe'), 'b-ad-app-le');
46+
expect(hyphenate('bAd 3AppLe'), 'b-ad-3app-le');
47+
expect(hyphenate('bAd App3Le'), 'b-ad-app3le');
48+
});
49+
50+
test('ensure underscore converts correctly', () {
51+
const result1 = 'nice_peach';
52+
53+
expect(underscore('nice peach'), result1);
54+
expect(underscore('nice Peach'), result1);
55+
expect(underscore('Nice Peach'), result1);
56+
expect(underscore('niCe PeaCh'), 'ni_ce_pea_ch');
57+
expect(underscore('niCe 3PeaCh'), 'ni_ce_3pea_ch');
58+
expect(underscore('niCe Pea3Ch'), 'ni_ce_pea3ch');
59+
});
60+
61+
test('ensure lower camel case converts correctly', () {
62+
expect(lowerCamelCase('dart is cool'), 'dartIsCool');
63+
expect(lowerCamelCase('dart is 2cool'), 'dartIs2cool');
64+
});
65+
66+
test('ensure title case converts correctly', () {
67+
expect(titleCase('ToKillAMockingbird'), 'To Kill A Mockingbird');
68+
expect(titleCase('Gone with the wind'), 'Gone with the wind');
69+
});
2070
});
2171
}

0 commit comments

Comments
 (0)