Skip to content

Commit e6cab27

Browse files
committed
fix(StaticMetadataExtractor): Map members annotations to all annotations
Closes dart-archive#904
1 parent d040b60 commit e6cab27

7 files changed

+65
-59
lines changed

lib/tools/html_extractor.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class HtmlExpressionExtractor {
7070
visitNodes(List<Node> nodes, NodeVisitor visitor) {
7171
for (Node node in nodes) {
7272
visitor(node);
73-
if (node.nodes.length > 0) {
73+
if (node.nodes.isNotEmpty) {
7474
visitNodes(node.nodes, visitor);
7575
}
7676
}

lib/tools/io.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ library angular.io;
33
typedef FsVisitor(String file);
44

55
/**
6-
* A simple mockabe wrapper around dart:io that can be used without introducing
6+
* A simple mockable wrapper around dart:io that can be used without introducing
77
* direct dependencies on dart:io.
88
*/
99
abstract class IoService {

lib/tools/selector.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ class _SelectorPart {
2222
final String attrName;
2323
final String attrValue;
2424

25-
const _SelectorPart.fromElement(String this.element)
25+
const _SelectorPart.fromElement(this.element)
2626
: className = null, attrName = null, attrValue = null;
2727

28-
const _SelectorPart.fromClass(String this.className)
28+
const _SelectorPart.fromClass(this.className)
2929
: element = null, attrName = null, attrValue = null;
3030

3131

32-
const _SelectorPart.fromAttribute(String this.attrName, String this.attrValue)
32+
const _SelectorPart.fromAttribute(this.attrName, this.attrValue)
3333
: element = null, className = null;
3434

35-
toString() =>
35+
String toString() =>
3636
element == null
3737
? (className == null
3838
? (attrValue == '' ? '[$attrName]' : '[$attrName=$attrValue]')

lib/tools/source_metadata_extractor.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class SourceMetadataExtractor {
9898
dirInfo.expressionAttrs.forEach((String attr) {
9999
if (attr == '.') {
100100
var matches = _ATTR_SELECTOR_REGEXP.allMatches(dirInfo.selector);
101-
if (matches.length > 0) {
101+
if (matches.isNotEmpty) {
102102
reprocessedAttrs.add(matches.last.group(1));
103103
}
104104
} else {

lib/tools/transformer/metadata_extractor.dart

+44-48
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,7 @@ class AnnotationExtractor {
270270
return false;
271271
}
272272
// Skip all non-Ng* Attributes.
273-
if (!cls.name.startsWith('Ng')) {
274-
return false;
275-
}
276-
return true;
273+
return cls.name.startsWith('Ng');
277274
}).toList();
278275

279276

@@ -335,53 +332,52 @@ class AnnotationExtractor {
335332
return;
336333
}
337334

338-
// Default to using the first acceptable annotation- not sure if
339-
// more than one should ever occur.
340-
var sourceAnnotation = acceptableAnnotations.first;
341-
342-
// Clone the annotation so we don't modify the one in the persistent AST.
343-
var index = type.annotations.indexOf(sourceAnnotation);
344-
var annotation = new AstCloner().visitAnnotation(sourceAnnotation);
345-
ResolutionCopier.copyResolutionData(sourceAnnotation, annotation);
346-
type.annotations[index] = annotation;
347-
348-
var mapArg = annotation.arguments.arguments.firstWhere((arg) =>
349-
(arg is NamedExpression) && (arg.name.label.name == 'map'),
350-
orElse: () => null);
351-
352-
// If we don't have a 'map' parameter yet, add one.
353-
if (mapArg == null) {
354-
var map = new MapLiteral(null, null, null, [], null);
355-
var label = new Label(new SimpleIdentifier(
356-
new _GeneratedToken(TokenType.STRING, 'map')),
357-
new _GeneratedToken(TokenType.COLON, ':'));
358-
mapArg = new NamedExpression(label, map);
359-
annotation.arguments.arguments.add(mapArg);
360-
}
335+
// Merge attribute annotations in all of the class annotations
336+
acceptableAnnotations.forEach((srcAnnotation) {
337+
// Clone the annotation so we don't modify the one in the persistent AST.
338+
var index = type.annotations.indexOf(srcAnnotation);
339+
var annotation = new AstCloner().visitAnnotation(srcAnnotation);
340+
ResolutionCopier.copyResolutionData(srcAnnotation, annotation);
341+
type.annotations[index] = annotation;
342+
343+
var mapArg = annotation.arguments.arguments.firstWhere(
344+
(arg) => (arg is NamedExpression) && (arg.name.label.name == 'map'),
345+
orElse: () => null);
346+
347+
// If we don't have a 'map' parameter yet, add one.
348+
if (mapArg == null) {
349+
var map = new MapLiteral(null, null, null, [], null);
350+
var label = new Label(new SimpleIdentifier(
351+
new _GeneratedToken(TokenType.STRING, 'map')),
352+
new _GeneratedToken(TokenType.COLON, ':'));
353+
mapArg = new NamedExpression(label, map);
354+
annotation.arguments.arguments.add(mapArg);
355+
}
361356

362-
var map = mapArg.expression;
363-
if (map is! MapLiteral) {
364-
warn('Expected \'map\' argument of $annotation to be a map literal',
365-
type.type);
366-
return;
367-
}
368-
memberAnnotations.forEach((memberName, annotation) {
369-
var key = annotation.arguments.arguments.first;
370-
// If the key already exists then it means we have two annotations for
371-
// same member.
372-
if (map.entries.any((entry) => entry.key.toString() == key.toString())) {
373-
warn('Directive $annotation already contains an entry for $key',
374-
type.type);
357+
var map = mapArg.expression;
358+
if (map is! MapLiteral) {
359+
warn('Expected \'map\' argument of $annotation to be a map literal',
360+
type.type);
375361
return;
376362
}
363+
memberAnnotations.forEach((memberName, annotation) {
364+
var key = annotation.arguments.arguments.first;
365+
// If the key already exists then it means we have two annotations for
366+
// same member.
367+
if (map.entries.any((entry) => entry.key.toString() == key.toString())) {
368+
warn('Directive $annotation already contains an entry for $key',
369+
type.type);
370+
return;
371+
}
377372

378-
var typeName = annotation.element.enclosingElement.name;
379-
var value = '${_annotationToMapping[typeName]}$memberName';
380-
var entry = new MapLiteralEntry(
381-
key,
382-
new _GeneratedToken(TokenType.COLON, ':'),
383-
new SimpleStringLiteral(stringToken(value), value));
384-
map.entries.add(entry);
373+
var typeName = annotation.element.enclosingElement.name;
374+
var value = '${_annotationToMapping[typeName]}$memberName';
375+
var entry = new MapLiteralEntry(
376+
key,
377+
new _GeneratedToken(TokenType.COLON, ':'),
378+
new SimpleStringLiteral(stringToken(value), value));
379+
map.entries.add(entry);
380+
});
385381
});
386382
}
387383

@@ -430,5 +426,5 @@ class _AnnotationVisitor extends GeneralizingAstVisitor {
430426
}
431427

432428
bool get hasAnnotations =>
433-
!classAnnotations.isEmpty || !memberAnnotations.isEmpty;
429+
classAnnotations.isNotEmpty || memberAnnotations.isNotEmpty;
434430
}

test/tools/source_metadata_extractor_spec.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ void main() {
116116
}
117117

118118
flattenList(list, map) => list.map(map).fold([], (prev, exprs) =>
119-
new List.from(prev)..addAll(exprs));
119+
new List.from(prev)..addAll(exprs));
120120

121121
List<DirectiveInfo> extractDirectiveInfo(List<DirectiveMetadata> metadata) {
122122
var sourceCrawler = new MockSourceCrawler();

test/tools/transformer/metadata_generator_spec.dart

+13-3
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,12 @@ main() {
115115
'a|web/main.dart': '''
116116
import 'package:angular/angular.dart';
117117
118-
@NgDirective(map: {'another-expression': '=>anotherExpression'})
118+
@NgDirective(
119+
selector: 'first',
120+
map: {'first-expression': '=>anotherExpression'})
121+
@NgDirective(
122+
selector: 'second',
123+
map: {'second-expression': '=>anotherExpression'})
119124
class Engine {
120125
set anotherExpression(Function) {}
121126
@@ -132,8 +137,13 @@ main() {
132137
],
133138
classes: {
134139
'import_0.Engine': [
135-
'const import_1.NgDirective(map: const {'
136-
'\'another-expression\': \'=>anotherExpression\', '
140+
'const import_1.NgDirective(selector: \'first\', '
141+
'map: const {'
142+
'\'first-expression\': \'=>anotherExpression\', '
143+
'\'two-way-stuff\': \'<=>twoWayStuff\'})',
144+
'const import_1.NgDirective(selector: \'second\', '
145+
'map: const {'
146+
'\'second-expression\': \'=>anotherExpression\', '
137147
'\'two-way-stuff\': \'<=>twoWayStuff\'})',
138148
]
139149
});

0 commit comments

Comments
 (0)