Skip to content

Commit 5ae7850

Browse files
committed
feat: support multi scopes (#10)
1 parent 722c6b4 commit 5ae7850

File tree

4 files changed

+54
-24
lines changed

4 files changed

+54
-24
lines changed

lib/src/ensure.dart

+29-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import 'package:change_case/change_case.dart';
22

33
import 'types/case.dart';
44

5-
bool ensureCase(String raw, Case target) {
5+
bool ensureCase(dynamic raw, Case target) {
6+
if (raw is Iterable) {
7+
return raw.isEmpty || raw.every((element) => ensureCase(element, target));
8+
}
9+
if (raw is! String) {
10+
return false;
11+
}
612
switch (target) {
713
case Case.lower:
814
return raw.toLowerCase() == raw;
@@ -31,16 +37,34 @@ bool ensureLeadingBlank(String raw) {
3137
return raw.startsWith('\n');
3238
}
3339

34-
bool ensureMaxLength(String raw, num maxLength) {
35-
return raw.length <= maxLength;
40+
bool ensureMaxLength(dynamic raw, num maxLength) {
41+
if (raw == null) {
42+
return true;
43+
}
44+
if (raw is String) {
45+
return raw.length <= maxLength;
46+
}
47+
if (raw is Iterable) {
48+
return raw.isEmpty || raw.every((element) => element.length <= maxLength);
49+
}
50+
return false;
3651
}
3752

3853
bool ensureMaxLineLength(String raw, num maxLineLength) {
3954
return raw.split('\n').every((line) => ensureMaxLength(line, maxLineLength));
4055
}
4156

42-
bool ensureMinLength(String raw, num minLength) {
43-
return raw.length >= minLength;
57+
bool ensureMinLength(dynamic raw, num minLength) {
58+
if (raw == null) {
59+
return false;
60+
}
61+
if (raw is String) {
62+
return raw.length >= minLength;
63+
}
64+
if (raw is Iterable) {
65+
return raw.isEmpty || raw.every((element) => element.length >= minLength);
66+
}
67+
return false;
4468
}
4569

4670
bool ensureEmpty(dynamic raw) {

lib/src/parse.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ Commit parse(String raw) {
141141
merge: merge,
142142
header: header,
143143
type: headerParts['type'],
144-
scope: headerParts['scope'],
144+
scopes: headerParts['scope']?.split(RegExp(r'(/|,|\\)')),
145145
subject: headerParts['subject'],
146146
body: body != null ? _trimOffNewlines(body) : null,
147147
footer: footer != null ? _trimOffNewlines(footer) : null,

lib/src/types/commit.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
class Commit {
33
final String header;
44
final String? type;
5-
final String? scope;
5+
final List<String>? scopes;
66
final String? subject;
77
final String? body;
88
final String? footer;
@@ -15,7 +15,7 @@ class Commit {
1515
Commit({
1616
required this.header,
1717
this.type,
18-
this.scope,
18+
this.scopes,
1919
this.subject,
2020
this.body,
2121
this.footer,
@@ -29,7 +29,7 @@ class Commit {
2929
Commit.empty()
3030
: header = '',
3131
type = null,
32-
scope = null,
32+
scopes = null,
3333
subject = null,
3434
body = null,
3535
footer = null,
@@ -44,7 +44,7 @@ class Commit {
4444
case CommitComponent.type:
4545
return type as T?;
4646
case CommitComponent.scope:
47-
return scope as T?;
47+
return scopes as T?;
4848
case CommitComponent.subject:
4949
return subject as T?;
5050
case CommitComponent.header:

test/parse_test.dart

+20-14
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ void main() {
2222
expect(commit.notes, equals([]));
2323
expect(commit.references, equals([]));
2424
expect(commit.type, equals(null));
25-
expect(commit.scope, equals(null));
25+
expect(commit.scopes, equals(null));
2626
expect(commit.subject, equals(null));
2727
});
2828
test('supports `type(scope): subject`', () {
@@ -35,7 +35,7 @@ void main() {
3535
expect(commit.notes, equals([]));
3636
expect(commit.references, equals([]));
3737
expect(commit.type, equals('type'));
38-
expect(commit.scope, equals('scope'));
38+
expect(commit.scopes, equals(['scope']));
3939
expect(commit.subject, equals('subject'));
4040
});
4141
test('supports `type!: subject`', () {
@@ -48,7 +48,7 @@ void main() {
4848
expect(commit.notes, equals([]));
4949
expect(commit.references, equals([]));
5050
expect(commit.type, equals('type'));
51-
expect(commit.scope, equals(null));
51+
expect(commit.scopes, equals(null));
5252
expect(commit.subject, equals('subject'));
5353
});
5454
test('supports `type(scope)!: subject`', () {
@@ -61,18 +61,24 @@ void main() {
6161
expect(commit.notes, equals([]));
6262
expect(commit.references, equals([]));
6363
expect(commit.type, equals('type'));
64-
expect(commit.scope, equals('scope'));
64+
expect(commit.scopes, equals(['scope']));
6565
expect(commit.subject, equals('subject'));
6666
});
67-
test('supports scopes with /', () {
68-
const message = 'type(some/scope): subject';
67+
test('supports multi scopes separated by `/`', () {
68+
const message = 'type(multi/scope): subject';
6969
final commit = parse(message);
70-
expect(commit.scope, equals('some/scope'));
70+
expect(commit.scopes, equals(['multi', 'scope']));
71+
expect(commit.subject, equals('subject'));
72+
});
73+
test('supports multi scopes separated by `,`)', () {
74+
const message = 'type(multi,scope): subject';
75+
final commit = parse(message);
76+
expect(commit.scopes, equals(['multi', 'scope']));
7177
expect(commit.subject, equals('subject'));
7278
});
7379

7480
test('keep -side notes- in the body section', () {
75-
final header = "type(some/scope): subject";
81+
final header = "type(scope): subject";
7682
final body =
7783
"CI on master branch caught this:\n\n```\nUnhandled Exception:\nSystem.AggregateException: One or more errors occurred. (Some problem when connecting to 'api.mycryptoapi.com/eth')\n\n--- End of stack trace from previous location where exception was thrown ---\n\nat GWallet.Backend.FSharpUtil.ReRaise (System.Exception ex) [0x00000] in /Users/runner/work/geewallet/geewallet/src/GWallet.Backend/FSharpUtil.fs:206\n...\n```";
7884
final message = "$header\n\n$body";
@@ -88,7 +94,7 @@ void main() {
8894
const message = 'fix(面试评价): 测试';
8995
final commit = parse(message);
9096
expect(commit.subject, isNotNull);
91-
expect(commit.scope, isNotNull);
97+
expect(commit.scopes, isNotNull);
9298
});
9399
test('should trim extra newlines', () {
94100
final commit = parse(
@@ -104,7 +110,7 @@ void main() {
104110
expect(commit.header,
105111
equals('feat(scope): broadcast destroy event on scope destruction'));
106112
expect(commit.type, equals('feat'));
107-
expect(commit.scope, equals('scope'));
113+
expect(commit.scopes, equals(['scope']));
108114
expect(commit.subject,
109115
equals('broadcast destroy event on scope destruction'));
110116
expect(
@@ -156,7 +162,7 @@ void main() {
156162
equals(
157163
' feat(scope): broadcast destroy event on scope destruction '));
158164
expect(commit.type, equals(null));
159-
expect(commit.scope, equals(null));
165+
expect(commit.scopes, equals(null));
160166
expect(commit.subject, equals(null));
161167
expect(
162168
commit.body,
@@ -200,7 +206,7 @@ void main() {
200206
expect(commit.header,
201207
equals('feat(scope): broadcast destroy event on scope destruction'));
202208
expect(commit.type, equals('feat'));
203-
expect(commit.scope, equals('scope'));
209+
expect(commit.scopes, equals(['scope']));
204210
expect(commit.subject,
205211
equals('broadcast destroy event on scope destruction'));
206212
expect(
@@ -267,7 +273,7 @@ void main() {
267273

268274
test('should understand header parts in GitHub like pull request', () {
269275
expect(githubCommit.type, equals('feat'));
270-
expect(githubCommit.scope, equals('scope'));
276+
expect(githubCommit.scopes, equals(['scope']));
271277
expect(githubCommit.subject,
272278
equals('broadcast destroy event on scope destruction'));
273279
});
@@ -295,7 +301,7 @@ void main() {
295301

296302
test('should understand header parts in GitLab like merge request', () {
297303
expect(gitlabCommit.type, equals('feat'));
298-
expect(gitlabCommit.scope, equals('scope'));
304+
expect(gitlabCommit.scopes, equals(['scope']));
299305
expect(gitlabCommit.subject,
300306
equals('broadcast destroy event on scope destruction'));
301307
});

0 commit comments

Comments
 (0)