Skip to content

Commit

Permalink
Merge pull request #22590 from amcasey/DiagEvents
Browse files Browse the repository at this point in the history
Add support for suppressing project events
  • Loading branch information
amcasey authored Mar 23, 2018
2 parents e16bb3e + e37ff25 commit 6524fc5
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 8 deletions.
89 changes: 86 additions & 3 deletions src/harness/unittests/tsserverProjectSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,12 @@ namespace ts.projectSystem {
readonly session: TestSession;
readonly service: server.ProjectService;
readonly host: TestServerHost;
constructor(files: FileOrFolder[]) {
constructor(files: FileOrFolder[], suppressDiagnosticEvents?: boolean) {
this.host = createServerHost(files);
this.session = createSession(this.host, {
canUseEvents: true,
eventHandler: event => this.events.push(event),
suppressDiagnosticEvents,
});
this.service = this.session.getProjectService();
}
Expand Down Expand Up @@ -485,6 +486,12 @@ namespace ts.projectSystem {
checkNthEvent(session, server.toEvent("projectsUpdatedInBackground", { openFiles }), 0, /*isMostRecent*/ true);
}

function checkNoDiagnosticEvents(session: TestSession) {
for (const event of session.events) {
assert.isFalse(event.event.endsWith("Diag"), JSON.stringify(event));
}
}

function checkNthEvent(session: TestSession, expectedEvent: protocol.Event, index: number, isMostRecent: boolean) {
const events = session.events;
assert.deepEqual(events[index], expectedEvent);
Expand Down Expand Up @@ -4074,6 +4081,63 @@ namespace ts.projectSystem {
session.clearMessages();
});

it("suppressed diagnostic events", () => {
const file: FileOrFolder = {
path: "/a.ts",
content: "1 = 2;",
};

const host = createServerHost([file]);
const session = createSession(host, { canUseEvents: true, suppressDiagnosticEvents: true });
const service = session.getProjectService();

session.executeCommandSeq<protocol.OpenRequest>({
command: server.CommandNames.Open,
arguments: { file: file.path, fileContent: file.content },
});

checkNumberOfProjects(service, { inferredProjects: 1 });

host.checkTimeoutQueueLength(0);
checkNoDiagnosticEvents(session);

session.clearMessages();

let expectedSequenceId = session.getNextSeq();

session.executeCommandSeq<protocol.GeterrRequest>({
command: server.CommandNames.Geterr,
arguments: {
delay: 0,
files: [file.path],
}
});

host.checkTimeoutQueueLength(0);
checkNoDiagnosticEvents(session);

checkCompleteEvent(session, 1, expectedSequenceId);

session.clearMessages();

expectedSequenceId = session.getNextSeq();

session.executeCommandSeq<protocol.GeterrForProjectRequest>({
command: server.CommandNames.Geterr,
arguments: {
delay: 0,
file: file.path,
}
});

host.checkTimeoutQueueLength(0);
checkNoDiagnosticEvents(session);

checkCompleteEvent(session, 1, expectedSequenceId);

session.clearMessages();
});

function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage, args: ReadonlyArray<string> = []): protocol.Diagnostic {
return { start, end, text: formatStringFromArgs(message.message, args), code: message.code, category: diagnosticCategoryName(message), source: undefined };
}
Expand Down Expand Up @@ -4149,7 +4213,7 @@ namespace ts.projectSystem {
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path);
});

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

