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

Commit 136ed23

Browse files
pavelgjmhevery
authored andcommitted
refactor(compiler): pass DirectiveMap on compiler call instead of constructor
1 parent a5801dc commit 136ed23

21 files changed

+194
-170
lines changed

lib/bootstrap.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Injector ngBootstrap({
8787
return zone.run(() {
8888
var rootElements = [element];
8989
Injector injector = injectorFactory(ngModules);
90-
injector.get(Compiler)(rootElements)(injector, rootElements);
90+
injector.get(Compiler)(rootElements, injector.get(DirectiveMap))(injector, rootElements);
9191
return injector;
9292
});
9393
}

lib/core/directive.dart

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -436,62 +436,3 @@ abstract class NgDetachAware {
436436
void detach();
437437
}
438438

439-
@NgInjectableService()
440-
class DirectiveMap extends AnnotationsMap<NgAnnotation> {
441-
DirectiveMap(Injector injector, MetadataExtractor metadataExtractor,
442-
FieldMetadataExtractor fieldMetadataExtractor)
443-
: super(injector, metadataExtractor) {
444-
Map<NgAnnotation, List<Type>> directives = {};
445-
forEach((NgAnnotation annotation, Type type) {
446-
var match;
447-
var fieldMetadata = fieldMetadataExtractor(type);
448-
if (fieldMetadata.isNotEmpty) {
449-
var newMap = annotation.map == null ? {} : new Map.from(annotation.map);
450-
fieldMetadata.forEach((String fieldName, AttrFieldAnnotation ann) {
451-
var attrName = ann.attrName;
452-
if (newMap.containsKey(attrName)) {
453-
throw 'Mapping for attribute $attrName is already defined (while '
454-
'processing annottation for field $fieldName of $type)';
455-
}
456-
newMap[attrName] = '${ann.mappingSpec}$fieldName';
457-
});
458-
annotation = annotation.cloneWithNewMap(newMap);
459-
}
460-
directives.putIfAbsent(annotation, () => []).add(type);
461-
});
462-
_map.clear();
463-
_map.addAll(directives);
464-
}
465-
}
466-
467-
@NgInjectableService()
468-
class FieldMetadataExtractor {
469-
List<TypeMirror> _fieldAnnotations = [reflectType(NgAttr),
470-
reflectType(NgOneWay), reflectType(NgOneWayOneTime),
471-
reflectType(NgTwoWay), reflectType(NgCallback)];
472-
473-
Map<String, AttrFieldAnnotation> call(Type type) {
474-
ClassMirror cm = reflectType(type);
475-
Map<String, AttrFieldAnnotation> fields = <String, AttrFieldAnnotation>{};
476-
cm.declarations.forEach((Symbol name, DeclarationMirror decl) {
477-
if (decl is VariableMirror ||
478-
(decl is MethodMirror && (decl.isGetter || decl.isSetter))) {
479-
var fieldName = MirrorSystem.getName(name);
480-
if (decl is MethodMirror && decl.isSetter) {
481-
// Remove = from the end of the setter.
482-
fieldName = fieldName.substring(0, fieldName.length - 1);
483-
}
484-
decl.metadata.forEach((InstanceMirror meta) {
485-
if (_fieldAnnotations.contains(meta.type)) {
486-
if (fields[fieldName] != null) {
487-
throw 'Attribute annotation for $fieldName is defined more '
488-
'than once in $type';
489-
}
490-
fields[fieldName] = meta.reflectee as AttrFieldAnnotation;
491-
}
492-
});
493-
}
494-
});
495-
return fields;
496-
}
497-
}

lib/core/module.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ class NgCoreModule extends Module {
3030
type(ScopeDigestTTL);
3131

3232
type(MetadataExtractor);
33-
type(FieldMetadataExtractor);
3433
type(Cache);
35-
type(DirectiveMap);
3634
type(ExceptionHandler);
3735
type(FilterMap);
3836
type(Interpolate);

lib/core/registry.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,26 @@ abstract class AnnotationMap<K> {
3131
}
3232

3333
abstract class AnnotationsMap<K> {
34-
final Map<K, List<Type>> _map = {};
34+
final Map<K, List<Type>> map = {};
3535

3636
AnnotationsMap(Injector injector, MetadataExtractor extractMetadata) {
3737
injector.types.forEach((type) {
3838
var meta = extractMetadata(type)
3939
.where((annotation) => annotation is K)
4040
.forEach((annotation) {
41-
_map.putIfAbsent(annotation, () => []).add(type);
41+
map.putIfAbsent(annotation, () => []).add(type);
4242
});
4343
});
4444
}
4545

4646
List operator[](K annotation) {
47-
var value = _map[annotation];
47+
var value = map[annotation];
4848
if (value == null) throw 'No $annotation found!';
4949
return value;
5050
}
5151

5252
forEach(fn(K, Type)) {
53-
_map.forEach((annotation, types) {
53+
map.forEach((annotation, types) {
5454
types.forEach((type) {
5555
fn(annotation, type);
5656
});

lib/core_dom/block_factory.dart

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,12 @@ class BlockFactory {
154154
BlockCache blockCache = injector.get(BlockCache);
155155
Http http = injector.get(Http);
156156
TemplateCache templateCache = injector.get(TemplateCache);
157+
DirectiveMap directives = injector.get(DirectiveMap);
157158
// This is a bit of a hack since we are returning different type then we are.
158159
var componentFactory = new _ComponentFactory(node, ref.type, ref.annotation as NgComponent, injector.get(dom.NodeTreeSanitizer));
159160
if (fctrs == null) fctrs = new Map<Type, _ComponentFactory>();
160161
fctrs[ref.type] = componentFactory;
161-
return componentFactory.call(injector, compiler, scope, blockCache, http, templateCache);
162+
return componentFactory.call(injector, compiler, scope, blockCache, http, templateCache, directives);
162163
}, visibility: visibility);
163164
} else {
164165
nodeModule.type(ref.type, visibility: visibility);
@@ -258,19 +259,20 @@ class BlockCache {
258259

259260
BlockCache(this.$http, this.$templateCache, this.compiler, this.treeSanitizer);
260261

261-
BlockFactory fromHtml(String html) {
262+
BlockFactory fromHtml(String html, DirectiveMap directives) {
262263
BlockFactory blockFactory = _blockFactoryCache.get(html);
263264
if (blockFactory == null) {
264265
var div = new dom.Element.tag('div');
265266
div.setInnerHtml(html, treeSanitizer: treeSanitizer);
266-
blockFactory = compiler(div.nodes);
267+
blockFactory = compiler(div.nodes, directives);
267268
_blockFactoryCache.put(html, blockFactory);
268269
}
269270
return blockFactory;
270271
}
271272

272-
async.Future<BlockFactory> fromUrl(String url) {
273-
return $http.getString(url, cache: $templateCache).then(fromHtml);
273+
async.Future<BlockFactory> fromUrl(String url, DirectiveMap directives) {
274+
return $http.getString(url, cache: $templateCache).then(
275+
(html) => fromHtml(html, directives));
274276
}
275277
}
276278

@@ -294,7 +296,7 @@ class _ComponentFactory {
294296

295297
_ComponentFactory(this.element, this.type, this.component, this.treeSanitizer);
296298

297-
dynamic call(Injector injector, Compiler compiler, Scope scope, BlockCache $blockCache, Http $http, TemplateCache $templateCache) {
299+
dynamic call(Injector injector, Compiler compiler, Scope scope, BlockCache $blockCache, Http $http, TemplateCache $templateCache, DirectiveMap directives) {
298300
this.compiler = compiler;
299301
shadowDom = element.createShadowRoot();
300302
shadowDom.applyAuthorStyles = component.applyAuthorStyles;
@@ -315,9 +317,9 @@ class _ComponentFactory {
315317
}
316318
var blockFuture;
317319
if (component.template != null) {
318-
blockFuture = new async.Future.value($blockCache.fromHtml(component.template));
320+
blockFuture = new async.Future.value($blockCache.fromHtml(component.template, directives));
319321
} else if (component.templateUrl != null) {
320-
blockFuture = $blockCache.fromUrl(component.templateUrl);
322+
blockFuture = $blockCache.fromUrl(component.templateUrl, directives);
321323
}
322324
TemplateLoader templateLoader = new TemplateLoader( async.Future.wait(cssFutures).then((Iterable<String> cssList) {
323325
if (cssList != null) {

lib/core_dom/compiler.dart

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,23 @@ part of angular.core.dom;
22

33
@NgInjectableService()
44
class Compiler {
5-
final DirectiveMap directives;
65
final Profiler _perf;
76
final Parser _parser;
87
final Expando _expando;
98

10-
DirectiveSelector selector;
11-
12-
Compiler(this.directives, this._perf, this._parser, this._expando) {
13-
selector = directiveSelectorFactory(directives);
14-
}
9+
Compiler(this._perf, this._parser, this._expando);
1510

1611
_compileBlock(NodeCursor domCursor, NodeCursor templateCursor,
17-
List<DirectiveRef> useExistingDirectiveRefs) {
12+
List<DirectiveRef> useExistingDirectiveRefs,
13+
DirectiveMap directives) {
1814
if (domCursor.nodeList().length == 0) return null;
1915

2016
var directivePositions = null; // don't pre-create to create sparse tree and prevent GC pressure.
2117
var cursorAlreadyAdvanced;
2218

2319
do {
2420
var declaredDirectiveRefs = useExistingDirectiveRefs == null
25-
? selector(domCursor.nodeList()[0])
21+
? directives.selector(domCursor.nodeList()[0])
2622
: useExistingDirectiveRefs;
2723
var children = NgAnnotation.COMPILE_CHILDREN;
2824
var childDirectivePositions = null;
@@ -44,7 +40,7 @@ class Compiler {
4440
var remainingDirectives = declaredDirectiveRefs.sublist(j + 1);
4541
blockFactory = compileTransclusion(
4642
domCursor, templateCursor,
47-
directiveRef, remainingDirectives);
43+
directiveRef, remainingDirectives, directives);
4844

4945
j = jj; // stop processing further directives since they belong to transclusion;
5046
}
@@ -59,7 +55,8 @@ class Compiler {
5955
if (children == NgAnnotation.COMPILE_CHILDREN && domCursor.descend()) {
6056
templateCursor.descend();
6157

62-
childDirectivePositions = _compileBlock(domCursor, templateCursor, null);
58+
childDirectivePositions =
59+
_compileBlock(domCursor, templateCursor, null, directives);
6360

6461
domCursor.ascend();
6562
templateCursor.ascend();
@@ -82,14 +79,16 @@ class Compiler {
8279
BlockFactory compileTransclusion(
8380
NodeCursor domCursor, NodeCursor templateCursor,
8481
DirectiveRef directiveRef,
85-
List<DirectiveRef> transcludedDirectiveRefs) {
82+
List<DirectiveRef> transcludedDirectiveRefs,
83+
DirectiveMap directives) {
8684
var anchorName = directiveRef.annotation.selector + (directiveRef.value != null ? '=' + directiveRef.value : '');
8785
var blockFactory;
8886
var blocks;
8987

9088
var transcludeCursor = templateCursor.replaceWithAnchor(anchorName);
9189
var domCursorIndex = domCursor.index;
92-
var directivePositions = _compileBlock(domCursor, transcludeCursor, transcludedDirectiveRefs);
90+
var directivePositions =
91+
_compileBlock(domCursor, transcludeCursor, transcludedDirectiveRefs, directives);
9392
if (directivePositions == null) directivePositions = [];
9493

9594
blockFactory = new BlockFactory(transcludeCursor.elements, directivePositions, _perf, _expando);
@@ -112,14 +111,14 @@ class Compiler {
112111
return blockFactory;
113112
}
114113

115-
BlockFactory call(List<dom.Node> elements) {
114+
BlockFactory call(List<dom.Node> elements, DirectiveMap directives) {
116115
var timerId;
117116
assert((timerId = _perf.startTimer('ng.compile', _html(elements))) != false);
118117
List<dom.Node> domElements = elements;
119118
List<dom.Node> templateElements = cloneElements(domElements);
120119
var directivePositions = _compileBlock(
121120
new NodeCursor(domElements), new NodeCursor(templateElements),
122-
null);
121+
null, directives);
123122

124123
var blockFactory = new BlockFactory(templateElements,
125124
directivePositions == null ? [] : directivePositions, _perf, _expando);

lib/core_dom/directive_map.dart

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
part of angular.core.dom;
2+
3+
@NgInjectableService()
4+
class DirectiveMap extends AnnotationsMap<NgAnnotation> {
5+
DirectiveSelector selector;
6+
7+
DirectiveMap(Injector injector, MetadataExtractor metadataExtractor,
8+
FieldMetadataExtractor fieldMetadataExtractor)
9+
: super(injector, metadataExtractor) {
10+
Map<NgAnnotation, List<Type>> directives = {};
11+
forEach((NgAnnotation annotation, Type type) {
12+
var match;
13+
var fieldMetadata = fieldMetadataExtractor(type);
14+
if (fieldMetadata.isNotEmpty) {
15+
var newMap = annotation.map == null ? {} : new Map.from(annotation.map);
16+
fieldMetadata.forEach((String fieldName, AttrFieldAnnotation ann) {
17+
var attrName = ann.attrName;
18+
if (newMap.containsKey(attrName)) {
19+
throw 'Mapping for attribute $attrName is already defined (while '
20+
'processing annottation for field $fieldName of $type)';
21+
}
22+
newMap[attrName] = '${ann.mappingSpec}$fieldName';
23+
});
24+
annotation = annotation.cloneWithNewMap(newMap);
25+
}
26+
directives.putIfAbsent(annotation, () => []).add(type);
27+
});
28+
map.clear();
29+
map.addAll(directives);
30+
31+
selector = directiveSelectorFactory(this);
32+
}
33+
}
34+
35+
@NgInjectableService()
36+
class FieldMetadataExtractor {
37+
List<TypeMirror> _fieldAnnotations = [reflectType(NgAttr),
38+
reflectType(NgOneWay), reflectType(NgOneWayOneTime),
39+
reflectType(NgTwoWay), reflectType(NgCallback)];
40+
41+
Map<String, AttrFieldAnnotation> call(Type type) {
42+
ClassMirror cm = reflectType(type);
43+
Map<String, AttrFieldAnnotation> fields = <String, AttrFieldAnnotation>{};
44+
cm.declarations.forEach((Symbol name, DeclarationMirror decl) {
45+
if (decl is VariableMirror ||
46+
(decl is MethodMirror && (decl.isGetter || decl.isSetter))) {
47+
var fieldName = MirrorSystem.getName(name);
48+
if (decl is MethodMirror && decl.isSetter) {
49+
// Remove = from the end of the setter.
50+
fieldName = fieldName.substring(0, fieldName.length - 1);
51+
}
52+
decl.metadata.forEach((InstanceMirror meta) {
53+
if (_fieldAnnotations.contains(meta.type)) {
54+
if (fields[fieldName] != null) {
55+
throw 'Attribute annotation for $fieldName is defined more '
56+
'than once in $type';
57+
}
58+
fields[fieldName] = meta.reflectee as AttrFieldAnnotation;
59+
}
60+
});
61+
}
62+
});
63+
return fields;
64+
}
65+
}

lib/core_dom/module.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ library angular.core.dom;
33
import 'dart:async' as async;
44
import 'dart:convert' show JSON;
55
import 'dart:html' as dom;
6+
import 'dart:mirrors';
67

78
import 'package:di/di.dart';
89
import 'package:perf_api/perf_api.dart';
@@ -17,6 +18,7 @@ part 'cookies.dart';
1718
part 'common.dart';
1819
part 'compiler.dart';
1920
part 'directive.dart';
21+
part 'directive_map.dart';
2022
part 'http.dart';
2123
part 'ng_mustache.dart';
2224
part 'node_cursor.dart';
@@ -46,6 +48,8 @@ class NgCoreDomModule extends Module {
4648
type(BrowserCookies);
4749
type(Cookies);
4850
type(LocationWrapper);
51+
type(FieldMetadataExtractor);
52+
type(DirectiveMap);
4953
}
5054
}
5155

lib/directive/ng_include.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ class NgIncludeDirective {
2424
final Scope scope;
2525
final BlockCache blockCache;
2626
final Injector injector;
27+
final DirectiveMap directives;
2728

2829
Block _previousBlock;
2930
Scope _previousScope;
3031

31-
NgIncludeDirective(this.element, this.scope, this.blockCache, this.injector);
32+
NgIncludeDirective(this.element, this.scope, this.blockCache, this.injector, this.directives);
3233

3334
_cleanUp() {
3435
if (_previousBlock == null) return;
@@ -54,7 +55,7 @@ class NgIncludeDirective {
5455
set url(value) {
5556
_cleanUp();
5657
if (value != null && value != '') {
57-
blockCache.fromUrl(value).then(_updateContent);
58+
blockCache.fromUrl(value, directives).then(_updateContent);
5859
}
5960
}
6061
}

lib/mock/test_bed.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class TestBed {
3434
*
3535
* An option [scope] parameter can be supplied to link it with non root scope.
3636
*/
37-
Element compile(html, {Scope scope}) {
37+
Element compile(html, {Scope scope, DirectiveMap directives}) {
3838
var injector = this.injector;
3939
if(scope != null) {
4040
injector = injector.createChild([new Module()..value(Scope, scope)]);
@@ -49,7 +49,10 @@ class TestBed {
4949
throw 'Expecting: String, Node, or List<Node> got $html.';
5050
}
5151
rootElement = rootElements[0];
52-
rootBlock = compiler(rootElements)(injector, rootElements);
52+
if (directives == null) {
53+
directives = injector.get(DirectiveMap);
54+
}
55+
rootBlock = compiler(rootElements, directives)(injector, rootElements);
5356
return rootElement;
5457
}
5558

0 commit comments

Comments
 (0)