2020-04-29 18:08:22 -04: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
|
|
|
|
*/
|
|
|
|
|
2020-04-29 18:52:17 -04:00
|
|
|
import {CompilerOptions, createNgCompilerOptions} from '@angular/compiler-cli';
|
2020-04-29 18:08:22 -04:00
|
|
|
import * as ts from 'typescript/lib/tsserverlibrary';
|
2020-04-30 18:48:20 -04:00
|
|
|
import {Compiler} from './compiler/compiler';
|
2020-04-29 18:08:22 -04:00
|
|
|
|
|
|
|
export class LanguageService {
|
2020-04-29 18:52:17 -04:00
|
|
|
private options: CompilerOptions;
|
2020-04-30 18:48:20 -04:00
|
|
|
private readonly compiler: Compiler;
|
2020-04-29 18:52:17 -04:00
|
|
|
|
|
|
|
constructor(project: ts.server.Project, private readonly tsLS: ts.LanguageService) {
|
|
|
|
this.options = parseNgCompilerOptions(project);
|
|
|
|
this.watchConfigFile(project);
|
2020-04-30 18:48:20 -04:00
|
|
|
this.compiler = new Compiler(project, this.options);
|
2020-04-29 18:52:17 -04:00
|
|
|
}
|
2020-04-29 18:08:22 -04:00
|
|
|
|
|
|
|
getSemanticDiagnostics(fileName: string): ts.Diagnostic[] {
|
2020-04-30 18:48:20 -04:00
|
|
|
const program = this.compiler.analyze();
|
|
|
|
if (!program) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
const sourceFile = program.getSourceFile(fileName);
|
|
|
|
if (!sourceFile) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
return this.compiler.getDiagnostics(sourceFile);
|
2020-04-29 18:08:22 -04:00
|
|
|
}
|
2020-04-29 18:52:17 -04:00
|
|
|
|
|
|
|
private watchConfigFile(project: ts.server.Project) {
|
|
|
|
// TODO: Check the case when the project is disposed. An InferredProject
|
|
|
|
// could be disposed when a tsconfig.json is added to the workspace,
|
|
|
|
// in which case it becomes a ConfiguredProject (or vice-versa).
|
|
|
|
// We need to make sure that the FileWatcher is closed.
|
|
|
|
if (!(project instanceof ts.server.ConfiguredProject)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const {host} = project.projectService;
|
|
|
|
host.watchFile(
|
|
|
|
project.getConfigFilePath(), (fileName: string, eventKind: ts.FileWatcherEventKind) => {
|
|
|
|
project.log(`Config file changed: ${fileName}`);
|
|
|
|
if (eventKind === ts.FileWatcherEventKind.Changed) {
|
|
|
|
this.options = parseNgCompilerOptions(project);
|
2020-04-30 18:48:20 -04:00
|
|
|
this.compiler.setCompilerOptions(this.options);
|
2020-04-29 18:52:17 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function parseNgCompilerOptions(project: ts.server.Project): CompilerOptions {
|
|
|
|
let config = {};
|
|
|
|
if (project instanceof ts.server.ConfiguredProject) {
|
|
|
|
const configPath = project.getConfigFilePath();
|
|
|
|
const result = ts.readConfigFile(configPath, path => project.readFile(path));
|
|
|
|
if (result.error) {
|
|
|
|
project.error(ts.flattenDiagnosticMessageText(result.error.messageText, '\n'));
|
|
|
|
}
|
|
|
|
config = result.config || config;
|
|
|
|
}
|
|
|
|
const basePath = project.getCurrentDirectory();
|
|
|
|
return createNgCompilerOptions(basePath, config, project.getCompilationSettings());
|
2020-04-29 18:08:22 -04:00
|
|
|
}
|