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…
Reference in New Issue