Skip to content

Commit

Permalink
Support a list of include paths in analysis options (#1594)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
srawlins authored Nov 11, 2024
1 parent e62313b commit ecfc0cb
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 11 deletions.
40 changes: 33 additions & 7 deletions lib/src/analysis_options/analysis_options_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,7 @@ Future<AnalysisOptions> readAnalysisOptions(
// Lower the YAML to a regular map.
var options = {...yaml};

// If there is an `include:` key, then load that and merge it with these
// options.
if (options['include'] case String include) {
options.remove('include');

Future<Map<Object?, Object?>> optionsFromInclude(String include) async {
// If the include path is "package:", resolve it to a file path first.
var includeUri = Uri.tryParse(include);
if (includeUri != null && includeUri.scheme == 'package') {
Expand All @@ -95,9 +91,39 @@ Future<AnalysisOptions> readAnalysisOptions(
// options file.
var includePath = await fileSystem.join(
(await fileSystem.parentDirectory(optionsPath))!, include);
var includeFile = await readAnalysisOptions(fileSystem, includePath,
return await readAnalysisOptions(fileSystem, includePath,
resolvePackageUri: resolvePackageUri);
options = merge(includeFile, options) as AnalysisOptions;
}

// If there is an `include:` key with a String value, then load that and merge
// it with these options. If there is an `include:` key with a List value,
// then load each value, merging successive included options, overriding
// previous results with each set of included options, finally merging with
// these options.
switch (options['include']) {
case String include:
options.remove('include');
var includeOptions = await optionsFromInclude(include);
options = merge(includeOptions, options) as AnalysisOptions;
case List<Object?> includeList:
options.remove('include');
var mergedIncludeOptions = AnalysisOptions();
for (var include in includeList) {
if (include is! String) {
throw PackageResolutionException(
'Unsupported "include" value in analysis options include list: '
'"$include".');
}
var includeOptions = await optionsFromInclude(include);
mergedIncludeOptions =
merge(mergedIncludeOptions, includeOptions) as AnalysisOptions;
}
options = merge(mergedIncludeOptions, options) as AnalysisOptions;
case null:
break;
case Object include:
throw PackageResolutionException(
'Unsupported "include" value in analysis options: "$include".');
}

return options;
Expand Down
16 changes: 15 additions & 1 deletion test/analysis_options/analysis_options_file_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,29 @@ void main() {
'ab': 'from a',
'ac': 'from a',
'abc': 'from a',
'ad': 'from a',
}),
'dir|b.yaml': analysisOptions(include: 'c.yaml', other: {
'dir|b.yaml': analysisOptions(include: [
'c.yaml',
'd.yaml'
], other: {
'ab': 'from b',
'abc': 'from b',
'b': 'from b',
'bc': 'from b',
'bd': 'from b',
}),
'dir|c.yaml': analysisOptions(other: {
'ac': 'from c',
'abc': 'from c',
'bc': 'from c',
'c': 'from c',
'cd': 'from c',
}),
'dir|d.yaml': analysisOptions(other: {
'ad': 'from d',
'bd': 'from d',
'cd': 'from d',
}),
});

Expand All @@ -97,10 +108,13 @@ void main() {
expect(options['a'], 'from a');
expect(options['ab'], 'from a');
expect(options['ac'], 'from a');
expect(options['ad'], 'from a');
expect(options['abc'], 'from a');
expect(options['b'], 'from b');
expect(options['bc'], 'from b');
expect(options['bd'], 'from b');
expect(options['c'], 'from c');
expect(options['cd'], 'from d');
});

test('removes the include key after merging', () async {
Expand Down
14 changes: 11 additions & 3 deletions test/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,19 @@ d.DirectoryDescriptor packageConfig(String rootPackageName,
/// to include another analysis options file. If [other] is given, then those
/// are added as other top-level keys in the YAML.
String analysisOptions(
{int? pageWidth, String? include, Map<String, Object>? other}) {
{int? pageWidth,
Object? /* String | List<String> */ include,
Map<String, Object>? other}) {
var yaml = StringBuffer();

if (include != null) {
yaml.writeln('include: $include');
switch (include) {
case String _:
yaml.writeln('include: $include');
case List<String> _:
yaml.writeln('include:');
for (var path in include) {
yaml.writeln(' - $path');
}
}

if (pageWidth != null) {
Expand Down

0 comments on commit ecfc0cb

Please sign in to comment.