fix(compiler): throw an error if variable with the same name is already defined. (#7209)
* fix(compiler): throw an error if variable with the same name is already defined. Closes #6492 * fix(compiler): Clean up formatting for issue #6492 * fix(compiler): throw an error if reference with the same name is already defined. Closes #6492
This commit is contained in:
parent
263122ea5f
commit
9036f78b74
|
@ -140,21 +140,24 @@ export class TemplateParser {
|
||||||
directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
|
||||||
templateUrl: string): TemplateParseResult {
|
templateUrl: string): TemplateParseResult {
|
||||||
var htmlAstWithErrors = this._htmlParser.parse(template, templateUrl);
|
var htmlAstWithErrors = this._htmlParser.parse(template, templateUrl);
|
||||||
var errors: ParseError[] = htmlAstWithErrors.errors;
|
var errors:ParseError[] = htmlAstWithErrors.errors;
|
||||||
var result;
|
var result;
|
||||||
if (htmlAstWithErrors.rootNodes.length > 0) {
|
if (htmlAstWithErrors.rootNodes.length > 0) {
|
||||||
var uniqDirectives = <CompileDirectiveMetadata[]>removeDuplicates(directives);
|
var uniqDirectives = <CompileDirectiveMetadata[]>removeDuplicates(directives);
|
||||||
var uniqPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
|
var uniqPipes = <CompilePipeMetadata[]>removeDuplicates(pipes);
|
||||||
var providerViewContext =
|
var providerViewContext =
|
||||||
new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan);
|
new ProviderViewContext(component, htmlAstWithErrors.rootNodes[0].sourceSpan);
|
||||||
var parseVisitor = new TemplateParseVisitor(providerViewContext, uniqDirectives, uniqPipes,
|
var parseVisitor = new TemplateParseVisitor(providerViewContext, uniqDirectives, uniqPipes,
|
||||||
this._exprParser, this._schemaRegistry);
|
this._exprParser, this._schemaRegistry);
|
||||||
|
|
||||||
result = htmlVisitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
result = htmlVisitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_ELEMENT_CONTEXT);
|
||||||
errors = errors.concat(parseVisitor.errors).concat(providerViewContext.errors);
|
errors = errors.concat(parseVisitor.errors).concat(providerViewContext.errors);
|
||||||
} else {
|
} else {
|
||||||
result = [];
|
result = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._assertNoReferenceDuplicationOnTemplate(result, errors);
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
return new TemplateParseResult(result, errors);
|
return new TemplateParseResult(result, errors);
|
||||||
}
|
}
|
||||||
|
@ -164,6 +167,25 @@ export class TemplateParser {
|
||||||
}
|
}
|
||||||
return new TemplateParseResult(result, errors);
|
return new TemplateParseResult(result, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_assertNoReferenceDuplicationOnTemplate(result:any[], errors:TemplateParseError[]):void {
|
||||||
|
const existingReferences = [];
|
||||||
|
result
|
||||||
|
.filter(element => !!element.references)
|
||||||
|
.forEach(element => element.references.forEach(reference=> {
|
||||||
|
const name = reference.name;
|
||||||
|
if (existingReferences.indexOf(name) < 0) {
|
||||||
|
existingReferences.push(name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const error = new TemplateParseError(
|
||||||
|
`Reference "#${name}" is defined several times`,
|
||||||
|
reference.sourceSpan,
|
||||||
|
ParseErrorLevel.FATAL);
|
||||||
|
errors.push(error);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemplateParseVisitor implements HtmlAstVisitor {
|
class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
|
@ -522,9 +544,11 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
|
|
||||||
private _parseVariable(identifier: string, value: string, sourceSpan: ParseSourceSpan,
|
private _parseVariable(identifier: string, value: string, sourceSpan: ParseSourceSpan,
|
||||||
targetVars: VariableAst[]) {
|
targetVars: VariableAst[]) {
|
||||||
|
|
||||||
if (identifier.indexOf('-') > -1) {
|
if (identifier.indexOf('-') > -1) {
|
||||||
this._reportError(`"-" is not allowed in variable names`, sourceSpan);
|
this._reportError(`"-" is not allowed in variable names`, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetVars.push(new VariableAst(identifier, value, sourceSpan));
|
targetVars.push(new VariableAst(identifier, value, sourceSpan));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,6 +557,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||||
if (identifier.indexOf('-') > -1) {
|
if (identifier.indexOf('-') > -1) {
|
||||||
this._reportError(`"-" is not allowed in reference names`, sourceSpan);
|
this._reportError(`"-" is not allowed in reference names`, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
|
targetRefs.push(new ElementOrDirectiveRef(identifier, value, sourceSpan));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -822,6 +822,16 @@ There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"><
|
||||||
"let-" is only supported on template elements. ("<div [ERROR ->]let-a></div>"): TestComp@0:5`);
|
"let-" is only supported on template elements. ("<div [ERROR ->]let-a></div>"): TestComp@0:5`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should report duplicate reference names', () => {
|
||||||
|
expect(() => parse('<div #a></div><div #a></div>', []))
|
||||||
|
.toThrowError(`Template parse errors:
|
||||||
|
Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>"): TestComp@0:19`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not throw error when there is same reference name in different templates', () => {
|
||||||
|
expect(() => parse('<div #a><template #a><span>OK</span></template></div>', [])).not.toThrowError();
|
||||||
|
});
|
||||||
|
|
||||||
it('should assign references with empty value to components', () => {
|
it('should assign references with empty value to components', () => {
|
||||||
var dirA = CompileDirectiveMetadata.create({
|
var dirA = CompileDirectiveMetadata.create({
|
||||||
selector: '[a]',
|
selector: '[a]',
|
||||||
|
|
|
@ -1059,11 +1059,11 @@ class NeedsContentChildWithRead {
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'needs-view-children-read',
|
selector: 'needs-view-children-read',
|
||||||
template: '<div #q text="va"></div><div #q text="vb"></div>',
|
template: '<div #q text="va"></div><div #w text="vb"></div>',
|
||||||
directives: [TextDirective]
|
directives: [TextDirective]
|
||||||
})
|
})
|
||||||
class NeedsViewChildrenWithRead {
|
class NeedsViewChildrenWithRead {
|
||||||
@ViewChildren('q', {read: TextDirective}) textDirChildren: QueryList<TextDirective>;
|
@ViewChildren('q,w', {read: TextDirective}) textDirChildren: QueryList<TextDirective>;
|
||||||
@ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar: QueryList<TextDirective>;
|
@ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar: QueryList<TextDirective>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue