mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Search till root just like tsc when the projectRootPath specified doesnt contain the info.path
Fixes #21209
This commit is contained in:
@@ -3655,11 +3655,11 @@ namespace ts.projectSystem {
|
||||
// Open file1 -> configFile
|
||||
verifyConfigFileName(file1, "/a", configFile);
|
||||
verifyConfigFileName(file1, "/a/b", configFile);
|
||||
verifyConfigFileName(file1, "/a/B", useCaseSensitiveFileNames ? undefined : configFile);
|
||||
verifyConfigFileName(file1, "/a/B", configFile);
|
||||
|
||||
// Open file2 use root "/a/b"
|
||||
verifyConfigFileName(file2, "/a", useCaseSensitiveFileNames ? configFile2 : configFile);
|
||||
verifyConfigFileName(file2, "/a/b", useCaseSensitiveFileNames ? undefined : configFile);
|
||||
verifyConfigFileName(file2, "/a/b", useCaseSensitiveFileNames ? configFile2 : configFile);
|
||||
verifyConfigFileName(file2, "/a/B", useCaseSensitiveFileNames ? undefined : configFile);
|
||||
|
||||
function verifyConfigFileName(file: FileOrFolder, projectRoot: string, expectedConfigFile: FileOrFolder | undefined) {
|
||||
@@ -4998,6 +4998,83 @@ namespace ts.projectSystem {
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
checkWatchedDirectories(host, getTypeRootsFromLocation(projectDir), /*recursive*/ true);
|
||||
});
|
||||
|
||||
describe("when the opened file is not from project root", () => {
|
||||
const projectRoot = "/a/b/projects/project";
|
||||
const file: FileOrFolder = {
|
||||
path: `${projectRoot}/src/index.ts`,
|
||||
content: "let y = 10"
|
||||
};
|
||||
const tsconfig: FileOrFolder = {
|
||||
path: `${projectRoot}/tsconfig.json`,
|
||||
content: "{}"
|
||||
};
|
||||
const files = [file, libFile];
|
||||
const filesWithConfig = files.concat(tsconfig);
|
||||
const dirOfFile = getDirectoryPath(file.path);
|
||||
|
||||
function openClientFile(files: FileOrFolder[]) {
|
||||
const host = createServerHost(files);
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
projectService.openClientFile(file.path, /*fileContent*/ undefined, /*scriptKind*/ undefined, "/a/b/projects/proj");
|
||||
return { host, projectService };
|
||||
}
|
||||
|
||||
function verifyConfiguredProject(host: TestServerHost, projectService: TestProjectService) {
|
||||
projectService.checkNumberOfProjects({ configuredProjects: 1 });
|
||||
const project = projectService.configuredProjects.get(tsconfig.path);
|
||||
assert.isDefined(project);
|
||||
|
||||
checkProjectActualFiles(project, [file.path, libFile.path, tsconfig.path]);
|
||||
checkWatchedFiles(host, [libFile.path, tsconfig.path]);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectRoot].concat(getTypeRootsFromLocation(projectRoot)), /*recursive*/ true);
|
||||
}
|
||||
|
||||
function verifyInferredProject(host: TestServerHost, projectService: TestProjectService) {
|
||||
projectService.checkNumberOfProjects({ inferredProjects: 1 });
|
||||
const project = projectService.inferredProjects[0];
|
||||
assert.isDefined(project);
|
||||
|
||||
const filesToWatch = [libFile.path];
|
||||
forEachAncestorDirectory(dirOfFile, ancestor => {
|
||||
filesToWatch.push(combinePaths(ancestor, "tsconfig.json"));
|
||||
filesToWatch.push(combinePaths(ancestor, "jsconfig.json"));
|
||||
});
|
||||
|
||||
checkProjectActualFiles(project, [file.path, libFile.path]);
|
||||
checkWatchedFiles(host, filesToWatch);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, getTypeRootsFromLocation(dirOfFile), /*recursive*/ true);
|
||||
}
|
||||
|
||||
it("tsconfig for the file exists", () => {
|
||||
const { host, projectService } = openClientFile(filesWithConfig);
|
||||
verifyConfiguredProject(host, projectService);
|
||||
|
||||
host.reloadFS(files);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyInferredProject(host, projectService);
|
||||
|
||||
host.reloadFS(filesWithConfig);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyConfiguredProject(host, projectService);
|
||||
});
|
||||
|
||||
it("tsconfig for the file does not exist", () => {
|
||||
const { host, projectService } = openClientFile(files);
|
||||
verifyInferredProject(host, projectService);
|
||||
|
||||
host.reloadFS(filesWithConfig);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyConfiguredProject(host, projectService);
|
||||
|
||||
host.reloadFS(files);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyInferredProject(host, projectService);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem cancellationToken", () => {
|
||||
|
||||
@@ -1156,7 +1156,7 @@ namespace ts.server {
|
||||
* This is called by inferred project whenever script info is added as a root
|
||||
*/
|
||||
/* @internal */
|
||||
startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo, projectRootPath: NormalizedPath | undefined) {
|
||||
startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
|
||||
Debug.assert(info.isScriptOpen());
|
||||
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
|
||||
let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
|
||||
@@ -1178,7 +1178,7 @@ namespace ts.server {
|
||||
!this.getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath)) {
|
||||
this.createConfigFileWatcherOfConfigFileExistence(configFileName, canonicalConfigFilePath, configFileExistenceInfo);
|
||||
}
|
||||
}, projectRootPath);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1209,12 +1209,14 @@ namespace ts.server {
|
||||
* The server must start searching from the directory containing
|
||||
* the newly opened file.
|
||||
*/
|
||||
private forEachConfigFileLocation(info: ScriptInfo,
|
||||
action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void,
|
||||
projectRootPath?: NormalizedPath) {
|
||||
let searchPath = asNormalizedPath(getDirectoryPath(info.fileName));
|
||||
private forEachConfigFileLocation(info: ScriptInfo, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
|
||||
const projectRootPath = this.openFiles.get(info.path);
|
||||
let searchPath = asNormalizedPath(this.getNormalizedAbsolutePath(getDirectoryPath(info.fileName)));
|
||||
const isSearchPathInProjectRoot = () => containsPath(projectRootPath, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames);
|
||||
|
||||
while (!projectRootPath || containsPath(projectRootPath, searchPath, this.currentDirectory, !this.host.useCaseSensitiveFileNames)) {
|
||||
// If projectRootPath doesnt contain info.path, then do normal search for config file
|
||||
const anySearchPathOk = !projectRootPath || !isSearchPathInProjectRoot();
|
||||
do {
|
||||
const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName);
|
||||
const tsconfigFileName = asNormalizedPath(combinePaths(searchPath, "tsconfig.json"));
|
||||
let result = action(tsconfigFileName, combinePaths(canonicalSearchPath, "tsconfig.json"));
|
||||
@@ -1233,7 +1235,7 @@ namespace ts.server {
|
||||
break;
|
||||
}
|
||||
searchPath = parentPath;
|
||||
}
|
||||
} while (anySearchPathOk || isSearchPathInProjectRoot());
|
||||
|
||||
return undefined;
|
||||
}
|
||||
@@ -1246,13 +1248,12 @@ namespace ts.server {
|
||||
* The server must start searching from the directory containing
|
||||
* the newly opened file.
|
||||
*/
|
||||
private getConfigFileNameForFile(info: ScriptInfo, projectRootPath: NormalizedPath | undefined) {
|
||||
private getConfigFileNameForFile(info: ScriptInfo) {
|
||||
Debug.assert(info.isScriptOpen());
|
||||
this.logger.info(`Search path: ${getDirectoryPath(info.fileName)}`);
|
||||
const configFileName = this.forEachConfigFileLocation(info,
|
||||
(configFileName, canonicalConfigFilePath) =>
|
||||
this.configFileExists(configFileName, canonicalConfigFilePath, info),
|
||||
projectRootPath
|
||||
this.configFileExists(configFileName, canonicalConfigFilePath, info)
|
||||
);
|
||||
if (configFileName) {
|
||||
this.logger.info(`For info: ${info.fileName} :: Config file name: ${configFileName}`);
|
||||
@@ -1906,7 +1907,7 @@ namespace ts.server {
|
||||
// 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, this.openFiles.get(path));
|
||||
const configFileName = this.getConfigFileNameForFile(info);
|
||||
if (configFileName) {
|
||||
const project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
@@ -2012,9 +2013,10 @@ namespace ts.server {
|
||||
let configFileErrors: ReadonlyArray<Diagnostic>;
|
||||
|
||||
const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent);
|
||||
this.openFiles.set(info.path, projectRootPath);
|
||||
let project: ConfiguredProject | ExternalProject = this.findExternalProjetContainingOpenScriptInfo(info);
|
||||
if (!project) {
|
||||
configFileName = this.getConfigFileNameForFile(info, projectRootPath);
|
||||
configFileName = this.getConfigFileNameForFile(info);
|
||||
if (configFileName) {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
@@ -2047,7 +2049,6 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
Debug.assert(!info.isOrphan());
|
||||
this.openFiles.set(info.path, projectRootPath);
|
||||
|
||||
// Remove the configured projects that have zero references from open files.
|
||||
// This was postponed from closeOpenFile to after opening next file,
|
||||
|
||||
@@ -1200,7 +1200,7 @@ namespace ts.server {
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
Debug.assert(info.isScriptOpen());
|
||||
this.projectService.startWatchingConfigFilesForInferredProjectRoot(info, this.projectService.openFiles.get(info.path));
|
||||
this.projectService.startWatchingConfigFilesForInferredProjectRoot(info);
|
||||
if (!this._isJsInferredProject && info.isJavaScript()) {
|
||||
this.toggleJsInferredProject(/*isJsInferredProject*/ true);
|
||||
}
|
||||
|
||||
+2
-2
@@ -7891,7 +7891,7 @@ declare namespace ts.server {
|
||||
* The server must start searching from the directory containing
|
||||
* the newly opened file.
|
||||
*/
|
||||
private forEachConfigFileLocation(info, action, projectRootPath?);
|
||||
private forEachConfigFileLocation(info, action);
|
||||
/**
|
||||
* This function tries to search for a tsconfig.json for the given file.
|
||||
* This is different from the method the compiler uses because
|
||||
@@ -7900,7 +7900,7 @@ declare namespace ts.server {
|
||||
* The server must start searching from the directory containing
|
||||
* the newly opened file.
|
||||
*/
|
||||
private getConfigFileNameForFile(info, projectRootPath);
|
||||
private getConfigFileNameForFile(info);
|
||||
private printProjects();
|
||||
private findConfiguredProjectByProjectName(configFileName);
|
||||
private getConfiguredProjectByCanonicalConfigFilePath(canonicalConfigFilePath);
|
||||
|
||||
Reference in New Issue
Block a user