From 635313ee45e1edd09e5e6e849cc58d2ffdacdfc8 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 12 Oct 2016 15:33:56 -0700 Subject: [PATCH] Port #11285 to release-2.0.5 --- .../unittests/tsserverProjectSystem.ts | 107 +++++++++++++++++- src/server/editorServices.ts | 12 +- src/server/session.ts | 20 ++-- 3 files changed, 124 insertions(+), 15 deletions(-) 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 || [] } + }); } }