Skip to content

Commit 05aa50b

Browse files
kyliauayazhafiz
authored andcommitted
refactor: remove project_service.ts
`ProjectService` class in `project_service.ts` is just a thin wrapper around `ts.server.ProjectService`. It was added primarily to override the default behavior of `projectService.getDefaultProjectForFile()` and to prevent accidental calling of the original method. We have to override the method because the `ScriptInfo` for a HTML file does not necessarily have a default project. In the overridden method, we manually attach it to a project based on the closest `tsconfig.json`. However, this wrapper complicates the migration to Ivy because when it configures the plugin, it assumes the name of the plugin is always `@angular/language-service`, which is not true in the Ivy case. The methods that were overridden are now absorbed into `session.ts`.
1 parent 92146ff commit 05aa50b

File tree

2 files changed

+78
-137
lines changed

2 files changed

+78
-137
lines changed

server/src/project_service.ts

Lines changed: 0 additions & 129 deletions
This file was deleted.

server/src/session.ts

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import * as lsp from 'vscode-languageserver';
1212
import {tsCompletionEntryToLspCompletionItem} from './completion';
1313
import {tsDiagnosticToLspDiagnostic} from './diagnostic';
1414
import {Logger} from './logger';
15-
import {ProjectService} from './project_service';
1615
import {projectLoadingNotification} from './protocol';
1716
import {ServerHost} from './server_host';
1817
import {filePathToUri, lspPositionToTsPosition, lspRangeToTsPositions, tsTextSpanToLspRange, uriToFilePath} from './utils';
@@ -37,15 +36,19 @@ const EMPTY_RANGE = lsp.Range.create(0, 0, 0, 0);
3736
*/
3837
export class Session {
3938
private readonly connection: lsp.IConnection;
40-
private readonly projectService: ProjectService;
39+
private readonly projectService: ts.server.ProjectService;
4140
private diagnosticsTimeout: NodeJS.Timeout|null = null;
4241
private isProjectLoading = false;
4342

4443
constructor(options: SessionOptions) {
4544
// Create a connection for the server. The connection uses Node's IPC as a transport.
4645
this.connection = lsp.createConnection();
4746
this.addProtocolHandlers(this.connection);
48-
this.projectService = new ProjectService({
47+
this.projectService = this.createProjectService(options);
48+
}
49+
50+
private createProjectService(options: SessionOptions): ts.server.ProjectService {
51+
const projSvc = new ts.server.ProjectService({
4952
host: options.host,
5053
logger: options.logger,
5154
cancellationToken: ts.server.nullCancellationToken,
@@ -63,6 +66,26 @@ export class Session {
6366
pluginProbeLocations: [options.ngProbeLocation],
6467
allowLocalPluginLoads: false, // do not load plugins from tsconfig.json
6568
});
69+
70+
projSvc.setHostConfiguration({
71+
formatOptions: projSvc.getHostFormatCodeOptions(),
72+
extraFileExtensions: [
73+
{
74+
extension: '.html',
75+
isMixedContent: false,
76+
scriptKind: ts.ScriptKind.External,
77+
},
78+
],
79+
});
80+
81+
projSvc.configurePlugin({
82+
pluginName: '@angular/language-service',
83+
configuration: {
84+
angularOnly: true,
85+
},
86+
});
87+
88+
return projSvc;
6689
}
6790

6891
private addProtocolHandlers(conn: lsp.IConnection) {
@@ -142,7 +165,7 @@ export class Session {
142165
continue;
143166
}
144167

145-
const ngLS = this.projectService.getDefaultLanguageService(scriptInfo);
168+
const ngLS = this.getDefaultLanguageService(scriptInfo);
146169
if (!ngLS) {
147170
continue;
148171
}
@@ -157,6 +180,53 @@ export class Session {
157180
}
158181
}
159182

183+
/**
184+
* Return the default project for the specified `scriptInfo` if it is already
185+
* a configured project. If not, attempt to find a relevant config file and
186+
* make that project its default. This method is to ensure HTML files always
187+
* belong to a configured project instead of the default behavior of being in
188+
* an inferred project.
189+
* @param scriptInfo
190+
*/
191+
getDefaultProjectForScriptInfo(scriptInfo: ts.server.ScriptInfo): ts.server.Project|undefined {
192+
let project = this.projectService.getDefaultProjectForFile(
193+
scriptInfo.fileName,
194+
// ensureProject tries to find a default project for the scriptInfo if
195+
// it does not already have one. It is not needed here because we are
196+
// going to assign it a project below if it does not have one.
197+
false // ensureProject
198+
);
199+
200+
// TODO: verify that HTML files are attached to Inferred project by default.
201+
// If they are already part of a ConfiguredProject then the following is
202+
// not needed.
203+
if (!project || project.projectKind !== ts.server.ProjectKind.Configured) {
204+
const {configFileName} = this.projectService.openClientFile(scriptInfo.fileName);
205+
if (!configFileName) {
206+
// Failed to find a config file. There is nothing we could do.
207+
return;
208+
}
209+
project = this.projectService.findProject(configFileName);
210+
if (!project) {
211+
return;
212+
}
213+
scriptInfo.detachAllProjects();
214+
scriptInfo.attachToProject(project);
215+
}
216+
217+
return project;
218+
}
219+
220+
/**
221+
* Returns a language service for a default project created for the specified `scriptInfo`. If the
222+
* project does not support a language service, nothing is returned.
223+
*/
224+
getDefaultLanguageService(scriptInfo: ts.server.ScriptInfo): ts.LanguageService|undefined {
225+
const project = this.getDefaultProjectForScriptInfo(scriptInfo);
226+
if (!project?.languageServiceEnabled) return;
227+
return project.getLanguageService();
228+
}
229+
160230
private onInitialize(params: lsp.InitializeParams): lsp.InitializeResult {
161231
return {
162232
capabilities: {
@@ -245,7 +315,7 @@ export class Session {
245315
}
246316
}
247317

248-
const project = this.projectService.getDefaultProjectForScriptInfo(scriptInfo);
318+
const project = this.getDefaultProjectForScriptInfo(scriptInfo);
249319
if (!project || !project.languageServiceEnabled) {
250320
return;
251321
}
@@ -276,7 +346,7 @@ export class Session {
276346
}
277347

278348
const {fileName} = scriptInfo;
279-
const langSvc = this.projectService.getDefaultLanguageService(scriptInfo);
349+
const langSvc = this.getDefaultLanguageService(scriptInfo);
280350
if (!langSvc) {
281351
return;
282352
}
@@ -322,7 +392,7 @@ export class Session {
322392
if (!scriptInfo) {
323393
return;
324394
}
325-
const langSvc = this.projectService.getDefaultLanguageService(scriptInfo);
395+
const langSvc = this.getDefaultLanguageService(scriptInfo);
326396
if (!langSvc) {
327397
return;
328398
}
@@ -366,7 +436,7 @@ export class Session {
366436
return;
367437
}
368438
const {fileName} = scriptInfo;
369-
const langSvc = this.projectService.getDefaultLanguageService(scriptInfo);
439+
const langSvc = this.getDefaultLanguageService(scriptInfo);
370440
if (!langSvc) {
371441
return;
372442
}

0 commit comments

Comments
 (0)