diff --git a/packages/language-service/ivy/language_service.ts b/packages/language-service/ivy/language_service.ts index 2a6903bf65..8d8989f958 100644 --- a/packages/language-service/ivy/language_service.ts +++ b/packages/language-service/ivy/language_service.ts @@ -242,9 +242,11 @@ function getOrCreateTypeCheckScriptInfo( // attempt to fetch the content from disk and fail. scriptInfo = projectService.getOrCreateScriptInfoForNormalizedPath( ts.server.toNormalizedPath(tcf), - true, // openedByClient - '', // fileContent - ts.ScriptKind.TS, // scriptKind + true, // openedByClient + '', // fileContent + // script info added by plugins should be marked as external, see + // https://github.com/microsoft/TypeScript/blob/b217f22e798c781f55d17da72ed099a9dee5c650/src/compiler/program.ts#L1897-L1899 + ts.ScriptKind.External, // scriptKind ); if (!scriptInfo) { throw new Error(`Failed to create script info for ${tcf}`); diff --git a/packages/language-service/ivy/test/legacy/mock_host.ts b/packages/language-service/ivy/test/legacy/mock_host.ts index f1b6f3f4e0..d825907e41 100644 --- a/packages/language-service/ivy/test/legacy/mock_host.ts +++ b/packages/language-service/ivy/test/legacy/mock_host.ts @@ -243,9 +243,9 @@ export class MockService { } const newScriptInfo = this.ps.getOrCreateScriptInfoForNormalizedPath( ts.server.toNormalizedPath(fileName), - true, // openedByClient - '', // fileContent - ts.ScriptKind.External, // scriptKind + true, // openedByClient + '', // fileContent + ts.ScriptKind.Unknown, // scriptKind ); if (!newScriptInfo) { throw new Error(`Failed to create new script info for ${fileName}`); diff --git a/packages/language-service/ivy/test/legacy/ts_plugin_spec.ts b/packages/language-service/ivy/test/legacy/ts_plugin_spec.ts new file mode 100644 index 0000000000..ce6f75fc75 --- /dev/null +++ b/packages/language-service/ivy/test/legacy/ts_plugin_spec.ts @@ -0,0 +1,29 @@ +/** + * @license + * Copyright Google LLC 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 {LanguageService} from '../../language_service'; +import {getExternalFiles} from '../../ts_plugin'; + +import {APP_COMPONENT, setup} from './mock_host'; + +describe('getExternalFiles()', () => { + it('should return all typecheck files', () => { + const {project, tsLS} = setup(); + let externalFiles = getExternalFiles(project); + // Initially there are no external files because Ivy compiler hasn't done + // a global analysis + expect(externalFiles).toEqual([]); + // Trigger global analysis + const ngLS = new LanguageService(project, tsLS); + ngLS.getSemanticDiagnostics(APP_COMPONENT); + // Now that global analysis is run, we should have all the typecheck files + externalFiles = getExternalFiles(project); + expect(externalFiles.length).toBe(1); + expect(externalFiles[0].endsWith('app.component.ngtypecheck.ts')).toBeTrue(); + }); +}); diff --git a/packages/language-service/ivy/ts_plugin.ts b/packages/language-service/ivy/ts_plugin.ts index c21a04da47..b48adc87bd 100644 --- a/packages/language-service/ivy/ts_plugin.ts +++ b/packages/language-service/ivy/ts_plugin.ts @@ -120,3 +120,19 @@ export function create(info: ts.server.PluginCreateInfo): ts.LanguageService { getCompletionEntrySymbol, }; } + +export function getExternalFiles(project: ts.server.Project): string[] { + if (!project.hasRoots()) { + return []; // project has not been initialized + } + const typecheckFiles: string[] = []; + for (const scriptInfo of project.getScriptInfos()) { + if (scriptInfo.scriptKind === ts.ScriptKind.External) { + // script info for typecheck file is marked as external, see + // getOrCreateTypeCheckScriptInfo() in + // packages/language-service/ivy/language_service.ts + typecheckFiles.push(scriptInfo.fileName); + } + } + return typecheckFiles; +}