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
107 lines
3.8 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|
|
}
|