refactor(language-service): Consistent naming between ts and ng LanguageService (#34888)

This commit makes the Angular Language Service interface a strict subset
of TypeScript's Language Service by renaming all methods to be
consistent with TypeScript's.

The custom Angular `LanguageService` interface was needed before the
inception of TypeScript tsserver plugin, but is now obsolete since
Angular LS is a proper tsserver plugin.

This allows us to easily adapt to upstream TS changes in the future, and
also allows us to reuse all data types defined in TypeScript.

PR Close #34888
This commit is contained in:
Keen Yee Liau
2020-01-21 14:51:43 -08:00
committed by Matias Niemelä
parent 84d24c08e1
commit f723a27a71
8 changed files with 189 additions and 221 deletions

View File

@ -12,7 +12,7 @@ import {getTemplateCompletions} from './completions';
import {getDefinitionAndBoundSpan, getTsDefinitionAndBoundSpan} from './definitions';
import {getDeclarationDiagnostics, getTemplateDiagnostics, ngDiagnosticToTsDiagnostic, uniqueBySpan} from './diagnostics';
import {getHover, getTsHover} from './hover';
import {Diagnostic, LanguageService} from './types';
import * as ng from './types';
import {TypeScriptServiceHost} from './typescript_host';
/**
@ -20,16 +20,16 @@ import {TypeScriptServiceHost} from './typescript_host';
*
* @publicApi
*/
export function createLanguageService(host: TypeScriptServiceHost): LanguageService {
export function createLanguageService(host: TypeScriptServiceHost) {
return new LanguageServiceImpl(host);
}
class LanguageServiceImpl implements LanguageService {
class LanguageServiceImpl implements ng.LanguageService {
constructor(private readonly host: TypeScriptServiceHost) {}
getDiagnostics(fileName: string): tss.Diagnostic[] {
getSemanticDiagnostics(fileName: string): tss.Diagnostic[] {
const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const results: Diagnostic[] = [];
const results: ng.Diagnostic[] = [];
const templates = this.host.getTemplates(fileName);
for (const template of templates) {
@ -48,7 +48,9 @@ class LanguageServiceImpl implements LanguageService {
return uniqueBySpan(results).map(d => ngDiagnosticToTsDiagnostic(d, sourceFile));
}
getCompletionsAt(fileName: string, position: number): tss.CompletionInfo|undefined {
getCompletionsAtPosition(
fileName: string, position: number,
options?: tss.GetCompletionsAtPositionOptions): tss.CompletionInfo|undefined {
this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const ast = this.host.getTemplateAstAtPosition(fileName, position);
if (!ast) {
@ -67,7 +69,8 @@ class LanguageServiceImpl implements LanguageService {
};
}
getDefinitionAt(fileName: string, position: number): tss.DefinitionInfoAndBoundSpan|undefined {
getDefinitionAndBoundSpan(fileName: string, position: number): tss.DefinitionInfoAndBoundSpan
|undefined {
this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
if (templateInfo) {
@ -84,7 +87,7 @@ class LanguageServiceImpl implements LanguageService {
}
}
getHoverAt(fileName: string, position: number): tss.QuickInfo|undefined {
getQuickInfoAtPosition(fileName: string, position: number): tss.QuickInfo|undefined {
this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
if (templateInfo) {

View File

@ -36,7 +36,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
return results;
}
}
return ngLS.getCompletionsAt(fileName, position);
return ngLS.getCompletionsAtPosition(fileName, position, options);
}
function getQuickInfoAtPosition(fileName: string, position: number): tss.QuickInfo|undefined {
@ -47,7 +47,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
return result;
}
}
return ngLS.getHoverAt(fileName, position);
return ngLS.getQuickInfoAtPosition(fileName, position);
}
function getSemanticDiagnostics(fileName: string): tss.Diagnostic[] {
@ -56,7 +56,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
results.push(...tsLS.getSemanticDiagnostics(fileName));
}
// For semantic diagnostics we need to combine both TS + Angular results
results.push(...ngLS.getDiagnostics(fileName));
results.push(...ngLS.getSemanticDiagnostics(fileName));
return results;
}
@ -69,7 +69,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
return results;
}
}
const result = ngLS.getDefinitionAt(fileName, position);
const result = ngLS.getDefinitionAndBoundSpan(fileName, position);
if (!result || !result.definitions || !result.definitions.length) {
return;
}
@ -85,7 +85,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
return result;
}
}
return ngLS.getDefinitionAt(fileName, position);
return ngLS.getDefinitionAndBoundSpan(fileName, position);
}
const proxy: tss.LanguageService = Object.assign(

View File

@ -7,7 +7,7 @@
*/
import {CompileDirectiveMetadata, NgAnalyzedModules, StaticSymbol} from '@angular/compiler';
import * as ts from 'typescript';
import {AstResult} from './common';
import {BuiltinType, DeclarationKind, Definition, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols';
@ -354,48 +354,12 @@ export interface Hover {
/**
* An instance of an Angular language service created by `createLanguageService()`.
*
* The language service returns information about Angular templates that are included in a project
* as defined by the `LanguageServiceHost`.
*
* When a method expects a `fileName` this file can either be source file in the project that
* contains a template in a string literal or a template file referenced by the project returned
* by `getTemplateReference()`. All other files will cause the method to return `undefined`.
*
* If a method takes a `position`, it is the offset of the UTF-16 code-point relative to the
* beginning of the file reference by `fileName`.
*
* This interface and all interfaces and types marked as `LanguageService` types, describe a
* particular implementation of the Angular language service and is not intended to be
* implemented. Adding members to the interface will not be considered a breaking change as
* defined by SemVer.
*
* Removing a member or making a member optional, changing a method parameters, or changing a
* member's type will all be considered a breaking change.
*
* While an interface is marked as experimental breaking-changes will be allowed between minor
* releases. After an interface is marked as stable breaking-changes will only be allowed between
* major releases. No breaking changes are allowed between patch releases.
* The Angular language service implements a subset of methods defined in
* The Angular language service implements a subset of methods defined by
* the TypeScript language service.
*
* @publicApi
*/
export interface LanguageService {
/**
* Returns a list of all error for all templates in the given file.
*/
getDiagnostics(fileName: string): ts.Diagnostic[];
/**
* Return the completions at the given position.
*/
getCompletionsAt(fileName: string, position: number): ts.CompletionInfo|undefined;
/**
* Return the definition location for the symbol at position.
*/
getDefinitionAt(fileName: string, position: number): ts.DefinitionInfoAndBoundSpan|undefined;
/**
* Return the hover information for the symbol at position.
*/
getHoverAt(fileName: string, position: number): ts.QuickInfo|undefined;
}
export type LanguageService = Pick<
ts.LanguageService, 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'|
'getQuickInfoAtPosition'|'getSemanticDiagnostics'>;