fix(compiler): report errors for missing binding names (#34595)

Currently, would-be binding attributes that are missing binding names
are not parsed as bindings, and fall through as regular attributes. In
some cases, this can lead to a runtime error; trying to assign `#` as a
DOM attribute in an element like in `<div #></div>` fails because `#` is
not a valid attribute name.

Attributes composed of binding prefixes but not defining a binding
should be considered invalid, as this almost certainly indicates an
unintentional elision of a binding by the developer. This commit
introduces error reporting for attributes with a binding name prefix but
no actual binding name.

Closes https://github.com/angular/vscode-ng-language-service/issues/293.

PR Close #34595
This commit is contained in:
ayazhafiz
2019-12-28 18:02:09 -06:00
committed by Kara Erickson
parent e1160f19be
commit a92d97cda7
5 changed files with 92 additions and 2 deletions

View File

@ -167,6 +167,10 @@ describe('R3 template transform', () => {
]);
});
it('should report missing property names in bind- syntax', () => {
expect(() => parse('<div bind-></div>')).toThrowError(/Property name is missing in binding/);
});
it('should parse bound properties via {{...}}', () => {
expectFromHtml('<div prop="{{v}}"></div>').toEqual([
['Element', 'div'],
@ -339,6 +343,10 @@ describe('R3 template transform', () => {
]);
});
it('should report missing event names in on- syntax', () => {
expect(() => parse('<div on-></div>')).toThrowError(/Event name is missing in binding/);
});
it('should parse bound events and properties via [(...)]', () => {
expectFromHtml('<div [(prop)]="v"></div>').toEqual([
['Element', 'div'],
@ -355,12 +363,29 @@ describe('R3 template transform', () => {
]);
});
it('should report missing property names in bindon- syntax', () => {
expect(() => parse('<div bindon-></div>'))
.toThrowError(/Property name is missing in binding/);
});
it('should report an error on empty expression', () => {
expect(() => parse('<div (event)="">')).toThrowError(/Empty expressions are not allowed/);
expect(() => parse('<div (event)=" ">')).toThrowError(/Empty expressions are not allowed/);
});
});
describe('variables', () => {
it('should report variables not on template elements', () => {
expect(() => parse('<div let-a-name="b"></div>'))
.toThrowError(/"let-" is only supported on ng-template elements./);
});
it('should report missing variable names', () => {
expect(() => parse('<ng-template let-><ng-template>'))
.toThrowError(/Variable does not have a name/);
});
});
describe('references', () => {
it('should parse references via #...', () => {
expectFromHtml('<div #a></div>').toEqual([
@ -382,6 +407,20 @@ describe('R3 template transform', () => {
['Reference', 'someA', ''],
]);
});
it('should report invalid reference names', () => {
expect(() => parse('<div #a-b></div>')).toThrowError(/"-" is not allowed in reference names/);
});
it('should report missing reference names', () => {
expect(() => parse('<div #></div>')).toThrowError(/Reference does not have a name/);
});
});
describe('literal attribute', () => {
it('should report missing animation trigger in @ syntax', () => {
expect(() => parse('<div @></div>')).toThrowError(/Animation trigger is missing/);
});
});
describe('ng-content', () => {