Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
dart 3.6.0
dart 3.7.1
6 changes: 1 addition & 5 deletions bin/dependency_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ usage:''';

/// Parses the command-line arguments
final ArgParser argParser = ArgParser()
..addFlag(
helpArg,
abbr: 'h',
help: 'Displays this info.',
)
..addFlag(helpArg, abbr: 'h', help: 'Displays this info.')
..addFlag(
verboseArg,
defaultsTo: false,
Expand Down
33 changes: 21 additions & 12 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/// Regex used to detect all Dart import and export directives.
final RegExp importExportDartPackageRegex = RegExp(
r'''\b(import|export)\s+['"]{1,3}package:([a-zA-Z0-9_]+)\/[^;]+''',
multiLine: true);
r'''\b(import|export)\s+['"]{1,3}package:([a-zA-Z0-9_]+)\/[^;]+''',
multiLine: true,
);

/// Regex used to detect all Sass import directives.
final RegExp importScssPackageRegex =
RegExp(r'''\@import\s+['"]{1,3}package:\s*([a-zA-Z0-9_]+)\/[^;]+''');
final RegExp importScssPackageRegex = RegExp(
r'''\@import\s+['"]{1,3}package:\s*([a-zA-Z0-9_]+)\/[^;]+''',
);

/// Regex used to detect all Less import directives.
final RegExp importLessPackageRegex = RegExp(
r'@import\s+(?:\(.*\)\s+)?"(?:packages\/|package:\/\/)([a-zA-Z1-9_-]+)\/');
r'@import\s+(?:\(.*\)\s+)?"(?:packages\/|package:\/\/)([a-zA-Z1-9_-]+)\/',
);

/// String key in pubspec.yaml for the dependencies map.
const String dependenciesKey = 'dependencies';
Expand Down Expand Up @@ -50,21 +53,27 @@ class DependencyPinEvaluation {
/// possible prerelease.
static const DependencyPinEvaluation buildOrPrerelease =
DependencyPinEvaluation._(
'Builds or preleases as max bounds block minor bumps and patches.');
'Builds or preleases as max bounds block minor bumps and patches.',
);

/// 1.2.3
static const DependencyPinEvaluation directPin =
DependencyPinEvaluation._('This is a direct pin.');
static const DependencyPinEvaluation directPin = DependencyPinEvaluation._(
'This is a direct pin.',
);

/// >1.2.3 <1.2.3
static const DependencyPinEvaluation emptyPin = DependencyPinEvaluation._(
'Empty dependency versions cannot be resolved.');
'Empty dependency versions cannot be resolved.',
);

/// <=1.2.3
static const DependencyPinEvaluation inclusiveMax = DependencyPinEvaluation._(
'Inclusive max bounds restrict minor bumps and patches.');
'Inclusive max bounds restrict minor bumps and patches.',
);

/// :)
static const DependencyPinEvaluation notAPin =
DependencyPinEvaluation._('This dependency is good to go.', isPin: false);
static const DependencyPinEvaluation notAPin = DependencyPinEvaluation._(
'This dependency is good to go.',
isPin: false,
);
}
142 changes: 91 additions & 51 deletions lib/src/dependency_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ Future<bool> checkPackage({required String root}) async {
File('$root/pubspec.yaml').readAsStringSync(),
);
if (pubspecConfig.isNotEmpty) {
logger.warning(yellow.wrap(
logger.warning(
yellow.wrap(
'Configuring dependency_validator in pubspec.yaml is deprecated.\n'
'Use dart_dependency_validator.yaml instead.'));
'Use dart_dependency_validator.yaml instead.',
),
);
}
config = pubspecConfig.dependencyValidator;
}
Expand Down Expand Up @@ -97,8 +100,10 @@ Future<bool> checkPackage({required String root}) async {

// Extract the package names from the `dev_dependencies` section.
final devDeps = Set<String>.from(pubspec.devDependencies.keys);
logger.fine('dev_dependencies:\n'
'${bulletItems(devDeps)}\n');
logger.fine(
'dev_dependencies:\n'
'${bulletItems(devDeps)}\n',
);

final publicDirs = ['$root/bin/', '$root/lib/'];
logger.fine("Excluding: $excludes");
Expand All @@ -113,12 +118,18 @@ Future<bool> checkPackage({required String root}) async {
];

logger
..fine('public facing dart files:\n'
'${bulletItems(publicDartFiles.map((f) => f.path))}\n')
..fine('public facing scss files:\n'
'${bulletItems(publicScssFiles.map((f) => f.path))}\n')
..fine('public facing less files:\n'
'${bulletItems(publicLessFiles.map((f) => f.path))}\n');
..fine(
'public facing dart files:\n'
'${bulletItems(publicDartFiles.map((f) => f.path))}\n',
)
..fine(
'public facing scss files:\n'
'${bulletItems(publicScssFiles.map((f) => f.path))}\n',
)
..fine(
'public facing less files:\n'
'${bulletItems(publicLessFiles.map((f) => f.path))}\n',
);

// Read each file in lib/ and parse the package names from every import and
// export directive.
Expand All @@ -138,12 +149,12 @@ Future<bool> checkPackage({required String root}) async {
packagesUsedInPublicFiles.add(match.group(1)!);
}
}
logger.fine('packages used in public facing files:\n'
'${bulletItems(packagesUsedInPublicFiles)}\n');
logger.fine(
'packages used in public facing files:\n'
'${bulletItems(packagesUsedInPublicFiles)}\n',
);

