4
4
5
5
import 'dart:convert' ;
6
6
7
+ import 'package:analyzer/dart/ast/ast.dart' ;
7
8
import 'package:build_config/build_config.dart' ;
8
9
import 'package:built_collection/built_collection.dart' ;
9
10
import 'package:built_value/built_value.dart' ;
@@ -80,7 +81,7 @@ class BuildTriggers {
80
81
/// Parses [triggers] , or throws a descriptive exception on failure.
81
82
///
82
83
/// [triggers] is an `Object` read directly from yaml, to be valid it should
83
- /// be a list of strings that parse with [BuildTrigger.tryParse ] .
84
+ /// be a list of strings that parse with [BuildTrigger._tryParse ] .
84
85
static (Iterable <BuildTrigger >, List <String >) parseList ({
85
86
required Object triggers,
86
87
}) {
@@ -96,7 +97,7 @@ class BuildTriggers {
96
97
BuildTrigger ? trigger;
97
98
String ? warning;
98
99
if (triggerString is String ) {
99
- (trigger, warning) = BuildTrigger .tryParse (triggerString);
100
+ (trigger, warning) = BuildTrigger ._tryParse (triggerString);
100
101
}
101
102
if (trigger != null ) {
102
103
result.add (trigger);
@@ -124,13 +125,13 @@ class BuildTriggers {
124
125
}
125
126
126
127
/// A build trigger: a heuristic that possibly skips running a build step based
127
- /// on the primary input source .
128
+ /// on the parsed primary input.
128
129
abstract class BuildTrigger {
129
130
/// Parses a trigger, returning `null` on failure, optionally with a warning
130
131
/// message.
131
132
///
132
133
/// The only supported trigger is [ImportBuildTrigger] .
133
- static (BuildTrigger ? , String ? ) tryParse (String trigger) {
134
+ static (BuildTrigger ? , String ? ) _tryParse (String trigger) {
134
135
if (trigger.startsWith ('import ' )) {
135
136
trigger = trigger.substring ('import ' .length);
136
137
final result = ImportBuildTrigger (trigger);
@@ -143,18 +144,21 @@ abstract class BuildTrigger {
143
144
return (null , 'Invalid trigger: `$trigger `' );
144
145
}
145
146
146
- bool triggersOnPrimaryInput (String source);
147
+ /// Whether the trigger matches on any of [compilationUnits] .
148
+ ///
149
+ /// This will be called either with the primary input compilation unit or all
150
+ /// compilation units (parts) depending on [checksParts] .
151
+ bool triggersOn (List <CompilationUnit > compilationUnits);
152
+
153
+ /// Whether [triggersOn] should be called with all compilation units, not just
154
+ /// the primary input.
155
+ bool get checksParts;
147
156
}
148
157
149
158
// Note: `built_value` generated toString is relied on for digests, and
150
159
// equality for testing.
151
160
152
161
/// A build trigger that checks for a direct import.
153
- ///
154
- /// TODO(davidmorgan): this currently over-matches, it just checks for a
155
- /// matching substring. It's a heuristic so over matching is okay, but it might
156
- /// be better to actually parse directives and do a correct match because
157
- /// directives are needed when resolving source.
158
162
abstract class ImportBuildTrigger
159
163
implements
160
164
Built <ImportBuildTrigger , ImportBuildTriggerBuilder >,
@@ -166,18 +170,28 @@ abstract class ImportBuildTrigger
166
170
factory ImportBuildTrigger (String import) =>
167
171
_$ImportBuildTrigger ._(import: import);
168
172
173
+ @memoized
174
+ String get packageImport => 'package:$import ' ;
175
+
169
176
@override
170
- bool triggersOnPrimaryInput (String source) {
171
- return source.contains ('package:$import ' );
177
+ bool get checksParts => false ;
178
+
179
+ @override
180
+ bool triggersOn (List <CompilationUnit > compilationUnits) {
181
+ for (final compilationUnit in compilationUnits) {
182
+ for (final directive in compilationUnit.directives) {
183
+ if (directive is ! ImportDirective ) continue ;
184
+ if (directive.uri.stringValue == packageImport) return true ;
185
+ }
186
+ }
187
+ return false ;
172
188
}
173
189
174
190
String ? get warning =>
175
191
import.contains (_regexp) ? null : 'Invalid import trigger: `$import `' ;
176
192
}
177
193
178
194
/// A build trigger that checks for an annotation.
179
- ///
180
- /// TODO(davidmorgan): like `ImportBuildTrigger` this over-matches.
181
195
abstract class AnnotationBuildTrigger
182
196
implements
183
197
Built <AnnotationBuildTrigger , AnnotationBuildTriggerBuilder >,
@@ -190,8 +204,27 @@ abstract class AnnotationBuildTrigger
190
204
_$AnnotationBuildTrigger ._(annotation: annotation);
191
205
192
206
@override
193
- bool triggersOnPrimaryInput (String source) {
194
- return source.contains ('@$annotation ' );
207
+ bool get checksParts => true ;
208
+
209
+ @override
210
+ bool triggersOn (List <CompilationUnit > compilationUnits) {
211
+ for (final compilationUnit in compilationUnits) {
212
+ for (final declaration in compilationUnit.declarations) {
213
+ for (final metadata in declaration.metadata) {
214
+ var name = metadata.name.name;
215
+ if (metadata.constructorName != null ) {
216
+ name = '$name .${metadata .constructorName }' ;
217
+ }
218
+ if (annotation == name) return true ;
219
+ final periodIndex = name.indexOf ('.' );
220
+ if (periodIndex != - 1 ) {
221
+ name = name.substring (periodIndex + 1 );
222
+ if (annotation == name) return true ;
223
+ }
224
+ }
225
+ }
226
+ }
227
+ return false ;
195
228
}
196
229
197
230
String ? get warning =>
0 commit comments