diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts
index d98c950988d..2a11e885f64 100644
--- a/src/harness/unittests/tsserverProjectSystem.ts
+++ b/src/harness/unittests/tsserverProjectSystem.ts
@@ -1,4 +1,4 @@
-///
+///
///
namespace ts.projectSystem {
@@ -137,6 +137,19 @@ namespace ts.projectSystem {
return map(fileNames, toExternalFile);
}
+ export class TestServerEventManager {
+ private events: server.ProjectServiceEvent[] = [];
+
+ handler: server.ProjectServiceEventHandler = (event: server.ProjectServiceEvent) => {
+ this.events.push(event);
+ }
+
+ checkEventCountOfType(eventType: "context" | "configFileDiag", expectedCount: number) {
+ const eventsOfType = filter(this.events, e => e.eventName === eventType);
+ assert.equal(eventsOfType.length, expectedCount, `The actual event counts of type ${eventType} is ${eventsOfType.length}, while expected ${expectedCount}`);
+ }
+ }
+
export interface TestServerHostCreationParameters {
useCaseSensitiveFileNames?: boolean;
executingFilePath?: string;
@@ -160,11 +173,11 @@ namespace ts.projectSystem {
return host;
}
- export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller) {
+ export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller, projectServiceEventHandler?: server.ProjectServiceEventHandler) {
if (typingsInstaller === undefined) {
typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
}
- return new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);
+ return new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ projectServiceEventHandler !== undefined, projectServiceEventHandler);
}
export interface CreateProjectServiceParameters {
@@ -2065,4 +2078,92 @@ namespace ts.projectSystem {
assert.equal(snap.getLength(), expectedLength, "Incorrect snapshot size");
}
});
+
+ describe("Configure file diagnostics events", () => {
+
+ it("are generated when the config file has errors", () => {
+ const serverEventManager = new TestServerEventManager();
+ 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 host = createServerHost([file, configFile]);
+ const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
+ openFilesForSession([file], session);
+ serverEventManager.checkEventCountOfType("configFileDiag", 1);
+ });
+
+ it("are generated when the config file doesn't have errors", () => {
+ const serverEventManager = new TestServerEventManager();
+ const file = {
+ path: "/a/b/app.ts",
+ content: "let x = 10"
+ };
+ const configFile = {
+ path: "/a/b/tsconfig.json",
+ content: `{
+ "compilerOptions": {}
+ }`
+ };
+
+ const host = createServerHost([file, configFile]);
+ const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
+ openFilesForSession([file], session);
+ serverEventManager.checkEventCountOfType("configFileDiag", 1);
+ });
+ });
+
+ describe("Configure file diagnostics events", () => {
+
+ it("are generated when the config file has errors", () => {
+ const serverEventManager = new TestServerEventManager();
+ 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 host = createServerHost([file, configFile]);
+ const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
+ openFilesForSession([file], session);
+ serverEventManager.checkEventCountOfType("configFileDiag", 1);
+ });
+
+ it("are generated when the config file doesn't have errors", () => {
+ const serverEventManager = new TestServerEventManager();
+ const file = {
+ path: "/a/b/app.ts",
+ content: "let x = 10"
+ };
+ const configFile = {
+ path: "/a/b/tsconfig.json",
+ content: `{
+ "compilerOptions": {}
+ }`
+ };
+
+ const host = createServerHost([file, configFile]);
+ const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
+ openFilesForSession([file], session);
+ serverEventManager.checkEventCountOfType("configFileDiag", 1);
+ });
+ });
}
\ No newline at end of file
diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts
index d58bb416f26..e10b7e8b2cf 100644
--- a/src/server/editorServices.ts
+++ b/src/server/editorServices.ts
@@ -754,12 +754,14 @@ namespace ts.server {
}
private reportConfigFileDiagnostics(configFileName: string, diagnostics: Diagnostic[], triggerFile?: string) {
- if (diagnostics && diagnostics.length > 0) {
- this.eventHandler({
- eventName: "configFileDiag",
- data: { configFileName, diagnostics, triggerFile }
- });
+ if (!this.eventHandler) {
+ return;
}
+
+ this.eventHandler({
+ eventName: "configFileDiag",
+ data: { configFileName, diagnostics: diagnostics || [], triggerFile }
+ });
}
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, configFileErrors: Diagnostic[], clientFileName?: string) {
diff --git a/src/server/session.ts b/src/server/session.ts
index ff0de939d9d..9ab2a2c0ec9 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -155,6 +155,8 @@ namespace ts.server {
private immediateId: any;
private changeSeq = 0;
+ private eventHander: ProjectServiceEventHandler;
+
constructor(
private host: ServerHost,
cancellationToken: HostCancellationToken,
@@ -163,17 +165,18 @@ namespace ts.server {
private byteLength: (buf: string, encoding?: string) => number,
private hrtime: (start?: number[]) => number[],
protected logger: Logger,
- protected readonly canUseEvents: boolean) {
+ protected readonly canUseEvents: boolean,
+ eventHandler?: ProjectServiceEventHandler) {
- const eventHandler: ProjectServiceEventHandler = canUseEvents
- ? event => this.handleEvent(event)
+ this.eventHander = canUseEvents
+ ? eventHandler || (event => this.defaultEventHandler(event))
: undefined;
- this.projectService = new ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, eventHandler);
+ this.projectService = new ProjectService(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, this.eventHander);
this.gcTimer = new GcTimer(host, /*delay*/ 7000, logger);
}
- private handleEvent(event: ProjectServiceEvent) {
+ private defaultEventHandler(event: ProjectServiceEvent) {
switch (event.eventName) {
case "context":
const { project, fileName } = event.data;
@@ -714,8 +717,11 @@ namespace ts.server {
*/
private openClientFile(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind) {
const { configFileName, configFileErrors } = this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind);
- if (configFileErrors) {
- this.configFileDiagnosticEvent(fileName, configFileName, configFileErrors);
+ if (this.eventHander) {
+ this.eventHander({
+ eventName: "configFileDiag",
+ data: { fileName, configFileName, diagnostics: configFileErrors || [] }
+ });
}
}