/
check_dependencies.dart
126 lines (98 loc) · 3.72 KB
/
check_dependencies.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:build/build.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:pubspec_parse/pubspec_parse.dart';
const _productionDirectories = {'lib', 'bin'};
const _annotationPkgName = 'json_annotation';
final requiredJsonAnnotationMinVersion = Version.parse('4.5.0');
Future<void> pubspecHasRightVersion(BuildStep buildStep) async {
final segments = buildStep.inputId.pathSegments;
final productionDependency =
segments.length > 1 && _productionDirectories.contains(segments.first);
final resource =
productionDependency ? _productionDependency : _developmentDependency;
await resource.run(buildStep);
}
final _productionDependency = _OncePerBuild(true, _validatePubspec);
final _developmentDependency = _OncePerBuild(false, _validatePubspec);
Future<void> _validatePubspec(bool production, BuildStep buildStep) async {
final pubspecAssetId = AssetId(buildStep.inputId.package, 'pubspec.yaml');
if (!await buildStep.canRead(pubspecAssetId)) {
log.warning(
'Could not read the "pubspec.yaml` file associated with this package. '
'Usage of package:$_annotationPkgName could not be verified.',
);
return;
}
Future<Pubspec> readPubspec(AssetId asset) async {
final string = await buildStep.readAsString(asset);
return Pubspec.parse(string, sourceUrl: asset.uri);
}
final pubspec = await readPubspec(pubspecAssetId);
final errorMessage = _checkAnnotationConstraint(
pubspec,
!production,
);
if (errorMessage == null) return;
log.warning(errorMessage);
}
String? _checkAnnotationConstraint(
Pubspec pubspec,
bool includeDevDependencies,
) {
var dependency = pubspec.dependencies[_annotationPkgName];
if (dependency == null && includeDevDependencies) {
dependency = pubspec.devDependencies[_annotationPkgName];
}
if (dependency == null) {
if (includeDevDependencies) {
dependency = pubspec.devDependencies[_annotationPkgName];
if (dependency == null) {
return 'You are missing a required dependency on $_annotationPkgName '
'with a lower bound of at least '
'"$requiredJsonAnnotationMinVersion".';
}
} else {
return 'You are missing a required dependency on $_annotationPkgName in '
'the "dependencies" section of your pubspec with a lower bound of at '
'least "$requiredJsonAnnotationMinVersion".';
}
}
if (dependency is! HostedDependency) {
log.warning(
'Your dependency on `$_annotationPkgName` is not a '
'`$HostedDependency`, as expected. Version checking is being skipped.',
);
return null;
}
// We know it's a HostedDependency at this point!
final constraint = dependency.version;
final constraintTooLowMessage =
'The version constraint "$constraint" on $_annotationPkgName allows '
'versions before $requiredJsonAnnotationMinVersion which is not '
'allowed.';
if (constraint is Version && constraint < requiredJsonAnnotationMinVersion) {
return constraintTooLowMessage;
}
final range = constraint as VersionRange;
final rangeMin = range.min;
if (rangeMin == null || rangeMin < requiredJsonAnnotationMinVersion) {
return constraintTooLowMessage;
}
return null;
}
class _OncePerBuild {
final bool state;
final FutureOr<void> Function(bool, BuildStep) _callback;
bool _ran = false;
_OncePerBuild(this.state, this._callback);
Future<void> run(BuildStep buildStep) async {
if (!_ran) {
_ran = true;
await _callback(state, buildStep);
}
}
}