fix(ivy): ensure unique template and listener function identifiers (#27766)

Previously, there could be identical template/listener function names
for a component's template, if it had multiple similarly structured
nested sub-templates or listeners.
This resulted in build errors:
`Identifier '<SOME_IDENTIFIER>' has already been declared`

This commit fixes this by ensuring that the template index is included
in the `contextName` passed to the `TemplateDefinitionBuilder`
responsible for processing nested sub-templates.
Similarly, the template or element index is included in the listener
names.

PR Close #27766
This commit is contained in:
George Kalpakas
2018-12-19 22:17:38 +02:00
committed by Kara Erickson
parent d026b675be
commit 48555f95c6
8 changed files with 296 additions and 177 deletions

View File

@ -632,7 +632,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
element.outputs.forEach((outputAst: t.BoundEvent) => {
this.creationInstruction(
outputAst.sourceSpan, R3.listener,
this.prepareListenerParameter(element.name, outputAst));
this.prepareListenerParameter(element.name, outputAst, elementIndex));
});
}
@ -707,9 +707,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
const tagName = sanitizeIdentifier(template.tagName || '');
const contextName = tagName ? `${this.contextName}_${tagName}` : '';
const templateName =
contextName ? `${contextName}_Template_${templateIndex}` : `Template_${templateIndex}`;
const contextName = `${tagName ? this.contextName + '_' + tagName : ''}_${templateIndex}`;
const templateName = `${contextName}_Template`;
const parameters: o.Expression[] = [
o.literal(templateIndex),
@ -780,7 +779,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
template.outputs.forEach((outputAst: t.BoundEvent) => {
this.creationInstruction(
outputAst.sourceSpan, R3.listener,
this.prepareListenerParameter('ng_template', outputAst));
this.prepareListenerParameter('ng_template', outputAst, templateIndex));
});
}
@ -1062,14 +1061,16 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
return this.constantPool.getConstLiteral(asLiteral(refsParam), true);
}
private prepareListenerParameter(tagName: string, outputAst: t.BoundEvent): () => o.Expression[] {
private prepareListenerParameter(tagName: string, outputAst: t.BoundEvent, index: number):
() => o.Expression[] {
let eventName: string = outputAst.name;
if (outputAst.type === ParsedEventType.Animation) {
eventName = prepareSyntheticAttributeName(`${outputAst.name}.${outputAst.phase}`);
}
const evNameSanitized = sanitizeIdentifier(eventName);
const tagNameSanitized = sanitizeIdentifier(tagName);
const functionName = `${this.templateName}_${tagNameSanitized}_${evNameSanitized}_listener`;
const functionName =
`${this.templateName}_${tagNameSanitized}_${evNameSanitized}_${index}_listener`;
return () => {