fix(compiler): dedup directives in template compiler

Closes #5311

Closes #5464
This commit is contained in:
vsavkin 2015-11-24 11:26:37 -08:00 committed by Victor Savkin
parent 6ddfff5cd5
commit 87ddc8fb6a
3 changed files with 46 additions and 20 deletions

View File

@ -8,7 +8,6 @@ import {
RegExpWrapper
} from 'angular2/src/facade/lang';
import {BaseException} from 'angular2/src/facade/exceptions';
import {MapWrapper, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import * as cpl from './directive_metadata';
import * as md from 'angular2/src/core/metadata/directives';
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[] {
let directives = [];
if (isPresent(platformDirectives)) {

View File

@ -1,6 +1,6 @@
import {IS_DART, Type, Json, isBlank, stringify} from 'angular2/src/facade/lang';
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 {
CompiledComponentTemplate,
@ -96,6 +96,7 @@ export class TemplateCompiler {
private _compileComponentRuntime(
cacheKey: any, compMeta: CompileDirectiveMetadata, viewDirectives: CompileDirectiveMetadata[],
compilingComponentCacheKeys: Set<any>): CompiledComponentTemplate {
let uniqViewDirectives = removeDuplicates(viewDirectives);
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
var done = this._compiledTemplateDone.get(cacheKey);
if (isBlank(compiledTemplate)) {
@ -109,7 +110,7 @@ export class TemplateCompiler {
compilingComponentCacheKeys.add(cacheKey);
done = PromiseWrapper
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
viewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
.then((stylesAndNormalizedViewDirMetas: any[]) => {
var childPromises = [];
var normalizedViewDirMetas = stylesAndNormalizedViewDirMetas.slice(1);
@ -175,9 +176,9 @@ export class TemplateCompiler {
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
assertComponent(compMeta);
componentMetas.push(compMeta);
this._processTemplateCodeGen(compMeta,
<CompileDirectiveMetadata[]>componentWithDirs.directives,
declarations, templateArguments);
this._processTemplateCodeGen(compMeta, componentWithDirs.directives, declarations,
templateArguments);
if (compMeta.dynamicLoadable) {
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
componentMetas.push(hostMeta);
@ -212,9 +213,10 @@ export class TemplateCompiler {
private _processTemplateCodeGen(compMeta: CompileDirectiveMetadata,
directives: CompileDirectiveMetadata[],
targetDeclarations: string[], targetTemplateArguments: any[][]) {
let uniqueDirectives = removeDuplicates(directives);
var styleExpr = this._styleCompiler.compileComponentCodeGen(compMeta.template);
var parsedTemplate =
this._templateParser.parse(compMeta.template.template, directives, compMeta.type.name);
var parsedTemplate = this._templateParser.parse(compMeta.template.template, uniqueDirectives,
compMeta.type.name);
var changeDetectorsExprs = this._cdCompiler.compileComponentCodeGen(
compMeta.type, compMeta.changeDetection, parsedTemplate);
var commandsExpr = this._commandCompiler.compileComponentCodeGen(
@ -263,3 +265,17 @@ function addAll(source: any[], target: any[]) {
function codeGenComponentTemplateFactory(nestedCompType: CompileDirectiveMetadata): string {
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;
}

View File

@ -10,7 +10,7 @@ import {
afterEach,
AsyncTestCompleter,
inject,
beforeEachBindings
beforeEachProviders
} from 'angular2/testing_internal';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
@ -57,7 +57,7 @@ export function main() {
var compiler: TemplateCompiler;
var runtimeMetadataResolver: RuntimeMetadataResolver;
beforeEachBindings(() => TEST_PROVIDERS);
beforeEachProviders(() => TEST_PROVIDERS);
beforeEach(inject([TemplateCompiler, RuntimeMetadataResolver],
(_compiler, _runtimeMetadataResolver) => {
compiler = _compiler;
@ -122,9 +122,18 @@ export function main() {
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[]> {
return compiler.compileHostComponentRuntime(components[0])
.then((compiledHostTemplate) => humanizeTemplate(compiledHostTemplate.template));
@ -179,7 +188,6 @@ export function main() {
});
xhr.flush();
}));
});
describe('compileTemplatesCodeGen', () => {
@ -290,6 +298,15 @@ class CompWithBindingsAndStyles {
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})
@View({templateUrl: 'compUrl.html', encapsulation: ViewEncapsulation.None})
class CompWithTemplateUrl {
@ -349,7 +366,7 @@ export function humanizeTemplate(
}
class TestContext implements CompWithBindingsAndStyles, TreeComp, CompWithTemplateUrl,
CompWithEmbeddedTemplate {
CompWithEmbeddedTemplate, CompWithDupDirectives {
someProp: string;
}