Skip to content

Commit 6524fc5

Browse files
authored
Merge pull request microsoft#22590 from amcasey/DiagEvents
Add support for suppressing project events
2 parents e16bb3e + e37ff25 commit 6524fc5

File tree

5 files changed

+119
-8
lines changed

5 files changed

+119
-8
lines changed

src/harness/unittests/tsserverProjectSystem.ts

+86-3
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,12 @@ namespace ts.projectSystem {
168168
readonly session: TestSession;
169169
readonly service: server.ProjectService;
170170
readonly host: TestServerHost;
171-
constructor(files: FileOrFolder[]) {
171+
constructor(files: FileOrFolder[], suppressDiagnosticEvents?: boolean) {
172172
this.host = createServerHost(files);
173173
this.session = createSession(this.host, {
174174
canUseEvents: true,
175175
eventHandler: event => this.events.push(event),
176+
suppressDiagnosticEvents,
176177
});
177178
this.service = this.session.getProjectService();
178179
}
@@ -485,6 +486,12 @@ namespace ts.projectSystem {
485486
checkNthEvent(session, server.toEvent("projectsUpdatedInBackground", { openFiles }), 0, /*isMostRecent*/ true);
486487
}
487488

489+
function checkNoDiagnosticEvents(session: TestSession) {
490+
for (const event of session.events) {
491+
assert.isFalse(event.event.endsWith("Diag"), JSON.stringify(event));
492+
}
493+
}
494+
488495
function checkNthEvent(session: TestSession, expectedEvent: protocol.Event, index: number, isMostRecent: boolean) {
489496
const events = session.events;
490497
assert.deepEqual(events[index], expectedEvent);
@@ -4074,6 +4081,63 @@ namespace ts.projectSystem {
40744081
session.clearMessages();
40754082
});
40764083

4084+
it("suppressed diagnostic events", () => {
4085+
const file: FileOrFolder = {
4086+
path: "/a.ts",
4087+
content: "1 = 2;",
4088+
};
4089+
4090+
const host = createServerHost([file]);
4091+
const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true });
4092+
const service = session.getProjectService();
4093+
4094+
session.executeCommandSeq<protocol.OpenRequest>({
4095+
command: server.CommandNames.Open,
4096+
arguments: { file: file.path, fileContent: file.content },
4097+
});
4098+
4099+
checkNumberOfProjects(service, { inferredProjects: 1 });
4100+
4101+
host.checkTimeoutQueueLength(0);
4102+
checkNoDiagnosticEvents(session);
4103+
4104+
session.clearMessages();
4105+
4106+
let expectedSequenceId = session.getNextSeq();
4107+
4108+
session.executeCommandSeq<protocol.GeterrRequest>({
4109+
command: server.CommandNames.Geterr,
4110+
arguments: {
4111+
delay: 0,
4112+
files: [file.path],
4113+
}
4114+
});
4115+
4116+
host.checkTimeoutQueueLength(0);
4117+
checkNoDiagnosticEvents(session);
4118+
4119+
checkCompleteEvent(session, 1, expectedSequenceId);
4120+
4121+
session.clearMessages();
4122+
4123+
expectedSequenceId = session.getNextSeq();
4124+
4125+
session.executeCommandSeq<protocol.GeterrForProjectRequest>({
4126+
command: server.CommandNames.Geterr,
4127+
arguments: {
4128+
delay: 0,
4129+
file: file.path,
4130+
}
4131+
});
4132+
4133+
host.checkTimeoutQueueLength(0);
4134+
checkNoDiagnosticEvents(session);
4135+
4136+
checkCompleteEvent(session, 1, expectedSequenceId);
4137+
4138+
session.clearMessages();
4139+
});
4140+
40774141
function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage, args: ReadonlyArray<string> = []): protocol.Diagnostic {
40784142
return { start, end, text: formatStringFromArgs(message.message, args), code: message.code, category: diagnosticCategoryName(message), source: undefined };
40794143
}
@@ -4149,7 +4213,7 @@ namespace ts.projectSystem {
41494213
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path);
41504214
});
41514215

