diff --git a/lib/src/dependency_validator.dart b/lib/src/dependency_validator.dart index 7eb7d9e..2b30dd0 100644 --- a/lib/src/dependency_validator.dart +++ b/lib/src/dependency_validator.dart @@ -131,11 +131,16 @@ Future checkPackage({required String root}) async { '${bulletItems(publicLessFiles.map((f) => f.path))}\n', ); + // The language version that the dart files of this package are parsed with. + final featureSet = featureSetForPubspec(pubspec); + // Read each file in lib/ and parse the package names from every import and // export directive. final packagesUsedInPublicFiles = {}; for (final file in publicDartFiles) { - packagesUsedInPublicFiles.addAll(getDartDirectivePackageNames(file)); + packagesUsedInPublicFiles.addAll( + getDartDirectivePackageNames(file, featureSet: featureSet), + ); } for (final file in publicScssFiles) { final matches = importScssPackageRegex.allMatches(file.readAsStringSync()); @@ -201,7 +206,9 @@ Future checkPackage({required String root}) async { if (optionsIncludePackage != null) optionsIncludePackage, }; for (final file in nonPublicDartFiles) { - packagesUsedOutsidePublicDirs.addAll(getDartDirectivePackageNames(file)); + packagesUsedOutsidePublicDirs.addAll( + getDartDirectivePackageNames(file, featureSet: featureSet), + ); } for (final file in nonPublicScssFiles) { final matches = importScssPackageRegex.allMatches(file.readAsStringSync()); diff --git a/lib/src/import_export_ast_visitor.dart b/lib/src/import_export_ast_visitor.dart index 5eb82d1..19eff61 100644 --- a/lib/src/import_export_ast_visitor.dart +++ b/lib/src/import_export_ast_visitor.dart @@ -1,16 +1,31 @@ import 'dart:io'; +import 'package:analyzer/dart/analysis/features.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/analysis/utilities.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/visitor.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:pubspec_parse/pubspec_parse.dart'; + +import 'utils.dart'; /// Returns the list of package names that are exported and imported into the -/// provided dart file -Set getDartDirectivePackageNames(File file) { +/// provided dart file, which is parsed with the given [featureSet]. +/// +/// See [featureSetForPubspec] for resolving the [featureSet] of the package +/// that [file] belongs to. +Set getDartDirectivePackageNames( + File file, { + required FeatureSet featureSet, +}) { ParseStringResult parsed; try { - parsed = parseString(content: file.readAsStringSync(), path: file.path); + parsed = parseString( + content: file.readAsStringSync(), + path: file.path, + featureSet: featureSet, + ); } on ArgumentError catch (e) { print('Error parsing: ${file.path}'); print(e.message); @@ -22,6 +37,42 @@ Set getDartDirectivePackageNames(File file) { return visitor.packageNames; } +/// Returns the [FeatureSet] that matches the Dart SDK version declared by the +/// `environment: sdk:` constraint of [pubspec]. +/// +/// Falls back to [FeatureSet.latestLanguageVersion] when [pubspec] does not +/// declare an SDK constraint with a lower bound. +FeatureSet featureSetForPubspec(Pubspec pubspec) { + final languageVersion = _sdkLanguageVersionOf(pubspec); + if (languageVersion == null) { + logger.fine( + 'No SDK version found for ${pubspec.name}, ' + 'parsing with the latest language version.', + ); + return FeatureSet.latestLanguageVersion(); + } + + logger.fine('Using language version $languageVersion for ${pubspec.name}'); + return FeatureSet.fromEnableFlags2( + sdkLanguageVersion: languageVersion, + flags: const [], + ); +} + +/// Returns the language version implied by the `environment: sdk:` constraint +/// of [pubspec], or null if it has none. +Version? _sdkLanguageVersionOf(Pubspec pubspec) { + final sdkConstraint = pubspec.environment['sdk']; + + // `Version` also implements `VersionRange`, with itself as the lower bound. + final minSdkVersion = + sdkConstraint is VersionRange ? sdkConstraint.min : null; + if (minSdkVersion == null) return null; + + // A language version is only major.minor. + return Version(minSdkVersion.major, minSdkVersion.minor, 0); +} + class ImportExportVisitor extends GeneralizingAstVisitor { Set packageNames = {};