fix(language-service): correctly parse expressions in an attribute (#34517)
Currently, the language service provides completions in a template node attribute by first checking if the attribute contains template bindings to provide completions for, and then providing completions for the expression in the attribute. In the latter case, the expression AST was being constructed "synthetically" inside the language service, in particular declaring the expression to be a `PropertyRead` with an implicit receiver. Unfortunately, this AST can be incorrect if the expression is actually a property read on a component property receiver (e.g. when reading `key` in the expression `obj.key`, `obj` is the receiver). The fix is pretty simple - rather than a synthetic construction of the AST, ask the expression parser to parse the expression in the attribute. Fixes https://github.com/angular/vscode-ng-language-service/issues/523 PR Close #34517
This commit is contained in:

committed by
Alex Rickabaugh

parent
166009584f
commit
7a0d6e7cba
@ -320,6 +320,13 @@ describe('completions', () => {
|
||||
expectContain(completions, CompletionKind.VARIABLE, ['x']);
|
||||
});
|
||||
|
||||
it('should include expression completions', () => {
|
||||
mockHost.override(TEST_TEMPLATE, `<div *ngFor="let x of hero.~{expr-property-read}"></div>`);
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'expr-property-read');
|
||||
const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start);
|
||||
expectContain(completions, CompletionKind.PROPERTY, ['name']);
|
||||
});
|
||||
|
||||
it('should include variable in the let scope in interpolation', () => {
|
||||
mockHost.override(TEST_TEMPLATE, `
|
||||
<div *ngFor="let h of heroes">
|
||||
@ -370,6 +377,13 @@ describe('completions', () => {
|
||||
expectContain(completions, CompletionKind.PROPERTY, ['test']);
|
||||
});
|
||||
|
||||
it('should be able to complete property read', () => {
|
||||
mockHost.override(TEST_TEMPLATE, `<h1 [model]="hero.~{property-read}"></h1>`);
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'property-read');
|
||||
const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start);
|
||||
expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']);
|
||||
});
|
||||
|
||||
it('should be able to complete an event', () => {
|
||||
const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'event-binding-model');
|
||||
const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start);
|
||||
@ -471,6 +485,16 @@ describe('completions', () => {
|
||||
expectContain(completions, CompletionKind.PROPERTY, ['name', 'testEvent']);
|
||||
});
|
||||
|
||||
it('should get reference property completions in a data binding', () => {
|
||||
mockHost.override(TEST_TEMPLATE, `
|
||||
<test-comp #test></test-comp>
|
||||
<div (click)="test.~{property-read}"></div>
|
||||
`);
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'property-read');
|
||||
const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start);
|
||||
expectContain(completions, CompletionKind.PROPERTY, ['name', 'testEvent']);
|
||||
});
|
||||
|
||||
// TODO: Enable when we have a flag that indicates the project targets the DOM
|
||||
// it('should reference the element if no component', () => {
|
||||
// const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'test-comp-after-div');
|
||||
|
Reference in New Issue
Block a user