Keen Yee Liau c365eded5b fix(language-service): Remove getTemplateReferences() from LanguageService API (#33807)
The method `getTemplateReferences()` appears in both the LanguageService
interface and LanguageServiceHost interface. It should belong in the
latter and not the former, since the former deals with the semantics of
the language and not the mechanics.

PR Close #33807
2019-11-15 10:41:51 -08:00

107 lines
3.8 KiB
TypeScript

/**
* @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 tss from 'typescript/lib/tsserverlibrary';
import {isAstResult} from './common';
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 {TypeScriptServiceHost} from './typescript_host';
/**
* Create an instance of an Angular `LanguageService`.
*
* @publicApi
*/
export function createLanguageService(host: TypeScriptServiceHost): LanguageService {
return new LanguageServiceImpl(host);
}
class LanguageServiceImpl implements LanguageService {
constructor(private readonly host: TypeScriptServiceHost) {}
getDiagnostics(fileName: string): tss.Diagnostic[] {
const analyzedModules = this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const results: Diagnostic[] = [];
const templates = this.host.getTemplates(fileName);
for (const template of templates) {
const astOrDiagnostic = this.host.getTemplateAst(template);
if (isAstResult(astOrDiagnostic)) {
results.push(...getTemplateDiagnostics(astOrDiagnostic));
} else {
results.push(astOrDiagnostic);
}
}
const declarations = this.host.getDeclarations(fileName);
if (declarations && declarations.length) {
results.push(...getDeclarationDiagnostics(declarations, analyzedModules, this.host));
}
const sourceFile = fileName.endsWith('.ts') ? this.host.getSourceFile(fileName) : undefined;
return uniqueBySpan(results).map(d => ngDiagnosticToTsDiagnostic(d, sourceFile));
}
getCompletionsAt(fileName: string, position: number): tss.CompletionInfo|undefined {
this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const ast = this.host.getTemplateAstAtPosition(fileName, position);
if (!ast) {
return;
}
const results = getTemplateCompletions(ast, position);
if (!results || !results.length) {
return;
}
return {
isGlobalCompletion: false,
isMemberCompletion: false,
isNewIdentifierLocation: false,
// Cast CompletionEntry.kind from ng.CompletionKind to ts.ScriptElementKind
entries: results as unknown as ts.CompletionEntry[],
};
}
getDefinitionAt(fileName: string, position: number): tss.DefinitionInfoAndBoundSpan|undefined {
this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
if (templateInfo) {
return getDefinitionAndBoundSpan(templateInfo, position);
}
// Attempt to get Angular-specific definitions in a TypeScript file, like templates defined
// in a `templateUrl` property.
if (fileName.endsWith('.ts')) {
const sf = this.host.getSourceFile(fileName);
if (sf) {
return getTsDefinitionAndBoundSpan(sf, position, this.host.tsLsHost);
}
}
}
getHoverAt(fileName: string, position: number): tss.QuickInfo|undefined {
this.host.getAnalyzedModules(); // same role as 'synchronizeHostData'
const templateInfo = this.host.getTemplateAstAtPosition(fileName, position);
if (templateInfo) {
return getHover(templateInfo, position, this.host);
}
// Attempt to get Angular-specific hover information in a TypeScript file, the NgModule a
// directive belongs to.
if (fileName.endsWith('.ts')) {
const sf = this.host.getSourceFile(fileName);
if (sf) {
return getTsHover(sf, position, this.host);
}
}
}
}