X Tutup
Skip to content

Commit eda4c3e

Browse files
committed
fix(template_compiler): Fix erroneous cycle detection
Before, the check for cycles was wrong and lead to false positives. Fixes angular#6404 Closes angular#6474
1 parent 4d0c2ed commit eda4c3e

File tree

2 files changed

+48
-8
lines changed

2 files changed

+48
-8
lines changed

modules/angular2/src/compiler/template_compiler.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export class TemplateCompiler {
124124
var hostMeta: CompileDirectiveMetadata =
125125
createHostComponentMeta(compMeta.type, compMeta.selector);
126126

127-
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], [], new Set());
127+
this._compileComponentRuntime(hostCacheKey, hostMeta, [compMeta], [], []);
128128
}
129129
return this._compiledTemplateDone.get(hostCacheKey)
130130
.then((compiledTemplate: CompiledTemplate) =>
@@ -172,15 +172,14 @@ export class TemplateCompiler {
172172
private _compileComponentRuntime(cacheKey: any, compMeta: CompileDirectiveMetadata,
173173
viewDirectives: CompileDirectiveMetadata[],
174174
pipes: CompilePipeMetadata[],
175-
compilingComponentCacheKeys: Set<any>): CompiledTemplate {
175+
compilingComponentsPath: any[]): CompiledTemplate {
176176
let uniqViewDirectives = <CompileDirectiveMetadata[]>removeDuplicates(viewDirectives);
177177
let uniqViewPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
178178
var compiledTemplate = this._compiledTemplateCache.get(cacheKey);
179179
var done = this._compiledTemplateDone.get(cacheKey);
180180
if (isBlank(compiledTemplate)) {
181181
compiledTemplate = new CompiledTemplate();
182182
this._compiledTemplateCache.set(cacheKey, compiledTemplate);
183-
compilingComponentCacheKeys.add(cacheKey);
184183
done = PromiseWrapper
185184
.all([<any>this._styleCompiler.compileComponentRuntime(compMeta.template)].concat(
186185
uniqViewDirectives.map(dirMeta => this.normalizeDirectiveMetadata(dirMeta))))
@@ -195,14 +194,13 @@ export class TemplateCompiler {
195194
var usedDirectives = DirectiveCollector.findUsedDirectives(parsedTemplate);
196195
usedDirectives.components.forEach(
197196
component => this._compileNestedComponentRuntime(
198-
component, compilingComponentCacheKeys, childPromises));
197+
component, compilingComponentsPath, childPromises));
199198
return PromiseWrapper.all(childPromises)
200199
.then((_) => {
201200
var filteredPipes = filterPipes(parsedTemplate, uniqViewPipes);
202201
compiledTemplate.init(this._createViewFactoryRuntime(
203202
compMeta, parsedTemplate, usedDirectives.directives, styles,
204203
filteredPipes));
205-
SetWrapper.delete(compilingComponentCacheKeys, cacheKey);
206204
return compiledTemplate;
207205
});
208206
});
@@ -212,16 +210,19 @@ export class TemplateCompiler {
212210
}
213211

214212
private _compileNestedComponentRuntime(childComponentDir: CompileDirectiveMetadata,
215-
compilingComponentCacheKeys: Set<Type>,
213+
parentCompilingComponentsPath: any[],
216214
childPromises: Promise<any>[]) {
215+
var compilingComponentsPath = ListWrapper.clone(parentCompilingComponentsPath);
216+
217217
var childCacheKey = childComponentDir.type.runtime;
218218
var childViewDirectives: CompileDirectiveMetadata[] =
219219
this._runtimeMetadataResolver.getViewDirectivesMetadata(childComponentDir.type.runtime);
220220
var childViewPipes: CompilePipeMetadata[] =
221221
this._runtimeMetadataResolver.getViewPipesMetadata(childComponentDir.type.runtime);
222-
var childIsRecursive = SetWrapper.has(compilingComponentCacheKeys, childCacheKey);
222+
var childIsRecursive = ListWrapper.contains(compilingComponentsPath, childCacheKey);
223+
compilingComponentsPath.push(childCacheKey);
223224
this._compileComponentRuntime(childCacheKey, childComponentDir, childViewDirectives,
224-
childViewPipes, compilingComponentCacheKeys);
225+
childViewPipes, compilingComponentsPath);
225226
if (!childIsRecursive) {
226227
// Only wait for a child if it is not a cycle
227228
childPromises.push(this._compiledTemplateDone.get(childCacheKey));

modules/angular2/test/compiler/template_compiler_spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ export function main() {
105105
});
106106
}));
107107

108+
it('should compile components at various nesting levels',
109+
inject([AsyncTestCompleter], (async) => {
110+
compile([CompWith2NestedComps, Comp1, Comp2])
111+
.then((humanizedView) => {
112+
expect(humanizedView['elements']).toEqual(['<comp-with-2nested>']);
113+
expect(humanizedView['componentViews'][0]['elements'])
114+
.toEqual(['<comp1>', '<comp2>']);
115+
expect(humanizedView['componentViews'][0]['componentViews'][0]['elements'])
116+
.toEqual(['<a>', '<comp2>']);
117+
expect(humanizedView['componentViews'][0]['componentViews'][1]['elements'])
118+
.toEqual(['<b>']);
119+
120+
async.done();
121+
});
122+
}));
123+
108124
it('should compile recursive components', inject([AsyncTestCompleter], (async) => {
109125
compile([TreeComp])
110126
.then((humanizedView) => {
@@ -365,6 +381,29 @@ export class NonComponent {
365381
}
366382

367383

384+
@Component({selector: 'comp2', moduleId: THIS_MODULE_ID})
385+
@View({template: '<b></b>', encapsulation: ViewEncapsulation.None})
386+
export class Comp2 {
387+
}
388+
389+
@Component({selector: 'comp1', moduleId: THIS_MODULE_ID})
390+
@View({
391+
template: '<a></a>, <comp2></comp2>',
392+
encapsulation: ViewEncapsulation.None,
393+
directives: [Comp2]
394+
})
395+
export class Comp1 {
396+
}
397+
398+
@Component({selector: 'comp-with-2nested', moduleId: THIS_MODULE_ID})
399+
@View({
400+
template: '<comp1></comp1>, <comp2></comp2>',
401+
encapsulation: ViewEncapsulation.None,
402+
directives: [Comp1, Comp2]
403+
})
404+
export class CompWith2NestedComps {
405+
}
406+
368407
function testableTemplateModule(sourceModule: SourceModule,
369408
normComp: CompileDirectiveMetadata): SourceModule {
370409
var testableSource = `

0 commit comments

Comments
 (0)
X Tutup