1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15- import 'dart:mirrors' as mirrors;
16-
1715import 'package:analyzer/dart/ast/ast.dart' ;
1816import 'package:build/build.dart' show log;
1917import 'package:collection/collection.dart' show IterableExtension;
20- import 'package:over_react/src/builder/vendor/transformer_utils/transformer_utils.dart' ;
2118
22- import 'ast_util .dart' ;
19+ import 'package:over_react/src/component_declaration/annotations .dart' as a ;
2320
24- /// Uses reflection to instantiate and return the first annotation on [member] of type
25- /// [T] , or null if no matching annotations are found.
26- ///
27- /// > See [instantiateAnnotation] for more information.
28- T ? instantiateAnnotationTyped <T >(AnnotatedNode member,
29- {dynamic Function (Expression argument)? onUnsupportedArgument}) {
30- return instantiateAnnotation (member, T , onUnsupportedArgument: onUnsupportedArgument) as T ? ;
31- }
21+ import '../vendor/transformer_utils/src/analyzer_helpers.dart' ;
3222
33- /// Returns the first annotation AST node on [member ] of type [annotationType ] ,
23+ /// Returns the first annotation AST node on [node ] of type [T ] ,
3424/// or null if no matching annotations are found.
35- Annotation ? _getMatchingAnnotation (AnnotatedNode member, Type annotationType) {
36- // Be sure to use `originalDeclaration` so that generic parameters work.
37- final classMirror = mirrors.reflectClass (annotationType).originalDeclaration;
38- final className = mirrors.MirrorSystem .getName (classMirror.simpleName);
39- return member.getAnnotationWithName (className);
40- }
25+ Annotation ? _getMatchingAnnotationFromGeneric <T extends Object >(AnnotatedNode node) =>
26+ _getMatchingAnnotation (_AnnotationClass .fromGeneric <T >(), node);
27+
28+ /// Returns the first annotation AST node on [node] of type [annotationClass] ,
29+ /// or null if no matching annotations are found.
30+ Annotation ? _getMatchingAnnotation (_AnnotationClass annotationClass, AnnotatedNode node) =>
31+ node.metadata.firstWhereOrNull ((m) => m.name.name == annotationClass.className);
4132
4233/// Utility class that allows partial instantiation of annotations, to support reading
4334/// annotation data in a context without a resolved AST. See [isIncomplete] for more info.
44- ///
45- /// Based off of [NodeWithMeta] .
46- class InstantiatedMeta <TMeta > {
35+ class InstantiatedMeta <TMeta extends Object > {
4736 /// The node of the [TMeta] annotation, if it exists.
4837 final Annotation metaNode;
4938
@@ -62,8 +51,8 @@ class InstantiatedMeta<TMeta> {
6251 /// The original node will be available via [node] .
6352 ///
6453 /// The instantiated annotation will be available via [value] .
65- static InstantiatedMeta <T >? fromNode <T >(AnnotatedNode node) {
66- final metaNode = _getMatchingAnnotation (node, T );
54+ static InstantiatedMeta <T >? fromNode <T extends Object >(AnnotatedNode node) {
55+ final metaNode = _getMatchingAnnotationFromGeneric < T > (node);
6756 if (metaNode == null ) return null ;
6857
6958 final unsupportedArguments = < Expression > [];
@@ -99,7 +88,7 @@ class InstantiatedMeta<TMeta> {
9988/// Utility that allows partial instantiation of a `Component` /`Component2` annotation.
10089///
10190/// See superclass for more information.
102- class InstantiatedComponentMeta <TMeta > extends InstantiatedMeta <TMeta > {
91+ class InstantiatedComponentMeta <TMeta extends Object > extends InstantiatedMeta <TMeta > {
10392 static const String _subtypeOfParamName = 'subtypeOf' ;
10493
10594 final Identifier ? subtypeOfValue;
@@ -108,7 +97,7 @@ class InstantiatedComponentMeta<TMeta> extends InstantiatedMeta<TMeta> {
10897 Annotation metaNode, TMeta meta, List <Expression > unsupportedArguments, this .subtypeOfValue)
10998 : super ._(metaNode, meta, unsupportedArguments);
11099
111- static InstantiatedComponentMeta <T >? fromNode <T >(AnnotatedNode node) {
100+ static InstantiatedComponentMeta <T >? fromNode <T extends Object >(AnnotatedNode node) {
112101 try {
113102 final instantiated = InstantiatedMeta .fromNode <T >(node);
114103 if (instantiated == null ) return null ;
@@ -140,3 +129,106 @@ class InstantiatedComponentMeta<TMeta> extends InstantiatedMeta<TMeta> {
140129 }
141130 }
142131}
132+
133+ T ? instantiateAnnotationTyped <T extends Object >(
134+ AnnotatedNode node, {
135+ dynamic Function (Expression argument)? onUnsupportedArgument,
136+ }) {
137+ final annotationClass = _AnnotationClass .fromGeneric <T >();
138+
139+ final annotation = _getMatchingAnnotation (annotationClass, node);
140+ if (annotation == null ) return null ;
141+
142+ final args = parseAnnotationArgs (annotation, onUnsupportedArgument: onUnsupportedArgument);
143+ S namedArg <S >(String name) => args.named[name] as S ;
144+
145+ switch (annotationClass) {
146+ case _AnnotationClass .props:
147+ return a.Props (
148+ keyNamespace: namedArg ('keyNamespace' ),
149+ disableRequiredPropValidation: namedArg ('disableRequiredPropValidation' ),
150+ disableValidationForClassDefaultProps:
151+ namedArg ('disableValidationForClassDefaultProps' ) ?? true ,
152+ ) as T ;
153+ case _AnnotationClass .abstractProps:
154+ return a.AbstractProps (
155+ keyNamespace: namedArg ('keyNamespace' ),
156+ ) as T ;
157+ case _AnnotationClass .propsMixin:
158+ // ignore: deprecated_member_use_from_same_package
159+ return a.PropsMixin (
160+ keyNamespace: namedArg ('keyNamespace' ),
161+ ) as T ;
162+ case _AnnotationClass .state:
163+ return a.State (
164+ keyNamespace: namedArg ('keyNamespace' ),
165+ ) as T ;
166+ case _AnnotationClass .abstractState:
167+ return a.AbstractState (
168+ keyNamespace: namedArg ('keyNamespace' ),
169+ ) as T ;
170+ case _AnnotationClass .stateMixin:
171+ // ignore: deprecated_member_use_from_same_package
172+ return a.StateMixin (
173+ keyNamespace: namedArg ('keyNamespace' ),
174+ ) as T ;
175+ case _AnnotationClass .component2:
176+ return a.Component2 (
177+ isWrapper: namedArg ('isWrapper' ) ?? false ,
178+ subtypeOf: namedArg ('subtypeOf' ),
179+ isErrorBoundary: namedArg ('isErrorBoundary' ) ?? false ,
180+ ) as T ;
181+ case _AnnotationClass .component:
182+ // ignore: deprecated_member_use_from_same_package
183+ return a.Component (
184+ isWrapper: namedArg ('isWrapper' ) ?? false ,
185+ subtypeOf: namedArg ('subtypeOf' ),
186+ ) as T ;
187+ case _AnnotationClass .accessor:
188+ return a.Accessor (
189+ key: namedArg ('key' ),
190+ keyNamespace: namedArg ('keyNamespace' ),
191+ isRequired: namedArg ('isRequired' ) ?? false ,
192+ isNullable: namedArg ('isNullable' ) ?? false ,
193+ requiredErrorMessage: namedArg ('requiredErrorMessage' ),
194+ doNotGenerate: namedArg ('doNotGenerate' ) ?? false ,
195+ ) as T ;
196+ }
197+ }
198+
199+ enum _AnnotationClass {
200+ props ('Props' ),
201+ abstractProps ('AbstractProps' ),
202+ propsMixin ('PropsMixin' ),
203+ state ('State' ),
204+ abstractState ('AbstractState' ),
205+ stateMixin ('StateMixin' ),
206+ component2 ('Component2' ),
207+ component ('Component' ),
208+ accessor ('Accessor' );
209+
210+ final String className;
211+
212+ const _AnnotationClass (this .className);
213+
214+ static _AnnotationClass fromGeneric <T >() {
215+ if (_isSubtypeOf< T , a.Props > ()) return _AnnotationClass .props;
216+ if (_isSubtypeOf< T , a.AbstractProps > ()) return _AnnotationClass .abstractProps;
217+ // ignore: deprecated_member_use_from_same_package
218+ if (_isSubtypeOf< T , a.PropsMixin > ()) return _AnnotationClass .propsMixin;
219+ if (_isSubtypeOf< T , a.State > ()) return _AnnotationClass .state;
220+ if (_isSubtypeOf< T , a.AbstractState > ()) return _AnnotationClass .abstractState;
221+ // ignore: deprecated_member_use_from_same_package
222+ if (_isSubtypeOf< T , a.StateMixin > ()) return _AnnotationClass .stateMixin;
223+ if (_isSubtypeOf< T , a.Component2 > ()) return _AnnotationClass .component2;
224+ // ignore: deprecated_member_use_from_same_package
225+ if (_isSubtypeOf< T , a.Component > ()) return _AnnotationClass .component;
226+ if (_isSubtypeOf< T , a.Accessor > ()) return _AnnotationClass .accessor;
227+
228+ throw ArgumentError ('Unsupported generic: $T . Must correspond to a type in this enum.' );
229+ }
230+ }
231+
232+ bool _isSubtypeOf <T , S >() => _SubtypeOfHelper <T >() is _SubtypeOfHelper <S >;
233+
234+ class _SubtypeOfHelper <T > {}
0 commit comments