Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for suppressing project events #22590

Merged
merged 2 commits into from
Mar 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -7256,6 +7256,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 @@ -7274,6 +7276,7 @@ declare namespace ts.server {
private hrtime;
protected logger: Logger;
protected canUseEvents: boolean;
private suppressDiagnosticEvents?;
private eventHandler;
constructor(opts: SessionOptions);
private sendRequestCompletedEvent;
Expand All @@ -7289,6 +7292,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 @@ -7817,6 +7821,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 @@ -7883,6 +7888,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