mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-24 02:21:30 -05:00
Store the projectRootPath the script info was opened with so that we can reuse it later to search/set file watches
This commit is contained in:
@@ -352,9 +352,9 @@ namespace ts.server {
|
||||
*/
|
||||
readonly configuredProjects = createMap<ConfiguredProject>();
|
||||
/**
|
||||
* list of open files
|
||||
* Open files: with value being project root path, and key being Path of the file that is open
|
||||
*/
|
||||
readonly openFiles: ScriptInfo[] = [];
|
||||
readonly openFiles = createMap<NormalizedPath>();
|
||||
|
||||
private compilerOptionsForInferredProjects: CompilerOptions;
|
||||
private compilerOptionsForInferredProjectsPerProjectRoot = createMap<CompilerOptions>();
|
||||
@@ -582,7 +582,7 @@ namespace ts.server {
|
||||
const event: ProjectsUpdatedInBackgroundEvent = {
|
||||
eventName: ProjectsUpdatedInBackgroundEvent,
|
||||
data: {
|
||||
openFiles: this.openFiles.map(f => f.fileName)
|
||||
openFiles: arrayFrom(this.openFiles.keys(), path => this.getScriptInfoForPath(path as Path).fileName)
|
||||
}
|
||||
};
|
||||
this.eventHandler(event);
|
||||
@@ -891,7 +891,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
assignOrphanScriptInfoToInferredProject(info: ScriptInfo, projectRootPath?: string) {
|
||||
assignOrphanScriptInfoToInferredProject(info: ScriptInfo, projectRootPath: NormalizedPath | undefined) {
|
||||
Debug.assert(info.isOrphan());
|
||||
|
||||
const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath) ||
|
||||
@@ -935,7 +935,7 @@ namespace ts.server {
|
||||
info.close();
|
||||
this.stopWatchingConfigFilesForClosedScriptInfo(info);
|
||||
|
||||
unorderedRemoveItem(this.openFiles, info);
|
||||
this.openFiles.delete(info.path);
|
||||
|
||||
const fileExists = this.host.fileExists(info.fileName);
|
||||
|
||||
@@ -974,11 +974,12 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// collect orphaned files and assign them to inferred project just like we treat open of a file
|
||||
for (const f of this.openFiles) {
|
||||
this.openFiles.forEach((projectRootPath, path) => {
|
||||
const f = this.getScriptInfoForPath(path as Path);
|
||||
if (f.isOrphan()) {
|
||||
this.assignOrphanScriptInfoToInferredProject(f);
|
||||
this.assignOrphanScriptInfoToInferredProject(f, projectRootPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup script infos that arent part of any project (eg. those could be closed script infos not referenced by any project)
|
||||
// is postponed to next file open so that if file from same project is opened,
|
||||
@@ -1172,7 +1173,7 @@ namespace ts.server {
|
||||
* This is called by inferred project whenever script info is added as a root
|
||||
*/
|
||||
/* @internal */
|
||||
startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
|
||||
startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo, projectRootPath: NormalizedPath | undefined) {
|
||||
Debug.assert(info.isScriptOpen());
|
||||
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
|
||||
let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
|
||||
@@ -1194,7 +1195,7 @@ namespace ts.server {
|
||||
!this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath)) {
|
||||
this.createConfigFileWatcherOfConfigFileExistence(configFileName, canonicalConfigFilePath, configFileExistenceInfo);
|
||||
}
|
||||
});
|
||||
}, projectRootPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1262,7 +1263,7 @@ namespace ts.server {
|
||||
* The server must start searching from the directory containing
|
||||
* the newly opened file.
|
||||
*/
|
||||
private getConfigFileNameForFile(info: ScriptInfo, projectRootPath?: NormalizedPath) {
|
||||
private getConfigFileNameForFile(info: ScriptInfo, projectRootPath: NormalizedPath | undefined) {
|
||||
Debug.assert(info.isScriptOpen());
|
||||
this.logger.info(`Search path: ${getDirectoryPath(info.fileName)}`);
|
||||
const configFileName = this.forEachConfigFileLocation(info,
|
||||
@@ -1301,9 +1302,9 @@ namespace ts.server {
|
||||
printProjects(this.inferredProjects, counter);
|
||||
|
||||
this.logger.info("Open files: ");
|
||||
for (const rootFile of this.openFiles) {
|
||||
this.logger.info(`\t${rootFile.fileName}`);
|
||||
}
|
||||
this.openFiles.forEach((projectRootPath, path) => {
|
||||
this.logger.info(`\tFileName: ${this.getScriptInfoForPath(path as Path).fileName} ProjectRootPath: ${projectRootPath}`);
|
||||
});
|
||||
|
||||
this.logger.endGroup();
|
||||
}
|
||||
@@ -1605,7 +1606,7 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
private getOrCreateInferredProjectForProjectRootPathIfEnabled(info: ScriptInfo, projectRootPath: string | undefined): InferredProject | undefined {
|
||||
private getOrCreateInferredProjectForProjectRootPathIfEnabled(info: ScriptInfo, projectRootPath: NormalizedPath | undefined): InferredProject | undefined {
|
||||
if (!this.useInferredProjectPerProjectRoot) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1659,7 +1660,7 @@ namespace ts.server {
|
||||
return this.createInferredProject(/*currentDirectory*/ undefined, /*isSingleInferredProject*/ true);
|
||||
}
|
||||
|
||||
private createInferredProject(currentDirectory: string | undefined, isSingleInferredProject?: boolean, projectRootPath?: string): InferredProject {
|
||||
private createInferredProject(currentDirectory: string | undefined, isSingleInferredProject?: boolean, projectRootPath?: NormalizedPath): InferredProject {
|
||||
const compilerOptions = projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) || this.compilerOptionsForInferredProjects;
|
||||
const project = new InferredProject(this, this.documentRegistry, compilerOptions, projectRootPath, currentDirectory);
|
||||
if (isSingleInferredProject) {
|
||||
@@ -1796,23 +1797,19 @@ namespace ts.server {
|
||||
// as there is no need to load contents of the files from the disk
|
||||
|
||||
// Reload Projects
|
||||
this.reloadConfiguredProjectForFiles(this.openFiles, /*delayReload*/ false);
|
||||
this.reloadConfiguredProjectForFiles(this.openFiles, /*delayReload*/ false, returnTrue);
|
||||
this.refreshInferredProjects();
|
||||
}
|
||||
|
||||
private delayReloadConfiguredProjectForFiles(configFileExistenceInfo: ConfigFileExistenceInfo, ignoreIfNotRootOfInferredProject: boolean) {
|
||||
// Get open files to reload projects for
|
||||
const openFiles = mapDefinedIter(
|
||||
configFileExistenceInfo.openFilesImpactedByConfigFile.entries(),
|
||||
([path, isRootOfInferredProject]) => {
|
||||
if (!ignoreIfNotRootOfInferredProject || isRootOfInferredProject) {
|
||||
const info = this.getScriptInfoForPath(path as Path);
|
||||
Debug.assert(!!info);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
this.reloadConfiguredProjectForFiles(
|
||||
configFileExistenceInfo.openFilesImpactedByConfigFile,
|
||||
/*delayReload*/ true,
|
||||
ignoreIfNotRootOfInferredProject ?
|
||||
isRootOfInferredProject => isRootOfInferredProject : // Reload open files if they are root of inferred project
|
||||
returnTrue // Reload all the open files impacted by config file
|
||||
);
|
||||
this.reloadConfiguredProjectForFiles(openFiles, /*delayReload*/ true);
|
||||
this.delayInferredProjectsRefresh();
|
||||
}
|
||||
|
||||
@@ -1821,16 +1818,24 @@ namespace ts.server {
|
||||
* If the config file is found and it refers to existing project, it reloads it either immediately
|
||||
* or schedules it for reload depending on delayReload option
|
||||
* If the there is no existing project it just opens the configured project for the config file
|
||||
* reloadForInfo provides a way to filter out files to reload configured project for
|
||||
*/
|
||||
private reloadConfiguredProjectForFiles(openFiles: ReadonlyArray<ScriptInfo>, delayReload: boolean) {
|
||||
private reloadConfiguredProjectForFiles<T>(openFiles: Map<T>, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean) {
|
||||
const updatedProjects = createMap<true>();
|
||||
// try to reload config file for all open files
|
||||
for (const info of openFiles) {
|
||||
openFiles.forEach((openFileValue, path) => {
|
||||
// Filter out the files that need to be ignored
|
||||
if (!shouldReloadProjectFor(openFileValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const info = this.getScriptInfoForPath(path as Path);
|
||||
Debug.assert(info.isScriptOpen());
|
||||
// This tries to search for a tsconfig.json for the given file. If we found it,
|
||||
// we first detect if there is already a configured project created for it: if so,
|
||||
// we re- read the tsconfig file content and update the project only if we havent already done so
|
||||
// otherwise we create a new one.
|
||||
const configFileName = this.getConfigFileNameForFile(info);
|
||||
const configFileName = this.getConfigFileNameForFile(info, this.openFiles.get(path));
|
||||
if (configFileName) {
|
||||
const project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
@@ -1848,7 +1853,7 @@ namespace ts.server {
|
||||
updatedProjects.set(configFileName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1893,16 +1898,17 @@ namespace ts.server {
|
||||
this.logger.info("refreshInferredProjects: updating project structure from ...");
|
||||
this.printProjects();
|
||||
|
||||
for (const info of this.openFiles) {
|
||||
this.openFiles.forEach((projectRootPath, path) => {
|
||||
const info = this.getScriptInfoForPath(path as Path);
|
||||
// collect all orphaned script infos from open files
|
||||
if (info.isOrphan()) {
|
||||
this.assignOrphanScriptInfoToInferredProject(info);
|
||||
this.assignOrphanScriptInfoToInferredProject(info, projectRootPath);
|
||||
}
|
||||
else {
|
||||
// Or remove the root of inferred project if is referenced in more than one projects
|
||||
this.removeRootOfInferredProjectIfNowPartOfOtherProject(info);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const p of this.inferredProjects) {
|
||||
p.updateGraph();
|
||||
@@ -1956,7 +1962,7 @@ namespace ts.server {
|
||||
this.assignOrphanScriptInfoToInferredProject(info, projectRootPath);
|
||||
}
|
||||
Debug.assert(!info.isOrphan());
|
||||
this.openFiles.push(info);
|
||||
this.openFiles.set(info.path, projectRootPath);
|
||||
|
||||
if (sendConfigFileDiagEvent) {
|
||||
configFileErrors = project.getAllProjectErrors();
|
||||
|
||||
@@ -1064,7 +1064,7 @@ namespace ts.server {
|
||||
projectService: ProjectService,
|
||||
documentRegistry: DocumentRegistry,
|
||||
compilerOptions: CompilerOptions,
|
||||
projectRootPath: string | undefined,
|
||||
projectRootPath: NormalizedPath | undefined,
|
||||
currentDirectory: string | undefined) {
|
||||
super(InferredProject.newName(),
|
||||
ProjectKind.Inferred,
|
||||
@@ -1080,7 +1080,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
this.projectService.startWatchingConfigFilesForInferredProjectRoot(info);
|
||||
Debug.assert(info.isScriptOpen());
|
||||
this.projectService.startWatchingConfigFilesForInferredProjectRoot(info, this.projectService.openFiles.get(info.path));
|
||||
if (!this._isJsInferredProject && info.isJavaScript()) {
|
||||
this.toggleJsInferredProject(/*isJsInferredProject*/ true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user