From f047111c649a708d398ba7a39b8c635af28ebeb2 Mon Sep 17 00:00:00 2001 From: Ben Lichtman Date: Fri, 24 Jan 2020 15:15:05 -0800 Subject: [PATCH] Track changes to redirect info --- src/server/project.ts | 83 +++++++++++++++++++++++++++++++----------- src/server/protocol.ts | 9 ++++- 2 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/server/project.ts b/src/server/project.ts index 8da99ee5149..b9b6e170d7f 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -167,7 +167,7 @@ namespace ts.server { /** * Set of files that was returned from the last call to getChangesSinceVersion. */ - private lastReportedFileNames: Map | undefined; + private lastReportedFileNames: Map | undefined; /** * Last version that was reported. */ @@ -803,6 +803,22 @@ namespace ts.server { return result; } + /* @internal */ + getFileNamesWithRedirectInfo(includeProjectReferenceRedirectInfo: boolean) { + const fileNames = this.getFileNames(); + if (includeProjectReferenceRedirectInfo) { + return fileNames.map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({ + fileName, + isSourceOfProjectReferenceRedirect: this.isSourceOfProjectReferenceRedirect(fileName) + })); + } + + return fileNames.map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({ + fileName, + isSourceOfProjectReferenceRedirect: false + })); + } + hasConfigFile(configFilePath: NormalizedPath) { if (this.program && this.languageServiceEnabled) { const configFile = this.program.getCompilerOptions().configFile; @@ -1301,16 +1317,13 @@ namespace ts.server { /* @internal */ getChangesSinceVersion(lastKnownVersion?: number, includeProjectReferenceRedirectInfo?: boolean): ProjectFilesWithTSDiagnostics { - const includeProjectReferenceRedirectInfoIfRequested = (files: string[]) => { - if (includeProjectReferenceRedirectInfo) { - return files.map((fileName: string): protocol.FileWithProjectReferenceRedirectInfo => ({ + const includeProjectReferenceRedirectInfoIfRequested = + includeProjectReferenceRedirectInfo + ? (files: Map) => arrayFrom(files.keys(), (fileName: string): protocol.FileWithProjectReferenceRedirectInfo => ({ fileName, - isSourceOfProjectReferenceRedirect: this.program?.isSourceOfProjectReferenceRedirect(fileName) ?? false - })); - } - - return files; - }; + isSourceOfProjectReferenceRedirect: files.get(fileName)! // fileName guaranteed to be in files + })) + : (files: Map) => arrayFrom(files.keys()); // Update the graph only if initial configured project load is not pending if (!this.isInitialLoadPending()) { @@ -1335,21 +1348,36 @@ namespace ts.server { } // compute and return the difference const lastReportedFileNames = this.lastReportedFileNames; - const externalFiles = this.getExternalFiles().map(f => toNormalizedPath(f)); - const currentFiles = arrayToSet(this.getFileNames().concat(externalFiles)); + const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ + fileName: toNormalizedPath(f), + isSourceOfProjectReferenceRedirect: false + })); + const currentFiles = arrayToMap( + this.getFileNamesWithRedirectInfo(!!includeProjectReferenceRedirectInfo).concat(externalFiles), + info => info.fileName, + info => info.isSourceOfProjectReferenceRedirect + ); + + const added: Map = new Map(); + const removed: Map = new Map(); - const added: string[] = []; - const removed: string[] = []; const updated: string[] = updatedFileNames ? arrayFrom(updatedFileNames.keys()) : []; + const updatedRedirects: protocol.FileWithProjectReferenceRedirectInfo[] = []; forEachKey(currentFiles, id => { if (!lastReportedFileNames.has(id)) { - added.push(id); + added.set(id, currentFiles.get(id)!); // id guaranteed to be in currentFiles + } + else if (includeProjectReferenceRedirectInfo && lastReportedFileNames.get(id) !== currentFiles.get(id)){ + updatedRedirects.push({ + fileName: id, + isSourceOfProjectReferenceRedirect: currentFiles.get(id)! // id guaranteed to be in currentFiles + }); } }); forEachKey(lastReportedFileNames, id => { if (!currentFiles.has(id)) { - removed.push(id); + removed.set(id, lastReportedFileNames.get(id)!); // id guaranteed to be in lastReportedFileNames } }); this.lastReportedFileNames = currentFiles; @@ -1359,21 +1387,34 @@ namespace ts.server { changes: { added: includeProjectReferenceRedirectInfoIfRequested(added), removed: includeProjectReferenceRedirectInfoIfRequested(removed), - updated: includeProjectReferenceRedirectInfoIfRequested(updated) + updated: includeProjectReferenceRedirectInfoIfRequested + ? updated.map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({ + fileName, + isSourceOfProjectReferenceRedirect: this.isSourceOfProjectReferenceRedirect(fileName) + })) + : updated, + updatedRedirects: includeProjectReferenceRedirectInfo ? updatedRedirects : undefined }, projectErrors: this.getGlobalProjectErrors() }; } else { // unknown version - return everything - const projectFileNames = this.getFileNames(); - const externalFiles = this.getExternalFiles().map(f => toNormalizedPath(f)); + const projectFileNames = this.getFileNamesWithRedirectInfo(!!includeProjectReferenceRedirectInfo); + const externalFiles = this.getExternalFiles().map((f): protocol.FileWithProjectReferenceRedirectInfo => ({ + fileName: toNormalizedPath(f), + isSourceOfProjectReferenceRedirect: false + })); const allFiles = projectFileNames.concat(externalFiles); - this.lastReportedFileNames = arrayToSet(allFiles); + this.lastReportedFileNames = arrayToMap( + projectFileNames.concat(externalFiles), + info => info.fileName, + info => info.isSourceOfProjectReferenceRedirect + ); this.lastReportedVersion = this.projectProgramVersion; return { info, - files: includeProjectReferenceRedirectInfoIfRequested(allFiles), + files: includeProjectReferenceRedirectInfo ? allFiles : allFiles.map(f => f.fileName), projectErrors: this.getGlobalProjectErrors() }; } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 09457ddfbdd..2e33942b5b7 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1352,6 +1352,11 @@ namespace ts.server.protocol { * List of updated files */ updated: string[] | FileWithProjectReferenceRedirectInfo[]; + /** + * List of files that have had their project reference redirect status updated + * Only provided when the synchronizeProjectList request has includeProjectReferenceRedirectInfo set to true + */ + updatedRedirects?: FileWithProjectReferenceRedirectInfo[]; } /** @@ -1369,6 +1374,8 @@ namespace ts.server.protocol { info?: ProjectVersionInfo; /** * List of files in project (might be omitted if current state of project can be computed using only information from 'changes') + * This property will have type FileWithProjectReferenceRedirectInfo[] if includeProjectReferenceRedirectInfo is set to true in + * the corresponding SynchronizeProjectList request; otherwise, it will have type string[]. */ files?: string[] | FileWithProjectReferenceRedirectInfo[]; /** @@ -1635,7 +1642,7 @@ namespace ts.server.protocol { knownProjects: ProjectVersionInfo[]; /** * If true, response specifies whether or not each file in each project - * is the result of a project reference redirect + * is a source from a project reference redirect */ includeProjectReferenceRedirectInfo?: boolean; }