1- import { Type , FIELD , isBlank , isPresent } from 'facade/lang' ;
1+ import { Type , FIELD , isBlank , isPresent , BaseException , stringify } from 'facade/lang' ;
22import { Promise , PromiseWrapper } from 'facade/async' ;
3- import { List , ListWrapper } from 'facade/collection' ;
3+ import { List , ListWrapper , MapWrapper } from 'facade/collection' ;
44import { DOM , Element } from 'facade/dom' ;
55
66import { Parser } from 'change_detection/parser/parser' ;
@@ -14,6 +14,30 @@ import {TemplateLoader} from './template_loader';
1414import { AnnotatedType } from './annotated_type' ;
1515import { Component } from '../annotations/annotations' ;
1616
17+ /**
18+ * Cache that stores the ProtoView of the template of a component.
19+ * Used to prevent duplicate work and resolve cyclic dependencies.
20+ */
21+ export class CompilerCache {
22+ _cache :Map ;
23+ constructor ( ) {
24+ this . _cache = MapWrapper . create ( ) ;
25+ }
26+
27+ set ( component :Type , protoView :ProtoView ) {
28+ MapWrapper . set ( this . _cache , component , protoView ) ;
29+ }
30+
31+ get ( component :Type ) :ProtoView {
32+ var result = MapWrapper . get ( this . _cache , component ) ;
33+ if ( isBlank ( result ) ) {
34+ // need to normalize undefined to null so that type checking passes :-(
35+ return null ;
36+ }
37+ return result ;
38+ }
39+ }
40+
1741/**
1842 * The compiler loads and translates the html templates of components into
1943 * nested ProtoViews. To decompose its functionality it uses
@@ -23,10 +47,12 @@ export class Compiler {
2347 _templateLoader :TemplateLoader ;
2448 _reader: DirectiveMetadataReader ;
2549 _parser:Parser ;
26- constructor ( templateLoader :TemplateLoader , reader : DirectiveMetadataReader , parser :Parser ) {
50+ _compilerCache:CompilerCache ;
51+ constructor ( templateLoader :TemplateLoader , reader : DirectiveMetadataReader , parser :Parser , cache :CompilerCache ) {
2752 this . _templateLoader = templateLoader ;
2853 this . _reader = reader ;
2954 this . _parser = parser ;
55+ this . _compilerCache = cache ;
3056 }
3157
3258 createSteps ( component :AnnotatedType ) :List < CompileStep > {
@@ -40,15 +66,22 @@ export class Compiler {
4066 }
4167
4268 compile ( component :Type , templateRoot :Element = null ) :Promise < ProtoView > {
43- // TODO load all components transitively from the cache first
44- var cache = null ;
45- return PromiseWrapper . resolve ( this . compileWithCache (
46- cache , this . _reader . annotatedType ( component ) , templateRoot )
69+ var templateCache = null ;
70+ // TODO load all components that have urls
71+ // transitively via the _templateLoader and store them in templateCache
72+
73+ return PromiseWrapper . resolve ( this . compileAllLoaded (
74+ templateCache , this . _reader . annotatedType ( component ) , templateRoot )
4775 ) ;
4876 }
4977
5078 // public so that we can compile in sync in performance tests.
51- compileWithCache ( cache , component :AnnotatedType , templateRoot :Element = null ) :ProtoView {
79+ compileAllLoaded ( templateCache , component :AnnotatedType , templateRoot :Element = null ) :ProtoView {
80+ var rootProtoView = this . _compilerCache . get ( component . type ) ;
81+ if ( isPresent ( rootProtoView ) ) {
82+ return rootProtoView ;
83+ }
84+
5285 if ( isBlank ( templateRoot ) ) {
5386 // TODO: read out the cache if templateRoot = null. Could contain:
5487 // - templateRoot string
@@ -57,15 +90,18 @@ export class Compiler {
5790 var annotation :any = component . annotation ;
5891 templateRoot = DOM . createTemplate ( annotation . template . inline ) ;
5992 }
93+
6094 var pipeline = new CompilePipeline ( this . createSteps ( component ) ) ;
6195 var compileElements = pipeline . process ( templateRoot ) ;
62- var rootProtoView = compileElements [ 0 ] . inheritedProtoView ;
63- // TODO: put the rootProtoView into the cache to support recursive templates!
96+ rootProtoView = compileElements [ 0 ] . inheritedProtoView ;
97+ // Save the rootProtoView before we recurse so that we are able
98+ // to compile components that use themselves in their template.
99+ this . _compilerCache . set ( component . type , rootProtoView ) ;
64100
65101 for ( var i = 0 ; i < compileElements . length ; i ++ ) {
66102 var ce = compileElements [ i ] ;
67103 if ( isPresent ( ce . componentDirective ) ) {
68- ce . inheritedElementBinder . nestedProtoView = this . compileWithCache ( cache , ce . componentDirective , null ) ;
104+ ce . inheritedElementBinder . nestedProtoView = this . compileAllLoaded ( templateCache , ce . componentDirective , null ) ;
69105 }
70106 }
71107
0 commit comments