refactor(language-service): Avoid leaking host outside of LanguageService (#34941)
As part of the effort to tighten the API surface of `TypeScriptServiceHost` in preparation for the migration to Ivy, I realized some recently added APIs are not strictly needed. They can be safely removed without sacrificing functionality. This allows us to clean up the code, especially in the implementation of QuickInfo, where the `TypeScriptServiceHost` is leaked outside of the `LanguageService` class. This refactoring also cleans up some duplicate code where the QuickInfo object is generated. The logic is now consolidated into a simple `createQuickInfo` method shared across two different implementations. PR Close #34941
This commit is contained in:

committed by
Andrew Kushnir

parent
b890d10fc6
commit
49d68730f6
@ -89,31 +89,24 @@ describe('hover', () => {
|
||||
});
|
||||
|
||||
it('should be able to find a reference to a component', () => {
|
||||
const fileName = mockHost.addCode(`
|
||||
@Component({
|
||||
template: '«<ᐱtestᐱ-comp></test-comp>»'
|
||||
})
|
||||
export class MyComponent { }`);
|
||||
const marker = mockHost.getDefinitionMarkerFor(fileName, 'test');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(component) AppModule.TestComponent: class');
|
||||
mockHost.override(TEST_TEMPLATE, '<~{cursor}test-comp></test-comp>');
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeDefined();
|
||||
const {displayParts, documentation} = quickInfo !;
|
||||
expect(toText(displayParts)).toBe('(component) AppModule.TestComponent: typeof TestComponent');
|
||||
expect(toText(documentation)).toBe('This Component provides the `test-comp` selector.');
|
||||
});
|
||||
|
||||
it('should be able to find a reference to a directive', () => {
|
||||
const fileName = mockHost.addCode(`
|
||||
@Component({
|
||||
template: '<test-comp «string-model»></test-comp>'
|
||||
})
|
||||
export class MyComponent { }`);
|
||||
const marker = mockHost.getReferenceMarkerFor(fileName, 'string-model');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(fileName, marker.start);
|
||||
expect(quickInfo).toBeTruthy();
|
||||
const {textSpan, displayParts} = quickInfo !;
|
||||
expect(textSpan).toEqual(marker);
|
||||
expect(toText(displayParts)).toBe('(directive) StringModel: typeof StringModel');
|
||||
const content = mockHost.override(TEST_TEMPLATE, `<div string-model~{cursor}></div>`);
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start);
|
||||
expect(quickInfo).toBeDefined();
|
||||
const {displayParts, textSpan} = quickInfo !;
|
||||
expect(toText(displayParts)).toBe('(directive) AppModule.StringModel: typeof StringModel');
|
||||
expect(content.substring(textSpan.start, textSpan.start + textSpan.length))
|
||||
.toBe('string-model');
|
||||
});
|
||||
|
||||
it('should be able to find an event provider', () => {
|
||||
|
@ -176,51 +176,4 @@ describe('TypeScriptServiceHost', () => {
|
||||
// files have changed.
|
||||
expect(newModules).toBe(oldModules);
|
||||
});
|
||||
|
||||
it('should get the correct StaticSymbol for a Directive', () => {
|
||||
const tsLSHost = new MockTypescriptHost(['/app/app.component.ts', '/app/main.ts']);
|
||||
const tsLS = ts.createLanguageService(tsLSHost);
|
||||
const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS);
|
||||
ngLSHost.getAnalyzedModules(); // modules are analyzed lazily
|
||||
const sf = ngLSHost.getSourceFile('/app/app.component.ts');
|
||||
expect(sf).toBeDefined();
|
||||
const directiveDecl = sf !.forEachChild(n => {
|
||||
if (ts.isClassDeclaration(n) && n.name && n.name.text === 'AppComponent') return n;
|
||||
});
|
||||
|
||||
expect(directiveDecl).toBeDefined();
|
||||
expect(directiveDecl !.name).toBeDefined();
|
||||
const fileName = directiveDecl !.getSourceFile().fileName;
|
||||
const symbolName = directiveDecl !.name !.getText();
|
||||
const directiveSymbol = ngLSHost.getStaticSymbol(fileName, symbolName);
|
||||
expect(directiveSymbol).toBeDefined();
|
||||
expect(directiveSymbol !.name).toBe('AppComponent');
|
||||
});
|
||||
|
||||
it('should allow for retreiving analyzedModules in synchronized mode', () => {
|
||||
const fileName = '/app/app.component.ts';
|
||||
const tsLSHost = new MockTypescriptHost([fileName]);
|
||||
const tsLS = ts.createLanguageService(tsLSHost);
|
||||
const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS);
|
||||
|
||||
// Get initial state
|
||||
const originalModules = ngLSHost.getAnalyzedModules();
|
||||
|
||||
// Override app.component.ts with a different component
|
||||
tsLSHost.override(fileName, `
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
template: '<div>Hello!</div>',
|
||||
})
|
||||
export class HelloComponent {}
|
||||
`);
|
||||
// Make sure synchronized modules match the original state
|
||||
const syncModules = ngLSHost.getAnalyzedModules(false);
|
||||
expect(originalModules).toEqual(syncModules);
|
||||
|
||||
// Now, get modules for the updated project, which should not be synchronized
|
||||
const updatedModules = ngLSHost.getAnalyzedModules();
|
||||
expect(updatedModules).not.toEqual(syncModules);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user