Skip to content

Commit ecfc0cb

Browse files
authored
Support a list of include paths in analysis options (#1594)
Support a list of include paths in analysis options The implementation is fairly simple. If the include value in an analysis options file is a List, then iteratively merge included options files. Fixes #1591.
1 parent e62313b commit ecfc0cb

File tree

3 files changed

+59
-11
lines changed

3 files changed

+59
-11
lines changed

lib/src/analysis_options/analysis_options_file.dart

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,7 @@ Future<AnalysisOptions> readAnalysisOptions(
6868
// Lower the YAML to a regular map.
6969
var options = {...yaml};
7070

71-
// If there is an `include:` key, then load that and merge it with these
72-
// options.
73-
if (options['include'] case String include) {
74-
options.remove('include');
75-
71+
Future<Map<Object?, Object?>> optionsFromInclude(String include) async {
7672
// If the include path is "package:", resolve it to a file path first.
7773
var includeUri = Uri.tryParse(include);
7874
if (includeUri != null && includeUri.scheme == 'package') {
@@ -95,9 +91,39 @@ Future<AnalysisOptions> readAnalysisOptions(
9591
// options file.
9692
var includePath = await fileSystem.join(
9793
(await fileSystem.parentDirectory(optionsPath))!, include);
98-
var includeFile = await readAnalysisOptions(fileSystem, includePath,
94+
return await readAnalysisOptions(fileSystem, includePath,
9995
resolvePackageUri: resolvePackageUri);
100-
options = merge(includeFile, options) as AnalysisOptions;
96+
}
97+
98+
// If there is an `include:` key with a String value, then load that and merge
99+
// it with these options. If there is an `include:` key with a List value,
100+
// then load each value, merging successive included options, overriding
101+
// previous results with each set of included options, finally merging with
102+
// these options.
103+
switch (options['include']) {
104+
case String include:
105+
options.remove('include');
106+
var includeOptions = await optionsFromInclude(include);
107+
options = merge(includeOptions, options) as AnalysisOptions;
108+
case List<Object?> includeList:
109+
options.remove('include');
110+
var mergedIncludeOptions = AnalysisOptions();
111+
for (var include in includeList) {
112+
if (include is! String) {
113+
throw PackageResolutionException(
114+
'Unsupported "include" value in analysis options include list: '
115+
'"$include".');
116+
}
117+
var includeOptions = await optionsFromInclude(include);
118+
mergedIncludeOptions =
119+
merge(mergedIncludeOptions, includeOptions) as AnalysisOptions;
120+
}
121+
options = merge(mergedIncludeOptions, options) as AnalysisOptions;
122+
case null:
123+
break;
124+
case Object include:
125+
throw PackageResolutionException(
126+
'Unsupported "include" value in analysis options: "$include".');
101127
}
102128

103129
return options;

test/analysis_options/analysis_options_file_test.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,29 @@ void main() {
7777
'ab': 'from a',
7878
'ac': 'from a',
7979
'abc': 'from a',
80+
'ad': 'from a',
8081
}),
81-
'dir|b.yaml': analysisOptions(include: 'c.yaml', other: {
82+
'dir|b.yaml': analysisOptions(include: [
83+
'c.yaml',
84+
'd.yaml'
85+
], other: {
8286
'ab': 'from b',
8387
'abc': 'from b',
8488
'b': 'from b',
8589
'bc': 'from b',
90+
'bd': 'from b',
8691
}),
8792
'dir|c.yaml': analysisOptions(other: {
8893
'ac': 'from c',
8994
'abc': 'from c',
9095
'bc': 'from c',
9196
'c': 'from c',
97+
'cd': 'from c',
98+
}),
99+
'dir|d.yaml': analysisOptions(other: {
100+
'ad': 'from d',
101+
'bd': 'from d',
102+
'cd': 'from d',
92103
}),
93104
});
94105

@@ -97,10 +108,13 @@ void main() {
97108
expect(options['a'], 'from a');
98109
expect(options['ab'], 'from a');
99110
expect(options['ac'], 'from a');
111+
expect(options['ad'], 'from a');
100112
expect(options['abc'], 'from a');
101113
expect(options['b'], 'from b');
102114
expect(options['bc'], 'from b');
115+
expect(options['bd'], 'from b');
103116
expect(options['c'], 'from c');
117+
expect(options['cd'], 'from d');
104118
});
105119

106120
test('removes the include key after merging', () async {

test/utils.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,19 @@ d.DirectoryDescriptor packageConfig(String rootPackageName,
200200
/// to include another analysis options file. If [other] is given, then those
201201
/// are added as other top-level keys in the YAML.
202202
String analysisOptions(
203-
{int? pageWidth, String? include, Map<String, Object>? other}) {
203+
{int? pageWidth,
204+
Object? /* String | List<String> */ include,
205+
Map<String, Object>? other}) {
204206
var yaml = StringBuffer();
205207

206-
if (include != null) {
207-
yaml.writeln('include: $include');
208+
switch (include) {
209+
case String _:
210+
yaml.writeln('include: $include');
211+
case List<String> _:
212+
yaml.writeln('include:');
213+
for (var path in include) {
214+
yaml.writeln(' - $path');
215+
}
208216
}
209217

210218
if (pageWidth != null) {

0 commit comments

Comments
 (0)