diff --git a/packages/language-service/ivy/BUILD.bazel b/packages/language-service/ivy/BUILD.bazel index 849916eb81..1849b649f7 100644 --- a/packages/language-service/ivy/BUILD.bazel +++ b/packages/language-service/ivy/BUILD.bazel @@ -6,6 +6,7 @@ ts_library( name = "ivy", srcs = glob(["*.ts"]), deps = [ + "//packages/compiler-cli", "@npm//typescript", ], ) diff --git a/packages/language-service/ivy/language_service.ts b/packages/language-service/ivy/language_service.ts index 3c51444754..b9d258352a 100644 --- a/packages/language-service/ivy/language_service.ts +++ b/packages/language-service/ivy/language_service.ts @@ -6,12 +6,50 @@ * found in the LICENSE file at https://angular.io/license */ +import {CompilerOptions, createNgCompilerOptions} from '@angular/compiler-cli'; import * as ts from 'typescript/lib/tsserverlibrary'; export class LanguageService { - constructor(private readonly tsLS: ts.LanguageService) {} + private options: CompilerOptions; + + constructor(project: ts.server.Project, private readonly tsLS: ts.LanguageService) { + this.options = parseNgCompilerOptions(project); + this.watchConfigFile(project); + } getSemanticDiagnostics(fileName: string): ts.Diagnostic[] { return []; } + + 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); + } + }); + } +} + +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()); } diff --git a/packages/language-service/ivy/test/BUILD.bazel b/packages/language-service/ivy/test/BUILD.bazel index 2c70a5e70c..938725080a 100644 --- a/packages/language-service/ivy/test/BUILD.bazel +++ b/packages/language-service/ivy/test/BUILD.bazel @@ -5,6 +5,7 @@ ts_library( testonly = True, srcs = glob(["*.ts"]), deps = [ + "//packages/language-service/ivy", "@npm//typescript", ], ) diff --git a/packages/language-service/ivy/test/language_service_spec.ts b/packages/language-service/ivy/test/language_service_spec.ts new file mode 100644 index 0000000000..0363f1a504 --- /dev/null +++ b/packages/language-service/ivy/test/language_service_spec.ts @@ -0,0 +1,24 @@ +/** + * @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 {parseNgCompilerOptions} from '../language_service'; + +import {setup} from './mock_host'; + +const {project} = setup(); + +describe('parseNgCompilerOptions', () => { + it('should read angularCompilerOptions in tsconfig.json', () => { + const options = parseNgCompilerOptions(project); + expect(options).toEqual(jasmine.objectContaining({ + enableIvy: true, // default for ivy is true + fullTemplateTypeCheck: true, + strictInjectionParameters: true, + })); + }); +}); diff --git a/packages/language-service/ivy/ts_plugin.ts b/packages/language-service/ivy/ts_plugin.ts index 46ba8a49f9..053adbb2cf 100644 --- a/packages/language-service/ivy/ts_plugin.ts +++ b/packages/language-service/ivy/ts_plugin.ts @@ -10,10 +10,10 @@ import * as ts from 'typescript/lib/tsserverlibrary'; import {LanguageService} from './language_service'; export function create(info: ts.server.PluginCreateInfo): ts.LanguageService { - const {languageService: tsLS, config} = info; + const {project, languageService: tsLS, config} = info; const angularOnly = config?.angularOnly === true; - const ngLS = new LanguageService(tsLS); + const ngLS = new LanguageService(project, tsLS); function getSemanticDiagnostics(fileName: string): ts.Diagnostic[] { const diagnostics: ts.Diagnostic[] = [];