1
1
import 'package:analyzer/dart/constant/value.dart' ;
2
2
import 'package:analyzer/dart/element/element.dart' ;
3
+ import 'package:analyzer/dart/element/nullability_suffix.dart' ;
3
4
import 'package:analyzer/dart/element/type.dart' ;
4
5
import 'package:build/build.dart' ;
5
6
import 'package:cloud_firestore_odm/annotation.dart' ;
@@ -26,6 +27,7 @@ class CollectionData {
26
27
required this .queryableFields,
27
28
required this .fromJson,
28
29
required this .toJson,
30
+ required this .injections,
29
31
}) : collectionName =
30
32
collectionName ?? ReCase (path.split ('/' ).last).camelCase;
31
33
@@ -62,12 +64,26 @@ class CollectionData {
62
64
String Function (String json) fromJson;
63
65
String Function (String value) toJson;
64
66
67
+ final List <FieldInjection > injections;
68
+
65
69
@override
66
70
String toString () {
67
71
return 'CollectionData(type: $type , collectionName: $collectionName , path: $path )' ;
68
72
}
69
73
}
70
74
75
+ class FieldInjection {
76
+ const FieldInjection ({
77
+ required this .type,
78
+ required this .name,
79
+ required this .nullable,
80
+ });
81
+
82
+ final FirestoreValue type;
83
+ final String name;
84
+ final bool nullable;
85
+ }
86
+
71
87
class Data {
72
88
Data (this .roots, this .subCollections);
73
89
@@ -274,6 +290,60 @@ class CollectionGenerator extends ParserGenerator<void, Data, Collection> {
274
290
}
275
291
}
276
292
293
+ const injectTs = TypeChecker .fromRuntime (Inject );
294
+ final injections = < FieldInjection > [];
295
+
296
+ final setters = collectionTargetElement.accessors;
297
+ final fields = collectionTargetElement.fields;
298
+ for (final f in [...setters, ...fields]) {
299
+ final annotations = injectTs.annotationsOf (f);
300
+
301
+ if (annotations.isEmpty) continue ;
302
+ if (annotations.length > 1 ) {
303
+ throw InvalidGenerationSourceError (
304
+ 'Only one @Inject annotation may be used for each field.' ,
305
+ element: f,
306
+ );
307
+ }
308
+
309
+ if ((f is PropertyAccessorElement && ! f.isSetter) ||
310
+ (f is FieldElement && f.isFinal)) {
311
+ throw InvalidGenerationSourceError (
312
+ '@Inject fields or properties must be settable.' ,
313
+ element: f,
314
+ );
315
+ }
316
+
317
+ final annotation = annotations.first;
318
+ final annotationType = _parseInjectAnnotationType (annotation);
319
+
320
+ DartType ? type;
321
+ if (f is PropertyAccessorElement ) {
322
+ type = f.parameters[0 ].type;
323
+ } else if (f is FieldElement ) {
324
+ type = f.type;
325
+ }
326
+
327
+ if (type == null || ! type.isDartCoreString) {
328
+ throw InvalidGenerationSourceError (
329
+ 'Fields with @Inject must be of type String.' ,
330
+ element: f,
331
+ );
332
+ }
333
+
334
+ // Names of setters have '=' appended.
335
+ final name = f is PropertyAccessorElement
336
+ ? f.name.substring (0 , f.name.length - 1 )
337
+ : f.name! ;
338
+
339
+ final injection = FieldInjection (
340
+ type: annotationType,
341
+ name: name,
342
+ nullable: type.nullabilitySuffix != NullabilitySuffix .none,
343
+ );
344
+ injections.add (injection);
345
+ }
346
+
277
347
return CollectionData (
278
348
type: type,
279
349
path: path,
@@ -288,6 +358,7 @@ class CollectionGenerator extends ParserGenerator<void, Data, Collection> {
288
358
},
289
359
queryableFields: collectionTargetElement.fields
290
360
.where ((f) => f.isPublic)
361
+ .whereNot ((f) => injections.any ((inj) => inj.name == f.name))
291
362
.where (
292
363
(f) =>
293
364
f.type.isDartCoreString ||
@@ -299,9 +370,15 @@ class CollectionGenerator extends ParserGenerator<void, Data, Collection> {
299
370
// TODO filter list other than LIst<string|bool|num>
300
371
)
301
372
.toList (),
373
+ injections: injections,
302
374
);
303
375
}
304
376
377
+ FirestoreValue _parseInjectAnnotationType (DartObject annotation) {
378
+ return FirestoreValue
379
+ .values[annotation.getField ('type' )! .getField ('index' )! .toIntValue ()! ];
380
+ }
381
+
305
382
@override
306
383
Iterable <Object > generateForAll (void globalData) sync * {
307
384
yield '''
0 commit comments