11library angular2.transform.common.directive_metadata_reader;
22
33import 'package:analyzer/analyzer.dart' ;
4+ import 'package:analyzer/src/generated/element.dart' ;
45import 'package:angular2/src/render/api.dart' ;
5- import 'logging.dart' ;
6- import 'parser.dart' ;
76
8- /// Reads [DirectiveMetadata] from the `attributes` of `t` .
9- DirectiveMetadata readDirectiveMetadata (RegisteredType t) {
7+ /// Reads [DirectiveMetadata] from the `node` . `node` is expected to be an
8+ /// instance of [Annotation] , [NodeList<Annotation>] , ListLiteral, or
9+ /// [InstanceCreationExpression] .
10+ DirectiveMetadata readDirectiveMetadata (dynamic node) {
11+ assert (node is Annotation ||
12+ node is NodeList ||
13+ node is InstanceCreationExpression ||
14+ node is ListLiteral );
1015 var visitor = new _DirectiveMetadataVisitor ();
11- t.annotations.accept (visitor);
12- if (visitor.meta != null ) {
13- visitor.meta.id = '${t .typeName }' ;
14- }
16+ node.accept (visitor);
1517 return visitor.meta;
1618}
1719
18- num _getDirectiveType (String annotationName) {
20+ num _getDirectiveType (String annotationName, Element element) {
21+ var byNameMatch = - 1 ;
1922 // TODO(kegluneq): Detect subtypes & implementations of `Directive`s.
2023 switch (annotationName) {
2124 case 'Directive' :
22- return DirectiveMetadata .DIRECTIVE_TYPE ;
25+ byNameMatch = DirectiveMetadata .DIRECTIVE_TYPE ;
26+ break ;
2327 case 'Component' :
24- return DirectiveMetadata .COMPONENT_TYPE ;
28+ byNameMatch = DirectiveMetadata .COMPONENT_TYPE ;
29+ break ;
2530 default :
2631 return - 1 ;
2732 }
33+ if (element != null ) {
34+ var byResolvedAst = - 1 ;
35+ var libName = element.library.name;
36+ // If we have resolved, ensure the library is correct.
37+ if (libName == 'angular2.src.core.annotations.annotations' ||
38+ libName == 'angular2.src.core.annotations_impl.annotations' ) {
39+ byResolvedAst = byNameMatch;
40+ }
41+ // TODO(kegluneq): @keertip, can we expose this as a warning?
42+ assert (byNameMatch == byResolvedAst);
43+ }
44+ return byNameMatch;
2845}
2946
3047/// Visitor responsible for processing the `annotations` property of a
@@ -33,22 +50,45 @@ class _DirectiveMetadataVisitor extends Object
3350 with RecursiveAstVisitor <Object > {
3451 DirectiveMetadata meta;
3552
53+ void _createEmptyMetadata (num type) {
54+ assert (type >= 0 );
55+ meta = new DirectiveMetadata (
56+ type: type,
57+ compileChildren: true ,
58+ properties: {},
59+ hostListeners: {},
60+ hostProperties: {},
61+ hostAttributes: {},
62+ readAttributes: []);
63+ }
64+
65+ @override
66+ Object visitAnnotation (Annotation node) {
67+ var directiveType = _getDirectiveType ('${node .name }' , node.element);
68+ if (directiveType >= 0 ) {
69+ if (meta != null ) {
70+ throw new FormatException ('Only one Directive is allowed per class. '
71+ 'Found "$node " but already processed "$meta ".' ,
72+ '$node ' /* source */ );
73+ }
74+ _createEmptyMetadata (directiveType);
75+ super .visitAnnotation (node);
76+ }
77+ // Annotation we do not recognize - no need to visit.
78+ return null ;
79+ }
80+
3681 @override
3782 Object visitInstanceCreationExpression (InstanceCreationExpression node) {
38- var directiveType = _getDirectiveType ('${node .constructorName .type .name }' );
83+ var directiveType = _getDirectiveType (
84+ '${node .constructorName .type .name }' , node.staticElement);
3985 if (directiveType >= 0 ) {
4086 if (meta != null ) {
41- logger.error ('Only one Directive is allowed per class. '
42- 'Found "$node " but already processed "$meta ".' );
87+ throw new FormatException ('Only one Directive is allowed per class. '
88+ 'Found "$node " but already processed "$meta ".' ,
89+ '$node ' /* source */ );
4390 }
44- meta = new DirectiveMetadata (
45- type: directiveType,
46- compileChildren: true ,
47- properties: {},
48- hostListeners: {},
49- hostProperties: {},
50- hostAttributes: {},
51- readAttributes: []);
91+ _createEmptyMetadata (directiveType);
5292 super .visitInstanceCreationExpression (node);
5393 }
5494 // Annotation we do not recognize - no need to visit.
@@ -59,10 +99,9 @@ class _DirectiveMetadataVisitor extends Object
5999 Object visitNamedExpression (NamedExpression node) {
60100 // TODO(kegluneq): Remove this limitation.
61101 if (node.name is ! Label || node.name.label is ! SimpleIdentifier ) {
62- logger.error (
63- 'Angular 2 currently only supports simple identifiers in directives.'
64- ' Source: ${node }' );
65- return null ;
102+ throw new FormatException (
103+ 'Angular 2 currently only supports simple identifiers in directives.' ,
104+ '$node ' /* source */ );
66105 }
67106 var keyString = '${node .name .label }' ;
68107 // TODO(kegluneq): Populate the other values in [DirectiveMetadata] once
@@ -93,9 +132,9 @@ class _DirectiveMetadataVisitor extends Object
93132 String _expressionToString (Expression node, String nodeDescription) {
94133 // TODO(kegluneq): Accept more options.
95134 if (node is ! SimpleStringLiteral ) {
96- logger. error ( 'Angular 2 currently only supports string literals '
97- 'in $ nodeDescription . Source: ${ node }' );
98- return null ;
135+ throw new FormatException (
136+ 'Angular 2 currently only supports string literals '
137+ 'in $ nodeDescription .' , '$ node ' /* source */ ) ;
99138 }
100139 return stringLiteralToString (node);
101140 }
@@ -104,23 +143,30 @@ class _DirectiveMetadataVisitor extends Object
104143 meta.selector = _expressionToString (selectorValue, 'Directive#selector' );
105144 }
106145
146+ void _checkMeta () {
147+ if (meta == null ) {
148+ throw new ArgumentError (
149+ 'Incorrect value passed to readDirectiveMetadata. '
150+ 'Expected types are Annotation and InstanceCreationExpression' );
151+ }
152+ }
153+
107154 void _populateCompileChildren (Expression compileChildrenValue) {
155+ _checkMeta ();
108156 if (compileChildrenValue is ! BooleanLiteral ) {
109- logger. error (
157+ throw new FormatException (
110158 'Angular 2 currently only supports boolean literal values for '
111- 'Directive#compileChildren.'
112- ' Source: ${compileChildrenValue }' );
113- return ;
159+ 'Directive#compileChildren.' , '$compileChildrenValue ' /* source */ );
114160 }
115161 meta.compileChildren = (compileChildrenValue as BooleanLiteral ).value;
116162 }
117163
118164 void _populateProperties (Expression propertiesValue) {
165+ _checkMeta ();
119166 if (propertiesValue is ! MapLiteral ) {
120- logger.error ('Angular 2 currently only supports map literal values for '
121- 'Directive#properties.'
122- ' Source: ${propertiesValue }' );
123- return ;
167+ throw new FormatException (
168+ 'Angular 2 currently only supports map literal values for '
169+ 'Directive#properties.' , '$propertiesValue ' /* source */ );
124170 }
125171 for (MapLiteralEntry entry in (propertiesValue as MapLiteral ).entries) {
126172 var sKey = _expressionToString (entry.key, 'Directive#properties keys' );
@@ -130,11 +176,11 @@ class _DirectiveMetadataVisitor extends Object
130176 }
131177
132178 void _populateHostListeners (Expression hostListenersValue) {
179+ _checkMeta ();
133180 if (hostListenersValue is ! MapLiteral ) {
134- logger.error ('Angular 2 currently only supports map literal values for '
135- 'Directive#hostListeners.'
136- ' Source: ${hostListenersValue }' );
137- return ;
181+ throw new FormatException (
182+ 'Angular 2 currently only supports map literal values for '
183+ 'Directive#hostListeners.' , '$hostListenersValue ' /* source */ );
138184 }
139185 for (MapLiteralEntry entry in (hostListenersValue as MapLiteral ).entries) {
140186 var sKey = _expressionToString (entry.key, 'Directive#hostListeners keys' );
@@ -145,11 +191,11 @@ class _DirectiveMetadataVisitor extends Object
145191 }
146192
147193 void _populateHostProperties (Expression hostPropertyValue) {
194+ _checkMeta ();
148195 if (hostPropertyValue is ! MapLiteral ) {
149- logger.error ('Angular 2 currently only supports map literal values for '
150- 'Directive#hostProperties.'
151- ' Source: ${hostPropertyValue }' );
152- return ;
196+ throw new FormatException (
197+ 'Angular 2 currently only supports map literal values for '
198+ 'Directive#hostProperties.' , '$hostPropertyValue ' /* source */ );
153199 }
154200 for (MapLiteralEntry entry in (hostPropertyValue as MapLiteral ).entries) {
155201 var sKey =
@@ -161,11 +207,11 @@ class _DirectiveMetadataVisitor extends Object
161207 }
162208
163209 void _populateHostAttributes (Expression hostAttributeValue) {
210+ _checkMeta ();
164211 if (hostAttributeValue is ! MapLiteral ) {
165- logger.error ('Angular 2 currently only supports map literal values for '
166- 'Directive#hostAttributes.'
167- ' Source: ${hostAttributeValue }' );
168- return ;
212+ throw new FormatException (
213+ 'Angular 2 currently only supports map literal values for '
214+ 'Directive#hostAttributes.' , '$hostAttributeValue ' /* source */ );
169215 }
170216 for (MapLiteralEntry entry in (hostAttributeValue as MapLiteral ).entries) {
171217 var sKey =
0 commit comments