Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit 0148897

Browse files
mheveryjbdeboer
authored andcommitted
fix(directive): Support multiple directives with same selector.
1 parent 148b79a commit 0148897

14 files changed

+196
-233
lines changed

lib/core/formatter.dart

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
library angular.core_internal.formatter_map;
22

3+
import 'dart:collection';
34
import 'package:di/di.dart';
45
import 'package:angular/core/annotation_src.dart';
56
import 'package:angular/core/registry.dart';
@@ -8,16 +9,30 @@ import 'package:angular/core/registry.dart';
89
* Registry of formatters at runtime.
910
*/
1011
@Injectable()
11-
class FormatterMap extends AnnotationMap<Formatter> {
12-
Injector _injector;
13-
FormatterMap(Injector injector, MetadataExtractor extractMetadata)
14-
: this._injector = injector,
15-
super(injector, extractMetadata);
12+
class FormatterMap {
13+
final Map<String, Type> _map = new HashMap<String, Type>();
14+
final Injector _injector;
1615

17-
call(String name) {
18-
var formatter = new Formatter(name: name);
19-
var formatterType = this[formatter];
20-
return _injector.get(formatterType);
16+
FormatterMap(this._injector, MetadataExtractor extractMetadata) {
17+
_injector.types.forEach((type) {
18+
extractMetadata(type)
19+
.where((annotation) => annotation is Formatter)
20+
.forEach((Formatter formatter) {
21+
_map[formatter.name] = type;
22+
});
23+
});
24+
}
25+
26+
call(String name) => _injector.get(this[name]);
27+
28+
Type operator[](String name) {
29+
Type formatterType = _map[name];
30+
if (formatterType == null) throw "No formatter '$name' found!";
31+
return formatterType;
32+
}
33+
34+
void forEach(fn(K, Type)) {
35+
_map.forEach(fn);
2136
}
2237
}
2338

lib/core/registry.dart

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,5 @@
11
library angular.core.registry;
22

3-
import 'package:di/di.dart' show Injector;
4-
5-
abstract class AnnotationMap<K> {
6-
final Map<K, Type> _map = {};
7-
8-
AnnotationMap(Injector injector, MetadataExtractor extractMetadata) {
9-
injector.types.forEach((type) {
10-
extractMetadata(type)
11-
.where((annotation) => annotation is K)
12-
.forEach((annotation) {
13-
_map[annotation] = type;
14-
});
15-
});
16-
}
17-
18-
Type operator[](K annotation) {
19-
var value = _map[annotation];
20-
if (value == null) throw 'No $annotation found!';
21-
return value;
22-
}
23-
24-
void forEach(fn(K, Type)) {
25-
_map.forEach(fn);
26-
}
27-
28-
List<K> annotationsFor(Type type) {
29-
final res = <K>[];
30-
forEach((ann, annType) {
31-
if (annType == type) res.add(ann);
32-
});
33-
return res;
34-
}
35-
}
36-
37-
abstract class AnnotationsMap<K> {
38-
final Map<K, List<Type>> map = {};
39-
40-
AnnotationsMap(Injector injector, MetadataExtractor extractMetadata) {
41-
injector.types.forEach((type) {
42-
extractMetadata(type)
43-
.where((annotation) => annotation is K)
44-
.forEach((annotation) {
45-
map.putIfAbsent(annotation, () => []).add(type);
46-
});
47-
});
48-
}
49-
50-
List operator[](K annotation) {
51-
var value = map[annotation];
52-
if (value == null) throw 'No $annotation found!';
53-
return value;
54-
}
55-
56-
void forEach(fn(K, Type)) {
57-
map.forEach((annotation, types) {
58-
types.forEach((type) {
59-
fn(annotation, type);
60-
});
61-
});
62-
}
63-
64-
List<K> annotationsFor(Type type) {
65-
var res = <K>[];
66-
forEach((ann, annType) {
67-
if (annType == type) res.add(ann);
68-
});
69-
return res;
70-
}
71-
}
72-
733
abstract class MetadataExtractor {
744
Iterable call(Type type);
755
}

lib/core/registry_static.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
library angular.core_static;
22

3-
import 'package:angular/core/annotation_src.dart' show Injectable;
3+
import 'package:angular/core/annotation_src.dart';
44
import 'package:angular/core/registry.dart';
55

66
@Injectable()

lib/core_dom/directive_map.dart

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,48 @@
11
part of angular.core.dom_internal;
22

3+
class DirectiveTypeTuple {
4+
final Directive directive;
5+
final Type type;
6+
DirectiveTypeTuple(this.directive, this.type);
7+
toString() => '@$directive#$type';
8+
}
9+
310
@Injectable()
4-
class DirectiveMap extends AnnotationsMap<Directive> {
11+
class DirectiveMap {
12+
final Map<String, List<DirectiveTypeTuple>> map = new HashMap<String, List<DirectiveTypeTuple>>();
513
DirectiveSelectorFactory _directiveSelectorFactory;
614
FormatterMap _formatters;
715
DirectiveSelector _selector;
16+
17+
DirectiveMap(Injector injector,
18+
this._formatters,
19+
MetadataExtractor metadataExtractor,
20+
this._directiveSelectorFactory) {
21+
injector.types.forEach((type) {
22+
metadataExtractor(type)
23+
.where((annotation) => annotation is Directive)
24+
.forEach((Directive directive) {
25+
map.putIfAbsent(directive.selector, () => []).add(new DirectiveTypeTuple(directive, type));
26+
});
27+
});
28+
}
29+
830
DirectiveSelector get selector {
931
if (_selector != null) return _selector;
1032
return _selector = _directiveSelectorFactory.selector(this, _formatters);
1133
}
1234

13-
DirectiveMap(Injector injector,
14-
this._formatters,
15-
MetadataExtractor metadataExtractor,
16-
this._directiveSelectorFactory)
17-
: super(injector, metadataExtractor);
35+
List<DirectiveTypeTuple> operator[](String key) {
36+
var value = map[key];
37+
if (value == null) throw 'No Directive selector $key found!';
38+
return value;
39+
}
40+
41+
void forEach(fn(K, Type)) {
42+
map.forEach((_, types) {
43+
types.forEach((tuple) {
44+
fn(tuple.directive, tuple.type);
45+
});
46+
});
47+
}
1848
}

lib/core_dom/selector.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ class DirectiveSelector {
4141
}
4242

4343
if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) {
44-
textSelector.add(new _ContainsSelector(annotation, match[1]));
44+
textSelector.add(new _ContainsSelector(selector, match[1]));
4545
} else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) {
46-
attrSelector.add(new _ContainsSelector(annotation, match[1]));
46+
attrSelector.add(new _ContainsSelector(selector, match[1]));
4747
} else if ((selectorParts = _splitCss(selector, type)) != null){
4848
elementSelector.addDirective(selectorParts, new _Directive(type, annotation));
4949
} else {
@@ -97,12 +97,12 @@ class DirectiveSelector {
9797
// this directive is matched on any attribute name, and so
9898
// we need to pass the name to the directive by prefixing it to
9999
// the value. Yes it is a bit of a hack.
100-
_directives[selectorRegExp.annotation].forEach((type) {
100+
_directives[selectorRegExp.selector].forEach((DirectiveTypeTuple tuple) {
101101
// Pre-compute the AST to watch this value.
102102
String expression = _interpolate(value);
103103
AST valueAST = _astParser(expression, formatters: _formatters);
104104
builder.addDirective(new DirectiveRef(
105-
node, type, selectorRegExp.annotation, new Key(type), attrName, valueAST));
105+
node, tuple.type, tuple.directive, new Key(tuple.type), attrName, valueAST));
106106
});
107107
}
108108
}
@@ -135,13 +135,13 @@ class DirectiveSelector {
135135
for (var k = 0; k < textSelector.length; k++) {
136136
var selectorRegExp = textSelector[k];
137137
if (selectorRegExp.regexp.hasMatch(value)) {
138-
_directives[selectorRegExp.annotation].forEach((type) {
138+
_directives[selectorRegExp.selector].forEach((tuple) {
139139
// Pre-compute the AST to watch this value.
140140
String expression = _interpolate(value);
141141
var valueAST = _astParser(expression, formatters: _formatters);
142142

143-
builder.addDirective(new DirectiveRef(node, type,
144-
selectorRegExp.annotation, new Key(type), value, valueAST));
143+
builder.addDirective(new DirectiveRef(node, tuple.type,
144+
tuple.directive, new Key(tuple.type), value, valueAST));
145145
});
146146
}
147147
}
@@ -187,10 +187,10 @@ class _Directive {
187187
}
188188

189189
class _ContainsSelector {
190-
final Directive annotation;
190+
final String selector;
191191
final RegExp regexp;
192192

193-
_ContainsSelector(this.annotation, String regexp)
193+
_ContainsSelector(this.selector, String regexp)
194194
: regexp = new RegExp(regexp);
195195
}
196196

test/core/core_directive_spec.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ void main() {
1111
});
1212

1313
it('should extract attr map from annotated component', (DirectiveMap directives) {
14-
var annotations = directives.annotationsFor(AnnotatedIoComponent);
15-
expect(annotations.length).toEqual(1);
16-
expect(annotations[0] is Component).toBeTruthy();
14+
var tuples = directives['annotated-io'];
15+
expect(tuples.length).toEqual(1);
16+
expect(tuples[0].directive is Component).toBeTruthy();
1717

18-
Component annotation = annotations[0];
18+
Component annotation = tuples[0].directive;
1919
expect(annotation.selector).toEqual('annotated-io');
2020
expect(annotation.visibility).toEqual(Directive.LOCAL_VISIBILITY);
2121
expect(annotation.exportExpressions).toEqual(['exportExpressions']);
@@ -77,11 +77,11 @@ void main() {
7777
});
7878

7979
it("should extract attr map from annotated component which inherits other component", (DirectiveMap directives) {
80-
var annotations = directives.annotationsFor(Sub);
81-
expect(annotations.length).toEqual(1);
82-
expect(annotations[0] is Directive).toBeTruthy();
80+
var tupls = directives['[sub]'];
81+
expect(tupls.length).toEqual(1);
82+
expect(tupls[0].directive is Directive).toBeTruthy();
8383

84-
Directive annotation = annotations[0];
84+
Directive annotation = tupls[0].directive;
8585
expect(annotation.selector).toEqual('[sub]');
8686
expect(annotation.map).toEqual({
8787
"foo": "=>foo",
@@ -112,7 +112,7 @@ class NullParser implements Parser {
112112
'foo': '=>foo'
113113
})
114114
class AnnotatedIoComponent {
115-
static module() => new Module()..bind(String, toFactory: (i) => i.get(AnnotatedIoComponent),
115+
static module(i) => i.bind(String, toFactory: (i) => i.get(AnnotatedIoComponent),
116116
visibility: Directive.LOCAL_VISIBILITY);
117117

118118
AnnotatedIoComponent(Scope scope) {

test/core/parser/parser_spec.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ main() {
456456
});
457457

458458
xdescribe('reserved words', () {
459-
iit('should support reserved words in member get access', () {
459+
it('should support reserved words in member get access', () {
460460
for (String reserved in RESERVED_WORDS) {
461461
expect(parser("o.$reserved").eval({ 'o': new Object() })).toEqual(null);
462462
expect(parser("o.$reserved").eval({ 'o': { reserved: reserved }})).toEqual(reserved);
@@ -1139,10 +1139,10 @@ main() {
11391139
it('should parse formatters', () {
11401140
expect(() {
11411141
eval("1|nonexistent");
1142-
}).toThrow('No Formatter: nonexistent found!');
1142+
}).toThrow('No formatter \'nonexistent\' found!');
11431143
expect(() {
11441144
eval("1|nonexistent", formatters);
1145-
}).toThrow('No Formatter: nonexistent found!');
1145+
}).toThrow('No formatter \'nonexistent\' found!');
11461146

11471147
context['offset'] = 3;
11481148
expect(eval("'abcd'|substring:1:offset")).toEqual("bc");
@@ -1153,12 +1153,12 @@ main() {
11531153
var expression = parser("'World'|hello");
11541154
expect(() {
11551155
expression.eval({}, formatters);
1156-
}).toThrow('No Formatter: hello found!');
1156+
}).toThrow('No formatter \'hello\' found!');
11571157

11581158
var module = new Module()
1159+
..bind(FormatterMap)
11591160
..bind(HelloFormatter);
1160-
var childInjector = injector.createChild([module],
1161-
forceNewInstances: [FormatterMap]);
1161+
var childInjector = injector.createChild([module]);
11621162
var newFormatters = childInjector.get(FormatterMap);
11631163

11641164
expect(expression.eval({}, newFormatters)).toEqual('Hello, World!');

test/core/registry_spec.dart

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)