Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

Commit 1b6a848

Browse files
authored
feat: support dynamic method name for member-ordering (#1044)
1 parent 371f598 commit 1b6a848

File tree

7 files changed

+106
-107
lines changed

7 files changed

+106
-107
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* feat: make CliRunner a part of public API in order to support transitive executable calls use-case.
88
* feat: add static code diagnostic [`avoid-cascade-after-if-null`](https://dartcodemetrics.dev/docs/rules/common/avoid-cascade-after-if-null).
99
* feat: **Breaking change** handle widget members order separately in [`member-ordering`](https://dartcodemetrics.dev/docs/rules/common/member-ordering).
10+
* feat: support dynamic method names for [`member-ordering`](https://dartcodemetrics.dev/docs/rules/common/member-ordering).
1011

1112
## 4.21.2
1213

lib/src/analyzers/lint_analyzer/rules/rules_list/member_ordering/config_parser.dart

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ class _ConfigParser {
2929

3030
static final _regExp = RegExp(
3131
'(overridden-|protected-)?(private-|public-)?(static-)?(late-)?'
32-
'(var-|final-|const-)?(nullable-)?(named-)?(factory-)?(build-)?'
33-
'(init-state-)?(did-change-dependencies-)?(did-update-widget-)?'
34-
'(dispose-)?',
32+
'(var-|final-|const-)?(nullable-)?(named-)?(factory-)?',
3533
);
3634

3735
static List<_MemberGroup> parseOrder(Map<String, Object> config) {
@@ -64,6 +62,17 @@ class _ConfigParser {
6462
final type = _MemberType.parse(lastGroup);
6563
final result = _regExp.allMatches(group.toLowerCase());
6664

65+
final isNamedMethod = group.endsWith('-method');
66+
if (isNamedMethod) {
67+
final name = group.split('-method').first.replaceAll('-', '');
68+
69+
return _MethodMemberGroup.named(
70+
name: name,
71+
memberType: _MemberType.method,
72+
rawRepresentation: group,
73+
);
74+
}
75+
6776
final hasGroups = result.isNotEmpty && result.first.groupCount > 0;
6877
if (hasGroups && type != null) {
6978
final match = result.first;
@@ -76,11 +85,6 @@ class _ConfigParser {
7685
final isNullable = match.group(6) != null;
7786
final isNamed = match.group(7) != null;
7887
final isFactory = match.group(8) != null;
79-
final isBuild = match.group(9) != null;
80-
final isInitState = match.group(10) != null;
81-
final isDidChangeDependencies = match.group(11) != null;
82-
final isDidUpdateWidget = match.group(12) != null;
83-
final isDispose = match.group(13) != null;
8488

8589
switch (type) {
8690
case _MemberType.field:
@@ -97,13 +101,9 @@ class _ConfigParser {
97101

98102
case _MemberType.method:
99103
return _MethodMemberGroup._(
104+
name: null,
100105
isNullable: isNullable,
101106
isStatic: isStatic,
102-
isBuild: isBuild,
103-
isInitState: isInitState,
104-
isDidChangeDependencies: isDidChangeDependencies,
105-
isDidUpdateWidget: isDidUpdateWidget,
106-
isDispose: isDispose,
107107
annotation: annotation,
108108
memberType: type,
109109
modifier: modifier,

lib/src/analyzers/lint_analyzer/rules/rules_list/member_ordering/models/member_group.dart

Lines changed: 43 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ abstract class _MemberGroup {
77

88
final String rawRepresentation;
99

10-
const _MemberGroup(
11-
this.annotation,
12-
this.memberType,
13-
this.modifier,
14-
this.rawRepresentation,
15-
);
10+
const _MemberGroup({
11+
required this.annotation,
12+
required this.memberType,
13+
required this.modifier,
14+
required this.rawRepresentation,
15+
});
1616

1717
int getSortingCoefficient();
1818
}
@@ -28,16 +28,11 @@ class _FieldMemberGroup extends _MemberGroup {
2828
required this.isNullable,
2929
required this.isStatic,
3030
required this.keyword,
31-
required _Annotation annotation,
32-
required _MemberType memberType,
33-
required _Modifier modifier,
34-
required String rawRepresentation,
35-
}) : super(
36-
annotation,
37-
memberType,
38-
modifier,
39-
rawRepresentation,
40-
);
31+
required super.annotation,
32+
required super.memberType,
33+
required super.modifier,
34+
required super.rawRepresentation,
35+
});
4136

4237
factory _FieldMemberGroup.parse(FieldDeclaration declaration) {
4338
final annotation = declaration.metadata
@@ -89,30 +84,32 @@ class _FieldMemberGroup extends _MemberGroup {
8984
class _MethodMemberGroup extends _MemberGroup {
9085
final bool isStatic;
9186
final bool isNullable;
92-
final bool isBuild;
93-
final bool isInitState;
94-
final bool isDidChangeDependencies;
95-
final bool isDidUpdateWidget;
96-
final bool isDispose;
87+
final String? name;
9788

9889
const _MethodMemberGroup._({
9990
required this.isNullable,
10091
required this.isStatic,
101-
required this.isBuild,
102-
required this.isInitState,
103-
required this.isDidChangeDependencies,
104-
required this.isDidUpdateWidget,
105-
required this.isDispose,
106-
required _Annotation annotation,
92+
required this.name,
93+
required super.annotation,
94+
required super.memberType,
95+
required super.modifier,
96+
required super.rawRepresentation,
97+
});
98+
99+
factory _MethodMemberGroup.named({
100+
required String name,
107101
required _MemberType memberType,
108-
required _Modifier modifier,
109102
required String rawRepresentation,
110-
}) : super(
111-
annotation,
112-
memberType,
113-
modifier,
114-
rawRepresentation,
115-
);
103+
}) =>
104+
_MethodMemberGroup._(
105+
name: name,
106+
isNullable: false,
107+
isStatic: false,
108+
modifier: _Modifier.unset,
109+
annotation: _Annotation.unset,
110+
memberType: memberType,
111+
rawRepresentation: rawRepresentation,
112+
);
116113

117114
factory _MethodMemberGroup.parse(MethodDeclaration declaration) {
118115
final methodName = declaration.name.lexeme;
@@ -124,24 +121,11 @@ class _MethodMemberGroup extends _MemberGroup {
124121
? _Modifier.private
125122
: _Modifier.public;
126123

127-
final hasOverrideAnnotation = annotation == _Annotation.override;
128-
final isBuild = methodName == 'build' && hasOverrideAnnotation;
129-
final isInitState = methodName == 'initState' && hasOverrideAnnotation;
130-
final isDidChangeDependencies =
131-
methodName == 'didChangeDependencies' && hasOverrideAnnotation;
132-
final isDidUpdateWidget =
133-
methodName == 'didUpdateWidget' && hasOverrideAnnotation;
134-
final isDispose = methodName == 'dispose' && hasOverrideAnnotation;
135-
136124
return _MethodMemberGroup._(
125+
name: methodName.toLowerCase(),
137126
annotation: annotation ?? _Annotation.unset,
138127
isStatic: declaration.isStatic,
139128
isNullable: declaration.returnType?.question != null,
140-
isBuild: isBuild,
141-
isInitState: isInitState,
142-
isDidChangeDependencies: isDidChangeDependencies,
143-
isDidUpdateWidget: isDidUpdateWidget,
144-
isDispose: isDispose,
145129
memberType: _MemberType.method,
146130
modifier: modifier,
147131
rawRepresentation: '',
@@ -156,11 +140,7 @@ class _MethodMemberGroup extends _MemberGroup {
156140
coefficient += isNullable ? 1 : 0;
157141
coefficient += annotation != _Annotation.unset ? 1 : 0;
158142
coefficient += modifier != _Modifier.unset ? 1 : 0;
159-
coefficient += isBuild ? 10 : 0;
160-
coefficient += isInitState ? 10 : 0;
161-
coefficient += isDidChangeDependencies ? 10 : 0;
162-
coefficient += isDidUpdateWidget ? 10 : 0;
163-
coefficient += isDispose ? 10 : 0;
143+
coefficient += name != null ? 10 : 0;
164144

165145
return coefficient;
166146
}
@@ -176,16 +156,11 @@ class _ConstructorMemberGroup extends _MemberGroup {
176156
const _ConstructorMemberGroup._({
177157
required this.isNamed,
178158
required this.isFactory,
179-
required _Annotation annotation,
180-
required _MemberType memberType,
181-
required _Modifier modifier,
182-
required String rawRepresentation,
183-
}) : super(
184-
annotation,
185-
memberType,
186-
modifier,
187-
rawRepresentation,
188-
);
159+
required super.annotation,
160+
required super.memberType,
161+
required super.modifier,
162+
required super.rawRepresentation,
163+
});
189164

190165
factory _ConstructorMemberGroup.parse(ConstructorDeclaration declaration) {
191166
final annotation = declaration.metadata
@@ -235,11 +210,11 @@ class _GetSetMemberGroup extends _MemberGroup {
235210
const _GetSetMemberGroup._({
236211
required this.isNullable,
237212
required this.isStatic,
238-
required _Annotation annotation,
239-
required _MemberType memberType,
240-
required _Modifier modifier,
241-
required String rawRepresentation,
242-
}) : super(annotation, memberType, modifier, rawRepresentation);
213+
required super.annotation,
214+
required super.memberType,
215+
required super.modifier,
216+
required super.rawRepresentation,
217+
});
243218

244219
factory _GetSetMemberGroup.parse(MethodDeclaration declaration) {
245220
final annotation = declaration.metadata

lib/src/analyzers/lint_analyzer/rules/rules_list/member_ordering/visitor.dart

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ class _Visitor extends RecursiveAstVisitor<List<_MemberInfo>> {
124124
_isConstructorGroup(group, parsedGroup) ||
125125
_isFieldGroup(group, parsedGroup) ||
126126
_isGetSetGroup(group, parsedGroup) ||
127-
_isFlutterMethodGroup(group, parsedGroup) ||
128127
_isMethodGroup(group, parsedGroup),
129128
)
130129
.sorted(
@@ -211,28 +210,12 @@ class _Visitor extends RecursiveAstVisitor<List<_MemberInfo>> {
211210
parsedGroup is _MethodMemberGroup &&
212211
(!group.isStatic || group.isStatic == parsedGroup.isStatic) &&
213212
(!group.isNullable || group.isNullable == parsedGroup.isNullable) &&
214-
!group.isBuild &&
215-
!group.isDidChangeDependencies &&
216-
!group.isDidUpdateWidget &&
217-
!group.isInitState &&
218-
!group.isDispose &&
213+
(group.name == null || group.name == parsedGroup.name) &&
219214
(group.modifier == _Modifier.unset ||
220215
group.modifier == parsedGroup.modifier) &&
221216
(group.annotation == _Annotation.unset ||
222217
group.annotation == parsedGroup.annotation);
223218

224-
bool _isFlutterMethodGroup(_MemberGroup group, _MemberGroup parsedGroup) =>
225-
group is _MethodMemberGroup &&
226-
parsedGroup is _MethodMemberGroup &&
227-
((group.isBuild && group.isBuild == parsedGroup.isBuild) ||
228-
(group.isInitState && group.isInitState == parsedGroup.isInitState) ||
229-
(group.isDidChangeDependencies &&
230-
group.isDidChangeDependencies ==
231-
parsedGroup.isDidChangeDependencies) ||
232-
(group.isDidUpdateWidget &&
233-
group.isDidUpdateWidget == parsedGroup.isDidUpdateWidget) ||
234-
(group.isDispose && group.isDispose == parsedGroup.isDispose));
235-
236219
bool _isGetSetGroup(_MemberGroup group, _MemberGroup parsedGroup) =>
237220
group is _GetSetMemberGroup &&
238221
parsedGroup is _GetSetMemberGroup &&

test/src/analyzers/lint_analyzer/rules/rules_list/member_ordering/examples/flutter_widget_example.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ class Widget {}
3030
class StatelessWidget extends Widget {
3131
Widget build(BuildContext context);
3232

33-
void initState();
33+
void initState(); // LINT
3434

35-
void didChangeDependencies();
35+
void didChangeDependencies(); // LINT
3636

37-
void didUpdateWidget();
37+
void didUpdateWidget(); // LINT
3838

39-
void dispose();
39+
void dispose(); // LINT
4040

4141
void someOtherMethod();
4242
}

test/src/analyzers/lint_analyzer/rules/rules_list/member_ordering/member_ordering_rule_test.dart

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,16 @@ void main() {
7474

7575
RuleTestHelper.verifyIssues(
7676
issues: issues,
77-
startLines: [12],
78-
startColumns: [3],
77+
startLines: [12, 33],
78+
startColumns: [3, 3],
7979
locationTexts: [
8080
'@override\n'
8181
' void initState() {}',
82+
'void initState();',
8283
],
8384
messages: [
8485
'init-state-method should be before build-method.',
86+
'init-state-method should be before build-method.',
8587
],
8688
);
8789
});
@@ -251,8 +253,8 @@ void main() {
251253

252254
RuleTestHelper.verifyIssues(
253255
issues: issues,
254-
startLines: [7, 12, 15, 18, 21, 24],
255-
startColumns: [3, 3, 3, 3, 3, 3],
256+
startLines: [7, 12, 15, 18, 21, 24, 33, 35, 37, 39],
257+
startColumns: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
256258
locationTexts: [
257259
'@override\n'
258260
' Widget build(BuildContext context) {\n'
@@ -268,6 +270,10 @@ void main() {
268270
' void dispose() {}',
269271
'@override\n'
270272
' void someOtherMethod() {}',
273+
'void initState();',
274+
'void didChangeDependencies();',
275+
'void didUpdateWidget();',
276+
'void dispose();',
271277
],
272278
messages: [
273279
'build-method should be before public-methods.',
@@ -276,6 +282,10 @@ void main() {
276282
'did-update-widget-method should be before did-change-dependencies-method.',
277283
'dispose-method should be before did-update-widget-method.',
278284
'overridden-methods should be before dispose-method.',
285+
'init-state-method should be before build-method.',
286+
'did-change-dependencies-method should be before init-state-method.',
287+
'did-update-widget-method should be before did-change-dependencies-method.',
288+
'dispose-method should be before did-update-widget-method.',
279289
],
280290
);
281291
});

website/docs/rules/common/member-ordering.mdx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ The value for the `order` or `widgets-order` entries should match the following
1212

1313
where values in the `<>` are optional, values in the `()` are interchangeable and the last part of the pattern which represents a class member type is **REQUIRED**.
1414

15+
You can also apply order to a separate method by listing its name like:
16+
17+
- build-method
18+
- dispose-method
19+
- init-state-method
20+
- my-castom-cool-thing-method
21+
1522
:::info
1623

1724
Not all of the pattern parts are applicable for every case, for example, `late-constructors` are not expected, since they are not supported by the language itself.
@@ -106,13 +113,36 @@ dart_code_metrics:
106113
107114
**OR** Flutter specific:
108115
116+
```yaml
117+
dart_code_metrics:
118+
...
119+
rules:
120+
...
121+
- member-ordering:
122+
widgets-order:
123+
- build-method
124+
- init-state-method
125+
- did-change-dependencies-method
126+
- did-update-widget-method
127+
- dispose-method
128+
```
129+
130+
**OR** both custom and Flutter specific:
131+
109132
```yaml
110133
dart_code_metrics:
111134
...
112135
rules:
113136
...
114137
- member-ordering:
115138
order:
139+
- public-fields
140+
- private-fields
141+
- constructors
142+
- close-method
143+
- dispose-method
144+
widgets-order:
145+
- constructor
116146
- build-method
117147
- init-state-method
118148
- did-change-dependencies-method

0 commit comments

Comments
 (0)