Skip to content

Commit 8b5293e

Browse files
feat: add named_parameters_ordering
1 parent 76546be commit 8b5293e

File tree

9 files changed

+564
-1
lines changed

9 files changed

+564
-1
lines changed

lib/solid_lints.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import 'package:solid_lints/src/lints/cyclomatic_complexity/cyclomatic_complexit
1717
import 'package:solid_lints/src/lints/double_literal_format/double_literal_format_rule.dart';
1818
import 'package:solid_lints/src/lints/function_lines_of_code/function_lines_of_code_rule.dart';
1919
import 'package:solid_lints/src/lints/member_ordering/member_ordering_rule.dart';
20+
import 'package:solid_lints/src/lints/named_parameters_ordering/named_parameters_ordering_rule.dart';
2021
import 'package:solid_lints/src/lints/newline_before_return/newline_before_return_rule.dart';
2122
import 'package:solid_lints/src/lints/no_empty_block/no_empty_block_rule.dart';
2223
import 'package:solid_lints/src/lints/no_equal_then_else/no_equal_then_else_rule.dart';
@@ -65,6 +66,7 @@ class _SolidLints extends PluginBase {
6566
AvoidDebugPrintInReleaseRule.createRule(configs),
6667
PreferEarlyReturnRule.createRule(configs),
6768
AvoidFinalWithGetterRule.createRule(configs),
69+
NamedParametersOrderingRule.createRule(configs),
6870
];
6971

7072
// Return only enabled rules
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2020-2021 Dart Code Checker team
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
// SOFTWARE.
23+
24+
import 'package:collection/collection.dart';
25+
import 'package:solid_lints/src/lints/named_parameters_ordering/models/parameter_type.dart';
26+
27+
/// Helper class to parse member_ordering rule config
28+
class NamedParametersConfigParser {
29+
static const _defaultOrderList = [
30+
'super',
31+
'required_super',
32+
'required',
33+
'nullable',
34+
'default',
35+
];
36+
37+
/// Parse rule config for regular class order rules
38+
static List<ParameterType> parseOrder(Object? orderConfig) {
39+
final order = orderConfig is Iterable
40+
? List<String>.from(orderConfig)
41+
: _defaultOrderList;
42+
43+
return order
44+
.map(
45+
(type) =>
46+
ParameterType.values.firstWhereOrNull((o) => o.type == type),
47+
)
48+
.nonNulls
49+
.toList();
50+
}
51+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// MIT License
2+
//
3+
// Copyright (c) 2020-2021 Dart Code Checker team
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
// SOFTWARE.
23+
24+
import 'package:solid_lints/src/lints/named_parameters_ordering/config_parser.dart';
25+
import 'package:solid_lints/src/lints/named_parameters_ordering/models/parameter_type.dart';
26+
27+
/// A data model class that represents the parameter ordering input
28+
/// parameters.
29+
class NamedParametersOrderingParameters {
30+
/// Config keys
31+
static const _orderConfig = 'order';
32+
33+
/// Config used for order of named parameters
34+
final List<ParameterType> order;
35+
36+
/// Constructor for [NamedParametersOrderingParameters] model
37+
const NamedParametersOrderingParameters({required this.order});
38+
39+
/// Method for creating from json data
40+
factory NamedParametersOrderingParameters.fromJson(
41+
Map<String, Object?> json,
42+
) =>
43+
NamedParametersOrderingParameters(
44+
order: NamedParametersConfigParser.parseOrder(
45+
json[_orderConfig],
46+
),
47+
);
48+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// Represents a function parameter type
2+
enum ParameterType {
3+
/// Super parameter type (super.parameterName)
4+
super$('super'),
5+
6+
/// Required super parameter type (required super.parameterName)
7+
requiredSuper('required_super'),
8+
9+
/// Required parameter type (required String parameterName)
10+
required('required'),
11+
12+
/// Nullable parameter type (String? parameterName)
13+
nullable('nullable'),
14+
15+
/// Default parameter type (String parameterName = 'defaultValue')
16+
default$('default');
17+
18+
/// String representation of the parameter type
19+
final String type;
20+
21+
/// Display name of the parameter type
22+
String get displayName => type.replaceAll('_', ' ');
23+
24+
const ParameterType(this.type);
25+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import 'package:analyzer/error/listener.dart';
2+
import 'package:custom_lint_builder/custom_lint_builder.dart';
3+
import 'package:solid_lints/src/lints/named_parameters_ordering/models/named_parameters_ordering_parameters.dart';
4+
import 'package:solid_lints/src/lints/named_parameters_ordering/visitors/named_parameters_ordering_visitor.dart';
5+
import 'package:solid_lints/src/models/rule_config.dart';
6+
import 'package:solid_lints/src/models/solid_lint_rule.dart';
7+
8+
/// A lint which allows to enforce a particular named parameter ordering
9+
/// conventions.
10+
///
11+
/// ### Configuration format
12+
/// ```yaml
13+
/// - named_parameters_ordering:
14+
/// order:
15+
/// - (parameterType)
16+
/// ```
17+
/// Where parameterType can be one of:
18+
///
19+
/// - `super`
20+
/// - `required_super`
21+
/// - `required`
22+
/// - `nullable`
23+
/// - `default`
24+
///
25+
/// ### Example:
26+
///
27+
/// Assuming config:
28+
///
29+
/// ```yaml
30+
/// custom_lint:
31+
/// rules:
32+
/// - named_parameters_ordering:
33+
/// order:
34+
/// - required
35+
/// - required_super
36+
/// - default
37+
/// - nullable
38+
/// - super
39+
/// ```
40+
///
41+
/// #### BAD:
42+
///
43+
/// ```dart
44+
/// class User {
45+
/// final String accountType;
46+
/// final String? userId;
47+
///
48+
/// User({
49+
/// required this.accountType,
50+
/// this.userId,
51+
/// });
52+
/// }
53+
///
54+
/// class UserProfile extends User {
55+
/// final String? age;
56+
/// final String? country;
57+
/// final String email;
58+
/// final bool isActive;
59+
/// final String name;
60+
///
61+
/// UserProfile({
62+
/// this.age,
63+
/// required super.accountType, // LINT, required super named parameters should be before nullable named parameters
64+
/// required this.name, // LINT, required named parameters should be before super named parameters
65+
/// super.userId,
66+
/// this.country, // LINT, nullable named parameters should be before super named parameters
67+
/// this.isActive = true, // LINT, default named parameters should be before nullable named parameters
68+
/// required this.email, // LINT, required named parameters should be before default named parameters
69+
/// });
70+
///
71+
/// void doSomething({
72+
/// required String name,
73+
/// int? age,
74+
/// bool isActive = true, // LINT, default named parameters should be before nullable named parameters
75+
/// required String email, // LINT, required named parameters should be before default named parameters
76+
/// }) {
77+
/// return;
78+
/// }
79+
/// }
80+
/// ```
81+
///
82+
/// #### GOOD:
83+
///
84+
/// ```dart
85+
/// class User {
86+
/// final String accountType;
87+
/// final String? userId;
88+
///
89+
/// User({
90+
/// required this.accountType,
91+
/// this.userId,
92+
/// });
93+
/// }
94+
///
95+
/// class UserProfile extends User {
96+
/// final String? age;
97+
/// final String? country;
98+
/// final String email;
99+
/// final bool isActive;
100+
/// final String name;
101+
///
102+
/// UserProfile({
103+
/// required this.name,
104+
/// required this.email,
105+
/// required super.accountType,
106+
/// this.isActive = true,
107+
/// this.age,
108+
/// this.country,
109+
/// super.userId,
110+
/// });
111+
///
112+
/// void doSomething({
113+
/// required String name,
114+
/// required String email,
115+
/// bool isActive = true,
116+
/// int? age,
117+
/// }) {
118+
/// return;
119+
/// }
120+
/// }
121+
/// ```
122+
class NamedParametersOrderingRule
123+
extends SolidLintRule<NamedParametersOrderingParameters> {
124+
/// This lint rule represents
125+
/// the error whether we use bad formatted double literals.
126+
static const lintName = 'named_parameters_ordering';
127+
128+
static const _warningMessage = 'should be before';
129+
130+
NamedParametersOrderingRule._(super.config);
131+
132+
/// Creates a new instance of [NamedParametersOrderingRule]
133+
/// based on the lint configuration.
134+
factory NamedParametersOrderingRule.createRule(CustomLintConfigs configs) {
135+
final config = RuleConfig<NamedParametersOrderingParameters>(
136+
configs: configs,
137+
name: lintName,
138+
paramsParser: NamedParametersOrderingParameters.fromJson,
139+
problemMessage: (_) => "Order of named parameter is wrong",
140+
);
141+
142+
return NamedParametersOrderingRule._(config);
143+
}
144+
145+
@override
146+
void run(
147+
CustomLintResolver resolver,
148+
ErrorReporter reporter,
149+
CustomLintContext context,
150+
) {
151+
context.registry.addFormalParameterList((node) {
152+
final visitor = NamedParametersOrderingVisitor(config.parameters.order);
153+
154+
final parametersInfo = visitor.visitFormalParameterList(node);
155+
156+
final wrongOrderParameters = parametersInfo.where(
157+
(info) => info.parameterOrderingInfo.isWrong,
158+
);
159+
160+
for (final parameterInfo in wrongOrderParameters) {
161+
reporter.atNode(
162+
parameterInfo.formalParameter,
163+
_createWrongOrderLintCode(parameterInfo.parameterOrderingInfo),
164+
);
165+
}
166+
});
167+
}
168+
169+
LintCode _createWrongOrderLintCode(ParameterOrderingInfo info) {
170+
final parameterOrdering = info.parameterType;
171+
final previousParameterOrdering = info.previousParameterType;
172+
173+
return LintCode(
174+
name: lintName,
175+
problemMessage: "${parameterOrdering.displayName} named parameters"
176+
" $_warningMessage "
177+
"${previousParameterOrdering!.displayName} named parameters.",
178+
);
179+
}
180+
}

0 commit comments

Comments
 (0)