Skip to content

Commit ab19bd3

Browse files
kyliauprofanis
authored andcommitted
fix(language-service): reinstate getExternalFiles() (angular#37750)
`getExternalFiles()` is an API that could optionally be provided by a tsserver plugin to notify the server of any additional files that should belong to a particular project. This API was removed in angular#34260 mainly due to performance reasons. However, with the introduction of "solution-style" tsconfig in typescript 3.9, the Angular extension could no longer reliably detect the owning Project solely based on the ancestor tsconfig.json. In order to support this use case, we have to reinstate `getExternalFiles()`. Fixes angular/vscode-ng-language-service#824 PR Close angular#37750
1 parent 892a089 commit ab19bd3

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

packages/language-service/src/ts_plugin.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,30 @@ import * as tss from 'typescript/lib/tsserverlibrary';
1111
import {createLanguageService} from './language_service';
1212
import {TypeScriptServiceHost} from './typescript_host';
1313

14+
// Use a WeakMap to keep track of Project to Host mapping so that when Project
15+
// is deleted Host could be garbage collected.
16+
const PROJECT_MAP = new WeakMap<tss.server.Project, TypeScriptServiceHost>();
17+
18+
/**
19+
* This function is called by tsserver to retrieve the external (non-TS) files
20+
* that should belong to the specified `project`. For Angular, these files are
21+
* external templates. This is called once when the project is loaded, then
22+
* every time when the program is updated.
23+
* @param project Project for which external files should be retrieved.
24+
*/
25+
export function getExternalFiles(project: tss.server.Project): string[] {
26+
if (!project.hasRoots()) {
27+
// During project initialization where there is no root files yet we should
28+
// not do any work.
29+
return [];
30+
}
31+
const ngLsHost = PROJECT_MAP.get(project);
32+
ngLsHost?.getAnalyzedModules();
33+
return ngLsHost?.getExternalTemplates() || [];
34+
}
35+
1436
export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
15-
const {languageService: tsLS, languageServiceHost: tsLSHost, config} = info;
37+
const {languageService: tsLS, languageServiceHost: tsLSHost, config, project} = info;
1638
// This plugin could operate under two different modes:
1739
// 1. TS + Angular
1840
// Plugin augments TS language service to provide additional Angular
@@ -25,6 +47,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService {
2547
const angularOnly = config ? config.angularOnly === true : false;
2648
const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS);
2749
const ngLS = createLanguageService(ngLSHost);
50+
PROJECT_MAP.set(project, ngLSHost);
2851

2952
function getCompletionsAtPosition(
3053
fileName: string, position: number, options: tss.GetCompletionsAtPositionOptions|undefined) {

packages/language-service/src/typescript_host.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ export class TypeScriptServiceHost implements LanguageServiceHost {
151151
return this.resolver.getReflector() as StaticReflector;
152152
}
153153

154+
/**
155+
* Return all known external templates.
156+
*/
157+
getExternalTemplates(): string[] {
158+
return [...this.fileToComponent.keys()];
159+
}
160+
154161
/**
155162
* Checks whether the program has changed and returns all analyzed modules.
156163
* If program has changed, invalidate all caches and update fileToComponent

packages/language-service/test/ts_plugin_spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import * as ts from 'typescript';
1010

11-
import {create} from '../src/ts_plugin';
11+
import {create, getExternalFiles} from '../src/ts_plugin';
1212
import {CompletionKind} from '../src/types';
1313

1414
import {MockTypescriptHost} from './test_utils';
@@ -129,6 +129,13 @@ describe('plugin', () => {
129129
},
130130
]);
131131
});
132+
133+
it('should return external templates when getExternalFiles() is called', () => {
134+
const externalTemplates = getExternalFiles(mockProject);
135+
expect(externalTemplates).toEqual([
136+
'/app/test.ng',
137+
]);
138+
});
132139
});
133140

134141
describe(`with config 'angularOnly = true`, () => {

0 commit comments

Comments
 (0)