Skip to content

Commit e567b0a

Browse files
srawlinsCommit Queue
authored andcommitted
analyzer: use typed data in RuleConfig to store enablement
Instead of using a Map of args, with a String key, `'enabled`', just use a bool field. Also document the fields on RuleConfig. Also delete a test that verifies support for bool-like String YAML keys, like `'true'`. We can just support bool keys. Change-Id: I5bf3ab32c7e1c9ee683b977e44be88feb06ccb88 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391683 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Phil Quitslund <[email protected]>
1 parent 9774348 commit e567b0a

File tree

2 files changed

+63
-79
lines changed

2 files changed

+63
-79
lines changed

pkg/analyzer/lib/src/lint/config.dart

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import 'package:analyzer/src/task/options.dart';
66
import 'package:analyzer/src/util/yaml.dart';
77
import 'package:yaml/yaml.dart';
88

9-
/// Parses [optionsMap] into a [LintConfig], returning the config, or `null` if
10-
/// [optionsMap] does not have `linter` map.
9+
/// Parses [optionsMap] into a list of [RuleConfig]s, returning them, or `null`
10+
/// if [optionsMap] does not have `linter` map.
1111
List<RuleConfig>? parseLintRuleConfigs(YamlMap optionsMap) {
1212
var options = optionsMap.valueAt('linter');
1313
// Quick check of basic contract.
@@ -24,29 +24,16 @@ List<RuleConfig>? parseLintRuleConfigs(YamlMap optionsMap) {
2424
return null;
2525
}
2626

27-
/// Returns [scalar] as a [bool], if it can be parsed as one.
28-
bool? _asBool(YamlNode scalar) {
29-
var value = scalar is YamlScalar ? scalar.valueOrThrow : scalar;
30-
return switch (value) {
31-
bool() => value,
32-
'true' => true,
33-
'false' => false,
34-
_ => null,
35-
};
36-
}
37-
38-
/// Returns [scalar] as a [String], if it can be parsed as one.
39-
String? _asString(Object scalar) {
40-
var value = scalar is YamlScalar ? scalar.value : scalar;
41-
return value is String ? value : null;
42-
}
43-
44-
Map<String, bool> _parseArgs(YamlNode args) {
45-
var enabled = _asBool(args);
46-
if (enabled != null) {
47-
return {'enabled': enabled};
27+
RuleConfig? _parseRuleConfig(dynamic configKey, YamlNode configNode,
28+
{String? group}) {
29+
// For example: `{unnecessary_getters: false}`.
30+
if (configKey case YamlScalar(value: String ruleName)) {
31+
if (configNode case YamlScalar(value: bool isEnabled)) {
32+
return RuleConfig._(name: ruleName, isEnabled: isEnabled, group: group);
33+
}
4834
}
49-
return {};
35+
36+
return null;
5037
}
5138

5239
/// Returns the [RuleConfig]s that are parsed from [value], which can be either
@@ -59,56 +46,65 @@ List<RuleConfig> _ruleConfigs(YamlNode value) {
5946
// - camel_case_types
6047
// ```
6148
if (value is YamlList) {
62-
return [
63-
for (var rule in value.nodes)
64-
RuleConfig(name: _asString(rule), args: {'enabled': true}),
65-
];
66-
}
67-
68-
// style_guide: {unnecessary_getters: false, camel_case_types: true}
69-
if (value is YamlMap) {
7049
var ruleConfigs = <RuleConfig>[];
71-
value.nodes.cast<Object, YamlNode>().forEach((key, value) {
72-
// For example: `{unnecessary_getters: false}`.
73-
var valueAsBool = _asBool(value);
74-
if (valueAsBool != null) {
75-
ruleConfigs.add(RuleConfig(
76-
name: _asString(key),
77-
args: {'enabled': valueAsBool},
78-
));
79-
}
80-
81-
// style_guide: {unnecessary_getters: false, camel_case_types: true}
82-
if (value is YamlMap) {
83-
value.nodes.cast<Object, YamlNode>().forEach((rule, args) {
84-
// TODO(brianwilkerson): verify format.
85-
// For example: `unnecessary_getters: false`.
86-
ruleConfigs.add(RuleConfig(
87-
name: _asString(rule),
88-
args: _parseArgs(args),
89-
group: _asString(key),
90-
));
91-
});
50+
for (var ruleNode in value.nodes) {
51+
if (ruleNode case YamlScalar(value: String ruleName)) {
52+
ruleConfigs.add(RuleConfig._(name: ruleName, isEnabled: true));
9253
}
93-
});
54+
}
9455
return ruleConfigs;
9556
}
9657

97-
return const [];
58+
if (value is! YamlMap) {
59+
return const [];
60+
}
61+
62+
var ruleConfigs = <RuleConfig>[];
63+
value.nodes.forEach((configKey, configValue) {
64+
if (configKey case YamlScalar(value: String configName)) {
65+
var ruleConfig = _parseRuleConfig(configKey, configValue);
66+
if (ruleConfig != null) {
67+
ruleConfigs.add(ruleConfig);
68+
return;
69+
}
70+
71+
if (configValue is! YamlMap) {
72+
return;
73+
}
74+
// For example:
75+
//
76+
// ```yaml
77+
// style_guide: {unnecessary_getters: false, camel_case_types: true}
78+
// ```
79+
configValue.nodes.forEach((ruleName, ruleValue) {
80+
var ruleConfig =
81+
_parseRuleConfig(ruleName, ruleValue, group: configName);
82+
if (ruleConfig != null) {
83+
ruleConfigs.add(ruleConfig);
84+
return;
85+
}
86+
});
87+
}
88+
});
89+
return ruleConfigs;
9890
}
9991

10092
/// The configuration of a single lint rule within an analysis options file.
10193
class RuleConfig {
102-
final Map<String, bool> args;
94+
/// Whether this rule is enabled or disabled in this configuration.
95+
final bool isEnabled;
96+
97+
/// The name of the group under which this configuration is found.
10398
final String? group;
104-
final String? name;
10599

106-
RuleConfig({required this.name, required this.args, this.group});
100+
/// The name of the rule.
101+
final String name;
102+
103+
RuleConfig._({required this.name, required this.isEnabled, this.group});
107104

108105
/// Returns whether [ruleName] is disabled in this configuration.
109-
bool disables(String ruleName) =>
110-
ruleName == name && args['enabled'] == false;
106+
bool disables(String ruleName) => ruleName == name && !isEnabled;
111107

112108
/// Returns whether [ruleName] is enabled in this configuration.
113-
bool enables(String ruleName) => ruleName == name && args['enabled'] == true;
109+
bool enables(String ruleName) => ruleName == name && isEnabled;
114110
}

pkg/analyzer/test/src/lint/config_test.dart

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ linter:
6464
var ruleConfig = ruleConfigs[0];
6565
expect(ruleConfig.group, 'style_guide');
6666
expect(ruleConfig.name, 'unnecessary_getters');
67-
expect(ruleConfig.args, {'enabled': false});
67+
expect(ruleConfig.isEnabled, isFalse);
6868
expect(ruleConfig.disables('unnecessary_getters'), isTrue);
6969
});
7070
});
@@ -107,7 +107,7 @@ linter:
107107
var ruleConfigs = processAnalysisOptionsFile(src)!;
108108
expect(ruleConfigs, hasLength(1));
109109
// Verify that defaults are enabled.
110-
expect(ruleConfigs[0].args['enabled'], isTrue);
110+
expect(ruleConfigs[0].isEnabled, isTrue);
111111
});
112112

