fix(compiler): report better error on interpolation in an expression (#30300)

Compiler results in weird error message when encounters interpolation inside
existing expression context, e.g. *ngIf="name {{ name }}"

PR Close #30300
This commit is contained in:
Krzysztof Grzybek 2019-05-07 17:50:44 +02:00 committed by Jessica Janiuk
parent 23c36a24ed
commit 94e790d4ee
2 changed files with 23 additions and 6 deletions

View File

@ -974,7 +974,8 @@ export class _ParseAST {
} else { } else {
// Otherwise the key must be a directive keyword, like "of". Transform // Otherwise the key must be a directive keyword, like "of". Transform
// the key to actual key. Eg. of -> ngForOf, trackBy -> ngForTrackBy // the key to actual key. Eg. of -> ngForOf, trackBy -> ngForTrackBy
key.source = templateKey.source + key.source[0].toUpperCase() + key.source.substring(1); key.source =
templateKey.source + key.source.charAt(0).toUpperCase() + key.source.substring(1);
bindings.push(...this.parseDirectiveKeywordBindings(key)); bindings.push(...this.parseDirectiveKeywordBindings(key));
} }
} }

View File

@ -779,6 +779,14 @@ describe('parser', () => {
]); ]);
}); });
it('should report unexpected token when encountering interpolation', () => {
const attr = '*ngIf="name && {{name}}"';
expectParseTemplateBindingsError(
attr,
'Parser Error: Unexpected token {, expected identifier, keyword, or string at column 10 in [name && {{name}}] in foo.html');
});
it('should map variable declaration via "as"', () => { it('should map variable declaration via "as"', () => {
const attr = const attr =
'*ngFor="let item; of items | slice:0:1 as collection, trackBy: func; index as i"'; '*ngFor="let item; of items | slice:0:1 as collection, trackBy: func; index as i"';
@ -1026,17 +1034,25 @@ function parseBinding(text: string, location: any = null, offset: number = 0): A
} }
function parseTemplateBindings(attribute: string, templateUrl = 'foo.html'): TemplateBinding[] { function parseTemplateBindings(attribute: string, templateUrl = 'foo.html'): TemplateBinding[] {
const result = _parseTemplateBindings(attribute, templateUrl);
expect(result.errors).toEqual([]);
expect(result.warnings).toEqual([]);
return result.templateBindings;
}
function expectParseTemplateBindingsError(attribute: string, error: string) {
const result = _parseTemplateBindings(attribute, 'foo.html');
expect(result.errors[0].message).toEqual(error);
}
function _parseTemplateBindings(attribute: string, templateUrl: string) {
const match = attribute.match(/^\*(.+)="(.*)"$/); const match = attribute.match(/^\*(.+)="(.*)"$/);
expect(match).toBeTruthy(`failed to extract key and value from ${attribute}`); expect(match).toBeTruthy(`failed to extract key and value from ${attribute}`);
const [_, key, value] = match; const [_, key, value] = match;
const absKeyOffset = 1; // skip the * prefix const absKeyOffset = 1; // skip the * prefix
const absValueOffset = attribute.indexOf('=') + '="'.length; const absValueOffset = attribute.indexOf('=') + '="'.length;
const parser = createParser(); const parser = createParser();
const result = return parser.parseTemplateBindings(key, value, templateUrl, absKeyOffset, absValueOffset);
parser.parseTemplateBindings(key, value, templateUrl, absKeyOffset, absValueOffset);
expect(result.errors).toEqual([]);
expect(result.warnings).toEqual([]);
return result.templateBindings;
} }
function parseInterpolation(text: string, location: any = null, offset: number = 0): ASTWithSource| function parseInterpolation(text: string, location: any = null, offset: number = 0): ASTWithSource|