@@ -6,14 +6,20 @@ import 'package:angular2/src/core/render/api.dart';
66import 'package:angular2/src/core/change_detection/change_detection.dart' ;
77
88/// Reads [RenderDirectiveMetadata] from the `node` . `node` is expected to be an
9- /// instance of [Annotation] , [NodeList<Annotation>] , ListLiteral, or
10- /// [InstanceCreationExpression] .
11- RenderDirectiveMetadata readDirectiveMetadata (dynamic node) {
12- assert (node is Annotation ||
13- node is NodeList ||
14- node is InstanceCreationExpression ||
15- node is ListLiteral );
16- var visitor = new _DirectiveMetadataVisitor ();
9+ /// instance of [ClassDeclaration] (a class which may have a [Directive] or
10+ /// [Component] annotation) or an [InstanceCreationExpression] (an instantiation
11+ /// of [ReflectionInfo] ).
12+ RenderDirectiveMetadata readDirectiveMetadata (AstNode node) {
13+ var visitor;
14+ if (node is ClassDeclaration ) {
15+ visitor = new _DeclarationVisitor ();
16+ } else if (node is InstanceCreationExpression ) {
17+ visitor = new _ReflectionInfoVisitor ();
18+ } else {
19+ throw new ArgumentError ('Incorrect value passed to readDirectiveMetadata. '
20+ 'Expected types are ClassDeclaration and InstanceCreationExpression '
21+ 'Provided type was ${node .runtimeType }' );
22+ }
1723 node.accept (visitor);
1824 return visitor.meta;
1925}
@@ -45,8 +51,79 @@ num _getDirectiveType(String annotationName, Element element) {
4551 return byNameMatch;
4652}
4753
48- /// Visitor responsible for processing the `annotations` property of a
49- /// [RegisterType] object and pulling out [RenderDirectiveMetadata] .
54+ class _ReflectionInfoVisitor extends _DirectiveMetadataVisitor {
55+ // TODO(kegluneq): Create a more robust check that this is a real
56+ // `ReflectionInfo` instantiation.
57+ static bool _isReflectionInfo (InstanceCreationExpression node) {
58+ var name = node.constructorName.type.name;
59+ name = name is PrefixedIdentifier ? name.identifier : name;
60+ return '$name ' == 'ReflectionInfo' ;
61+ }
62+
63+ @override
64+ Object visitInstanceCreationExpression (InstanceCreationExpression node) {
65+ if (_isReflectionInfo (node)) {
66+ // NOTE(kegluneq): This is very tightly coupled with the `Reflector`
67+ // implementation. Clean this up with a better intermediate representation
68+ // for .ng_deps.dart files.
69+ var reflectionInfoArgs = node.argumentList.arguments;
70+ if (reflectionInfoArgs.length > 0 ) {
71+ // Process annotations to determine information specified via
72+ // `Component` and `Directive` parameters.
73+ reflectionInfoArgs[0 ].accept (this );
74+ if (_hasMeta && reflectionInfoArgs.length > 3 ) {
75+ // Process interfaces to determine which lifecycle events we need to
76+ // react to for this `Directive`.
77+ _processInterfaces (reflectionInfoArgs[3 ]);
78+ }
79+ }
80+ return null ;
81+ }
82+ var directiveType = _getDirectiveType (
83+ '${node .constructorName .type .name }' , node.staticElement);
84+ if (directiveType >= 0 ) {
85+ if (_hasMeta) {
86+ throw new FormatException (
87+ 'Only one Directive is allowed per class. '
88+ 'Found "$node " but already processed "$meta ".' ,
89+ '$node ' /* source */ );
90+ }
91+ _initializeMetadata (directiveType);
92+ super .visitInstanceCreationExpression (node);
93+ }
94+ // Annotation we do not recognize - no need to visit.
95+ return null ;
96+ }
97+
98+ void _processInterfaces (Expression lifecycleValue) {
99+ _checkMeta ();
100+ if (lifecycleValue is ! ListLiteral ) {
101+ throw new FormatException (
102+ 'Angular 2 expects a List but could not understand the value for interfaces. '
103+ '$lifecycleValue ' );
104+ }
105+ ListLiteral l = lifecycleValue;
106+ _populateLifecycle (l.elements.map ((s) => s.toSource ().split ('.' ).last));
107+ }
108+ }
109+
110+ class _DeclarationVisitor extends _DirectiveMetadataVisitor {
111+ @override
112+ Object visitClassDeclaration (ClassDeclaration node) {
113+ node.metadata.accept (this );
114+ if (this ._hasMeta) {
115+ if (node.implementsClause != null &&
116+ node.implementsClause.interfaces != null ) {
117+ _populateLifecycle (node.implementsClause.interfaces
118+ .map ((s) => s.toSource ().split ('.' ).last));
119+ }
120+ }
121+ return null ;
122+ }
123+ }
124+
125+ /// Visitor responsible for processing [Directive] code into a
126+ /// [RenderDirectiveMetadata] object.
50127class _DirectiveMetadataVisitor extends Object
51128 with RecursiveAstVisitor <Object > {
52129 bool get _hasMeta => _type != null ;
@@ -130,24 +207,6 @@ class _DirectiveMetadataVisitor extends Object
130207 return null ;
131208 }
132209
133- @override
134- Object visitInstanceCreationExpression (InstanceCreationExpression node) {
135- var directiveType = _getDirectiveType (
136- '${node .constructorName .type .name }' , node.staticElement);
137- if (directiveType >= 0 ) {
138- if (_hasMeta) {
139- throw new FormatException (
140- 'Only one Directive is allowed per class. '
141- 'Found "$node " but already processed "$meta ".' ,
142- '$node ' /* source */ );
143- }
144- _initializeMetadata (directiveType);
145- super .visitInstanceCreationExpression (node);
146- }
147- // Annotation we do not recognize - no need to visit.
148- return null ;
149- }
150-
151210 @override
152211 Object visitNamedExpression (NamedExpression node) {
153212 // TODO(kegluneq): Remove this limitation.
@@ -170,10 +229,6 @@ class _DirectiveMetadataVisitor extends Object
170229 case 'host' :
171230 _populateHost (node.expression);
172231 break ;
173- // TODO(vicb) should come from the interfaces on the class
174- case 'lifecycle' :
175- _populateLifecycle (node.expression);
176- break ;
177232 case 'exportAs' :
178233 _populateExportAs (node.expression);
179234 break ;
@@ -207,8 +262,7 @@ class _DirectiveMetadataVisitor extends Object
207262 if (! _hasMeta) {
208263 throw new ArgumentError (
209264 'Incorrect value passed to readDirectiveMetadata. '
210- 'Expected types are Annotation, InstanceCreationExpression, '
211- 'NodeList or ListLiteral' );
265+ 'Expected types are ClassDeclaration and InstanceCreationExpression' );
212266 }
213267 }
214268
@@ -271,23 +325,19 @@ class _DirectiveMetadataVisitor extends Object
271325 _exportAs = _expressionToString (exportAsValue, 'Directive#exportAs' );
272326 }
273327
274- void _populateLifecycle (Expression lifecycleValue ) {
328+ void _populateLifecycle (Iterable < String > lifecycleInterfaceNames ) {
275329 _checkMeta ();
276- if (lifecycleValue is ! ListLiteral ) {
277- throw new FormatException (
278- 'Angular 2 expects a List but could not understand the value for lifecycle. '
279- '$lifecycleValue ' );
280- }
281- ListLiteral l = lifecycleValue;
282- var lifecycleEvents = l.elements.map ((s) => s.toSource ().split ('.' ).last);
283- _callOnDestroy = lifecycleEvents.contains ("OnDestroy" );
284- _callOnChange = lifecycleEvents.contains ("OnChanges" );
285- _callDoCheck = lifecycleEvents.contains ("DoCheck" );
286- _callOnInit = lifecycleEvents.contains ("OnInit" );
287- _callAfterContentInit = lifecycleEvents.contains ("AfterContentInit" );
288- _callAfterContentChecked = lifecycleEvents.contains ("AfterContentChecked" );
289- _callAfterViewInit = lifecycleEvents.contains ("AfterViewInit" );
290- _callAfterViewChecked = lifecycleEvents.contains ("AfterViewChecked" );
330+ _callOnDestroy = lifecycleInterfaceNames.contains ("OnDestroy" );
331+ _callOnChange = lifecycleInterfaceNames.contains ("OnChanges" );
332+ _callDoCheck = lifecycleInterfaceNames.contains ("DoCheck" );
333+ _callOnInit = lifecycleInterfaceNames.contains ("OnInit" );
334+ _callAfterContentInit =
335+ lifecycleInterfaceNames.contains ("AfterContentInit" );
336+ _callAfterContentChecked =
337+ lifecycleInterfaceNames.contains ("AfterContentChecked" );
338+ _callAfterViewInit = lifecycleInterfaceNames.contains ("AfterViewInit" );
339+ _callAfterViewChecked =
340+ lifecycleInterfaceNames.contains ("AfterViewChecked" );
291341 }
292342
293343 void _populateEvents (Expression eventsValue) {
@@ -301,5 +351,6 @@ class _DirectiveMetadataVisitor extends Object
301351 }
302352}
303353
304- final Map <String , ChangeDetectionStrategy > changeDetectionStrategies
305- = new Map .fromIterable (ChangeDetectionStrategy .values, key: (v) => v.toString ());
354+ final Map <String , ChangeDetectionStrategy > changeDetectionStrategies =
355+ new Map .fromIterable (ChangeDetectionStrategy .values,
356+ key: (v) => v.toString ());
0 commit comments