fix(compiler): dedup directives in template compiler
Closes #5311 Closes #5464
This commit is contained in:
		
							parent
							
								
									6ddfff5cd5
								
							
						
					
					
						commit
						87ddc8fb6a
					
				| @ -8,7 +8,6 @@ import { | |||||||
|   RegExpWrapper |   RegExpWrapper | ||||||
| } from 'angular2/src/facade/lang'; | } from 'angular2/src/facade/lang'; | ||||||
| import {BaseException} from 'angular2/src/facade/exceptions'; | import {BaseException} from 'angular2/src/facade/exceptions'; | ||||||
| import {MapWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; |  | ||||||
| import * as cpl from './directive_metadata'; | import * as cpl from './directive_metadata'; | ||||||
| import * as md from 'angular2/src/core/metadata/directives'; | import * as md from 'angular2/src/core/metadata/directives'; | ||||||
| import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver'; | import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver'; | ||||||
| @ -77,16 +76,10 @@ export class RuntimeMetadataResolver { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return removeDuplicates(directives).map(type => this.getMetadata(type)); |     return directives.map(type => this.getMetadata(type)); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function removeDuplicates(items: any[]): any[] { |  | ||||||
|   let m = new Map<any, any>(); |  | ||||||
|   items.forEach(i => m.set(i, null)); |  | ||||||
|   return MapWrapper.keys(m); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[] { | function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[] { | ||||||
|   let directives = []; |   let directives = []; | ||||||
|   if (isPresent(platformDirectives)) { |   if (isPresent(platformDirectives)) { | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import {IS_DART, Type, Json, isBlank, stringify} from 'angular2/src/facade/lang'; | import {IS_DART, Type, Json, isBlank, stringify} from 'angular2/src/facade/lang'; | ||||||
| import {BaseException} from 'angular2/src/facade/exceptions'; | import {BaseException} from 'angular2/src/facade/exceptions'; | ||||||
| import {ListWrapper, SetWrapper} from 'angular2/src/facade/collection'; | import {ListWrapper, SetWrapper, MapWrapper} from 'angular2/src/facade/collection'; | ||||||
| import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; | import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; | ||||||
| import { | import { | ||||||
|   CompiledComponentTemplate, |   CompiledComponentTemplate, | ||||||
| @ -96,6 +96,7 @@ export class TemplateCompiler { | |||||||
|   private _compileComponentRuntime( |   private _compileComponentRuntime( | ||||||
|       cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[], |       cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[], | ||||||
|       compilingComponentCacheKeys: Set<any>): CompiledComponentTemplate { |       compilingComponentCacheKeys: Set<any>): CompiledComponentTemplate { | ||||||
|  |     let uniqViewDirectives = removeDuplicates(viewDirectives); | ||||||
|     var compiledTemplate = this._compiledTemplateCache.get(cacheKey); |     var compiledTemplate = this._compiledTemplateCache.get(cacheKey); | ||||||
|     var done = this._compiledTemplateDone.get(cacheKey); |     var done = this._compiledTemplateDone.get(cacheKey); | ||||||
|     if (isBlank(compiledTemplate)) { |     if (isBlank(compiledTemplate)) { | ||||||
| @ -109,7 +110,7 @@ export class TemplateCompiler { | |||||||
|       compilingComponentCacheKeys.add(cacheKey); |       compilingComponentCacheKeys.add(cacheKey); | ||||||
|       done = PromiseWrapper |       done = PromiseWrapper | ||||||
|                  .all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat( |                  .all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat( | ||||||
|                      viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta)))) |                      uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta)))) | ||||||
|                  .then((stylesAndNormalizedViewDirMetas: any[]) => { |                  .then((stylesAndNormalizedViewDirMetas: any[]) => { | ||||||
|                    var childPromises = []; |                    var childPromises = []; | ||||||
|                    var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1); |                    var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1); | ||||||
| @ -175,9 +176,9 @@ export class TemplateCompiler { | |||||||
|       var compMeta = <CompileDirectiveMetadata>componentWithDirs.component; |       var compMeta = <CompileDirectiveMetadata>componentWithDirs.component; | ||||||
|       assertComponent(compMeta); |       assertComponent(compMeta); | ||||||
|       componentMetas.push(compMeta); |       componentMetas.push(compMeta); | ||||||
|       this._processTemplateCodeGen(compMeta, | 
 | ||||||
|                                    <CompileDirectiveMetadata[]>componentWithDirs.directives, |       this._processTemplateCodeGen(compMeta, componentWithDirs.directives, declarations, | ||||||
|                                    declarations, templateArguments); |                                    templateArguments); | ||||||
|       if (compMeta.dynamicLoadable) { |       if (compMeta.dynamicLoadable) { | ||||||
|         var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector); |         var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector); | ||||||
|         componentMetas.push(hostMeta); |         componentMetas.push(hostMeta); | ||||||
| @ -212,9 +213,10 @@ export class TemplateCompiler { | |||||||
|   private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, |   private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata, | ||||||
|                                   directives: CompileDirectiveMetadata[], |                                   directives: CompileDirectiveMetadata[], | ||||||
|                                   targetDeclarations: string[], targetTemplateArguments: any[][]) { |                                   targetDeclarations: string[], targetTemplateArguments: any[][]) { | ||||||
|  |     let uniqueDirectives = removeDuplicates(directives); | ||||||
|     var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.template); |     var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.template); | ||||||
|     var parsedTemplate = |     var parsedTemplate = this._templateParser.parse(compMeta.template.template, uniqueDirectives, | ||||||
|         this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name); |                                                     compMeta.type.name); | ||||||
|     var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen( |     var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen( | ||||||
|         compMeta.type, compMeta.changeDetection, parsedTemplate); |         compMeta.type, compMeta.changeDetection, parsedTemplate); | ||||||
|     var commandsExpr = this._commandCompiler.compileComponentCodeGen( |     var commandsExpr = this._commandCompiler.compileComponentCodeGen( | ||||||
| @ -263,3 +265,17 @@ function addAll(source: any[], target: any[]) { | |||||||
| function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string { | function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string { | ||||||
|   return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateGetterName(nestedCompType.type)}`; |   return `${moduleRef(templateModuleUrl(nestedCompType.type.moduleUrl))}${templateGetterName(nestedCompType.type)}`; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | function removeDuplicates(items: CompileDirectiveMetadata[]): CompileDirectiveMetadata[] { | ||||||
|  |   let res = []; | ||||||
|  |   items.forEach(item => { | ||||||
|  |     let hasMatch = | ||||||
|  |         res.filter(r => r.type.name == item.type.name && r.type.moduleUrl == item.type.moduleUrl && | ||||||
|  |                         r.type.runtime == item.type.runtime) | ||||||
|  |             .length > 0; | ||||||
|  |     if (!hasMatch) { | ||||||
|  |       res.push(item); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |   return res; | ||||||
|  | } | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ import { | |||||||
|   afterEach, |   afterEach, | ||||||
|   AsyncTestCompleter, |   AsyncTestCompleter, | ||||||
|   inject, |   inject, | ||||||
|   beforeEachBindings |   beforeEachProviders | ||||||
| } from 'angular2/testing_internal'; | } from 'angular2/testing_internal'; | ||||||
| 
 | 
 | ||||||
| import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; | import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; | ||||||
| @ -57,7 +57,7 @@ export function main() { | |||||||
|     var compiler: TemplateCompiler; |     var compiler: TemplateCompiler; | ||||||
|     var runtimeMetadataResolver: RuntimeMetadataResolver; |     var runtimeMetadataResolver: RuntimeMetadataResolver; | ||||||
| 
 | 
 | ||||||
|     beforeEachBindings(() => TEST_PROVIDERS); |     beforeEachProviders(() => TEST_PROVIDERS); | ||||||
|     beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver], |     beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver], | ||||||
|                       (_compiler, _runtimeMetadataResolver) => { |                       (_compiler, _runtimeMetadataResolver) => { | ||||||
|                         compiler = _compiler; |                         compiler = _compiler; | ||||||
| @ -122,9 +122,18 @@ export function main() { | |||||||
|                    async.done(); |                    async.done(); | ||||||
|                  }); |                  }); | ||||||
|            })); |            })); | ||||||
|  | 
 | ||||||
|  |         it('should dedup directives', inject([AsyncTestCompleter], (async) => { | ||||||
|  |              compile([CompWithDupDirectives, TreeComp]) | ||||||
|  |                  .then((humanizedTemplate) => { | ||||||
|  |                    expect(humanizedTemplate['commands'][1]['commands'][0]).toEqual("<tree>"); | ||||||
|  |                    async.done(); | ||||||
|  | 
 | ||||||
|  |                  }); | ||||||
|  |            })); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       xdescribe('compileHostComponentRuntime', () => { |       describe('compileHostComponentRuntime', () => { | ||||||
|         function compile(components: Type[]): Promise<any[]> { |         function compile(components: Type[]): Promise<any[]> { | ||||||
|           return compiler.compileHostComponentRuntime(components[0]) |           return compiler.compileHostComponentRuntime(components[0]) | ||||||
|               .then((compiledHostTemplate) => humanizeTemplate(compiledHostTemplate.template)); |               .then((compiledHostTemplate) => humanizeTemplate(compiledHostTemplate.template)); | ||||||
| @ -179,7 +188,6 @@ export function main() { | |||||||
|                  }); |                  }); | ||||||
|              xhr.flush(); |              xhr.flush(); | ||||||
|            })); |            })); | ||||||
| 
 |  | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       describe('compileTemplatesCodeGen', () => { |       describe('compileTemplatesCodeGen', () => { | ||||||
| @ -290,6 +298,15 @@ class CompWithBindingsAndStyles { | |||||||
| class TreeComp { | class TreeComp { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Component({selector: 'comp-wit-dup-tpl', moduleId: THIS_MODULE_ID}) | ||||||
|  | @View({ | ||||||
|  |   template: '<tree></tree>', | ||||||
|  |   directives: [TreeComp, TreeComp], | ||||||
|  |   encapsulation: ViewEncapsulation.None | ||||||
|  | }) | ||||||
|  | class CompWithDupDirectives { | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Component({selector: 'comp-url', moduleId: THIS_MODULE_ID}) | @Component({selector: 'comp-url', moduleId: THIS_MODULE_ID}) | ||||||
| @View({templateUrl: 'compUrl.html', encapsulation: ViewEncapsulation.None}) | @View({templateUrl: 'compUrl.html', encapsulation: ViewEncapsulation.None}) | ||||||
| class CompWithTemplateUrl { | class CompWithTemplateUrl { | ||||||
| @ -349,7 +366,7 @@ export function humanizeTemplate( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class TestContext implements CompWithBindingsAndStyles, TreeComp, CompWithTemplateUrl, | class TestContext implements CompWithBindingsAndStyles, TreeComp, CompWithTemplateUrl, | ||||||
|     CompWithEmbeddedTemplate { |     CompWithEmbeddedTemplate, CompWithDupDirectives { | ||||||
|   someProp: string; |   someProp: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user