From c5e7eb90b96c193df23a477f18a08d514fea324f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levent=20Kantaro=C4=9Flu?= <63751824+leventkantaroglu@users.noreply.github.com> Date: Mon, 6 Oct 2025 22:31:08 +0300 Subject: [PATCH 1/3] Enhance getAnalysisOptionsIncludePackage to support single and list includes, and update tests accordingly --- lib/src/dependency_validator.dart | 3 ++- lib/src/utils.dart | 38 +++++++++++++++++++++++++----- test/utils_test.dart | 39 ++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/lib/src/dependency_validator.dart b/lib/src/dependency_validator.dart index 4fe5ed1..434a848 100644 --- a/lib/src/dependency_validator.dart +++ b/lib/src/dependency_validator.dart @@ -199,7 +199,8 @@ Future checkPackage({required String root}) async { final packagesUsedOutsidePublicDirs = { // For more info on analysis options: // https://dart.dev/guides/language/analysis-options#the-analysis-options-file - if (optionsIncludePackage != null) optionsIncludePackage, + if (optionsIncludePackage != null && optionsIncludePackage.isNotEmpty) + ...optionsIncludePackage, }; for (final file in nonPublicDartFiles) { packagesUsedOutsidePublicDirs.addAll(getDartDirectivePackageNames(file)); diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 427a5f5..1310070 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -31,19 +31,45 @@ final Logger logger = Logger('dependency_validator'); String bulletItems(Iterable items) => items.map((l) => ' * $l').join('\n'); -/// Returns the name of the package referenced in the `include:` directive in an -/// analysis_options.yaml file, or null if there is not one. -String? getAnalysisOptionsIncludePackage({String? path}) { +/// Returns the names of the packages referenced in the `include:` directive in an +/// analysis_options.yaml file, or null if there are none. +/// +/// Supports both single string includes: +/// include: package:flutter_lints/flutter.yaml +/// +/// And list includes: +/// include: +/// - package:flutter_lints/flutter.yaml +/// - package:another_package/config.yaml +Set? getAnalysisOptionsIncludePackage({String? path}) { final optionsFile = File(p.join(path ?? p.current, 'analysis_options.yaml')); if (!optionsFile.existsSync()) return null; final YamlMap? analysisOptions = loadYaml(optionsFile.readAsStringSync()); if (analysisOptions == null) return null; - final String? include = analysisOptions['include']; - if (include == null || !include.startsWith('package:')) return null; + final dynamic include = analysisOptions['include']; + if (include == null) return null; + + final Set packageNames = {}; + + if (include is String) { + // Handle single string include + if (include.startsWith('package:')) { + final packageName = Uri.parse(include).pathSegments.first; + packageNames.add(packageName); + } + } else if (include is YamlList) { + // Handle list of includes + for (final dynamic item in include) { + if (item is String && item.startsWith('package:')) { + final packageName = Uri.parse(item).pathSegments.first; + packageNames.add(packageName); + } + } + } - return Uri.parse(include).pathSegments.first; + return packageNames.isEmpty ? null : packageNames; } /// Returns an iterable of all Dart files (files ending in .dart) in the given diff --git a/test/utils_test.dart b/test/utils_test.dart index 4c7407c..bc40e78 100644 --- a/test/utils_test.dart +++ b/test/utils_test.dart @@ -43,7 +43,44 @@ linter: await d.file('analysis_options.yaml', ''' include: package:pedantic/analysis_options.1.8.0.yaml ''').create(); - expect(getAnalysisOptionsIncludePackage(path: d.sandbox), 'pedantic'); + expect(getAnalysisOptionsIncludePackage(path: d.sandbox), {'pedantic'}); + }); + + test('returns package names from list `include:`', () async { + await d.file('analysis_options.yaml', ''' +include: + - package:flutter_lints/flutter.yaml + - package:pedantic/analysis_options.1.8.0.yaml +''').create(); + expect(getAnalysisOptionsIncludePackage(path: d.sandbox), + {'flutter_lints', 'pedantic'}); + }); + + test('filters out non-package includes from list', () async { + await d.file('analysis_options.yaml', ''' +include: + - package:flutter_lints/flutter.yaml + - analysis_options_shared.yaml + - package:pedantic/analysis_options.1.8.0.yaml +''').create(); + expect(getAnalysisOptionsIncludePackage(path: d.sandbox), + {'flutter_lints', 'pedantic'}); + }); + + test('returns null for list with no package includes', () async { + await d.file('analysis_options.yaml', ''' +include: + - analysis_options_shared.yaml + - ../common_options.yaml +''').create(); + expect(getAnalysisOptionsIncludePackage(path: d.sandbox), isNull); + }); + + test('handles empty list', () async { + await d.file('analysis_options.yaml', ''' +include: [] +''').create(); + expect(getAnalysisOptionsIncludePackage(path: d.sandbox), isNull); }); }); From 5235fe81c92103a79f2d8c5dd9248c6137f5f11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levent=20Kantaro=C4=9Flu?= <63751824+leventkantaroglu@users.noreply.github.com> Date: Sun, 12 Oct 2025 17:41:53 +0300 Subject: [PATCH 2/3] update dependency_validator.dart and utils.dart --- lib/src/dependency_validator.dart | 57 ++++++++++++++++--------------- lib/src/utils.dart | 6 ++-- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/src/dependency_validator.dart b/lib/src/dependency_validator.dart index 434a848..a23e871 100644 --- a/lib/src/dependency_validator.dart +++ b/lib/src/dependency_validator.dart @@ -54,18 +54,17 @@ Future checkPackage({required String root}) async { config = pubspecConfig.dependencyValidator; } - final excludes = - config.exclude - .map((s) { - try { - return makeGlob("$root/$s"); - } catch (_, __) { - logger.shout(yellow.wrap('invalid glob syntax: "$s"')); - return null; - } - }) - .nonNulls - .toList(); + final excludes = config.exclude + .map((s) { + try { + return makeGlob("$root/$s"); + } catch (_, __) { + logger.shout(yellow.wrap('invalid glob syntax: "$s"')); + return null; + } + }) + .nonNulls + .toList(); logger.fine('excludes:\n${bulletItems(excludes.map((g) => g.pattern))}\n'); final ignoredPackages = config.ignore; logger.fine('ignored packages:\n${bulletItems(ignoredPackages)}\n'); @@ -199,8 +198,7 @@ Future checkPackage({required String root}) async { final packagesUsedOutsidePublicDirs = { // For more info on analysis options: // https://dart.dev/guides/language/analysis-options#the-analysis-options-file - if (optionsIncludePackage != null && optionsIncludePackage.isNotEmpty) - ...optionsIncludePackage, + if (optionsIncludePackage != null) ...optionsIncludePackage, }; for (final file in nonPublicDartFiles) { packagesUsedOutsidePublicDirs.addAll(getDartDirectivePackageNames(file)); @@ -269,13 +267,13 @@ Future checkPackage({required String root}) async { // Packages that are not used in lib/, but are used elsewhere, that are // dependencies when they should be dev_dependencies. final overPromotedDependencies = - // Start with dependencies that are not used in lib/ - (deps - .difference(packagesUsedInPublicFiles) - // Intersect with deps that are used outside lib/ (excludes unused deps) - .intersection(packagesUsedOutsidePublicDirs)) - // Ignore known over-promoted packages. - ..removeAll(ignoredPackages); + // Start with dependencies that are not used in lib/ + (deps + .difference(packagesUsedInPublicFiles) + // Intersect with deps that are used outside lib/ (excludes unused deps) + .intersection(packagesUsedOutsidePublicDirs)) + // Ignore known over-promoted packages. + ..removeAll(ignoredPackages); if (overPromotedDependencies.isNotEmpty) { log( @@ -288,10 +286,10 @@ Future checkPackage({required String root}) async { // Packages that are used in lib/, but are dev_dependencies. final underPromotedDependencies = - // Start with dev_dependencies that are used in lib/ - devDeps.intersection(packagesUsedInPublicFiles) - // Ignore known under-promoted packages - ..removeAll(ignoredPackages); + // Start with dev_dependencies that are used in lib/ + devDeps.intersection(packagesUsedInPublicFiles) + // Ignore known under-promoted packages + ..removeAll(ignoredPackages); if (underPromotedDependencies.isNotEmpty) { log( @@ -335,8 +333,8 @@ Future checkPackage({required String root}) async { for (final target in rootBuildConfig.buildTargets.values) ...target.builders.keys, ] - .map((key) => normalizeBuilderKeyUsage(key, pubspec.name)) - .any((key) => key.startsWith('$dependencyName:')); + .map((key) => normalizeBuilderKeyUsage(key, pubspec.name)) + .any((key) => key.startsWith('$dependencyName:')); final packagesWithConsumedBuilders = Set(); for (final name in unusedDependencies) { @@ -421,7 +419,10 @@ Future checkPackage({required String root}) async { Future dependencyDefinesAutoAppliedBuilder(String path) async => (await BuildConfig.fromPackageDir( path, - )).builderDefinitions.values.any((def) => def.autoApply != AutoApply.none); + )) + .builderDefinitions + .values + .any((def) => def.autoApply != AutoApply.none); /// Checks for dependency pins. /// diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 1310070..342a202 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -48,10 +48,10 @@ Set? getAnalysisOptionsIncludePackage({String? path}) { final YamlMap? analysisOptions = loadYaml(optionsFile.readAsStringSync()); if (analysisOptions == null) return null; - final dynamic include = analysisOptions['include']; + final Object? include = analysisOptions['include']; if (include == null) return null; - final Set packageNames = {}; + final packageNames = {}; if (include is String) { // Handle single string include @@ -61,7 +61,7 @@ Set? getAnalysisOptionsIncludePackage({String? path}) { } } else if (include is YamlList) { // Handle list of includes - for (final dynamic item in include) { + for (final item in include) { if (item is String && item.startsWith('package:')) { final packageName = Uri.parse(item).pathSegments.first; packageNames.add(packageName); From 44d9cf7635be3b4df3c290c3385256cf0d0664f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levent=20Kantaro=C4=9Flu?= <63751824+leventkantaroglu@users.noreply.github.com> Date: Sun, 12 Oct 2025 17:46:01 +0300 Subject: [PATCH 3/3] docs: update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ed194e..2ee6bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 5.0.3 + +- Add YAML list format support for analysis_options file + # 5.0.2 - Fixed changelog entries caused from mis-configured auto-release