final publicDirGlobs = [
for (final dir in publicDirs) makeGlob('$dir**'),
];
final publicDirGlobs = [for (final dir in publicDirs) makeGlob('$dir**')];

final subpackageGlobs = [
for (final subpackage in pubspec.workspace ?? [])
Expand All @@ -152,26 +163,35 @@ Future<bool> checkPackage({required String root}) async {

logger.fine('subpackage globs: $subpackageGlobs');

final nonPublicDartFiles = listDartFilesIn(
'$root/',
[...excludes, ...publicDirGlobs, ...subpackageGlobs],
);
final nonPublicScssFiles = listScssFilesIn(
'$root/',
[...excludes, ...publicDirGlobs, ...subpackageGlobs],
);
final nonPublicLessFiles = listLessFilesIn(
'$root/',
[...excludes, ...publicDirGlobs, ...subpackageGlobs],
);
final nonPublicDartFiles = listDartFilesIn('$root/', [
...excludes,
...publicDirGlobs,
...subpackageGlobs,
]);
final nonPublicScssFiles = listScssFilesIn('$root/', [
...excludes,
...publicDirGlobs,
...subpackageGlobs,
]);
final nonPublicLessFiles = listLessFilesIn('$root/', [
...excludes,
...publicDirGlobs,
...subpackageGlobs,
]);

logger
..fine('non-public dart files:\n'
'${bulletItems(nonPublicDartFiles.map((f) => f.path))}\n')
..fine('non-public scss files:\n'
'${bulletItems(nonPublicScssFiles.map((f) => f.path))}\n')
..fine('non-public less files:\n'
'${bulletItems(nonPublicLessFiles.map((f) => f.path))}\n');
..fine(
'non-public dart files:\n'
'${bulletItems(nonPublicDartFiles.map((f) => f.path))}\n',
)
..fine(
'non-public scss files:\n'
'${bulletItems(nonPublicScssFiles.map((f) => f.path))}\n',
)
..fine(
'non-public less files:\n'
'${bulletItems(nonPublicLessFiles.map((f) => f.path))}\n',
);

// Read each file outside lib/ and parse the package names from every
// import and export directive.
Expand All @@ -196,8 +216,10 @@ Future<bool> checkPackage({required String root}) async {
}
}

logger.fine('packages used outside public dirs:\n'
'${bulletItems(packagesUsedOutsidePublicDirs)}\n');
logger.fine(
'packages used outside public dirs:\n'
'${bulletItems(packagesUsedOutsidePublicDirs)}\n',
);

// Packages that are used in lib/ but are not dependencies.
final missingDependencies =
Expand Down Expand Up @@ -287,18 +309,25 @@ Future<bool> checkPackage({required String root}) async {
.difference(packagesUsedInPublicFiles)
.difference(packagesUsedOutsidePublicDirs)
// Remove this package, since we know they're using our executable
..remove(dependencyValidatorPackageName);
..remove(dependencyValidatorPackageName)
..removeAll(ignoredPackages);

final packageConfig = await findPackageConfig(Directory.current);
if (packageConfig == null) {
logger.severe(red.wrap(
'Could not find package config. Make sure you run `dart pub get` first.'));
logger.severe(
red.wrap(
'Could not find package config. Make sure you run `dart pub get` first.',
),
);
return false;
}

// Remove deps that provide builders that will be applied
final rootBuildConfig = await BuildConfig.fromBuildConfigDir(
pubspec.name, pubspec.dependencies.keys, '.');
pubspec.name,
pubspec.dependencies.keys,
'.',
);
bool rootPackageReferencesDependencyInBuildYaml(String dependencyName) => [
...rootBuildConfig.globalOptions.keys,
for (final target in rootBuildConfig.buildTargets.values)
Expand Down Expand Up @@ -365,14 +394,12 @@ Future<bool> checkPackage({required String root}) async {
if (unusedDependencies.contains('analyzer')) {
logger.warning(
yellow.wrap(
'You do not need to depend on `analyzer` to run the Dart analyzer.\n'
'Instead, just run the `dartanalyzer` executable that is bundled with the Dart SDK.'),
'You do not need to depend on `analyzer` to run the Dart analyzer.\n'
'Instead, just run the `dartanalyzer` executable that is bundled with the Dart SDK.',
),
);
}

// Ignore known unused packages
unusedDependencies.removeAll(ignoredPackages);

if (unusedDependencies.isNotEmpty) {
log(
Level.WARNING,
Expand All @@ -390,7 +417,9 @@ Future<bool> checkPackage({required String root}) async {

/// Whether a dependency at [path] defines an auto applied builder.
Future<bool> dependencyDefinesAutoAppliedBuilder(String path) async =>
(await BuildConfig.fromPackageDir(path))
(await BuildConfig.fromPackageDir(
path,
))
.builderDefinitions
.values
.any((def) => def.autoApply != AutoApply.none);
Expand Down Expand Up @@ -418,15 +447,26 @@ void checkPubspecForPins(
List<String> ignoredPackages = const [],
}) {
final List<String> infractions = [];
infractions.addAll(getDependenciesWithPins(pubspec.dependencies,
ignoredPackages: ignoredPackages));
infractions.addAll(
getDependenciesWithPins(
pubspec.dependencies,
ignoredPackages: ignoredPackages,
),
);

infractions.addAll(getDependenciesWithPins(pubspec.devDependencies,
ignoredPackages: ignoredPackages));
infractions.addAll(
getDependenciesWithPins(
pubspec.devDependencies,
ignoredPackages: ignoredPackages,
),
);

if (infractions.isNotEmpty) {
log(Level.WARNING, 'These packages are pinned in pubspec.yaml:',
infractions);
log(
Level.WARNING,
'These packages are pinned in pubspec.yaml:',
infractions,
);
exitCode = 1;
}
}
32 changes: 20 additions & 12 deletions lib/src/pubspec_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import 'package:json_annotation/json_annotation.dart';
part 'pubspec_config.g.dart';

@JsonSerializable(
anyMap: true,
checked: true,
createToJson: false,
fieldRename: FieldRename.snake)
anyMap: true,
checked: true,
createToJson: false,
fieldRename: FieldRename.snake,
)
class PubspecDepValidatorConfig {
final DepValidatorConfig dependencyValidator;

Expand All @@ -23,15 +24,19 @@ class PubspecDepValidatorConfig {

factory PubspecDepValidatorConfig.fromYaml(String yamlContent, {sourceUrl}) =>
checkedYamlDecode(
yamlContent, (m) => PubspecDepValidatorConfig.fromJson(m ?? {}),
allowNull: true, sourceUrl: sourceUrl);
yamlContent,
(m) => PubspecDepValidatorConfig.fromJson(m ?? {}),
allowNull: true,
sourceUrl: sourceUrl,
);
}

@JsonSerializable(
anyMap: true,
checked: true,
createToJson: true,
fieldRename: FieldRename.snake)
anyMap: true,
checked: true,
createToJson: true,
fieldRename: FieldRename.snake,
)
class DepValidatorConfig {
@JsonKey(defaultValue: [])
final List<String> exclude;
Expand All @@ -53,8 +58,11 @@ class DepValidatorConfig {

factory DepValidatorConfig.fromYaml(String yamlContent, {sourceUrl}) =>
checkedYamlDecode(
yamlContent, (m) => DepValidatorConfig.fromJson(m ?? {}),
allowNull: true, sourceUrl: sourceUrl);
yamlContent,
(m) => DepValidatorConfig.fromJson(m ?? {}),
allowNull: true,
sourceUrl: sourceUrl,
);

Map<String, dynamic> toJson() => _$DepValidatorConfigToJson(this);
}
Loading
Loading