fix(template_compiler): Fix erroneous cycle detection
Before, the check for cycles was wrong and lead to false positives. Fixes #6404 Closes #6474
This commit is contained in:
parent
4d0c2ed1f6
commit
eda4c3eb4c
|
@ -124,7 +124,7 @@ export class TemplateCompiler {
|
||||||
var hostMeta: CompileDirectiveMetadata =
|
var hostMeta: CompileDirectiveMetadata =
|
||||||
createHostComponentMeta(compMeta.type, compMeta.selector);
|
createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||||
|
|
||||||
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], [], new Set());
|
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], [], []);
|
||||||
}
|
}
|
||||||
return this._compiledTemplateDone.get(hostCacheKey)
|
return this._compiledTemplateDone.get(hostCacheKey)
|
||||||
.then((compiledTemplate: CompiledTemplate) =>
|
.then((compiledTemplate: CompiledTemplate) =>
|
||||||
|
@ -172,7 +172,7 @@ export class TemplateCompiler {
|
||||||
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
|
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
|
||||||
viewDirectives: CompileDirectiveMetadata[],
|
viewDirectives: CompileDirectiveMetadata[],
|
||||||
pipes: CompilePipeMetadata[],
|
pipes: CompilePipeMetadata[],
|
||||||
compilingComponentCacheKeys: Set<any>): CompiledTemplate {
|
compilingComponentsPath: any[]): CompiledTemplate {
|
||||||
let uniqViewDirectives = <CompileDirectiveMetadata[]>removeDuplicates(viewDirectives);
|
let uniqViewDirectives = <CompileDirectiveMetadata[]>removeDuplicates(viewDirectives);
|
||||||
let uniqViewPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
|
let uniqViewPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
|
||||||
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
|
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
|
||||||
|
@ -180,7 +180,6 @@ export class TemplateCompiler {
|
||||||
if (isBlank(compiledTemplate)) {
|
if (isBlank(compiledTemplate)) {
|
||||||
compiledTemplate = new CompiledTemplate();
|
compiledTemplate = new CompiledTemplate();
|
||||||
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
|
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
|
||||||
compilingComponentCacheKeys.add(cacheKey);
|
|
||||||
done = PromiseWrapper
|
done = PromiseWrapper
|
||||||
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
|
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
|
||||||
uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
|
||||||
|
@ -195,14 +194,13 @@ export class TemplateCompiler {
|
||||||
var usedDirectives = DirectiveCollector.findUsedDirectives(parsedTemplate);
|
var usedDirectives = DirectiveCollector.findUsedDirectives(parsedTemplate);
|
||||||
usedDirectives.components.forEach(
|
usedDirectives.components.forEach(
|
||||||
component => this._compileNestedComponentRuntime(
|
component => this._compileNestedComponentRuntime(
|
||||||
component, compilingComponentCacheKeys, childPromises));
|
component, compilingComponentsPath, childPromises));
|
||||||
return PromiseWrapper.all(childPromises)
|
return PromiseWrapper.all(childPromises)
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
var filteredPipes = filterPipes(parsedTemplate, uniqViewPipes);
|
var filteredPipes = filterPipes(parsedTemplate, uniqViewPipes);
|
||||||
compiledTemplate.init(this._createViewFactoryRuntime(
|
compiledTemplate.init(this._createViewFactoryRuntime(
|
||||||
compMeta, parsedTemplate, usedDirectives.directives, styles,
|
compMeta, parsedTemplate, usedDirectives.directives, styles,
|
||||||
filteredPipes));
|
filteredPipes));
|
||||||
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
|
|
||||||
return compiledTemplate;
|
return compiledTemplate;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -212,16 +210,19 @@ export class TemplateCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _compileNestedComponentRuntime(childComponentDir: CompileDirectiveMetadata,
|
private _compileNestedComponentRuntime(childComponentDir: CompileDirectiveMetadata,
|
||||||
compilingComponentCacheKeys: Set<Type>,
|
parentCompilingComponentsPath: any[],
|
||||||
childPromises: Promise<any>[]) {
|
childPromises: Promise<any>[]) {
|
||||||
|
var compilingComponentsPath = ListWrapper.clone(parentCompilingComponentsPath);
|
||||||
|
|
||||||
var childCacheKey = childComponentDir.type.runtime;
|
var childCacheKey = childComponentDir.type.runtime;
|
||||||
var childViewDirectives: CompileDirectiveMetadata[] =
|
var childViewDirectives: CompileDirectiveMetadata[] =
|
||||||
this._runtimeMetadataResolver.getViewDirectivesMetadata(childComponentDir.type.runtime);
|
this._runtimeMetadataResolver.getViewDirectivesMetadata(childComponentDir.type.runtime);
|
||||||
var childViewPipes: CompilePipeMetadata[] =
|
var childViewPipes: CompilePipeMetadata[] =
|
||||||
this._runtimeMetadataResolver.getViewPipesMetadata(childComponentDir.type.runtime);
|
this._runtimeMetadataResolver.getViewPipesMetadata(childComponentDir.type.runtime);
|
||||||
var childIsRecursive = SetWrapper.has(compilingComponentCacheKeys, childCacheKey);
|
var childIsRecursive = ListWrapper.contains(compilingComponentsPath, childCacheKey);
|
||||||
|
compilingComponentsPath.push(childCacheKey);
|
||||||
this._compileComponentRuntime(childCacheKey, childComponentDir, childViewDirectives,
|
this._compileComponentRuntime(childCacheKey, childComponentDir, childViewDirectives,
|
||||||
childViewPipes, compilingComponentCacheKeys);
|
childViewPipes, compilingComponentsPath);
|
||||||
if (!childIsRecursive) {
|
if (!childIsRecursive) {
|
||||||
// Only wait for a child if it is not a cycle
|
// Only wait for a child if it is not a cycle
|
||||||
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
|
childPromises.push(this._compiledTemplateDone.get(childCacheKey));
|
||||||
|
|
|
@ -105,6 +105,22 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should compile components at various nesting levels',
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
compile([CompWith2NestedComps, Comp1, Comp2])
|
||||||
|
.then((humanizedView) => {
|
||||||
|
expect(humanizedView['elements']).toEqual(['<comp-with-2nested>']);
|
||||||
|
expect(humanizedView['componentViews'][0]['elements'])
|
||||||
|
.toEqual(['<comp1>', '<comp2>']);
|
||||||
|
expect(humanizedView['componentViews'][0]['componentViews'][0]['elements'])
|
||||||
|
.toEqual(['<a>', '<comp2>']);
|
||||||
|
expect(humanizedView['componentViews'][0]['componentViews'][1]['elements'])
|
||||||
|
.toEqual(['<b>']);
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should compile recursive components', inject([AsyncTestCompleter], (async) => {
|
it('should compile recursive components', inject([AsyncTestCompleter], (async) => {
|
||||||
compile([TreeComp])
|
compile([TreeComp])
|
||||||
.then((humanizedView) => {
|
.then((humanizedView) => {
|
||||||
|
@ -365,6 +381,29 @@ export class NonComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Component({selector: 'comp2', moduleId: THIS_MODULE_ID})
|
||||||
|
@View({template: '<b></b>', encapsulation: ViewEncapsulation.None})
|
||||||
|
export class Comp2 {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'comp1', moduleId: THIS_MODULE_ID})
|
||||||
|
@View({
|
||||||
|
template: '<a></a>, <comp2></comp2>',
|
||||||
|
encapsulation: ViewEncapsulation.None,
|
||||||
|
directives: [Comp2]
|
||||||
|
})
|
||||||
|
export class Comp1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'comp-with-2nested', moduleId: THIS_MODULE_ID})
|
||||||
|
@View({
|
||||||
|
template: '<comp1></comp1>, <comp2></comp2>',
|
||||||
|
encapsulation: ViewEncapsulation.None,
|
||||||
|
directives: [Comp1, Comp2]
|
||||||
|
})
|
||||||
|
export class CompWith2NestedComps {
|
||||||
|
}
|
||||||
|
|
||||||
function testableTemplateModule(sourceModule: SourceModule,
|
function testableTemplateModule(sourceModule: SourceModule,
|
||||||
normComp: CompileDirectiveMetadata): SourceModule {
|
normComp: CompileDirectiveMetadata): SourceModule {
|
||||||
var testableSource = `
|
var testableSource = `
|
||||||
|
|
Loading…
Reference in New Issue