4152-
it("are not generated when the config file doesnot include file opened and config file has errors", () => {
4216+
it("are not generated when the config file does not include file opened and config file has errors", () => {
41534217
const file = {
41544218
path: "/a/b/app.ts",
41554219
content: "let x = 10"
@@ -4173,7 +4237,26 @@ namespace ts.projectSystem {
41734237
serverEventManager.hasZeroEvent("configFileDiag");
41744238
});
41754239

4176-
it("are not generated when the config file doesnot include file opened and doesnt contain any errors", () => {
4240+
it("are not generated when the config file has errors but suppressDiagnosticEvents is true", () => {
4241+
const file = {
4242+
path: "/a/b/app.ts",
4243+
content: "let x = 10"
4244+
};
4245+
const configFile = {
4246+
path: "/a/b/tsconfig.json",
4247+
content: `{
4248+
"compilerOptions": {
4249+
"foo": "bar",
4250+
"allowJS": true
4251+
}
4252+
}`
4253+
};
4254+
const serverEventManager = new TestServerEventManager([file, configFile], /*suppressDiagnosticEvents*/ true);
4255+
openFilesForSession([file], serverEventManager.session);
4256+
serverEventManager.hasZeroEvent("configFileDiag");
4257+
});
4258+
4259+
it("are not generated when the config file does not include file opened and doesnt contain any errors", () => {
41774260
const file = {
41784261
path: "/a/b/app.ts",
41794262
content: "let x = 10"

src/server/editorServices.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ namespace ts.server {
305305
useInferredProjectPerProjectRoot: boolean;
306306
typingsInstaller: ITypingsInstaller;
307307
eventHandler?: ProjectServiceEventHandler;
308+
suppressDiagnosticEvents?: boolean;
308309
throttleWaitMilliseconds?: number;
309310
globalPlugins?: ReadonlyArray<string>;
310311
pluginProbeLocations?: ReadonlyArray<string>;
@@ -392,6 +393,7 @@ namespace ts.server {
392393
public readonly typingsInstaller: ITypingsInstaller;
393394
public readonly throttleWaitMilliseconds?: number;
394395
private readonly eventHandler?: ProjectServiceEventHandler;
396+
private readonly suppressDiagnosticEvents?: boolean;
395397

396398
public readonly globalPlugins: ReadonlyArray<string>;
397399
public readonly pluginProbeLocations: ReadonlyArray<string>;
@@ -413,6 +415,7 @@ namespace ts.server {
413415
this.typingsInstaller = opts.typingsInstaller || nullTypingsInstaller;
414416
this.throttleWaitMilliseconds = opts.throttleWaitMilliseconds;
415417
this.eventHandler = opts.eventHandler;
418+
this.suppressDiagnosticEvents = opts.suppressDiagnosticEvents;
416419
this.globalPlugins = opts.globalPlugins || emptyArray;
417420
this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray;
418421
this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads;
@@ -1598,7 +1601,7 @@ namespace ts.server {
15981601
}
15991602

16001603
private sendConfigFileDiagEvent(project: ConfiguredProject, triggerFile: NormalizedPath) {
1601-
if (!this.eventHandler) {
1604+
if (!this.eventHandler || this.suppressDiagnosticEvents) {
16021605
return;
16031606
}
16041607

src/server/server.ts

+2
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ namespace ts.server {
512512
hrtime: process.hrtime,
513513
logger,
514514
canUseEvents: true,
515+
suppressDiagnosticEvents,
515516
globalPlugins,
516517
pluginProbeLocations,
517518
allowLocalPluginLoads,
@@ -927,6 +928,7 @@ namespace ts.server {
927928
const useSingleInferredProject = hasArgument("--useSingleInferredProject");
928929
const useInferredProjectPerProjectRoot = hasArgument("--useInferredProjectPerProjectRoot");
929930
const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition");
931+
const suppressDiagnosticEvents = hasArgument("--suppressDiagnosticEvents");
930932
const telemetryEnabled = hasArgument(Arguments.EnableTelemetry);
931933

932934
logger.info(`Starting TS Server`);

src/server/session.ts

+21-4
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ namespace ts.server {
295295
*/
296296
canUseEvents: boolean;
297297
eventHandler?: ProjectServiceEventHandler;
298+
/** Has no effect if eventHandler is also specified. */
299+
suppressDiagnosticEvents?: boolean;
298300
throttleWaitMilliseconds?: number;
299301

300302
globalPlugins?: ReadonlyArray<string>;
@@ -318,6 +320,7 @@ namespace ts.server {
318320
protected logger: Logger;
319321

320322
protected canUseEvents: boolean;
323+
private suppressDiagnosticEvents?: boolean;
321324
private eventHandler: ProjectServiceEventHandler;
322325

323326
constructor(opts: SessionOptions) {
@@ -328,6 +331,7 @@ namespace ts.server {
328331
this.hrtime = opts.hrtime;
329332
this.logger = opts.logger;
330333
this.canUseEvents = opts.canUseEvents;
334+
this.suppressDiagnosticEvents = opts.suppressDiagnosticEvents;
331335

332336
const { throttleWaitMilliseconds } = opts;
333337

@@ -352,6 +356,7 @@ namespace ts.server {
352356
typingsInstaller: this.typingsInstaller,
353357
throttleWaitMilliseconds,
354358
eventHandler: this.eventHandler,
359+
suppressDiagnosticEvents: this.suppressDiagnosticEvents,
355360
globalPlugins: opts.globalPlugins,
356361
pluginProbeLocations: opts.pluginProbeLocations,
357362
allowLocalPluginLoads: opts.allowLocalPluginLoads
@@ -401,11 +406,12 @@ namespace ts.server {
401406
private projectsUpdatedInBackgroundEvent(openFiles: string[]): void {
402407
this.projectService.logger.info(`got projects updated in background, updating diagnostics for ${openFiles}`);
403408
if (openFiles.length) {
404-
const checkList = this.createCheckList(openFiles);
405-
406-
// For now only queue error checking for open files. We can change this to include non open files as well
407-
this.errorCheck.startNew(next => this.updateErrorCheck(next, checkList, 100, /*requireOpen*/ true));
409+
if (!this.suppressDiagnosticEvents) {
410+
const checkList = this.createCheckList(openFiles);
408411

412+
// For now only queue error checking for open files. We can change this to include non open files as well
413+
this.errorCheck.startNew(next => this.updateErrorCheck(next, checkList, 100, /*requireOpen*/ true));
414+
}
409415

410416
// Send project changed event
411417
this.event<protocol.ProjectsUpdatedInBackgroundEventBody>({
@@ -489,7 +495,10 @@ namespace ts.server {
489495
}
490496
}
491497

498+
/** It is the caller's responsibility to verify that `!this.suppressDiagnosticEvents`. */
492499
private updateErrorCheck(next: NextStep, checkList: PendingErrorCheck[], ms: number, requireOpen = true) {
500+
Debug.assert(!this.suppressDiagnosticEvents); // Caller's responsibility
501+
493502
const seq = this.changeSeq;
494503
const followMs = Math.min(ms, 200);
495504

@@ -1379,6 +1388,10 @@ namespace ts.server {
13791388
}
13801389

13811390
private getDiagnostics(next: NextStep, delay: number, fileNames: string[]): void {
1391+
if (this.suppressDiagnosticEvents) {
1392+
return;
1393+
}
1394+
13821395
const checkList = this.createCheckList(fileNames);
13831396
if (checkList.length > 0) {
13841397
this.updateErrorCheck(next, checkList, delay);
@@ -1748,6 +1761,10 @@ namespace ts.server {
17481761
}
17491762

17501763
private getDiagnosticsForProject(next: NextStep, delay: number, fileName: string): void {
1764+
if (this.suppressDiagnosticEvents) {
1765+
return;
1766+
}
1767+
17511768
const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true, /*excludeConfigFiles*/ true);
17521769
if (languageServiceDisabled) {
17531770
return;

tests/baselines/reference/api/tsserverlibrary.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -7258,6 +7258,8 @@ declare namespace ts.server {
72587258
*/
72597259
canUseEvents: boolean;
72607260
eventHandler?: ProjectServiceEventHandler;
7261+
/** Has no effect if eventHandler is also specified. */
7262+
suppressDiagnosticEvents?: boolean;
72617263
throttleWaitMilliseconds?: number;
72627264
globalPlugins?: ReadonlyArray<string>;
72637265
pluginProbeLocations?: ReadonlyArray<string>;
@@ -7276,6 +7278,7 @@ declare namespace ts.server {
72767278
private hrtime;
72777279
protected logger: Logger;
72787280
protected canUseEvents: boolean;
7281+
private suppressDiagnosticEvents?;
72797282
private eventHandler;
72807283
constructor(opts: SessionOptions);
72817284
private sendRequestCompletedEvent;
@@ -7291,6 +7294,7 @@ declare namespace ts.server {
72917294
private syntacticCheck;
72927295
private infoCheck;
72937296
private sendDiagnosticsEvent;
7297+
/** It is the caller's responsibility to verify that `!this.suppressDiagnosticEvents`. */
72947298
private updateErrorCheck;
72957299
private cleanProjects;
72967300
private cleanup;
@@ -7819,6 +7823,7 @@ declare namespace ts.server {
78197823
useInferredProjectPerProjectRoot: boolean;
78207824
typingsInstaller: ITypingsInstaller;
78217825
eventHandler?: ProjectServiceEventHandler;
7826+
suppressDiagnosticEvents?: boolean;
78227827
throttleWaitMilliseconds?: number;
78237828
globalPlugins?: ReadonlyArray<string>;
78247829
pluginProbeLocations?: ReadonlyArray<string>;
@@ -7885,6 +7890,7 @@ declare namespace ts.server {
78857890
readonly typingsInstaller: ITypingsInstaller;
78867891
readonly throttleWaitMilliseconds?: number;
78877892
private readonly eventHandler?;
7893+
private readonly suppressDiagnosticEvents?;
78887894
readonly globalPlugins: ReadonlyArray<string>;
78897895
readonly pluginProbeLocations: ReadonlyArray<string>;
78907896
readonly allowLocalPluginLoads: boolean;

0 commit comments

Comments
 (0)