Merge pull request #36383 from uniqueiniquity/redirectInfo

Redirect info
This commit is contained in:
Ben Lichtman
2020-01-28 11:51:06 -08:00
committed by GitHub
6 changed files with 301 additions and 31 deletions

View File

@@ -3124,19 +3124,24 @@ namespace ts.server {
return result;
}
private collectChanges(lastKnownProjectVersions: protocol.ProjectVersionInfo[], currentProjects: Project[], result: ProjectFilesWithTSDiagnostics[]): void {
private collectChanges(
lastKnownProjectVersions: protocol.ProjectVersionInfo[],
currentProjects: Project[],
includeProjectReferenceRedirectInfo: boolean | undefined,
result: ProjectFilesWithTSDiagnostics[]
): void {
for (const proj of currentProjects) {
const knownProject = find(lastKnownProjectVersions, p => p.projectName === proj.getProjectName());
result.push(proj.getChangesSinceVersion(knownProject && knownProject.version));
result.push(proj.getChangesSinceVersion(knownProject && knownProject.version, includeProjectReferenceRedirectInfo));
}
}
/* @internal */
synchronizeProjectList(knownProjects: protocol.ProjectVersionInfo[]): ProjectFilesWithTSDiagnostics[] {
synchronizeProjectList(knownProjects: protocol.ProjectVersionInfo[], includeProjectReferenceRedirectInfo?: boolean): ProjectFilesWithTSDiagnostics[] {
const files: ProjectFilesWithTSDiagnostics[] = [];
this.collectChanges(knownProjects, this.externalProjects, files);
this.collectChanges(knownProjects, arrayFrom(this.configuredProjects.values()), files);
this.collectChanges(knownProjects, this.inferredProjects, files);
this.collectChanges(knownProjects, this.externalProjects, includeProjectReferenceRedirectInfo, files);
this.collectChanges(knownProjects, arrayFrom(this.configuredProjects.values()), includeProjectReferenceRedirectInfo, files);
this.collectChanges(knownProjects, this.inferredProjects, includeProjectReferenceRedirectInfo, files);
return files;
}

View File

@@ -167,7 +167,7 @@ namespace ts.server {
/**
* Set of files that was returned from the last call to getChangesSinceVersion.
*/
private lastReportedFileNames: Map<true> | undefined;
private lastReportedFileNames: Map<boolean> | undefined;
/**
* Last version that was reported.
*/
@@ -803,6 +803,14 @@ namespace ts.server {
return result;
}
/* @internal */
getFileNamesWithRedirectInfo(includeProjectReferenceRedirectInfo: boolean) {
return this.getFileNames().map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({
fileName,
isSourceOfProjectReferenceRedirect: includeProjectReferenceRedirectInfo && this.isSourceOfProjectReferenceRedirect(fileName)
}));
}
hasConfigFile(configFilePath: NormalizedPath) {
if (this.program && this.languageServiceEnabled) {
const configFile = this.program.getCompilerOptions().configFile;
@@ -1300,7 +1308,15 @@ namespace ts.server {
}
/* @internal */
getChangesSinceVersion(lastKnownVersion?: number): ProjectFilesWithTSDiagnostics {
getChangesSinceVersion(lastKnownVersion?: number, includeProjectReferenceRedirectInfo?: boolean): ProjectFilesWithTSDiagnostics {
const includeProjectReferenceRedirectInfoIfRequested =
includeProjectReferenceRedirectInfo
? (files: Map<boolean>) => arrayFrom(files.entries(), ([fileName, isSourceOfProjectReferenceRedirect]): protocol.FileWithProjectReferenceRedirectInfo => ({
fileName,
isSourceOfProjectReferenceRedirect
}))
: (files: Map<boolean>) => arrayFrom(files.keys());
// Update the graph only if initial configured project load is not pending
if (!this.isInitialLoadPending()) {
updateProjectIfDirty(this);
@@ -1324,35 +1340,75 @@ 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<boolean> = new Map<boolean>();
const removed: Map<boolean> = new Map<boolean>();
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);
forEachEntry(currentFiles, (isSourceOfProjectReferenceRedirect, fileName) => {
if (!lastReportedFileNames.has(fileName)) {
added.set(fileName, isSourceOfProjectReferenceRedirect);
}
else if (includeProjectReferenceRedirectInfo && isSourceOfProjectReferenceRedirect !== lastReportedFileNames.get(fileName)){
updatedRedirects.push({
fileName,
isSourceOfProjectReferenceRedirect
});
}
});
forEachKey(lastReportedFileNames, id => {
if (!currentFiles.has(id)) {
removed.push(id);
forEachEntry(lastReportedFileNames, (isSourceOfProjectReferenceRedirect, fileName) => {
if (!currentFiles.has(fileName)) {
removed.set(fileName, isSourceOfProjectReferenceRedirect);
}
});
this.lastReportedFileNames = currentFiles;
this.lastReportedVersion = this.projectProgramVersion;
return { info, changes: { added, removed, updated }, projectErrors: this.getGlobalProjectErrors() };
return {
info,
changes: {
added: includeProjectReferenceRedirectInfoIfRequested(added),
removed: includeProjectReferenceRedirectInfoIfRequested(removed),
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(
allFiles,
info => info.fileName,
info => info.isSourceOfProjectReferenceRedirect
);
this.lastReportedVersion = this.projectProgramVersion;
return { info, files: allFiles, projectErrors: this.getGlobalProjectErrors() };
return {
info,
files: includeProjectReferenceRedirectInfo ? allFiles : allFiles.map(f => f.fileName),
projectErrors: this.getGlobalProjectErrors()
};
}
}

View File

@@ -1324,6 +1324,18 @@ namespace ts.server.protocol {
lastFileExceededProgramSize?: string;
}
export interface FileWithProjectReferenceRedirectInfo {
/**
* Name of file
*/
fileName: string;
/**
* True if the file is primarily included in a referenced project
*/
isSourceOfProjectReferenceRedirect: boolean;
}
/**
* Represents a set of changes that happen in project
*/
@@ -1331,15 +1343,20 @@ namespace ts.server.protocol {
/**
* List of added files
*/
added: string[];
added: string[] | FileWithProjectReferenceRedirectInfo[];
/**
* List of removed files
*/
removed: string[];
removed: string[] | FileWithProjectReferenceRedirectInfo[];
/**
* List of updated files
*/
updated: string[];
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[];
}
/**
@@ -1357,8 +1374,10 @@ 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[];
files?: string[] | FileWithProjectReferenceRedirectInfo[];
/**
* Set of changes in project (omitted if the entire set of files in project should be replaced)
*/
@@ -1621,6 +1640,11 @@ namespace ts.server.protocol {
* List of last known projects
*/
knownProjects: ProjectVersionInfo[];
/**
* If true, response specifies whether or not each file in each project
* is a source from a project reference redirect
*/
includeProjectReferenceRedirectInfo?: boolean;
}
/**

View File

@@ -2265,7 +2265,7 @@ namespace ts.server {
return this.requiredResponse(/*response*/ true);
},
[CommandNames.SynchronizeProjectList]: (request: protocol.SynchronizeProjectListRequest) => {
const result = this.projectService.synchronizeProjectList(request.arguments.knownProjects);
const result = this.projectService.synchronizeProjectList(request.arguments.knownProjects, request.arguments.includeProjectReferenceRedirectInfo);
if (!result.some(p => p.projectErrors && p.projectErrors.length !== 0)) {
return this.requiredResponse(result);
}