Skip to content

Commit 3b0515f

Browse files
authored
Send config file diagnonstics event even when no errors were found (#11285)
* emit config diagnostics event when no errors found * Add tests for project service events
1 parent 997acae commit 3b0515f

File tree

3 files changed

+80
-15
lines changed

3 files changed

+80
-15
lines changed

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// <reference path="..\harness.ts" />
1+
/// <reference path="..\harness.ts" />
22
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />
33

44
namespace ts.projectSystem {
@@ -136,6 +136,19 @@ namespace ts.projectSystem {
136136
return map(fileNames, toExternalFile);
137137
}
138138

139+
export class TestServerEventManager {
140+
private events: server.ProjectServiceEvent[] = [];
141+
142+
handler: server.ProjectServiceEventHandler = (event: server.ProjectServiceEvent) => {
143+
this.events.push(event);
144+
}
145+
146+
checkEventCountOfType(eventType: "context" | "configFileDiag", expectedCount: number) {
147+
const eventsOfType = filter(this.events, e => e.eventName === eventType);
148+
assert.equal(eventsOfType.length, expectedCount, `The actual event counts of type ${eventType} is ${eventsOfType.length}, while expected ${expectedCount}`);
149+
}
150+
}
151+
139152
export interface TestServerHostCreationParameters {
140153
useCaseSensitiveFileNames?: boolean;
141154
executingFilePath?: string;
@@ -159,11 +172,11 @@ namespace ts.projectSystem {
159172
return host;
160173
}
161174

162-
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller) {
175+
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller, projectServiceEventHandler?: server.ProjectServiceEventHandler) {
163176
if (typingsInstaller === undefined) {
164177
typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
165178
}
166-
return new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);
179+
return new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ projectServiceEventHandler !== undefined, projectServiceEventHandler);
167180
}
168181

169182
export interface CreateProjectServiceParameters {
@@ -2121,4 +2134,48 @@ namespace ts.projectSystem {
21212134
projectService.inferredProjects[0].getLanguageService().getProgram();
21222135
});
21232136
});
2137+
2138+
describe("Configure file diagnostics events", () => {
2139+
2140+
it("are generated when the config file has errors", () => {
2141+
const serverEventManager = new TestServerEventManager();
2142+
const file = {
2143+
path: "/a/b/app.ts",
2144+
content: "let x = 10"
2145+
};
2146+
const configFile = {
2147+
path: "/a/b/tsconfig.json",
2148+
content: `{
2149+
"compilerOptions": {
2150+
"foo": "bar",
2151+
"allowJS": true
2152+
}
2153+
}`
2154+
};
2155+
2156+
const host = createServerHost([file, configFile]);
2157+
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
2158+
openFilesForSession([file], session);
2159+
serverEventManager.checkEventCountOfType("configFileDiag", 1);
2160+
});
2161+
2162+
it("are generated when the config file doesn't have errors", () => {
2163+
const serverEventManager = new TestServerEventManager();
2164+
const file = {
2165+
path: "/a/b/app.ts",
2166+
content: "let x = 10"
2167+
};
2168+
const configFile = {
2169+
path: "/a/b/tsconfig.json",
2170+
content: `{
2171+
"compilerOptions": {}
2172+
}`
2173+
};
2174+
2175+
const host = createServerHost([file, configFile]);
2176+
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
2177+
openFilesForSession([file], session);
2178+
serverEventManager.checkEventCountOfType("configFileDiag", 1);
2179+
});
2180+
});
21242181
}

src/server/editorServices.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -755,12 +755,14 @@ namespace ts.server {
755755
}
756756

757757
private reportConfigFileDiagnostics(configFileName: string, diagnostics: Diagnostic[], triggerFile?: string) {
758-
if (diagnostics && diagnostics.length > 0) {
759-
this.eventHandler({
760-
eventName: "configFileDiag",
761-
data: { configFileName, diagnostics, triggerFile }
762-
});
758+
if (!this.eventHandler) {
759+
return;
763760
}
761+
762+
this.eventHandler({
763+
eventName: "configFileDiag",
764+
data: { configFileName, diagnostics: diagnostics || [], triggerFile }
765+
});
764766
}
765767

766768
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, configFileErrors: Diagnostic[], clientFileName?: string) {

src/server/session.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ namespace ts.server {
155155
private immediateId: any;
156156
private changeSeq = 0;
157157

158+
private eventHander: ProjectServiceEventHandler;
159+
158160
constructor(
159161
private host: ServerHost,
160162
cancellationToken: HostCancellationToken,
@@ -163,17 +165,18 @@ namespace ts.server {
163165
private byteLength: (buf: string, encoding?: string) => number,
164166
private hrtime: (start?: number[]) => number[],
165167
protected logger: Logger,
166-
protected readonly canUseEvents: boolean) {
168+
protected readonly canUseEvents: boolean,
169+
eventHandler?: ProjectServiceEventHandler) {
167170

168-
const eventHandler: ProjectServiceEventHandler = canUseEvents
169-
? event => this.handleEvent(event)
171+
this.eventHander = canUseEvents
172+
? eventHandler || (event => this.defaultEventHandler(event))
170173
: undefined;
171174

172-
this.projectService = new ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, eventHandler);
175+
this.projectService = new ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, this.eventHander);
173176
this.gcTimer = new GcTimer(host, /*delay*/ 7000, logger);
174177
}
175178

176-
private handleEvent(event: ProjectServiceEvent) {
179+
private defaultEventHandler(event: ProjectServiceEvent) {
177180
switch (event.eventName) {
178181
case "context":
179182
const { project, fileName } = event.data;
@@ -734,8 +737,11 @@ namespace ts.server {
734737
*/
735738
private openClientFile(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind) {
736739
const { configFileName, configFileErrors } = this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind);
737-
if (configFileErrors) {
738-
this.configFileDiagnosticEvent(fileName, configFileName, configFileErrors);
740+
if (this.eventHander) {
741+
this.eventHander({
742+
eventName: "configFileDiag",
743+
data: { fileName, configFileName, diagnostics: configFileErrors || [] }
744+
});
739745
}
740746
}
741747

0 commit comments

Comments
 (0)