-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathanalysis_options_loader.dart
More file actions
126 lines (106 loc) · 4.18 KB
/
Copy pathanalysis_options_loader.dart
File metadata and controls
126 lines (106 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import 'package:analyzer/analysis_rule/rule_context.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:solid_lints/src/common/parameter_parser/analysis_options_parser.dart';
import 'package:solid_lints/src/common/parameter_parser/cached_package_rules.dart';
import 'package:solid_lints/src/common/parameter_parser/package_config_resolver.dart';
/// Loads and parses analysis options from a Dart project's YAML file.
class AnalysisOptionsLoader {
final ResourceProvider _resourceProvider;
final Map<String, CachedPackageRules> _rulesCache = {};
late final AnalysisOptionsParser _parser;
/// Creates an instance of [AnalysisOptionsLoader].
AnalysisOptionsLoader({
ResourceProvider? resourceProvider,
AnalysisOptionsParser? parser,
}) : _resourceProvider =
resourceProvider ?? PhysicalResourceProvider.INSTANCE {
_parser = parser ??
AnalysisOptionsParser(
_resourceProvider,
PackageConfigResolver(_resourceProvider),
);
}
/// Gets the options for a specific rule by its name.
Map<String, Object?>? getRuleOptions(RuleContext context, String ruleName) =>
_withNearestAnalysisOptionsFilePathForContext<Map<String, Object?>?>(
context,
(path) => _rulesCache[path]?.rules[ruleName],
);
/// Gets the options for a specific rule by looking up the nearest
/// `analysis_options.yaml` from the given [filePath]'s directory.
///
/// Unlike [getRuleOptions], this method does not require a [RuleContext]
/// and can be used from quick fixes.
Map<String, Object?>? getRuleOptionsForFile(
String filePath,
String ruleName,
) {
final dirPath = _resourceProvider.pathContext.dirname(filePath);
final yamlPath = _findNearestAnalysisOptionsFilePath(dirPath);
if (yamlPath == null) return null;
_loadRulesOptionsIfNewer(yamlPath);
return _rulesCache[yamlPath]?.rules[ruleName];
}
/// Checks if a rule is explicitly disabled.
bool isRuleDisabled(RuleContext context, String ruleName) =>
_withNearestAnalysisOptionsFilePathForContext<bool>(
context,
(path) {
_loadRulesOptionsIfNewer(path);
return _rulesCache[path]?.disabledRules.contains(ruleName) ?? false;
},
) ??
false;
/// Loads lint rules from the analysis options file for all rules
/// using the provided [RuleContext].
void loadRulesOptionsFromContext(RuleContext context) =>
_withNearestAnalysisOptionsFilePathForContext(
context,
_loadRulesOptionsIfNewer,
);
T? _withNearestAnalysisOptionsFilePathForContext<T>(
RuleContext context,
T Function(String) f,
) {
final filePath = context.definingUnit.file.path;
final dirPath = _resourceProvider.pathContext.dirname(filePath);
final yamlPath = _findNearestAnalysisOptionsFilePath(dirPath);
if (yamlPath == null) return null;
return f(yamlPath);
}
void _loadRulesOptionsIfNewer(String yamlPath) {
final analysisOptionsFile = _resourceProvider.getFile(yamlPath);
final modificationStamp = analysisOptionsFile.modificationStamp;
final cachedRules = _rulesCache[yamlPath];
if (cachedRules?.modificationStamp == modificationStamp) {
return;
}
final rulesData = _parser.parse(analysisOptionsFile);
_rulesCache[yamlPath] = CachedPackageRules(
modificationStamp: modificationStamp,
rules: rulesData.rules,
disabledRules: rulesData.disabledRules,
);
}
String? _findNearestAnalysisOptionsFilePath(String startDirectoryPath) {
final pathContext = _resourceProvider.pathContext;
var currentDirectoryPath = startDirectoryPath;
while (currentDirectoryPath.isNotEmpty) {
final candidatePath = pathContext.join(
currentDirectoryPath,
'analysis_options.yaml',
);
final candidateFile = _resourceProvider.getFile(candidatePath);
if (candidateFile.exists) {
return candidatePath;
}
final parentDir = pathContext.dirname(currentDirectoryPath);
if (parentDir == currentDirectoryPath) {
break;
}
currentDirectoryPath = parentDir;
}
return null;
}
}