fix(language-service): Resolve template variable in nested ngFor (#33676)

This commit fixes a bug whereby template variables in nested scope are
not resolved properly and instead are simply typed as `any`.

PR closes https://github.com/angular/vscode-ng-language-service/issues/144

PR Close #33676
This commit is contained in:
Keen Yee Liau
2019-11-06 10:32:45 -08:00
committed by Kara Erickson
parent 72796b98b1
commit 66157436f8
4 changed files with 102 additions and 45 deletions

View File

@ -283,6 +283,20 @@ describe('completions', () => {
const completions = ngLS.getCompletionsAt(PARSING_CASES, marker.start);
expectContain(completions, CompletionKind.PROPERTY, ['name', 'age', 'street']);
});
it('should be able to resolve variable in nested loop', () => {
mockHost.override(TEST_TEMPLATE, `
<div *ngFor="let leagueMembers of league">
<div *ngFor="let member of leagueMembers">
{{member.~{position}}}
</div>
</div>
`);
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'position');
const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start);
// member variable of type Hero has properties 'id' and 'name'.
expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']);
});
});
describe('data binding', () => {

View File

@ -173,6 +173,23 @@ describe('diagnostics', () => {
expect(diagnostics).toEqual([]);
});
it('should report diagnostic for invalid property in nested ngFor', () => {
const content = mockHost.override(TEST_TEMPLATE, `
<div *ngFor="let leagueMembers of league">
<div *ngFor="let member of leagueMembers">
{{member.xyz}}
</div>
</div>
`);
const diagnostics = ngLS.getDiagnostics(TEST_TEMPLATE);
expect(diagnostics.length).toBe(1);
const {messageText, start, length} = diagnostics[0];
expect(messageText)
.toBe(`Identifier 'xyz' is not defined. 'Hero' does not contain such a member`);
expect(start).toBe(content.indexOf('member.xyz'));
expect(length).toBe('member.xyz'.length);
});
describe('with $event', () => {
it('should accept an event', () => {
const fileName = '/app/test.ng';

View File

@ -189,6 +189,7 @@ export class TemplateReference {
title = 'Some title';
hero: Hero = {id: 1, name: 'Windstorm'};
heroes: Hero[] = [this.hero];
league: Hero[][] = [this.heroes];
anyValue: any;
myClick(event: any) {}
}