it("are not generated when the config file doesnot include file opened and doesnt contain any errors", () => {
it("are not generated when the config file has errors but suppressDiagnosticEvents is true", () => {
const file = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const configFile = {
path: "/a/b/tsconfig.json",
content: `{
"compilerOptions": {
"foo": "bar",
"allowJS": true
}
}`
};
const serverEventManager = new TestServerEventManager([file, configFile], /*suppressDiagnosticEvents*/ true);
openFilesForSession([file], serverEventManager.session);
serverEventManager.hasZeroEvent("configFileDiag");
});

it("are not generated when the config file does not include file opened and doesnt contain any errors", () => {
const file = {
path: "/a/b/app.ts",
content: "let x = 10"
Expand Down
5 changes: 4 additions & 1 deletion src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ namespace ts.server {
useInferredProjectPerProjectRoot: boolean;
typingsInstaller: ITypingsInstaller;
eventHandler?: ProjectServiceEventHandler;
suppressDiagnosticEvents?: boolean;
throttleWaitMilliseconds?: number;
globalPlugins?: ReadonlyArray<string>;
pluginProbeLocations?: ReadonlyArray<string>;
Expand Down Expand Up @@ -392,6 +393,7 @@ namespace ts.server {
public readonly typingsInstaller: ITypingsInstaller;
public readonly throttleWaitMilliseconds?: number;
private readonly eventHandler?: ProjectServiceEventHandler;
private readonly suppressDiagnosticEvents?: boolean;

public readonly globalPlugins: ReadonlyArray<string>;
public readonly pluginProbeLocations: ReadonlyArray<string>;
Expand All @@ -413,6 +415,7 @@ namespace ts.server {
this.typingsInstaller = opts.typingsInstaller || nullTypingsInstaller;
this.throttleWaitMilliseconds = opts.throttleWaitMilliseconds;
this.eventHandler = opts.eventHandler;
this.suppressDiagnosticEvents = opts.suppressDiagnosticEvents;
this.globalPlugins = opts.globalPlugins || emptyArray;
this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray;
this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads;
Expand Down Expand Up @@ -1598,7 +1601,7 @@ namespace ts.server {
}

private sendConfigFileDiagEvent(project: ConfiguredProject, triggerFile: NormalizedPath) {
if (!this.eventHandler) {
if (!this.eventHandler || this.suppressDiagnosticEvents) {
return;
}

Expand Down
2 changes: 2 additions & 0 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ namespace ts.server {
hrtime: process.hrtime,
logger,
canUseEvents: true,
suppressDiagnosticEvents,
globalPlugins,
pluginProbeLocations,
allowLocalPluginLoads,
Expand Down Expand Up @@ -927,6 +928,7 @@ namespace ts.server {
const useSingleInferredProject = hasArgument("--useSingleInferredProject");
const useInferredProjectPerProjectRoot = hasArgument("--useInferredProjectPerProjectRoot");
const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition");
const suppressDiagnosticEvents = hasArgument("--suppressDiagnosticEvents");
const telemetryEnabled = hasArgument(Arguments.EnableTelemetry);

logger.info(`Starting TS Server`);
Expand Down
25 changes: 21 additions & 4 deletions src/server/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ namespace ts.server {
*/
canUseEvents: boolean;
eventHandler?: ProjectServiceEventHandler;
/** Has no effect if eventHandler is also specified. */
suppressDiagnosticEvents?: boolean;
throttleWaitMilliseconds?: number;

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

protected canUseEvents: boolean;
private suppressDiagnosticEvents?: boolean;
private eventHandler: ProjectServiceEventHandler;

constructor(opts: SessionOptions) {
Expand All @@ -328,6 +331,7 @@ namespace ts.server {
this.hrtime = opts.hrtime;
this.logger = opts.logger;
this.canUseEvents = opts.canUseEvents;
this.suppressDiagnosticEvents = opts.suppressDiagnosticEvents;

const { throttleWaitMilliseconds } = opts;

Expand All @@ -352,6 +356,7 @@ namespace ts.server {
typingsInstaller: this.typingsInstaller,
throttleWaitMilliseconds,
eventHandler: this.eventHandler,
suppressDiagnosticEvents: this.suppressDiagnosticEvents,
globalPlugins: opts.globalPlugins,
pluginProbeLocations: opts.pluginProbeLocations,
allowLocalPluginLoads: opts.allowLocalPluginLoads
Expand Down Expand Up @@ -401,11 +406,12 @@ namespace ts.server {
private projectsUpdatedInBackgroundEvent(openFiles: string[]): void {
this.projectService.logger.info(`got projects updated in background, updating diagnostics for ${openFiles}`);
if (openFiles.length) {
const checkList = this.createCheckList(openFiles);

// For now only queue error checking for open files. We can change this to include non open files as well
this.errorCheck.startNew(next => this.updateErrorCheck(next, checkList, 100, /*requireOpen*/ true));
if (!this.suppressDiagnosticEvents) {
const checkList = this.createCheckList(openFiles);

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

// Send project changed event
this.event<protocol.ProjectsUpdatedInBackgroundEventBody>({
Expand Down Expand Up @@ -489,7 +495,10 @@ namespace ts.server {
}
}

/** It is the caller's responsibility to verify that `!this.suppressDiagnosticEvents`. */
private updateErrorCheck(next: NextStep, checkList: PendingErrorCheck[], ms: number, requireOpen = true) {
Debug.assert(!this.suppressDiagnosticEvents); // Caller's responsibility

const seq = this.changeSeq;
const followMs = Math.min(ms, 200);

Expand Down Expand Up @@ -1379,6 +1388,10 @@ namespace ts.server {
}

private getDiagnostics(next: NextStep, delay: number, fileNames: string[]): void {
if (this.suppressDiagnosticEvents) {
return;
}

const checkList = this.createCheckList(fileNames);
if (checkList.length > 0) {
this.updateErrorCheck(next, checkList, delay);
Expand Down Expand Up @@ -1748,6 +1761,10 @@ namespace ts.server {
}

private getDiagnosticsForProject(next: NextStep, delay: number, fileName: string): void {
if (this.suppressDiagnosticEvents) {
return;
}

const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true, /*excludeConfigFiles*/ true);
if (languageServiceDisabled) {
return;
Expand Down
6 changes: 6 additions & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7258,6 +7258,8 @@ declare namespace ts.server {
*/
canUseEvents: boolean;
eventHandler?: ProjectServiceEventHandler;
/** Has no effect if eventHandler is also specified. */
suppressDiagnosticEvents?: boolean;
throttleWaitMilliseconds?: number;
globalPlugins?: ReadonlyArray<string>;
pluginProbeLocations?: ReadonlyArray<string>;
Expand All @@ -7276,6 +7278,7 @@ declare namespace ts.server {
private hrtime;
protected logger: Logger;
protected canUseEvents: boolean;
private suppressDiagnosticEvents?;
private eventHandler;
constructor(opts: SessionOptions);
private sendRequestCompletedEvent;
Expand All @@ -7291,6 +7294,7 @@ declare namespace ts.server {
private syntacticCheck;
private infoCheck;
private sendDiagnosticsEvent;
/** It is the caller's responsibility to verify that `!this.suppressDiagnosticEvents`. */
private updateErrorCheck;
private cleanProjects;
private cleanup;
Expand Down Expand Up @@ -7819,6 +7823,7 @@ declare namespace ts.server {
useInferredProjectPerProjectRoot: boolean;
typingsInstaller: ITypingsInstaller;
eventHandler?: ProjectServiceEventHandler;
suppressDiagnosticEvents?: boolean;
throttleWaitMilliseconds?: number;
globalPlugins?: ReadonlyArray<string>;
pluginProbeLocations?: ReadonlyArray<string>;
Expand Down Expand Up @@ -7885,6 +7890,7 @@ declare namespace ts.server {
readonly typingsInstaller: ITypingsInstaller;
readonly throttleWaitMilliseconds?: number;
private readonly eventHandler?;
private readonly suppressDiagnosticEvents?;
readonly globalPlugins: ReadonlyArray<string>;
readonly pluginProbeLocations: ReadonlyArray<string>;
readonly allowLocalPluginLoads: boolean;
Expand Down

0 comments on commit 6524fc5

Please sign in to comment.