| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {createLanguageService} from '../src/language_service'; | 
					
						
							|  |  |  | import {TypeScriptServiceHost} from '../src/typescript_host'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | import {MockTypescriptHost} from './test_utils'; | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-04 11:30:14 +08:00
										 |  |  | const TEST_TEMPLATE = '/app/test.ng'; | 
					
						
							| 
									
										
										
										
											2020-01-14 18:54:40 -08:00
										 |  |  | const PARSING_CASES = '/app/parsing-cases.ts'; | 
					
						
							| 
									
										
										
										
											2020-01-04 11:30:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | describe('definitions', () => { | 
					
						
							| 
									
										
										
										
											2019-10-16 12:00:41 -07:00
										 |  |  |   const mockHost = new MockTypescriptHost(['/app/main.ts']); | 
					
						
							|  |  |  |   const service = ts.createLanguageService(mockHost); | 
					
						
							|  |  |  |   const ngHost = new TypeScriptServiceHost(mockHost, service); | 
					
						
							|  |  |  |   const ngService = createLanguageService(ngHost); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     mockHost.reset(); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find field in an interpolation', () => { | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         template: '{{«name»}}' | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { | 
					
						
							|  |  |  |         «ᐱnameᐱ: string;» | 
					
						
							|  |  |  |       }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(textSpan).toEqual(marker); | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(def.fileName).toBe(fileName); | 
					
						
							|  |  |  |     expect(def.name).toBe('name'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('property'); | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     expect(def.textSpan).toEqual(mockHost.getDefinitionMarkerFor(fileName, 'name')); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find a field in a attribute reference', () => { | 
					
						
							| 
									
										
										
										
											2020-01-14 18:54:40 -08:00
										 |  |  |     mockHost.override(TEST_TEMPLATE, `<input [(ngModel)]="«title»">`); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-14 18:54:40 -08:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); | 
					
						
							|  |  |  |     const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(textSpan).toEqual(marker); | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2020-01-27 08:13:37 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(def.fileName).toBe(PARSING_CASES); | 
					
						
							|  |  |  |     expect(def.name).toBe('title'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('property'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const fileContent = mockHost.readFile(def.fileName); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(fileContent!.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) | 
					
						
							| 
									
										
										
										
											2020-01-27 08:13:37 -08:00
										 |  |  |         .toEqual(`title = 'Some title';`); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find a method from a call', () => { | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       @Component({ | 
					
						
							| 
									
										
										
										
											2020-04-27 18:54:30 -07:00
										 |  |  |         template: '<div (click)="«myClick»();"></div>' | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { | 
					
						
							|  |  |  |         «ᐱmyClickᐱ() { }» | 
					
						
							|  |  |  |       }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'myClick'); | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:54:30 -07:00
										 |  |  |     expect(textSpan).toEqual(marker); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(def.fileName).toBe(fileName); | 
					
						
							|  |  |  |     expect(def.name).toBe('myClick'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('method'); | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     expect(def.textSpan).toEqual(mockHost.getDefinitionMarkerFor(fileName, 'myClick')); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find a field reference in an *ngIf', () => { | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         template: '<div *ngIf="«include»"></div>' | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { | 
					
						
							|  |  |  |         «ᐱincludeᐱ = true;» | 
					
						
							|  |  |  |       }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'include'); | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(textSpan).toEqual(marker); | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(def.fileName).toBe(fileName); | 
					
						
							|  |  |  |     expect(def.name).toBe('include'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('property'); | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     expect(def.textSpan).toEqual(mockHost.getDefinitionMarkerFor(fileName, 'include')); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find a reference to a component', () => { | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         template: '~{start-my}<«test-comp»></test-comp>~{end-my}' | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Get the marker for «test-comp» in the code added above.
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'test-comp'); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Get the marker for bounded text in the code added above.
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(textSpan).toEqual(boundedText); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // There should be exactly 1 definition
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const refFileName = '/app/parsing-cases.ts'; | 
					
						
							|  |  |  |     expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |     expect(def.name).toBe('TestComponent'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('component'); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const content = mockHost.readFile(refFileName)!; | 
					
						
							| 
									
										
										
										
											2019-09-12 15:20:54 -07:00
										 |  |  |     const begin = '/*BeginTestComponent*/ '; | 
					
						
							|  |  |  |     const start = content.indexOf(begin) + begin.length; | 
					
						
							|  |  |  |     const end = content.indexOf(' /*EndTestComponent*/'); | 
					
						
							|  |  |  |     expect(def.textSpan).toEqual({ | 
					
						
							|  |  |  |       start, | 
					
						
							|  |  |  |       length: end - start, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find an event provider', () => { | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         template: '<test-comp ~{start-my}(«test»)="myHandler()"~{end-my}></div>' | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { myHandler() {} }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Get the marker for «test» in the code added above.
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'test'); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Get the marker for bounded text in the code added above
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(textSpan).toEqual(boundedText); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // There should be exactly 1 definition
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const refFileName = '/app/parsing-cases.ts'; | 
					
						
							|  |  |  |     expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |     expect(def.name).toBe('testEvent'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('event'); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const content = mockHost.readFile(refFileName)!; | 
					
						
							| 
									
										
										
										
											2019-09-12 15:20:54 -07:00
										 |  |  |     const ref = `@Output('test') testEvent = new EventEmitter();`; | 
					
						
							|  |  |  |     expect(def.textSpan).toEqual({ | 
					
						
							|  |  |  |       start: content.indexOf(ref), | 
					
						
							|  |  |  |       length: ref.length, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find an input provider', () => { | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       @Component({ | 
					
						
							|  |  |  |         template: '<test-comp ~{start-my}[«tcName»]="name"~{end-my}></div>' | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { | 
					
						
							|  |  |  |         name = 'my name'; | 
					
						
							|  |  |  |       }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Get the marker for «test» in the code added above.
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'tcName'); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Get the marker for bounded text in the code added above
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(textSpan).toEqual(boundedText); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // There should be exactly 1 definition
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const refFileName = '/app/parsing-cases.ts'; | 
					
						
							|  |  |  |     expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |     expect(def.name).toBe('name'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('property'); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const content = mockHost.readFile(refFileName)!; | 
					
						
							| 
									
										
										
										
											2019-09-12 15:20:54 -07:00
										 |  |  |     const ref = `@Input('tcName') name = 'test';`; | 
					
						
							|  |  |  |     expect(def.textSpan).toEqual({ | 
					
						
							|  |  |  |       start: content.indexOf(ref), | 
					
						
							|  |  |  |       length: ref.length, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find a pipe', () => { | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       @Component({ | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  |         template: '<div *ngIf="input | «async»"></div>' | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { | 
					
						
							|  |  |  |         input: EventEmitter; | 
					
						
							|  |  |  |       }`);
 | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  |     // Get the marker for «async» in the code added above.
 | 
					
						
							| 
									
										
										
										
											2019-08-28 12:55:12 -07:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'async'); | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  |     expect(textSpan).toEqual(marker); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(4); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const refFileName = '/node_modules/@angular/common/common.d.ts'; | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     for (const def of definitions!) { | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |       expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |       expect(def.name).toBe('async'); | 
					
						
							|  |  |  |       expect(def.kind).toBe('pipe'); | 
					
						
							|  |  |  |       // Not asserting the textSpan of definition because it's external file
 | 
					
						
							| 
									
										
										
										
											2016-11-22 09:10:23 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-09-01 09:58:14 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  |   // https://github.com/angular/vscode-ng-language-service/issues/677
 | 
					
						
							|  |  |  |   it('should be able to find a pipe with arguments', () => { | 
					
						
							|  |  |  |     mockHost.override(TEST_TEMPLATE, `{{birthday | «date»: "MM/dd/yy"}}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'date'); | 
					
						
							|  |  |  |     const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  |     expect(textSpan).toEqual(marker); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const refFileName = '/node_modules/@angular/common/common.d.ts'; | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     for (const def of definitions!) { | 
					
						
							| 
									
										
										
										
											2020-03-09 22:16:08 -07:00
										 |  |  |       expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |       expect(def.name).toBe('date'); | 
					
						
							|  |  |  |       expect(def.kind).toBe('pipe'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |   describe('in structural directive', () => { | 
					
						
							|  |  |  |     it('should be able to find the directive', () => { | 
					
						
							|  |  |  |       mockHost.override( | 
					
						
							|  |  |  |           TEST_TEMPLATE, `<div ~{start-my}*«ngFor»="let item of heroes;"~{end-my}></div>`); | 
					
						
							| 
									
										
										
										
											2019-12-26 15:19:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       // Get the marker for ngFor in the code added above.
 | 
					
						
							|  |  |  |       const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'ngFor'); | 
					
						
							| 
									
										
										
										
											2019-12-26 15:19:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); | 
					
						
							|  |  |  |       expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-12-26 15:19:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       // Get the marker for bounded text in the code added above
 | 
					
						
							|  |  |  |       const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); | 
					
						
							|  |  |  |       expect(textSpan).toEqual(boundedText); | 
					
						
							| 
									
										
										
										
											2019-12-26 15:19:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       expect(definitions!.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2019-12-26 15:19:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       const refFileName = '/node_modules/@angular/common/common.d.ts'; | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |       expect(def.name).toBe('NgForOf'); | 
					
						
							|  |  |  |       expect(def.kind).toBe('directive'); | 
					
						
							|  |  |  |       // Not asserting the textSpan of definition because it's external file
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to find the directive property', () => { | 
					
						
							| 
									
										
										
										
											2020-03-05 15:38:25 -08:00
										 |  |  |       mockHost.override(TEST_TEMPLATE, `<div *ngFor="let item of heroes; «trackBy»: test;"></div>`); | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // Get the marker for trackBy in the code added above.
 | 
					
						
							|  |  |  |       const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'trackBy'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); | 
					
						
							|  |  |  |       expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // Get the marker for bounded text in the code added above
 | 
					
						
							| 
									
										
										
										
											2020-03-05 15:38:25 -08:00
										 |  |  |       expect(textSpan).toEqual(marker); | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       expect(definitions).toBeDefined(); | 
					
						
							|  |  |  |       // The two definitions are setter and getter of 'ngForTrackBy'.
 | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       expect(definitions!.length).toBe(2); | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const refFileName = '/node_modules/@angular/common/common.d.ts'; | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       definitions!.forEach(def => { | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |         expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |         expect(def.name).toBe('ngForTrackBy'); | 
					
						
							|  |  |  |         expect(def.kind).toBe('method'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       // Not asserting the textSpan of definition because it's external file
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should be able to find the property value', () => { | 
					
						
							|  |  |  |       mockHost.override(TEST_TEMPLATE, `<div *ngFor="let item of «heroes»; trackBy: test;"></div>`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Get the marker for heroes in the code added above.
 | 
					
						
							|  |  |  |       const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'heroes'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); | 
					
						
							|  |  |  |       expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       expect(textSpan).toEqual(marker); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       expect(definitions!.length).toBe(1); | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const refFileName = '/app/parsing-cases.ts'; | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       expect(def.fileName).toBe(refFileName); | 
					
						
							|  |  |  |       expect(def.name).toBe('heroes'); | 
					
						
							|  |  |  |       expect(def.kind).toBe('property'); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |       const content = mockHost.readFile(refFileName)!; | 
					
						
							| 
									
										
										
										
											2020-01-17 18:11:23 +08:00
										 |  |  |       expect(content.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) | 
					
						
							|  |  |  |           .toEqual(`heroes: Hero[] = [this.hero];`); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-12-26 15:19:38 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  |   it('should be able to find a two-way binding', () => { | 
					
						
							| 
									
										
										
										
											2020-01-04 11:30:14 +08:00
										 |  |  |     mockHost.override( | 
					
						
							|  |  |  |         TEST_TEMPLATE, | 
					
						
							|  |  |  |         `<test-comp string-model ~{start-my}[(«model»)]="title"~{end-my}></test-comp>`); | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  |     // Get the marker for «model» in the code added above.
 | 
					
						
							| 
									
										
										
										
											2020-01-04 11:30:14 +08:00
										 |  |  |     const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'model'); | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Get the marker for bounded text in the code added above
 | 
					
						
							| 
									
										
										
										
											2020-01-04 11:30:14 +08:00
										 |  |  |     const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  |     expect(textSpan).toEqual(boundedText); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(2); | 
					
						
							|  |  |  |     const [def1, def2] = definitions!; | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const refFileName = '/app/parsing-cases.ts'; | 
					
						
							| 
									
										
										
										
											2020-01-14 18:54:40 -08:00
										 |  |  |     expect(def1.fileName).toBe(refFileName); | 
					
						
							|  |  |  |     expect(def1.name).toBe('model'); | 
					
						
							|  |  |  |     expect(def1.kind).toBe('property'); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     let content = mockHost.readFile(refFileName)!; | 
					
						
							| 
									
										
										
										
											2020-01-14 18:54:40 -08:00
										 |  |  |     expect(content.substring(def1.textSpan.start, def1.textSpan.start + def1.textSpan.length)) | 
					
						
							| 
									
										
										
										
											2020-01-06 10:37:49 +08:00
										 |  |  |         .toEqual(`@Input() model: string = 'model';`); | 
					
						
							| 
									
										
										
										
											2020-01-14 18:54:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(def2.fileName).toBe(refFileName); | 
					
						
							|  |  |  |     expect(def2.name).toBe('modelChange'); | 
					
						
							|  |  |  |     expect(def2.kind).toBe('event'); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     content = mockHost.readFile(refFileName)!; | 
					
						
							| 
									
										
										
										
											2020-01-14 18:54:40 -08:00
										 |  |  |     expect(content.substring(def2.textSpan.start, def2.textSpan.start + def2.textSpan.length)) | 
					
						
							|  |  |  |         .toEqual(`@Output() modelChange: EventEmitter<string> = new EventEmitter();`); | 
					
						
							| 
									
										
										
										
											2020-01-03 18:32:30 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-01 09:58:14 -05:00
										 |  |  |   it('should be able to find a template from a url', () => { | 
					
						
							|  |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							|  |  |  | 	      @Component({ | 
					
						
							|  |  |  | 	        templateUrl: './«test».ng', | 
					
						
							|  |  |  | 	      }) | 
					
						
							|  |  |  | 	      export class MyComponent {}`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'test'); | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-09-01 09:58:14 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-09-01 09:58:14 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(textSpan).toEqual({start: marker.start - 2, length: 9}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const [def] = definitions!; | 
					
						
							| 
									
										
										
										
											2019-09-01 09:58:14 -05:00
										 |  |  |     expect(def.fileName).toBe('/app/test.ng'); | 
					
						
							|  |  |  |     expect(def.textSpan).toEqual({start: 0, length: 0}); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-09-01 09:56:29 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should be able to find a stylesheet from a url', () => { | 
					
						
							|  |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							|  |  |  | 	      @Component({ | 
					
						
							|  |  |  | 	        templateUrl: './test.ng', | 
					
						
							|  |  |  |                 styleUrls: ['./«test».css'], | 
					
						
							|  |  |  | 	      }) | 
					
						
							|  |  |  | 	      export class MyComponent {}`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'test'); | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-09-01 09:56:29 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-09-01 09:56:29 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(textSpan).toEqual({start: marker.start - 2, length: 10}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const [def] = definitions!; | 
					
						
							| 
									
										
										
										
											2019-09-01 09:56:29 -05:00
										 |  |  |     expect(def.fileName).toBe('/app/test.css'); | 
					
						
							|  |  |  |     expect(def.textSpan).toEqual({start: 0, length: 0}); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-12-21 19:23:09 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   it('should not expand i18n templates', () => { | 
					
						
							|  |  |  |     const fileName = mockHost.addCode(`
 | 
					
						
							|  |  |  |       @Component({ | 
					
						
							|  |  |  |         template: '<div i18n="@@el">{{«name»}}</div>' | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       export class MyComponent { | 
					
						
							|  |  |  |         «ᐱnameᐱ: string;» | 
					
						
							|  |  |  |       }`);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); | 
					
						
							| 
									
										
										
										
											2020-01-21 14:51:43 -08:00
										 |  |  |     const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); | 
					
						
							| 
									
										
										
										
											2019-12-21 19:23:09 -06:00
										 |  |  |     expect(result).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     const {textSpan, definitions} = result!; | 
					
						
							| 
									
										
										
										
											2019-12-21 19:23:09 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(textSpan).toEqual(marker); | 
					
						
							|  |  |  |     expect(definitions).toBeDefined(); | 
					
						
							| 
									
										
										
										
											2020-04-03 20:57:39 -07:00
										 |  |  |     expect(definitions!.length).toBe(1); | 
					
						
							|  |  |  |     const def = definitions![0]; | 
					
						
							| 
									
										
										
										
											2019-12-21 19:23:09 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     expect(def.fileName).toBe(fileName); | 
					
						
							|  |  |  |     expect(def.name).toBe('name'); | 
					
						
							|  |  |  |     expect(def.kind).toBe('property'); | 
					
						
							|  |  |  |     expect(def.textSpan).toEqual(mockHost.getDefinitionMarkerFor(fileName, 'name')); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2019-08-01 13:07:32 -07:00
										 |  |  | }); |