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

feat: support dynamic method name for member-ordering #1044

Merged
merged 1 commit into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* feat: make CliRunner a part of public API in order to support transitive executable calls use-case.
* feat: add static code diagnostic [`avoid-cascade-after-if-null`](https://dartcodemetrics.dev/docs/rules/common/avoid-cascade-after-if-null).
* feat: **Breaking change** handle widget members order separately in [`member-ordering`](https://dartcodemetrics.dev/docs/rules/common/member-ordering).
* feat: support dynamic method names for [`member-ordering`](https://dartcodemetrics.dev/docs/rules/common/member-ordering).

## 4.21.2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ class _ConfigParser {

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

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

final isNamedMethod = group.endsWith('-method');
if (isNamedMethod) {
final name = group.split('-method').first.replaceAll('-', '');

return _MethodMemberGroup.named(
name: name,
memberType: _MemberType.method,
rawRepresentation: group,
);
}

final hasGroups = result.isNotEmpty && result.first.groupCount > 0;
if (hasGroups && type != null) {
final match = result.first;
Expand All @@ -76,11 +85,6 @@ class _ConfigParser {
final isNullable = match.group(6) != null;
final isNamed = match.group(7) != null;
final isFactory = match.group(8) != null;
final isBuild = match.group(9) != null;
final isInitState = match.group(10) != null;
final isDidChangeDependencies = match.group(11) != null;
final isDidUpdateWidget = match.group(12) != null;
final isDispose = match.group(13) != null;

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

case _MemberType.method:
return _MethodMemberGroup._(
name: null,
isNullable: isNullable,
isStatic: isStatic,
isBuild: isBuild,
isInitState: isInitState,
isDidChangeDependencies: isDidChangeDependencies,
isDidUpdateWidget: isDidUpdateWidget,
isDispose: isDispose,
annotation: annotation,
memberType: type,
modifier: modifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ abstract class _MemberGroup {

final String rawRepresentation;

const _MemberGroup(
this.annotation,
this.memberType,
this.modifier,
this.rawRepresentation,
);
const _MemberGroup({
required this.annotation,
required this.memberType,
required this.modifier,
required this.rawRepresentation,
});

int getSortingCoefficient();
}
Expand All @@ -28,16 +28,11 @@ class _FieldMemberGroup extends _MemberGroup {
required this.isNullable,
required this.isStatic,
required this.keyword,
required _Annotation annotation,
required _MemberType memberType,
required _Modifier modifier,
required String rawRepresentation,
}) : super(
annotation,
memberType,
modifier,
rawRepresentation,
);
required super.annotation,
required super.memberType,
required super.modifier,
required super.rawRepresentation,
});

factory _FieldMemberGroup.parse(FieldDeclaration declaration) {
final annotation = declaration.metadata
Expand Down Expand Up @@ -89,30 +84,32 @@ class _FieldMemberGroup extends _MemberGroup {
class _MethodMemberGroup extends _MemberGroup {
final bool isStatic;
final bool isNullable;
final bool isBuild;
final bool isInitState;
final bool isDidChangeDependencies;
final bool isDidUpdateWidget;
final bool isDispose;
final String? name;

const _MethodMemberGroup._({
required this.isNullable,
required this.isStatic,
required this.isBuild,
required this.isInitState,
required this.isDidChangeDependencies,
required this.isDidUpdateWidget,
required this.isDispose,
required _Annotation annotation,
required this.name,
required super.annotation,
required super.memberType,
required super.modifier,
required super.rawRepresentation,
});

factory _MethodMemberGroup.named({
required String name,
required _MemberType memberType,
required _Modifier modifier,
required String rawRepresentation,
}) : super(
annotation,
memberType,
modifier,
rawRepresentation,
);
}) =>
_MethodMemberGroup._(
name: name,
isNullable: false,
isStatic: false,
modifier: _Modifier.unset,
annotation: _Annotation.unset,
memberType: memberType,
rawRepresentation: rawRepresentation,
);

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

final hasOverrideAnnotation = annotation == _Annotation.override;
final isBuild = methodName == 'build' && hasOverrideAnnotation;
final isInitState = methodName == 'initState' && hasOverrideAnnotation;
final isDidChangeDependencies =
methodName == 'didChangeDependencies' && hasOverrideAnnotation;
final isDidUpdateWidget =
methodName == 'didUpdateWidget' && hasOverrideAnnotation;
final isDispose = methodName == 'dispose' && hasOverrideAnnotation;

return _MethodMemberGroup._(
name: methodName.toLowerCase(),
annotation: annotation ?? _Annotation.unset,
isStatic: declaration.isStatic,
isNullable: declaration.returnType?.question != null,
isBuild: isBuild,
isInitState: isInitState,
isDidChangeDependencies: isDidChangeDependencies,
isDidUpdateWidget: isDidUpdateWidget,
isDispose: isDispose,
memberType: _MemberType.method,
modifier: modifier,
rawRepresentation: '',
Expand All @@ -156,11 +140,7 @@ class _MethodMemberGroup extends _MemberGroup {
coefficient += isNullable ? 1 : 0;
coefficient += annotation != _Annotation.unset ? 1 : 0;
coefficient += modifier != _Modifier.unset ? 1 : 0;
coefficient += isBuild ? 10 : 0;
coefficient += isInitState ? 10 : 0;
coefficient += isDidChangeDependencies ? 10 : 0;
coefficient += isDidUpdateWidget ? 10 : 0;
coefficient += isDispose ? 10 : 0;
coefficient += name != null ? 10 : 0;

return coefficient;
}
Expand All @@ -176,16 +156,11 @@ class _ConstructorMemberGroup extends _MemberGroup {
const _ConstructorMemberGroup._({
required this.isNamed,
required this.isFactory,
required _Annotation annotation,
required _MemberType memberType,
required _Modifier modifier,
required String rawRepresentation,
}) : super(
annotation,
memberType,
modifier,
rawRepresentation,
);
required super.annotation,
required super.memberType,
required super.modifier,
required super.rawRepresentation,
});

factory _ConstructorMemberGroup.parse(ConstructorDeclaration declaration) {
final annotation = declaration.metadata
Expand Down Expand Up @@ -235,11 +210,11 @@ class _GetSetMemberGroup extends _MemberGroup {
const _GetSetMemberGroup._({
required this.isNullable,
required this.isStatic,
required _Annotation annotation,
required _MemberType memberType,
required _Modifier modifier,
required String rawRepresentation,
}) : super(annotation, memberType, modifier, rawRepresentation);
required super.annotation,
required super.memberType,
required super.modifier,
required super.rawRepresentation,
});

factory _GetSetMemberGroup.parse(MethodDeclaration declaration) {
final annotation = declaration.metadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ class _Visitor extends RecursiveAstVisitor<List<_MemberInfo>> {
_isConstructorGroup(group, parsedGroup) ||
_isFieldGroup(group, parsedGroup) ||
_isGetSetGroup(group, parsedGroup) ||
_isFlutterMethodGroup(group, parsedGroup) ||
_isMethodGroup(group, parsedGroup),
)
.sorted(
Expand Down Expand Up @@ -211,28 +210,12 @@ class _Visitor extends RecursiveAstVisitor<List<_MemberInfo>> {
parsedGroup is _MethodMemberGroup &&
(!group.isStatic || group.isStatic == parsedGroup.isStatic) &&
(!group.isNullable || group.isNullable == parsedGroup.isNullable) &&
!group.isBuild &&
!group.isDidChangeDependencies &&
!group.isDidUpdateWidget &&
!group.isInitState &&
!group.isDispose &&
(group.name == null || group.name == parsedGroup.name) &&
(group.modifier == _Modifier.unset ||
group.modifier == parsedGroup.modifier) &&
(group.annotation == _Annotation.unset ||
group.annotation == parsedGroup.annotation);

bool _isFlutterMethodGroup(_MemberGroup group, _MemberGroup parsedGroup) =>
group is _MethodMemberGroup &&
parsedGroup is _MethodMemberGroup &&
((group.isBuild && group.isBuild == parsedGroup.isBuild) ||
(group.isInitState && group.isInitState == parsedGroup.isInitState) ||
(group.isDidChangeDependencies &&
group.isDidChangeDependencies ==
parsedGroup.isDidChangeDependencies) ||
(group.isDidUpdateWidget &&
group.isDidUpdateWidget == parsedGroup.isDidUpdateWidget) ||
(group.isDispose && group.isDispose == parsedGroup.isDispose));

bool _isGetSetGroup(_MemberGroup group, _MemberGroup parsedGroup) =>
group is _GetSetMemberGroup &&
parsedGroup is _GetSetMemberGroup &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ class Widget {}
class StatelessWidget extends Widget {
Widget build(BuildContext context);

void initState();
void initState(); // LINT

void didChangeDependencies();
void didChangeDependencies(); // LINT

void didUpdateWidget();
void didUpdateWidget(); // LINT

void dispose();
void dispose(); // LINT

void someOtherMethod();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,16 @@ void main() {

RuleTestHelper.verifyIssues(
issues: issues,
startLines: [12],
startColumns: [3],
startLines: [12, 33],
startColumns: [3, 3],
locationTexts: [
'@override\n'
' void initState() {}',
'void initState();',
],
messages: [
'init-state-method should be before build-method.',
'init-state-method should be before build-method.',
],
);
});
Expand Down Expand Up @@ -251,8 +253,8 @@ void main() {

RuleTestHelper.verifyIssues(
issues: issues,
startLines: [7, 12, 15, 18, 21, 24],
startColumns: [3, 3, 3, 3, 3, 3],
startLines: [7, 12, 15, 18, 21, 24, 33, 35, 37, 39],
startColumns: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
locationTexts: [
'@override\n'
' Widget build(BuildContext context) {\n'
Expand All @@ -268,6 +270,10 @@ void main() {
' void dispose() {}',
'@override\n'
' void someOtherMethod() {}',
'void initState();',
'void didChangeDependencies();',
'void didUpdateWidget();',
'void dispose();',
],
messages: [
'build-method should be before public-methods.',
Expand All @@ -276,6 +282,10 @@ void main() {
'did-update-widget-method should be before did-change-dependencies-method.',
'dispose-method should be before did-update-widget-method.',
'overridden-methods should be before dispose-method.',
'init-state-method should be before build-method.',
'did-change-dependencies-method should be before init-state-method.',
'did-update-widget-method should be before did-change-dependencies-method.',
'dispose-method should be before did-update-widget-method.',
],
);
});
Expand Down
30 changes: 30 additions & 0 deletions website/docs/rules/common/member-ordering.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ The value for the `order` or `widgets-order` entries should match the following

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**.

You can also apply order to a separate method by listing its name like:

- build-method
- dispose-method
- init-state-method
- my-castom-cool-thing-method

:::info

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.
Expand Down Expand Up @@ -106,13 +113,36 @@ dart_code_metrics:

**OR** Flutter specific:

```yaml
dart_code_metrics:
...
rules:
...
- member-ordering:
widgets-order:
- build-method
- init-state-method
- did-change-dependencies-method
- did-update-widget-method
- dispose-method
```

**OR** both custom and Flutter specific:

```yaml
dart_code_metrics:
...
rules:
...
- member-ordering:
order:
- public-fields
- private-fields
- constructors
- close-method
- dispose-method
widgets-order:
- constructor
- build-method
- init-state-method
- did-change-dependencies-method
Expand Down