113113
test('rule map (bools)', () {
@@ -122,13 +122,13 @@ linter:
122122
unnecessary_getters: false #disable
123123
''';
124124
var ruleConfigs = processAnalysisOptionsFile(src)!;
125-
ruleConfigs.sort((RuleConfig rc1, RuleConfig rc2) =>
126-
rc1.name!.compareTo(rc2.name!));
125+
ruleConfigs.sort(
126+
(RuleConfig rc1, RuleConfig rc2) => rc1.name.compareTo(rc2.name));
127127
expect(ruleConfigs, hasLength(2));
128128
expect(ruleConfigs[0].name, 'camel_case_types');
129-
expect(ruleConfigs[0].args['enabled'], isTrue);
129+
expect(ruleConfigs[0].isEnabled, isTrue);
130130
expect(ruleConfigs[1].name, 'unnecessary_getters');
131-
expect(ruleConfigs[1].args['enabled'], isFalse);
131+
expect(ruleConfigs[1].isEnabled, isFalse);
132132
});
133133
});
134134
});
@@ -172,18 +172,6 @@ linter:
172172
expect(ruleConfigs, hasLength(1));
173173
});
174174

175-
test('rule map (string)', () {
176-
var options = <Object, Object?>{};
177-
var lintOptions = {
178-
'rules': {'camel_case_types': 'true'}
179-
};
180-
options['linter'] = lintOptions;
181-
182-
var ruleConfigs = parseMap(options);
183-
expect(ruleConfigs, isNotNull);
184-
expect(ruleConfigs, hasLength(1));
185-
});
186-
187175
test('nested rule map (bool)', () {
188176
var options = <Object, Object?>{};
189177
var lintOptions = {

0 commit comments

Comments
 (0)